mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-27 21:27:19 -08:00
Compare commits
6 commits
9ed5226eab
...
3da52208ba
Author | SHA1 | Date | |
---|---|---|---|
|
3da52208ba | ||
|
9e14327f3c | ||
|
fa2eb0cd26 | ||
|
b23f284e21 | ||
|
d0ae24b0b7 | ||
|
f6e0b0b1c0 |
14 changed files with 167 additions and 64 deletions
|
@ -24,9 +24,9 @@ namespace SourceGit.Commands
|
||||||
Context = repo;
|
Context = repo;
|
||||||
|
|
||||||
if (ignoreWhitespace)
|
if (ignoreWhitespace)
|
||||||
Args = $"diff --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}";
|
Args = $"diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}";
|
||||||
else
|
else
|
||||||
Args = $"diff --ignore-cr-at-eol --unified={unified} {opt}";
|
Args = $"diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Models.DiffResult Result()
|
public Models.DiffResult Result()
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace SourceGit.Commands
|
||||||
WorkingDirectory = repo;
|
WorkingDirectory = repo;
|
||||||
Context = repo;
|
Context = repo;
|
||||||
TraitErrorAsOutput = true;
|
TraitErrorAsOutput = true;
|
||||||
Args = "gc --prune";
|
Args = "gc --prune=now";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReadline(string line)
|
protected override void OnReadline(string line)
|
||||||
|
|
|
@ -7,9 +7,11 @@ namespace SourceGit.Commands
|
||||||
{
|
{
|
||||||
public QueryTags(string repo)
|
public QueryTags(string repo)
|
||||||
{
|
{
|
||||||
|
_boundary = $"----- BOUNDARY OF TAGS {Guid.NewGuid()} -----";
|
||||||
|
|
||||||
Context = repo;
|
Context = repo;
|
||||||
WorkingDirectory = repo;
|
WorkingDirectory = repo;
|
||||||
Args = "tag -l --sort=-creatordate --format=\"%(refname)%00%(objectname)%00%(*objectname)\"";
|
Args = $"tag -l --sort=-creatordate --format=\"{_boundary}%(refname)%00%(objectname)%00%(*objectname)%00%(contents:subject)%0a%0a%(contents:body)\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Models.Tag> Result()
|
public List<Models.Tag> Result()
|
||||||
|
@ -19,27 +21,25 @@ namespace SourceGit.Commands
|
||||||
if (!rs.IsSuccess)
|
if (!rs.IsSuccess)
|
||||||
return tags;
|
return tags;
|
||||||
|
|
||||||
var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
var records = rs.StdOut.Split(_boundary, StringSplitOptions.RemoveEmptyEntries);
|
||||||
foreach (var line in lines)
|
foreach (var record in records)
|
||||||
{
|
{
|
||||||
var tag = ParseLine(line);
|
var subs = record.Split('\0', StringSplitOptions.None);
|
||||||
if (tag != null)
|
if (subs.Length != 4)
|
||||||
tags.Add(tag);
|
continue;
|
||||||
|
|
||||||
|
var message = subs[3].Trim();
|
||||||
|
tags.Add(new Models.Tag()
|
||||||
|
{
|
||||||
|
Name = subs[0].Substring(10),
|
||||||
|
SHA = string.IsNullOrEmpty(subs[2]) ? subs[1] : subs[2],
|
||||||
|
Message = string.IsNullOrEmpty(message) ? null : message,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Models.Tag ParseLine(string line)
|
private string _boundary = string.Empty;
|
||||||
{
|
|
||||||
var subs = line.Split('\0');
|
|
||||||
if (subs.Length != 3)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var tag = new Models.Tag();
|
|
||||||
tag.Name = subs[0].Substring(10);
|
|
||||||
tag.SHA = string.IsNullOrEmpty(subs[2]) ? subs[1] : subs[2];
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string SHA { get; set; }
|
public string SHA { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
public bool IsFiltered { get; set; }
|
public bool IsFiltered { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,7 +322,7 @@
|
||||||
<x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">COMMIT TIME</x:String>
|
<x:String x:Key="Text.Histories.Header.Time" xml:space="preserve">COMMIT TIME</x:String>
|
||||||
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">SELECTED {0} COMMITS</x:String>
|
<x:String x:Key="Text.Histories.Selected" xml:space="preserve">SELECTED {0} COMMITS</x:String>
|
||||||
<x:String x:Key="Text.Histories.Tips" xml:space="preserve">Holding 'Ctrl' or 'Shift' to select multiple commits.</x:String>
|
<x:String x:Key="Text.Histories.Tips" xml:space="preserve">Holding 'Ctrl' or 'Shift' to select multiple commits.</x:String>
|
||||||
<x:String x:Key="Text.Histories.Tips.MacOS" xml:space="preserve">Holding '⌘' or '⇧' to select multiple commits.</x:String>
|
<x:String x:Key="Text.Histories.Tips.MacOS" xml:space="preserve">Holding ⌘ or ⇧ to select multiple commits.</x:String>
|
||||||
<x:String x:Key="Text.Histories.Tips.Prefix" xml:space="preserve">TIPS:</x:String>
|
<x:String x:Key="Text.Histories.Tips.Prefix" xml:space="preserve">TIPS:</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Keyboard Shortcuts Reference</x:String>
|
<x:String x:Key="Text.Hotkeys" xml:space="preserve">Keyboard Shortcuts Reference</x:String>
|
||||||
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
|
<x:String x:Key="Text.Hotkeys.Global" xml:space="preserve">GLOBAL</x:String>
|
||||||
|
@ -595,6 +595,7 @@
|
||||||
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Delete Submodule</x:String>
|
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">Delete Submodule</x:String>
|
||||||
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
|
<x:String x:Key="Text.Sure" xml:space="preserve">OK</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Copy Tag Name</x:String>
|
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">Copy Tag Name</x:String>
|
||||||
|
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">Copy Tag Message</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Delete ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">Delete ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Push ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">Push ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
|
<x:String x:Key="Text.URL" xml:space="preserve">URL:</x:String>
|
||||||
|
|
|
@ -593,6 +593,7 @@
|
||||||
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">删除子模块</x:String>
|
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">删除子模块</x:String>
|
||||||
<x:String x:Key="Text.Sure" xml:space="preserve">确 定</x:String>
|
<x:String x:Key="Text.Sure" xml:space="preserve">确 定</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">复制标签名</x:String>
|
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">复制标签名</x:String>
|
||||||
|
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">复制标签信息</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">删除 ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">删除 ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">推送 ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">推送 ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.URL" xml:space="preserve">仓库地址 :</x:String>
|
<x:String x:Key="Text.URL" xml:space="preserve">仓库地址 :</x:String>
|
||||||
|
|
|
@ -598,6 +598,7 @@
|
||||||
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">刪除子模組</x:String>
|
<x:String x:Key="Text.Submodule.Remove" xml:space="preserve">刪除子模組</x:String>
|
||||||
<x:String x:Key="Text.Sure" xml:space="preserve">確 定</x:String>
|
<x:String x:Key="Text.Sure" xml:space="preserve">確 定</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">複製標籤名稱</x:String>
|
<x:String x:Key="Text.TagCM.Copy" xml:space="preserve">複製標籤名稱</x:String>
|
||||||
|
<x:String x:Key="Text.TagCM.CopyMessage" xml:space="preserve">複製標籤訊息</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">刪除 ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Delete" xml:space="preserve">刪除 ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">推送 ${0}$...</x:String>
|
<x:String x:Key="Text.TagCM.Push" xml:space="preserve">推送 ${0}$...</x:String>
|
||||||
<x:String x:Key="Text.URL" xml:space="preserve">存放庫網址:</x:String>
|
<x:String x:Key="Text.URL" xml:space="preserve">存放庫網址:</x:String>
|
||||||
|
|
|
@ -1829,6 +1829,16 @@ namespace SourceGit.ViewModels
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var copyMessage = new MenuItem();
|
||||||
|
copyMessage.Header = App.Text("TagCM.CopyMessage");
|
||||||
|
copyMessage.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||||
|
copyMessage.IsEnabled = !string.IsNullOrEmpty(tag.Message);
|
||||||
|
copyMessage.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
App.CopyText(tag.Message);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
var menu = new ContextMenu();
|
var menu = new ContextMenu();
|
||||||
menu.Items.Add(createBranch);
|
menu.Items.Add(createBranch);
|
||||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||||
|
@ -1838,6 +1848,7 @@ namespace SourceGit.ViewModels
|
||||||
menu.Items.Add(archive);
|
menu.Items.Add(archive);
|
||||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||||
menu.Items.Add(copy);
|
menu.Items.Add(copy);
|
||||||
|
menu.Items.Add(copyMessage);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
@ -150,6 +151,74 @@ namespace SourceGit.ViewModels
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ContextMenu MakeContextMenuForChange(Models.Change change)
|
||||||
|
{
|
||||||
|
if (change == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var diffWithMerger = new MenuItem();
|
||||||
|
diffWithMerger.Header = App.Text("DiffWithMerger");
|
||||||
|
diffWithMerger.Icon = App.CreateMenuIcon("Icons.OpenWith");
|
||||||
|
diffWithMerger.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
var toolType = Preference.Instance.ExternalMergeToolType;
|
||||||
|
var toolPath = Preference.Instance.ExternalMergeToolPath;
|
||||||
|
var opt = new Models.DiffOption($"{_selectedStash.SHA}^", _selectedStash.SHA, change);
|
||||||
|
|
||||||
|
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo.FullPath, toolType, toolPath, opt));
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var fullPath = Path.Combine(_repo.FullPath, change.Path);
|
||||||
|
var explore = new MenuItem();
|
||||||
|
explore.Header = App.Text("RevealFile");
|
||||||
|
explore.Icon = App.CreateMenuIcon("Icons.Explore");
|
||||||
|
explore.IsEnabled = File.Exists(fullPath);
|
||||||
|
explore.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
Native.OS.OpenInFileManager(fullPath, true);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var resetToThisRevision = new MenuItem();
|
||||||
|
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
|
||||||
|
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
|
||||||
|
resetToThisRevision.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_selectedStash.SHA}");
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var copyPath = new MenuItem();
|
||||||
|
copyPath.Header = App.Text("CopyPath");
|
||||||
|
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||||
|
copyPath.Click += (_, ev) =>
|
||||||
|
{
|
||||||
|
App.CopyText(change.Path);
|
||||||
|
ev.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var copyFileName = new MenuItem();
|
||||||
|
copyFileName.Header = App.Text("CopyFileName");
|
||||||
|
copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||||
|
copyFileName.Click += (_, e) =>
|
||||||
|
{
|
||||||
|
App.CopyText(Path.GetFileName(change.Path));
|
||||||
|
e.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var menu = new ContextMenu();
|
||||||
|
menu.Items.Add(diffWithMerger);
|
||||||
|
menu.Items.Add(explore);
|
||||||
|
menu.Items.Add(new MenuItem { Header = "-" });
|
||||||
|
menu.Items.Add(resetToThisRevision);
|
||||||
|
menu.Items.Add(new MenuItem { Header = "-" });
|
||||||
|
menu.Items.Add(copyPath);
|
||||||
|
menu.Items.Add(copyFileName);
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
if (PopupHost.CanCreatePopup())
|
if (PopupHost.CanCreatePopup())
|
||||||
|
|
|
@ -12,6 +12,11 @@ namespace SourceGit.ViewModels
|
||||||
public Models.Tag Tag { get; private set; } = null;
|
public Models.Tag Tag { get; private set; } = null;
|
||||||
public List<TagTreeNode> Children { get; private set; } = [];
|
public List<TagTreeNode> Children { get; private set; } = [];
|
||||||
|
|
||||||
|
public object ToolTip
|
||||||
|
{
|
||||||
|
get => Tag?.Message;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsFolder
|
public bool IsFolder
|
||||||
{
|
{
|
||||||
get => Tag == null;
|
get => Tag == null;
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
|
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="m:Change">
|
<DataTemplate DataType="m:Change">
|
||||||
<Grid ColumnDefinitions="24,*">
|
<Grid ColumnDefinitions="24,*" Background="Transparent" ContextRequested="OnChangeContextRequested">
|
||||||
<v:ChangeStatusIcon Grid.Column="0" Width="14" Height="14" Change="{Binding}"/>
|
<v:ChangeStatusIcon Grid.Column="0" Width="14" Height="14" Change="{Binding}"/>
|
||||||
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Path}" Margin="4,0,0,0"/>
|
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Path}" Margin="4,0,0,0"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -18,5 +18,15 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is ViewModels.StashesPage vm && sender is Grid grid)
|
||||||
|
{
|
||||||
|
var menu = vm.MakeContextMenuForChange(grid.DataContext as Models.Change);
|
||||||
|
grid.OpenContextMenu(menu);
|
||||||
|
}
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
Margin="{Binding Depth, Converter={x:Static c:IntConverters.ToTreeMargin}}"
|
Margin="{Binding Depth, Converter={x:Static c:IntConverters.ToTreeMargin}}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ContextRequested="OnRowContextRequested"
|
ContextRequested="OnRowContextRequested"
|
||||||
DoubleTapped="OnDoubleTappedNode">
|
DoubleTapped="OnDoubleTappedNode"
|
||||||
|
ToolTip.Tip="{Binding ToolTip}">
|
||||||
<v:TagTreeNodeToggleButton Grid.Column="0"
|
<v:TagTreeNodeToggleButton Grid.Column="0"
|
||||||
Classes="tree_expander"
|
Classes="tree_expander"
|
||||||
Focusable="False"
|
Focusable="False"
|
||||||
|
@ -64,7 +65,10 @@
|
||||||
SelectionChanged="OnRowSelectionChanged">
|
SelectionChanged="OnRowSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate DataType="m:Tag">
|
<DataTemplate DataType="m:Tag">
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto" Background="Transparent" ContextRequested="OnRowContextRequested">
|
<Grid ColumnDefinitions="Auto,*,Auto"
|
||||||
|
Background="Transparent"
|
||||||
|
ContextRequested="OnRowContextRequested"
|
||||||
|
ToolTip.Tip="{Binding Message}">
|
||||||
<Path Grid.Column="0"
|
<Path Grid.Column="0"
|
||||||
Width="10" Height="10"
|
Width="10" Height="10"
|
||||||
Margin="8,0,0,0"
|
Margin="8,0,0,0"
|
||||||
|
|
Loading…
Reference in a new issue