From 4deac98c4eb8429d750d5ddfda8fede82145933c Mon Sep 17 00:00:00 2001 From: Aikawa Yataro Date: Mon, 16 Sep 2024 08:51:39 +0000 Subject: [PATCH 01/42] fix: crash when trying to open terminal from the Welcome screen --- src/Native/Linux.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 9537a39a..30aa7cc9 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -78,7 +78,8 @@ namespace SourceGit.Native } var startInfo = new ProcessStartInfo(); - startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? "~" : workdir; + var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? home : workdir; startInfo.FileName = OS.ShellOrTerminal; Process.Start(startInfo); } From 53c915578e926f0d21472d2ecacb878df50078f5 Mon Sep 17 00:00:00 2001 From: Aikawa Yataro Date: Mon, 16 Sep 2024 11:55:50 +0000 Subject: [PATCH 02/42] enhance: allow terminal without full path and adjust error message --- src/Native/Linux.cs | 14 +++++++++++--- src/Native/OS.cs | 2 +- src/Native/Windows.cs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 30aa7cc9..191f4ddd 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq.Expressions; using System.Runtime.Versioning; using Avalonia; @@ -71,9 +72,9 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - if (string.IsNullOrEmpty(OS.ShellOrTerminal) || !File.Exists(OS.ShellOrTerminal)) + if (string.IsNullOrEmpty(OS.ShellOrTerminal)) { - App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured."); + App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured."); return; } @@ -81,7 +82,14 @@ namespace SourceGit.Native var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? home : workdir; startInfo.FileName = OS.ShellOrTerminal; - Process.Start(startInfo); + try + { + Process.Start(startInfo); + } + catch (Exception e) + { + App.RaiseException(workdir, e.Message); + } } public void OpenWithDefaultEditor(string file) diff --git a/src/Native/OS.cs b/src/Native/OS.cs index 87655798..7df0b3ae 100644 --- a/src/Native/OS.cs +++ b/src/Native/OS.cs @@ -95,7 +95,7 @@ namespace SourceGit.Native public static void OpenTerminal(string workdir) { if (string.IsNullOrEmpty(ShellOrTerminal)) - App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured."); + App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured."); else _backend.OpenTerminal(workdir); } diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 19362d0c..13438e02 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -160,7 +160,7 @@ namespace SourceGit.Native { if (string.IsNullOrEmpty(OS.ShellOrTerminal) || !File.Exists(OS.ShellOrTerminal)) { - App.RaiseException(workdir, $"Can not found terminal! Please confirm that the correct shell/terminal has been configured."); + App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured."); return; } From 736ad02991700411a7268b74093f95599dace90b Mon Sep 17 00:00:00 2001 From: Aikawa Yataro Date: Mon, 16 Sep 2024 12:03:56 +0000 Subject: [PATCH 03/42] enhance: allow to specify custom terminal --- src/Models/ShellOrTerminal.cs | 1 + src/Native/Linux.cs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Models/ShellOrTerminal.cs b/src/Models/ShellOrTerminal.cs index fa3a207b..02b294a0 100644 --- a/src/Models/ShellOrTerminal.cs +++ b/src/Models/ShellOrTerminal.cs @@ -54,6 +54,7 @@ namespace SourceGit.Models new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"), new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"), new ShellOrTerminal("foot", "Foot", "foot"), + new ShellOrTerminal("custom", "Custom", ""), }; } } diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 191f4ddd..16fd1b78 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq.Expressions; using System.Runtime.Versioning; using Avalonia; @@ -27,6 +26,11 @@ namespace SourceGit.Native public string FindTerminal(Models.ShellOrTerminal shell) { + if (string.IsNullOrEmpty(shell.Exec)) + { + return string.Empty; + } + var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; var pathes = pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); foreach (var path in pathes) From 54ab6259319d5ce3febccab594351836a422ab68 Mon Sep 17 00:00:00 2001 From: Aikawa Yataro Date: Tue, 17 Sep 2024 07:20:17 +0000 Subject: [PATCH 04/42] enhance: select any terminal when none is set --- src/ViewModels/Preference.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index 6887e6c9..b62e3720 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -41,6 +41,22 @@ namespace SourceGit.ViewModels if (!_instance.IsGitConfigured()) _instance.GitInstallPath = Native.OS.FindGitExecutable(); + if (!_instance.IsTerminalConfigured()) + { + for (var i = 0; i < Models.ShellOrTerminal.Supported.Count; i++) + { + _instance.ShellOrTerminal = i; + if (string.IsNullOrEmpty(_instance.ShellOrTerminalPath)) + { + _instance.ShellOrTerminal = -1; + } + else + { + break; + } + } + } + if (_instance.Workspaces.Count == 0) _instance.Workspaces.Add(new Workspace() { Name = "Default", Color = 4278221015 }); @@ -380,6 +396,11 @@ namespace SourceGit.ViewModels return !string.IsNullOrEmpty(path) && File.Exists(path); } + public bool IsTerminalConfigured() + { + return ShellOrTerminal != -1; + } + public bool ShouldCheck4UpdateOnStartup() { if (!_check4UpdatesOnStartup) From bc633e4085b6527ed3127d493491c29c601c305e Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Sep 2024 22:09:51 +0800 Subject: [PATCH 05/42] code_review: PR #480 * remove `string.IsNullOrEmpty(OS.ShellOrTerminal)` checking from detail backend since it has been checked by `Native.OS.OpenTerminal` * remove `ViewModels.Preference.IsTerminalConfigured` because it is only used by itself (Unlike `IsGitConfigured`). * add `Native.OS.TestShellOrTerminal` and use it instead of setting `Preference.ShellOrTerminal` directly, because we have binded a callback that will save preference into file when its property changed. It may cause lag in some enviroments if we saving preference into file too frequently (see PR #436). * run `dotnet format` --- src/Native/Linux.cs | 11 +---- src/Native/OS.cs | 11 +++-- src/Native/Windows.cs | 2 +- src/ViewModels/Preference.cs | 71 +++++++++++++++----------------- src/Views/ImageDiffView.axaml.cs | 10 ----- 5 files changed, 44 insertions(+), 61 deletions(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 16fd1b78..9df41160 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -27,9 +27,7 @@ namespace SourceGit.Native public string FindTerminal(Models.ShellOrTerminal shell) { if (string.IsNullOrEmpty(shell.Exec)) - { return string.Empty; - } var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; var pathes = pathVariable.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); @@ -76,23 +74,18 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - if (string.IsNullOrEmpty(OS.ShellOrTerminal)) - { - App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured."); - return; - } - var startInfo = new ProcessStartInfo(); var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? home : workdir; startInfo.FileName = OS.ShellOrTerminal; + try { Process.Start(startInfo); } catch (Exception e) { - App.RaiseException(workdir, e.Message); + App.RaiseException(workdir, $"Failed to start '{OS.ShellOrTerminal}'. Reason: {e.Message}"); } } diff --git a/src/Native/OS.cs b/src/Native/OS.cs index 7df0b3ae..bc9c5403 100644 --- a/src/Native/OS.cs +++ b/src/Native/OS.cs @@ -74,12 +74,17 @@ namespace SourceGit.Native return _backend.FindGitExecutable(); } - public static void SetShellOrTerminal(Models.ShellOrTerminal shellOrTerminal) + public static bool TestShellOrTerminal(Models.ShellOrTerminal shell) { - if (shellOrTerminal == null) + return !string.IsNullOrEmpty(_backend.FindTerminal(shell)); + } + + public static void SetShellOrTerminal(Models.ShellOrTerminal shell) + { + if (shell == null) ShellOrTerminal = string.Empty; else - ShellOrTerminal = _backend.FindTerminal(shellOrTerminal); + ShellOrTerminal = _backend.FindTerminal(shell); } public static void OpenInFileManager(string path, bool select = false) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 13438e02..ab91ffdb 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -158,7 +158,7 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - if (string.IsNullOrEmpty(OS.ShellOrTerminal) || !File.Exists(OS.ShellOrTerminal)) + if (!File.Exists(OS.ShellOrTerminal)) { App.RaiseException(workdir, $"Terminal is not specified! Please confirm that the correct shell/terminal has been configured."); return; diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index b62e3720..2df40675 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -18,44 +18,15 @@ namespace SourceGit.ViewModels if (_instance == null) { _isLoading = true; - - var path = Path.Combine(Native.OS.DataDir, "preference.json"); - if (!File.Exists(path)) - { - _instance = new Preference(); - } - else - { - try - { - _instance = JsonSerializer.Deserialize(File.ReadAllText(path), JsonCodeGen.Default.Preference); - } - catch - { - _instance = new Preference(); - } - } + _instance = Load(); _isLoading = false; } if (!_instance.IsGitConfigured()) _instance.GitInstallPath = Native.OS.FindGitExecutable(); - if (!_instance.IsTerminalConfigured()) - { - for (var i = 0; i < Models.ShellOrTerminal.Supported.Count; i++) - { - _instance.ShellOrTerminal = i; - if (string.IsNullOrEmpty(_instance.ShellOrTerminalPath)) - { - _instance.ShellOrTerminal = -1; - } - else - { - break; - } - } - } + if (_instance._shellOrTerminal == -1) + _instance.AutoSelectShellOrTerminal(); if (_instance.Workspaces.Count == 0) _instance.Workspaces.Add(new Workspace() { Name = "Default", Color = 4278221015 }); @@ -396,11 +367,6 @@ namespace SourceGit.ViewModels return !string.IsNullOrEmpty(path) && File.Exists(path); } - public bool IsTerminalConfigured() - { - return ShellOrTerminal != -1; - } - public bool ShouldCheck4UpdateOnStartup() { if (!_check4UpdatesOnStartup) @@ -519,6 +485,35 @@ namespace SourceGit.ViewModels File.WriteAllText(file, data); } + private static Preference Load() + { + var path = Path.Combine(Native.OS.DataDir, "preference.json"); + if (!File.Exists(path)) + return new Preference(); + + try + { + return JsonSerializer.Deserialize(File.ReadAllText(path), JsonCodeGen.Default.Preference); + } + catch + { + return new Preference(); + } + } + + private void AutoSelectShellOrTerminal() + { + for (int i = 0; i < Models.ShellOrTerminal.Supported.Count; i++) + { + var shell = Models.ShellOrTerminal.Supported[i]; + if (Native.OS.TestShellOrTerminal(shell)) + { + ShellOrTerminal = i; + break; + } + } + } + private RepositoryNode FindNodeRecursive(string id, List collection) { foreach (var node in collection) @@ -557,7 +552,7 @@ namespace SourceGit.ViewModels return true; } - foreach (RepositoryNode one in collection) + foreach (var one in collection) { if (RemoveNodeRecursive(node, one.SubNodes)) return true; diff --git a/src/Views/ImageDiffView.axaml.cs b/src/Views/ImageDiffView.axaml.cs index bc516b5a..7e32c91a 100644 --- a/src/Views/ImageDiffView.axaml.cs +++ b/src/Views/ImageDiffView.axaml.cs @@ -1,17 +1,7 @@ -using System; - -using Avalonia; using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Media; -using Avalonia.Media.Imaging; namespace SourceGit.Views { - - - - public partial class ImageDiffView : UserControl { public ImageDiffView() From 934d784d4081b1bd466c3813e26f4c9b3c98a8c6 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Sep 2024 22:26:35 +0800 Subject: [PATCH 06/42] fix: unable to access the `Stage/Unstage` buttons in diff viewer when line wrap is enabled (#481) * disable line wrap in side-by-side diff mode --- src/Views/TextDiffView.axaml | 4 ++-- src/Views/TextDiffView.axaml.cs | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Views/TextDiffView.axaml b/src/Views/TextDiffView.axaml index 1ab75ef6..b14bb07d 100644 --- a/src/Views/TextDiffView.axaml +++ b/src/Views/TextDiffView.axaml @@ -45,7 +45,7 @@ IndicatorForeground="{DynamicResource Brush.FG2}" FontFamily="{DynamicResource Fonts.Monospace}" UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}" - WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}" + WordWrap="False" ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}" EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}" SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/> @@ -65,7 +65,7 @@ IndicatorForeground="{DynamicResource Brush.FG2}" FontFamily="{DynamicResource Fonts.Monospace}" UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}" - WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}" + WordWrap="False" ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}" EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}" SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"/> diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index b2459127..02564428 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -519,7 +519,17 @@ namespace SourceGit.Views private void OnTextViewPointerMoved(object sender, PointerEventArgs e) { if (EnableChunkSelection && sender is TextView view) + { + var chunk = SelectedChunk; + if (chunk != null) + { + var rect = new Rect(0, chunk.Y, Bounds.Width, chunk.Height); + if (rect.Contains(e.GetPosition(this))) + return; + } + UpdateSelectedChunk(e.GetPosition(view).Y + view.VerticalOffset); + } } private void OnTextViewPointerWheelChanged(object sender, PointerWheelEventArgs e) From a00cf4f0092cf48d388acc8f467a0a3483f753e3 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Sep 2024 22:58:28 +0800 Subject: [PATCH 07/42] ux: add custom terminal icon --- src/Resources/Images/ShellIcons/custom.png | Bin 0 -> 2509 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/Resources/Images/ShellIcons/custom.png diff --git a/src/Resources/Images/ShellIcons/custom.png b/src/Resources/Images/ShellIcons/custom.png new file mode 100644 index 0000000000000000000000000000000000000000..0175688f7694b5df804c67795bbef14e812cad56 GIT binary patch literal 2509 zcmV;;2{QJHP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0000) zWmrjOO-%qQ0000800D<-00aO40096102%-Q00003paB2_0000100961paK8{00001 z0000$paTE|000010000$00000Mo~hr000RHNklu@;HXZIzIy#xy4W@DGWJfy7Y7-~9j~*hB|E1|8}^v>W@b z*nW)lD`}e1$x%`@iIX^q9e>-`zW4CH*GaIilO~>M>lmNt*gof;bMN~+=RN0r9lx)H zHA)~5aAe%xtx`U}2eR#63C5iQ*dj?%hY<9s3JS@>QUs}9h9u3CjIRqxxu_<5BRxG* z_C_L_GglfgI5E*>lhtE3N&2=hM33F!aM@%V3}LJ^{Py-!5z~ z*zM{OR;yGpiTB=l8*jaK2A9r%h~W4*G)*g>Uv-}yPA59My0CliethlGqv$(u5Dg7( zQ!{d!_G%`XKeoT8W426i+RwHt<1?>~MiOFVJ|<4R`L5_Yc#xHA!&X{Eap3MlgypP> zX*7})L*vtDhKGe(M!?Yc%+CUIQFGvP&z}&jo7y%kaO| z4GW=)$W8?0#Z@!MlAN>}Yky2B~fLq%9X!LmKWF^k34E!?PM1rpCNX28ApPqtF z*2`Lcb>fdW{Pk}l8INC4)3JUT*TdUs&<>t>>Q66~fww6NI=0+_mex&>$q!(rnIK)$ zA#}t1%QpFRF90$Kj}l@4+}_5=OEb@w*#FVvJ-Ic6y-`nL-aI| z{5O5z6XqrsUJQrJWoqr*)MUw%1}~g9eHxF~>&#};du2nG9^(BxH8F11;?as-g}bTQ zTwU&G@J3F+?v~MUj~mWSHt5tYb`HrIgW5*bZ>jBc;CPGgese$bf;EyeM9y5vgMx&U z9Xi$&8gidPuA+|#2+hnOn=N&l*{P7pn<}V1U~@|7`A!SEA8v%bNk-qZ?U+56#?|M; z$js)K55{6bN}gVNw3J-B84dOX8AHCvd1FV8y;}AV3HL6AuE*Tt~-B<~qjTW2i88nGXzJ zyp?R{^8M+$K^7$&*3rDZZxzj z7(KaQZUNSijaJr80K2<_{+ZFNT`=&CD}QC*jii-4TbCy zfy**6bcKK8YVrA?T7n8W@R&nrH)=6RcE(U#91aKk?d`O#6#54d=77m}II6PqQ(cs4 z(Oo>&3@}Vk2rUoVXodH8l7gnK(Qlki!<7k;4e<}zkdy%}o6WEW?CI+-!?`dULN=W? z4~(*lRocM|re)G*#JE+&JNNE0^NBdAN`iV`b|oWYM8}9iQQ==ce8f7QBCB%R` z5;g;-*;+8WRar?k!_cuXKZmJnV`bs;Eb})WJ6cGlqKqw}Ow635y}s+v z{SRQ@7w*EPb03xv!EyH?3NmK%!Lhd-LR)QSlU14zZH@LkB}bLWztrfb1ggFRUo7l@ zL!90vNri!&KEi1voK8~nDKnH7#OXntCbUG1`Ob+%oHN8E)N;}kCx(?JO)&$UO2#Q= zoLa^taH<)noRO-tBd}pBr~YvYAYC*p7?^5vx|I`@9Q81Vzo$}3 zT=>@q`0Jlv!sUUB2u@6t*;P}0s_2D%na=KR?CZY^4}9e?4&8UZnNiATL@uYD&Pn?B z_H5o9S`xV|%I74p(;E!^#HQGP=ulNJJ4x&eaY_wmmCS}hW=3f;nV`dl(q+o-uypHN z_)bE2$dzyQw184!OrM6$I$JiDof0Nyv|Ro-a%}E+Z*OnO3Aw8HAB~54goN*sxAawl zvcu_gIV73&f=mrZN%5vwb@nX;Z+R3aQ0rt0bCeK7@& Date: Wed, 18 Sep 2024 10:00:32 +0800 Subject: [PATCH 08/42] feature: supports `Zed` editor as an external editor (#477) --- README.md | 1 + src/Models/ExternalTool.cs | 5 +++++ src/Native/Linux.cs | 1 + src/Native/MacOS.cs | 1 + src/Resources/Images/ExternalToolIcons/zed.png | Bin 0 -> 5420 bytes 5 files changed, 8 insertions(+) create mode 100644 src/Resources/Images/ExternalToolIcons/zed.png diff --git a/README.md b/README.md index 170e7bd6..255d7c11 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ This app supports open repository in external tools listed in the table below. | VSCodium | YES | YES | YES | VSCODIUM | | JetBrains Fleet | YES | YES | YES | FLEET | | Sublime Text | YES | YES | YES | SUBLIME_TEXT | +| Zed | NO | YES | YES | ZED | > [!NOTE] > This app will try to find those tools based on some pre-defined or expected locations automatically. If you are using one portable version of these tools, it will not be detected by this app. diff --git a/src/Models/ExternalTool.cs b/src/Models/ExternalTool.cs index 45682dab..b26a9a90 100644 --- a/src/Models/ExternalTool.cs +++ b/src/Models/ExternalTool.cs @@ -149,6 +149,11 @@ namespace SourceGit.Models TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT", platformFinder); } + public void Zed(Func platformFinder) + { + TryAdd("Zed", "zed", "\"{0}\"", "ZED", platformFinder); + } + public void FindJetBrainsFromToolbox(Func platformFinder) { var exclude = new List { "fleet", "dotmemory", "dottrace", "resharper-u", "androidstudio" }; diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 9df41160..7c3f20f8 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -50,6 +50,7 @@ namespace SourceGit.Native finder.Fleet(FindJetBrainsFleet); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox"); finder.SublimeText(() => FindExecutable("subl")); + finder.Zed(() => FindExecutable("zed")); return finder.Founded; } diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs index 0ad608b2..81918284 100644 --- a/src/Native/MacOS.cs +++ b/src/Native/MacOS.cs @@ -46,6 +46,7 @@ namespace SourceGit.Native finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Applications/Fleet.app/Contents/MacOS/Fleet"); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}/Library/Application Support/JetBrains/Toolbox"); finder.SublimeText(() => "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl"); + finder.Zed(() => File.Exists("/usr/local/bin/zed") ? "/usr/local/bin/zed" : "/Applications/Zed.app/Contents/MacOS/cli"); return finder.Founded; } diff --git a/src/Resources/Images/ExternalToolIcons/zed.png b/src/Resources/Images/ExternalToolIcons/zed.png new file mode 100644 index 0000000000000000000000000000000000000000..07c4c50fd33ec00c3974382f62375cc0f5650688 GIT binary patch literal 5420 zcmV+{71Qd8P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc6v0VEK~#8N)tg(4 zp2c~`=iTpHd)LM>7z{q)T_3&LMmK< zgaidONI(b#(}Ej;j8r9+sf8h^1zZr|6CfWbHa_fk=>PYhdA@!3^X_6ty>R|yzL|IC znddamJTvdRPL+-TXPj}y(oSmpI8~kRce`nIqtRH>Znft%2b;6HolYgBsv1bGb}J1G z45R_IQ|fwdH?=j^P^+V{MryaadahDejHnAy>U1SRbJeZKJQq}*c4?(FFbE&!NY>a` zYNTdL4O8#e&u+E04Gs=`(CW1RV@B2dmyH`Y{*Nb4gJ~VGX3d)O+MVh?$-8hs7GePC zbUIcZ{jF*-rlVSPc0yY;jLOtB&}^hmOO6<5%1E_MCqAuC>e^R%ex(|7t(1PMPB%3* zx825xmBupNfcW6Rfv#k#ud83pwiBTT%|@fE>2Efx>K`_2*zlG+C&8o+7#SHkerRau z5jAhF2Fh>u)w~+O)@=HDpa{ zShj50>0=eZ*q zQ|r}SP_cSNWqVV+@o5MTr-WjlYs1QFFkiaW$C;On>$uQ1KiG@dxkI$dB5+GB87B(Q zg@e|z2Y6bqq7O0=!}b91CSvT2;L+{wXf+z=zq?^W&k0B}2zw>5SJhkqeO4x~rV^d& zFrK|Opw%64i03iTV4ii-T9i2$8nEHrmK4Vl@nEi3P{v?Ep&bw-99Sv*Z2^7gBN|7H zo~dyTd4OHt)b^P{RBAM2=0zZ~lv~uNvY>tNz^iASb=L7F5PA+6931>dRV(w8y=BiK zq#@xD(nlfDbqP-yBP}&njFD!HqbLTkud{(Fs%@lz(&mTZsxif>OWwoggRQaD62GS8 zHt{Gct6}u9&&)?WaDoP?F_au*Ih+jAjXuDFb)+XrR9LzH(4j{?AXuXnD^~nK-uib< z5bvyHy|&S;h_&XJLnopjdpNsCeQM)%`(HFD%(KT(PIFPNAuEXxD~?XtD(96$I!d!+ zSXmjVJuUS!FPq;PJ~`xJ&}M~rmf;j9MN`We?M_z_w@S8D z7b=m-cV$_vDxB3&@{{%O|6=yDn z5+OuF#WpE2dp!9m2)^|~RMg~sUs0R#j@NckIxUC^gt()ukSnFgBf(b$^bgJR4^^`HHqNckcJ@li@SVSP%A) zcvfW}sl&>IL+E?>;fK=&Kl+i!NLqNhE$@?PqBsnTaB3$u6>67`whwesSk2ma%<(F_ zmeP{PQ9L{}oZfr?cj?0qKQw>l`xuX?l1-dmv0y${vC}qWgR5oBM)ql6&hi7{C$C|o zFE80v{OFYhxPh@5GiIcX8#n6y(oDDC{?}>!`nPOw;hV3pf*mR4f?qh0U-q!C)pUr4 zvDgC0VP5DG5y^IY>ZzyF$tRzjwr}5_uDbS`w0qZXpFGgw-0Xl1uI%sz5e4uI-qpy+ z(u4BS3=_+HR#3ut)53(F@%G%fV#gnUeA=*KgU8P~=N#?F-C|snRU!l2`F&uNdG5mz zW)@0jnYlmfP)CeWPC4b2^z_qDrv(cZq^(=Grdw{gC2iThO&s!@A9^W7%$c@%m9JEU zygF=`C5SK4r3Dz!Jv4-7#i`hB%EpM3I3 zJ7I_R{7pCAl(uc#<}XdiY?JIHpG%f?M=s~85L+M;X+8yVU5$>8)-<45gd$u|u`+qzE1!9l%M;s5kLcxN+wUKRqVNqnT#t?}E9y~EGLZ??ECFL!G5@cc(gB3x z;}h?)Wfd9A4@{aXK;^wVNdp z?0{28mO{xC8>SRtLQfKSdva0{NzZGlS>3nae%sG=2P|E>G`;!88-CT@wR4vhp9ofL z8t|G|Fk|M7blh>rxsA~`-+c1~<9*kcVqBLI#3wYH$q#vqsL+kk3kRstUr`MYB0>&W zqJ_?e<#R6=UT>MkcRfiMXHqb4-n>a2aN6mor**Htp7!tG&v%C2zKi*FHnd}lK7gaoPJ^*$4TsQl8BdSUD|hGe_FL>l`cg5F@zVZDlK2W zBK@&wtwiD3kGt-=%SWD#zkb|!5NExgRFfn4L(9Hz_h}0h$E!bhLl>DpfbMJo=%}kD zOGdQFY@nQ+!T}sTT03Rb@;#s^VW>S{H?jY$Ibi3`off=m)vEMwzy7ryuzckT-56&& zH;gJdu6uo5nmMRD*W|YMfbkQ;z9>D$9Yan4$eJ@}j{En>`F2b(9(pG_qM!!G!WPD8 z4|F6uA*=3jMJ>vG%&_0IFcl)ca z@g>LK8rY|jg`svp;Td|+H*@ApKU+s37Rx%8K0qHB*Bu%ykb4Ul@SqC9+(!|WGwU?y z&Fw?pUJ@q7_I&-d!xe*PXe*HLUU=aJC%hfoccg2ty*6#rInV9R7aVFS%xgD=qYD{f zBqv5hMy744jUFwPyj4OcXh43Z;E3XYAfoPhs5b#4vgas)dK>h{Gph{GgSS=X~C8-Lf_P^sj#El?O=1ASSjI1sFPe_H3~mHy)4#aY}3fkZpi6 z)7HUQb_BGvl?X%edLiuGhES8VPx8x+ndh;oz z>T9m{3l0ieHi|M|HD#9W5W~Ym%INtR3k){d0)CM#$dVDudjLS!;FBE{TUhx-#SUOF z>I^1i<>{y75X*Ia6@q!tQF>5+U18`JX~lo>i(mB4`KzwFDs7b$_>yz>*=MIeJMX-7 zijLTjLE$>g$B+0d7X{bk|p8v0t=E;wm?RvkG)dcdS8{XkgV$bN(Z z0HZP9VXwV@>7|#ZPe1)MjU77VfAPWisi&Um#1>#K5ina$=$Atti7gODMhRHHzY*{q zSUE!fF4y$_dqu1uGoY!LnA;EY5*Et1mtK0wi4XA6@{va#@tfm= z4?dXgz4u=JDURPUNNh2W8(Sp7h=7neQ@J6W)zf*+WgU{>&rn+`4EuX zt`0+eI}#vK5D0lBNA3Xt8_=1t&_8VO5nL{KOzrh+L8}u_Jdsp6=~mD@mx^;x858hl zPk>QeVqnI~ef8B>?g!xfJS(gPRRTuujM-xZF-f| zl+nSGB};shgXx)Po|(S<@=Nyz!uYkXtWBpZ$e*z;zx;A1K4c*$WP(sI#-fcQ?!5C( zhx&^zzUT;JTtDfi8*ent%P+s2_U_$VI314u2(N=v0GJ>OCjk4s_m>vgT>ncCrH=k* zKr(yfl~>Y&h55ziiYu=0-M)T;1dsu|A{ZxRxtWgDXa8eJYzqxK{JjMVUFgPm6c9Ct z@j&k$5HLYu-T5J)wT^;6axI2M$blrtlGke(Km3 z)Z`M5Lge6t0R4U!D2|!Tx&4Uoa6~nC?%acVuHPocw}6oa@?pp$WeaHQr2Fr`-|c(u zxhL)0x6f^dz4mG(yx7|mj6_NLDBphjt@|-L`dVXpK6s#)AEKY~=%bJJz6#+8UY%+4 zcLLrq0MGpkG955$g3BCYDtYyD1W@w_Nw!3Q*I!;_?zrQQ^tJBzcr(JD1R08OTjQez z=QS%vL3u)&ea#9|N1N+ygf>TCz6B1a4?g(7cL(5=Rt>MX2OKFP;-e4&`_(@bp+RRI z?fi{Z3g`ZYpAQGe87seNp{}=jrM>O8+j^N9-ciUdi0WvCJ*L7}B62L_UVx$;z&Ij@ z&*61o_}zEk?e=4jJvLD)x-JmyTQu!1LI%$)vwYbU2@p-mt1m5Z?)?1 zzxv=^p|+2+f)t%MazKpHAB!>>Z~&JljAd&Ok%7bcPmOWP-xDJvBM$q;Iu^tD_>u!q zAPT2QKeDppYD5GaNm#Q@*ak;JI~9lkve)=Es~|jA_a>-E0N2*H-g+x7UbI;6`g_ui zI+wZI2f~VfN4%@xzs&vi# zUrn4-x+W+9`a{0{%*BQb9AK{hR;M>E=99^(5gsQ2Z8CbjuU`6Tso_f!u z3;h)KdbBARN`dD6_uo&?KKrbBg$~mKQ|d)v3-B3c@pOjPy&LUNl4t&CNgITbVSJ$8 zW(@jpOwht}Dm@qrdceJd3sa!3<7AkEZyN{vPK`5<)&U@lj=B!`)r}6+4XyJE+PZV< ze3^6f$Tq>*pY{7bY)a-%z6x)d&iJDNMxc1C6iWB6+*AnKXh&V|KU!e8|Jfe$C(%KC zw`&m^=c?gMIrqx&Tgy)eMY}D>?Gj7S+VoA1Mlbl#r3->h@{s@?Ssw zfbI?I&!$qw|D{MSbR(OR?U*>;^*@&Wtw;KR(sjcopzst6hgPgQFH11~1Hx~}0rTY* zu5J1AO~GWVt5;DwpO|h44*6ks~?a2P_N)X3D9D1)>ZsmHT~&%f^@xIohF9sRr2SYBfxhFJeHt{*r6?P z{-HyM4*$Q+0S$a4gU(m^sB}$>sY2`+#pZtF!C@&ICul1WBLAdvn1!r(l*tmzF$iq< zXGQn9{lEs|1#&1ft4iz>AK%NC|$l*y Date: Wed, 18 Sep 2024 14:49:53 +0800 Subject: [PATCH 09/42] enhance: skip auto fetching when `index.lock` file exists in the repository's git dir --- src/Models/AutoFetchManager.cs | 12 +++++++++--- src/ViewModels/Launcher.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Models/AutoFetchManager.cs b/src/Models/AutoFetchManager.cs index 7f1e4da6..313f5f64 100644 --- a/src/Models/AutoFetchManager.cs +++ b/src/Models/AutoFetchManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; @@ -20,6 +21,7 @@ namespace SourceGit.Models public class Job { + public string IndexLockFile = string.Empty; public Commands.Fetch Cmd = null; public DateTime NextRunTimepoint = DateTime.MinValue; } @@ -75,8 +77,11 @@ namespace SourceGit.Models foreach (var job in uptodate) { - job.Cmd.Exec(); - job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); + if (!File.Exists(job.IndexLockFile)) + { + job.Cmd.Exec(); + job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); + } } Thread.Sleep(2000); @@ -86,10 +91,11 @@ namespace SourceGit.Models }); } - public void AddRepository(string repo) + public void AddRepository(string repo, string gitDir) { var job = new Job { + IndexLockFile = Path.Combine(gitDir, "index.lock"), Cmd = new Commands.Fetch(repo, "--all", true, false, null) { RaiseError = false }, NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)), }; diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 1cd7aef3..6ed9cee1 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -271,7 +271,7 @@ namespace SourceGit.ViewModels repo.Open(); ActiveWorkspace.AddRepository(repo.FullPath); - Models.AutoFetchManager.Instance.AddRepository(repo.FullPath); + Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir); if (page == null) { From 69b39dac6c5ba257ddc904a8b17d45129a3aca94 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Sep 2024 15:19:24 +0800 Subject: [PATCH 10/42] code_style: simpfy `FindTerminal` * [macOS] should return `string.Empty` when failed to find terminal path * [Linux] use `shell.Type` instead of `shell.Exec` to skip custom terminal detection --- src/Native/Linux.cs | 13 ++----------- src/Native/MacOS.cs | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 7c3f20f8..f784c691 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -26,19 +26,10 @@ namespace SourceGit.Native public string FindTerminal(Models.ShellOrTerminal shell) { - if (string.IsNullOrEmpty(shell.Exec)) + if (shell.Type.Equals("custom", StringComparison.Ordinal)) return string.Empty; - 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, shell.Exec); - if (File.Exists(test)) - return test; - } - - return string.Empty; + return FindExecutable(shell.Exec); } public List FindExternalTools() diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs index 81918284..6e2293a7 100644 --- a/src/Native/MacOS.cs +++ b/src/Native/MacOS.cs @@ -34,7 +34,7 @@ namespace SourceGit.Native return "iTerm"; } - return "InvalidTerminal"; + return string.Empty; } public List FindExternalTools() From bbd4012bc50cd09b17c685306e9c2869e3c30888 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Sep 2024 16:02:38 +0800 Subject: [PATCH 11/42] enhance: do NOT create sub-nodes for detached HEAD --- src/ViewModels/BranchTreeNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ViewModels/BranchTreeNode.cs b/src/ViewModels/BranchTreeNode.cs index 71f96a90..e3e65da0 100644 --- a/src/ViewModels/BranchTreeNode.cs +++ b/src/ViewModels/BranchTreeNode.cs @@ -120,7 +120,7 @@ namespace SourceGit.ViewModels private void MakeBranchNode(Models.Branch branch, List roots, Dictionary folders, string prefix, bool isFiltered, bool bForceExpanded) { var sepIdx = branch.Name.IndexOf('/', StringComparison.Ordinal); - if (sepIdx == -1) + if (sepIdx == -1 || branch.IsDetachedHead) { roots.Add(new BranchTreeNode() { From 6932ce44a95740b494374e96f4425c53b03e947a Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Sep 2024 17:19:55 +0800 Subject: [PATCH 12/42] fix: new window opened on failing fetch due to missing `StrictHostKeyChecking=accept-new` for repo remote without private ssh key (#485) --- src/App.axaml.cs | 3 +++ src/Commands/Command.cs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/App.axaml.cs b/src/App.axaml.cs index a434fa5e..090f060e 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -521,6 +521,9 @@ namespace SourceGit return false; var param = args[0]; + if (Directory.Exists(param)) + return false; + if (!param.StartsWith("enter passphrase", StringComparison.OrdinalIgnoreCase) && !param.Contains(" password", StringComparison.OrdinalIgnoreCase)) return false; diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs index b347dc37..c30ba59b 100644 --- a/src/Commands/Command.cs +++ b/src/Commands/Command.cs @@ -59,9 +59,14 @@ namespace SourceGit.Commands // If an SSH private key was provided, sets the environment. if (!string.IsNullOrEmpty(SSHKey)) + { start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new -i '{SSHKey}'"); + } else + { + start.Environment.Add("GIT_SSH_COMMAND", $"ssh -o StrictHostKeyChecking=accept-new"); start.Arguments += "-c credential.helper=manager "; + } // Force using en_US.UTF-8 locale to avoid GCM crash if (OperatingSystem.IsLinux()) From 900ebd8282d7e88853274775645b1a8108486c5b Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Sep 2024 20:11:34 +0800 Subject: [PATCH 13/42] feature: supports parameters in commit template (#487) - ${files_num} will be replaced with staged changes count - ${files} will be replaced with changed file paths - ${files:N} will be replaced with top N changes file paths and with `and {TOTAL - N} other files` at end of replaced string. --- src/Models/CommitTemplate.cs | 62 +++++++++++++++++++++++++++++++++-- src/ViewModels/WorkingCopy.cs | 6 +--- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/Models/CommitTemplate.cs b/src/Models/CommitTemplate.cs index d67d4839..57a88508 100644 --- a/src/Models/CommitTemplate.cs +++ b/src/Models/CommitTemplate.cs @@ -1,9 +1,17 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.Models { - public class CommitTemplate : ObservableObject + public partial class CommitTemplate : ObservableObject { + [GeneratedRegex(@"\$\{files(\:\d+)?\}")] + private static partial Regex REG_COMMIT_TEMPLATE_FILES(); + public string Name { get => _name; @@ -16,6 +24,56 @@ namespace SourceGit.Models set => SetProperty(ref _content, value); } + public string Apply(List changes) + { + var content = _content.Replace("${files_num}", $"{changes.Count}"); + var matches = REG_COMMIT_TEMPLATE_FILES().Matches(content); + if (matches.Count == 0) + return content; + + var builder = new StringBuilder(); + var last = 0; + for (int i = 0; i < matches.Count; i++) + { + var match = matches[i]; + if (!match.Success) + continue; + + var start = match.Index; + if (start != last) + builder.Append(content.Substring(last, start - last)); + + var countStr = match.Groups[1].Value; + var paths = new List(); + var more = string.Empty; + if (countStr is { Length: <= 1 }) + { + foreach (var c in changes) + paths.Add(c.Path); + } + else + { + var count = Math.Min(int.Parse(countStr.Substring(1)), changes.Count); + for (int j = 0; j < count; j++) + paths.Add(changes[i].Path); + + if (count < changes.Count) + more = $" and {changes.Count - count} other files"; + } + + builder.Append(string.Join(", ", paths)); + if (!string.IsNullOrEmpty(more)) + builder.Append(more); + + last = start + match.Length; + } + + if (last != content.Length - 1) + builder.Append(content.Substring(last)); + + return builder.ToString(); + } + private string _name = string.Empty; private string _content = string.Empty; } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index c6f46011..2dad3fc2 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -780,13 +780,9 @@ namespace SourceGit.ViewModels foreach (var change in _selectedUnstaged) { if (change.IsConflit) - { hasConflicts = true; - } else - { hasNoneConflicts = true; - } } if (hasConflicts) @@ -1160,7 +1156,7 @@ namespace SourceGit.ViewModels item.Icon = App.CreateMenuIcon("Icons.Code"); item.Click += (_, e) => { - CommitMessage = template.Content; + CommitMessage = template.Apply(_staged); e.Handled = true; }; menu.Items.Add(item); From 84fda6a8db893e256f69542ad9f2b17fee274ee4 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Sep 2024 21:35:33 +0800 Subject: [PATCH 14/42] feature: add property `RestoreOnStartup` property to `ViewModels.Workspace` (#488) --- src/Resources/Locales/de_DE.axaml | 3 +- src/Resources/Locales/en_US.axaml | 3 +- src/Resources/Locales/zh_CN.axaml | 3 +- src/Resources/Locales/zh_TW.axaml | 3 +- src/ViewModels/ConfigureWorkspace.cs | 5 +--- src/ViewModels/Launcher.cs | 2 +- src/ViewModels/Preference.cs | 42 +++++++++++++++++++++------- src/ViewModels/Workspace.cs | 11 ++++++-- src/Views/ConfigureWorkspace.axaml | 12 +++++--- 9 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 586e2ed9..5cea52ce 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -150,8 +150,9 @@ Benutzername Benutzername für dieses Repository Arbeitsplätze - Name Farbe + Name + Zuletzt geöffnete Tabs beim Starten wiederherstellen Kopieren Kopiere gesamten Text COMMIT-NACHRICHT KOPIEREN diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 72a6a8ba..fec41bb4 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -149,8 +149,9 @@ User Name User name for this repository Workspaces - Name Color + Name + Restore tabs on startup Copy Copy All Text COPY MESSAGE diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 6c8739fe..0ae65f91 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -152,8 +152,9 @@ 用户名 应用于本仓库的用户名 工作区 - 名称 颜色 + 名称 + 启动时恢复打开的仓库 复制 复制全部文本 复制内容 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index defd33d1..c90893f7 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -152,8 +152,9 @@ 使用者名稱 用於本存放庫的使用者名稱 工作區 - 名稱 顏色 + 名稱 + 啟動時還原上次開啟的存放庫 複製 複製全部內容 複製內容 diff --git a/src/ViewModels/ConfigureWorkspace.cs b/src/ViewModels/ConfigureWorkspace.cs index 2c6c5595..23b0a1ae 100644 --- a/src/ViewModels/ConfigureWorkspace.cs +++ b/src/ViewModels/ConfigureWorkspace.cs @@ -36,10 +36,7 @@ namespace SourceGit.ViewModels public void Add() { - var workspace = new Workspace(); - workspace.Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}"; - workspace.Color = 4278221015; - + var workspace = new Workspace() { Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}" }; Preference.Instance.Workspaces.Add(workspace); Workspaces.Add(workspace); Selected = workspace; diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 6ed9cee1..15c22c16 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -81,7 +81,7 @@ namespace SourceGit.ViewModels } else { - ActiveWorkspace = new Workspace() { Name = "Unnamed", Color = 4278221015 }; + ActiveWorkspace = new Workspace() { Name = "Unnamed" }; foreach (var w in pref.Workspaces) w.IsActive = false; diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index 2df40675..ef63d61e 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -22,15 +22,9 @@ namespace SourceGit.ViewModels _isLoading = false; } - if (!_instance.IsGitConfigured()) - _instance.GitInstallPath = Native.OS.FindGitExecutable(); - - if (_instance._shellOrTerminal == -1) - _instance.AutoSelectShellOrTerminal(); - - if (_instance.Workspaces.Count == 0) - _instance.Workspaces.Add(new Workspace() { Name = "Default", Color = 4278221015 }); - + _instance.PrepareGit(); + _instance.PrepareShellOrTerminal(); + _instance.PrepareWorkspaces(); return _instance; } } @@ -501,8 +495,18 @@ namespace SourceGit.ViewModels } } - private void AutoSelectShellOrTerminal() + private void PrepareGit() { + var path = Native.OS.GitExecutable; + if (string.IsNullOrEmpty(path) || !File.Exists(path)) + GitInstallPath = Native.OS.FindGitExecutable(); + } + + private void PrepareShellOrTerminal() + { + if (_shellOrTerminal >= 0) + return; + for (int i = 0; i < Models.ShellOrTerminal.Supported.Count; i++) { var shell = Models.ShellOrTerminal.Supported[i]; @@ -514,6 +518,24 @@ namespace SourceGit.ViewModels } } + private void PrepareWorkspaces() + { + if (Workspaces.Count == 0) + { + Workspaces.Add(new Workspace() { Name = "Default" }); + return; + } + + foreach (var workspace in Workspaces) + { + if (!workspace.RestoreOnStartup) + { + workspace.Repositories.Clear(); + workspace.ActiveIdx = 0; + } + } + } + private RepositoryNode FindNodeRecursive(string id, List collection) { foreach (var node in collection) diff --git a/src/ViewModels/Workspace.cs b/src/ViewModels/Workspace.cs index 4c7c288a..c1c586bc 100644 --- a/src/ViewModels/Workspace.cs +++ b/src/ViewModels/Workspace.cs @@ -43,6 +43,12 @@ namespace SourceGit.ViewModels set => SetProperty(ref _isActive, value); } + public bool RestoreOnStartup + { + get => _restoreOnStartup; + set => SetProperty(ref _restoreOnStartup, value); + } + [JsonIgnore] public IBrush Brush { @@ -57,8 +63,9 @@ namespace SourceGit.ViewModels } private string _name = string.Empty; - private uint _color = 0; + private uint _color = 4278221015; private bool _isActive = false; - private IBrush _brush = null; + private bool _restoreOnStartup = true; + private IBrush _brush = new SolidColorBrush(4278221015); } } diff --git a/src/Views/ConfigureWorkspace.axaml b/src/Views/ConfigureWorkspace.axaml index e245032e..582995b8 100644 --- a/src/Views/ConfigureWorkspace.axaml +++ b/src/Views/ConfigureWorkspace.axaml @@ -46,7 +46,7 @@ - + @@ -107,12 +107,16 @@ - + - - + + + + From e4870759f7889a4f3a2f8ab7df54fb309e00798a Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Sep 2024 21:46:04 +0800 Subject: [PATCH 15/42] ux: workspace configuration window --- src/Resources/Locales/de_DE.axaml | 1 - src/Resources/Locales/en_US.axaml | 1 - src/Resources/Locales/zh_CN.axaml | 1 - src/Resources/Locales/zh_TW.axaml | 1 - src/Views/ColorPicker.cs | 2 +- src/Views/ConfigureWorkspace.axaml | 15 ++++++--------- 6 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 5cea52ce..8ec97547 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -151,7 +151,6 @@ Benutzername für dieses Repository Arbeitsplätze Farbe - Name Zuletzt geöffnete Tabs beim Starten wiederherstellen Kopieren Kopiere gesamten Text diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index fec41bb4..e9717845 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -150,7 +150,6 @@ User name for this repository Workspaces Color - Name Restore tabs on startup Copy Copy All Text diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 0ae65f91..6d3474b6 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -153,7 +153,6 @@ 应用于本仓库的用户名 工作区 颜色 - 名称 启动时恢复打开的仓库 复制 复制全部文本 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index c90893f7..7d31e33e 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -153,7 +153,6 @@ 用於本存放庫的使用者名稱 工作區 顏色 - 名稱 啟動時還原上次開啟的存放庫 複製 複製全部內容 diff --git a/src/Views/ColorPicker.cs b/src/Views/ColorPicker.cs index 8d1a65de..8a0ecb55 100644 --- a/src/Views/ColorPicker.cs +++ b/src/Views/ColorPicker.cs @@ -148,7 +148,7 @@ namespace SourceGit.Views protected override Size MeasureOverride(Size availableSize) { - return new Size(256, 256); + return new Size(256, 240); } protected override void OnPointerPressed(PointerPressedEventArgs e) diff --git a/src/Views/ConfigureWorkspace.axaml b/src/Views/ConfigureWorkspace.axaml index 582995b8..c7ed900b 100644 --- a/src/Views/ConfigureWorkspace.axaml +++ b/src/Views/ConfigureWorkspace.axaml @@ -46,7 +46,7 @@ - + @@ -107,16 +107,13 @@ - - - - - + + - - - + + From 33f9ae0cd6a7c659f3a8ac69490516d104c819aa Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Sep 2024 09:12:38 +0800 Subject: [PATCH 16/42] fix: wrong executable file name for Zed editor on Linux (#477) --- 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 f784c691..0bc93fef 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -41,7 +41,7 @@ namespace SourceGit.Native finder.Fleet(FindJetBrainsFleet); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}/JetBrains/Toolbox"); finder.SublimeText(() => FindExecutable("subl")); - finder.Zed(() => FindExecutable("zed")); + finder.Zed(() => FindExecutable("zeditor")); return finder.Founded; } From 687b58576d6d91c19ca669955f9072e77fb850e3 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Sep 2024 09:21:04 +0800 Subject: [PATCH 17/42] code_style: use readonly property instead of responsive property for `Workspace.Brush` --- src/ViewModels/Workspace.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ViewModels/Workspace.cs b/src/ViewModels/Workspace.cs index c1c586bc..949cca82 100644 --- a/src/ViewModels/Workspace.cs +++ b/src/ViewModels/Workspace.cs @@ -1,8 +1,5 @@ using System.Collections.Generic; -using System.Text.Json.Serialization; - using Avalonia.Media; - using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -21,7 +18,7 @@ namespace SourceGit.ViewModels set { if (SetProperty(ref _color, value)) - Brush = new SolidColorBrush(value); + OnPropertyChanged(nameof(Brush)); } } @@ -49,11 +46,9 @@ namespace SourceGit.ViewModels set => SetProperty(ref _restoreOnStartup, value); } - [JsonIgnore] public IBrush Brush { - get => _brush; - private set => SetProperty(ref _brush, value); + get => new SolidColorBrush(_color); } public void AddRepository(string repo) @@ -66,6 +61,5 @@ namespace SourceGit.ViewModels private uint _color = 4278221015; private bool _isActive = false; private bool _restoreOnStartup = true; - private IBrush _brush = new SolidColorBrush(4278221015); } } From 5574dd2c384277312d74649555902cd6da953d77 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Sep 2024 09:50:27 +0800 Subject: [PATCH 18/42] refactor: a better way to fix window drop shadow effect on Win10 --- src/Native/Windows.cs | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index ab91ffdb..8bb4a0f0 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -26,23 +26,11 @@ namespace SourceGit.Native internal string szCSDVersion; } - [StructLayout(LayoutKind.Sequential)] - internal struct MARGINS - { - public int cxLeftWidth; - public int cxRightWidth; - public int cyTopHeight; - public int cyBottomHeight; - } - - [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)] - private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs); - [DllImport("ntdll")] private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation); - [DllImport("dwmapi.dll")] - private static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins); + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)] + private static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs); [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = false)] private static extern IntPtr ILCreateFromPathW(string pszPath); @@ -60,8 +48,8 @@ namespace SourceGit.Native v.dwOSVersionInfoSize = (uint)Marshal.SizeOf(); if (RtlGetVersion(ref v) == 0 && (v.dwMajorVersion < 10 || v.dwBuildNumber < 22000)) { - Window.WindowStateProperty.Changed.AddClassHandler((w, _) => ExtendWindowFrame(w)); - Control.LoadedEvent.AddClassHandler((w, _) => ExtendWindowFrame(w)); + Window.WindowStateProperty.Changed.AddClassHandler((w, _) => FixWindowFrameOnWin10(w)); + Control.LoadedEvent.AddClassHandler((w, _) => FixWindowFrameOnWin10(w)); } } @@ -206,14 +194,12 @@ namespace SourceGit.Native Process.Start(start); } - private void ExtendWindowFrame(Window w) + private void FixWindowFrameOnWin10(Window w) { - var platformHandle = w.TryGetPlatformHandle(); - if (platformHandle == null) - return; - - var margins = new MARGINS { cxLeftWidth = 1, cxRightWidth = 1, cyTopHeight = 1, cyBottomHeight = 1 }; - DwmExtendFrameIntoClientArea(platformHandle.Handle, ref margins); + if (w.WindowState != WindowState.Normal) + w.SystemDecorations = SystemDecorations.Full; + else + w.SystemDecorations = SystemDecorations.BorderOnly; } #region EXTERNAL_EDITOR_FINDER From 0ed1f369e9f22ad1e0d03aa08472cca85a51a39b Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Sep 2024 14:38:11 +0800 Subject: [PATCH 19/42] feature: display commit's detail info even if the commit is not shown in histories --- src/ViewModels/Histories.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 662d58fa..b5a72763 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -113,11 +113,19 @@ namespace SourceGit.ViewModels public void NavigateTo(string commitSHA) { var commit = _commits.Find(x => x.SHA.StartsWith(commitSHA, StringComparison.Ordinal)); - if (commit != null) + if (commit == null) + { + AutoSelectedCommit = null; + commit = new Commands.QuerySingleCommit(_repo.FullPath, commitSHA).Result(); + } + else { AutoSelectedCommit = commit; NavigationId = _navigationId + 1; + } + if (commit != null) + { if (_detailContext is CommitDetail detail) { detail.Commit = commit; @@ -129,6 +137,10 @@ namespace SourceGit.ViewModels DetailContext = commitDetail; } } + else + { + DetailContext = null; + } } public void Select(IList commits) From a690f774684c0cc29f8f4b940bbf34fd079283cf Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Sep 2024 14:41:59 +0800 Subject: [PATCH 20/42] readme: update OpenAI usage (#489) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 255d7c11..4bd90c9e 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ For `OpenAI`: For other AI service: -* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions` +* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions`. For example, when using `Ollama`, it should be `http://localhost:11434/v1/chat/completions` instead of `http://localhost:11434/api/generate` * The `API Key` is optional that depends on the service ## External Tools From 6a0cf30db262143b2e04effbd0a8f38c7c937100 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Sep 2024 15:59:34 +0800 Subject: [PATCH 21/42] fix: wrong width for commit graph --- src/Views/Histories.axaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 46c73300..2c8014ca 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -451,7 +451,7 @@ namespace SourceGit.Views return; // Calculate drawing area. - double width = Bounds.Width - 156 - 96 - histories.AuthorNameColumnWidth.Value; + double width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value; double height = Bounds.Height; double startY = list.Scroll?.Offset.Y ?? 0; double endY = startY + height + 28; From cb2caa0930234e81210d94de546eb774da170a34 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 20 Sep 2024 10:12:21 +0800 Subject: [PATCH 22/42] ux: icons for group header --- src/Resources/Icons.axaml | 8 +++++-- src/Views/Repository.axaml | 49 ++++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml index 0b32369c..f99bbf63 100644 --- a/src/Resources/Icons.axaml +++ b/src/Resources/Icons.axaml @@ -85,6 +85,7 @@ m224 154a166 166 0 00-166 166v192a166 166 0 00166 166h64v-76h-64a90 90 0 01-90-90v-192a90 90 0 0190-90h320a90 90 0 0190 90v192a90 90 0 01-90 90h-128v77h128a166 166 0 00166-167v-192a166 166 0 00-166-166h-320zm166 390a90 90 0 0190-90h128v-76h-128a166 166 0 00-166 166v192a166 166 0 00166 166h320a166 166 0 00166-166v-192a166 166 0 00-166-166h-64v77h64a90 90 0 0190 90v192a90 90 0 01-90 90h-320a90 90 0 01-90-90v-192z M706 302a289 289 0 00-173 44 27 27 0 1029 46 234 234 0 01125-36c23 0 45 3 66 9 93 28 161 114 161 215C914 704 813 805 687 805H337C211 805 110 704 110 580c0-96 61-178 147-210C282 263 379 183 495 183a245 245 0 01210 119z M364 512h67v108h108v67h-108v108h-67v-108h-108v-67h108v-108zm298-64A107 107 0 01768 555C768 614 720 660 660 660h-108v-54h-108v-108h-94v108h-94c4-21 22-47 44-51l-1-12a75 75 0 0171-75a128 128 0 01239-7a106 106 0 0153-14z + M725 128a85 85 0 0185 85v427a85 85 0 01-85 85h-171v85h43a43 43 0 0143 43h299v85h-299a43 43 0 01-43 43h-171a43 43 0 01-43-43H85v-85h299a43 43 0 0143-43h43v-85H299a85 85 0 01-85-85V213a85 85 0 0185-85h427z M1024 64v704h-128v128h-128v128h-768v-704h128v-128h128v-128zM64 960h640v-576h-640zM320 128v64h576v512h64v-576zM192 256v64h576v512h64v-576zM432 688L576 832H480L384 736 288 832H192l144-144L192 544h96L384 640l96-96H576z M853 256h-43v512h43c47 0 85-38 85-85v-341c0-47-38-85-85-85zM725 768V171h128V85h-341v85H640v85H171c-47 0-85 38-85 85v341c0 47 38 85 85 85h469V853h-128v85h341v-85H725v-86zm-469-171v-171h384v171H256z M960 146v91C960 318 759 384 512 384S64 318 64 238V146C64 66 265 0 512 0s448 66 448 146zM960 352v206C960 638 759 704 512 704S64 638 64 558V352c96 66 272 97 448 97S864 418 960 352zm0 320v206C960 958 759 1024 512 1024S64 958 64 878V672c96 66 272 97 448 97S864 738 960 672z @@ -101,9 +102,11 @@ M576 160H448c-18 0-32-14-32-32s14-32 32-32h128c18 0 32 14 32 32s-14 32-32 32zm243 186 36-36c13-13 13-33 0-45s-33-13-45 0l-33 33C708 233 614 192 512 192c-212 0-384 172-384 384s172 384 384 384 384-172 384-384c0-86-29-166-77-230zM544 894V864c0-18-14-32-32-32s-32 14-32 32v30C329 879 209 759 194 608H224c18 0 32-14 32-32s-14-32-32-32h-30C209 393 329 273 480 258V288c0 18 14 32 32 32s32-14 32-32v-30C695 273 815 393 830 544H800c-18 0-32 14-32 32s14 32 32 32h30C815 759 695 879 544 894zm108-471-160 128c-14 11-16 31-5 45 6 8 16 12 25 12 7 0 14-2 20-7l160-128c14-11 16-31 5-45-11-14-31-16-45-5z M558 545 790 403c24-15 31-47 16-71-15-24-46-31-70-17L507 457 277 315c-24-15-56-7-71 17-15 24-7 56 17 71l232 143V819c0 28 23 51 51 51 28 0 51-23 51-51V545h0zM507 0l443 256v512L507 1024 63 768v-512L507 0z M770 320a41 41 0 00-56-14l-252 153L207 306a41 41 0 10-43 70l255 153 2 296a41 41 0 0082 0l-2-295 255-155a41 41 0 0014-56zM481 935a42 42 0 01-42 0L105 741a42 42 0 01-21-36v-386a42 42 0 0121-36L439 89a42 42 0 0142 0l335 193a42 42 0 0121 36v87h84v-87a126 126 0 00-63-109L523 17a126 126 0 00-126 0L63 210a126 126 0 00-63 109v386a126 126 0 0063 109l335 193a126 126 0 00126 0l94-54-42-72zM1029 700h-126v-125a42 42 0 00-84 0v126h-126a42 42 0 000 84h126v126a42 42 0 1084 0v-126h126a42 42 0 000-84z + M416 587c21 0 37 17 37 37v299A37 37 0 01416 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zm448 0c21 0 37 17 37 37v299A37 37 0 01864 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zM758 91l183 189a37 37 0 010 52l-182 188a37 37 0 01-53 1l-183-189a37 37 0 010-52l182-188a37 37 0 0153-1zM416 139c21 0 37 17 37 37v299A37 37 0 01416 512h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299z M875 128h-725A107 107 0 0043 235v555A107 107 0 00149 896h725a107 107 0 00107-107v-555A107 107 0 00875 128zm-115 640h-183v-58l25-3c15 0 19-8 14-24l-22-61H419l-28 82 39 2V768h-166v-58l18-3c18-2 22-11 26-24l125-363-40-4V256h168l160 448 39 3zM506 340l-72 218h145l-71-218h-2z M177 156c-22 5-33 17-36 37c-10 57-33 258-13 278l445 445c23 23 61 23 84 0l246-246c23-23 23-61 0-84l-445-445C437 120 231 145 177 156zM331 344c-26 26-69 26-95 0c-26-26-26-69 0-95s69-26 95 0C357 276 357 318 331 344z M683 537h-144v-142h-142V283H239a44 44 0 00-41 41v171a56 56 0 0014 34l321 321a41 41 0 0058 0l174-174a41 41 0 000-58zm-341-109a41 41 0 110-58a41 41 0 010 58zM649 284V142h-69v142h-142v68h142v142h69v-142h142v-68h-142z + M996 452 572 28A96 96 0 00504 0H96C43 0 0 43 0 96v408a96 96 0 0028 68l424 424c37 37 98 37 136 0l408-408c37-37 37-98 0-136zM224 320c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96zm1028 268L844 996c-37 37-98 37-136 0l-1-1L1055 647c34-34 53-79 53-127s-19-93-53-127L663 0h97a96 96 0 0168 28l424 424c37 37 37 98 0 136z M765 118 629 239l-16 137-186 160 54 59 183-168 144 4 136-129 47-43-175-12L827 67zM489 404c-66 0-124 55-124 125s54 121 124 121c66 0 120-55 120-121H489l23-121c-8-4-16-4-23-4zM695 525c0 114-93 207-206 207s-206-94-206-207 93-207 206-207c16 0 27 0 43 4l43-207c-27-4-54-8-85-8-229 0-416 188-416 419s187 419 416 419c225 0 408-180 416-403v-12l-210-4z M144 112h736c18 0 32 14 32 32v736c0 18-14 32-32 32H144c-18 0-32-14-32-32V144c0-18 14-32 32-32zm112 211v72a9 9 0 003 7L386 509 259 615a9 9 0 00-3 7v72a9 9 0 0015 7L493 516a9 9 0 000-14l-222-186a9 9 0 00-15 7zM522 624a10 10 0 00-10 10v60a10 10 0 0010 10h237a10 10 0 0010-10v-60a10 10 0 00-10-10H522z M897 673v13c0 51-42 93-93 93h-10c-1 0-2 0-2 0H220c-23 0-42 19-42 42v13c0 23 19 42 42 42h552c14 0 26 12 26 26 0 14-12 26-26 26H220c-51 0-93-42-93-93v-13c0-51 42-93 93-93h20c1-0 2-0 2-0h562c23 0 42-19 42-42v-13c0-11-5-22-13-29-8-7-17-11-28-10H660c-14 0-26-12-26-26 0-14 12-26 26-26h144c24-1 47 7 65 24 18 17 29 42 29 67zM479 98c-112 0-203 91-203 203 0 44 14 85 38 118l132 208c15 24 50 24 66 0l133-209c23-33 37-73 37-117 0-112-91-203-203-203zm0 327c-68 0-122-55-122-122s55-122 122-122 122 55 122 122-55 122-122 122z @@ -121,6 +124,7 @@ M256 128l0 192L64 320l0 576 704 0 0-192 192 0L960 128 256 128zM704 832 128 832 128 384l576 0L704 832zM896 640l-128 0L768 320 320 320 320 192l576 0L896 640z M248 221a77 77 0 00-30-21c-18-7-40-10-68-5a224 224 0 00-45 13c-5 2-10 5-15 8l-3 2v68l11-9c10-8 21-14 34-19 13-5 26-7 39-7 12 0 21 3 28 10 6 6 9 16 9 29l-62 9c-14 2-26 6-36 11a80 80 0 00-25 20c-7 8-12 17-15 27-6 21-6 44 1 65a70 70 0 0041 43c10 4 21 6 34 6a80 80 0 0063-28v22h64V298c0-16-2-31-6-44a91 91 0 00-18-33zm-41 121v15c0 8-1 15-4 22a48 48 0 01-24 29 44 44 0 01-33 2 29 29 0 01-10-6 25 25 0 01-6-9 30 30 0 01-2-12c0-5 1-9 2-14a21 21 0 015-9 28 28 0 0110-7 83 83 0 0120-5l42-6zm323-68a144 144 0 00-16-42 87 87 0 00-28-29 75 75 0 00-41-11 73 73 0 00-44 14c-6 5-12 11-17 17V64H326v398h59v-18c8 10 18 17 30 21 6 2 13 3 21 3 16 0 31-4 43-11 12-7 23-18 31-31a147 147 0 0019-46 248 248 0 006-57c0-17-2-33-5-49zm-55 49c0 15-1 28-4 39-2 11-6 20-10 27a41 41 0 01-15 15 37 37 0 01-36 1 44 44 0 01-13-12 59 59 0 01-9-18A76 76 0 01384 352v-33c0-10 1-20 4-29 2-8 6-15 10-22a43 43 0 0115-13 37 37 0 0119-5 35 35 0 0132 18c4 6 7 14 9 23 2 9 3 20 3 31zM154 634a58 58 0 0120-15c14-6 35-7 49-1 7 3 13 6 20 12l21 17V572l-6-4a124 124 0 00-58-14c-20 0-38 4-54 11-16 7-30 17-41 30-12 13-20 29-26 46-6 17-9 36-9 57 0 18 3 36 8 52 6 16 14 30 24 42 10 12 23 21 38 28 15 7 32 10 50 10 15 0 28-2 39-5 11-3 21-8 30-14l5-4v-57l-13 6a26 26 0 01-5 2c-3 1-6 2-8 3-2 1-15 6-15 6-4 2-9 3-14 4a63 63 0 01-38-4 53 53 0 01-20-14 70 70 0 01-13-24 111 111 0 01-5-34c0-13 2-26 5-36 3-10 8-19 14-26zM896 384h-256V320h288c21 1 32 12 32 32v384c0 18-12 32-32 32H504l132 133-45 45-185-185c-16-21-16-25 0-45l185-185L637 576l-128 128H896V384z M128 691H6V38h838v160h-64V102H70v525H128zM973 806H154V250h819v557zm-755-64h691V314H218v429zM365 877h448v64h-448z - M512 0C229 0 0 72 0 160v128C0 376 229 448 512 448s512-72 512-160v-128C1024 72 795 0 512 0zM512 544C229 544 0 472 0 384v192c0 88 229 160 512 160s512-72 512-160V384c0 88-229 160-512 160zM512 832c-283 0-512-72-512-160v192C0 952 229 1024 512 1024s512-72 512-160v-192c0 88-229 160-512 160z - M640 725 768 725 768 597 853 597 853 725 981 725 981 811 853 811 853 939 768 939 768 811 640 811 640 725M384 128C573 128 725 204 725 299 725 393 573 469 384 469 195 469 43 393 43 299 43 204 195 128 384 128M43 384C43 478 195 555 384 555 573 555 725 478 725 384L725 512 683 512 683 595C663 612 640 627 610 640L555 640 555 660C504 675 446 683 384 683 195 683 43 606 43 512L43 384M43 597C43 692 195 768 384 768 446 768 504 760 555 745L555 873C504 888 446 896 384 896 195 896 43 820 43 725L43 597Z + M853 267H514c-4 0-6-2-9-4l-38-66c-13-21-38-36-64-36H171c-41 0-75 34-75 75v555c0 41 34 75 75 75h683c41 0 75-34 75-75V341c0-41-34-75-75-75zm-683-43h233c4 0 6 2 9 4l38 66c13 21 38 36 64 36H853c6 0 11 4 11 11v75h-704V235c0-6 4-11 11-11zm683 576H171c-6 0-11-4-11-11V480h704V789c0 6-4 11-11 11z + M896 96 614 96c-58 0-128-19-179-51C422 38 390 19 358 19L262 19 128 19c-70 0-128 58-128 128l0 736c0 70 58 128 128 128l768 0c70 0 128-58 128-128L1024 224C1024 154 966 96 896 96zM704 685 544 685l0 160c0 19-13 32-32 32s-32-13-32-32l0-160L320 685c-19 0-32-13-32-32 0-19 13-32 32-32l160 0L480 461c0-19 13-32 32-32s32 13 32 32l0 160L704 621c19 0 32 13 32 32C736 666 723 685 704 685zM890 326 102 326 102 250c0-32 32-64 64-64l659 0c38 0 64 32 64 64L890 326z + M1182 527a91 91 0 00-88-117H92a91 91 0 00-88 117l137 441A80 80 0 00217 1024h752a80 80 0 0076-56zM133 295a31 31 0 0031 31h858a31 31 0 0031-31A93 93 0 00959 203H226a93 93 0 00-94 92zM359 123h467a31 31 0 0031-31A92 92 0 00765 0H421a92 92 0 00-92 92 31 31 0 0031 31z diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index ba4ac133..6200bd69 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -163,7 +163,10 @@ - + + + + - - - @@ -194,15 +198,16 @@ - - - - + + + + - - - From 5f567460e25ac678ba5316317a2364bf1f602c83 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 20 Sep 2024 14:15:19 +0800 Subject: [PATCH 23/42] fix: missing `-d ${WORKDIR}` parameter for `wt.exe` (#490) --- src/Native/Windows.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 8bb4a0f0..0f2e458d 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -155,6 +155,11 @@ namespace SourceGit.Native var startInfo = new ProcessStartInfo(); startInfo.WorkingDirectory = workdir; startInfo.FileName = OS.ShellOrTerminal; + + // Directly launching `Windows Terminal` need to specify the `-d` parameter + if (OS.ShellOrTerminal.EndsWith("wt.exe", StringComparison.OrdinalIgnoreCase)) + startInfo.Arguments = $"-d \"{workdir}\""; + Process.Start(startInfo); } From 094b07b03acd939424355ce3e301affcbe35284f Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 20 Sep 2024 14:41:27 +0800 Subject: [PATCH 24/42] ux: new icon for remotes --- src/Resources/Icons.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml index f99bbf63..ef3e13aa 100644 --- a/src/Resources/Icons.axaml +++ b/src/Resources/Icons.axaml @@ -85,7 +85,7 @@ m224 154a166 166 0 00-166 166v192a166 166 0 00166 166h64v-76h-64a90 90 0 01-90-90v-192a90 90 0 0190-90h320a90 90 0 0190 90v192a90 90 0 01-90 90h-128v77h128a166 166 0 00166-167v-192a166 166 0 00-166-166h-320zm166 390a90 90 0 0190-90h128v-76h-128a166 166 0 00-166 166v192a166 166 0 00166 166h320a166 166 0 00166-166v-192a166 166 0 00-166-166h-64v77h64a90 90 0 0190 90v192a90 90 0 01-90 90h-320a90 90 0 01-90-90v-192z M706 302a289 289 0 00-173 44 27 27 0 1029 46 234 234 0 01125-36c23 0 45 3 66 9 93 28 161 114 161 215C914 704 813 805 687 805H337C211 805 110 704 110 580c0-96 61-178 147-210C282 263 379 183 495 183a245 245 0 01210 119z M364 512h67v108h108v67h-108v108h-67v-108h-108v-67h108v-108zm298-64A107 107 0 01768 555C768 614 720 660 660 660h-108v-54h-108v-108h-94v108h-94c4-21 22-47 44-51l-1-12a75 75 0 0171-75a128 128 0 01239-7a106 106 0 0153-14z - M725 128a85 85 0 0185 85v427a85 85 0 01-85 85h-171v85h43a43 43 0 0143 43h299v85h-299a43 43 0 01-43 43h-171a43 43 0 01-43-43H85v-85h299a43 43 0 0143-43h43v-85H299a85 85 0 01-85-85V213a85 85 0 0185-85h427z + M115 386l19 33c17 29 44 50 76 60l116 33c34 10 58 41 58 77v80c0 22 12 42 32 52s32 30 32 52v78c0 31 30 54 60 45 32-9 57-35 65-68l6-22c8-34 30-63 61-80l16-9c30-17 48-49 48-83v-17c0-25-10-50-28-68l-8-8c-18-18-42-28-68-28H514c-22 0-44-6-64-17l-69-39c-9-5-15-13-18-22-6-19 2-40 20-49l12-6c13-7 29-8 43-3l46 15c16 5 34-1 44-15 9-14 8-33-2-46l-27-33c-20-24-20-59 1-83l31-37c18-21 20-50 7-73l-5-8c-7-0-14-1-21-1-186 0-343 122-396 290zM928 512c0-74-19-143-53-203L824 330c-31 13-48 48-37 80l34 101c7 21 24 37 45 42l58 15c2-18 4-36 4-55zM0 512a512 512 0 111024 0 512 512 0 11-1024 0z M1024 64v704h-128v128h-128v128h-768v-704h128v-128h128v-128zM64 960h640v-576h-640zM320 128v64h576v512h64v-576zM192 256v64h576v512h64v-576zM432 688L576 832H480L384 736 288 832H192l144-144L192 544h96L384 640l96-96H576z M853 256h-43v512h43c47 0 85-38 85-85v-341c0-47-38-85-85-85zM725 768V171h128V85h-341v85H640v85H171c-47 0-85 38-85 85v341c0 47 38 85 85 85h469V853h-128v85h341v-85H725v-86zm-469-171v-171h384v171H256z M960 146v91C960 318 759 384 512 384S64 318 64 238V146C64 66 265 0 512 0s448 66 448 146zM960 352v206C960 638 759 704 512 704S64 638 64 558V352c96 66 272 97 448 97S864 418 960 352zm0 320v206C960 958 759 1024 512 1024S64 958 64 878V672c96 66 272 97 448 97S864 738 960 672z From 535dc1ef49bf1de4f9e62f934f010273857e6e55 Mon Sep 17 00:00:00 2001 From: Jens Fischer Date: Fri, 20 Sep 2024 13:51:05 +0200 Subject: [PATCH 25/42] Add syntax highlighting for Kotlin --- src/Models/TextMateHelper.cs | 12 +- src/Resources/Grammars/kotlin.json | 701 +++++++++++++++++++++++++++++ 2 files changed, 708 insertions(+), 5 deletions(-) create mode 100644 src/Resources/Grammars/kotlin.json diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs index 4fb6ad93..b070c1cf 100644 --- a/src/Models/TextMateHelper.cs +++ b/src/Models/TextMateHelper.cs @@ -24,7 +24,7 @@ namespace SourceGit.Models _backend = new RegistryOptions(defaultTheme); _extraGrammars = new List(); - string[] extraGrammarFiles = ["toml.json"]; + string[] extraGrammarFiles = ["toml.json", "kotlin.json"]; foreach (var file in extraGrammarFiles) { var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Grammars/{file}", @@ -71,16 +71,18 @@ namespace SourceGit.Models public string GetScopeByFileName(string filename) { var extension = Path.GetExtension(filename); - var grammar = _extraGrammars.Find(x => x.GetScopeName().EndsWith(extension, StringComparison.OrdinalIgnoreCase)); - if (grammar != null) - return grammar.GetScopeName(); - if (extension == ".h") extension = ".cpp"; else if (extension == ".resx" || extension == ".plist" || extension == ".manifest") extension = ".xml"; else if (extension == ".command") extension = ".sh"; + else if (extension == ".kt" || extension == ".kts") + extension = ".kotlin"; + + var grammar = _extraGrammars.Find(x => x.GetScopeName().EndsWith(extension, StringComparison.OrdinalIgnoreCase)); + if (grammar != null) + return grammar.GetScopeName(); return _backend.GetScopeByExtension(extension); } diff --git a/src/Resources/Grammars/kotlin.json b/src/Resources/Grammars/kotlin.json new file mode 100644 index 00000000..e8f844d0 --- /dev/null +++ b/src/Resources/Grammars/kotlin.json @@ -0,0 +1,701 @@ +{ + "information_for_contributors": [ + "This file has been copied from https://github.com/eclipse/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/org.eclipse.buildship.kotlindsl.provider/kotlin.tmLanguage.json" + ], + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Kotlin", + "scopeName": "source.kotlin", + "patterns": [ + { + "include": "#import" + }, + { + "include": "#package" + }, + { + "include": "#code" + } + ], + "fileTypes": [ + "kts" + ], + "repository": { + "import": { + "begin": "\\b(import)\\b\\s?([\\w+.]*\\w+)?\\s*", + "beginCaptures": { + "1": { + "name": "storage.type.import.kotlin" + }, + "2": { + "name": "storage.modifier.import.kotlin" + } + }, + "end": ";|$", + "name": "meta.import.kotlin", + "contentName": "entity.name.package.kotlin", + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#hard-keywords" + }, + { + "match": "\\*", + "name": "variable.language.wildcard.kotlin" + } + ] + }, + "package": { + "begin": "\\b(package)\\b\\s*", + "beginCaptures": { + "1": { + "name": "storage.type.package.kotlin" + } + }, + "end": ";|$", + "name": "meta.package.kotlin", + "contentName": "entity.name.package.kotlin", + "patterns": [ + { + "include": "#comments" + } + ] + }, + "code": { + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#keywords" + }, + { + "include": "#annotation-simple" + }, + { + "include": "#annotation-site-list" + }, + { + "include": "#annotation-site" + }, + { + "include": "#class-declaration" + }, + { + "include": "#object-declaration" + }, + { + "include": "#type-alias" + }, + { + "include": "#function-declaration" + }, + { + "include": "#variable-declaration" + }, + { + "include": "#constant-declaration" + }, + { + "include": "#variable" + }, + { + "include": "#object" + }, + { + "include": "#type-constraint" + }, + { + "include": "#type-annotation" + }, + { + "include": "#function-call" + }, + { + "include": "#property.reference" + }, + { + "include": "#method-reference" + }, + { + "include": "#key" + }, + { + "include": "#string" + }, + { + "include": "#string-empty" + }, + { + "include": "#string-multiline" + }, + { + "include": "#character" + }, + { + "include": "#lambda-arrow" + }, + { + "include": "#operators" + }, + { + "include": "#self-reference" + }, + { + "include": "#decimal-literal" + }, + { + "include": "#hex-literal" + }, + { + "include": "#binary-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "match": ",", + "name": "punctuation.separator.delimiter.kotlin" + }, + { + "match": "\\.", + "name": "punctuation.separator.period.kotlin" + }, + { + "match": "\\?\\.", + "name": "punctuation.accessor.optional.kotlin" + } + ] + }, + "comments": { + "patterns": [ + { + "include": "#comment-line" + }, + { + "include": "#comment-block" + }, + { + "include": "#comment-javadoc" + } + ] + }, + "comment-line": { + "begin": "//", + "end": "$", + "name": "comment.line.double-slash.kotlin" + }, + "comment-block": { + "begin": "/\\*(?!\\*)", + "end": "\\*/", + "name": "comment.block.kotlin" + }, + "comment-javadoc": { + "patterns": [ + { + "begin": "/\\*\\*", + "end": "\\*/", + "name": "comment.block.javadoc.kotlin", + "patterns": [ + { + "match": "@(author|deprecated|return|see|serial|since|version)\\b", + "name": "keyword.other.documentation.javadoc.kotlin" + }, + { + "match": "(@param)\\s+(\\S+)", + "captures": { + "1": { + "name": "keyword.other.documentation.javadoc.kotlin" + }, + "2": { + "name": "variable.parameter.kotlin" + } + } + }, + { + "match": "(@(?:exception|throws))\\s+(\\S+)", + "captures": { + "1": { + "name": "keyword.other.documentation.javadoc.kotlin" + }, + "2": { + "name": "entity.name.type.class.kotlin" + } + } + }, + { + "match": "{(@link)\\s+(\\S+)?#([\\w$]+\\s*\\([^\\(\\)]*\\)).*}", + "captures": { + "1": { + "name": "keyword.other.documentation.javadoc.kotlin" + }, + "2": { + "name": "entity.name.type.class.kotlin" + }, + "3": { + "name": "variable.parameter.kotlin" + } + } + } + ] + } + ] + }, + "keywords": { + "patterns": [ + { + "include": "#prefix-modifiers" + }, + { + "include": "#postfix-modifiers" + }, + { + "include": "#soft-keywords" + }, + { + "include": "#hard-keywords" + }, + { + "include": "#control-keywords" + }, + { + "include": "#map-keywords" + } + ] + }, + "prefix-modifiers": { + "match": "\\b(abstract|final|enum|open|annotation|sealed|data|override|final|lateinit|private|protected|public|internal|inner|companion|noinline|crossinline|vararg|reified|tailrec|operator|infix|inline|external|const|suspend|value)\\b", + "name": "storage.modifier.other.kotlin" + }, + "postfix-modifiers": { + "match": "\\b(where|by|get|set)\\b", + "name": "storage.modifier.other.kotlin" + }, + "soft-keywords": { + "match": "\\b(catch|finally|field)\\b", + "name": "keyword.soft.kotlin" + }, + "hard-keywords": { + "match": "\\b(as|typeof|is|in)\\b", + "name": "keyword.hard.kotlin" + }, + "control-keywords": { + "match": "\\b(if|else|while|do|when|try|throw|break|continue|return|for)\\b", + "name": "keyword.control.kotlin" + }, + "map-keywords": { + "match": "\\b(to)\\b", + "name": "keyword.map.kotlin" + }, + "annotation-simple": { + "match": "(?<([^<>]|\\g)+>)?", + "captures": { + "1": { + "name": "storage.type.class.kotlin" + }, + "2": { + "name": "entity.name.type.class.kotlin" + }, + "3": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + } + } + }, + "object-declaration": { + "match": "\\b(object)\\s+(\\b\\w+\\b|`[^`]+`)", + "captures": { + "1": { + "name": "storage.type.object.kotlin" + }, + "2": { + "name": "entity.name.type.object.kotlin" + } + } + }, + "type-alias": { + "match": "\\b(typealias)\\s+(\\b\\w+\\b|`[^`]+`)\\s*(?<([^<>]|\\g)+>)?", + "captures": { + "1": { + "name": "storage.type.alias.kotlin" + }, + "2": { + "name": "entity.name.type.kotlin" + }, + "3": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + } + } + }, + "function-declaration": { + "begin": "\\b(fun)\\b\\s*(?<([^<>]|\\g)+>)?\\s*(?:(\\w+)\\.)?(\\b\\w+\\b|`[^`]+`)\\(", + "beginCaptures": { + "1": { + "name": "storage.type.function.kotlin" + }, + "2": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + }, + "4": { + "name": "entity.name.type.class.extension.kotlin" + }, + "5": { + "name": "entity.name.function.declaration.kotlin" + } + }, + "end": "\\)", + "endCaptures": { + "1": { + "name": "keyword.operator.assignment.type.kotlin" + } + }, + "patterns": [ + { + "include": "#parameter-declaration" + } + ] + }, + "parameter-declaration": { + "match": "\\b(\\w+)\\s*(:)\\s*(\\w+)(\\?)?(,)?", + "captures": { + "1": { + "name": "variable.parameter.kotlin" + }, + "2": { + "name": "keyword.operator.assignment.type.kotlin" + }, + "3": { + "name": "entity.name.type.kotlin" + }, + "4": { + "name": "keyword.operator.optional" + }, + "5": { + "name": "punctuation.separator.delimiter.kotlin" + } + } + }, + "variable-declaration": { + "match": "\\b(var)\\b\\s*(?<([^<>]|\\g)+>)?", + "captures": { + "1": { + "name": "storage.type.variable.kotlin" + }, + "2": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + } + } + }, + "constant-declaration": { + "match": "\\b(val)\\b\\s*(?<([^<>]|\\g)+>)?", + "captures": { + "1": { + "name": "storage.type.variable.readonly.kotlin" + }, + "2": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + } + } + }, + "variable" : { + "match": "\\b(\\w+)(?=\\s*[:=])", + "captures": { + "1": { + "name": "variable.other.definition.kotlin" + } + } + }, + "object" : { + "match": "\\b(\\w+)(?=\\.)", + "captures": { + "1": { + "name": "variable.other.object.kotlin" + } + } + }, + "type-parameter": { + "patterns": [ + { + "match": "(:)?\\s*(\\b\\w+\\b)(\\?)?", + "captures": { + "1": { + "name": "keyword.operator.assignment.kotlin" + }, + "2": { + "name": "entity.name.type.kotlin" + }, + "3": { + "name": "keyword.operator.optional" + } + } + }, + { + "match": "\\b(in|out)\\b", + "name": "storage.modifier.kotlin" + } + ] + }, + "type-annotation": { + "match": "(?|(?[<(]([^<>()\"']|\\g)+[)>]))+", + "captures": { + "0": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + } + } + }, + "function-call": { + "match": "(?:(\\?\\.)|(\\.))?(\\b\\w+\\b|`[^`]+`)\\s*(?<([^<>]|\\g)+>)?\\s*(?=[({])", + "captures": { + "1": { + "name": "punctuation.accessor.optional.kotlin" + }, + "2": { + "name": "punctuation.separator.period.kotlin" + }, + "3": { + "name": "entity.name.function.call.kotlin" + }, + "4": { + "patterns": [ + { + "include": "#type-parameter" + } + ] + } + } + }, + "property.reference": { + "match": "(?:(\\?\\.)|(\\.))(\\w+)\\b", + "captures": { + "1": { + "name": "punctuation.accessor.optional.kotlin" + }, + "2": { + "name": "punctuation.separator.period.kotlin" + }, + "3": { + "name": "variable.other.property.kotlin" + } + } + }, + "method-reference": { + "match": "\\??::(\\b\\w+\\b|`[^`]+`)", + "captures": { + "1": { + "name": "entity.name.function.reference.kotlin" + } + } + }, + "key": { + "match": "\\b(\\w=)\\s*(=)", + "captures": { + "1": { + "name": "variable.parameter.kotlin" + }, + "2": { + "name": "keyword.operator.assignment.kotlin" + } + } + }, + "string-empty": { + "match": "(?", + "name": "storage.type.function.arrow.kotlin" + }, + "operators": { + "patterns": [ + { + "match": "(===?|\\!==?|<=|>=|<|>)", + "name": "keyword.operator.comparison.kotlin" + }, + { + "match": "(\\?:)", + "name": "keyword.operator.elvis.kotlin" + }, + { + "match": "([+*/%-]=)", + "name": "keyword.operator.assignment.arithmetic.kotlin" + }, + { + "match": "(=)", + "name": "keyword.operator.assignment.kotlin" + }, + { + "match": "([+*/%-])", + "name": "keyword.operator.arithmetic.kotlin" + }, + { + "match": "(!|&&|\\|\\|)", + "name": "keyword.operator.logical.kotlin" + }, + { + "match": "(--|\\+\\+)", + "name": "keyword.operator.increment-decrement.kotlin" + }, + { + "match": "(\\.\\.)", + "name": "keyword.operator.range.kotlin" + } + ] + }, + "self-reference": { + "match": "\\b(this|super)(@\\w+)?\\b", + "name": "variable.language.this.kotlin" + } + } +} \ No newline at end of file From a8a85613fcf09c40e2564607481a23638be102af Mon Sep 17 00:00:00 2001 From: Jens Fischer Date: Fri, 20 Sep 2024 14:13:02 +0200 Subject: [PATCH 26/42] Add support for WezTerm --- src/Models/ShellOrTerminal.cs | 1 + src/Native/Linux.cs | 3 +++ src/Resources/Images/ShellIcons/wezterm.png | Bin 0 -> 3071 bytes 3 files changed, 4 insertions(+) create mode 100644 src/Resources/Images/ShellIcons/wezterm.png diff --git a/src/Models/ShellOrTerminal.cs b/src/Models/ShellOrTerminal.cs index 02b294a0..8ab25788 100644 --- a/src/Models/ShellOrTerminal.cs +++ b/src/Models/ShellOrTerminal.cs @@ -54,6 +54,7 @@ namespace SourceGit.Models new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"), new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"), new ShellOrTerminal("foot", "Foot", "foot"), + new ShellOrTerminal("wezterm", "WezTerm", "wezterm"), new ShellOrTerminal("custom", "Custom", ""), }; } diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 0bc93fef..8f84a735 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -71,6 +71,9 @@ namespace SourceGit.Native startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? home : workdir; startInfo.FileName = OS.ShellOrTerminal; + if (OS.ShellOrTerminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase)) + startInfo.Arguments = $"start --cwd \"{workdir}\""; + try { Process.Start(startInfo); diff --git a/src/Resources/Images/ShellIcons/wezterm.png b/src/Resources/Images/ShellIcons/wezterm.png new file mode 100644 index 0000000000000000000000000000000000000000..ed7a659f6656d59a4969c77b5f0e324b3ec7a85e GIT binary patch literal 3071 zcmVEX>4Tx04R}tkv&MmKpe$i(~2Kd9Lyl%kfA!+MMZS0RVYG*P%E_RU~=gfG-*gu zTpR`0f`cE6RR2@dv=!RpZ z5^*V$U6s0D(F+k_gfOcx+nkf-Bz(u$Jpz2ai}Ec0bAOJ0EoUUT9?#W*m&KWDqT&FpL1QxLb84^@fQ9>CGqO=;M*htZS+{Zuc`DJpclfrSJ>&10HMuF~Kpiy((?_<|(oB+XR;L2$GD|KMzlk{3! ziyQ$1+rY(jTT}Od%N=0o$y6-GlY%sbd>(i|qi@OrgSSB6TC=y-K29HiGxhU`@FlSv$ucGwEFu2oN;ou1lX3H00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNliru=m``I1`*L%@8$pi3H(V!K~#9!<(o;299J2~f3KFV z-ex@Gneo`MQ6^pjjvZnX9NPgqLg56GAuLLi0~`VzP=tsC5rGR5C>IpL2_+#QxB&?v zBnVECAVIM`1QN#!!MkNUo_*`RtLl9mx~Hdms=B*orjhKKZ}bk+UG;QTIo10V0zzlF6cnkP5sH3Nk{jJ>W1r_$;UHcDPO7VH%2cSL* z7~GnoffFDd0!@xbPE%`TazyR(C?q==D9+3T(R8+xOg8&%7 z5ewlUYgZ0hf^1*I0BpAqde$%iJr;=7QNvPQbUB{}0YL*o$-hL&J9#q#U|XH;F=2n4 zjopvckxa#S_QjhO04$NtcIcRQG^7}UPoaE{PLI;u1-Hy1*6_nypV|EEMZ21QfA;& zUuW8wz!Eh;sTjS9N9avGNX!~&%c2zqC%!;FwiAX8%p0D#E0K|ztKfwsuPpxNL z_F*k$`IfPX%{@<&az4Uxt7Wb~iG;ixwo`^mEXj2));<7FGA;YCqIVu=OV3jzojaTE zK&7?T2+z-kg6D@g%8E*>h!I3W0nj?z858JDd?|GCWpA9h!Z0QG8irx8vF9-q23i-G z$o>V}>?3Awz_!+7n|+kM8=)$xLrg$nphQ&}<#GT}_`1*u6VP-e?hV<^SuRgJiK{=T zg7iqm=7Ewo%0%{s+T;}`rqNT=lb{I{L)6Yhl!=HR(FZtzd21=PGl2*Yh>vad2Vs#C zo}Q>J$+0)rX~qbGUpGCk`fL-3r5xe|ED)msGKF0;A)#C!Mo^2Qh8DNVL8L`dKAhC!eNR zz7qO<(%Df{LDw5c>$xRqfUjo}(TjY5jUrat;Y4g}W9sc}tpTF2YYw>H2Z)s06$Yal zs;jSYY2y223MX1S79&Z@Ib17Sv&$^f zW?Vz05+N;0IzuC}Jq$m5|xMF3YtL-82jeEBq6`ZDM4oIGcJOWuWUD zEqVf9mx5$ibz!PL9D8GhVY)Y%$-lJ#keMbKI|#&4%37oWxwiA~$ca$gULZiz*}qdL zT?!4CgFRnhUHmi6*g12eg%Bsl-bg&QC$ulup9*n;F_QE4uS?98 z-b4_x#rGF9Ft!=n>z zTQ$G9j<2Tym@E9FwqVmpR-;5?iOuudld;J40Ml59*7+)3)ph6()fkxTO(QyA4NKjm z6FWmQ$dY>@G)MPzuDYlNr`na+yvb5P9}isknydlOajQ*@ zD0Xam4#RM8-AT&c6lHG&&(G48xTk@5tWP~kJhp}IrFGAJ;vzlukiGEn~bxFuXC72P{(q`vsJoOf9P?6vO7jRwk2pz-gG1%AHfLZ#9ij@(pb;vwps zE4>r?#$0}wzV1(joS_m^h{~85g#uDWG8V2CJLFIPUT9vm9gjW&t%1dLnT+;}zS{ga3 z;5}f^8r%JM6f$gPrzicc_5G6wUuN}OlWQNz6_4MzaQ2J=phUd_^70ze|CdDMHR^YK z)7CpT2)xefy)!s3CxHh?E}k7{vC40}+0-F0uPT|I`=_CUbFbg?95ay)z|;B65f-_ZSlcd7zkbQ_B@X8^yuYt z*hR*XPew3Epdh92>iQ!EN@!{{XE N002ovPDHLkV1g2*&rbjV literal 0 HcmV?d00001 From 30765cf7b39bc7dccbf70d84fcbacacc344b02f9 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 20 Sep 2024 21:59:40 +0800 Subject: [PATCH 27/42] code_review: PR #495 * correct the path passed to `--cwd` --- src/Native/Linux.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs index 8f84a735..55b7b43b 100644 --- a/src/Native/Linux.cs +++ b/src/Native/Linux.cs @@ -66,13 +66,15 @@ namespace SourceGit.Native public void OpenTerminal(string workdir) { - var startInfo = new ProcessStartInfo(); var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - startInfo.WorkingDirectory = string.IsNullOrEmpty(workdir) ? home : workdir; + var cwd = string.IsNullOrEmpty(workdir) ? home : workdir; + + var startInfo = new ProcessStartInfo(); + startInfo.WorkingDirectory = cwd; startInfo.FileName = OS.ShellOrTerminal; if (OS.ShellOrTerminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase)) - startInfo.Arguments = $"start --cwd \"{workdir}\""; + startInfo.Arguments = $"start --cwd \"{cwd}\""; try { From 0dbca4fe47f0bf359bad1dbf1d6f6fbf81e4c6ce Mon Sep 17 00:00:00 2001 From: Jens Fischer Date: Fri, 20 Sep 2024 16:30:40 +0200 Subject: [PATCH 28/42] Add syntax highlighting for Haxe --- src/Models/TextMateHelper.cs | 2 +- src/Resources/Grammars/haxe.json | 2488 ++++++++++++++++++++++++++++++ src/Resources/Grammars/hxml.json | 70 + 3 files changed, 2559 insertions(+), 1 deletion(-) create mode 100644 src/Resources/Grammars/haxe.json create mode 100644 src/Resources/Grammars/hxml.json diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs index b070c1cf..fdb2cb66 100644 --- a/src/Models/TextMateHelper.cs +++ b/src/Models/TextMateHelper.cs @@ -24,7 +24,7 @@ namespace SourceGit.Models _backend = new RegistryOptions(defaultTheme); _extraGrammars = new List(); - string[] extraGrammarFiles = ["toml.json", "kotlin.json"]; + string[] extraGrammarFiles = ["toml.json", "kotlin.json", "haxe.json", "hxml.json"]; foreach (var file in extraGrammarFiles) { var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Grammars/{file}", diff --git a/src/Resources/Grammars/haxe.json b/src/Resources/Grammars/haxe.json new file mode 100644 index 00000000..12acc538 --- /dev/null +++ b/src/Resources/Grammars/haxe.json @@ -0,0 +1,2488 @@ +{ + "information_for_contributors": [ + "This file has been copied from https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/haxe.tmLanguage", + "and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage" + ], + "fileTypes": [ + "hx", + "dump" + ], + "name": "Haxe", + "scopeName": "source.hx", + "uuid": "67c72f9f-862c-4e48-8951-dcc22c0bb4ea", + "patterns": [ + { + "include": "#all" + } + ], + "repository": { + "all": { + "patterns": [ + { + "include": "#global" + }, + { + "include": "#package" + }, + { + "include": "#import" + }, + { + "include": "#using" + }, + { + "match": "\\b(final)\\b(?=\\s+(class|interface|extern|private)\\b)", + "name": "storage.modifier.hx" + }, + { + "include": "#abstract" + }, + { + "include": "#class" + }, + { + "include": "#enum" + }, + { + "include": "#interface" + }, + { + "include": "#typedef" + }, + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "global": { + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#conditional-compilation" + } + ] + }, + "block": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.block.end.hx" + } + }, + "patterns": [ + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "block-contents": { + "patterns": [ + { + "include": "#global" + }, + { + "include": "#regex" + }, + { + "include": "#array" + }, + { + "include": "#constants" + }, + { + "include": "#strings" + }, + { + "include": "#metadata" + }, + { + "include": "#method" + }, + { + "include": "#variable" + }, + { + "include": "#modifiers" + }, + { + "include": "#new-expr" + }, + { + "include": "#for-loop" + }, + { + "include": "#keywords" + }, + { + "include": "#arrow-function" + }, + { + "include": "#method-call" + }, + { + "include": "#enum-constructor-call" + }, + { + "include": "#punctuation-braces" + }, + { + "include": "#macro-reification" + }, + { + "include": "#operators" + }, + { + "include": "#operator-assignment" + }, + { + "include": "#punctuation-terminator" + }, + { + "include": "#punctuation-comma" + }, + { + "include": "#punctuation-accessor" + }, + { + "include": "#identifiers" + } + ] + }, + "identifiers": { + "patterns": [ + { + "include": "#constant-name" + }, + { + "include": "#type-name" + }, + { + "include": "#identifier-name" + } + ] + }, + "package": { + "begin": "package\\b", + "beginCaptures": { + "0": { + "name": "keyword.other.package.hx" + } + }, + "end": "$|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "patterns": [ + { + "include": "#type-path" + }, + { + "include": "#type-path-package-name" + } + ] + }, + "using": { + "begin": "using\\b", + "beginCaptures": { + "0": { + "name": "keyword.other.using.hx" + } + }, + "end": "$|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "patterns": [ + { + "include": "#type-path" + }, + { + "include": "#type-path-package-name" + } + ] + }, + "import": { + "begin": "import\\b", + "beginCaptures": { + "0": { + "name": "keyword.control.import.hx" + } + }, + "end": "$|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "patterns": [ + { + "include": "#type-path" + }, + { + "match": "\\b(as)\\b", + "name": "keyword.control.as.hx" + }, + { + "match": "\\b(in)\\b", + "name": "keyword.control.in.hx" + }, + { + "match": "\\*", + "name": "constant.language.import-all.hx" + }, + { + "match": "\\b([_A-Za-z]\\w*)\\b(?=\\s*(as|in|$|(;)))", + "name": "variable.other.hxt" + }, + { + "include": "#type-path-package-name" + } + ] + }, + "type-path": { + "patterns": [ + { + "include": "#global" + }, + { + "include": "#punctuation-accessor" + }, + { + "include": "#type-path-type-name" + } + ] + }, + "type-path-type-name": { + "match": "\\b(_*[A-Z]\\w*)\\b", + "name": "entity.name.type.hx" + }, + "type-path-package-name": { + "match": "\\b([_A-Za-z]\\w*)\\b", + "name": "support.package.hx" + }, + "abstract": { + "begin": "(?=abstract\\s+[A-Z])", + "end": "(?<=\\})|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "name": "meta.abstract.hx", + "patterns": [ + { + "include": "#abstract-name" + }, + { + "include": "#abstract-name-post" + }, + { + "include": "#abstract-block" + } + ] + }, + "abstract-name": { + "begin": "\\b(abstract)\\b", + "beginCaptures": { + "1": { + "name": "storage.type.class.hx" + } + }, + "end": "([_A-Za-z]\\w*)", + "endCaptures": { + "1": { + "name": "entity.name.type.class.hx" + } + }, + "patterns": [ + { + "include": "#global" + } + ] + }, + "abstract-name-post": { + "begin": "(?<=\\w)", + "end": "([\\{;])", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "patterns": [ + { + "include": "#global" + }, + { + "match": "\\b(from|to)\\b", + "name": "keyword.other.hx" + }, + { + "include": "#type" + }, + { + "match": "[\\(\\)]", + "name": "punctuation.definition.other.hx" + } + ] + }, + "abstract-block": { + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.end.hx" + } + }, + "name": "meta.block.hx", + "patterns": [ + { + "include": "#method" + }, + { + "include": "#modifiers" + }, + { + "include": "#variable" + }, + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "class": { + "begin": "(?=class)", + "end": "(?<=\\})|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "name": "meta.class.hx", + "patterns": [ + { + "include": "#class-name" + }, + { + "include": "#class-name-post" + }, + { + "include": "#class-block" + } + ] + }, + "class-name": { + "begin": "\\b(class)\\b", + "beginCaptures": { + "1": { + "name": "storage.type.class.hx" + } + }, + "end": "([_A-Za-z]\\w*)", + "endCaptures": { + "1": { + "name": "entity.name.type.class.hx" + } + }, + "name": "meta.class.identifier.hx", + "patterns": [ + { + "include": "#global" + } + ] + }, + "class-name-post": { + "begin": "(?<=\\w)", + "end": "([\\{;])", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "patterns": [ + { + "include": "#modifiers-inheritance" + }, + { + "include": "#type" + } + ] + }, + "class-block": { + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.end.hx" + } + }, + "name": "meta.block.hx", + "patterns": [ + { + "include": "#method" + }, + { + "include": "#modifiers" + }, + { + "include": "#variable" + }, + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "enum": { + "begin": "(?=enum\\s+[A-Z])", + "end": "(?<=\\})|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "name": "meta.enum.hx", + "patterns": [ + { + "include": "#enum-name" + }, + { + "include": "#enum-name-post" + }, + { + "include": "#enum-block" + } + ] + }, + "enum-name": { + "begin": "\\b(enum)\\b", + "beginCaptures": { + "1": { + "name": "storage.type.class.hx" + } + }, + "end": "([_A-Za-z]\\w*)", + "endCaptures": { + "1": { + "name": "entity.name.type.class.hx" + } + }, + "patterns": [ + { + "include": "#global" + } + ] + }, + "enum-name-post": { + "begin": "(?<=\\w)", + "end": "([\\{;])", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + }, + "enum-block": { + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.end.hx" + } + }, + "name": "meta.block.hx", + "patterns": [ + { + "include": "#global" + }, + { + "include": "#metadata" + }, + { + "include": "#parameters" + }, + { + "include": "#identifiers" + } + ] + }, + "interface": { + "begin": "(?=interface)", + "end": "(?<=\\})|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "name": "meta.interface.hx", + "patterns": [ + { + "include": "#interface-name" + }, + { + "include": "#interface-name-post" + }, + { + "include": "#interface-block" + } + ] + }, + "interface-name": { + "begin": "\\b(interface)\\b", + "beginCaptures": { + "1": { + "name": "storage.type.class.hx" + } + }, + "end": "([_A-Za-z]\\w*)", + "endCaptures": { + "1": { + "name": "entity.name.type.class.hx" + } + }, + "patterns": [ + { + "include": "#global" + } + ] + }, + "interface-name-post": { + "begin": "(?<=\\w)", + "end": "([\\{;])", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "patterns": [ + { + "include": "#global" + }, + { + "include": "#modifiers-inheritance" + }, + { + "include": "#type" + } + ] + }, + "interface-block": { + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.end.hx" + } + }, + "name": "meta.block.hx", + "patterns": [ + { + "include": "#method" + }, + { + "include": "#variable" + }, + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "typedef": { + "begin": "(?=typedef)", + "end": "(?<=\\})|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "name": "meta.typedef.hx", + "patterns": [ + { + "include": "#typedef-name" + }, + { + "include": "#typedef-name-post" + }, + { + "include": "#typedef-block" + } + ] + }, + "typedef-name": { + "begin": "\\b(typedef)\\b", + "beginCaptures": { + "1": { + "name": "storage.type.class.hx" + } + }, + "end": "([_A-Za-z]\\w*)", + "endCaptures": { + "1": { + "name": "entity.name.type.class.hx" + } + }, + "patterns": [ + { + "include": "#global" + } + ] + }, + "typedef-name-post": { + "begin": "(?<=\\w)", + "end": "(\\{)|(?=;)", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "patterns": [ + { + "include": "#global" + }, + { + "include": "#punctuation-brackets" + }, + { + "include": "#punctuation-separator" + }, + { + "include": "#operator-assignment" + }, + { + "include": "#type" + } + ] + }, + "typedef-block": { + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.end.hx" + } + }, + "name": "meta.block.hx", + "patterns": [ + { + "include": "#global" + }, + { + "include": "#metadata" + }, + { + "include": "#method" + }, + { + "include": "#variable" + }, + { + "include": "#modifiers" + }, + { + "include": "#punctuation-comma" + }, + { + "include": "#operator-optional" + }, + { + "include": "#typedef-extension" + }, + { + "include": "#typedef-simple-field-type-hint" + }, + { + "include": "#identifier-name" + }, + { + "include": "#strings" + } + ] + }, + "typedef-extension": { + "begin": ">", + "end": ",|$", + "patterns": [ + { + "include": "#type" + } + ] + }, + "typedef-simple-field-type-hint": { + "begin": ":", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.annotation.hx" + } + }, + "end": "(?=\\}|,|;)", + "patterns": [ + { + "include": "#type" + } + ] + }, + "regex": { + "begin": "(~/)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.hx" + } + }, + "end": "(/)([gimsu]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.hx" + }, + "2": { + "name": "keyword.other.hx" + } + }, + "name": "string.regexp.hx", + "patterns": [ + { + "include": "#regexp" + } + ] + }, + "regex-character-class": { + "patterns": [ + { + "match": "\\\\[wWsSdDtrnvf]|\\.", + "name": "constant.other.character-class.regexp" + }, + { + "match": "\\\\([0-7]{3}|x\\h\\h|u\\h\\h\\h\\h)", + "name": "constant.character.numeric.regexp" + }, + { + "match": "\\\\c[A-Z]", + "name": "constant.character.control.regexp" + }, + { + "match": "\\\\.", + "name": "constant.character.escape.backslash.regexp" + } + ] + }, + "regexp": { + "patterns": [ + { + "match": "\\\\[bB]|\\^|\\$", + "name": "keyword.control.anchor.regexp" + }, + { + "match": "\\\\[1-9]\\d*", + "name": "keyword.other.back-reference.regexp" + }, + { + "match": "[?+*]|\\{(\\d+,\\d+|\\d+,|,\\d+|\\d+)\\}\\??", + "name": "keyword.operator.quantifier.regexp" + }, + { + "match": "\\|", + "name": "keyword.operator.or.regexp" + }, + { + "begin": "(\\()((\\?=)|(\\?!))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.group.regexp" + }, + "2": { + "name": "punctuation.definition.group.assertion.regexp" + }, + "3": { + "name": "meta.assertion.look-ahead.regexp" + }, + "4": { + "name": "meta.assertion.negative-look-ahead.regexp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.group.regexp" + } + }, + "name": "meta.group.assertion.regexp", + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "begin": "\\((\\?:)?", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + }, + "1": { + "name": "punctuation.definition.group.capture.regexp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.regexp" + } + }, + "name": "meta.group.regexp", + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "begin": "(\\[)(\\^)?", + "beginCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + }, + "2": { + "name": "keyword.operator.negation.regexp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.character-class.regexp" + } + }, + "name": "constant.other.character-class.set.regexp", + "patterns": [ + { + "match": "(?:.|(\\\\(?:[0-7]{3}|x\\h\\h|u\\h\\h\\h\\h))|(\\\\c[A-Z])|(\\\\.))\\-(?:[^\\]\\\\]|(\\\\(?:[0-7]{3}|x\\h\\h|u\\h\\h\\h\\h))|(\\\\c[A-Z])|(\\\\.))", + "captures": { + "1": { + "name": "constant.character.numeric.regexp" + }, + "2": { + "name": "constant.character.control.regexp" + }, + "3": { + "name": "constant.character.escape.backslash.regexp" + }, + "4": { + "name": "constant.character.numeric.regexp" + }, + "5": { + "name": "constant.character.control.regexp" + }, + "6": { + "name": "constant.character.escape.backslash.regexp" + } + }, + "name": "constant.other.character-class.range.regexp" + }, + { + "include": "#regex-character-class" + } + ] + }, + { + "include": "#regex-character-class" + } + ] + }, + "array": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.array.begin.hx" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.array.end.hx" + } + }, + "name": "meta.array.literal.hx", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "constants": { + "patterns": [ + { + "match": "\\b(true|false|null)\\b", + "name": "constant.language.hx" + }, + { + "match": "\\b(?:0[xX][0-9a-fA-F][_0-9a-fA-F]*([iu][0-9][0-9_]*)?)\\b", + "captures": { + "0": { + "name": "constant.numeric.hex.hx" + }, + "1": { + "name": "constant.numeric.suffix.hx" + } + } + }, + { + "match": "\\b(?:0[bB][01][_01]*([iu][0-9][0-9_]*)?)\\b", + "captures": { + "0": { + "name": "constant.numeric.bin.hx" + }, + "1": { + "name": "constant.numeric.suffix.hx" + } + } + }, + { + "match": "(?x)\n(?])", + "end": "(\\{)|(;)", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + }, + "2": { + "name": "punctuation.terminator.hx" + } + }, + "patterns": [ + { + "include": "#parameters" + }, + { + "include": "#method-return-type-hint" + }, + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "method-block": { + "begin": "(?<=\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.definition.block.end.hx" + } + }, + "name": "meta.method.block.hx", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "parameters": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.hx" + } + }, + "end": "\\s*(\\)(?!\\s*->))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.hx" + } + }, + "name": "meta.parameters.hx", + "patterns": [ + { + "include": "#parameter" + } + ] + }, + "parameter": { + "begin": "(?<=\\(|,)", + "end": "(?=\\)(?!\\s*->)|,)", + "patterns": [ + { + "include": "#parameter-name" + }, + { + "include": "#parameter-type-hint" + }, + { + "include": "#parameter-assign" + }, + { + "include": "#punctuation-comma" + }, + { + "include": "#global" + } + ] + }, + "parameter-name": { + "begin": "(?<=\\(|,)", + "end": "([_a-zA-Z]\\w*)", + "endCaptures": { + "1": { + "name": "variable.parameter.hx" + } + }, + "patterns": [ + { + "include": "#global" + }, + { + "include": "#metadata" + }, + { + "include": "#operator-optional" + } + ] + }, + "parameter-type-hint": { + "begin": ":", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.annotation.hx" + } + }, + "end": "(?=\\)(?!\\s*->)|,|=)", + "patterns": [ + { + "include": "#type" + } + ] + }, + "parameter-assign": { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.assignment.hx" + } + }, + "end": "(?=\\)|,)", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "arrow-function": { + "begin": "(\\()(?=[^(]*?\\)\\s*->)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.parameters.begin.hx" + } + }, + "end": "(\\))\\s*(->)", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.hx" + }, + "2": { + "name": "storage.type.function.arrow.hx" + } + }, + "name": "meta.method.arrow.hx", + "patterns": [ + { + "include": "#arrow-function-parameter" + } + ] + }, + "arrow-function-parameter": { + "begin": "(?<=\\(|,)", + "end": "(?=\\)|,)", + "patterns": [ + { + "include": "#parameter-name" + }, + { + "include": "#arrow-function-parameter-type-hint" + }, + { + "include": "#parameter-assign" + }, + { + "include": "#punctuation-comma" + }, + { + "include": "#global" + } + ] + }, + "arrow-function-parameter-type-hint": { + "begin": ":", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.annotation.hx" + } + }, + "end": "(?=\\)|,|=)", + "patterns": [ + { + "include": "#type" + } + ] + }, + "method-return-type-hint": { + "begin": "(?<=\\))\\s*(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.hx" + } + }, + "end": "(?=\\{|;|[a-z0-9])", + "patterns": [ + { + "include": "#type" + } + ] + }, + "operator-optional": { + "match": "(\\?)(?!\\s)", + "name": "keyword.operator.optional.hx" + }, + "variable": { + "begin": "(?=\\b(var|final)\\b)", + "end": "(?=$)|(;)", + "endCaptures": { + "1": { + "name": "punctuation.terminator.hx" + } + }, + "patterns": [ + { + "include": "#variable-name" + }, + { + "include": "#variable-name-next" + }, + { + "include": "#variable-assign" + }, + { + "include": "#variable-name-post" + } + ] + }, + "variable-name": { + "begin": "\\b(var|final)\\b", + "beginCaptures": { + "1": { + "name": "storage.type.variable.hx" + } + }, + "end": "(?=$)|([_a-zA-Z]\\w*)", + "endCaptures": { + "1": { + "name": "variable.other.hx" + } + }, + "patterns": [ + { + "include": "#operator-optional" + } + ] + }, + "variable-name-next": { + "begin": ",", + "beginCaptures": { + "0": { + "name": "punctuation.separator.comma.hx" + } + }, + "end": "([_a-zA-Z]\\w*)", + "endCaptures": { + "1": { + "name": "variable.other.hx" + } + }, + "patterns": [ + { + "include": "#global" + } + ] + }, + "variable-type-hint": { + "begin": ":", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.annotation.hx" + } + }, + "end": "(?=$|;|,|=)", + "patterns": [ + { + "include": "#type" + } + ] + }, + "variable-assign": { + "begin": "=", + "beginCaptures": { + "0": { + "name": "keyword.operator.assignment.hx" + } + }, + "end": "(?=;|,)", + "patterns": [ + { + "include": "#block" + }, + { + "include": "#block-contents" + } + ] + }, + "variable-name-post": { + "begin": "(?<=\\w)", + "end": "(?=;)|(?==)", + "patterns": [ + { + "include": "#variable-accessors" + }, + { + "include": "#variable-type-hint" + }, + { + "include": "#block-contents" + } + ] + }, + "variable-accessors": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.hx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.hx" + } + }, + "name": "meta.parameters.hx", + "patterns": [ + { + "include": "#global" + }, + { + "include": "#keywords-accessor" + }, + { + "include": "#accessor-method" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "keywords-accessor": { + "match": "\\b(default|get|set|dynamic|never|null)\\b", + "name": "storage.type.property.hx" + }, + "accessor-method": { + "patterns": [ + { + "match": "\\b(get|set)_[_A-Za-z]\\w*\\b", + "name": "entity.name.function.hx" + } + ] + }, + "modifiers": { + "patterns": [ + { + "match": "\\b(enum)\\b", + "name": "storage.type.class" + }, + { + "match": "\\b(public|private|static|dynamic|inline|macro|extern|override|overload|abstract)\\b", + "name": "storage.modifier.hx" + }, + { + "match": "\\b(final)\\b(?=\\s+(public|private|static|dynamic|inline|macro|extern|override|overload|abstract|function))", + "name": "storage.modifier.hx" + } + ] + }, + "new-expr": { + "name": "new.expr.hx", + "begin": "(?", + "name": "keyword.operator.extractor.hx" + }, + { + "include": "#operator-assignment" + }, + { + "include": "#punctuation-comma" + }, + { + "include": "#keywords" + }, + { + "include": "#method-call" + }, + { + "include": "#identifiers" + } + ] + }, + { + "match": "\\b(if|else|return|do|while|for|break|continue|switch|case|default)\\b", + "name": "keyword.control.flow-control.hx" + }, + { + "match": "\\b(cast|untyped)\\b", + "name": "keyword.other.untyped.hx" + }, + { + "match": "\\btrace\\b", + "name": "keyword.other.trace.hx" + }, + { + "match": "\\$type\\b", + "name": "keyword.other.type.hx" + }, + { + "match": "\\__(global|this)__\\b", + "name": "keyword.other.untyped-property.hx" + }, + { + "match": "\\b(this|super)\\b", + "name": "variable.language.hx" + }, + { + "match": "\\bnew\\b", + "name": "keyword.operator.new.hx" + }, + { + "match": "\\b(abstract|class|enum|interface|typedef)\\b", + "name": "storage.type.hx" + }, + { + "match": "->", + "name": "storage.type.function.arrow.hx" + }, + { + "include": "#modifiers" + }, + { + "include": "#modifiers-inheritance" + } + ] + }, + "punctuation-braces": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.hx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.hx" + } + }, + "patterns": [ + { + "include": "#keywords" + }, + { + "include": "#block" + }, + { + "include": "#block-contents" + }, + { + "include": "#type-check" + } + ] + }, + "type-check": { + "begin": "(?>>|<<|>>)", + "name": "keyword.operator.bitwise.hx" + }, + { + "match": "(==|!=|<=|>=|<|>)", + "name": "keyword.operator.comparison.hx" + }, + { + "match": "(!)", + "name": "keyword.operator.logical.hx" + }, + { + "match": "(\\-\\-|\\+\\+)", + "name": "keyword.operator.increment-decrement.hx" + }, + { + "match": "(\\-|\\+|\\*|\\/|%)", + "name": "keyword.operator.arithmetic.hx" + }, + { + "match": "\\.\\.\\.", + "name": "keyword.operator.intiterator.hx" + }, + { + "match": "=>", + "name": "keyword.operator.arrow.hx" + }, + { + "match": "\\?\\?", + "name": "keyword.operator.nullcoalescing.hx" + }, + { + "match": "\\?\\.", + "name": "keyword.operator.safenavigation.hx" + }, + { + "match": "\\bis\\b(?!\\()", + "name": "keyword.other.hx" + }, + { + "begin": "\\?", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.hx" + } + }, + "end": ":", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.hx" + } + }, + "patterns": [ + { + "include": "#block-contents" + } + ] + } + ] + }, + "punctuation-comma": { + "match": ",", + "name": "punctuation.separator.comma.hx" + }, + "punctuation-accessor": { + "match": "\\.", + "name": "punctuation.accessor.hx" + }, + "punctuation-terminator": { + "match": ";", + "name": "punctuation.terminator.hx" + }, + "constant-name": { + "match": "\\b([_A-Z][_A-Z0-9]*)\\b", + "name": "variable.other.hx" + }, + "type": { + "patterns": [ + { + "include": "#global" + }, + { + "include": "#macro-reification" + }, + { + "include": "#type-name" + }, + { + "include": "#type-parameters" + }, + { + "match": "->", + "name": "keyword.operator.type.function.hx" + }, + { + "match": "&", + "name": "keyword.operator.type.intersection.hx" + }, + { + "match": "\\?(?=\\s*[_A-Z])", + "name": "keyword.operator.optional" + }, + { + "match": "\\?(?!\\s*[_A-Z])", + "name": "punctuation.definition.tag" + }, + { + "begin": "(\\{)", + "beginCaptures": { + "0": { + "name": "punctuation.definition.block.begin.hx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#typedef-block" + } + ] + }, + { + "include": "#function-type" + } + ] + }, + "function-type": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.hx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.hx" + } + }, + "patterns": [ + { + "include": "#function-type-parameter" + } + ] + }, + "function-type-parameter": { + "begin": "(?<=\\(|,)", + "end": "(?=\\)|,)", + "patterns": [ + { + "include": "#global" + }, + { + "include": "#metadata" + }, + { + "include": "#operator-optional" + }, + { + "include": "#punctuation-comma" + }, + { + "include": "#function-type-parameter-name" + }, + { + "include": "#function-type-parameter-type-hint" + }, + { + "include": "#parameter-assign" + }, + { + "include": "#type" + }, + { + "include": "#global" + } + ] + }, + "function-type-parameter-name": { + "match": "([_a-zA-Z]\\w*)(?=\\s*:)", + "captures": { + "1": { + "name": "variable.parameter.hx" + } + } + }, + "function-type-parameter-type-hint": { + "begin": ":", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.annotation.hx" + } + }, + "end": "(?=\\)|,|=)", + "patterns": [ + { + "include": "#type" + } + ] + }, + "type-name": { + "patterns": [ + { + "match": "\\b(Any|Array|ArrayAccess|Bool|Class|Date|DateTools|Dynamic|Enum|EnumValue|EReg|Float|IMap|Int|IntIterator|Iterable|Iterator|KeyValueIterator|KeyValueIterable|Lambda|List|ListIterator|ListNode|Map|Math|Null|Reflect|Single|Std|String|StringBuf|StringTools|Sys|Type|UInt|UnicodeString|ValueType|Void|Xml|XmlType)(?:(\\.)(_*[A-Z]\\w*[a-z]\\w*))*\\b", + "captures": { + "1": { + "name": "support.class.builtin.hx" + }, + "2": { + "name": "support.package.hx" + }, + "3": { + "name": "entity.name.type.hx" + } + } + }, + { + "match": "\\b(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.hx" + } + }, + "name": "meta.type-parameters.hx", + "patterns": [ + { + "include": "#type" + }, + { + "include": "#type-parameter-constraint-old" + }, + { + "include": "#type-parameter-constraint-new" + }, + { + "include": "#global" + }, + { + "include": "#regex" + }, + { + "include": "#array" + }, + { + "include": "#constants" + }, + { + "include": "#strings" + }, + { + "include": "#metadata" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type-parameter-constraint-old": { + "begin": "(:)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.hx" + }, + "2": { + "name": "punctuation.definition.constraint.begin.hx" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.constraint.end.hx" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type-parameter-constraint-new": { + "match": ":", + "name": "keyword.operator.type.annotation.hxt" + }, + "identifier-name": { + "match": "\\b([_A-Za-z]\\w*)\\b", + "name": "variable.other.hx" + } + } +} \ No newline at end of file diff --git a/src/Resources/Grammars/hxml.json b/src/Resources/Grammars/hxml.json new file mode 100644 index 00000000..829c403e --- /dev/null +++ b/src/Resources/Grammars/hxml.json @@ -0,0 +1,70 @@ +{ + "information_for_contributors": [ + "This file has been copied from https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/hxml.tmLanguage", + "and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage" + ], + "fileTypes": [ + "hxml" + ], + "foldingStartMarker": "--next", + "foldingStopMarker": "\\n\\n", + "keyEquivalent": "^@H", + "name": "Hxml", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.comment.hxml" + } + }, + "match": "(#).*$\\n?", + "name": "comment.line.number-sign.hxml" + }, + { + "begin": "(? Date: Sat, 21 Sep 2024 16:33:34 +0800 Subject: [PATCH 29/42] refactor: rewrites the built-in grammar extension --- src/Models/TextMateHelper.cs | 107 ++++++++++++++++++++++------------- src/Native/Windows.cs | 2 +- 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs index fdb2cb66..b1cf15af 100644 --- a/src/Models/TextMateHelper.cs +++ b/src/Models/TextMateHelper.cs @@ -17,31 +17,75 @@ using TextMateSharp.Themes; namespace SourceGit.Models { - public class RegistryOptionsWrapper : IRegistryOptions + public static class GrammarUtility { - public RegistryOptionsWrapper(ThemeName defaultTheme) + private static readonly ExtraGrammar[] s_extraGrammas = + [ + new ExtraGrammar("source.toml", ".toml", "toml.json"), + new ExtraGrammar("source.kotlin", ".kotlin", "kotlin.json"), + new ExtraGrammar("source.hx", ".hx", "haxe.json"), + new ExtraGrammar("source.hxml", ".hxml", "hxml.json"), + ]; + + public static string GetExtension(string file) { - _backend = new RegistryOptions(defaultTheme); - _extraGrammars = new List(); + var extension = Path.GetExtension(file); + if (extension == ".h") + extension = ".cpp"; + else if (extension == ".resx" || extension == ".plist" || extension == ".manifest") + extension = ".xml"; + else if (extension == ".command") + extension = ".sh"; + else if (extension == ".kt" || extension == ".kts") + extension = ".kotlin"; - string[] extraGrammarFiles = ["toml.json", "kotlin.json", "haxe.json", "hxml.json"]; - foreach (var file in extraGrammarFiles) - { - var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Grammars/{file}", - UriKind.RelativeOrAbsolute)); - - try - { - var grammar = GrammarReader.ReadGrammarSync(new StreamReader(asset)); - _extraGrammars.Add(grammar); - } - catch - { - // ignore - } - } + return extension; } + public static string GetScopeByExtension(string extension) + { + foreach (var grammar in s_extraGrammas) + { + if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase)) + return grammar.Scope; + } + + return null; + } + + public static IRawGrammar Load(string scopeName) + { + foreach (var grammar in s_extraGrammas) + { + if (grammar.Scope.Equals(scopeName, StringComparison.OrdinalIgnoreCase)) + { + var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/Grammars/{grammar.File}", + UriKind.RelativeOrAbsolute)); + + try + { + return GrammarReader.ReadGrammarSync(new StreamReader(asset)); + } + catch + { + break; + } + } + } + + return null; + } + + private record ExtraGrammar(string Scope, string Extension, string File) + { + public readonly string Scope = Scope; + public readonly string Extension = Extension; + public readonly string File = File; + } + } + + public class RegistryOptionsWrapper(ThemeName defaultTheme) : IRegistryOptions + { public IRawTheme GetTheme(string scopeName) { return _backend.GetTheme(scopeName); @@ -49,8 +93,7 @@ namespace SourceGit.Models public IRawGrammar GetGrammar(string scopeName) { - var grammar = _extraGrammars.Find(x => x.GetScopeName().Equals(scopeName, StringComparison.Ordinal)); - return grammar ?? _backend.GetGrammar(scopeName); + return GrammarUtility.Load(scopeName) ?? _backend.GetGrammar(scopeName); } public ICollection GetInjections(string scopeName) @@ -70,25 +113,11 @@ namespace SourceGit.Models public string GetScopeByFileName(string filename) { - var extension = Path.GetExtension(filename); - if (extension == ".h") - extension = ".cpp"; - else if (extension == ".resx" || extension == ".plist" || extension == ".manifest") - extension = ".xml"; - else if (extension == ".command") - extension = ".sh"; - else if (extension == ".kt" || extension == ".kts") - extension = ".kotlin"; - - var grammar = _extraGrammars.Find(x => x.GetScopeName().EndsWith(extension, StringComparison.OrdinalIgnoreCase)); - if (grammar != null) - return grammar.GetScopeName(); - - return _backend.GetScopeByExtension(extension); + var ext = GrammarUtility.GetExtension(filename); + return GrammarUtility.GetScopeByExtension(ext) ?? _backend.GetScopeByExtension(ext); } - private readonly RegistryOptions _backend; - private readonly List _extraGrammars; + private readonly RegistryOptions _backend = new(defaultTheme); } public static class TextMateHelper diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 0f2e458d..b02112cc 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -202,7 +202,7 @@ namespace SourceGit.Native private void FixWindowFrameOnWin10(Window w) { if (w.WindowState != WindowState.Normal) - w.SystemDecorations = SystemDecorations.Full; + w.SystemDecorations = SystemDecorations.Full; else w.SystemDecorations = SystemDecorations.BorderOnly; } From 80017d8bd0193b4e81ec43d86791bad07ab77247 Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 21 Sep 2024 22:02:50 +0800 Subject: [PATCH 30/42] code_style: simplify `Models.TextMateHelper` --- src/Models/TextMateHelper.cs | 67 +++++++++--------------------------- 1 file changed, 17 insertions(+), 50 deletions(-) diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs index b1cf15af..5a58b6e3 100644 --- a/src/Models/TextMateHelper.cs +++ b/src/Models/TextMateHelper.cs @@ -27,7 +27,7 @@ namespace SourceGit.Models new ExtraGrammar("source.hxml", ".hxml", "hxml.json"), ]; - public static string GetExtension(string file) + public static string GetScope(string file, RegistryOptions reg) { var extension = Path.GetExtension(file); if (extension == ".h") @@ -38,22 +38,17 @@ namespace SourceGit.Models extension = ".sh"; else if (extension == ".kt" || extension == ".kts") extension = ".kotlin"; - - return extension; - } - - public static string GetScopeByExtension(string extension) - { + foreach (var grammar in s_extraGrammas) { if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase)) return grammar.Scope; } - return null; + return reg.GetScopeByExtension(extension); } - public static IRawGrammar Load(string scopeName) + public static IRawGrammar GetGrammar(string scopeName, RegistryOptions reg) { foreach (var grammar in s_extraGrammas) { @@ -73,7 +68,7 @@ namespace SourceGit.Models } } - return null; + return reg.GetGrammar(scopeName); } private record ExtraGrammar(string Scope, string Extension, string File) @@ -86,37 +81,13 @@ namespace SourceGit.Models public class RegistryOptionsWrapper(ThemeName defaultTheme) : IRegistryOptions { - public IRawTheme GetTheme(string scopeName) - { - return _backend.GetTheme(scopeName); - } - - public IRawGrammar GetGrammar(string scopeName) - { - return GrammarUtility.Load(scopeName) ?? _backend.GetGrammar(scopeName); - } - - public ICollection GetInjections(string scopeName) - { - return _backend.GetInjections(scopeName); - } - - public IRawTheme GetDefaultTheme() - { - return _backend.GetDefaultTheme(); - } - - public IRawTheme LoadTheme(ThemeName name) - { - return _backend.LoadTheme(name); - } - - public string GetScopeByFileName(string filename) - { - var ext = GrammarUtility.GetExtension(filename); - return GrammarUtility.GetScopeByExtension(ext) ?? _backend.GetScopeByExtension(ext); - } - + public IRawTheme GetTheme(string scopeName) => _backend.GetTheme(scopeName); + public IRawTheme GetDefaultTheme() => _backend.GetDefaultTheme(); + public IRawTheme LoadTheme(ThemeName name) => _backend.LoadTheme(name); + public ICollection GetInjections(string scopeName) => _backend.GetInjections(scopeName); + public IRawGrammar GetGrammar(string scopeName) => GrammarUtility.GetGrammar(scopeName, _backend); + public string GetScope(string filename) => GrammarUtility.GetScope(filename, _backend); + private readonly RegistryOptions _backend = new(defaultTheme); } @@ -124,18 +95,14 @@ namespace SourceGit.Models { public static TextMate.Installation CreateForEditor(TextEditor editor) { - if (Application.Current?.ActualThemeVariant == ThemeVariant.Dark) - return editor.InstallTextMate(new RegistryOptionsWrapper(ThemeName.DarkPlus)); - - return editor.InstallTextMate(new RegistryOptionsWrapper(ThemeName.LightPlus)); + return editor.InstallTextMate(Application.Current?.ActualThemeVariant == ThemeVariant.Dark ? + new RegistryOptionsWrapper(ThemeName.DarkPlus) : + new RegistryOptionsWrapper(ThemeName.LightPlus)); } public static void SetThemeByApp(TextMate.Installation installation) { - if (installation == null) - return; - - if (installation.RegistryOptions is RegistryOptionsWrapper reg) + if (installation is { RegistryOptions: RegistryOptionsWrapper reg }) { var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark; installation.SetTheme(reg.LoadTheme(isDark ? ThemeName.DarkPlus : ThemeName.LightPlus)); @@ -146,7 +113,7 @@ namespace SourceGit.Models { if (installation is { RegistryOptions: RegistryOptionsWrapper reg }) { - installation.SetGrammar(reg.GetScopeByFileName(filePath)); + installation.SetGrammar(reg.GetScope(filePath)); GC.Collect(); } } From 0b6ecc03887affdf500c7b94350ef670de6e36af Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 21 Sep 2024 22:04:50 +0800 Subject: [PATCH 31/42] code_style: typo in `s_extraGrammars` --- src/Models/TextMateHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs index 5a58b6e3..f8e5acf2 100644 --- a/src/Models/TextMateHelper.cs +++ b/src/Models/TextMateHelper.cs @@ -19,7 +19,7 @@ namespace SourceGit.Models { public static class GrammarUtility { - private static readonly ExtraGrammar[] s_extraGrammas = + private static readonly ExtraGrammar[] s_extraGrammars = [ new ExtraGrammar("source.toml", ".toml", "toml.json"), new ExtraGrammar("source.kotlin", ".kotlin", "kotlin.json"), @@ -39,7 +39,7 @@ namespace SourceGit.Models else if (extension == ".kt" || extension == ".kts") extension = ".kotlin"; - foreach (var grammar in s_extraGrammas) + foreach (var grammar in s_extraGrammars) { if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase)) return grammar.Scope; @@ -50,7 +50,7 @@ namespace SourceGit.Models public static IRawGrammar GetGrammar(string scopeName, RegistryOptions reg) { - foreach (var grammar in s_extraGrammas) + foreach (var grammar in s_extraGrammars) { if (grammar.Scope.Equals(scopeName, StringComparison.OrdinalIgnoreCase)) { From 81b72f7c1ccee0a4e33062f731e865d8aea6cceb Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 22 Sep 2024 11:00:30 +0800 Subject: [PATCH 32/42] enhance: use `~` to represent the home dir of current user --- src/Converters/PathConverters.cs | 21 ++++++++++++++++++--- src/Views/Welcome.axaml | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Converters/PathConverters.cs b/src/Converters/PathConverters.cs index 6f10b66d..95da6c79 100644 --- a/src/Converters/PathConverters.cs +++ b/src/Converters/PathConverters.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using Avalonia.Data.Converters; @@ -7,9 +8,23 @@ namespace SourceGit.Converters public static class PathConverters { public static readonly FuncValueConverter PureFileName = - new FuncValueConverter(fullpath => Path.GetFileName(fullpath) ?? ""); + new(v => Path.GetFileName(v) ?? ""); public static readonly FuncValueConverter PureDirectoryName = - new FuncValueConverter(fullpath => Path.GetDirectoryName(fullpath) ?? ""); + new(v => Path.GetDirectoryName(v) ?? ""); + + public static readonly FuncValueConverter RelativeToHome = + new(v => + { + if (OperatingSystem.IsWindows()) + return v; + + var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length; + if (v.StartsWith(home, StringComparison.Ordinal)) + return "~" + v.Substring(prefixLen); + + return v; + }); } } diff --git a/src/Views/Welcome.axaml b/src/Views/Welcome.axaml index 6bd735ea..6d79948a 100644 --- a/src/Views/Welcome.axaml +++ b/src/Views/Welcome.axaml @@ -140,7 +140,7 @@ Margin="8,0" HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="{DynamicResource Brush.FG2}" - Text="{Binding Id}" + Text="{Binding Id, Converter={x:Static c:PathConverters.RelativeToHome}}" IsVisible="{Binding IsRepository}"/> From 977b800c89984cea3c9c378c92754a506bcbe32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=A3=D1=81=D0=BE?= =?UTF-8?q?=D1=86=D0=BA=D0=B8=D0=B9?= Date: Sun, 22 Sep 2024 13:00:08 +0300 Subject: [PATCH 33/42] Added locale file --- src/App.axaml | 1 + src/Models/Locales.cs | 1 + src/Resources/Locales/ru_RU.axaml | 645 ++++++++++++++++++++++++++++++ 3 files changed, 647 insertions(+) create mode 100644 src/Resources/Locales/ru_RU.axaml diff --git a/src/App.axaml b/src/App.axaml index 56d81615..b1fe303b 100644 --- a/src/App.axaml +++ b/src/App.axaml @@ -15,6 +15,7 @@ + diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs index 51121b5f..0d9e5f69 100644 --- a/src/Models/Locales.cs +++ b/src/Models/Locales.cs @@ -12,6 +12,7 @@ namespace SourceGit.Models new Locale("Deutsch", "de_DE"), new Locale("Français", "fr_FR"), new Locale("Português (Brasil)", "pt_BR"), + new Locale("Русский", "ru_RU"), new Locale("简体中文", "zh_CN"), new Locale("繁體中文", "zh_TW"), }; diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml new file mode 100644 index 00000000..3ea4d033 --- /dev/null +++ b/src/Resources/Locales/ru_RU.axaml @@ -0,0 +1,645 @@ + + О программе + О SourceGit + • Сборка с + © 2024 sourcegit-scm + • Текстовый редактор от + • Моноширинные шрифты взяты из + • Исходный код можно найти по адресу + Бесплатный графический клиент Git с исходным кодом + Добавить рабочее дерево + Что проверить: + Существующую ветку + Создать новую ветку + Расположение: + Путь к этому рабочему дереву. Поддерживается относительный путью + Имя ветки: + Необязательно. По умолчанию используется имя целевой папки. + Отслеживание ветки: + Отслеживание внешней ветки + OpenAI Ассистент + Использовать OpenAI для создания сообщения о фиксации + Исправить + Ошибка + Выдает ошибки и отказывается применять исправление + Все ошибки + Аналогично "ошибке", но показывает больше + Файл исправлений: + Выберите файл .patch для применения + Игнорировать изменения пробелов + Нет предупреждений + Отключает предупреждение о пробелах в конце + Применить исправление + Предупреждение + Выдает предупреждения о нескольких таких ошибках, но применяет + Пробел: + Архивировать... + Сохранить архив в: + Выберите путь к архивному файлу + Ревизия: + Архив + Спросить разрешения SourceGit + ФАЙЛЫ СЧИТАЮТСЯ НЕИЗМЕНЕННЫМИ + НИ ОДИН ФАЙЛ НЕ СЧИТАЕТСЯ НЕИЗМЕНЕННЫМ + УДАЛИТЬ + ДВОИЧНЫЙ ФАЙЛ НЕ ПОДДЕРЖИВАЕТСЯ!!! + Обвинение + ОБВИНЕНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!! + Проверить ${0}$... + Сравнить в веткой + Сравнить в заголовком + Сравнить в рабочим деревом + Копировать имя ветки + Удалить ${0}$... + Удалить выбранные {0} ветки + Отклонить все изменения. + Быстрая перемотка вперёд к ${0}$ + Поток Git - Завершение ${0}$ + Слить ${0}$ в ${1}$... + Вытащить ${0}$ + Перетащить ${0}$ в ${1}$... + Выложить ${0}$ + Переместить ${0}$ на ${1}$... + Переименовать ${0}$... + Установить отслеживание ветки + Отключить основной поток + Сравнение ветвей + Байты + ОТМЕНА + Сбросить эту ревизию + Сбросить родительскую ревизию + ИЗМЕНИТЬ РЕЖИМ ОТОБРАЖЕНИЯ + Показывать в виде списка файлов и каталогов + Показать в виде списка путей + Показать в виде дерева файловой системы + Проверить ветку + Проверить фиксацию + Предупреждение: При выполнении проверки фиксации ваша голова будет отсоединена + Фиксация: + Ветка: + Локальные изменения: + Отклонить + Ничего не делать + Отложить и примненить повторно + Частичный выбор + Фиксация(и): + Фиксировать все изменения. + Очистить отложенные + Вы пытаетесь очистить все отложенные. Вы уверены, что будете продолжать? + Клонировать внешнее хранилище + Расширенные параметры: + Дополнительные аргументы для клонирования хранилища. Необязательно. + Локальное имя: + Имя хранилища. Необязательно. + Родительский каталог: + Сетевой адрес хранилища: + ЗАКРЫТЬ + Редактор + Выбрать из списка эту фиксацию + Список выбора ... + Проверить фиксацию + Сравнить в заголовком + Сравнить с рабочим деревом + Копировать информацию + Копировать SHA + Интерактивное перемещение ${0}$ сюда + Переместить ${0}$ сюда + Сбросить ${0}$ сюда + Вернуть фиксацию + Переформулировать + Сохранить как исправление... + Уплотнить в родительскую + Уплотнить дочерную фиксацию сюда + ИЗМЕНЕНИЯ + Найти изменения.... + ФАЙЛЫ + Файл ХБФ + Подмодуль + ИНФОРМАЦИЯ + АВТОР + ИЗМЕНЁННЫЙ + ФИКСАТОР + Проверить ссылки, содержащие эту фиксацию + ФИКСАЦИЯ СОДЕРЖИТСЯ В + Отображаются только первые 100 изменений. Смотрите все изменения на вкладке ИЗМЕНЕНИЯ. + СООБЩЕНИЕ + РОДИТЕЛИ + ССЫЛКИ + SHA + Открыть в браузере + Введите тему фиксации + Описание + Настройка хранилища + ШАБЛОН ФИКСАЦИИ + Имя шаблона: + Шаблон содержания: + Адрес электронной почты + Адрес электронной почты + GIT + ОТСЛЕЖИВАНИЕ ПРОБЛЕМ + Добавить пример правила для Git + Добавить пример правила Jira + Новое правило + Проблема с регулярным выражением: + Имя правила: + Сетевой адрес результата: + Пожалуйста, используйте $1, $2 для доступа к значениям групп регулярных выражений. + HTTP-прокси + HTTP-прокси, используемый этим хранилищем + Имя пользовтаеля + Имя пользователя для этого хранилища + Рабочие пространства + Имя + Цвет + Копировать + Копировать весь текст + КОПИРОВАТЬ СООБЩЕНИЕ + Копировать путь + Копировать имя файла + Создать ветку... + Основан на: + Проверить созданную ветку + Локальные изменения: + Отклонить + Ничего не делать + Отложить и применить повторно + Имя новой ветки: + Ввести имя ветки. + Создать локальную ветку + Создать тег... + Новый тег у: + Подпись GPG + Сообщение с тегом: + Необязательно. + Имя тега: + Рекомендуемый формат: v1.0.0-alpha + Выложить на все внешние хранилища после создания + Создать новый тег + Добрый: + аннотированный + лёгкий + Удерживайте Ctrl, чтобы начать непосредственно + Вырезать + Удалить ветку + Ветка: + Вы собираетесь удалить удаленную ветку!!! + Также удалите удаленную ветку ${0}$ + Удаление нескольких веток + Вы пытаетесь удалить несколько веток одновременно. Обязательно перепроверьте, прежде чем предпринимать какие-либо действия! + Удалить внешнее хранилище + Внешнее хранилище: + Цель: + Подтвердите удаление группы + Подтвердите удаление хранилища + Удалить подмодуль + Путь подмодуля: + Удалить тег + Тег: + Удалить из внешнего хранилища + РАЗНИЦА БИНАРНИКОВ + НОВЫЙ + СТАРЫЙ + Копировать + Режим файла изменён + ИЗМЕНЕНИЕ ОБЪЕКТА ХБФ + Следующее различие + НИКАКИХ ИЗМЕНЕНИЙ ИЛИ МЕНЯЕТСЯ ТОЛЬКО EOL + Предыдущее различие + Различие бок о бок + ПОДМОДУЛЬ + НОВЫЙ + Подсветка синтаксиса + Перенос слов в строке + Открыть в инструменте слияния + Уменьшить количество видимых линий + Увеличить количество видимых линий + ВЫБРАТЬ ФАЙЛ ДЛЯ ПРОСМОТРА ИЗМЕНЕНИЙ + Показать скрытые символы + Обмен + Открыть в инструменте слияния + Отклонить изменения + Все локальные изменения в рабочей копии. + Изменения: + Всего {0} изменений будут отменены + Вы не можете отменить это действие!!! + Закладка: + Новое имя: + Цель: + Редактировать выбранную группу + Редактировать выбранное хранилище + Быстрая перемотка вперёд (без проверки) + Извлечь + Извлечь все внешние хранилища + Извлечь без тегов + Удалить внешние мёртвые ветки + Внешнее хранилище: + Извлечь внешние изменения + Допустить без изменений + Отклонить... + Отклонить {0} файлов... + Отклонить изменения в выбранной(ых) строке(ах) + Открыть расширенный инструмент слияния + Сохранить как исправление... + Подготовить + Подготовленные {0} файлы + Подготовленные изменения в выбранной(ых) строке(ах) + Отложить... + Отложить {0} файлов... + Снять подготовленный + Неподготовленные {0} файлы + Неподготовленные изменения в выбранной(ых) строке(ах) + Использовать их (checkout --theirs) + Использовать мой (checkout --ours) + История файлов + СОДЕРЖИМОЕ + ИЗМЕНИТЬ + ФИЛЬТР + Git-поток + Ветка разработчика: + Свойство: + Свойство префикса: + ПОТОК - Finish Feature + ПОТОК - Закончить исправление + ПОТОК - Завершить выпуск + Цель: + Исправление: + Префикс исправлений: + Инициализировать Git-поток + Держать ветку + Производственная ветка: + Выпуск: + Префикс выпуска: + Свойство запуска... + ПОТОК - Свойство запуска + Запуск исправлений... + ПОТОК - Запуск исправлений + Ввести имя + Запуск выпуска... + ПОТОК - Запуск выпуска + Префикс тега версии: + Git хранилища больших файлов + Добавить шаблон отслеживания... + Шаблон — это имя файла + Изменить шаблон: + Добавить шаблон отслеживания в ХБФ Git + Извлечь + Извлечь объекты ХБФ + Запустите `git lfs fetch", чтобы загрузить объекты ХБФ Git. При этом рабочая копия не обновляется. + Установить перехват ХБФ Git + Показать блокировки + Нет заблокированных файлов + Блокировка + Блокировки ХБФ + Разблокировка + Принудительная разблокировка + Обрезка + Запустите `git lfs prune", чтобы удалить старые файлы ХБФ из локального хранилища + Забрать + Забрать объекты ХБФ + Запустите `git lfs pull", чтобы загрузить все файлы ХБФ Git для текущей ссылки и проверить + Выложить + Выложить объекты ХБФ + Отправляйте большие файлы, помещенные в очередь, в конечную точку ХБФ Git + Внешнее хранилище: + Отслеживать файлы с именем '{0}' + Отслеживать все *{0} файлов + Истории + Переключение горизонтального/вертикального расположения + Переключение режима построения кривой/полилинии + АВТОР + ГРАФ И СУБЪЕКТ + SHA + ВРЕМЯ ФИКСАЦИИ + ПОИСК SHA/СУБЪЕКТ/АВТОР. НАЖМИТЕ ВВОД ДЛЯ ПОИСКА, ESC ДЛЯ ВЫХОДА + ОЧИСТИТЬ + ВЫБРАННЫЕ {0} ФИКСАЦИИ + Ссылка на сочетания клавиш + ОБЩЕЕ + Отменить текущее всплывающее окно + Закрыть текущее окно + Перейти на предыдущую страницу + Перейти на следующую страницу + Создать новую страницу + Открыть диалоговое окно настроек + ХРАНИЛИЩЕ + Фиксация подготовленных изменений + Фиксировать и выложить подготовленные изменения + Отклонить выбранные изменения + Режим доски (по-умолчанию) + Принудительно перезагрузить этот репозиторий + Подгтовленные/Неподготовленные выбранные изменения + Режим поиска фиксаций + Перекключить на 'Изменения' + Перекключить на 'Истории' + Перекключить на 'Спрятанные' + ТЕКСТОВЫЙ РЕДАКТОР + Закрыть панель поиска + Найти следующее совпадение + Найти предыдущее совпадение + Открыть панель поиска + Подготовить + Снять из подготовленных + Отклонить + Инициализировать хранилище + Путь: + Выполняется частичный забор. Нажмите 'Отбой' для восстановления заголовка. + Выполняет запрос слияния. Нажмите 'Отбой' для восстановления заголовка. + Выполняется перенос. Нажмите 'Отбой' для восстановления заголовка. + Выполняется возврат. Нажмите 'Отбой' для восстановления заголовка. + Интерактивное перемещение + целевая ветка: + На: + Вверх + Вниз + Source Git + ОШИБКА + УВЕДОМЛЕНИЕ + Открыть главное меню + Слить ветку + В: + Опции слияния: + Исходная ветка: + Переместить узел хранилища + Выбрать родительский узел для: + Имя: + Git НЕ был настроен. Пожалуйста, перейдите в [Настройки] и сначала настройте его. + УВЕДОМЛЕНИЕ + Открыть приложение каталогов данных + ВЫБОР КАТАЛОГА + Окрыть с... + Необязательно. + Создать новую страницу + Закладка + Закрыть вкладку + Закрыть другие вкладки + Закрыть вкладки справа + Копировать путь хранилища + Хранилища + Вставить + Сейчас + {0} минут спустя + {0} часов спустя + Вчера + {0} дней спустя + Последний месяц + {0} месяцев спустя + Последние годы + {0} лет спустя + Параметры + ОТКРЫТЬ ВИ + Сервер + Ключ API + Модель + ВИД + Шрифт по-умолчанию + Размер шрифта по-умолчанию + Моноширный шрифт + В текстовом редакторе используется только моноширный шрифт + Тема + Переопределение темы + Использовать фиксированную ширину табуляции в строке заголовка. + Использовать системное окно + ИНСТРУМЕНТ РАЗЛИЧИЙ/СЛИЯНИЯ + Путь установки + Введите путь для инструмента различия/слияния + Инструмент + ГЛАВНЫЙ + Проверить обновления при старте + Язык + История фиксаций + Длина темы фиксации + GIT + Автоматическое извлечение внешних хранилищ + Интервал автоматического извлечения + Минут(а/ы) + Включить автозавершение CRLF + Каталог клонирования по-умолчанию + Электроная почта пользователя + Общая электроная почта пользователя git + путь установки + Имя пользователя + общее имя пользователя git + Версия Git + Git (>= 2.23.0) требуется для этого приложения + ПОДПИСЬ GPG + Фиксация подписи GPG + Тег подписи GPG + Формат GPG + Путь установки программы + Введите путь для установленной программы GPG + Ключ подписи пользователя + Ключ подписи GPG пользователя + ВНЕДРЕНИЕ + ОБОЛОЧКА/ТЕРМИНАЛ + Оболочка/Терминал + Путь + Удалить внешнее хранилище + Цель: + Удалить рабочее дерево + Информация об обрезке рабочего дерева в `$GIT_DIR/worktrees` + Забрать + Ветка: + Извлечь все ветки + В: + Локальные изменения: + Отклонить + Ничего не делать + Отложить и применить повторно + Забрать без тегов + Внешнее хранилище: + Забрать (Получить и слить) + Используйте перемещение вместо слияния + Выложить + Убедитесь, что подмодули были вставлены + Принудительно выложить + Локальная ветка: + Внешнее хранилище: + Выложить изменения на внешнее хранилище + Ветка внешнего хранилища: + Установить в качестве ветки отслеживания + Выложить все теги + Выложить тег на внешнее хранилище + Выложить на все внешние хранилища + Внешнее хранилище: + Тег: + Выйти + Перемещение текущей ветки + Отложить и применить повторно локальные изменения + На: + Переместить: + Обновить + Добавить внешнее хранилище + Редактировать внешнее хранилище + Имя: + Имя внешнего хранилища + Сетевой адрес хранилища: + Сетевой адрес внешнего хранилища git + Копировать сетевой адрес + Удалить... + Редактировать... + Извлечь + Открыть в браузере + Удалить + Цель: + Подтвердить удаление рабочего дерева + Включить опцию `--force` + Цель: + Переименовать ветку + Новое имя: + Уникальное имя для данной ветки + Ветка: + ОТБОЙ + Очистка (Сбор мусора и удаление) + Запустить команду `git gc` для данного хранилища. + Очистить всё + Настройка этого хранилища + ПРОДОЛЖИТЬ + Открыть в файловом менеджере + поиск веток, тегов и подмодулей + ОТФИЛЬТРОВАНО ОТ: + ЛОКАЛЬНЫЕ ВЕТКИ + Навигация по заголовку + Включить опцию '--first-parent' + Создать ветку + Открыть в {0} + Открыть в расширенном инструменте + Обновить + ВНЕШНИЕ ХРАНИЛИЩА + ДОБАВИТЬ ВНЕШНЕЕ ХРАНИЛИЩЕ + РАЗРЕШИТЬ + Поиск фиксации + Поиск по + Файл + Сообщение + SHA + Автор и фиксатор + Показать теги как дерево + Статистики + ПОДМОДУЛИ + ДОБАВИТЬ ПОДМОДУЛЬ + ОБНОВИТЬ ПОДМОДУЛЬ + ТЕГИ + НОВЫЙ ТЕГ + Открыть в терминале + РАБОЧИЕ ДЕРЕВЬЯ + ДОБАВИТЬ РАБОЧЕЕ ДЕРЕВО + ОБРЕЗКА + Сетевой адрес хранилища Git + Сбросить текущую втеку до версии + Режим сброса: + Переместить в: + Текущая ветка: + Раскрыть в файловом менеджере + Отменить фиксацию + Фиксация: + Отмена изменений фиксации + Переформулировать сообщение фиксации + Используйте "Shift+Enter" для ввода новой строки. "Enter" - это горячая клавиша кнопки OK + Запуск. Подождите пожалуйста... + СОХРАНИТЬ + Сохранить как... + Исправление успешно сохранено! + Сканирование хранилищ + Корневой каталог: + Проверка для обновления... + Доступна новая версия этого программного обеспечения: + Не удалось проверить наличие обновлений! + Загрузка + Пропустить эту версию + Обновление ПО + В настоящее время обновления недоступны. + Уплотнить фиксации + В: + Частный ключ SSH: + Путь хранения частного ключа SSH + ЗАПУСК + Отложить + Включить неотслеживаемые файлы + Сообщение: + Необязательно. Имя этого тайника + Отложить локальные изменения + Принять + Отбросить + Применить + Отрбосить тайник + Отбросить: + Отложенные + ИЗМЕНЕНИЯ + ОТЛОЖЕННЫЕ + Статистики + ФИКСАЦИИ + ФИКСАТОРЫ + МЕСЯЦ + НЕДЕЛЯ + ГОД + ФИКСАЦИИ: + АВТОРЫ: + ПОДМОДУЛИ + Добавить подмодули + Копировать относительный путь + Извлечение вложенных подмодулей + Открыть подмодуль хранилища + Относительный путь: + Относительный каталог для хранения подмодуля. + удалить подмодуль + ОК + Копировать имя тега + Удалить ${0}$... + Выложить ${0}$... + Сетевой адрес: + Обновление подмодулей + Все подмодули + Инициализировать по необходимости + Рекурсивно + Подмодуль: + Используйте опцию --remote + Предупреждение + Приветствие + Создать группу + Создать подгруппу + Клонировать хранилище + Удалить + ПОДДЕРЖИВАЕТСЯ: ПЕРЕТАСКИВАНИЕ КАТАЛОГОВ, ПОЛЬЗОВАТЕЛЬСКАЯ ГРУППИРОВКА. + Редактировать + Перейти в другую группу + Открыть все хранилища + Открыть хранилище + Открыть терминал + Повторное сканирование хранилищ в каталоге клонирования по-умолчанию + Поиск хранилищ... + Сортировка + Изменения + Игнорировать Git + Игнорировать все *{0} файлы + Игнорировать *{0} файлы в том же каталоге + Игнорировать файлы в том же каталоге + Игнорировать только эти файлы + Изменить + Автоподготовка + Теперь вы можете подготовитть этот файл. + ФИКСАЦИЯ + ФИКСАЦИЯ и ОТПРАВКА + Шаблон/Истории + CTRL + Enter + ОБНАРУЖЕНЫ КОНФЛИКТЫ + КОНФЛИКТЫ ФАЙЛОВ РАЗРЕШЕНЫ + ВКЛЮЧИТЬ НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ + НЕТ ПОСЛЕДНИХ ВХОДНЫХ СООБЩЕНИЙ + НЕТ ШАБЛОНОВ ФИКСАЦИИ + ПОДГОТОВЛЕННЫЕ + СНЯТЬ ПОДГОТОВЛЕННЫЙ + СНЯТЬ ВСЕ ПОДГОТОВЛЕННЫЕ + НЕПОДГОТОВЛЕННЫЕ + ПОДГОТОВИТЬ + ВСЕ ПОДГОТОВИТЬ + ВИД ПРЕДПОЛАГАЕТСЯ НЕИЗМЕННЫМ + Шаблон: ${0}$ + Щёлкните правой кнопкой мыши выбранный файл(ы) и сделайте свой выбор для разрешения конфликтов. + РАБОЧЕЕ ПРОСТРАНСТВО: + Настройка рабочего пространства... + РАБОЧЕЕ ДЕРЕВО + Копировать путь + Заблокировать + Удалить + Разблокировать + From 45ad1363fa8fa6a8cea05502f41c69124b29684f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=A3=D1=81=D0=BE?= =?UTF-8?q?=D1=86=D0=BA=D0=B8=D0=B9?= Date: Sun, 22 Sep 2024 13:37:33 +0300 Subject: [PATCH 34/42] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Resources/Locales/ru_RU.axaml | 6 +++--- src/src.sln | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/src.sln diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 3ea4d033..0c2d22d6 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -331,7 +331,7 @@ Режим поиска фиксаций Перекключить на 'Изменения' Перекключить на 'Истории' - Перекключить на 'Спрятанные' + Перекключить на 'Отложенные' ТЕКСТОВЫЙ РЕДАКТОР Закрыть панель поиска Найти следующее совпадение @@ -448,7 +448,7 @@ Забрать без тегов Внешнее хранилище: Забрать (Получить и слить) - Используйте перемещение вместо слияния + Использовать перемещение вместо слияния Выложить Убедитесь, что подмодули были вставлены Принудительно выложить @@ -534,7 +534,7 @@ Фиксация: Отмена изменений фиксации Переформулировать сообщение фиксации - Используйте "Shift+Enter" для ввода новой строки. "Enter" - это горячая клавиша кнопки OK + Использовать "Shift+Enter" для ввода новой строки. "Enter" - это горячая клавиша кнопки OK Запуск. Подождите пожалуйста... СОХРАНИТЬ Сохранить как... diff --git a/src/src.sln b/src/src.sln new file mode 100644 index 00000000..82ca21ac --- /dev/null +++ b/src/src.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGit", "SourceGit.csproj", "{3592C870-A8F6-44C4-B335-7B6227DCB12C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A96FF510-0878-4167-AA61-D0674DBDD101} + EndGlobalSection +EndGlobal From 01380ff194195d2edad4f6b0d25ae4b403fea72e Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 22 Sep 2024 19:03:55 +0800 Subject: [PATCH 35/42] code_review: PR #497 * remove unused file * update readme --- README.md | 2 +- src/src.sln | 25 ------------------------- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 src/src.sln diff --git a/README.md b/README.md index 4bd90c9e..1c8105c5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Opensource Git GUI client. * Supports Windows/macOS/Linux * Opensource/Free * Fast -* English/Français/Deutsch/Português/简体中文/繁體中文 +* English/Français/Deutsch/Português/Русский/简体中文/繁體中文 * Built-in light/dark themes * Customize theme * Visual commit graph diff --git a/src/src.sln b/src/src.sln deleted file mode 100644 index 82ca21ac..00000000 --- a/src/src.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.002.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGit", "SourceGit.csproj", "{3592C870-A8F6-44C4-B335-7B6227DCB12C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3592C870-A8F6-44C4-B335-7B6227DCB12C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A96FF510-0878-4167-AA61-D0674DBDD101} - EndGlobalSection -EndGlobal From 07cba1cf5ffb570576e50872de6390a8dba89dd5 Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 22 Sep 2024 20:48:36 +0800 Subject: [PATCH 36/42] feature: support using left/right arrow to expand/collapse tree node (#463) --- src/Views/ChangeCollectionView.axaml.cs | 35 ++++++++++++++----------- src/Views/RevisionFileTreeView.axaml | 14 +++++----- src/Views/RevisionFileTreeView.axaml.cs | 24 +++++++++++++++-- src/Views/Welcome.axaml | 26 +++++++++--------- src/Views/Welcome.axaml.cs | 20 ++++++++++++++ 5 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/Views/ChangeCollectionView.axaml.cs b/src/Views/ChangeCollectionView.axaml.cs index f364d7e4..39d46d77 100644 --- a/src/Views/ChangeCollectionView.axaml.cs +++ b/src/Views/ChangeCollectionView.axaml.cs @@ -33,7 +33,16 @@ namespace SourceGit.Views protected override void OnKeyDown(KeyEventArgs e) { - if (e.Key != Key.Space) + if (SelectedItems is [ViewModels.ChangeTreeNode { IsFolder: true } node] && e.KeyModifiers == KeyModifiers.None) + { + if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right)) + { + this.FindAncestorOfType()?.ToggleNodeIsExpanded(node); + e.Handled = true; + } + } + + if (!e.Handled && e.Key != Key.Space) base.OnKeyDown(e); } } @@ -157,13 +166,11 @@ namespace SourceGit.Views { if (lastUnselected == -1) continue; - else - break; - } - else - { - lastUnselected = i; + + break; } + + lastUnselected = i; } } @@ -179,13 +186,11 @@ namespace SourceGit.Views { if (lastUnselected == -1) continue; - else - break; - } - else - { - lastUnselected = i; + + break; } + + lastUnselected = i; } if (lastUnselected != -1) @@ -239,9 +244,9 @@ namespace SourceGit.Views _disableSelectionChangingEvent = true; var selected = new List(); - if (sender is ListBox list) + if (sender is ListBox { SelectedItems: {} selectedItems }) { - foreach (var item in list.SelectedItems) + foreach (var item in selectedItems) { if (item is Models.Change c) selected.Add(c); diff --git a/src/Views/RevisionFileTreeView.axaml b/src/Views/RevisionFileTreeView.axaml index d0984f66..7266c429 100644 --- a/src/Views/RevisionFileTreeView.axaml +++ b/src/Views/RevisionFileTreeView.axaml @@ -8,12 +8,12 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.RevisionFileTreeView" x:Name="ThisControl"> - + @@ -46,5 +46,5 @@ - + diff --git a/src/Views/RevisionFileTreeView.axaml.cs b/src/Views/RevisionFileTreeView.axaml.cs index 52d19a2c..89f02ccb 100644 --- a/src/Views/RevisionFileTreeView.axaml.cs +++ b/src/Views/RevisionFileTreeView.axaml.cs @@ -103,6 +103,26 @@ namespace SourceGit.Views } } + public class RevisionFileRowsListBox : ListBox + { + protected override Type StyleKeyOverride => typeof(ListBox); + + protected override void OnKeyDown(KeyEventArgs e) + { + if (SelectedItems is [ViewModels.RevisionFileTreeNode { IsFolder: true } node] && e.KeyModifiers == KeyModifiers.None) + { + if ((node.IsExpanded && e.Key == Key.Left) || (!node.IsExpanded && e.Key == Key.Right)) + { + this.FindAncestorOfType()?.ToggleNodeIsExpanded(node); + e.Handled = true; + } + } + + if (!e.Handled) + base.OnKeyDown(e); + } + } + public partial class RevisionFileTreeView : UserControl { public static readonly StyledProperty RevisionProperty = @@ -285,8 +305,8 @@ namespace SourceGit.Views } } - private List _tree = new List(); - private AvaloniaList _rows = new AvaloniaList(); + private List _tree = []; + private AvaloniaList _rows = []; private bool _disableSelectionChangingEvent = false; } } diff --git a/src/Views/Welcome.axaml b/src/Views/Welcome.axaml index 6d79948a..19703fa9 100644 --- a/src/Views/Welcome.axaml +++ b/src/Views/Welcome.axaml @@ -45,18 +45,18 @@ - +