From 4ac705f8ca456f5a339aa8b449b404f4e281734c Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 8 Apr 2024 17:39:52 +0800 Subject: [PATCH 01/35] feature: add powershell support for Windows --- README.md | 10 ++-- .../{ExternalEditor.cs => ExternalTool.cs} | 12 ++--- src/Native/Linux.cs | 6 +-- src/Native/MacOS.cs | 6 +-- src/Native/OS.cs | 7 +-- src/Native/Windows.cs | 48 +++++++++++++------ src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/ViewModels/Preference.cs | 13 +++++ src/ViewModels/Repository.cs | 16 +++---- src/Views/Preference.axaml | 8 +++- src/Views/Repository.axaml | 2 +- src/Views/Repository.axaml.cs | 4 +- 13 files changed, 88 insertions(+), 46 deletions(-) rename src/Models/{ExternalEditor.cs => ExternalTool.cs} (86%) diff --git a/README.md b/README.md index 351fecb0..9af7f471 100644 --- a/README.md +++ b/README.md @@ -53,20 +53,20 @@ For **Linux** users: * Maybe you need to set environment variable `AVALONIA_SCREEN_SCALE_FACTORS`. See https://github.com/AvaloniaUI/Avalonia/wiki/Configuring-X11-per-monitor-DPI. * Modify `SourceGit.desktop.template` (replace SOURCEGIT_LOCAL_FOLDER with real path) and move it into `~/.local/share/applications`. -## External Editors +## External Tools -This app supports open repository in external editors listed in the table below. +This app supports open repository in external tools listed in the table below. -| Editor | Windows | macOS | Linux | Environment Variable | +| Tool | Windows | macOS | Linux | Environment Variable | | --- | --- | --- | --- | --- | | Visual Studio Code | YES | YES | YES | VSCODE_PATH | | Visual Studio Code - Insiders | YES | YES | YES | VSCODE_INSIDERS_PATH | | JetBrains Fleet | YES | YES | YES | FLEET_PATH | | Sublime Text | YES | YES | YES | SUBLIME_TEXT_PATH | -You can set the given environment variable for special editor if it can NOT be found by this app automatically. +You can set the given environment variable for special tool if it can NOT be found by this app automatically. -## Screen Shots +## Screenshots * Dark Theme diff --git a/src/Models/ExternalEditor.cs b/src/Models/ExternalTool.cs similarity index 86% rename from src/Models/ExternalEditor.cs rename to src/Models/ExternalTool.cs index 094d0a5f..5383a6bf 100644 --- a/src/Models/ExternalEditor.cs +++ b/src/Models/ExternalTool.cs @@ -5,7 +5,7 @@ using System.IO; namespace SourceGit.Models { - public class ExternalEditor + public class ExternalTool { public string Name { get; set; } = string.Empty; public string Icon { get; set; } = string.Empty; @@ -24,13 +24,13 @@ namespace SourceGit.Models } } - public class ExternalEditorFinder + public class ExternalToolsFinder { - public List Editors + public List Founded { get; private set; - } = new List(); + } = new List(); public void VSCode(Func platform_finder) { @@ -52,7 +52,7 @@ namespace SourceGit.Models TryAdd("Sublime Text", "sublime_text.png", "\"{0}\"", "SUBLIME_TEXT_PATH", platform_finder); } - private void TryAdd(string name, string icon, string args, string env, Func finder) + public void TryAdd(string name, string icon, string args, string env, Func finder) { var path = Environment.GetEnvironmentVariable(env); if (string.IsNullOrEmpty(path) || !File.Exists(path)) @@ -62,7 +62,7 @@ namespace SourceGit.Models return; } - Editors.Add(new ExternalEditor + Founded.Add(new ExternalTool { Name = name, Icon = icon, diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 56d42306..df5d753f 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -31,14 +31,14 @@ namespace SourceGit.Native return string.Empty; } - public List FindExternalEditors() + public List FindExternalTools() { - var finder = new Models.ExternalEditorFinder(); + var finder = new Models.ExternalToolsFinder(); finder.VSCode(() => "/usr/share/code/code"); finder.VSCodeInsiders(() => "/usr/share/code-insiders/code-insiders"); finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox/apps/fleet/bin/Fleet"); finder.SublimeText(() => File.Exists("/usr/bin/subl") ? "/usr/bin/subl" : "/usr/local/bin/subl"); - return finder.Editors; + return finder.Founded; } public void OpenBrowser(string url) diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs index ac864986..28519e40 100644 --- a/src/Native/MacOS.cs +++ b/src/Native/MacOS.cs @@ -28,14 +28,14 @@ namespace SourceGit.Native return string.Empty; } - public List FindExternalEditors() + public List FindExternalTools() { - var finder = new Models.ExternalEditorFinder(); + var finder = new Models.ExternalToolsFinder(); finder.VSCode(() => "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"); finder.VSCodeInsiders(() => "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"); finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Applications/Fleet.app/Contents/MacOS/Fleet"); finder.SublimeText(() => "/Applications/Sublime Text.app/Contents/SharedSupport/bin"); - return finder.Editors; + return finder.Founded; } public void OpenBrowser(string url) diff --git a/src/Native/OS.cs b/src/Native/OS.cs index 61a33ed6..03b98e6d 100644 --- a/src/Native/OS.cs +++ b/src/Native/OS.cs @@ -12,7 +12,7 @@ namespace SourceGit.Native void SetupApp(AppBuilder builder); string FindGitExecutable(); - List FindExternalEditors(); + List FindExternalTools(); void OpenTerminal(string workdir); void OpenInFileManager(string path, bool select); @@ -21,7 +21,8 @@ namespace SourceGit.Native } public static string GitExecutable { get; set; } = string.Empty; - public static List ExternalEditors { get; set; } = new List(); + public static bool UsePowershellOnWindows { get; set; } = false; + public static List ExternalTools { get; set; } = new List(); static OS() { @@ -42,7 +43,7 @@ namespace SourceGit.Native throw new Exception("Platform unsupported!!!"); } - ExternalEditors = _backend.FindExternalEditors(); + ExternalTools = _backend.FindExternalTools(); } public static void SetupApp(AppBuilder builder) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 78fef704..1b5af417 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -54,6 +54,16 @@ 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 Windows() + { + var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( + Microsoft.Win32.RegistryHive.LocalMachine, + Microsoft.Win32.RegistryView.Registry64); + + var pwsh = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\pwsh.exe"); + _powershellPath = pwsh != null ? pwsh.GetValue(null) as string : "powershell"; + } + public void SetupApp(AppBuilder builder) { builder.With(new FontManagerOptions() @@ -114,14 +124,14 @@ namespace SourceGit.Native return null; } - public List FindExternalEditors() + public List FindExternalTools() { - var finder = new Models.ExternalEditorFinder(); + var finder = new Models.ExternalToolsFinder(); finder.VSCode(FindVSCode); finder.VSCodeInsiders(FindVSCodeInsiders); finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\Programs\\Fleet\\Fleet.exe"); finder.SublimeText(FindSublimeText); - return finder.Editors; + return finder.Founded; } public void OpenBrowser(string url) @@ -133,19 +143,27 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - 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; - } - - var startInfo = new ProcessStartInfo(); - startInfo.UseShellExecute = true; - startInfo.FileName = bash; + var startInfo = new ProcessStartInfo() { UseShellExecute = true }; if (!string.IsNullOrEmpty(workdir) && Path.Exists(workdir)) startInfo.WorkingDirectory = workdir; + + if (OS.UsePowershellOnWindows) + { + startInfo.FileName = _powershellPath; + } + 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; + } + Process.Start(startInfo); } @@ -281,5 +299,7 @@ namespace SourceGit.Native ILFree(pidl); } } + + private string _powershellPath = string.Empty; } } diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 68e57b4c..08b41c0a 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -268,6 +268,7 @@ Install Path 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 79cf9973..8f03755b 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -268,6 +268,7 @@ 安装路径 用户名 默认GIT用户名 + 使用PowerShell替代Git Bash Git 版本 GPG签名 启用提交签名 diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index ee8f96a9..7d97ba4f 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -219,6 +219,19 @@ 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; diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 61f034ff..89740d7d 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -287,10 +287,10 @@ namespace SourceGit.ViewModels Native.OS.OpenTerminal(_fullpath); } - public ContextMenu CreateContextMenuForExternalEditors() + public ContextMenu CreateContextMenuForExternalTools() { - var editors = Native.OS.ExternalEditors; - if (editors.Count == 0) + var tools = Native.OS.ExternalTools; + if (tools.Count == 0) { App.RaiseException(_fullpath, "No available external editors found!"); return null; @@ -300,16 +300,16 @@ namespace SourceGit.ViewModels menu.Placement = PlacementMode.BottomEdgeAlignedLeft; RenderOptions.SetBitmapInterpolationMode(menu, BitmapInterpolationMode.HighQuality); - foreach (var editor in editors) + foreach (var tool in tools) { - var dupEditor = editor; - var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/ExternalToolIcons/{dupEditor.Icon}", UriKind.RelativeOrAbsolute)); + var dupTool = tool; + var icon = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/ExternalToolIcons/{dupTool.Icon}", UriKind.RelativeOrAbsolute)); var item = new MenuItem(); - item.Header = App.Text("Repository.OpenIn", dupEditor.Name); + item.Header = App.Text("Repository.OpenIn", dupTool.Name); item.Icon = new Image { Width = 16, Height = 16, Source = new Bitmap(icon) }; item.Click += (o, e) => { - dupEditor.Open(_fullpath); + dupTool.Open(_fullpath); e.Handled = true; }; diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index 24d10e8d..49cd30f2 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -231,7 +231,7 @@ - + + + diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index 4bfb98a6..d618ea4c 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -22,7 +22,7 @@ - diff --git a/src/Views/Repository.axaml.cs b/src/Views/Repository.axaml.cs index 858f5f3d..43d9ee11 100644 --- a/src/Views/Repository.axaml.cs +++ b/src/Views/Repository.axaml.cs @@ -61,11 +61,11 @@ namespace SourceGit.Views InitializeComponent(); } - private void OnOpenWithExternalEditor(object sender, RoutedEventArgs e) + private void OnOpenWithExternalTools(object sender, RoutedEventArgs e) { if (sender is Button button && DataContext is ViewModels.Repository repo) { - var menu = repo.CreateContextMenuForExternalEditors(); + var menu = repo.CreateContextMenuForExternalTools(); if (menu != null) { menu.Open(button); From 4882fd9d69ddbd0e53563cc4f22311b3c83516a0 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 10:41:37 +0800 Subject: [PATCH 02/35] refactor: external tools and shells * rename Models.ExternalMergeTools to Models.ExternalMerger * supports Git Bash/PowerShell/Command Prompt/Default Shell in Windows Terminal --- src/Models/ExternalMergeTools.cs | 88 -------------------------- src/Models/ExternalMerger.cs | 88 ++++++++++++++++++++++++++ src/Models/Shell.cs | 10 +++ src/Native/OS.cs | 28 +++++++- src/Native/Windows.cs | 53 +++++++++++----- src/Resources/Locales/en_US.axaml | 2 +- src/Resources/Locales/zh_CN.axaml | 2 +- src/Resources/ShellIcons/cmd.png | Bin 0 -> 2263 bytes src/Resources/ShellIcons/git-bash.png | Bin 0 -> 3512 bytes src/Resources/ShellIcons/pwsh.png | Bin 0 -> 9517 bytes src/Resources/ShellIcons/wt.png | Bin 0 -> 2485 bytes src/SourceGit.csproj | 3 +- src/ViewModels/CommitDetail.cs | 2 +- src/ViewModels/DiffContext.cs | 2 +- src/ViewModels/Preference.cs | 29 ++++----- src/ViewModels/RevisionCompare.cs | 2 +- src/ViewModels/WorkingCopy.cs | 2 +- src/Views/Preference.axaml | 80 ++++++++++++++++------- src/Views/Preference.axaml.cs | 4 +- 19 files changed, 243 insertions(+), 152 deletions(-) delete mode 100644 src/Models/ExternalMergeTools.cs create mode 100644 src/Models/ExternalMerger.cs create mode 100644 src/Models/Shell.cs create mode 100644 src/Resources/ShellIcons/cmd.png create mode 100644 src/Resources/ShellIcons/git-bash.png create mode 100644 src/Resources/ShellIcons/pwsh.png create mode 100644 src/Resources/ShellIcons/wt.png 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 0000000000000000000000000000000000000000..4a3aa2189625eb96ecc0686893a0791cf1f9cadc GIT binary patch literal 2263 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 literal 0 HcmV?d00001 diff --git a/src/Resources/ShellIcons/wt.png b/src/Resources/ShellIcons/wt.png new file mode 100644 index 0000000000000000000000000000000000000000..3462cc6e3d12ce670fab0f7b127c79665fc91fb6 GIT binary patch literal 2485 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 literal 0 HcmV?d00001 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() }], From a3c81745aa23a957281b7926b3bd78244c4144b5 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 10:49:36 +0800 Subject: [PATCH 03/35] enhance: add -WorkingDirectory and -Nologo arguments for PowerShell --- src/Native/Windows.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index fbcdb0bf..a14b6cc7 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -149,16 +149,13 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - var startInfo = new ProcessStartInfo(); + if (string.IsNullOrEmpty(workdir) || !Path.Exists(workdir)) + { + workdir = "."; + } - if (!string.IsNullOrEmpty(workdir) && Path.Exists(workdir)) - { - startInfo.WorkingDirectory = workdir; - } - else - { - startInfo.WorkingDirectory = "."; - } + var startInfo = new ProcessStartInfo(); + startInfo.WorkingDirectory = workdir; switch (Shell) { @@ -167,7 +164,7 @@ namespace SourceGit.Native var bash = Path.Combine(binDir, "bash.exe"); if (!File.Exists(bash)) { - App.RaiseException(string.IsNullOrEmpty(workdir) ? "" : workdir, $"Can NOT found bash.exe under '{binDir}'"); + App.RaiseException(workdir, $"Can NOT found bash.exe under '{binDir}'"); return; } @@ -175,6 +172,7 @@ namespace SourceGit.Native break; case Models.Shell.PowerShell: startInfo.FileName = _powershellPath; + startInfo.Arguments = $"-WorkingDirectory \"{workdir}\" -Nologo"; break; case Models.Shell.CommandPrompt: startInfo.FileName = "cmd"; @@ -183,7 +181,7 @@ namespace SourceGit.Native startInfo.FileName = "wt"; break; default: - App.RaiseException(string.IsNullOrEmpty(workdir) ? "" : workdir, $"Bad shell configuration!"); + App.RaiseException(workdir, $"Bad shell configuration!"); return; } From 5c9b92c3dbc1e0235a1a673ddde6050101865197 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 11:12:22 +0800 Subject: [PATCH 04/35] fix: the system default powershell.exe does not recognize the -WorkingDirectory arg --- src/Native/Windows.cs | 44 +++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index a14b6cc7..a0b5fbe0 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -60,16 +60,6 @@ namespace SourceGit.Native set; } = Models.Shell.Default; - public Windows() - { - var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( - Microsoft.Win32.RegistryHive.LocalMachine, - Microsoft.Win32.RegistryView.Registry64); - - var pwsh = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\pwsh.exe"); - _powershellPath = pwsh != null ? pwsh.GetValue(null) as string : "powershell"; - } - public void SetupApp(AppBuilder builder) { builder.With(new FontManagerOptions() @@ -171,8 +161,8 @@ namespace SourceGit.Native startInfo.FileName = bash; break; case Models.Shell.PowerShell: - startInfo.FileName = _powershellPath; - startInfo.Arguments = $"-WorkingDirectory \"{workdir}\" -Nologo"; + startInfo.FileName = ChoosePowerShell(); + startInfo.Arguments = startInfo.FileName.EndsWith("pswd.exe") ? $"-WorkingDirectory \"{workdir}\" -Nologo" : "-Nologo"; break; case Models.Shell.CommandPrompt: startInfo.FileName = "cmd"; @@ -228,6 +218,36 @@ namespace SourceGit.Native Process.Start(start); } + // There's two version of PowerShell : pwsh.exe (preferred) and powershell.exe (system default) + private string ChoosePowerShell() + { + if (!string.IsNullOrEmpty(_powershellPath)) return _powershellPath; + + var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( + Microsoft.Win32.RegistryHive.LocalMachine, + Microsoft.Win32.RegistryView.Registry64); + + var pwsh = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\pwsh.exe"); + if (pwsh != null) + { + var path = pwsh.GetValue(null) as string; + if (File.Exists(path)) + { + _powershellPath = path; + return _powershellPath; + } + } + + var finder = new StringBuilder("powershell.exe", 512); + if (PathFindOnPath(finder, null)) + { + _powershellPath = finder.ToString(); + return _powershellPath; + } + + return string.Empty; + } + #region EXTERNAL_EDITOR_FINDER private string FindVSCode() { From 3fd1e0ea19aecb385abc49a9bc1043bced0bf8c5 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 11:18:16 +0800 Subject: [PATCH 05/35] fix: Windows Terminal is not a built-in app on Windows 10 --- src/Native/Windows.cs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index a0b5fbe0..1fdadb30 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -168,7 +168,14 @@ namespace SourceGit.Native startInfo.FileName = "cmd"; break; case Models.Shell.DefaultShellOfWindowsTerminal: - startInfo.FileName = "wt"; + var wt = FindWindowsTerminalApp(); + if (!File.Exists(wt)) + { + App.RaiseException(workdir, $"Can NOT found wt.exe on your system!"); + return; + } + + startInfo.FileName = FindWindowsTerminalApp(); break; default: App.RaiseException(workdir, $"Bad shell configuration!"); @@ -221,7 +228,8 @@ namespace SourceGit.Native // There's two version of PowerShell : pwsh.exe (preferred) and powershell.exe (system default) private string ChoosePowerShell() { - if (!string.IsNullOrEmpty(_powershellPath)) return _powershellPath; + if (!string.IsNullOrEmpty(_powershellPath)) + return _powershellPath; var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey( Microsoft.Win32.RegistryHive.LocalMachine, @@ -248,6 +256,21 @@ namespace SourceGit.Native return string.Empty; } + private string FindWindowsTerminalApp() + { + if (!string.IsNullOrEmpty(_wtPath)) + return _wtPath; + + var finder = new StringBuilder("wt.exe", 512); + if (PathFindOnPath(finder, null)) + { + _wtPath = finder.ToString(); + return _wtPath; + } + + return string.Empty; + } + #region EXTERNAL_EDITOR_FINDER private string FindVSCode() { @@ -342,5 +365,6 @@ namespace SourceGit.Native } private string _powershellPath = string.Empty; + private string _wtPath = string.Empty; } } From 395bd29084edc30486a9734920e6d21d015cc7e2 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 13:06:27 +0800 Subject: [PATCH 06/35] feature: add supports to deepin-terminal --- src/Native/Linux.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 56d42306..90fdf8e4 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -89,9 +89,13 @@ namespace SourceGit.Native { Process.Start("/usr/bin/xfce4-terminal", $"--working-directory=\"{dir}\""); } + else if (File.Exists("/usr/bin/deepin-terminal")) + { + Process.Start("/usr/bin/deepin-terminal", $"--work-directory=\"{dir}\""); + } else { - App.RaiseException("", $"Only supports gnome-terminal/konsole/xfce4-terminal!"); + App.RaiseException(dir, $"Only supports gnome-terminal/konsole/xfce4-terminal/deepin-terminal!"); return; } } From 6811103cf48c8d05ad60d2be21087ef5b69bb97d Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 13:34:42 +0800 Subject: [PATCH 07/35] ux: use RenderOptions.BitmapInterpolationMode="HighQuality" for shell icons --- src/Native/Windows.cs | 4 +++- src/Views/Preference.axaml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 1fdadb30..e2dbc5d2 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -225,7 +225,7 @@ namespace SourceGit.Native Process.Start(start); } - // There's two version of PowerShell : pwsh.exe (preferred) and powershell.exe (system default) + // There are two versions of PowerShell : pwsh.exe (preferred) and powershell.exe (system default) private string ChoosePowerShell() { if (!string.IsNullOrEmpty(_powershellPath)) @@ -332,6 +332,7 @@ namespace SourceGit.Native Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry64); + // Sublime Text 4 var sublime = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sublime Text_is1"); if (sublime != null) { @@ -339,6 +340,7 @@ namespace SourceGit.Native return Path.Combine(Path.GetDirectoryName(icon), "subl.exe"); } + // Sublime Text 3 var sublime3 = localMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sublime Text 3_is1"); if (sublime3 != null) { diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index cd2d4ce1..a6918a1a 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -266,6 +266,7 @@ Padding="8,0" HorizontalAlignment="Stretch" HorizontalContentAlignment="Left" + RenderOptions.BitmapInterpolationMode="HighQuality" FontSize="{Binding DefaultFontSize, Mode=OneWay}" SelectedIndex="{Binding GitShell, Mode=TwoWay}" IsVisible="{OnPlatform False, Windows=True}"> From 7be7ef161b62d24b3304c56cb5f46e21f48de76b Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 13:59:55 +0800 Subject: [PATCH 08/35] fix: deepin-terminal commandline argument format --- src/Native/Linux.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 90fdf8e4..7a31ebc5 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -91,7 +91,7 @@ namespace SourceGit.Native } else if (File.Exists("/usr/bin/deepin-terminal")) { - Process.Start("/usr/bin/deepin-terminal", $"--work-directory=\"{dir}\""); + Process.Start("/usr/bin/deepin-terminal", $"--work-directory \"{dir}\""); } else { From 7336a870f7f0c6316a6f5603086c6e3c166a506f Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 9 Apr 2024 14:36:32 +0800 Subject: [PATCH 09/35] ux: macOS main menu position --- src/Views/Launcher.axaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Views/Launcher.axaml b/src/Views/Launcher.axaml index cb396c43..ab3e9dd0 100644 --- a/src/Views/Launcher.axaml +++ b/src/Views/Launcher.axaml @@ -49,10 +49,11 @@ - - - - - From 972b9407424fbbef4081576ddeaa219652c8d6ea Mon Sep 17 00:00:00 2001 From: Gadfly Date: Fri, 12 Apr 2024 19:37:06 +0800 Subject: [PATCH 24/35] fix: GPG executable file input didn't echo after selected --- src/Views/Preference.axaml.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Views/Preference.axaml.cs b/src/Views/Preference.axaml.cs index 7b50b9a1..1dd77b50 100644 --- a/src/Views/Preference.axaml.cs +++ b/src/Views/Preference.axaml.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Threading.Tasks; - +using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Input; @@ -52,10 +51,13 @@ namespace SourceGit.Views set; } + public static readonly StyledProperty GPGExecutableFileProperty = + AvaloniaProperty.Register(nameof(GPGExecutableFile)); + public string GPGExecutableFile { - get; - set; + get => GetValue(GPGExecutableFileProperty); + set => SetValue(GPGExecutableFileProperty, value); } public string GPGUserKey From a249eed1ac3028123a04310afff791269b63bd4a Mon Sep 17 00:00:00 2001 From: Gadfly Date: Fri, 12 Apr 2024 21:38:36 +0800 Subject: [PATCH 25/35] feat: show git file mode change if exist --- src/Commands/Diff.cs | 17 +++++++++++++++++ src/Converters/ObjectConverters.cs | 13 +++++++++++++ src/Models/DiffResult.cs | 7 +++++++ src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/ViewModels/DiffContext.cs | 13 +++++++++++++ src/Views/DiffView.axaml | 11 +++++++++-- 7 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/Converters/ObjectConverters.cs diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 090eba98..4984e3db 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using SourceGit.Models; namespace SourceGit.Commands { @@ -46,6 +47,22 @@ namespace SourceGit.Commands protected override void OnReadline(string line) { + if (line.StartsWith("old mode ", StringComparison.Ordinal)) + { + _result.FileModeDiff ??= new FileModeDiff(); + + _result.FileModeDiff.Old = line.Substring(9); + return; + } + + if (line.StartsWith("new mode ", StringComparison.Ordinal)) + { + _result.FileModeDiff ??= new FileModeDiff(); + + _result.FileModeDiff.New = line.Substring(9); + return; + } + if (_result.IsBinary) return; diff --git a/src/Converters/ObjectConverters.cs b/src/Converters/ObjectConverters.cs new file mode 100644 index 00000000..8b11ef93 --- /dev/null +++ b/src/Converters/ObjectConverters.cs @@ -0,0 +1,13 @@ +using Avalonia.Data.Converters; + +namespace SourceGit.Converters +{ + public static class ObjectConverters + { + public static readonly FuncValueConverter IsNull = + new FuncValueConverter(v => v == null); + + public static readonly FuncValueConverter IsNotNull = + new FuncValueConverter(v => v != null); + } +} diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs index 8cceced8..3325a841 100644 --- a/src/Models/DiffResult.cs +++ b/src/Models/DiffResult.cs @@ -576,11 +576,18 @@ namespace SourceGit.Models { } + public class FileModeDiff + { + public string Old { get; set; } = string.Empty; + public string New { get; set; } = string.Empty; + } + public class DiffResult { public bool IsBinary { get; set; } = false; public bool IsLFS { get; set; } = false; public TextDiff TextDiff { get; set; } = null; public LFSDiff LFSDiff { get; set; } = null; + public FileModeDiff FileModeDiff { get; set; } = null; } } diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 870868ac..10d632f6 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -131,6 +131,7 @@ NEW OLD Copy + File Mode Changed : LFS OBJECT CHANGE Next Difference NO CHANGES OR ONLY EOL CHANGES diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 330961f9..ede3aa65 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -131,6 +131,7 @@ 当前大小 原始大小 复制 + 文件权限已变化 : LFS对象变更 下一个差异 没有变更或仅有换行符差异 diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 17514656..19449cc9 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -7,6 +7,7 @@ using Avalonia.Media.Imaging; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; +using SourceGit.Models; namespace SourceGit.ViewModels { @@ -66,6 +67,12 @@ namespace SourceGit.ViewModels set => SetProperty(ref _syncScrollOffset, value); } + public Models.FileModeDiff FileModeDiff + { + get => _fileModeDiff; + set => SetProperty(ref _fileModeDiff, value); + } + public DiffContext(string repo, Models.DiffOption option, DiffContext previous = null) { _repo = repo; @@ -86,6 +93,11 @@ namespace SourceGit.ViewModels var latest = new Commands.Diff(repo, option).Result(); var rs = null as object; + if (latest.FileModeDiff != null) + { + FileModeDiff = latest.FileModeDiff; + } + if (latest.TextDiff != null) { latest.TextDiff.File = _option.Path; @@ -180,5 +192,6 @@ namespace SourceGit.ViewModels private bool _isTextDiff = false; private object _content = null; private Vector _syncScrollOffset = Vector.Zero; + private Models.FileModeDiff _fileModeDiff = null; } } diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index 04fff7a9..571098c1 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -13,7 +13,7 @@ - + @@ -26,7 +26,14 @@ - + + + + + + + + Date: Fri, 12 Apr 2024 21:58:54 +0800 Subject: [PATCH 26/35] fix: change file mode status postion to right --- src/Views/DiffView.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index 571098c1..fdbf4169 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -13,7 +13,7 @@ - + From f7dd856e497b699e6d08a8c78be1e94ac5240dbe Mon Sep 17 00:00:00 2001 From: Gadfly Date: Sat, 13 Apr 2024 01:33:44 +0800 Subject: [PATCH 27/35] fix: enhance diff view by truncating long file paths with ellipsis and adding tooltips for full path display --- src/Views/DiffView.axaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index fdbf4169..80e9f56c 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -20,11 +20,12 @@ - - - - - + + + + + From f4e1e0fb6bf860324d0af334bcf4bca4fecbbde8 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Sat, 13 Apr 2024 02:05:26 +0800 Subject: [PATCH 28/35] fix: use TextTrimming alternative PathConverters --- src/ViewModels/DiffContext.cs | 7 +++++++ src/Views/DiffView.axaml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 19449cc9..7c2aab14 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -3,6 +3,7 @@ using System.IO; using System.Threading.Tasks; using Avalonia; +using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Threading; @@ -73,6 +74,11 @@ namespace SourceGit.ViewModels set => SetProperty(ref _fileModeDiff, value); } + public TextTrimming PathTrimming + { + get => _pathTrimming; + } + public DiffContext(string repo, Models.DiffOption option, DiffContext previous = null) { _repo = repo; @@ -193,5 +199,6 @@ namespace SourceGit.ViewModels private object _content = null; private Vector _syncScrollOffset = Vector.Zero; private Models.FileModeDiff _fileModeDiff = null; + private TextTrimming _pathTrimming = new TextLeadingPrefixTrimming("...", 20); } } diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index 80e9f56c..cb56de34 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -22,8 +22,8 @@ - + From 54c95529855d4c887ec598555976ebe06999bfba Mon Sep 17 00:00:00 2001 From: Gadfly Date: Sat, 13 Apr 2024 18:54:46 +0800 Subject: [PATCH 29/35] refactor: remove duplicate ObjectConverters, remove unused using --- src/Converters/ObjectConverters.cs | 13 ------------- src/ViewModels/DiffContext.cs | 7 +------ src/Views/DiffView.axaml | 2 +- 3 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 src/Converters/ObjectConverters.cs diff --git a/src/Converters/ObjectConverters.cs b/src/Converters/ObjectConverters.cs deleted file mode 100644 index 8b11ef93..00000000 --- a/src/Converters/ObjectConverters.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Avalonia.Data.Converters; - -namespace SourceGit.Converters -{ - public static class ObjectConverters - { - public static readonly FuncValueConverter IsNull = - new FuncValueConverter(v => v == null); - - public static readonly FuncValueConverter IsNotNull = - new FuncValueConverter(v => v != null); - } -} diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 7c2aab14..e0c9de25 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -8,7 +8,6 @@ using Avalonia.Media.Imaging; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; -using SourceGit.Models; namespace SourceGit.ViewModels { @@ -74,10 +73,7 @@ namespace SourceGit.ViewModels set => SetProperty(ref _fileModeDiff, value); } - public TextTrimming PathTrimming - { - get => _pathTrimming; - } + public TextTrimming PathTrimming { get; } = new TextLeadingPrefixTrimming("...", 20); public DiffContext(string repo, Models.DiffOption option, DiffContext previous = null) { @@ -199,6 +195,5 @@ namespace SourceGit.ViewModels private object _content = null; private Vector _syncScrollOffset = Vector.Zero; private Models.FileModeDiff _fileModeDiff = null; - private TextTrimming _pathTrimming = new TextLeadingPrefixTrimming("...", 20); } } diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index cb56de34..568d47b8 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -27,7 +27,7 @@ - + From 7b5534a267ed6ea3147d6cfd2f73a9f52643c101 Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 13 Apr 2024 19:24:45 +0800 Subject: [PATCH 30/35] code_style: run `dotnet format` to apply rules defined in .editorconfig --- src/Commands/Diff.cs | 7 ++----- src/ViewModels/WorkingCopy.cs | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 4984e3db..3846e4bb 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using SourceGit.Models; namespace SourceGit.Commands { @@ -49,16 +48,14 @@ namespace SourceGit.Commands { if (line.StartsWith("old mode ", StringComparison.Ordinal)) { - _result.FileModeDiff ??= new FileModeDiff(); - + _result.FileModeDiff ??= new Models.FileModeDiff(); _result.FileModeDiff.Old = line.Substring(9); return; } if (line.StartsWith("new mode ", StringComparison.Ordinal)) { - _result.FileModeDiff ??= new FileModeDiff(); - + _result.FileModeDiff ??= new Models.FileModeDiff(); _result.FileModeDiff.New = line.Substring(9); return; } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 83cff278..2a158242 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -531,7 +531,7 @@ namespace SourceGit.ViewModels UseTheirs(changes); e.Handled = true; }; - + var useMine = new MenuItem(); useMine.Icon = App.CreateMenuIcon("Icons.Local"); useMine.Header = App.Text("FileCM.UseMine"); @@ -641,7 +641,7 @@ namespace SourceGit.ViewModels menu.Items.Add(assumeUnchanged); menu.Items.Add(new MenuItem() { Header = "-" }); } - + var copy = new MenuItem(); copy.Header = App.Text("CopyPath"); copy.Icon = App.CreateMenuIcon("Icons.Copy"); @@ -649,7 +649,7 @@ namespace SourceGit.ViewModels { App.CopyText(change.Path); e.Handled = true; - }; + }; menu.Items.Add(copy); } else From 7bf6793a11c2ddfee9051299443c6b7f5eda93de Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 14 Apr 2024 11:13:32 +0800 Subject: [PATCH 31/35] refactor: detecting programs from the PATH environment variable instead of hard coded (#72) --- src/Native/Linux.cs | 144 +++++++++++++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 43 deletions(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 4d4d3fc3..172d598b 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -13,6 +13,29 @@ namespace SourceGit.Native [SupportedOSPlatform("linux")] internal class Linux : OS.IBackend { + class Terminal + { + public string FilePath { get; set; } = string.Empty; + public string OpenArgFormat { get; set; } = string.Empty; + + public Terminal(string exec, string fmt) + { + FilePath = exec; + OpenArgFormat = fmt; + } + + public void Open(string dir) + { + Process.Start(FilePath, string.Format(OpenArgFormat, dir)); + } + } + + public Linux() + { + _xdgOpenPath = FindExecutable("xdg-open"); + _terminal = FindTerminal(); + } + public void SetupApp(AppBuilder builder) { builder.With(new FontManagerOptions() @@ -26,50 +49,45 @@ namespace SourceGit.Native public string FindGitExecutable() { - if (File.Exists("/usr/bin/git")) - return "/usr/bin/git"; - return string.Empty; + return FindExecutable("git"); } public List FindExternalTools() { var finder = new Models.ExternalToolsFinder(); - finder.VSCode(() => "/usr/share/code/code"); - finder.VSCodeInsiders(() => "/usr/share/code-insiders/code-insiders"); - finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox/apps/fleet/bin/Fleet"); - finder.SublimeText(() => File.Exists("/usr/bin/subl") ? "/usr/bin/subl" : "/usr/local/bin/subl"); + finder.VSCode(() => FindExecutable("code")); + finder.VSCodeInsiders(() => FindExecutable("code-insiders")); + finder.Fleet(FindJetBrainFleet); + finder.SublimeText(() => FindExecutable("subl")); return finder.Founded; } public void OpenBrowser(string url) { - if (!File.Exists("/usr/bin/xdg-open")) - { - App.RaiseException("", $"You should install xdg-open first!"); - return; - } - - Process.Start("xdg-open", $"\"{url}\""); + if (string.IsNullOrEmpty(_xdgOpenPath)) + App.RaiseException("", $"Can NOT find `xdg-open` command!!!"); + else + Process.Start(_xdgOpenPath, $"\"{url}\""); } public void OpenInFileManager(string path, bool select) { - if (!File.Exists("/usr/bin/xdg-open")) + if (string.IsNullOrEmpty(_xdgOpenPath)) { - App.RaiseException("", $"You should install xdg-open first!"); + App.RaiseException("", $"Can NOT find `xdg-open` command!!!"); return; } if (Directory.Exists(path)) { - Process.Start("xdg-open", $"\"{path}\""); + Process.Start(_xdgOpenPath, $"\"{path}\""); } else { var dir = Path.GetDirectoryName(path); if (Directory.Exists(dir)) { - Process.Start("xdg-open", $"\"{dir}\""); + Process.Start(_xdgOpenPath, $"\"{dir}\""); } } } @@ -77,46 +95,86 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { var dir = string.IsNullOrEmpty(workdir) ? "~" : workdir; - if (File.Exists("/usr/bin/gnome-terminal")) - { - Process.Start("/usr/bin/gnome-terminal", $"--working-directory=\"{dir}\""); - } - else if (File.Exists("/usr/bin/konsole")) - { - Process.Start("/usr/bin/konsole", $"--workdir \"{dir}\""); - } - else if (File.Exists("/usr/bin/xfce4-terminal")) - { - Process.Start("/usr/bin/xfce4-terminal", $"--working-directory=\"{dir}\""); - } - else if (File.Exists("/usr/bin/deepin-terminal")) - { - Process.Start("/usr/bin/deepin-terminal", $"--work-directory \"{dir}\""); - } - else - { + if (_terminal == null) App.RaiseException(dir, $"Only supports gnome-terminal/konsole/xfce4-terminal/deepin-terminal!"); - return; - } + else + _terminal.Open(dir); } public void OpenWithDefaultEditor(string file) { - if (!File.Exists("/usr/bin/xdg-open")) + if (string.IsNullOrEmpty(_xdgOpenPath)) { - App.RaiseException("", $"You should install xdg-open first!"); + App.RaiseException("", $"Can NOT find `xdg-open` command!!!"); return; } - var proc = Process.Start("xdg-open", $"\"{file}\""); + var proc = Process.Start(_xdgOpenPath, $"\"{file}\""); proc.WaitForExit(); if (proc.ExitCode != 0) - { App.RaiseException("", $"Failed to open \"{file}\""); - } proc.Close(); } + + private string FindExecutable(string filename) + { + var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; + var pathes = pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); + foreach (var path in pathes) + { + var test = Path.Combine(path, filename); + if (File.Exists(test)) + { + return test; + } + } + + return string.Empty; + } + + private Terminal FindTerminal() + { + var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; + var pathes = pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); + foreach (var path in pathes) + { + var test = Path.Combine(path, "gnome-terminal"); + if (File.Exists(test)) + { + return new Terminal(test, "--working-directory=\"{0}\""); + } + + test = Path.Combine(path, "konsole"); + if (File.Exists(test)) + { + return new Terminal(test, "--workdir \"{0}\""); + } + + test = Path.Combine(path, "xfce4-terminal"); + if (File.Exists(test)) + { + return new Terminal(test, "--working-directory=\"{0}\""); + } + + test = Path.Combine(path, "deepin-terminal"); + if (File.Exists(test)) + { + return new Terminal(test, "--work-directory \"{0}\""); + } + } + + return null; + } + + private string FindJetBrainFleet() + { + var path = $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox/apps/fleet/bin/Fleet"; + return File.Exists(path) ? path : FindExecutable("fleet"); + } + + private string _xdgOpenPath = string.Empty; + private Terminal _terminal = null; } } From ab26bb83e9573b30c55a3beb923b805c8ed79d9c Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 14 Apr 2024 12:27:09 +0800 Subject: [PATCH 32/35] refactor: re-design toolbar of Views.DiffView --- src/Commands/Diff.cs | 6 ++-- src/Converters/PathConverters.cs | 8 ----- src/Models/DiffResult.cs | 5 ++- src/Resources/Locales/en_US.axaml | 2 +- src/Resources/Locales/zh_CN.axaml | 2 +- src/ViewModels/DiffContext.cs | 42 +++++++++---------------- src/Views/DiffView.axaml | 51 +++++++++++++++---------------- 7 files changed, 47 insertions(+), 69 deletions(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 3846e4bb..e92b2234 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -48,15 +48,13 @@ namespace SourceGit.Commands { if (line.StartsWith("old mode ", StringComparison.Ordinal)) { - _result.FileModeDiff ??= new Models.FileModeDiff(); - _result.FileModeDiff.Old = line.Substring(9); + _result.OldMode = line.Substring(9); return; } if (line.StartsWith("new mode ", StringComparison.Ordinal)) { - _result.FileModeDiff ??= new Models.FileModeDiff(); - _result.FileModeDiff.New = line.Substring(9); + _result.NewMode = line.Substring(9); return; } diff --git a/src/Converters/PathConverters.cs b/src/Converters/PathConverters.cs index fcd9f174..6f10b66d 100644 --- a/src/Converters/PathConverters.cs +++ b/src/Converters/PathConverters.cs @@ -11,13 +11,5 @@ namespace SourceGit.Converters public static readonly FuncValueConverter PureDirectoryName = new FuncValueConverter(fullpath => Path.GetDirectoryName(fullpath) ?? ""); - - public static readonly FuncValueConverter TruncateIfTooLong = - new FuncValueConverter(fullpath => - { - if (fullpath.Length <= 50) - return fullpath; - return fullpath.Substring(0, 20) + ".../" + Path.GetFileName(fullpath); - }); } } diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs index 3325a841..70219dcf 100644 --- a/src/Models/DiffResult.cs +++ b/src/Models/DiffResult.cs @@ -586,8 +586,11 @@ namespace SourceGit.Models { public bool IsBinary { get; set; } = false; public bool IsLFS { get; set; } = false; + public string OldMode { get; set; } = string.Empty; + public string NewMode { get; set; } = string.Empty; public TextDiff TextDiff { get; set; } = null; public LFSDiff LFSDiff { get; set; } = null; - public FileModeDiff FileModeDiff { get; set; } = null; + + public string FileModeChange => string.IsNullOrEmpty(OldMode) ? string.Empty : $"{OldMode} → {NewMode}"; } } diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 10d632f6..9752f0d6 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -131,7 +131,7 @@ NEW OLD Copy - File Mode Changed : + File Mode Changed LFS OBJECT CHANGE Next Difference NO CHANGES OR ONLY EOL CHANGES diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index ede3aa65..a6fdb67f 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -131,7 +131,7 @@ 当前大小 原始大小 复制 - 文件权限已变化 : + 文件权限已变化 LFS对象变更 下一个差异 没有变更或仅有换行符差异 diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index e0c9de25..18c03936 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -3,7 +3,6 @@ using System.IO; using System.Threading.Tasks; using Avalonia; -using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Threading; @@ -28,19 +27,16 @@ namespace SourceGit.ViewModels get => _option.IsUnstaged; } - public string FilePath + public string Title { - get => _option.Path; + get => _title; + private set => SetProperty(ref _title, value); } - public bool IsOrgFilePathVisible + public string FileModeChange { - get => !string.IsNullOrWhiteSpace(_option.OrgPath) && _option.OrgPath != "/dev/null"; - } - - public string OrgFilePath - { - get => _option.OrgPath; + get => _fileModeChange; + private set => SetProperty(ref _fileModeChange, value); } public bool IsLoading @@ -67,14 +63,6 @@ namespace SourceGit.ViewModels set => SetProperty(ref _syncScrollOffset, value); } - public Models.FileModeDiff FileModeDiff - { - get => _fileModeDiff; - set => SetProperty(ref _fileModeDiff, value); - } - - public TextTrimming PathTrimming { get; } = new TextLeadingPrefixTrimming("...", 20); - public DiffContext(string repo, Models.DiffOption option, DiffContext previous = null) { _repo = repo; @@ -86,20 +74,11 @@ namespace SourceGit.ViewModels _content = previous._content; } - OnPropertyChanged(nameof(FilePath)); - OnPropertyChanged(nameof(IsOrgFilePathVisible)); - OnPropertyChanged(nameof(OrgFilePath)); - Task.Run(() => { var latest = new Commands.Diff(repo, option).Result(); var rs = null as object; - if (latest.FileModeDiff != null) - { - FileModeDiff = latest.FileModeDiff; - } - if (latest.TextDiff != null) { latest.TextDiff.File = _option.Path; @@ -154,6 +133,12 @@ namespace SourceGit.ViewModels Dispatcher.UIThread.Post(() => { + if (string.IsNullOrEmpty(_option.OrgPath)) + Title = _option.Path; + else + Title = $"{_option.OrgPath} → {_option.Path}"; + + FileModeChange = latest.FileModeChange; Content = rs; IsTextDiff = latest.TextDiff != null; IsLoading = false; @@ -190,10 +175,11 @@ namespace SourceGit.ViewModels private readonly string _repo = string.Empty; private readonly Models.DiffOption _option = null; + private string _title = string.Empty; + private string _fileModeChange = string.Empty; private bool _isLoading = true; private bool _isTextDiff = false; private object _content = null; private Vector _syncScrollOffset = Vector.Zero; - private Models.FileModeDiff _fileModeDiff = null; } } diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index 568d47b8..5ba5a211 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -13,34 +13,33 @@ - - - - - - + + + - - - - - + + + + - - - - - - + + - + + @@ -50,11 +49,11 @@ Background="Transparent" Padding="9,6" IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=TwoWay}" - IsVisible="{Binding IsTextDiff}" + IsVisible="{Binding IsTextDiff}" ToolTip.Tip="{DynamicResource Text.Diff.SideBySide}"> - + @@ -135,18 +134,18 @@ - + - + - Date: Sun, 14 Apr 2024 20:13:07 +0800 Subject: [PATCH 33/35] code_style: remove unused name declaration --- src/Views/Preference.axaml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index 820b6dc9..4579fe42 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -372,7 +372,6 @@ HorizontalAlignment="Right" Margin="0,0,16,0"/> From f58cff2cb6fc061077e2a7791c77938f07559b52 Mon Sep 17 00:00:00 2001 From: walterlv Date: Mon, 15 Apr 2024 08:58:25 +0800 Subject: [PATCH 34/35] Fix windows terminal startup directory --- src/Native/Windows.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index b6c9bd59..04fe5e8b 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -161,6 +161,7 @@ namespace SourceGit.Native } startInfo.FileName = FindWindowsTerminalApp(); + startInfo.Arguments = $"-d \"{workdir}\""; break; default: App.RaiseException(workdir, $"Bad shell configuration!"); From f3532c4cf27eec291598a521ecdfdcd16612029d Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 15 Apr 2024 09:20:20 +0800 Subject: [PATCH 35/35] version: Release 8.8 --- build/resources/App.plist | 6 +++--- src/SourceGit.csproj | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/resources/App.plist b/build/resources/App.plist index da322389..3327c5d8 100644 --- a/build/resources/App.plist +++ b/build/resources/App.plist @@ -9,7 +9,7 @@ CFBundleName SourceGit CFBundleVersion - 8.7.0 + 8.8.0 LSMinimumSystemVersion 10.12 CFBundleExecutable @@ -19,8 +19,8 @@ CFBundlePackageType APPL CFBundleShortVersionString - 8.7 + 8.8 NSHighResolutionCapable - \ No newline at end of file + diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj index d439eee8..ecad8b6c 100644 --- a/src/SourceGit.csproj +++ b/src/SourceGit.csproj @@ -5,7 +5,7 @@ true App.manifest App.ico - 8.7 + 8.8 false true true