diff --git a/src/Models/ExternalMergeTools.cs b/src/Models/ExternalMergeTools.cs deleted file mode 100644 index f07ef088..00000000 --- a/src/Models/ExternalMergeTools.cs +++ /dev/null @@ -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 Supported; - - static ExternalMergeTools() - { - if (OperatingSystem.IsWindows()) - { - Supported = new List() { - 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() { - 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() { - 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() { - 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(); - var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries); - foreach (var c in choices) - { - patterns.Add(Path.GetFileName(c)); - } - return patterns.ToArray(); - } - } - } -} diff --git a/src/Models/ExternalMerger.cs b/src/Models/ExternalMerger.cs new file mode 100644 index 00000000..6643bbbb --- /dev/null +++ b/src/Models/ExternalMerger.cs @@ -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 Supported; + + static ExternalMerger() + { + if (OperatingSystem.IsWindows()) + { + Supported = new List() { + 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() { + 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() { + 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() { + 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(); + var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries); + foreach (var c in choices) + { + patterns.Add(Path.GetFileName(c)); + } + return patterns.ToArray(); + } + } + } +} diff --git a/src/Models/Shell.cs b/src/Models/Shell.cs new file mode 100644 index 00000000..9960d136 --- /dev/null +++ b/src/Models/Shell.cs @@ -0,0 +1,10 @@ +namespace SourceGit.Models +{ + public enum Shell + { + Default = 0, + PowerShell, + CommandPrompt, + DefaultShellOfWindowsTerminal, + } +} diff --git a/src/Native/OS.cs b/src/Native/OS.cs index 03b98e6d..259b6a22 100644 --- a/src/Native/OS.cs +++ b/src/Native/OS.cs @@ -21,7 +21,6 @@ namespace SourceGit.Native } public static string GitExecutable { get; set; } = string.Empty; - public static bool UsePowershellOnWindows { get; set; } = false; public static List ExternalTools { get; set; } = new List(); static OS() @@ -46,6 +45,33 @@ namespace SourceGit.Native 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) { _backend.SetupApp(builder); diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 1b5af417..fbcdb0bf 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -54,6 +54,12 @@ namespace SourceGit.Native [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)] private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, int cild, IntPtr apidl, int dwFlags); + public Models.Shell Shell + { + get; + set; + } = Models.Shell.Default; + public Windows() { var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( @@ -143,27 +149,44 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - var startInfo = new ProcessStartInfo() { UseShellExecute = true }; - if (!string.IsNullOrEmpty(workdir) && Path.Exists(workdir)) - startInfo.WorkingDirectory = workdir; + var startInfo = new ProcessStartInfo(); - if (OS.UsePowershellOnWindows) + if (!string.IsNullOrEmpty(workdir) && Path.Exists(workdir)) { - startInfo.FileName = _powershellPath; + startInfo.WorkingDirectory = workdir; } else { - 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; + startInfo.WorkingDirectory = "."; } - + + 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); } diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 08b41c0a..8277d3c5 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -266,9 +266,9 @@ User Email Global git user email Install Path + Shell User Name Global git user name - Use Powershell instead of Git bash Git version GPG SIGNING Commit GPG signing diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 8f03755b..fb7fecc3 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -266,9 +266,9 @@ 邮箱 默认GIT用户邮箱 安装路径 + 终端Shell 用户名 默认GIT用户名 - 使用PowerShell替代Git Bash Git 版本 GPG签名 启用提交签名 diff --git a/src/Resources/ShellIcons/cmd.png b/src/Resources/ShellIcons/cmd.png new file mode 100644 index 00000000..4a3aa218 Binary files /dev/null and b/src/Resources/ShellIcons/cmd.png differ diff --git a/src/Resources/ShellIcons/git-bash.png b/src/Resources/ShellIcons/git-bash.png new file mode 100644 index 00000000..1f7a2ced Binary files /dev/null and b/src/Resources/ShellIcons/git-bash.png differ diff --git a/src/Resources/ShellIcons/pwsh.png b/src/Resources/ShellIcons/pwsh.png new file mode 100644 index 00000000..67fa8c91 Binary files /dev/null and b/src/Resources/ShellIcons/pwsh.png differ diff --git a/src/Resources/ShellIcons/wt.png b/src/Resources/ShellIcons/wt.png new file mode 100644 index 00000000..3462cc6e Binary files /dev/null and b/src/Resources/ShellIcons/wt.png differ diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj index 0a3ef8a6..d439eee8 100644 --- a/src/SourceGit.csproj +++ b/src/SourceGit.csproj @@ -22,8 +22,9 @@ - + + diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index fe719517..f290fd4c 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -205,7 +205,7 @@ namespace SourceGit.ViewModels var type = Preference.Instance.ExternalMergeToolType; 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)) { App.RaiseException(_repo, "Invalid merge tool in preference setting!"); diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 728c4f43..17514656 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -152,7 +152,7 @@ namespace SourceGit.ViewModels var type = Preference.Instance.ExternalMergeToolType; 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)) { App.RaiseException(_repo, "Invalid merge tool in preference setting!"); diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index 7d97ba4f..8d0520c8 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -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 { 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 { get => _externalMergeToolType; set { 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)) ExternalMergeToolPath = tool.Exec; else diff --git a/src/ViewModels/RevisionCompare.cs b/src/ViewModels/RevisionCompare.cs index 167f3a41..1ed85c9e 100644 --- a/src/ViewModels/RevisionCompare.cs +++ b/src/ViewModels/RevisionCompare.cs @@ -166,7 +166,7 @@ namespace SourceGit.ViewModels var type = Preference.Instance.ExternalMergeToolType; 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)) { App.RaiseException(_repo, "Invalid merge tool in preference setting!"); diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 6aa9d999..a52a31df 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -423,7 +423,7 @@ namespace SourceGit.ViewModels var type = Preference.Instance.ExternalMergeToolType; 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) { App.RaiseException(_repo.FullPath, "Invalid merge tool in preference setting!"); diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index 49cd30f2..cd2d4ce1 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -231,7 +231,7 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -269,31 +307,31 @@ - - - + + + - - - - @@ -376,8 +408,8 @@ MinHeight="28" Padding="8,0" HorizontalAlignment="Stretch" - ItemsSource="{Binding Source={x:Static m:ExternalMergeTools.Supported}}" - DisplayMemberBinding="{Binding Name, x:DataType=m:ExternalMergeTools}" + ItemsSource="{Binding Source={x:Static m:ExternalMerger.Supported}}" + DisplayMemberBinding="{Binding Name, x:DataType=m:ExternalMerger}" SelectedIndex="{Binding ExternalMergeToolType, Mode=TwoWay}"/> = Models.ExternalMergeTools.Supported.Count) + if (type < 0 || type >= Models.ExternalMerger.Supported.Count) { ViewModels.Preference.Instance.ExternalMergeToolType = 0; type = 0; } - var tool = Models.ExternalMergeTools.Supported[type]; + var tool = Models.ExternalMerger.Supported[type]; var options = new FilePickerOpenOptions() { FileTypeFilter = [new FilePickerFileType(tool.Name) { Patterns = tool.GetPatterns() }],