refactor: external tools and shells

* rename Models.ExternalMergeTools to Models.ExternalMerger
* supports Git Bash/PowerShell/Command Prompt/Default Shell in Windows Terminal
This commit is contained in:
leo 2024-04-09 10:41:37 +08:00
parent 4ac705f8ca
commit 4882fd9d69
19 changed files with 243 additions and 152 deletions

View file

@ -1,88 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace SourceGit.Models
{
public class ExternalMergeTools
{
public int Type { get; set; }
public string Name { get; set; }
public string Exec { get; set; }
public string Cmd { get; set; }
public string DiffCmd { get; set; }
public static readonly List<ExternalMergeTools> Supported;
static ExternalMergeTools()
{
if (OperatingSystem.IsWindows())
{
Supported = new List<ExternalMergeTools>() {
new ExternalMergeTools(0, "Custom", "", "", ""),
new ExternalMergeTools(1, "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(2, "Visual Studio Code - Insiders", "Code - Insiders.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(3, "Visual Studio 2017/2019/2022", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" /m", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(4, "Tortoise Merge", "TortoiseMerge.exe;TortoiseGitMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", "-base:\"$LOCAL\" -theirs:\"$REMOTE\""),
new ExternalMergeTools(5, "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(6, "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(7, "WinMerge", "WinMergeU.exe", "-u -e \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsMacOS())
{
Supported = new List<ExternalMergeTools>() {
new ExternalMergeTools(0, "Custom", "", "", ""),
new ExternalMergeTools(1, "FileMerge", "/usr/bin/opendiff", "\"$BASE\" \"$LOCAL\" \"$REMOTE\" -ancestor \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(2, "Visual Studio Code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(3, "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(4, "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(5, "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsLinux())
{
Supported = new List<ExternalMergeTools>() {
new ExternalMergeTools(0, "Custom", "", "", ""),
new ExternalMergeTools(1, "Visual Studio Code", "/usr/share/code/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(2, "Visual Studio Code - Insiders", "/usr/share/code-insiders/code-insiders", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(3, "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMergeTools(4, "Beyond Compare", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
};
}
else
{
Supported = new List<ExternalMergeTools>() {
new ExternalMergeTools(0, "Custom", "", "", ""),
};
}
}
public ExternalMergeTools(int type, string name, string exec, string cmd, string diffCmd)
{
Type = type;
Name = name;
Exec = exec;
Cmd = cmd;
DiffCmd = diffCmd;
}
public string[] GetPatterns()
{
if (OperatingSystem.IsWindows())
{
return Exec.Split(';');
}
else
{
var patterns = new List<string>();
var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (var c in choices)
{
patterns.Add(Path.GetFileName(c));
}
return patterns.ToArray();
}
}
}
}

View file

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace SourceGit.Models
{
public class ExternalMerger
{
public int Type { get; set; }
public string Name { get; set; }
public string Exec { get; set; }
public string Cmd { get; set; }
public string DiffCmd { get; set; }
public static readonly List<ExternalMerger> Supported;
static ExternalMerger()
{
if (OperatingSystem.IsWindows())
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "Custom", "", "", ""),
new ExternalMerger(1, "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(2, "Visual Studio Code - Insiders", "Code - Insiders.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(3, "Visual Studio 2017/2019/2022", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" /m", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(4, "Tortoise Merge", "TortoiseMerge.exe;TortoiseGitMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", "-base:\"$LOCAL\" -theirs:\"$REMOTE\""),
new ExternalMerger(5, "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(6, "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(7, "WinMerge", "WinMergeU.exe", "-u -e \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", "-u -e \"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsMacOS())
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "Custom", "", "", ""),
new ExternalMerger(1, "FileMerge", "/usr/bin/opendiff", "\"$BASE\" \"$LOCAL\" \"$REMOTE\" -ancestor \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(2, "Visual Studio Code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(3, "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(4, "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(5, "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsLinux())
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "Custom", "", "", ""),
new ExternalMerger(1, "Visual Studio Code", "/usr/share/code/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(2, "Visual Studio Code - Insiders", "/usr/share/code-insiders/code-insiders", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(3, "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(4, "Beyond Compare", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
};
}
else
{
Supported = new List<ExternalMerger>() {
new ExternalMerger(0, "Custom", "", "", ""),
};
}
}
public ExternalMerger(int type, string name, string exec, string cmd, string diffCmd)
{
Type = type;
Name = name;
Exec = exec;
Cmd = cmd;
DiffCmd = diffCmd;
}
public string[] GetPatterns()
{
if (OperatingSystem.IsWindows())
{
return Exec.Split(';');
}
else
{
var patterns = new List<string>();
var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (var c in choices)
{
patterns.Add(Path.GetFileName(c));
}
return patterns.ToArray();
}
}
}
}

10
src/Models/Shell.cs Normal file
View file

@ -0,0 +1,10 @@
namespace SourceGit.Models
{
public enum Shell
{
Default = 0,
PowerShell,
CommandPrompt,
DefaultShellOfWindowsTerminal,
}
}

View file

@ -21,7 +21,6 @@ namespace SourceGit.Native
} }
public static string GitExecutable { get; set; } = string.Empty; public static string GitExecutable { get; set; } = string.Empty;
public static bool UsePowershellOnWindows { get; set; } = false;
public static List<Models.ExternalTool> ExternalTools { get; set; } = new List<Models.ExternalTool>(); public static List<Models.ExternalTool> ExternalTools { get; set; } = new List<Models.ExternalTool>();
static OS() static OS()
@ -46,6 +45,33 @@ namespace SourceGit.Native
ExternalTools = _backend.FindExternalTools(); ExternalTools = _backend.FindExternalTools();
} }
public static Models.Shell GetShell()
{
if (OperatingSystem.IsWindows())
{
return (_backend as Windows).Shell;
}
else
{
return Models.Shell.Default;
}
}
public static bool SetShell(Models.Shell shell)
{
if (OperatingSystem.IsWindows())
{
var windows = (_backend as Windows);
if (windows.Shell != shell)
{
windows.Shell = shell;
return true;
}
}
return false;
}
public static void SetupApp(AppBuilder builder) public static void SetupApp(AppBuilder builder)
{ {
_backend.SetupApp(builder); _backend.SetupApp(builder);

View file

@ -54,6 +54,12 @@ namespace SourceGit.Native
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)] [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, int cild, IntPtr apidl, int dwFlags); private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, int cild, IntPtr apidl, int dwFlags);
public Models.Shell Shell
{
get;
set;
} = Models.Shell.Default;
public Windows() public Windows()
{ {
var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey(
@ -143,27 +149,44 @@ namespace SourceGit.Native
public void OpenTerminal(string workdir) public void OpenTerminal(string workdir)
{ {
var startInfo = new ProcessStartInfo() { UseShellExecute = true }; var startInfo = new ProcessStartInfo();
if (!string.IsNullOrEmpty(workdir) && Path.Exists(workdir))
startInfo.WorkingDirectory = workdir;
if (OS.UsePowershellOnWindows) if (!string.IsNullOrEmpty(workdir) && Path.Exists(workdir))
{ {
startInfo.FileName = _powershellPath; startInfo.WorkingDirectory = workdir;
} }
else else
{ {
var binDir = Path.GetDirectoryName(OS.GitExecutable); startInfo.WorkingDirectory = ".";
var bash = Path.Combine(binDir, "bash.exe");
if (!File.Exists(bash))
{
App.RaiseException(string.IsNullOrEmpty(workdir) ? "" : workdir, $"Can NOT found bash.exe under '{binDir}'");
return;
}
startInfo.FileName = bash;
} }
switch (Shell)
{
case Models.Shell.Default:
var binDir = Path.GetDirectoryName(OS.GitExecutable);
var bash = Path.Combine(binDir, "bash.exe");
if (!File.Exists(bash))
{
App.RaiseException(string.IsNullOrEmpty(workdir) ? "" : workdir, $"Can NOT found bash.exe under '{binDir}'");
return;
}
startInfo.FileName = bash;
break;
case Models.Shell.PowerShell:
startInfo.FileName = _powershellPath;
break;
case Models.Shell.CommandPrompt:
startInfo.FileName = "cmd";
break;
case Models.Shell.DefaultShellOfWindowsTerminal:
startInfo.FileName = "wt";
break;
default:
App.RaiseException(string.IsNullOrEmpty(workdir) ? "" : workdir, $"Bad shell configuration!");
return;
}
Process.Start(startInfo); Process.Start(startInfo);
} }

View file

@ -266,9 +266,9 @@
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">User Email</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">User Email</x:String>
<x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">Global git user email</x:String> <x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">Global git user email</x:String>
<x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">Install Path</x:String> <x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">Install Path</x:String>
<x:String x:Key="Text.Preference.Git.Shell" xml:space="preserve">Shell</x:String>
<x:String x:Key="Text.Preference.Git.User" xml:space="preserve">User Name</x:String> <x:String x:Key="Text.Preference.Git.User" xml:space="preserve">User Name</x:String>
<x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">Global git user name</x:String> <x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">Global git user name</x:String>
<x:String x:Key="Text.Preference.Git.UsePowershellOnWindows" xml:space="preserve">Use Powershell instead of Git bash</x:String>
<x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git version</x:String> <x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git version</x:String>
<x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG SIGNING</x:String> <x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG SIGNING</x:String>
<x:String x:Key="Text.Preference.GPG.Enabled" xml:space="preserve">Commit GPG signing</x:String> <x:String x:Key="Text.Preference.GPG.Enabled" xml:space="preserve">Commit GPG signing</x:String>

View file

@ -266,9 +266,9 @@
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">邮箱</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">邮箱</x:String>
<x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">默认GIT用户邮箱</x:String> <x:String x:Key="Text.Preference.Git.Email.Placeholder" xml:space="preserve">默认GIT用户邮箱</x:String>
<x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">安装路径</x:String> <x:String x:Key="Text.Preference.Git.Path" xml:space="preserve">安装路径</x:String>
<x:String x:Key="Text.Preference.Git.Shell" xml:space="preserve">终端Shell</x:String>
<x:String x:Key="Text.Preference.Git.User" xml:space="preserve">用户名</x:String> <x:String x:Key="Text.Preference.Git.User" xml:space="preserve">用户名</x:String>
<x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">默认GIT用户名</x:String> <x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">默认GIT用户名</x:String>
<x:String x:Key="Text.Preference.Git.UsePowershellOnWindows" xml:space="preserve">使用PowerShell替代Git Bash</x:String>
<x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git 版本</x:String> <x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git 版本</x:String>
<x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG签名</x:String> <x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG签名</x:String>
<x:String x:Key="Text.Preference.GPG.Enabled" xml:space="preserve">启用提交签名</x:String> <x:String x:Key="Text.Preference.GPG.Enabled" xml:space="preserve">启用提交签名</x:String>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -22,8 +22,9 @@
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="App.ico" /> <AvaloniaResource Include="App.ico" />
<AvaloniaResource Include="Resources/Fonts/*" />
<AvaloniaResource Include="Resources/ExternalToolIcons/*" /> <AvaloniaResource Include="Resources/ExternalToolIcons/*" />
<AvaloniaResource Include="Resources/Fonts/*" />
<AvaloniaResource Include="Resources/ShellIcons/*" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -205,7 +205,7 @@ namespace SourceGit.ViewModels
var type = Preference.Instance.ExternalMergeToolType; var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath; var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMergeTools.Supported.Find(x => x.Type == type); var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec)) if (tool == null || !File.Exists(exec))
{ {
App.RaiseException(_repo, "Invalid merge tool in preference setting!"); App.RaiseException(_repo, "Invalid merge tool in preference setting!");

View file

@ -152,7 +152,7 @@ namespace SourceGit.ViewModels
var type = Preference.Instance.ExternalMergeToolType; var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath; var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMergeTools.Supported.Find(x => x.Type == type); var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec)) if (tool == null || !File.Exists(exec))
{ {
App.RaiseException(_repo, "Invalid merge tool in preference setting!"); App.RaiseException(_repo, "Invalid merge tool in preference setting!");

View file

@ -200,6 +200,18 @@ namespace SourceGit.ViewModels
} }
} }
public Models.Shell GitShell
{
get => Native.OS.GetShell();
set
{
if (Native.OS.SetShell(value))
{
OnPropertyChanged(nameof(GitShell));
}
}
}
public string GitDefaultCloneDir public string GitDefaultCloneDir
{ {
get => _gitDefaultCloneDir; get => _gitDefaultCloneDir;
@ -219,28 +231,15 @@ namespace SourceGit.ViewModels
} }
} }
public bool UsePowershellOnWindows
{
get => Native.OS.UsePowershellOnWindows;
set
{
if (Native.OS.UsePowershellOnWindows != value)
{
Native.OS.UsePowershellOnWindows = value;
OnPropertyChanged(nameof(UsePowershellOnWindows));
}
}
}
public int ExternalMergeToolType public int ExternalMergeToolType
{ {
get => _externalMergeToolType; get => _externalMergeToolType;
set set
{ {
var changed = SetProperty(ref _externalMergeToolType, value); var changed = SetProperty(ref _externalMergeToolType, value);
if (changed && !OperatingSystem.IsWindows() && value > 0 && value < Models.ExternalMergeTools.Supported.Count) if (changed && !OperatingSystem.IsWindows() && value > 0 && value < Models.ExternalMerger.Supported.Count)
{ {
var tool = Models.ExternalMergeTools.Supported[value]; var tool = Models.ExternalMerger.Supported[value];
if (File.Exists(tool.Exec)) if (File.Exists(tool.Exec))
ExternalMergeToolPath = tool.Exec; ExternalMergeToolPath = tool.Exec;
else else

View file

@ -166,7 +166,7 @@ namespace SourceGit.ViewModels
var type = Preference.Instance.ExternalMergeToolType; var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath; var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMergeTools.Supported.Find(x => x.Type == type); var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null || !File.Exists(exec)) if (tool == null || !File.Exists(exec))
{ {
App.RaiseException(_repo, "Invalid merge tool in preference setting!"); App.RaiseException(_repo, "Invalid merge tool in preference setting!");

View file

@ -423,7 +423,7 @@ namespace SourceGit.ViewModels
var type = Preference.Instance.ExternalMergeToolType; var type = Preference.Instance.ExternalMergeToolType;
var exec = Preference.Instance.ExternalMergeToolPath; var exec = Preference.Instance.ExternalMergeToolPath;
var tool = Models.ExternalMergeTools.Supported.Find(x => x.Type == type); var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
if (tool == null) if (tool == null)
{ {
App.RaiseException(_repo.FullPath, "Invalid merge tool in preference setting!"); App.RaiseException(_repo.FullPath, "Invalid merge tool in preference setting!");

View file

@ -231,7 +231,7 @@
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Git}"/> <TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.Git}"/>
</TabItem.Header> </TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,Auto,32" ColumnDefinitions="Auto,*"> <Grid Margin="8" RowDefinitions="32,32,Auto,32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.Git.Path}" Text="{DynamicResource Text.Preference.Git.Path}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
@ -254,11 +254,49 @@
<TextBlock Grid.Row="1" Grid.Column="1" <TextBlock Grid.Row="1" Grid.Column="1"
x:Name="txtVersion"/> x:Name="txtVersion"/>
<TextBlock Grid.Row="2" Grid.Column="0" <Border Grid.Row="2" Grid.Column="0"
Height="32"
IsVisible="{OnPlatform False, Windows=True}">
<TextBlock Text="{DynamicResource Text.Preference.Git.Shell}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
</Border>
<ComboBox Grid.Row="2" Grid.Column="1"
MinHeight="28"
Padding="8,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
FontSize="{Binding DefaultFontSize, Mode=OneWay}"
SelectedIndex="{Binding GitShell, Mode=TwoWay}"
IsVisible="{OnPlatform False, Windows=True}">
<ComboBox.Items>
<Grid ColumnDefinitions="Auto,*">
<Image Grid.Column="0" Width="16" Height="16" Source="/Resources/ShellIcons/git-bash.png" RenderOptions.BitmapInterpolationMode="HighQuality"/>
<TextBlock Grid.Column="1" Text="Git Bash" Margin="6,0,0,0"/>
</Grid>
<Grid ColumnDefinitions="Auto,*">
<Image Grid.Column="0" Width="16" Height="16" Source="/Resources/ShellIcons/pwsh.png" RenderOptions.BitmapInterpolationMode="HighQuality"/>
<TextBlock Grid.Column="1" Text="PowerShell" Margin="6,0,0,0"/>
</Grid>
<Grid ColumnDefinitions="Auto,*">
<Image Grid.Column="0" Width="16" Height="16" Source="/Resources/ShellIcons/cmd.png" RenderOptions.BitmapInterpolationMode="HighQuality"/>
<TextBlock Grid.Column="1" Text="Command Prompt" Margin="6,0,0,0"/>
</Grid>
<Grid ColumnDefinitions="Auto,*">
<Image Grid.Column="0" Width="16" Height="16" Source="/Resources/ShellIcons/wt.png" RenderOptions.BitmapInterpolationMode="HighQuality"/>
<TextBlock Grid.Column="1" Text="Default Shell in Windows Terminal" Margin="6,0,0,0"/>
</Grid>
</ComboBox.Items>
</ComboBox>
<TextBlock Grid.Row="3" Grid.Column="0"
Text="{DynamicResource Text.Preference.Git.DefaultCloneDir}" Text="{DynamicResource Text.Preference.Git.DefaultCloneDir}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Margin="0,0,16,0"/> Margin="0,0,16,0"/>
<TextBox Grid.Row="2" Grid.Column="1" <TextBox Grid.Row="3" Grid.Column="1"
Height="28" Height="28"
CornerRadius="3" CornerRadius="3"
Text="{Binding GitDefaultCloneDir, Mode=TwoWay}"> Text="{Binding GitDefaultCloneDir, Mode=TwoWay}">
@ -269,31 +307,31 @@
</TextBox.InnerRightContent> </TextBox.InnerRightContent>
</TextBox> </TextBox>
<TextBlock Grid.Row="3" Grid.Column="0"
Text="{DynamicResource Text.Preference.Git.User}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<TextBox Grid.Row="3" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding #me.DefaultUser, Mode=TwoWay}"
Watermark="{DynamicResource Text.Preference.Git.User.Placeholder}"/>
<TextBlock Grid.Row="4" Grid.Column="0" <TextBlock Grid.Row="4" Grid.Column="0"
Text="{DynamicResource Text.Preference.Git.Email}" Text="{DynamicResource Text.Preference.Git.User}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Margin="0,0,16,0"/> Margin="0,0,16,0"/>
<TextBox Grid.Row="4" Grid.Column="1" <TextBox Grid.Row="4" Grid.Column="1"
Height="28"
CornerRadius="3"
Text="{Binding #me.DefaultUser, Mode=TwoWay}"
Watermark="{DynamicResource Text.Preference.Git.User.Placeholder}"/>
<TextBlock Grid.Row="5" Grid.Column="0"
Text="{DynamicResource Text.Preference.Git.Email}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<TextBox Grid.Row="5" Grid.Column="1"
Height="28" Height="28"
CornerRadius="3" CornerRadius="3"
Text="{Binding #me.DefaultEmail, Mode=TwoWay}" Text="{Binding #me.DefaultEmail, Mode=TwoWay}"
Watermark="{DynamicResource Text.Preference.Git.Email.Placeholder}"/> Watermark="{DynamicResource Text.Preference.Git.Email.Placeholder}"/>
<TextBlock Grid.Row="5" Grid.Column="0" <TextBlock Grid.Row="6" Grid.Column="0"
Text="{DynamicResource Text.Preference.Git.CRLF}" Text="{DynamicResource Text.Preference.Git.CRLF}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Margin="0,0,16,0"/> Margin="0,0,16,0"/>
<ComboBox Grid.Row="5" Grid.Column="1" <ComboBox Grid.Row="6" Grid.Column="1"
MinHeight="28" MinHeight="28"
Padding="8,0" Padding="8,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
@ -309,12 +347,6 @@
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</ComboBox> </ComboBox>
<CheckBox Grid.Row="6" Grid.Column="1"
Height="32"
Content="{DynamicResource Text.Preference.Git.UsePowershellOnWindows}"
IsChecked="{Binding UsePowershellOnWindows, Mode=TwoWay}"
IsVisible="{OnPlatform False, Windows=True}"/>
<CheckBox Grid.Row="7" Grid.Column="1" <CheckBox Grid.Row="7" Grid.Column="1"
Content="{DynamicResource Text.Preference.Git.AutoFetch}" Content="{DynamicResource Text.Preference.Git.AutoFetch}"
IsChecked="{Binding GitAutoFetch, Mode=TwoWay}"/> IsChecked="{Binding GitAutoFetch, Mode=TwoWay}"/>
@ -376,8 +408,8 @@
MinHeight="28" MinHeight="28"
Padding="8,0" Padding="8,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding Source={x:Static m:ExternalMergeTools.Supported}}" ItemsSource="{Binding Source={x:Static m:ExternalMerger.Supported}}"
DisplayMemberBinding="{Binding Name, x:DataType=m:ExternalMergeTools}" DisplayMemberBinding="{Binding Name, x:DataType=m:ExternalMerger}"
SelectedIndex="{Binding ExternalMergeToolType, Mode=TwoWay}"/> SelectedIndex="{Binding ExternalMergeToolType, Mode=TwoWay}"/>
<TextBlock Grid.Row="1" Grid.Column="0" <TextBlock Grid.Row="1" Grid.Column="0"

View file

@ -222,13 +222,13 @@ namespace SourceGit.Views
private async void SelectExternalMergeTool(object sender, RoutedEventArgs e) private async void SelectExternalMergeTool(object sender, RoutedEventArgs e)
{ {
var type = ViewModels.Preference.Instance.ExternalMergeToolType; var type = ViewModels.Preference.Instance.ExternalMergeToolType;
if (type < 0 || type >= Models.ExternalMergeTools.Supported.Count) if (type < 0 || type >= Models.ExternalMerger.Supported.Count)
{ {
ViewModels.Preference.Instance.ExternalMergeToolType = 0; ViewModels.Preference.Instance.ExternalMergeToolType = 0;
type = 0; type = 0;
} }
var tool = Models.ExternalMergeTools.Supported[type]; var tool = Models.ExternalMerger.Supported[type];
var options = new FilePickerOpenOptions() var options = new FilePickerOpenOptions()
{ {
FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = tool.GetPatterns() }], FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = tool.GetPatterns() }],