refactor: external diff merge tool - supports to use difftool/mergetool settings from git config directly (#181)

This commit is contained in:
leo 2024-06-18 12:10:38 +08:00
parent 06245320a9
commit c56d0cf85e
No known key found for this signature in database
GPG key ID: B528468E49CD0E58
15 changed files with 89 additions and 163 deletions

View file

@ -6,57 +6,63 @@ namespace SourceGit.Commands
{
public static class MergeTool
{
public static bool OpenForMerge(string repo, string tool, string mergeCmd, string file)
public static bool OpenForMerge(string repo, int toolType, string toolPath, string file)
{
if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(mergeCmd))
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, "Invalid external merge tool settings!");
});
return false;
}
if (!File.Exists(tool))
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, $"Can NOT found external merge tool in '{tool}'!");
});
return false;
}
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.RaiseError = false;
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{tool}\\\" {mergeCmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit \"{file}\"";
cmd.Context = repo;
cmd.RaiseError = true;
if (toolType == 0)
{
cmd.Args = $"mergetool \"{file}\"";
return cmd.Exec();
}
public static bool OpenForDiff(string repo, string tool, string diffCmd, Models.DiffOption option)
if (!File.Exists(toolPath))
{
if (string.IsNullOrWhiteSpace(tool) || string.IsNullOrWhiteSpace(diffCmd))
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, "Invalid external merge tool settings!");
});
Dispatcher.UIThread.Post(() => App.RaiseException(repo, $"Can NOT found external merge tool in '{toolPath}'!"));
return false;
}
if (!File.Exists(tool))
var supported = Models.ExternalMerger.Supported.Find(x => x.Type == toolType);
if (supported == null)
{
Dispatcher.UIThread.Invoke(() =>
{
App.RaiseException(repo, $"Can NOT found external merge tool in '{tool}'!");
});
Dispatcher.UIThread.Post(() => App.RaiseException(repo, "Invalid merge tool in preference setting!"));
return false;
}
cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit \"{file}\"";
return cmd.Exec();
}
public static bool OpenForDiff(string repo, int toolType, string toolPath, Models.DiffOption option)
{
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.RaiseError = false;
cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{tool}\\\" {diffCmd}\" difftool --tool=sourcegit --no-prompt {option}";
cmd.Context = repo;
cmd.RaiseError = true;
if (toolType == 0)
{
cmd.Args = $"difftool -g --no-prompt {option}";
return cmd.Exec();
}
if (!File.Exists(toolPath))
{
Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, $"Can NOT found external diff tool in '{toolPath}'!"));
return false;
}
var supported = Models.ExternalMerger.Supported.Find(x => x.Type == toolType);
if (supported == null)
{
Dispatcher.UIThread.Post(() => App.RaiseException(repo, "Invalid merge tool in preference setting!"));
return false;
}
cmd.Args = $"-c difftool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.DiffCmd}\" difftool --tool=sourcegit --no-prompt {option}";
return cmd.Exec();
}
}

View file

@ -32,7 +32,7 @@ namespace SourceGit.Models
if (OperatingSystem.IsWindows())
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "custom_diff", "Custom", "", "", ""),
new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
new ExternalMerger(1, "vscode", "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(2, "vscode_insiders", "Visual Studio Code - Insiders", "Code - Insiders.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(3, "vs", "Visual Studio", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" /m", "\"$LOCAL\" \"$REMOTE\""),
@ -46,7 +46,7 @@ namespace SourceGit.Models
else if (OperatingSystem.IsMacOS())
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "custom_diff", "Custom", "", "", ""),
new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
new ExternalMerger(1, "xcode", "FileMerge", "/usr/bin/opendiff", "\"$BASE\" \"$LOCAL\" \"$REMOTE\" -ancestor \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(2, "vscode", "Visual Studio Code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(3, "vscode_insiders", "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
@ -58,7 +58,7 @@ namespace SourceGit.Models
else if (OperatingSystem.IsLinux())
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "custom_diff", "Custom", "", "", ""),
new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
new ExternalMerger(1, "vscode", "Visual Studio Code", "/usr/share/code/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(2, "vscode_insiders", "Visual Studio Code - Insiders", "/usr/share/code-insiders/code-insiders", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(3, "kdiff3", "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
@ -70,7 +70,7 @@ namespace SourceGit.Models
else
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "custom_diff", "Custom", "", "", ""),
new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
};
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -339,12 +339,10 @@
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">Input path for installed gpg program</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">User Signing Key</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">User's gpg signing key</x:String>
<x:String x:Key="Text.Preference.Merger" xml:space="preserve">EXTERNAL MERGE TOOL</x:String>
<x:String x:Key="Text.Preference.Merger.CustomDiffCmd" xml:space="preserve">Diff Command</x:String>
<x:String x:Key="Text.Preference.Merger.CustomMergeCmd" xml:space="preserve">Merge Command</x:String>
<x:String x:Key="Text.Preference.Merger.Path" xml:space="preserve">Install Path</x:String>
<x:String x:Key="Text.Preference.Merger.Path.Placeholder" xml:space="preserve">Input path for merge tool</x:String>
<x:String x:Key="Text.Preference.Merger.Type" xml:space="preserve">Merger</x:String>
<x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">DIFF/MERGE TOOL</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">Install Path</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">Input path for diff/merge tool</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Type" xml:space="preserve">Tool</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">Prune Remote</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">Target:</x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">Pull</x:String>

View file

@ -342,12 +342,10 @@
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">签名程序所在路径</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">用户签名KEY</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">输入签名提交所使用的KEY</x:String>
<x:String x:Key="Text.Preference.Merger" xml:space="preserve">外部合并工具</x:String>
<x:String x:Key="Text.Preference.Merger.CustomDiffCmd" xml:space="preserve">对比模式启动参数</x:String>
<x:String x:Key="Text.Preference.Merger.CustomMergeCmd" xml:space="preserve">合并模式启动参数</x:String>
<x:String x:Key="Text.Preference.Merger.Path" xml:space="preserve">安装路径</x:String>
<x:String x:Key="Text.Preference.Merger.Path.Placeholder" xml:space="preserve">填写工具可执行文件所在位置</x:String>
<x:String x:Key="Text.Preference.Merger.Type" xml:space="preserve">工具</x:String>
<x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">对比/合并工具</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">安装路径</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">填写工具可执行文件所在位置</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Type" xml:space="preserve">工具</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">清理远程已删除分支</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">目标 </x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">拉回(pull)</x:String>

View file

@ -342,12 +342,10 @@
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">gpg.exe所在路徑</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">使用者簽名KEY</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">輸入簽名提交所使用的KEY</x:String>
<x:String x:Key="Text.Preference.Merger" xml:space="preserve">外部合併工具</x:String>
<x:String x:Key="Text.Preference.Merger.CustomDiffCmd" xml:space="preserve">對比模式啟動引數</x:String>
<x:String x:Key="Text.Preference.Merger.CustomMergeCmd" xml:space="preserve">合併模式啟動引數</x:String>
<x:String x:Key="Text.Preference.Merger.Path" xml:space="preserve">安裝路徑</x:String>
<x:String x:Key="Text.Preference.Merger.Path.Placeholder" xml:space="preserve">填寫工具可執行檔案所在位置</x:String>
<x:String x:Key="Text.Preference.Merger.Type" xml:space="preserve">工具</x:String>
<x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">對比/合併工具</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">安裝路徑</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">填寫工具可執行檔案所在位置</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Type" xml:space="preserve">工具</x:String>
<x:String x:Key="Text.PruneRemote" xml:space="preserve">清理遠端已刪除分支</x:String>
<x:String x:Key="Text.PruneRemote.Target" xml:space="preserve">目標 </x:String>
<x:String x:Key="Text.Pull" xml:space="preserve">拉回(pull)</x:String>

View file

@ -133,19 +133,11 @@ namespace SourceGit.ViewModels
diffWithMerger.Icon = App.CreateMenuIcon("Icons.Diff");
diffWithMerger.Click += (_, ev) =>
{
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
var opt = new Models.DiffOption(Base.Head, To.Head, change);
var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec))
{
App.RaiseException(_repo, "Invalid merge tool in preference setting!");
return;
}
var args = tool.Type != 0 ? tool.DiffCmd : Preference.Instance.ExternalMergeToolDiffCmd;
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, exec, args, opt));
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt));
ev.Handled = true;
};
menu.Items.Add(diffWithMerger);

View file

@ -218,19 +218,11 @@ namespace SourceGit.ViewModels
diffWithMerger.Icon = App.CreateMenuIcon("Icons.Diff");
diffWithMerger.Click += (_, ev) =>
{
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
var opt = new Models.DiffOption(_commit, change);
var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec))
{
App.RaiseException(_repo, "Invalid merge tool in preference setting!");
return;
}
var args = tool.Type != 0 ? tool.DiffCmd : Preference.Instance.ExternalMergeToolDiffCmd;
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, exec, args, opt));
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt));
ev.Handled = true;
};
menu.Items.Add(diffWithMerger);

View file

@ -98,18 +98,9 @@ namespace SourceGit.ViewModels
public void OpenExternalMergeTool()
{
var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec))
{
App.RaiseException(_repo, "Invalid merge tool in preference setting!");
return;
}
var args = tool.Type != 0 ? tool.DiffCmd : Preference.Instance.ExternalMergeToolDiffCmd;
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, exec, args, _option));
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, _option));
}
private void LoadDiffContent()

View file

@ -290,18 +290,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _externalMergeToolPath, value);
}
public string ExternalMergeToolCmd
{
get => _externalMergeToolCmd;
set => SetProperty(ref _externalMergeToolCmd, value);
}
public string ExternalMergeToolDiffCmd
{
get => _externalMergeToolDiffCmd;
set => SetProperty(ref _externalMergeToolDiffCmd, value);
}
public List<Repository> Repositories
{
get;
@ -556,8 +544,6 @@ namespace SourceGit.ViewModels
private int _externalMergeToolType = 0;
private string _externalMergeToolPath = string.Empty;
private string _externalMergeToolCmd = string.Empty;
private string _externalMergeToolDiffCmd = string.Empty;
private AvaloniaList<RepositoryNode> _repositoryNodes = new AvaloniaList<RepositoryNode>();
}

View file

@ -142,18 +142,10 @@ namespace SourceGit.ViewModels
diffWithMerger.Click += (_, ev) =>
{
var opt = new Models.DiffOption(StartPoint.SHA, _endPoint, change);
var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath;
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec))
{
App.RaiseException(_repo, "Invalid merge tool in preference setting!");
return;
}
var args = tool.Type != 0 ? tool.DiffCmd : Preference.Instance.ExternalMergeToolDiffCmd;
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, exec, args, opt));
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, toolType, toolPath, opt));
ev.Handled = true;
};
menu.Items.Add(diffWithMerger);

View file

@ -1120,20 +1120,11 @@ namespace SourceGit.ViewModels
private async void UseExternalMergeTool(Models.Change change)
{
var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null)
{
App.RaiseException(_repo.FullPath, "Invalid merge tool in preference setting!");
return;
}
var args = tool.Type != 0 ? tool.Cmd : Preference.Instance.ExternalMergeToolCmd;
var toolType = Preference.Instance.ExternalMergeToolType;
var toolPath = Preference.Instance.ExternalMergeToolPath;
_repo.SetWatcherEnabled(false);
await Task.Run(() => Commands.MergeTool.OpenForMerge(_repo.FullPath, exec, args, change.Path));
await Task.Run(() => Commands.MergeTool.OpenForMerge(_repo.FullPath, toolType, toolPath, change.Path));
_repo.SetWatcherEnabled(true);
}

View file

@ -449,12 +449,12 @@
<TabItem>
<TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Merger}"/>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.DiffMerge}"/>
</TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,Auto,Auto" ColumnDefinitions="Auto,*">
<Grid Margin="8" RowDefinitions="32,Auto" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.Merger.Type}"
Text="{DynamicResource Text.Preference.DiffMerge.Type}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<ComboBox Grid.Row="0" Grid.Column="1"
@ -477,41 +477,22 @@
</ComboBox>
<TextBlock Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Preference.Merger.Path}"
Text="{DynamicResource Text.Preference.DiffMerge.Path}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
Margin="0,0,16,0"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
<TextBox Grid.Row="1" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding ExternalMergeToolPath, Mode=TwoWay}">
Text="{Binding ExternalMergeToolPath, Mode=TwoWay}"
Watermark="{DynamicResource Text.Preference.DiffMerge.Path.Placeholder}"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsGreaterThanZero}}">
<TextBox.InnerRightContent>
<Button Classes="icon_button" Width="30" Height="30" Click="SelectExternalMergeTool">
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
</Button>
</TextBox.InnerRightContent>
</TextBox>
<TextBlock Grid.Row="2" Grid.Column="0"
Text="{DynamicResource Text.Preference.Merger.CustomMergeCmd}"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,16,0"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
<TextBox Grid.Row="2" Grid.Column="1"
Height="28" Margin="0,2"
CornerRadius="3"
Text="{Binding ExternalMergeToolCmd, Mode=TwoWay}"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
<TextBlock Grid.Row="3" Grid.Column="0"
Text="{DynamicResource Text.Preference.Merger.CustomDiffCmd}"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,16,0"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
<TextBox Grid.Row="3" Grid.Column="1"
Height="28" Margin="0,2"
CornerRadius="3"
Text="{Binding ExternalMergeToolDiffCmd, Mode=TwoWay}"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsZero}}"/>
</Grid>
</TabItem>
</TabControl>

View file

@ -287,6 +287,7 @@ namespace SourceGit.Views
{
ViewModels.Preference.Instance.ExternalMergeToolType = 0;
type = 0;
return;
}
var tool = Models.ExternalMerger.Supported[type];