From 245de9b4583f499c3e1b6e8c176e9f9fc3d48932 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 10:40:24 +0800 Subject: [PATCH 01/67] fix: tooltip did not hide after pointer move out (#1178) Signed-off-by: leo --- src/Views/Blame.axaml | 9 +++++++- src/Views/Blame.axaml.cs | 3 +-- src/Views/CommitBaseInfo.axaml | 14 +++++++++++++ src/Views/CommitBaseInfo.axaml.cs | 5 ----- src/Views/CommitMessagePresenter.cs | 32 ++++++++++++++++------------- src/Views/CommitSubjectPresenter.cs | 1 - 6 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/Views/Blame.axaml b/src/Views/Blame.axaml index eaad985a..7a3d7ddf 100644 --- a/src/Views/Blame.axaml +++ b/src/Views/Blame.axaml @@ -59,7 +59,14 @@ FontFamily="{DynamicResource Fonts.Monospace}" FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=EditorFontSize}" TabWidth="{Binding Source={x:Static vm:Preferences.Instance}, Path=EditorTabWidth}" - BlameData="{Binding Data}"/> + BlameData="{Binding Data}"> + + + + + + + + + + + + + + @@ -152,6 +159,13 @@ PointerEntered="OnSHAPointerEntered" PointerPressed="OnSHAPressed" ToolTip.ShowDelay="0"> + + + + + + + diff --git a/src/Views/CommitBaseInfo.axaml.cs b/src/Views/CommitBaseInfo.axaml.cs index 8767db9f..ac9b53cc 100644 --- a/src/Views/CommitBaseInfo.axaml.cs +++ b/src/Views/CommitBaseInfo.axaml.cs @@ -133,12 +133,7 @@ namespace SourceGit.Views Dispatcher.UIThread.Invoke(() => { if (ctl.IsEffectivelyVisible && ctl.DataContext is string newSHA && newSHA == sha) - { ToolTip.SetTip(ctl, c); - - if (ctl.IsPointerOver) - ToolTip.SetIsOpen(ctl, true); - } }); }); } diff --git a/src/Views/CommitMessagePresenter.cs b/src/Views/CommitMessagePresenter.cs index 002beda1..6f838509 100644 --- a/src/Views/CommitMessagePresenter.cs +++ b/src/Views/CommitMessagePresenter.cs @@ -5,6 +5,8 @@ using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Documents; +using Avalonia.Data; +using Avalonia.Data.Converters; using Avalonia.Input; using Avalonia.Threading; using Avalonia.VisualTree; @@ -24,6 +26,21 @@ namespace SourceGit.Views protected override Type StyleKeyOverride => typeof(SelectableTextBlock); + public CommitMessagePresenter() + { + var bindings = new MultiBinding() + { + Converter = BoolConverters.And, + Bindings = new[] + { + new Binding() { Path = "IsPointerOver", Source = this }, + new Binding() { Path = "(ToolTip.Tip)", Source = this, TypeResolver = (_, name) => name == "ToolTip" ? typeof(ToolTip) : null, Converter = ObjectConverters.IsNotNull }, + } + }; + + Bind(ToolTip.IsOpenProperty, bindings); + } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); @@ -107,14 +124,9 @@ namespace SourceGit.Views _lastHover = link; if (!link.IsCommitSHA) - { ToolTip.SetTip(this, link.Link); - ToolTip.SetIsOpen(this, true); - } else - { ProcessHoverCommitLink(link); - } return; } @@ -264,12 +276,7 @@ namespace SourceGit.Views // If we have already queried this SHA, just use it. if (_inlineCommits.TryGetValue(sha, out var exist)) { - if (exist != null) - { - ToolTip.SetTip(this, exist); - ToolTip.SetIsOpen(this, true); - } - + ToolTip.SetTip(this, exist); return; } @@ -294,10 +301,7 @@ namespace SourceGit.Views // Make sure user still hovers the target SHA. if (_lastHover == link && c != null) - { ToolTip.SetTip(this, c); - ToolTip.SetIsOpen(this, true); - } } }); }); diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index 32f6838d..83d79fe4 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -144,7 +144,6 @@ namespace SourceGit.Views _lastHover = match; SetCurrentValue(CursorProperty, Cursor.Parse("Hand")); ToolTip.SetTip(this, match.Link); - ToolTip.SetIsOpen(this, true); e.Handled = true; return; } From 17cf402c7819eb04594730c9ca6673413c3a72f5 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Mon, 14 Apr 2025 10:42:34 +0800 Subject: [PATCH 02/67] enhance: navigate to upstream head after fetch, pull, and merge (#1180) --- src/Commands/QueryBranches.cs | 4 ++-- src/Models/Branch.cs | 2 +- src/ViewModels/BranchTreeNode.cs | 2 +- src/ViewModels/FastForwardWithoutCheckout.cs | 6 +++++- src/ViewModels/Fetch.cs | 9 +++++---- src/ViewModels/FetchInto.cs | 6 +++++- src/ViewModels/Merge.cs | 17 ++++++++++++++++- src/ViewModels/Pull.cs | 6 +++++- src/ViewModels/Repository.cs | 20 ++++++++++++++++++++ 9 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs index 8dbc4055..39b77189 100644 --- a/src/Commands/QueryBranches.cs +++ b/src/Commands/QueryBranches.cs @@ -40,7 +40,7 @@ namespace SourceGit.Commands foreach (var b in branches) { if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream)) - b.IsUpsteamGone = !remoteBranches.Contains(b.Upstream); + b.IsUpstreamGone = !remoteBranches.Contains(b.Upstream); } return branches; @@ -86,7 +86,7 @@ namespace SourceGit.Commands branch.Head = parts[1]; branch.IsCurrent = parts[2] == "*"; branch.Upstream = parts[3]; - branch.IsUpsteamGone = false; + branch.IsUpstreamGone = false; if (branch.IsLocal && !string.IsNullOrEmpty(parts[4]) && !parts[4].Equals("=", StringComparison.Ordinal)) branch.TrackStatus = new QueryTrackStatus(WorkingDirectory, branch.Name, branch.Upstream).Result(); diff --git a/src/Models/Branch.cs b/src/Models/Branch.cs index 2d0ae5b2..d0ac1990 100644 --- a/src/Models/Branch.cs +++ b/src/Models/Branch.cs @@ -34,7 +34,7 @@ namespace SourceGit.Models public string Upstream { get; set; } public BranchTrackStatus TrackStatus { get; set; } public string Remote { get; set; } - public bool IsUpsteamGone { get; set; } + public bool IsUpstreamGone { get; set; } public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}"; } diff --git a/src/ViewModels/BranchTreeNode.cs b/src/ViewModels/BranchTreeNode.cs index 6c1d2e04..0148844a 100644 --- a/src/ViewModels/BranchTreeNode.cs +++ b/src/ViewModels/BranchTreeNode.cs @@ -44,7 +44,7 @@ namespace SourceGit.ViewModels public bool ShowUpstreamGoneTip { - get => Backend is Models.Branch { IsUpsteamGone: true }; + get => Backend is Models.Branch { IsUpstreamGone: true }; } public string Tooltip diff --git a/src/ViewModels/FastForwardWithoutCheckout.cs b/src/ViewModels/FastForwardWithoutCheckout.cs index df4b4d73..974730a7 100644 --- a/src/ViewModels/FastForwardWithoutCheckout.cs +++ b/src/ViewModels/FastForwardWithoutCheckout.cs @@ -32,7 +32,11 @@ namespace SourceGit.ViewModels return Task.Run(() => { new Commands.UpdateRef(_repo.FullPath, Local.FullName, To.FullName, SetProgressDescription).Exec(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); + CallUIThread(() => + { + _repo.NavigateToCommit(To.Head); + _repo.SetWatcherEnabled(true); + }); return true; }); } diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs index 1094012e..cc38aa70 100644 --- a/src/ViewModels/Fetch.cs +++ b/src/ViewModels/Fetch.cs @@ -34,14 +34,14 @@ namespace SourceGit.ViewModels set => _repo.Settings.EnableForceOnFetch = value; } - public Fetch(Repository repo, Models.Remote preferedRemote = null) + public Fetch(Repository repo, Models.Remote preferredRemote = null) { _repo = repo; - _fetchAllRemotes = preferedRemote == null; + _fetchAllRemotes = preferredRemote == null; - if (preferedRemote != null) + if (preferredRemote != null) { - SelectedRemote = preferedRemote; + SelectedRemote = preferredRemote; } else if (!string.IsNullOrEmpty(_repo.Settings.DefaultRemote)) { @@ -83,6 +83,7 @@ namespace SourceGit.ViewModels CallUIThread(() => { + _repo.SetNeedNavigateToUpstreamHead(); _repo.MarkFetched(); _repo.SetWatcherEnabled(true); }); diff --git a/src/ViewModels/FetchInto.cs b/src/ViewModels/FetchInto.cs index a52b1cd6..8143ac9c 100644 --- a/src/ViewModels/FetchInto.cs +++ b/src/ViewModels/FetchInto.cs @@ -32,7 +32,11 @@ namespace SourceGit.ViewModels return Task.Run(() => { new Commands.Fetch(_repo.FullPath, Local, Upstream, SetProgressDescription).Exec(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); + CallUIThread(() => + { + _repo.SetNeedNavigateToUpstreamHead(); + _repo.SetWatcherEnabled(true); + }); return true; }); } diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs index faadaf57..7130bb30 100644 --- a/src/ViewModels/Merge.cs +++ b/src/ViewModels/Merge.cs @@ -62,7 +62,22 @@ namespace SourceGit.ViewModels return Task.Run(() => { new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, SetProgressDescription).Exec(); - CallUIThread(() => _repo.SetWatcherEnabled(true)); + CallUIThread(() => + { + switch (Source) + { + case Models.Branch branch: + _repo.NavigateToCommit(branch.Head); + break; + case Models.Commit commit: + _repo.NavigateToCommit(commit.SHA); + break; + case Models.Tag tag: + _repo.NavigateToCommit(tag.SHA); + break; + } + _repo.SetWatcherEnabled(true); + }); return true; }); } diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index 62d68834..f40b0916 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -192,7 +192,11 @@ namespace SourceGit.ViewModels rs = new Commands.Stash(_repo.FullPath).Pop("stash@{0}"); } - CallUIThread(() => _repo.SetWatcherEnabled(true)); + CallUIThread(() => + { + _repo.SetNeedNavigateToUpstreamHead(); + _repo.SetWatcherEnabled(true); + }); return rs; }); } diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 6b1e439e..617105d9 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -717,6 +717,11 @@ namespace SourceGit.ViewModels _watcher?.SetEnabled(enabled); } + public void SetNeedNavigateToUpstreamHead() + { + _needNavigateToUpstreamHead = true; + } + public void MarkBranchesDirtyManually() { if (_watcher == null) @@ -773,6 +778,15 @@ namespace SourceGit.ViewModels NavigateToCommit(_currentBranch.Head); } + public void NavigateToCurrentUpstreamHead() + { + if (_currentBranch == null || string.IsNullOrEmpty(_currentBranch.Upstream)) + return; + var branch = _branches.Find(x => x.FullName == _currentBranch.Upstream); + if (branch != null) + NavigateToCommit(branch.Head); + } + public void ClearHistoriesFilter() { _settings.HistoriesFilters.Clear(); @@ -991,6 +1005,11 @@ namespace SourceGit.ViewModels _histories.IsLoading = false; _histories.Commits = commits; _histories.Graph = graph; + if (_needNavigateToUpstreamHead) + { + NavigateToCurrentUpstreamHead(); + _needNavigateToUpstreamHead = false; + } } }); } @@ -2588,5 +2607,6 @@ namespace SourceGit.ViewModels private bool _isAutoFetching = false; private Timer _autoFetchTimer = null; private DateTime _lastFetchTime = DateTime.MinValue; + private bool _needNavigateToUpstreamHead = false; } } From 0cb2ca78fe7ab2e10aee308b6ac7378d864574c2 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 11:35:50 +0800 Subject: [PATCH 03/67] code_review: PR #1180 - replace `SetNeedNavigateToUpstreamHead` with `NavigateToBranchDelayed` - navigate to current HEAD instead of original source HEAD after merge Signed-off-by: leo --- src/ViewModels/Fetch.cs | 2 +- src/ViewModels/FetchInto.cs | 2 +- src/ViewModels/Merge.cs | 13 +------------ src/ViewModels/Pull.cs | 2 +- src/ViewModels/Repository.cs | 26 +++++++++++--------------- 5 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/ViewModels/Fetch.cs b/src/ViewModels/Fetch.cs index cc38aa70..35e34bb3 100644 --- a/src/ViewModels/Fetch.cs +++ b/src/ViewModels/Fetch.cs @@ -83,7 +83,7 @@ namespace SourceGit.ViewModels CallUIThread(() => { - _repo.SetNeedNavigateToUpstreamHead(); + _repo.NavigateToBranchDelayed(_repo.CurrentBranch?.Upstream); _repo.MarkFetched(); _repo.SetWatcherEnabled(true); }); diff --git a/src/ViewModels/FetchInto.cs b/src/ViewModels/FetchInto.cs index 8143ac9c..878b0416 100644 --- a/src/ViewModels/FetchInto.cs +++ b/src/ViewModels/FetchInto.cs @@ -34,7 +34,7 @@ namespace SourceGit.ViewModels new Commands.Fetch(_repo.FullPath, Local, Upstream, SetProgressDescription).Exec(); CallUIThread(() => { - _repo.SetNeedNavigateToUpstreamHead(); + _repo.NavigateToBranchDelayed(Upstream.FullName); _repo.SetWatcherEnabled(true); }); return true; diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs index 7130bb30..8b2ad537 100644 --- a/src/ViewModels/Merge.cs +++ b/src/ViewModels/Merge.cs @@ -64,18 +64,7 @@ namespace SourceGit.ViewModels new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, SetProgressDescription).Exec(); CallUIThread(() => { - switch (Source) - { - case Models.Branch branch: - _repo.NavigateToCommit(branch.Head); - break; - case Models.Commit commit: - _repo.NavigateToCommit(commit.SHA); - break; - case Models.Tag tag: - _repo.NavigateToCommit(tag.SHA); - break; - } + _repo.NavigateToBranchDelayed(_repo.CurrentBranch?.FullName); _repo.SetWatcherEnabled(true); }); return true; diff --git a/src/ViewModels/Pull.cs b/src/ViewModels/Pull.cs index f40b0916..465a393a 100644 --- a/src/ViewModels/Pull.cs +++ b/src/ViewModels/Pull.cs @@ -194,7 +194,7 @@ namespace SourceGit.ViewModels CallUIThread(() => { - _repo.SetNeedNavigateToUpstreamHead(); + _repo.NavigateToBranchDelayed(_repo.CurrentBranch?.FullName); _repo.SetWatcherEnabled(true); }); return rs; diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 617105d9..9b720c7b 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -717,11 +717,6 @@ namespace SourceGit.ViewModels _watcher?.SetEnabled(enabled); } - public void SetNeedNavigateToUpstreamHead() - { - _needNavigateToUpstreamHead = true; - } - public void MarkBranchesDirtyManually() { if (_watcher == null) @@ -778,13 +773,9 @@ namespace SourceGit.ViewModels NavigateToCommit(_currentBranch.Head); } - public void NavigateToCurrentUpstreamHead() + public void NavigateToBranchDelayed(string branch) { - if (_currentBranch == null || string.IsNullOrEmpty(_currentBranch.Upstream)) - return; - var branch = _branches.Find(x => x.FullName == _currentBranch.Upstream); - if (branch != null) - NavigateToCommit(branch.Head); + _navigateToBranchDelayed = branch; } public void ClearHistoriesFilter() @@ -1005,12 +996,16 @@ namespace SourceGit.ViewModels _histories.IsLoading = false; _histories.Commits = commits; _histories.Graph = graph; - if (_needNavigateToUpstreamHead) + + if (!string.IsNullOrEmpty(_navigateToBranchDelayed)) { - NavigateToCurrentUpstreamHead(); - _needNavigateToUpstreamHead = false; + var branch = _branches.Find(x => x.FullName == _navigateToBranchDelayed); + if (branch != null) + NavigateToCommit(branch.Head); } } + + _navigateToBranchDelayed = string.Empty; }); } @@ -2607,6 +2602,7 @@ namespace SourceGit.ViewModels private bool _isAutoFetching = false; private Timer _autoFetchTimer = null; private DateTime _lastFetchTime = DateTime.MinValue; - private bool _needNavigateToUpstreamHead = false; + + private string _navigateToBranchDelayed = string.Empty; } } From e7f0217a7b66704b7a446d0572f2f89e39161e24 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 11:51:40 +0800 Subject: [PATCH 04/67] refactor: move binding for `ToolTip.IsOpen` from code to axaml Signed-off-by: leo --- src/Views/CommitBaseInfo.axaml | 7 +++++++ src/Views/CommitMessagePresenter.cs | 17 ----------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml index 43b28288..bdf5f226 100644 --- a/src/Views/CommitBaseInfo.axaml +++ b/src/Views/CommitBaseInfo.axaml @@ -203,6 +203,13 @@ FullMessage="{Binding #ThisControl.FullMessage}" HorizontalAlignment="Stretch" TextWrapping="Wrap"> + + + + + + + diff --git a/src/Views/CommitMessagePresenter.cs b/src/Views/CommitMessagePresenter.cs index 6f838509..c71c9687 100644 --- a/src/Views/CommitMessagePresenter.cs +++ b/src/Views/CommitMessagePresenter.cs @@ -5,8 +5,6 @@ using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Documents; -using Avalonia.Data; -using Avalonia.Data.Converters; using Avalonia.Input; using Avalonia.Threading; using Avalonia.VisualTree; @@ -26,21 +24,6 @@ namespace SourceGit.Views protected override Type StyleKeyOverride => typeof(SelectableTextBlock); - public CommitMessagePresenter() - { - var bindings = new MultiBinding() - { - Converter = BoolConverters.And, - Bindings = new[] - { - new Binding() { Path = "IsPointerOver", Source = this }, - new Binding() { Path = "(ToolTip.Tip)", Source = this, TypeResolver = (_, name) => name == "ToolTip" ? typeof(ToolTip) : null, Converter = ObjectConverters.IsNotNull }, - } - }; - - Bind(ToolTip.IsOpenProperty, bindings); - } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); From 81820e7034bc8e33da84f376096b3abf56947418 Mon Sep 17 00:00:00 2001 From: Massimo Date: Mon, 14 Apr 2025 09:18:45 +0200 Subject: [PATCH 05/67] =?UTF-8?q?refactor:=20improve=20diff=20handling=20f?= =?UTF-8?q?or=20EOL=20changes=20and=20enhance=20text=20diff=E2=80=A6=20(#1?= =?UTF-8?q?177)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: improve diff handling for EOL changes and enhance text diff display - Updated `Diff.cs` to streamline whitespace handling in diff arguments. - Enhanced `DiffContext.cs` to check for EOL changes when old and new hashes differ, creating a text diff if necessary. - Added support for showing end-of-line symbols in `TextDiffView.axaml.cs` options. * localization: update translations to include EOF handling in ignore whitespace messages - Modified the ignore whitespace text in multiple language files to specify that EOF changes are also ignored. - Ensured consistency across all localization files for the patch application feature. * revert: Typo in DiffResult comment * revert: update diff arguments to ignore CR at EOL in whitespace handling (like before changes) * revert: update translations to remove EOF references in Text.Apply.IgnoreWS and fixed typo in Text.Diff.IgnoreWhitespace (EOF => EOL) --------- Co-authored-by: mpagani --- src/Commands/Diff.cs | 2 +- src/Resources/Locales/de_DE.axaml | 2 +- src/Resources/Locales/en_US.axaml | 2 +- src/Resources/Locales/es_ES.axaml | 2 +- src/Resources/Locales/fr_FR.axaml | 2 +- src/Resources/Locales/it_IT.axaml | 2 +- src/Resources/Locales/ja_JP.axaml | 2 +- src/Resources/Locales/pt_BR.axaml | 2 +- src/Resources/Locales/ru_RU.axaml | 2 +- src/Resources/Locales/ta_IN.axaml | 2 +- src/Resources/Locales/zh_CN.axaml | 2 +- src/Resources/Locales/zh_TW.axaml | 2 +- src/ViewModels/DiffContext.cs | 45 ++++++++++++++++++++++++++++++- src/Views/TextDiffView.axaml.cs | 1 + 14 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 8ae6350f..a4e05ae5 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -30,7 +30,7 @@ namespace SourceGit.Commands if (ignoreWhitespace) Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}"; else - Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}"; + Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --unified={unified} {opt}"; } public Models.DiffResult Result() diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 25b54c60..1ceac07c 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -235,7 +235,7 @@ ALT Kopieren Dateimodus geändert - Ignoriere Leerzeichenänderungen + Ignoriere Leerzeichenänderungen und EOL LFS OBJEKT ÄNDERUNG Nächste Änderung KEINE ÄNDERUNG ODER NUR ZEILEN-ENDE ÄNDERUNGEN diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index ad71427b..7ec38670 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -241,7 +241,7 @@ Copy File Mode Changed First Difference - Ignore Whitespace Change + Ignore Whitespace Change and EOL Last Difference LFS OBJECT CHANGE Next Difference diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index e2af0860..04fdde4b 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -240,7 +240,7 @@ Copiar Modo de Archivo Cambiado Primera Diferencia - Ignorar Cambio de Espacios en Blanco + Ignorar Cambio de Espacios en Blanco y EOL Última Diferencia CAMBIO DE OBJETO LFS Siguiente Diferencia diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 83d590f5..f5679ab8 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -241,7 +241,7 @@ Copier Mode de fichier changé Première différence - Ignorer les changements d'espaces + Ignorer les changements d'espaces et EOL Dernière différence CHANGEMENT D'OBJET LFS Différence suivante diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index 59bf3028..5ed81da2 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -239,7 +239,7 @@ Copia Modalità File Modificata Prima differenza - Ignora Modifiche agli Spazi + Ignora Modifiche agli Spazi e EOL Ultima differenza MODIFICA OGGETTO LFS Differenza Successiva diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index fe643b5e..1b94ed6f 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -240,7 +240,7 @@ コピー ファイルモードが変更されました 先頭の差分 - 空白の変更を無視 + 空白の変更とEOLを無視 最後の差分 LFSオブジェクトの変更 次の差分 diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 3caac3cc..e78c1a36 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -216,7 +216,7 @@ ANTIGO Copiar Modo de Arquivo Alterado - Ignorar mudanças de espaço em branco + Ignorar mudanças de espaço em branco e EOL MUDANÇA DE OBJETO LFS Próxima Diferença SEM MUDANÇAS OU APENAS MUDANÇAS DE EOL diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index ee04f4d1..dd39b34f 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -246,7 +246,7 @@ Копировать Режим файла изменён Первое различие - Игнорировать изменение пробелов + Игнорировать изменение пробелов и EOL Последнее различие ИЗМЕНЕНИЕ ОБЪЕКТА LFS Следующее различие diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index 946a8d9c..30c2244b 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -240,7 +240,7 @@ நகல் கோப்பு முறை மாற்றப்பட்டது முதல் வேறுபாடு - வெள்ளைவெளி மாற்றத்தை புறக்கணி + வெள்ளைவெளி மாற்றத்தை மற்றும் EOL புறக்கணி கடைசி வேறுபாடு பெகோஅ பொருள் மாற்றம் அடுத்த வேறுபாடு diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 35a97b6e..d8b63422 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -245,7 +245,7 @@ 复制 文件权限已变化 首个差异 - 忽略空白符号变化 + 忽略空白符号变化和EOL 最后一个差异 LFS对象变更 下一个差异 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index d71281f7..833e6610 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -245,7 +245,7 @@ 複製 檔案權限已變更 第一個差異 - 忽略空白符號變化 + 忽略空白符號變化和EOL 最後一個差異 LFS 物件變更 下一個差異 diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 6dd836bf..0feb7d77 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -207,7 +207,50 @@ namespace SourceGit.ViewModels } else { - rs = new Models.NoOrEOLChange(); + // Check if old and new hashes differ but no text changes found + if (!string.IsNullOrEmpty(latest.OldHash) && + !string.IsNullOrEmpty(latest.NewHash) && + latest.OldHash != latest.NewHash) + { + // If hashes differ but no text diff found, it's likely an EOL change + // Create a text diff to show the file content + var textDiff = new Models.TextDiff() + { + Repo = _repo, + Option = _option, + File = _option.Path + }; + // Query the file content to show + var fileContent = Commands.QueryFileContent.Run(_repo, "HEAD", _option.Path); + using var reader = new StreamReader(fileContent); + var line = string.Empty; + int lineNumber = 1; + + while ((line = reader.ReadLine()) != null) + { + textDiff.Lines.Add(new Models.TextDiffLine( + Models.TextDiffLineType.Normal, + line, + lineNumber, + lineNumber)); + + lineNumber++; + } + + if (textDiff.Lines.Count > 0) + { + textDiff.MaxLineNumber = lineNumber - 1; + rs = textDiff; + } + else + { + rs = new Models.NoOrEOLChange(); + } + } + else + { + rs = new Models.NoOrEOLChange(); + } } Dispatcher.UIThread.Post(() => diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 7ce9f288..fa065fed 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -745,6 +745,7 @@ namespace SourceGit.Views var val = ShowHiddenSymbols; Options.ShowTabs = val; Options.ShowSpaces = val; + Options.ShowEndOfLine = val; } else if (change.Property == TabWidthProperty) { From e89dbd8f439ca9e7e669801460a289f7233a3726 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 16:06:52 +0800 Subject: [PATCH 06/67] code_review: PR #1177 - use `Command.ReadToEnd` instead of `Command.Exec` to avoid git trims line endings. - use `StringBuilder.Append('\n')` instead of `StringBuilder.AppendLine()` to restore original line endings (we split the original diff output by `\n` not `\r') - there's no need to show file content (the `StreamReader.ReadLine()` will trim line endings) Signed-off-by: leo --- src/Commands/Diff.cs | 29 +++++++++++++++++---- src/ViewModels/DiffContext.cs | 45 +-------------------------------- src/Views/TextDiffView.axaml.cs | 10 +++++--- 3 files changed, 31 insertions(+), 53 deletions(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index a4e05ae5..1d112231 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -35,7 +35,26 @@ namespace SourceGit.Commands public Models.DiffResult Result() { - Exec(); + var rs = ReadToEnd(); + if (!rs.IsSuccess) + { + _result.TextDiff = null; + return _result; + } + + var start = 0; + var end = rs.StdOut.IndexOf('\n', start); + while (end > 0) + { + var line = rs.StdOut.Substring(start, end - start); + ParseLine(line); + + start = end + 1; + end = rs.StdOut.IndexOf('\n', start); + } + + if (start < rs.StdOut.Length) + ParseLine(rs.StdOut.Substring(start)); if (_result.IsBinary || _result.IsLFS) { @@ -54,8 +73,11 @@ namespace SourceGit.Commands return _result; } - protected override void OnReadline(string line) + private void ParseLine(string line) { + if (_result.IsBinary) + return; + if (line.StartsWith("old mode ", StringComparison.Ordinal)) { _result.OldMode = line.Substring(9); @@ -80,9 +102,6 @@ namespace SourceGit.Commands return; } - if (_result.IsBinary) - return; - if (_result.IsLFS) { var ch = line[0]; diff --git a/src/ViewModels/DiffContext.cs b/src/ViewModels/DiffContext.cs index 0feb7d77..6dd836bf 100644 --- a/src/ViewModels/DiffContext.cs +++ b/src/ViewModels/DiffContext.cs @@ -207,50 +207,7 @@ namespace SourceGit.ViewModels } else { - // Check if old and new hashes differ but no text changes found - if (!string.IsNullOrEmpty(latest.OldHash) && - !string.IsNullOrEmpty(latest.NewHash) && - latest.OldHash != latest.NewHash) - { - // If hashes differ but no text diff found, it's likely an EOL change - // Create a text diff to show the file content - var textDiff = new Models.TextDiff() - { - Repo = _repo, - Option = _option, - File = _option.Path - }; - // Query the file content to show - var fileContent = Commands.QueryFileContent.Run(_repo, "HEAD", _option.Path); - using var reader = new StreamReader(fileContent); - var line = string.Empty; - int lineNumber = 1; - - while ((line = reader.ReadLine()) != null) - { - textDiff.Lines.Add(new Models.TextDiffLine( - Models.TextDiffLineType.Normal, - line, - lineNumber, - lineNumber)); - - lineNumber++; - } - - if (textDiff.Lines.Count > 0) - { - textDiff.MaxLineNumber = lineNumber - 1; - rs = textDiff; - } - else - { - rs = new Models.NoOrEOLChange(); - } - } - else - { - rs = new Models.NoOrEOLChange(); - } + rs = new Models.NoOrEOLChange(); } Dispatcher.UIThread.Post(() => diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index fa065fed..03e724ab 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1253,11 +1253,12 @@ namespace SourceGit.Views { builder.Append(line.Content.Substring(0, 1000)); builder.Append($"...({line.Content.Length - 1000} character trimmed)"); - builder.AppendLine(); + builder.Append('\n'); } else { - builder.AppendLine(line.Content); + builder.Append(line.Content); + builder.Append('\n'); } } @@ -1492,11 +1493,12 @@ namespace SourceGit.Views { builder.Append(line.Content.Substring(0, 1000)); builder.Append($"...({line.Content.Length - 1000} characters trimmed)"); - builder.AppendLine(); + builder.Append('\n'); } else { - builder.AppendLine(line.Content); + builder.Append(line.Content); + builder.Append('\n'); } } From f14a6660912e8b6befa2de3bd950c2d7810d672b Mon Sep 17 00:00:00 2001 From: Massimo Date: Mon, 14 Apr 2025 10:41:34 +0200 Subject: [PATCH 07/67] feat: add workspace-specific default clone directory functionality (#1183) * refactor: improve diff handling for EOL changes and enhance text diff display - Updated `Diff.cs` to streamline whitespace handling in diff arguments. - Enhanced `DiffContext.cs` to check for EOL changes when old and new hashes differ, creating a text diff if necessary. - Added support for showing end-of-line symbols in `TextDiffView.axaml.cs` options. * localization: update translations to include EOF handling in ignore whitespace messages - Modified the ignore whitespace text in multiple language files to specify that EOF changes are also ignored. - Ensured consistency across all localization files for the patch application feature. * revert: Typo in DiffResult comment * revert: update diff arguments to ignore CR at EOL in whitespace handling (like before changes) * revert: update translations to remove EOF references in Text.Apply.IgnoreWS and fixed typo in Text.Diff.IgnoreWhitespace (EOF => EOL) * feat: add workspace-specific default clone directory functionality - Implemented logic in Clone.cs to set ParentFolder based on the active workspace's DefaultCloneDir if available, falling back to the global GitDefaultCloneDir. - Added DefaultCloneDir property to Workspace.cs to store the default clone directory for each workspace. - Updated ConfigureWorkspace.axaml to include a TextBox and Button for setting the DefaultCloneDir in the UI. - Implemented folder selection functionality in ConfigureWorkspace.axaml.cs to allow users to choose a directory for cloning. - This closes issue #1145 --------- Co-authored-by: mpagani --- src/ViewModels/Clone.cs | 13 ++++++++++++- src/ViewModels/Workspace.cs | 7 +++++++ src/Views/ConfigureWorkspace.axaml | 13 ++++++++++--- src/Views/ConfigureWorkspace.axaml.cs | 26 ++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs index 3123d62a..2b7c2580 100644 --- a/src/ViewModels/Clone.cs +++ b/src/ViewModels/Clone.cs @@ -64,6 +64,17 @@ namespace SourceGit.ViewModels _pageId = pageId; View = new Views.Clone() { DataContext = this }; + // Use workspace-specific DefaultCloneDir if available + var activeWorkspace = Preferences.Instance.GetActiveWorkspace(); + if (activeWorkspace != null && !string.IsNullOrEmpty(activeWorkspace.DefaultCloneDir)) + { + ParentFolder = activeWorkspace.DefaultCloneDir; + } + else + { + ParentFolder = Preferences.Instance.GitDefaultCloneDir; + } + Task.Run(async () => { try @@ -170,7 +181,7 @@ namespace SourceGit.ViewModels private string _remote = string.Empty; private bool _useSSH = false; private string _sshKey = string.Empty; - private string _parentFolder = Preferences.Instance.GitDefaultCloneDir; + private string _parentFolder = string.Empty; private string _local = string.Empty; private string _extraArgs = string.Empty; } diff --git a/src/ViewModels/Workspace.cs b/src/ViewModels/Workspace.cs index d527ff48..3ae935c7 100644 --- a/src/ViewModels/Workspace.cs +++ b/src/ViewModels/Workspace.cs @@ -46,6 +46,12 @@ namespace SourceGit.ViewModels set => SetProperty(ref _restoreOnStartup, value); } + public string DefaultCloneDir + { + get => _defaultCloneDir; + set => SetProperty(ref _defaultCloneDir, value); + } + public IBrush Brush { get => new SolidColorBrush(_color); @@ -55,5 +61,6 @@ namespace SourceGit.ViewModels private uint _color = 4278221015; private bool _isActive = false; private bool _restoreOnStartup = true; + private string _defaultCloneDir = string.Empty; } } diff --git a/src/Views/ConfigureWorkspace.axaml b/src/Views/ConfigureWorkspace.axaml index 79eab390..0bef89b9 100644 --- a/src/Views/ConfigureWorkspace.axaml +++ b/src/Views/ConfigureWorkspace.axaml @@ -98,13 +98,20 @@ - + - - + + + + + + + diff --git a/src/Views/ConfigureWorkspace.axaml.cs b/src/Views/ConfigureWorkspace.axaml.cs index 9e458f6f..8ef5dec7 100644 --- a/src/Views/ConfigureWorkspace.axaml.cs +++ b/src/Views/ConfigureWorkspace.axaml.cs @@ -1,4 +1,7 @@ using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Platform.Storage; +using System; namespace SourceGit.Views { @@ -16,5 +19,28 @@ namespace SourceGit.Views if (!Design.IsDesignMode) ViewModels.Preferences.Instance.Save(); } + + private async void SelectDefaultCloneDir(object _, RoutedEventArgs e) + { + var workspace = DataContext as ViewModels.ConfigureWorkspace; + if (workspace?.Selected == null) + return; + + var options = new FolderPickerOpenOptions() { AllowMultiple = false }; + try + { + var selected = await StorageProvider.OpenFolderPickerAsync(options); + if (selected.Count == 1) + { + workspace.Selected.DefaultCloneDir = selected[0].Path.LocalPath; + } + } + catch (Exception ex) + { + App.RaiseException(string.Empty, $"Failed to select default clone directory: {ex.Message}"); + } + + e.Handled = true; + } } } From b7aa49403bdb3805460b1c70d7e3b7fa4887c13c Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 17:03:08 +0800 Subject: [PATCH 08/67] code_review: PR #1183 - code style in `Clone` constructor - re-design workspace configuration dialog Signed-off-by: leo --- src/Resources/Locales/de_DE.axaml | 1 + src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/es_ES.axaml | 1 + src/Resources/Locales/fr_FR.axaml | 1 + src/Resources/Locales/it_IT.axaml | 1 + src/Resources/Locales/ja_JP.axaml | 1 + src/Resources/Locales/pt_BR.axaml | 1 + src/Resources/Locales/ta_IN.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/Resources/Locales/zh_TW.axaml | 1 + src/ViewModels/Clone.cs | 17 +++++------------ src/Views/ConfigureWorkspace.axaml | 29 +++++++++++++++++------------ 12 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 1ceac07c..3cb70cea 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -176,6 +176,7 @@ Benutzername für dieses Repository Arbeitsplätze Farbe + Name Zuletzt geöffnete Tabs beim Starten wiederherstellen Konventionelle Commit-Hilfe Breaking Change: diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 7ec38670..7e931998 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -176,6 +176,7 @@ User name for this repository Workspaces Color + Name Restore tabs on startup CONTINUE Empty commit detected! Do you want to continue (--allow-empty)? diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 04fdde4b..24deeabd 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -179,6 +179,7 @@ Nombre de usuario para este repositorio Espacios de Trabajo Color + Nombre Restaurar pestañas al iniciar Asistente de Commit Convencional Cambio Importante: diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index f5679ab8..61098493 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -180,6 +180,7 @@ Nom d'utilisateur pour ce dépôt Espaces de travail Couleur + Nom Restaurer les onglets au démarrage Assistant Commits Conventionnels Changement Radical : diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index 5ed81da2..1d9901a8 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -179,6 +179,7 @@ Nome utente per questo repository Spazi di Lavoro Colore + Nome Ripristina schede all'avvio Guida Commit Convenzionali Modifica Sostanziale: diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index 1b94ed6f..db671768 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -179,6 +179,7 @@ このリポジトリにおけるユーザー名 ワークスペース + 名前 起動時にタブを復元 Conventional Commitヘルパー 破壊的変更: diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index e78c1a36..299ececd 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -161,6 +161,7 @@ Nome de usuário para este repositório Workspaces Cor + Nome Restaurar abas ao inicializar Assistente de Conventional Commit Breaking Change: diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index 30c2244b..d8d6f540 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -179,6 +179,7 @@ இந்த களஞ்சியத்திற்கான பயனர் பெயர் பணியிடங்கள் நிறம் + பெயர் தாவல்களை மீட்டமை வழக்கமான உறுதிமொழி உதவியாளர் உடைக்கும் மாற்றம்: diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index d8b63422..9040644a 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -180,6 +180,7 @@ 应用于本仓库的用户名 工作区 颜色 + 名称 启动时恢复打开的仓库 确认继续 提交未包含变更文件!是否继续(--allow-empty)? diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 833e6610..8437eefc 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -180,6 +180,7 @@ 用於本存放庫的使用者名稱 工作區 顏色 + 名稱 啟動時還原上次開啟的存放庫 确认继续 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)? diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs index 2b7c2580..97c90523 100644 --- a/src/ViewModels/Clone.cs +++ b/src/ViewModels/Clone.cs @@ -62,18 +62,13 @@ namespace SourceGit.ViewModels public Clone(string pageId) { _pageId = pageId; - View = new Views.Clone() { DataContext = this }; - // Use workspace-specific DefaultCloneDir if available var activeWorkspace = Preferences.Instance.GetActiveWorkspace(); - if (activeWorkspace != null && !string.IsNullOrEmpty(activeWorkspace.DefaultCloneDir)) - { - ParentFolder = activeWorkspace.DefaultCloneDir; - } - else - { - ParentFolder = Preferences.Instance.GitDefaultCloneDir; - } + _parentFolder = activeWorkspace?.DefaultCloneDir; + if (string.IsNullOrEmpty(ParentFolder)) + _parentFolder = Preferences.Instance.GitDefaultCloneDir; + + View = new Views.Clone() { DataContext = this }; Task.Run(async () => { @@ -81,9 +76,7 @@ namespace SourceGit.ViewModels { var text = await App.GetClipboardTextAsync(); if (Models.Remote.IsValidURL(text)) - { Dispatcher.UIThread.Invoke(() => Remote = text); - } } catch { diff --git a/src/Views/ConfigureWorkspace.axaml b/src/Views/ConfigureWorkspace.axaml index 0bef89b9..169df154 100644 --- a/src/Views/ConfigureWorkspace.axaml +++ b/src/Views/ConfigureWorkspace.axaml @@ -98,20 +98,25 @@ - - - + + + + + + + + + + + + + + - - - - - - - From 558eb7c9ac0ddff802047227e806770e303526cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 14 Apr 2025 09:03:23 +0000 Subject: [PATCH 09/67] doc: Update translation status and missing keys --- TRANSLATION.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index a2991c6e..7ae5b13f 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -70,7 +70,7 @@ This document shows the translation status of each locale file in the repository -### ![it__IT](https://img.shields.io/badge/it__IT-98.40%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-98.41%25-yellow)
Missing keys in it_IT.axaml @@ -90,7 +90,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-98.40%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-98.41%25-yellow)
Missing keys in ja_JP.axaml @@ -110,7 +110,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-89.76%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-89.77%25-yellow)
Missing keys in pt_BR.axaml From 09c0edef8e97f00e3dc479a2abd02ca416ac9d78 Mon Sep 17 00:00:00 2001 From: Massimo Date: Mon, 14 Apr 2025 13:16:15 +0200 Subject: [PATCH 10/67] feat: implement IPC for opening repositories in new tabs (#1185) * refactor: improve diff handling for EOL changes and enhance text diff display - Updated `Diff.cs` to streamline whitespace handling in diff arguments. - Enhanced `DiffContext.cs` to check for EOL changes when old and new hashes differ, creating a text diff if necessary. - Added support for showing end-of-line symbols in `TextDiffView.axaml.cs` options. * localization: update translations to include EOF handling in ignore whitespace messages - Modified the ignore whitespace text in multiple language files to specify that EOF changes are also ignored. - Ensured consistency across all localization files for the patch application feature. * revert: Typo in DiffResult comment * revert: update diff arguments to ignore CR at EOL in whitespace handling (like before changes) * revert: update translations to remove EOF references in Text.Apply.IgnoreWS and fixed typo in Text.Diff.IgnoreWhitespace (EOF => EOL) * feat: add workspace-specific default clone directory functionality - Implemented logic in Clone.cs to set ParentFolder based on the active workspace's DefaultCloneDir if available, falling back to the global GitDefaultCloneDir. - Added DefaultCloneDir property to Workspace.cs to store the default clone directory for each workspace. - Updated ConfigureWorkspace.axaml to include a TextBox and Button for setting the DefaultCloneDir in the UI. - Implemented folder selection functionality in ConfigureWorkspace.axaml.cs to allow users to choose a directory for cloning. - This closes issue #1145 * feat: implement IPC for opening repositories in new tabs - Added functionality to send repository paths to an existing instance of the application using named pipes. - Introduced a new preference option to open repositories in a new tab instead of a new window. - Updated UI to include a checkbox for the new preference. - Enhanced the handling of IPC server lifecycle based on the new preference setting. - This closes issue #1184 --------- Co-authored-by: mpagani --- src/App.axaml.cs | 145 +++++++++++++++++++++++++++++- src/Resources/Locales/en_US.axaml | 1 + src/ViewModels/Preferences.cs | 7 ++ src/Views/Preferences.axaml | 7 +- 4 files changed, 157 insertions(+), 3 deletions(-) diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 0448a247..b1be7072 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -2,12 +2,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.IO.Pipes; using System.Net.Http; using System.Reflection; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using System.Linq; using Avalonia; using Avalonia.Controls; @@ -46,6 +48,8 @@ namespace SourceGit Environment.Exit(exitTodo); else if (TryLaunchAsRebaseMessageEditor(args, out int exitMessage)) Environment.Exit(exitMessage); + else if (TrySendArgsToExistingInstance(args)) + Environment.Exit(0); else BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } @@ -77,6 +81,44 @@ namespace SourceGit return builder; } + private static bool TrySendArgsToExistingInstance(string[] args) + { + if (args == null || args.Length != 1 || !Directory.Exists(args[0])) + return false; + + var pref = ViewModels.Preferences.Instance; + + if (!pref.OpenReposInNewTab) + return false; + + try + { + var processes = Process.GetProcessesByName("SourceGit"); + + if (processes.Length <= 1) + return false; + + using var client = new NamedPipeClientStream(".", "SourceGitIPC", PipeDirection.Out); + + client.Connect(1000); + + if (client.IsConnected) + { + using var writer = new StreamWriter(client); + + writer.WriteLine(args[0]); + writer.Flush(); + + return true; + } + } + catch (Exception) + { + } + + return false; + } + private static void LogException(Exception ex) { if (ex == null) @@ -328,7 +370,13 @@ namespace SourceGit AvaloniaXamlLoader.Load(this); var pref = ViewModels.Preferences.Instance; - pref.PropertyChanged += (_, _) => pref.Save(); + + pref.PropertyChanged += (s, e) => { + pref.Save(); + + if (e.PropertyName.Equals(nameof(ViewModels.Preferences.OpenReposInNewTab))) + HandleOpenReposInNewTabChanged(); + }; SetLocale(pref.Locale); SetTheme(pref.Theme, pref.ThemeOverrides); @@ -488,13 +536,104 @@ namespace SourceGit _launcher = new ViewModels.Launcher(startupRepo); desktop.MainWindow = new Views.Launcher() { DataContext = _launcher }; -#if !DISABLE_UPDATE_DETECTION var pref = ViewModels.Preferences.Instance; + + HandleOpenReposInNewTabChanged(); + +#if !DISABLE_UPDATE_DETECTION if (pref.ShouldCheck4UpdateOnStartup()) Check4Update(); #endif } + private void HandleOpenReposInNewTabChanged() + { + var pref = ViewModels.Preferences.Instance; + + if (pref.OpenReposInNewTab) + { + if (_ipcServerTask == null || _ipcServerTask.IsCompleted) + { + // Start IPC server + _ipcServerCts = new CancellationTokenSource(); + _ipcServerTask = Task.Run(() => StartIPCServer(_ipcServerCts.Token)); + } + } + else + { + // Stop IPC server if running + if (_ipcServerCts != null && !_ipcServerCts.IsCancellationRequested) + { + _ipcServerCts.Cancel(); + _ipcServerCts.Dispose(); + _ipcServerCts = null; + } + _ipcServerTask = null; + } + } + + private void StartIPCServer(CancellationToken cancellationToken) + { + try + { + while (!cancellationToken.IsCancellationRequested) + { + using var server = new NamedPipeServerStream("SourceGitIPC", PipeDirection.In); + + // Use WaitForConnectionAsync with cancellation token + try + { + Task connectionTask = server.WaitForConnectionAsync(cancellationToken); + connectionTask.Wait(cancellationToken); + } + catch (OperationCanceledException) + { + return; + } + catch (AggregateException ae) when (ae.InnerExceptions.Any(e => e is OperationCanceledException)) + { + return; + } + + // Process the connection + using var reader = new StreamReader(server); + var repoPath = reader.ReadLine(); + + if (!string.IsNullOrEmpty(repoPath) && Directory.Exists(repoPath)) + { + Dispatcher.UIThread.Post(() => + { + try + { + var test = new Commands.QueryRepositoryRootPath(repoPath).ReadToEnd(); + + if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut)) + { + var repoRootPath = test.StdOut.Trim(); + var pref = ViewModels.Preferences.Instance; + var node = pref.FindOrAddNodeByRepositoryPath(repoRootPath, null, false); + + ViewModels.Welcome.Instance.Refresh(); + + _launcher?.OpenRepositoryInTab(node, null); + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow != null) + desktop.MainWindow.Activate(); + } + } + catch (Exception) + { + } + }); + } + } + } + catch (Exception) + { + // Pipe server failed, we can just exit the thread + } + } + private void Check4Update(bool manually = false) { Task.Run(async () => @@ -584,5 +723,7 @@ namespace SourceGit private ResourceDictionary _activeLocale = null; private ResourceDictionary _themeOverrides = null; private ResourceDictionary _fontsOverrides = null; + private Task _ipcServerTask = null; + private CancellationTokenSource _ipcServerCts = null; } } diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 7e931998..123b6381 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -752,4 +752,5 @@ Lock Remove Unlock + Open repositories in new tab instead of new window diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs index cad6c224..d1e78d6a 100644 --- a/src/ViewModels/Preferences.cs +++ b/src/ViewModels/Preferences.cs @@ -90,6 +90,12 @@ namespace SourceGit.ViewModels } } + public bool OpenReposInNewTab + { + get => _openReposInNewTab; + set => SetProperty(ref _openReposInNewTab, value); + } + public bool UseSystemWindowFrame { get => _useSystemWindowFrame; @@ -632,6 +638,7 @@ namespace SourceGit.ViewModels private string _defaultFontFamily = string.Empty; private string _monospaceFontFamily = string.Empty; private bool _onlyUseMonoFontInEditor = false; + private bool _openReposInNewTab = false; private bool _useSystemWindowFrame = false; private double _defaultFontSize = 13; private double _editorFontSize = 13; diff --git a/src/Views/Preferences.axaml b/src/Views/Preferences.axaml index 702ec20f..704757df 100644 --- a/src/Views/Preferences.axaml +++ b/src/Views/Preferences.axaml @@ -46,7 +46,7 @@ - + + + Date: Mon, 14 Apr 2025 22:03:51 +0800 Subject: [PATCH 11/67] code_review: PR #1185 - make `SourceGit` running in singleton mode - `TrySendArgsToExistingInstance` should not be called before `BuildAvaloniaApp().StartWithClassicDesktopLifetime(args)` since we may want to launch `SourceGit` as a core editor. - avoid `preference.json` to be saved by multiple instances. - move IPC code to models. Signed-off-by: leo --- src/App.axaml.cs | 166 +++++------------------------- src/Models/IpcChannel.cs | 97 +++++++++++++++++ src/Resources/Locales/en_US.axaml | 1 - src/ViewModels/Preferences.cs | 15 ++- src/Views/Preferences.axaml | 7 +- 5 files changed, 133 insertions(+), 153 deletions(-) create mode 100644 src/Models/IpcChannel.cs diff --git a/src/App.axaml.cs b/src/App.axaml.cs index b1be7072..6504e85b 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -2,14 +2,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.IO.Pipes; using System.Net.Http; using System.Reflection; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using System.Linq; using Avalonia; using Avalonia.Controls; @@ -48,8 +46,6 @@ namespace SourceGit Environment.Exit(exitTodo); else if (TryLaunchAsRebaseMessageEditor(args, out int exitMessage)) Environment.Exit(exitMessage); - else if (TrySendArgsToExistingInstance(args)) - Environment.Exit(0); else BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } @@ -81,44 +77,6 @@ namespace SourceGit return builder; } - private static bool TrySendArgsToExistingInstance(string[] args) - { - if (args == null || args.Length != 1 || !Directory.Exists(args[0])) - return false; - - var pref = ViewModels.Preferences.Instance; - - if (!pref.OpenReposInNewTab) - return false; - - try - { - var processes = Process.GetProcessesByName("SourceGit"); - - if (processes.Length <= 1) - return false; - - using var client = new NamedPipeClientStream(".", "SourceGitIPC", PipeDirection.Out); - - client.Connect(1000); - - if (client.IsConnected) - { - using var writer = new StreamWriter(client); - - writer.WriteLine(args[0]); - writer.Flush(); - - return true; - } - } - catch (Exception) - { - } - - return false; - } - private static void LogException(Exception ex) { if (ex == null) @@ -370,13 +328,7 @@ namespace SourceGit AvaloniaXamlLoader.Load(this); var pref = ViewModels.Preferences.Instance; - - pref.PropertyChanged += (s, e) => { - pref.Save(); - - if (e.PropertyName.Equals(nameof(ViewModels.Preferences.OpenReposInNewTab))) - HandleOpenReposInNewTabChanged(); - }; + pref.PropertyChanged += (_, _) => pref.Save(); SetLocale(pref.Locale); SetTheme(pref.Theme, pref.ThemeOverrides); @@ -395,7 +347,17 @@ namespace SourceGit if (TryLaunchAsAskpass(desktop)) return; - TryLaunchAsNormal(desktop); + _ipcChannel = new Models.IpcChannel(); + if (!_ipcChannel.IsFirstInstance) + { + _ipcChannel.SendToFirstInstance(desktop.Args is { Length: 1 } ? desktop.Args[0] : string.Empty); + Quit(0); + } + else + { + _ipcChannel.MessageReceived += TryOpenRepository; + TryLaunchAsNormal(desktop); + } } } #endregion @@ -533,12 +495,12 @@ namespace SourceGit if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0])) startupRepo = desktop.Args[0]; + var pref = ViewModels.Preferences.Instance; + pref.SetCanModify(); + _launcher = new ViewModels.Launcher(startupRepo); desktop.MainWindow = new Views.Launcher() { DataContext = _launcher }; - - var pref = ViewModels.Preferences.Instance; - - HandleOpenReposInNewTabChanged(); + desktop.Exit += (_, _) => _ipcChannel.Dispose(); #if !DISABLE_UPDATE_DETECTION if (pref.ShouldCheck4UpdateOnStartup()) @@ -546,91 +508,20 @@ namespace SourceGit #endif } - private void HandleOpenReposInNewTabChanged() + private void TryOpenRepository(string repo) { - var pref = ViewModels.Preferences.Instance; - - if (pref.OpenReposInNewTab) + if (string.IsNullOrEmpty(repo) || !Directory.Exists(repo)) + return; + + var test = new Commands.QueryRepositoryRootPath(repo).ReadToEnd(); + if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut)) { - if (_ipcServerTask == null || _ipcServerTask.IsCompleted) + Dispatcher.UIThread.Invoke(() => { - // Start IPC server - _ipcServerCts = new CancellationTokenSource(); - _ipcServerTask = Task.Run(() => StartIPCServer(_ipcServerCts.Token)); - } - } - else - { - // Stop IPC server if running - if (_ipcServerCts != null && !_ipcServerCts.IsCancellationRequested) - { - _ipcServerCts.Cancel(); - _ipcServerCts.Dispose(); - _ipcServerCts = null; - } - _ipcServerTask = null; - } - } - - private void StartIPCServer(CancellationToken cancellationToken) - { - try - { - while (!cancellationToken.IsCancellationRequested) - { - using var server = new NamedPipeServerStream("SourceGitIPC", PipeDirection.In); - - // Use WaitForConnectionAsync with cancellation token - try - { - Task connectionTask = server.WaitForConnectionAsync(cancellationToken); - connectionTask.Wait(cancellationToken); - } - catch (OperationCanceledException) - { - return; - } - catch (AggregateException ae) when (ae.InnerExceptions.Any(e => e is OperationCanceledException)) - { - return; - } - - // Process the connection - using var reader = new StreamReader(server); - var repoPath = reader.ReadLine(); - - if (!string.IsNullOrEmpty(repoPath) && Directory.Exists(repoPath)) - { - Dispatcher.UIThread.Post(() => - { - try - { - var test = new Commands.QueryRepositoryRootPath(repoPath).ReadToEnd(); - - if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut)) - { - var repoRootPath = test.StdOut.Trim(); - var pref = ViewModels.Preferences.Instance; - var node = pref.FindOrAddNodeByRepositoryPath(repoRootPath, null, false); - - ViewModels.Welcome.Instance.Refresh(); - - _launcher?.OpenRepositoryInTab(node, null); - - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow != null) - desktop.MainWindow.Activate(); - } - } - catch (Exception) - { - } - }); - } - } - } - catch (Exception) - { - // Pipe server failed, we can just exit the thread + var node = ViewModels.Preferences.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), null, false); + ViewModels.Welcome.Instance.Refresh(); + _launcher?.OpenRepositoryInTab(node, null); + }); } } @@ -719,11 +610,10 @@ namespace SourceGit return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty; } + private Models.IpcChannel _ipcChannel = null; private ViewModels.Launcher _launcher = null; private ResourceDictionary _activeLocale = null; private ResourceDictionary _themeOverrides = null; private ResourceDictionary _fontsOverrides = null; - private Task _ipcServerTask = null; - private CancellationTokenSource _ipcServerCts = null; } } diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs new file mode 100644 index 00000000..e2a34b29 --- /dev/null +++ b/src/Models/IpcChannel.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; +using System.IO.Pipes; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace SourceGit.Models +{ + public class IpcChannel : IDisposable + { + public bool IsFirstInstance + { + get => _server != null; + } + + public event Action MessageReceived; + + public IpcChannel() + { + try + { + _server = new NamedPipeServerStream("SourceGitIPCChannel", PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly); + _cancellationTokenSource = new CancellationTokenSource(); + Task.Run(StartServer); + } + catch + { + // IGNORE + } + } + + public void SendToFirstInstance(string cmd) + { + try + { + using (var client = new NamedPipeClientStream(".", "SourceGitIPCChannel", PipeDirection.Out)) + { + client.Connect(1000); + if (client.IsConnected) + { + using (var writer = new StreamWriter(client)) + { + writer.Write(Encoding.UTF8.GetBytes(cmd)); + writer.Flush(); + } + } + } + } + catch + { + // IGNORE + } + } + + public void Dispose() + { + _server?.Close(); + } + + private async void StartServer() + { + var buffer = new byte[1024]; + + while (true) + { + try + { + await _server.WaitForConnectionAsync(_cancellationTokenSource.Token); + + using (var stream = new MemoryStream()) + { + while (true) + { + var readed = await _server.ReadAsync(buffer.AsMemory(0, 1024), _cancellationTokenSource.Token); + if (readed == 0) + break; + + stream.Write(buffer, 0, readed); + } + + stream.Seek(0, SeekOrigin.Begin); + MessageReceived?.Invoke(Encoding.UTF8.GetString(stream.ToArray()).Trim()); + _server.Disconnect(); + } + } + catch + { + // IGNORE + } + } + } + + private NamedPipeServerStream _server = null; + private CancellationTokenSource _cancellationTokenSource = null; + } +} diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 123b6381..7e931998 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -752,5 +752,4 @@ Lock Remove Unlock - Open repositories in new tab instead of new window diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs index d1e78d6a..9395e0a7 100644 --- a/src/ViewModels/Preferences.cs +++ b/src/ViewModels/Preferences.cs @@ -90,12 +90,6 @@ namespace SourceGit.ViewModels } } - public bool OpenReposInNewTab - { - get => _openReposInNewTab; - set => SetProperty(ref _openReposInNewTab, value); - } - public bool UseSystemWindowFrame { get => _useSystemWindowFrame; @@ -369,6 +363,11 @@ namespace SourceGit.ViewModels set => SetProperty(ref _lastCheckUpdateTime, value); } + public void SetCanModify() + { + _isReadonly = false; + } + public bool IsGitConfigured() { var path = GitInstallPath; @@ -496,7 +495,7 @@ namespace SourceGit.ViewModels public void Save() { - if (_isLoading) + if (_isLoading || _isReadonly) return; var file = Path.Combine(Native.OS.DataDir, "preference.json"); @@ -632,13 +631,13 @@ namespace SourceGit.ViewModels private static Preferences _instance = null; private static bool _isLoading = false; + private bool _isReadonly = true; private string _locale = "en_US"; private string _theme = "Default"; private string _themeOverrides = string.Empty; private string _defaultFontFamily = string.Empty; private string _monospaceFontFamily = string.Empty; private bool _onlyUseMonoFontInEditor = false; - private bool _openReposInNewTab = false; private bool _useSystemWindowFrame = false; private double _defaultFontSize = 13; private double _editorFontSize = 13; diff --git a/src/Views/Preferences.axaml b/src/Views/Preferences.axaml index 704757df..702ec20f 100644 --- a/src/Views/Preferences.axaml +++ b/src/Views/Preferences.axaml @@ -46,7 +46,7 @@ - + - - Date: Mon, 14 Apr 2025 22:05:05 +0800 Subject: [PATCH 12/67] fix: update visible staged changes retrieval in WorkingCopy (#1187) * doc: Update translation status and missing keys * fix: update visible staged changes retrieval in WorkingCopy * fix: prevent unintended amend behavior when changing current branch --------- Co-authored-by: github-actions[bot] --- TRANSLATION.md | 48 +++++++++++++++++++++++++++-------- src/ViewModels/Repository.cs | 10 +++++++- src/ViewModels/WorkingCopy.cs | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 7ae5b13f..b4194fd9 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-97.34%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-97.21%25-yellow)
Missing keys in de_DE.axaml @@ -31,10 +31,11 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs +- Text.Preferences.General.OpenReposInNewTab
-### ![es__ES](https://img.shields.io/badge/es__ES-98.67%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-98.54%25-yellow)
Missing keys in es_ES.axaml @@ -49,10 +50,11 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs +- Text.Preferences.General.OpenReposInNewTab
-### ![fr__FR](https://img.shields.io/badge/fr__FR-98.67%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-98.54%25-yellow)
Missing keys in fr_FR.axaml @@ -67,10 +69,11 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs +- Text.Preferences.General.OpenReposInNewTab
-### ![it__IT](https://img.shields.io/badge/it__IT-98.41%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-98.28%25-yellow)
Missing keys in it_IT.axaml @@ -87,10 +90,11 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs +- Text.Preferences.General.OpenReposInNewTab
-### ![ja__JP](https://img.shields.io/badge/ja__JP-98.41%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-98.28%25-yellow)
Missing keys in ja_JP.axaml @@ -107,10 +111,11 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs +- Text.Preferences.General.OpenReposInNewTab
-### ![pt__BR](https://img.shields.io/badge/pt__BR-89.77%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-89.66%25-yellow)
Missing keys in pt_BR.axaml @@ -192,12 +197,20 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs - Text.WorkingCopy.SignOff +- Text.Preferences.General.OpenReposInNewTab
-### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.87%25-yellow) -### ![ta__IN](https://img.shields.io/badge/ta__IN-98.67%25-yellow) +
+Missing keys in ru_RU.axaml + +- Text.Preferences.General.OpenReposInNewTab + +
+ +### ![ta__IN](https://img.shields.io/badge/ta__IN-98.54%25-yellow)
Missing keys in ta_IN.axaml @@ -212,9 +225,24 @@ This document shows the translation status of each locale file in the repository - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine - Text.WorkingCopy.Conflicts.UseTheirs +- Text.Preferences.General.OpenReposInNewTab
-### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen) +### ![zh__CN](https://img.shields.io/badge/zh__CN-99.87%25-yellow) -### ![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen) \ No newline at end of file +
+Missing keys in zh_CN.axaml + +- Text.Preferences.General.OpenReposInNewTab + +
+ +### ![zh__TW](https://img.shields.io/badge/zh__TW-99.87%25-yellow) + +
+Missing keys in zh_TW.axaml + +- Text.Preferences.General.OpenReposInNewTab + +
\ No newline at end of file diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 9b720c7b..97d47a77 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -162,7 +162,15 @@ namespace SourceGit.ViewModels public Models.Branch CurrentBranch { get => _currentBranch; - private set => SetProperty(ref _currentBranch, value); + private set + { + var oldHead = _currentBranch?.Head; + if (SetProperty(ref _currentBranch, value)) + { + if (oldHead != _currentBranch.Head && _workingCopy is { UseAmend: true }) + _workingCopy.UseAmend = false; + } + } } public List LocalBranchTrees diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 802c6c5d..3d7b9a28 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -94,6 +94,7 @@ namespace SourceGit.ViewModels } Staged = GetStagedChanges(); + VisibleStaged = GetVisibleChanges(_staged); SelectedStaged = []; } } From 1e0fd63543607b07664eb5083f6368ab804479e8 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Mon, 14 Apr 2025 22:07:24 +0800 Subject: [PATCH 13/67] localization: add translation sorting and formatting (#1186) * doc: Update translation status and missing keys * localization: add translation sorting and formatting --------- Co-authored-by: github-actions[bot] --- .github/workflows/localization-check.yml | 5 ++-- build/scripts/localization-check.js | 34 +++++++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/.github/workflows/localization-check.yml b/.github/workflows/localization-check.yml index cc5201ab..8dcd61c8 100644 --- a/.github/workflows/localization-check.yml +++ b/.github/workflows/localization-check.yml @@ -4,7 +4,6 @@ on: branches: [ develop ] paths: - 'src/Resources/Locales/**' - - 'README.md' workflow_dispatch: workflow_call: @@ -32,8 +31,8 @@ jobs: git config --global user.name 'github-actions[bot]' git config --global user.email 'github-actions[bot]@users.noreply.github.com' if [ -n "$(git status --porcelain)" ]; then - git add README.md TRANSLATION.md - git commit -m 'doc: Update translation status and missing keys' + git add TRANSLATION.md src/Resources/Locales/*.axaml + git commit -m 'doc: Update translation status and sort locale files' git push else echo "No changes to commit" diff --git a/build/scripts/localization-check.js b/build/scripts/localization-check.js index 1e8f1f0d..fc27fd1b 100644 --- a/build/scripts/localization-check.js +++ b/build/scripts/localization-check.js @@ -14,6 +14,22 @@ async function parseXml(filePath) { return parser.parseStringPromise(data); } +async function filterAndSortTranslations(localeData, enUSKeys, enUSData) { + const strings = localeData.ResourceDictionary['x:String']; + // Remove keys that don't exist in English file + const filtered = strings.filter(item => enUSKeys.has(item.$['x:Key'])); + + // Sort based on the key order in English file + const enUSKeysArray = enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']); + filtered.sort((a, b) => { + const aIndex = enUSKeysArray.indexOf(a.$['x:Key']); + const bIndex = enUSKeysArray.indexOf(b.$['x:Key']); + return aIndex - bIndex; + }); + + return filtered; +} + async function calculateTranslationRate() { const enUSData = await parseXml(enUSFile); const enUSKeys = new Set(enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key'])); @@ -33,6 +49,22 @@ async function calculateTranslationRate() { const localeKeys = new Set(localeData.ResourceDictionary['x:String'].map(item => item.$['x:Key'])); const missingKeys = [...enUSKeys].filter(key => !localeKeys.has(key)); + // Sort and clean up extra translations + const sortedAndCleaned = await filterAndSortTranslations(localeData, enUSKeys, enUSData); + localeData.ResourceDictionary['x:String'] = sortedAndCleaned; + + // Save the updated file + const builder = new xml2js.Builder({ + headless: true, + renderOpts: { pretty: true, indent: ' ' } + }); + let xmlStr = builder.buildObject(localeData); + + // Add an empty line before the first x:String + xmlStr = xmlStr.replace(' 0) { const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100; const badgeColor = progress >= 75 ? 'yellow' : 'red'; @@ -41,7 +73,7 @@ async function calculateTranslationRate() { lines.push(`
\nMissing keys in ${file}\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n
`) } else { lines.push(`### ![${locale}](https://img.shields.io/badge/${locale}-%E2%88%9A-brightgreen)`); - } + } } const content = lines.join('\n\n'); From e5dc211c35cb2a0d72a0d8910dee1c2dd06e9df6 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 22:24:48 +0800 Subject: [PATCH 14/67] refactor: simpfy IPC code Signed-off-by: leo --- src/Models/IpcChannel.cs | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs index e2a34b29..9a9e0315 100644 --- a/src/Models/IpcChannel.cs +++ b/src/Models/IpcChannel.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.IO.Pipes; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -41,7 +40,7 @@ namespace SourceGit.Models { using (var writer = new StreamWriter(client)) { - writer.Write(Encoding.UTF8.GetBytes(cmd)); + writer.WriteLine(cmd); writer.Flush(); } } @@ -55,34 +54,22 @@ namespace SourceGit.Models public void Dispose() { - _server?.Close(); + _cancellationTokenSource?.Cancel(); } private async void StartServer() { - var buffer = new byte[1024]; + using var reader = new StreamReader(_server); - while (true) + while (!_cancellationTokenSource.IsCancellationRequested) { try { await _server.WaitForConnectionAsync(_cancellationTokenSource.Token); - - using (var stream = new MemoryStream()) - { - while (true) - { - var readed = await _server.ReadAsync(buffer.AsMemory(0, 1024), _cancellationTokenSource.Token); - if (readed == 0) - break; - - stream.Write(buffer, 0, readed); - } - - stream.Seek(0, SeekOrigin.Begin); - MessageReceived?.Invoke(Encoding.UTF8.GetString(stream.ToArray()).Trim()); - _server.Disconnect(); - } + + var line = (await reader.ReadLineAsync(_cancellationTokenSource.Token))?.Trim(); + MessageReceived?.Invoke(line); + _server.Disconnect(); } catch { From 05982e6dc0df4784c8c3863b6b08c45eb1f87fc2 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 14 Apr 2025 23:23:40 +0800 Subject: [PATCH 15/67] style: re-design style for disabled primary button Signed-off-by: leo --- src/Resources/Styles.axaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index 38321356..391b9523 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -499,6 +499,12 @@ + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs new file mode 100644 index 00000000..624ff21e --- /dev/null +++ b/src/Views/ViewLogs.axaml.cs @@ -0,0 +1,108 @@ +using System; +using System.ComponentModel; + +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Interactivity; + +using AvaloniaEdit; +using AvaloniaEdit.Document; +using AvaloniaEdit.Editing; +using AvaloniaEdit.TextMate; + +namespace SourceGit.Views +{ + public class LogContentPresenter : TextEditor + { + public static readonly StyledProperty LogProperty = + AvaloniaProperty.Register(nameof(Log)); + + public ViewModels.CommandLog Log + { + get => GetValue(LogProperty); + set => SetValue(LogProperty, value); + } + + protected override Type StyleKeyOverride => typeof(TextEditor); + + public LogContentPresenter() : base(new TextArea(), new TextDocument()) + { + IsReadOnly = true; + ShowLineNumbers = false; + WordWrap = false; + HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; + VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + + TextArea.TextView.Margin = new Thickness(4, 0); + TextArea.TextView.Options.EnableHyperlinks = true; + TextArea.TextView.Options.EnableEmailHyperlinks = true; + } + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + + if (_textMate == null) + { + _textMate = Models.TextMateHelper.CreateForEditor(this); + Models.TextMateHelper.SetGrammarByFileName(_textMate, "Log.log"); + } + } + + protected override void OnUnloaded(RoutedEventArgs e) + { + base.OnUnloaded(e); + + if (_textMate != null) + { + _textMate.Dispose(); + _textMate = null; + } + + GC.Collect(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == LogProperty) + { + if (change.NewValue is ViewModels.CommandLog log) + { + Text = log.Content; + log.Register(OnLogLineReceived); + } + else + { + Text = string.Empty; + } + } + } + + private void OnLogLineReceived(string newline) + { + AppendText("\n"); + AppendText(newline); + } + + private TextMate.Installation _textMate = null; + } + + public partial class ViewLogs : ChromelessWindow + { + public ViewLogs() + { + InitializeComponent(); + } + + private void OnRemoveLog(object sender, RoutedEventArgs e) + { + if (sender is Button { DataContext: ViewModels.CommandLog log } && DataContext is ViewModels.ViewLogs vm) + vm.Logs.Remove(log); + + e.Handled = true; + } + } +} From c23177229836cf9329bb40f9048e2b7a0c8e922d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 05:24:26 +0000 Subject: [PATCH 41/67] doc: Update translation status and sort locale files --- TRANSLATION.md | 36 +++++++++++++++++++++++-------- src/Resources/Locales/zh_CN.axaml | 2 +- src/Resources/Locales/zh_TW.axaml | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index d942a328..e2535903 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-97.21%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-96.96%25-yellow)
Missing keys in de_DE.axaml @@ -26,7 +26,9 @@ This document shows the translation status of each locale file in the repository - Text.Preferences.AI.Streaming - Text.Preferences.Appearance.EditorTabWidth - Text.Preferences.General.ShowTagsInGraph +- Text.Repository.ViewLogs - Text.StashCM.SaveAsPatch +- Text.ViewLogs - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -35,7 +37,7 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-98.54%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-98.28%25-yellow)
Missing keys in es_ES.axaml @@ -46,6 +48,8 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.NoLocalChanges - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges +- Text.Repository.ViewLogs +- Text.ViewLogs - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -54,7 +58,7 @@ This document shows the translation status of each locale file in the repository
-### ![fr__FR](https://img.shields.io/badge/fr__FR-98.54%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-98.28%25-yellow)
Missing keys in fr_FR.axaml @@ -65,6 +69,8 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.NoLocalChanges - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges +- Text.Repository.ViewLogs +- Text.ViewLogs - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -73,7 +79,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-98.28%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-98.02%25-yellow)
Missing keys in it_IT.axaml @@ -86,6 +92,8 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.WithLocalChanges - Text.CopyFullPath - Text.Preferences.General.ShowTagsInGraph +- Text.Repository.ViewLogs +- Text.ViewLogs - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -94,7 +102,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-98.28%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-98.02%25-yellow)
Missing keys in ja_JP.axaml @@ -107,6 +115,8 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.WithLocalChanges - Text.Repository.FilterCommits - Text.Repository.Tags.OrderByNameDes +- Text.Repository.ViewLogs +- Text.ViewLogs - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -115,7 +125,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-89.66%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-89.42%25-yellow)
Missing keys in pt_BR.axaml @@ -183,6 +193,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.Tags.OrderByNameDes - Text.Repository.Tags.Sort - Text.Repository.UseRelativeTimeInHistories +- Text.Repository.ViewLogs - Text.SetUpstream - Text.SetUpstream.Local - Text.SetUpstream.Unset @@ -191,6 +202,7 @@ This document shows the translation status of each locale file in the repository - Text.Stash.AutoRestore - Text.Stash.AutoRestore.Tip - Text.StashCM.SaveAsPatch +- Text.ViewLogs - Text.WorkingCopy.CommitToEdit - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool @@ -201,16 +213,18 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.87%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.60%25-yellow)
Missing keys in ru_RU.axaml - Text.CommitMessageTextBox.SubjectCount +- Text.Repository.ViewLogs +- Text.ViewLogs
-### ![ta__IN](https://img.shields.io/badge/ta__IN-98.54%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-98.28%25-yellow)
Missing keys in ta_IN.axaml @@ -221,7 +235,9 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.NoLocalChanges - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges +- Text.Repository.ViewLogs - Text.UpdateSubmodules.Target +- Text.ViewLogs - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine @@ -229,13 +245,15 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-99.73%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-99.47%25-yellow)
Missing keys in uk_UA.axaml - Text.CommitMessageTextBox.SubjectCount - Text.ConfigureWorkspace.Name +- Text.Repository.ViewLogs +- Text.ViewLogs
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index a4d33601..cb99d6f0 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -759,4 +759,4 @@ 锁定工作树 移除工作树 解除工作树锁定 - + \ No newline at end of file diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 581f25f2..2fa67983 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -759,4 +759,4 @@ 鎖定工作區 移除工作區 解除鎖定工作區 - + \ No newline at end of file From 0e967ffc8e28a361d3bc4a48a1f72e38a58897c7 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 13:30:25 +0800 Subject: [PATCH 42/67] fix: pressing `Alt+Enter` to commit and push in a repository that has no remotes will crash (#1205) Signed-off-by: leo --- src/ViewModels/WorkingCopy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 60b8fd11..10544970 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1735,7 +1735,7 @@ namespace SourceGit.ViewModels CommitMessage = string.Empty; UseAmend = false; - if (autoPush) + if (autoPush && _repo.Remotes.Count > 0) _repo.ShowAndStartPopup(new Push(_repo, null)); } From 33ae6a998959bc63aa8796f10bdd4c705e7c021b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20J=2E=20Mart=C3=ADnez=20M=2E?= <56406225+jjesus-dev@users.noreply.github.com> Date: Wed, 16 Apr 2025 23:34:27 -0600 Subject: [PATCH 43/67] localization: update spanish translations (#1206) add missing translations modify instances of `stagear` with `hacer stage` --- src/Resources/Locales/es_ES.axaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index d4d442b0..ff6d02f7 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -136,6 +136,7 @@ SHA Abrir en Navegador Descripción + ASUNTO Introducir asunto del commit Configurar Repositorio PLANTILLA DE COMMIT @@ -157,6 +158,7 @@ Fetch remotos automáticamente Minuto(s) Remoto por Defecto + Modo preferido de Merge SEGUIMIENTO DE INCIDENCIAS Añadir Regla de Ejemplo para Azure DevOps Añadir Regla de Ejemplo para Incidencias de Gitee @@ -181,6 +183,10 @@ Color Nombre Restaurar pestañas al iniciar + CONTINUAR + ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)? + HACER STAGE A TODO & COMMIT + ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty) o hacer stage a todo y después commit? Asistente de Commit Convencional Cambio Importante: Incidencia Cerrada: @@ -717,15 +723,20 @@ Ignorar archivos en la misma carpeta Ignorar solo este archivo Enmendar - Puedes stagear este archivo ahora. + Puedes hacer stage a este archivo ahora. COMMIT COMMIT & PUSH Plantilla/Historias Activar evento de clic Commit (Editar) - Stagear todos los cambios y commit + Hacer stage a todos los cambios y commit + Tienes {0} archivo(s) en stage, pero solo {1} archivo(s) mostrado(s) ({2} archivo(s) están filtrados). ¿Quieres continuar? CONFLICTOS DETECTADOS + ABRIR HERRAMIENTA DE MERGE EXTERNA + ABRIR TODOS LOS CONFLICTOS EN HERRAMIENTA DE MERGE EXTERNA LOS CONFLICTOS DE ARCHIVOS ESTÁN RESUELTOS + USAR MÍOS + USAR SUYOS INCLUIR ARCHIVOS NO RASTREADOS NO HAY MENSAJES DE ENTRADA RECIENTES NO HAY PLANTILLAS DE COMMIT From 2a43efde07864bdfac359757cfcf1d17fe3f3e9d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 05:34:40 +0000 Subject: [PATCH 44/67] doc: Update translation status and sort locale files --- TRANSLATION.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index e2535903..62fe960f 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -37,24 +37,13 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-98.28%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.74%25-yellow)
Missing keys in es_ES.axaml -- Text.CommitMessageTextBox.SubjectCount -- Text.Configure.Git.PreferredMergeMode -- Text.ConfirmEmptyCommit.Continue -- Text.ConfirmEmptyCommit.NoLocalChanges -- Text.ConfirmEmptyCommit.StageAllThenCommit -- Text.ConfirmEmptyCommit.WithLocalChanges - Text.Repository.ViewLogs - Text.ViewLogs -- Text.WorkingCopy.ConfirmCommitWithFilter -- Text.WorkingCopy.Conflicts.OpenExternalMergeTool -- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts -- Text.WorkingCopy.Conflicts.UseMine -- Text.WorkingCopy.Conflicts.UseTheirs
From c1e31ac4e3a1a7ca062761c50533de65d455e692 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 15:48:02 +0800 Subject: [PATCH 45/67] ci: try to remove zlib1g-dev:arm64 Signed-off-by: leo --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bcb32580..12792cf6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,7 +58,7 @@ jobs: if: ${{ matrix.runtime == 'linux-arm64' }} run: | sudo apt-get update - sudo apt-get install -y llvm gcc-aarch64-linux-gnu zlib1g-dev:arm64 + sudo apt-get install -y llvm gcc-aarch64-linux-gnu - name: Build run: dotnet build -c Release - name: Publish From 021aab84087fd348a56283fda640caa9c89ec054 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 16:07:40 +0800 Subject: [PATCH 46/67] enhance: add a button to clear all git command logs Signed-off-by: leo --- build/scripts/localization-check.js | 3 +-- src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 3 ++- src/Resources/Locales/zh_TW.axaml | 3 ++- src/ViewModels/ViewLogs.cs | 6 ++++++ src/Views/ViewLogs.axaml | 11 ++++++++++- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/build/scripts/localization-check.js b/build/scripts/localization-check.js index fc27fd1b..8d636b5b 100644 --- a/build/scripts/localization-check.js +++ b/build/scripts/localization-check.js @@ -62,8 +62,7 @@ async function calculateTranslationRate() { // Add an empty line before the first x:String xmlStr = xmlStr.replace(' 0) { const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100; diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 5d1bb7e1..1e92ae38 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -699,6 +699,7 @@ Use --remote option URL: Logs + CLEAR ALL Warning Welcome Page Create Group diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index cb99d6f0..0471285f 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -703,6 +703,7 @@ 启用 '--remote' 仓库地址 : 日志列表 + 清空日志 警告 起始页 新建分组 @@ -759,4 +760,4 @@ 锁定工作树 移除工作树 解除工作树锁定 - \ No newline at end of file + diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 2fa67983..edd8cf8c 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -703,6 +703,7 @@ 啟用 [--remote] 選項 存放庫網址: 日誌清單 + 清除所有日誌 警告 起始頁 新增群組 @@ -759,4 +760,4 @@ 鎖定工作區 移除工作區 解除鎖定工作區 - \ No newline at end of file + diff --git a/src/ViewModels/ViewLogs.cs b/src/ViewModels/ViewLogs.cs index 44c819ce..21ab81ab 100644 --- a/src/ViewModels/ViewLogs.cs +++ b/src/ViewModels/ViewLogs.cs @@ -21,6 +21,12 @@ namespace SourceGit.ViewModels _repo = repo; } + public void ClearAll() + { + SelectedLog = null; + Logs.Clear(); + } + private Repository _repo = null; private CommandLog _selectedLog = null; } diff --git a/src/Views/ViewLogs.axaml b/src/Views/ViewLogs.axaml index 8272078d..125caa22 100644 --- a/src/Views/ViewLogs.axaml +++ b/src/Views/ViewLogs.axaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:SourceGit.ViewModels" xmlns:v="using:SourceGit.Views" + xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.ViewLogs" x:DataType="vm:ViewLogs" @@ -13,7 +14,7 @@ Width="800" Height="500" CanResize="False" WindowStartupLocation="CenterOwner"> - + + + +
diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs index 624ff21e..62bf288d 100644 --- a/src/Views/ViewLogs.axaml.cs +++ b/src/Views/ViewLogs.axaml.cs @@ -97,10 +97,33 @@ namespace SourceGit.Views InitializeComponent(); } - private void OnRemoveLog(object sender, RoutedEventArgs e) + private void OnLogContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is Button { DataContext: ViewModels.CommandLog log } && DataContext is ViewModels.ViewLogs vm) + if (sender is not Grid { DataContext: ViewModels.CommandLog log } grid || DataContext is not ViewModels.ViewLogs vm) + return; + + var copy = new MenuItem(); + copy.Header = App.Text("ViewLogs.CopyLog"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); + copy.Click += (_, ev) => + { + App.CopyText(log.Content); + ev.Handled = true; + }; + + var rm = new MenuItem(); + rm.Header = App.Text("ViewLogs.Delete"); + rm.Icon = App.CreateMenuIcon("Icons.Clear"); + rm.Click += (_, ev) => + { vm.Logs.Remove(log); + ev.Handled = true; + }; + + var menu = new ContextMenu(); + menu.Items.Add(copy); + menu.Items.Add(rm); + menu.Open(grid); e.Handled = true; } From a06d1183d76049bd7df1e6136025895dddbe1655 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 08:32:08 +0000 Subject: [PATCH 49/67] doc: Update translation status and sort locale files --- TRANSLATION.md | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 5e316750..4f13d26a 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-96.83%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-96.57%25-yellow)
Missing keys in de_DE.axaml @@ -30,6 +30,8 @@ This document shows the translation status of each locale file in the repository - Text.StashCM.SaveAsPatch - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -38,7 +40,7 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.60%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.34%25-yellow)
Missing keys in es_ES.axaml @@ -46,10 +48,12 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete
-### ![fr__FR](https://img.shields.io/badge/fr__FR-98.15%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-97.89%25-yellow)
Missing keys in fr_FR.axaml @@ -63,6 +67,8 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -71,7 +77,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.89%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-97.63%25-yellow)
Missing keys in it_IT.axaml @@ -87,6 +93,8 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -95,7 +103,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-97.89%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-97.63%25-yellow)
Missing keys in ja_JP.axaml @@ -111,6 +119,8 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -119,7 +129,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-89.30%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-89.06%25-yellow)
Missing keys in pt_BR.axaml @@ -198,6 +208,8 @@ This document shows the translation status of each locale file in the repository - Text.StashCM.SaveAsPatch - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete - Text.WorkingCopy.CommitToEdit - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool @@ -208,7 +220,7 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.47%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.21%25-yellow)
Missing keys in ru_RU.axaml @@ -217,10 +229,12 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete
-### ![ta__IN](https://img.shields.io/badge/ta__IN-98.15%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-97.89%25-yellow)
Missing keys in ta_IN.axaml @@ -235,6 +249,8 @@ This document shows the translation status of each locale file in the repository - Text.UpdateSubmodules.Target - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine @@ -242,7 +258,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-99.34%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-99.08%25-yellow)
Missing keys in uk_UA.axaml @@ -252,6 +268,8 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear +- Text.ViewLogs.CopyLog +- Text.ViewLogs.Delete
From 104a3f0bbf762063cadb7d97119f0e50139243db Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 16:35:18 +0800 Subject: [PATCH 50/67] code_style: run `dotnet format` Signed-off-by: leo --- src/Commands/QueryLocalChanges.cs | 226 +++++++++++++++--------------- src/ViewModels/CommandLog.cs | 2 +- src/Views/TextDiffView.axaml.cs | 2 +- src/Views/ViewLogs.axaml.cs | 1 - 4 files changed, 115 insertions(+), 116 deletions(-) diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs index e85e79c9..4e626a79 100644 --- a/src/Commands/QueryLocalChanges.cs +++ b/src/Commands/QueryLocalChanges.cs @@ -36,119 +36,119 @@ namespace SourceGit.Commands switch (status) { - case " M": - change.Set(Models.ChangeState.None, Models.ChangeState.Modified); - break; - case " T": - change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged); - break; - case " A": - change.Set(Models.ChangeState.None, Models.ChangeState.Added); - break; - case " D": - change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); - break; - case " R": - change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); - break; - case " C": - change.Set(Models.ChangeState.None, Models.ChangeState.Copied); - break; - case "M": - change.Set(Models.ChangeState.Modified); - break; - case "MM": - change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); - break; - case "MT": - change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged); - break; - case "MD": - change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); - break; - case "T": - change.Set(Models.ChangeState.TypeChanged); - break; - case "TM": - change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified); - break; - case "TT": - change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged); - break; - case "TD": - change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted); - break; - case "A": - change.Set(Models.ChangeState.Added); - break; - case "AM": - change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); - break; - case "AT": - change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged); - break; - case "AD": - change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); - break; - case "D": - change.Set(Models.ChangeState.Deleted); - break; - case "R": - change.Set(Models.ChangeState.Renamed); - break; - case "RM": - change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); - break; - case "RT": - change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged); - break; - case "RD": - change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); - break; - case "C": - change.Set(Models.ChangeState.Copied); - break; - case "CM": - change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); - break; - case "CT": - change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged); - break; - case "CD": - change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); - break; - case "DR": - change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); - break; - case "DC": - change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); - break; - case "DD": - change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); - break; - case "AU": - change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); - break; - case "UD": - change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); - break; - case "UA": - change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); - break; - case "DU": - change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); - break; - case "AA": - change.Set(Models.ChangeState.Added, Models.ChangeState.Added); - break; - case "UU": - change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); - break; - case "??": - change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); - break; - default: - break; + case " M": + change.Set(Models.ChangeState.None, Models.ChangeState.Modified); + break; + case " T": + change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged); + break; + case " A": + change.Set(Models.ChangeState.None, Models.ChangeState.Added); + break; + case " D": + change.Set(Models.ChangeState.None, Models.ChangeState.Deleted); + break; + case " R": + change.Set(Models.ChangeState.None, Models.ChangeState.Renamed); + break; + case " C": + change.Set(Models.ChangeState.None, Models.ChangeState.Copied); + break; + case "M": + change.Set(Models.ChangeState.Modified); + break; + case "MM": + change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); + break; + case "MT": + change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged); + break; + case "MD": + change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); + break; + case "T": + change.Set(Models.ChangeState.TypeChanged); + break; + case "TM": + change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified); + break; + case "TT": + change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged); + break; + case "TD": + change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted); + break; + case "A": + change.Set(Models.ChangeState.Added); + break; + case "AM": + change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); + break; + case "AT": + change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged); + break; + case "AD": + change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); + break; + case "D": + change.Set(Models.ChangeState.Deleted); + break; + case "R": + change.Set(Models.ChangeState.Renamed); + break; + case "RM": + change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); + break; + case "RT": + change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged); + break; + case "RD": + change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); + break; + case "C": + change.Set(Models.ChangeState.Copied); + break; + case "CM": + change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); + break; + case "CT": + change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged); + break; + case "CD": + change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted); + break; + case "DR": + change.Set(Models.ChangeState.Deleted, Models.ChangeState.Renamed); + break; + case "DC": + change.Set(Models.ChangeState.Deleted, Models.ChangeState.Copied); + break; + case "DD": + change.Set(Models.ChangeState.Deleted, Models.ChangeState.Deleted); + break; + case "AU": + change.Set(Models.ChangeState.Added, Models.ChangeState.Unmerged); + break; + case "UD": + change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Deleted); + break; + case "UA": + change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Added); + break; + case "DU": + change.Set(Models.ChangeState.Deleted, Models.ChangeState.Unmerged); + break; + case "AA": + change.Set(Models.ChangeState.Added, Models.ChangeState.Added); + break; + case "UU": + change.Set(Models.ChangeState.Unmerged, Models.ChangeState.Unmerged); + break; + case "??": + change.Set(Models.ChangeState.Untracked, Models.ChangeState.Untracked); + break; + default: + break; } if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None) diff --git a/src/ViewModels/CommandLog.cs b/src/ViewModels/CommandLog.cs index e10aa724..a677d0be 100644 --- a/src/ViewModels/CommandLog.cs +++ b/src/ViewModels/CommandLog.cs @@ -82,6 +82,6 @@ namespace SourceGit.ViewModels private string _content = string.Empty; private StringBuilder _builder = new StringBuilder(); - private event Action _onNewLineReceived; + private event Action _onNewLineReceived; } } diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 722d6912..ad2f8cea 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1261,7 +1261,7 @@ namespace SourceGit.Views if (line.NoNewLineEndOfFile) builder.Append("\u26D4"); - + builder.Append('\n'); } diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs index 62bf288d..107341ab 100644 --- a/src/Views/ViewLogs.axaml.cs +++ b/src/Views/ViewLogs.axaml.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using Avalonia; using Avalonia.Controls; From 3358ff9aee18918c67cdbf3fb7055ccb43b9fd35 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 17:24:56 +0800 Subject: [PATCH 51/67] enhance: disable hyper link and email link in git command logs Signed-off-by: leo --- src/Views/ViewLogs.axaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs index 107341ab..dcfc3dc9 100644 --- a/src/Views/ViewLogs.axaml.cs +++ b/src/Views/ViewLogs.axaml.cs @@ -34,8 +34,8 @@ namespace SourceGit.Views VerticalScrollBarVisibility = ScrollBarVisibility.Auto; TextArea.TextView.Margin = new Thickness(4, 0); - TextArea.TextView.Options.EnableHyperlinks = true; - TextArea.TextView.Options.EnableEmailHyperlinks = true; + TextArea.TextView.Options.EnableHyperlinks = false; + TextArea.TextView.Options.EnableEmailHyperlinks = false; } protected override void OnLoaded(RoutedEventArgs e) From 231010abc666c1d3e0bb2cc36e0da4cf207b633d Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 17:45:49 +0800 Subject: [PATCH 52/67] ux: custom style for command line in git command log Signed-off-by: leo --- src/Views/ViewLogs.axaml.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs index dcfc3dc9..8a3426d2 100644 --- a/src/Views/ViewLogs.axaml.cs +++ b/src/Views/ViewLogs.axaml.cs @@ -4,16 +4,39 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Interactivity; +using Avalonia.Media; using AvaloniaEdit; using AvaloniaEdit.Document; using AvaloniaEdit.Editing; +using AvaloniaEdit.Rendering; using AvaloniaEdit.TextMate; namespace SourceGit.Views { public class LogContentPresenter : TextEditor { + public class LineStyleTransformer : DocumentColorizingTransformer + { + protected override void ColorizeLine(DocumentLine line) + { + var content = CurrentContext.Document.GetText(line); + if (content.StartsWith("$ git ", StringComparison.Ordinal)) + { + ChangeLinePart(line.Offset, line.Offset + 1, v => + { + v.TextRunProperties.SetForegroundBrush(Brushes.Orange); + }); + + ChangeLinePart(line.Offset + 2, line.EndOffset, v => + { + var old = v.TextRunProperties.Typeface; + v.TextRunProperties.SetTypeface(new Typeface(old.FontFamily, old.Style, FontWeight.Bold)); + }); + } + } + } + public static readonly StyledProperty LogProperty = AvaloniaProperty.Register(nameof(Log)); @@ -46,6 +69,7 @@ namespace SourceGit.Views { _textMate = Models.TextMateHelper.CreateForEditor(this); Models.TextMateHelper.SetGrammarByFileName(_textMate, "Log.log"); + TextArea.TextView.LineTransformers.Add(new LineStyleTransformer()); } } From 090b64d68dcfdc19d1b05366f9b9b96e6027dc1e Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 18:21:55 +0800 Subject: [PATCH 53/67] refactor: notification popup uses the same text presenter with git command log viewer (#1149) Signed-off-by: leo --- src/Views/CommandLogContentPresenter.cs | 152 ++++++++++++++++++++++++ src/Views/LauncherPage.axaml | 8 +- src/Views/ViewLogs.axaml | 4 +- src/Views/ViewLogs.axaml.cs | 111 ----------------- 4 files changed, 159 insertions(+), 116 deletions(-) create mode 100644 src/Views/CommandLogContentPresenter.cs diff --git a/src/Views/CommandLogContentPresenter.cs b/src/Views/CommandLogContentPresenter.cs new file mode 100644 index 00000000..a2499f8d --- /dev/null +++ b/src/Views/CommandLogContentPresenter.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; + +using Avalonia; +using Avalonia.Controls.Primitives; +using Avalonia.Interactivity; +using Avalonia.Media; + +using AvaloniaEdit; +using AvaloniaEdit.Document; +using AvaloniaEdit.Editing; +using AvaloniaEdit.Rendering; +using AvaloniaEdit.TextMate; + +namespace SourceGit.Views +{ + public class CommandLogContentPresenter : TextEditor + { + public class LineStyleTransformer : DocumentColorizingTransformer + { + protected override void ColorizeLine(DocumentLine line) + { + var content = CurrentContext.Document.GetText(line); + if (content.StartsWith("$ git ", StringComparison.Ordinal)) + { + ChangeLinePart(line.Offset, line.Offset + 1, v => + { + v.TextRunProperties.SetForegroundBrush(Brushes.Orange); + }); + + ChangeLinePart(line.Offset + 2, line.EndOffset, v => + { + var old = v.TextRunProperties.Typeface; + v.TextRunProperties.SetTypeface(new Typeface(old.FontFamily, old.Style, FontWeight.Bold)); + }); + } + else if (content.StartsWith("remote: ", StringComparison.Ordinal)) + { + ChangeLinePart(line.Offset, line.Offset + 7, v => + { + v.TextRunProperties.SetForegroundBrush(Brushes.SeaGreen); + }); + } + else + { + foreach (var err in _errors) + { + var idx = content.IndexOf(err, StringComparison.Ordinal); + if (idx >= 0) + { + ChangeLinePart(line.Offset + idx, line.Offset + err.Length + 1, v => + { + v.TextRunProperties.SetForegroundBrush(Brushes.Red); + }); + } + } + } + } + + private readonly List _errors = ["! [rejected]", "! [remote rejected]"]; + } + + public static readonly StyledProperty LogProperty = + AvaloniaProperty.Register(nameof(Log)); + + public ViewModels.CommandLog Log + { + get => GetValue(LogProperty); + set => SetValue(LogProperty, value); + } + + public static readonly StyledProperty PureTextProperty = + AvaloniaProperty.Register(nameof(PureText)); + + public string PureText + { + get => GetValue(PureTextProperty); + set => SetValue(PureTextProperty, value); + } + + protected override Type StyleKeyOverride => typeof(TextEditor); + + public CommandLogContentPresenter() : base(new TextArea(), new TextDocument()) + { + IsReadOnly = true; + ShowLineNumbers = false; + WordWrap = false; + HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; + VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + + TextArea.TextView.Margin = new Thickness(4, 0); + TextArea.TextView.Options.EnableHyperlinks = false; + TextArea.TextView.Options.EnableEmailHyperlinks = false; + } + + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + + if (_textMate == null) + { + _textMate = Models.TextMateHelper.CreateForEditor(this); + Models.TextMateHelper.SetGrammarByFileName(_textMate, "Log.log"); + TextArea.TextView.LineTransformers.Add(new LineStyleTransformer()); + } + } + + protected override void OnUnloaded(RoutedEventArgs e) + { + base.OnUnloaded(e); + + if (_textMate != null) + { + _textMate.Dispose(); + _textMate = null; + } + + GC.Collect(); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == LogProperty) + { + if (change.NewValue is ViewModels.CommandLog log) + { + Text = log.Content; + log.Register(OnLogLineReceived); + } + else + { + Text = string.Empty; + } + } + else if (change.Property == PureTextProperty) + { + if (!string.IsNullOrEmpty(PureText)) + Text = PureText; + } + } + + private void OnLogLineReceived(string newline) + { + AppendText("\n"); + AppendText(newline); + } + + private TextMate.Installation _textMate = null; + } +} diff --git a/src/Views/LauncherPage.axaml b/src/Views/LauncherPage.axaml index 7ce450de..46fb97f6 100644 --- a/src/Views/LauncherPage.axaml +++ b/src/Views/LauncherPage.axaml @@ -141,9 +141,11 @@ - - - + diff --git a/src/Views/ViewLogs.axaml b/src/Views/ViewLogs.axaml index 9c1ae435..c4aa46f7 100644 --- a/src/Views/ViewLogs.axaml +++ b/src/Views/ViewLogs.axaml @@ -100,8 +100,8 @@ BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}"> - + diff --git a/src/Views/ViewLogs.axaml.cs b/src/Views/ViewLogs.axaml.cs index 8a3426d2..f0a27884 100644 --- a/src/Views/ViewLogs.axaml.cs +++ b/src/Views/ViewLogs.axaml.cs @@ -1,118 +1,7 @@ -using System; - -using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Interactivity; -using Avalonia.Media; - -using AvaloniaEdit; -using AvaloniaEdit.Document; -using AvaloniaEdit.Editing; -using AvaloniaEdit.Rendering; -using AvaloniaEdit.TextMate; namespace SourceGit.Views { - public class LogContentPresenter : TextEditor - { - public class LineStyleTransformer : DocumentColorizingTransformer - { - protected override void ColorizeLine(DocumentLine line) - { - var content = CurrentContext.Document.GetText(line); - if (content.StartsWith("$ git ", StringComparison.Ordinal)) - { - ChangeLinePart(line.Offset, line.Offset + 1, v => - { - v.TextRunProperties.SetForegroundBrush(Brushes.Orange); - }); - - ChangeLinePart(line.Offset + 2, line.EndOffset, v => - { - var old = v.TextRunProperties.Typeface; - v.TextRunProperties.SetTypeface(new Typeface(old.FontFamily, old.Style, FontWeight.Bold)); - }); - } - } - } - - public static readonly StyledProperty LogProperty = - AvaloniaProperty.Register(nameof(Log)); - - public ViewModels.CommandLog Log - { - get => GetValue(LogProperty); - set => SetValue(LogProperty, value); - } - - protected override Type StyleKeyOverride => typeof(TextEditor); - - public LogContentPresenter() : base(new TextArea(), new TextDocument()) - { - IsReadOnly = true; - ShowLineNumbers = false; - WordWrap = false; - HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; - VerticalScrollBarVisibility = ScrollBarVisibility.Auto; - - TextArea.TextView.Margin = new Thickness(4, 0); - TextArea.TextView.Options.EnableHyperlinks = false; - TextArea.TextView.Options.EnableEmailHyperlinks = false; - } - - protected override void OnLoaded(RoutedEventArgs e) - { - base.OnLoaded(e); - - if (_textMate == null) - { - _textMate = Models.TextMateHelper.CreateForEditor(this); - Models.TextMateHelper.SetGrammarByFileName(_textMate, "Log.log"); - TextArea.TextView.LineTransformers.Add(new LineStyleTransformer()); - } - } - - protected override void OnUnloaded(RoutedEventArgs e) - { - base.OnUnloaded(e); - - if (_textMate != null) - { - _textMate.Dispose(); - _textMate = null; - } - - GC.Collect(); - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == LogProperty) - { - if (change.NewValue is ViewModels.CommandLog log) - { - Text = log.Content; - log.Register(OnLogLineReceived); - } - else - { - Text = string.Empty; - } - } - } - - private void OnLogLineReceived(string newline) - { - AppendText("\n"); - AppendText(newline); - } - - private TextMate.Installation _textMate = null; - } - public partial class ViewLogs : ChromelessWindow { public ViewLogs() From 4c1a04477e69c2dfa146cc0fd32db822632c6461 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 20:03:46 +0800 Subject: [PATCH 54/67] refactor: enhanced copy commit information context menu (#1209) Signed-off-by: leo --- src/Resources/Icons.axaml | 3 ++ src/Resources/Locales/de_DE.axaml | 4 +-- src/Resources/Locales/en_US.axaml | 7 ++-- src/Resources/Locales/es_ES.axaml | 4 +-- src/Resources/Locales/fr_FR.axaml | 4 +-- src/Resources/Locales/it_IT.axaml | 4 +-- src/Resources/Locales/ja_JP.axaml | 4 +-- src/Resources/Locales/pt_BR.axaml | 4 +-- src/Resources/Locales/ru_RU.axaml | 4 +-- src/Resources/Locales/ta_IN.axaml | 4 +-- src/Resources/Locales/uk_UA.axaml | 4 +-- src/Resources/Locales/zh_CN.axaml | 7 ++-- src/Resources/Locales/zh_TW.axaml | 7 ++-- src/ViewModels/Histories.cs | 56 ++++++++++++++++++++++++++----- 14 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml index a966d47d..51e3d8bf 100644 --- a/src/Resources/Icons.axaml +++ b/src/Resources/Icons.axaml @@ -46,6 +46,7 @@ M416 832H128V128h384v192C512 355 541 384 576 384L768 384v32c0 19 13 32 32 32S832 435 832 416v-64c0-6 0-19-6-25l-256-256c-6-6-19-6-25-6H128A64 64 0 0064 128v704C64 867 93 896 129 896h288c19 0 32-13 32-32S435 832 416 832zM576 172 722 320H576V172zM736 512C614 512 512 614 512 736S614 960 736 960s224-102 224-224S858 512 736 512zM576 736C576 646 646 576 736 576c32 0 58 6 83 26l-218 218c-19-26-26-51-26-83zm160 160c-32 0-64-13-96-32l224-224c19 26 32 58 32 96 0 90-70 160-160 160z M896 320c0-19-6-32-19-45l-192-192c-13-13-26-19-45-19H192c-38 0-64 26-64 64v768c0 38 26 64 64 64h640c38 0 64-26 64-64V320zm-256 384H384c-19 0-32-13-32-32s13-32 32-32h256c19 0 32 13 32 32s-13 32-32 32zm166-384H640V128l192 192h-26z M599 425 599 657 425 832 425 425 192 192 832 192Z + M505 74c-145 3-239 68-239 68-12 8-15 25-7 37 9 13 25 15 38 6 0 0 184-136 448 2 12 7 29 3 36-10 8-13 3-29-12-37-71-38-139-56-199-63-23-3-44-3-65-3m17 111c-254-3-376 201-376 201-8 12-5 29 7 37 12 8 29 4 39-10 0 0 103-178 329-175 226 3 325 173 325 173 8 12 24 17 37 9 14-8 17-24 9-37 0 0-117-195-370-199m-31 106c-72 5-140 31-192 74C197 449 132 603 204 811c5 14 20 21 34 17 14-5 21-20 16-34-66-191-7-316 79-388 84-69 233-85 343-17 54 34 96 93 118 151 22 58 20 114 3 141-18 28-54 38-86 30-32-8-58-31-59-80-1-73-58-118-118-125-57-7-123 24-140 92-32 125 49 302 238 361 14 4 29-3 34-17 4-14-3-29-18-34-163-51-225-206-202-297 10-41 46-55 84-52 37 4 69 26 69 73 2 70 48 117 100 131 52 13 112-3 144-52 33-50 28-120 3-188-26-68-73-136-140-178a356 356 0 00-213-52m15 104v0c-76 3-152 42-195 125-56 106-31 215 7 293 38 79 90 131 90 131 10 11 27 11 38 0s11-26 0-38c0 0-46-47-79-116s-54-157-8-244c48-90 133-111 208-90 76 22 140 88 138 186-2 15 9 28 24 29 15 1 27-10 29-27 3-122-79-210-176-239a246 246 0 00-75-9m9 213c-15 0-26 13-26 27 0 0 1 63 36 124 36 61 112 119 244 107 15-1 26-13 25-28-1-15-14-26-30-25-116 11-165-33-193-81-28-47-29-98-29-98a27 27 0 00-27-27z m211 611a142 142 0 00-90-4v-190a142 142 0 0090-4v198zm0 262v150h-90v-146a142 142 0 0090-4zm0-723a142 142 0 00-90-4v-146h90zm-51 246a115 115 0 11115-115 115 115 0 01-115 115zm0 461a115 115 0 11115-115 115 115 0 01-115 115zm256-691h563v90h-563zm0 461h563v90h-563zm0-282h422v90h-422zm0 474h422v90h-422z 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 M1088 227H609L453 78a11 11 0 00-7-3H107a43 43 0 00-43 43v789a43 43 0 0043 43h981a43 43 0 0043-43V270a43 43 0 00-43-43zM757 599c0 5-5 9-10 9h-113v113c0 5-4 9-9 9h-56c-5 0-9-4-9-9V608h-113c-5 0-10-4-10-9V543c0-5 5-9 10-9h113V420c0-5 4-9 9-9h56c5 0 9 4 9 9V533h113c5 0 10 4 10 9v56z @@ -116,6 +117,7 @@ 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 + M653 435l-26 119H725c9 0 13 4 13 13v47c0 9-4 13-13 13h-107l-21 115c0 9-4 13-13 13h-47c-9 0-13-4-13-13l21-111H427l-21 115c0 9-4 13-13 13H346c-9 0-13-4-13-13l21-107h-85c-4-9-9-21-13-34v-38c0-9 4-13 13-13h98l26-119H294c-9 0-13-4-13-13V375c0-9 4-13 13-13h115l13-81c0-9 4-13 13-13h43c9 0 13 4 13 13L469 363h119l13-81c0-9 4-13 13-13h47c9 0 13 4 13 13l-13 77h85c9 0 13 4 13 13v47c0 9-4 13-13 13h-98v4zM512 0C230 0 0 230 0 512c0 145 60 282 166 375L90 1024H512c282 0 512-230 512-512S794 0 512 0zm-73 559h124l26-119h-128l-21 119z 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 @@ -130,6 +132,7 @@ M762 1024C876 818 895 504 448 514V768L64 384l384-384v248c535-14 595 472 314 776z M832 464H332V240c0-31 25-56 56-56h248c31 0 56 25 56 56v68c0 4 4 8 8 8h56c4 0 8-4 8-8v-68c0-71-57-128-128-128H388c-71 0-128 57-128 128v224h-68c-18 0-32 14-32 32v384c0 18 14 32 32 32h640c18 0 32-14 32-32V496c0-18-14-32-32-32zM540 701v53c0 4-4 8-8 8h-40c-4 0-8-4-8-8v-53c-12-9-20-23-20-39 0-27 22-48 48-48s48 22 48 48c0 16-8 30-20 39z M170 831l343-342L855 831l105-105-448-448L64 726 170 831z + M667 607c-3-2-7-14-0-38 73-77 118-187 118-290C784 115 668 0 508 0 348 0 236 114 236 278c0 104 45 215 119 292 7 24-2 33-8 35C274 631 0 725 0 854L0 1024l1024 0 0-192C989 714 730 627 667 607L667 607z M880 128A722 722 0 01555 13a77 77 0 00-85 0 719 719 0 01-325 115c-40 4-71 38-71 80v369c0 246 329 446 439 446 110 0 439-200 439-446V207c0-41-31-76-71-80zM465 692a36 36 0 01-53 0L305 579a42 42 0 010-57 36 36 0 0153 0l80 85L678 353a36 36 0 0153 0 42 42 0 01-0 57L465 692z M812 864h-29V654c0-21-11-40-28-52l-133-88 134-89c18-12 28-31 28-52V164h28c18 0 32-14 32-32s-14-32-32-32H212c-18 0-32 14-32 32s14 32 32 32h30v210c0 21 11 40 28 52l133 88-134 89c-18 12-28 31-28 52V864H212c-18 0-32 14-32 32s14 32 32 32h600c18 0 32-14 32-32s-14-32-32-32zM441 566c18-12 28-31 28-52s-11-40-28-52L306 373V164h414v209l-136 90c-18 12-28 31-28 52 0 21 11 40 28 52l135 89V695c-9-7-20-13-32-19-30-15-93-41-176-41-63 0-125 14-175 38-12 6-22 12-31 18v-36l136-90z M0 512M1024 512M512 0M512 1024M762 412v100h-500v-100h-150v200h800v-200h-150z diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 3cb70cea..7a3da294 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -102,8 +102,8 @@ Mehrere cherry-picken Mit HEAD vergleichen Mit Worktree vergleichen - Info kopieren - SHA kopieren + Information + SHA Benutzerdefinierte Aktion Interactives Rebase von ${0}$ auf diesen Commit Merge in ${0}$ hinein diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index bd4cfc56..20a70f22 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -99,8 +99,11 @@ Cherry-Pick ... Compare with HEAD Compare with Worktree - Copy Info - Copy SHA + Author + Committer + Information + SHA + Subject Custom Action Interactively Rebase ${0}$ on Here Merge to ${0}$ diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index e316a470..204cfc1a 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -103,8 +103,8 @@ Cherry-Pick ... Comparar con HEAD Comparar con Worktree - Copiar Información - Copiar SHA + Información + SHA Acción personalizada Rebase Interactivo ${0}$ hasta Aquí Merge a ${0}$ diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index fd41b4f0..f45a83d9 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -103,8 +103,8 @@ Cherry-Pick ... Comparer avec HEAD Comparer avec le worktree - Copier les informations - Copier le SHA + Informations + SHA Action personnalisée Rebase interactif de ${0}$ ici Fusionner dans ${0}$ diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index 4498348d..b7d2568a 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -103,8 +103,8 @@ Cherry-Pick... Confronta con HEAD Confronta con Worktree - Copia Info - Copia SHA + Informazioni + SHA Azione Personalizzata Riallinea Interattivamente ${0}$ fino a Qui Unisci a ${0}$ diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index 4b785c3d..c50504e1 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -103,8 +103,8 @@ チェリーピック... HEADと比較 ワークツリーと比較 - 情報をコピー - SHAをコピー + 情報 + SHA カスタムアクション ${0}$ ブランチをここにインタラクティブリベース ${0}$ にマージ diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 299ececd..a4e9d883 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -93,8 +93,8 @@ Cherry-Pick ... Comparar com HEAD Comparar com Worktree - Copiar Informações - Copiar SHA + Informações + SHA Ação customizada Rebase Interativo ${0}$ até Aqui Rebase ${0}$ até Aqui diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index c3e8b87a..b8c86415 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -103,8 +103,8 @@ Применить несколько ревизий ... Сравнить c ГОЛОВОЙ (HEAD) Сравнить с рабочим каталогом - Копировать информацию - Копировать SHA + Информацию + SHA Пользовательское действие Интерактивное перемещение (rebase -i) ${0}$ сюда Влить в ${0}$ diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index c62dd2b5..b4e4d939 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -103,8 +103,8 @@ கனி-பறி ... தலையுடன் ஒப்பிடுக பணிமரத்துடன் ஒப்பிடுக - தகவலை நகலெடு - பாகொவ-வை நகலெடு + தகவலை + பாகொவ-வை தனிப்பயன் செயல் இங்கே ${0}$ ஐ ஊடாடும் வகையில் மறுதளம் ${0}$ இதற்கு ஒன்றிணை diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index 828c36f8..a3b63bde 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -103,8 +103,8 @@ Cherry-pick ... Порівняти з HEAD Порівняти з робочим деревом - Копіювати інформацію - Копіювати SHA + Iнформацію + SHA Спеціальна дія Інтерактивно перебазувати ${0}$ сюди Злиття в ${0}$ diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 7546b3c4..3d41bccd 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -103,8 +103,11 @@ 挑选(cherry-pick)... 与当前HEAD比较 与本地工作树比较 - 复制简要信息 - 复制提交指纹 + 作者 + 提交者 + 简要信息 + 提交指纹 + 主题 自定义操作 交互式变基(rebase -i) ${0}$ 到此处 合并(merge)此提交至 ${0}$ diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 61921ea4..3a10f6ca 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -103,8 +103,11 @@ 揀選 (cherry-pick)... 與目前 HEAD 比較 與本機工作區比較 - 複製摘要資訊 - 複製提交編號 + 作者 + 提交者 + 摘要資訊 + 提交編號 + 標題 自訂動作 互動式重定基底 (rebase -i) ${0}$ 到此處 合併 (merge) 此提交到 ${0}$ diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index b3216a91..ee5e5891 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -330,7 +330,7 @@ namespace SourceGit.ViewModels var copyMultipleSHAs = new MenuItem(); copyMultipleSHAs.Header = App.Text("CommitCM.CopySHA"); - copyMultipleSHAs.Icon = App.CreateMenuIcon("Icons.Copy"); + copyMultipleSHAs.Icon = App.CreateMenuIcon("Icons.Fingerprint"); copyMultipleSHAs.Click += (_, e) => { var builder = new StringBuilder(); @@ -340,11 +340,10 @@ namespace SourceGit.ViewModels App.CopyText(builder.ToString()); e.Handled = true; }; - multipleMenu.Items.Add(copyMultipleSHAs); var copyMultipleInfo = new MenuItem(); copyMultipleInfo.Header = App.Text("CommitCM.CopyInfo"); - copyMultipleInfo.Icon = App.CreateMenuIcon("Icons.Copy"); + copyMultipleInfo.Icon = App.CreateMenuIcon("Icons.Info"); copyMultipleInfo.Click += (_, e) => { var builder = new StringBuilder(); @@ -354,7 +353,13 @@ namespace SourceGit.ViewModels App.CopyText(builder.ToString()); e.Handled = true; }; - multipleMenu.Items.Add(copyMultipleInfo); + + var copyMultiple = new MenuItem(); + copyMultiple.Header = App.Text("Copy"); + copyMultiple.Icon = App.CreateMenuIcon("Icons.Copy"); + copyMultiple.Items.Add(copyMultipleSHAs); + copyMultiple.Items.Add(copyMultipleInfo); + multipleMenu.Items.Add(copyMultiple); return multipleMenu; } @@ -715,23 +720,58 @@ namespace SourceGit.ViewModels var copySHA = new MenuItem(); copySHA.Header = App.Text("CommitCM.CopySHA"); - copySHA.Icon = App.CreateMenuIcon("Icons.Copy"); + copySHA.Icon = App.CreateMenuIcon("Icons.Fingerprint"); copySHA.Click += (_, e) => { App.CopyText(commit.SHA); e.Handled = true; }; - menu.Items.Add(copySHA); + + var copySubject = new MenuItem(); + copySubject.Header = App.Text("CommitCM.CopySubject"); + copySubject.Icon = App.CreateMenuIcon("Icons.Subject"); + copySubject.Click += (_, e) => + { + App.CopyText(commit.Subject); + e.Handled = true; + }; var copyInfo = new MenuItem(); copyInfo.Header = App.Text("CommitCM.CopyInfo"); - copyInfo.Icon = App.CreateMenuIcon("Icons.Copy"); + copyInfo.Icon = App.CreateMenuIcon("Icons.Info"); copyInfo.Click += (_, e) => { App.CopyText($"{commit.SHA.Substring(0, 10)} - {commit.Subject}"); e.Handled = true; }; - menu.Items.Add(copyInfo); + + var copyAuthor = new MenuItem(); + copyAuthor.Header = App.Text("CommitCM.CopyAuthor"); + copyAuthor.Icon = App.CreateMenuIcon("Icons.User"); + copyAuthor.Click += (_, e) => + { + App.CopyText(commit.Author.ToString()); + e.Handled = true; + }; + + var copyCommitter = new MenuItem(); + copyCommitter.Header = App.Text("CommitCM.CopyCommitter"); + copyCommitter.Icon = App.CreateMenuIcon("Icons.User"); + copyCommitter.Click += (_, e) => + { + App.CopyText(commit.Committer.ToString()); + e.Handled = true; + }; + + var copy = new MenuItem(); + copy.Header = App.Text("Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); + copy.Items.Add(copySHA); + copy.Items.Add(copySubject); + copy.Items.Add(copyInfo); + copy.Items.Add(copyAuthor); + copy.Items.Add(copyCommitter); + menu.Items.Add(copy); return menu; } From 5bd7dd428dc0df2616f8a7a8cf21af8c9d65981a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 12:04:02 +0000 Subject: [PATCH 55/67] doc: Update translation status and sort locale files --- TRANSLATION.md | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 4f13d26a..866aac65 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,12 +6,15 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-96.57%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-96.19%25-yellow)
Missing keys in de_DE.axaml - Text.BranchUpstreamInvalid +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.Configure.CustomAction.WaitForExit - Text.Configure.Git.PreferredMergeMode @@ -40,11 +43,14 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.34%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-98.95%25-yellow)
Missing keys in es_ES.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -53,11 +59,14 @@ This document shows the translation status of each locale file in the repository
-### ![fr__FR](https://img.shields.io/badge/fr__FR-97.89%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-97.51%25-yellow)
Missing keys in fr_FR.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.Configure.Git.PreferredMergeMode - Text.ConfirmEmptyCommit.Continue @@ -77,11 +86,14 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.63%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-97.24%25-yellow)
Missing keys in it_IT.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.Configure.Git.PreferredMergeMode - Text.ConfirmEmptyCommit.Continue @@ -103,11 +115,14 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-97.63%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-97.24%25-yellow)
Missing keys in ja_JP.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.Configure.Git.PreferredMergeMode - Text.ConfirmEmptyCommit.Continue @@ -129,7 +144,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-89.06%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-88.71%25-yellow)
Missing keys in pt_BR.axaml @@ -144,6 +159,9 @@ This document shows the translation status of each locale file in the repository - Text.BranchCM.MergeMultiBranches - Text.BranchUpstreamInvalid - Text.Clone.RecurseSubmodules +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitCM.Merge - Text.CommitCM.MergeMultiple - Text.CommitDetail.Files.Search @@ -220,11 +238,14 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.21%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-98.82%25-yellow)
Missing keys in ru_RU.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.Repository.ViewLogs - Text.ViewLogs @@ -234,11 +255,14 @@ This document shows the translation status of each locale file in the repository
-### ![ta__IN](https://img.shields.io/badge/ta__IN-97.89%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-97.51%25-yellow)
Missing keys in ta_IN.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.Configure.Git.PreferredMergeMode - Text.ConfirmEmptyCommit.Continue @@ -258,11 +282,14 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-99.08%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-98.69%25-yellow)
Missing keys in uk_UA.axaml +- Text.CommitCM.CopyAuthor +- Text.CommitCM.CopyCommitter +- Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.ConfigureWorkspace.Name - Text.Repository.ViewLogs From de31d4bad417e50ddea85496fe00da284f04e28f Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 17 Apr 2025 21:17:54 +0800 Subject: [PATCH 56/67] ux: layout of git command log item Signed-off-by: leo --- src/Views/ViewLogs.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/ViewLogs.axaml b/src/Views/ViewLogs.axaml index c4aa46f7..e29a5afd 100644 --- a/src/Views/ViewLogs.axaml +++ b/src/Views/ViewLogs.axaml @@ -75,7 +75,7 @@ Date: Thu, 17 Apr 2025 17:14:52 +0100 Subject: [PATCH 57/67] Fixed tooltip Tooltip for chosing mine was wrong. Was --theirs when should be --ours. (cherry picked from commit 26a471933c21a135e946273d49b9135b401bbd7f) --- src/Views/Conflict.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Views/Conflict.axaml b/src/Views/Conflict.axaml index f2d7bdec..cf2e25a0 100644 --- a/src/Views/Conflict.axaml +++ b/src/Views/Conflict.axaml @@ -111,7 +111,7 @@ -