From 750ca8ec61ad7a4600f9622caa178d92223e4d88 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 21 Apr 2025 14:44:02 +0800 Subject: [PATCH 01/45] refactor: use custom view locator to create new window/dialog (#1216) Signed-off-by: leo (cherry picked from commit 3e6f2b25f15b263e2b84922abc5cf6d621d62a83) --- src/App.Commands.cs | 6 +- src/App.axaml.cs | 38 +++++++++--- src/ViewModels/AIAssistant.cs | 80 +++++++++++++++++++++++++ src/ViewModels/CommitDetail.cs | 12 ++-- src/ViewModels/Histories.cs | 6 +- src/ViewModels/Launcher.cs | 2 +- src/ViewModels/Repository.cs | 16 ++--- src/ViewModels/WorkingCopy.cs | 41 +++---------- src/Views/AIAssistant.axaml | 13 ++-- src/Views/AIAssistant.axaml.cs | 72 ++-------------------- src/Views/CommitMessageTextBox.axaml.cs | 7 +-- src/Views/Launcher.axaml.cs | 2 +- src/Views/LauncherPage.axaml.cs | 2 +- src/Views/Preferences.axaml.cs | 4 +- src/Views/RepositoryToolbar.axaml.cs | 21 +++---- 15 files changed, 158 insertions(+), 164 deletions(-) create mode 100644 src/ViewModels/AIAssistant.cs diff --git a/src/App.Commands.cs b/src/App.Commands.cs index 85a75829..22e9fb51 100644 --- a/src/App.Commands.cs +++ b/src/App.Commands.cs @@ -37,10 +37,10 @@ namespace SourceGit } } - public static readonly Command OpenPreferencesCommand = new Command(_ => OpenDialog(new Views.Preferences())); - public static readonly Command OpenHotkeysCommand = new Command(_ => OpenDialog(new Views.Hotkeys())); + public static readonly Command OpenPreferencesCommand = new Command(_ => ShowWindow(new Views.Preferences(), false)); + public static readonly Command OpenHotkeysCommand = new Command(_ => ShowWindow(new Views.Hotkeys(), false)); public static readonly Command OpenAppDataDirCommand = new Command(_ => Native.OS.OpenInFileManager(Native.OS.DataDir)); - public static readonly Command OpenAboutCommand = new Command(_ => OpenDialog(new Views.About())); + public static readonly Command OpenAboutCommand = new Command(_ => ShowWindow(new Views.About(), false)); public static readonly Command CheckForUpdateCommand = new Command(_ => (Current as App)?.Check4Update(true)); public static readonly Command QuitCommand = new Command(_ => Quit(0)); public static readonly Command CopyTextBlockCommand = new Command(p => diff --git a/src/App.axaml.cs b/src/App.axaml.cs index c659388a..de6e94ff 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -105,10 +105,36 @@ namespace SourceGit #endregion #region Utility Functions - public static void OpenDialog(Window window) + public static void ShowWindow(object data, bool showAsDialog) { - if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) - window.ShowDialog(owner); + if (data is Views.ChromelessWindow window) + { + if (showAsDialog && Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) + window.ShowDialog(owner); + else + window.Show(); + + return; + } + + var dataTypeName = data.GetType().FullName; + if (string.IsNullOrEmpty(dataTypeName) || !dataTypeName.Contains(".ViewModels.", StringComparison.Ordinal)) + return; + + var viewTypeName = dataTypeName.Replace(".ViewModels.", ".Views."); + var viewType = Type.GetType(viewTypeName); + if (viewType == null || !viewType.IsSubclassOf(typeof(Views.ChromelessWindow))) + return; + + window = Activator.CreateInstance(viewType) as Views.ChromelessWindow; + if (window != null) + { + window.DataContext = data; + if (showAsDialog && Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) + window.ShowDialog(owner); + else + window.Show(); + } } public static void RaiseException(string context, string message) @@ -598,11 +624,7 @@ namespace SourceGit { Dispatcher.UIThread.Post(() => { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) - { - var dialog = new Views.SelfUpdate() { DataContext = new ViewModels.SelfUpdate() { Data = data } }; - dialog.ShowDialog(owner); - } + ShowWindow(new ViewModels.SelfUpdate() { Data = data }, true); }); } diff --git a/src/ViewModels/AIAssistant.cs b/src/ViewModels/AIAssistant.cs new file mode 100644 index 00000000..8756a30b --- /dev/null +++ b/src/ViewModels/AIAssistant.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +using Avalonia.Threading; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class AIAssistant : ObservableObject + { + public bool IsGenerating + { + get => _isGenerating; + private set => SetProperty(ref _isGenerating, value); + } + + public string Text + { + get => _text; + private set => SetProperty(ref _text, value); + } + + public AIAssistant(Repository repo, Models.OpenAIService service, List changes, Action onApply) + { + _repo = repo; + _service = service; + _changes = changes; + _onApply = onApply; + _cancel = new CancellationTokenSource(); + + Gen(); + } + + public void Regen() + { + if (_cancel is { IsCancellationRequested: false }) + _cancel.Cancel(); + + Gen(); + } + + public void Apply() + { + _onApply?.Invoke(Text); + } + + public void Cancel() + { + _cancel?.Cancel(); + } + + private void Gen() + { + Text = string.Empty; + IsGenerating = true; + + _cancel = new CancellationTokenSource(); + Task.Run(() => + { + new Commands.GenerateCommitMessage(_service, _repo.FullPath, _changes, _cancel.Token, message => + { + Dispatcher.UIThread.Invoke(() => Text = message); + }).Exec(); + + Dispatcher.UIThread.Invoke(() => IsGenerating = false); + }, _cancel.Token); + } + + private readonly Repository _repo = null; + private Models.OpenAIService _service = null; + private List _changes = null; + private Action _onApply = null; + private CancellationTokenSource _cancel = null; + private bool _isGenerating = false; + private string _text = string.Empty; + } +} diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 81c09472..0c3ad23f 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -332,8 +332,7 @@ namespace SourceGit.ViewModels history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, ev) => { - var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path, _commit.SHA) }; - window.Show(); + App.ShowWindow(new FileHistories(_repo, change.Path, _commit.SHA), false); ev.Handled = true; }; @@ -343,8 +342,7 @@ namespace SourceGit.ViewModels blame.IsEnabled = change.Index != Models.ChangeState.Deleted; blame.Click += (_, ev) => { - var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, change.Path, _commit.SHA) }; - window.Show(); + App.ShowWindow(new Blame(_repo.FullPath, change.Path, _commit.SHA), false); ev.Handled = true; }; @@ -508,8 +506,7 @@ namespace SourceGit.ViewModels history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, ev) => { - var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path, _commit.SHA) }; - window.Show(); + App.ShowWindow(new FileHistories(_repo, file.Path, _commit.SHA), false); ev.Handled = true; }; @@ -519,8 +516,7 @@ namespace SourceGit.ViewModels blame.IsEnabled = file.Type == Models.ObjectType.Blob; blame.Click += (_, ev) => { - var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, file.Path, _commit.SHA) }; - window.Show(); + App.ShowWindow(new Blame(_repo.FullPath, file.Path, _commit.SHA), false); ev.Handled = true; }; diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index a4a3c515..27457959 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -570,11 +570,7 @@ namespace SourceGit.ViewModels return; } - App.OpenDialog(new Views.InteractiveRebase() - { - DataContext = new InteractiveRebase(_repo, current, commit) - }); - + App.ShowWindow(new InteractiveRebase(_repo, current, commit), true); e.Handled = true; }; diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 9ae99b33..84ba96e4 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -380,7 +380,7 @@ namespace SourceGit.ViewModels configure.Header = App.Text("Workspace.Configure"); configure.Click += (_, e) => { - App.OpenDialog(new Views.ConfigureWorkspace() { DataContext = new ConfigureWorkspace() }); + App.ShowWindow(new ConfigureWorkspace(), true); e.Handled = true; }; menu.Items.Add(configure); diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 3ce40751..04f938ed 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -1405,8 +1405,7 @@ namespace SourceGit.ViewModels { locks.Click += (_, e) => { - var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(this, _remotes[0].Name) }; - App.OpenDialog(dialog); + App.ShowWindow(new LFSLocks(this, _remotes[0].Name), true); e.Handled = true; }; } @@ -1419,8 +1418,7 @@ namespace SourceGit.ViewModels lockRemote.Header = remoteName; lockRemote.Click += (_, e) => { - var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(this, remoteName) }; - App.OpenDialog(dialog); + App.ShowWindow(new LFSLocks(this, remoteName), true); e.Handled = true; }; locks.Items.Add(lockRemote); @@ -1706,10 +1704,7 @@ namespace SourceGit.ViewModels compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare"); compareWithHead.Click += (_, _) => { - App.OpenDialog(new Views.BranchCompare() - { - DataContext = new BranchCompare(_fullpath, branch, _currentBranch) - }); + App.ShowWindow(new BranchCompare(_fullpath, branch, _currentBranch), false); }; menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(compareWithHead); @@ -1989,10 +1984,7 @@ namespace SourceGit.ViewModels compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare"); compareWithHead.Click += (_, _) => { - App.OpenDialog(new Views.BranchCompare() - { - DataContext = new BranchCompare(_fullpath, branch, _currentBranch) - }); + App.ShowWindow(new BranchCompare(_fullpath, branch, _currentBranch), false); }; menu.Items.Add(compareWithHead); diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 65759412..29c8a13f 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -323,10 +323,7 @@ namespace SourceGit.ViewModels public void OpenAssumeUnchanged() { - App.OpenDialog(new Views.AssumeUnchangedManager() - { - DataContext = new AssumeUnchangedManager(_repo) - }); + App.ShowWindow(new AssumeUnchangedManager(_repo), true); } public void StashAll(bool autoStart) @@ -726,8 +723,7 @@ namespace SourceGit.ViewModels history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, e) => { - var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) }; - window.Show(); + App.ShowWindow(new FileHistories(_repo, change.Path), false); e.Handled = true; }; @@ -1093,8 +1089,7 @@ namespace SourceGit.ViewModels { ai.Click += (_, e) => { - var dialog = new Views.AIAssistant(services[0], _repo.FullPath, this, _selectedStaged); - App.OpenDialog(dialog); + App.ShowWindow(new AIAssistant(_repo, services[0], _selectedStaged, t => CommitMessage = t), true); e.Handled = true; }; } @@ -1108,8 +1103,7 @@ namespace SourceGit.ViewModels item.Header = service.Name; item.Click += (_, e) => { - var dialog = new Views.AIAssistant(dup, _repo.FullPath, this, _selectedStaged); - App.OpenDialog(dialog); + App.ShowWindow(new AIAssistant(_repo, dup, _selectedStaged, t => CommitMessage = t), true); e.Handled = true; }; @@ -1193,8 +1187,7 @@ namespace SourceGit.ViewModels history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, e) => { - var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) }; - window.Show(); + App.ShowWindow(new FileHistories(_repo, change.Path), false); e.Handled = true; }; @@ -1490,8 +1483,7 @@ namespace SourceGit.ViewModels if (services.Count == 1) { - var dialog = new Views.AIAssistant(services[0], _repo.FullPath, this, _staged); - App.OpenDialog(dialog); + App.ShowWindow(new AIAssistant(_repo, services[0], _staged, t => CommitMessage = t), true); return null; } @@ -1503,8 +1495,7 @@ namespace SourceGit.ViewModels item.Header = service.Name; item.Click += (_, e) => { - var dialog = new Views.AIAssistant(dup, _repo.FullPath, this, _staged); - App.OpenDialog(dialog); + App.ShowWindow(new AIAssistant(_repo, dup, _staged, t => CommitMessage = t), true); e.Handled = true; }; @@ -1705,14 +1696,7 @@ namespace SourceGit.ViewModels if (!string.IsNullOrEmpty(_filter) && _staged.Count > _visibleStaged.Count && !confirmWithFilter) { var confirmMessage = App.Text("WorkingCopy.ConfirmCommitWithFilter", _staged.Count, _visibleStaged.Count, _staged.Count - _visibleStaged.Count); - App.OpenDialog(new Views.ConfirmCommit() - { - DataContext = new ConfirmCommit(confirmMessage, () => - { - DoCommit(autoStage, autoPush, allowEmpty, true); - }) - }); - + App.ShowWindow(new ConfirmCommit(confirmMessage, () => DoCommit(autoStage, autoPush, allowEmpty, true)), true); return; } @@ -1720,14 +1704,7 @@ namespace SourceGit.ViewModels { if ((autoStage && _count == 0) || (!autoStage && _staged.Count == 0)) { - App.OpenDialog(new Views.ConfirmEmptyCommit() - { - DataContext = new ConfirmEmptyCommit(_count > 0, stageAll => - { - DoCommit(stageAll, autoPush, true, confirmWithFilter); - }) - }); - + App.ShowWindow(new ConfirmEmptyCommit(_count > 0, stageAll => DoCommit(stageAll, autoPush, true, confirmWithFilter)), true); return; } } diff --git a/src/Views/AIAssistant.axaml b/src/Views/AIAssistant.axaml index e07c3a3e..c9a37f3b 100644 --- a/src/Views/AIAssistant.axaml +++ b/src/Views/AIAssistant.axaml @@ -7,6 +7,7 @@ xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="120" x:Class="SourceGit.Views.AIAssistant" + x:DataType="vm:AIAssistant" x:Name="ThisControl" Icon="/App.ico" Title="{DynamicResource Text.AIAssistant}" @@ -48,20 +49,22 @@ - + + + diff --git a/src/Views/RepositoryToolbar.axaml.cs b/src/Views/RepositoryToolbar.axaml.cs index 9ddc64c8..80b5544d 100644 --- a/src/Views/RepositoryToolbar.axaml.cs +++ b/src/Views/RepositoryToolbar.axaml.cs @@ -116,6 +116,21 @@ namespace SourceGit.Views e.Handled = true; } + private void StartBisect(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.Repository { IsBisectCommandRunning: false } repo && + repo.InProgressContext == null && + repo.CanCreatePopup()) + { + if (repo.LocalChangesCount > 0) + App.RaiseException(repo.FullPath, "You have un-committed local changes. Please discard or stash them first."); + else + repo.Bisect("start"); + } + + e.Handled = true; + } + private void OpenCustomActionMenu(object sender, RoutedEventArgs e) { if (DataContext is ViewModels.Repository repo && sender is Control control) From a42df87b9c5e8549bc46d8f1a2056f0e2f7d07bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 22 Apr 2025 07:45:38 +0000 Subject: [PATCH 09/45] doc: Update translation status and sort locale files --- TRANSLATION.md | 96 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 866aac65..3fe63403 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,11 +6,18 @@ 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.19%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-95.32%25-yellow)
Missing keys in de_DE.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.BranchUpstreamInvalid - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter @@ -43,11 +50,18 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-98.95%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-98.05%25-yellow)
Missing keys in es_ES.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -59,11 +73,18 @@ This document shows the translation status of each locale file in the repository
-### ![fr__FR](https://img.shields.io/badge/fr__FR-97.51%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-96.62%25-yellow)
Missing keys in fr_FR.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -86,11 +107,18 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.24%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-96.36%25-yellow)
Missing keys in it_IT.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -115,11 +143,18 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-97.24%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-96.36%25-yellow)
Missing keys in ja_JP.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -144,7 +179,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-88.71%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-87.91%25-yellow)
Missing keys in pt_BR.axaml @@ -155,6 +190,13 @@ This document shows the translation status of each locale file in the repository - Text.ApplyStash.DropAfterApply - Text.ApplyStash.RestoreIndex - Text.ApplyStash.Stash +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.BranchCM.CustomAction - Text.BranchCM.MergeMultiBranches - Text.BranchUpstreamInvalid @@ -238,11 +280,18 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-98.82%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-97.92%25-yellow)
Missing keys in ru_RU.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -255,11 +304,18 @@ This document shows the translation status of each locale file in the repository
-### ![ta__IN](https://img.shields.io/badge/ta__IN-97.51%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-96.62%25-yellow)
Missing keys in ta_IN.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -282,11 +338,18 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-98.69%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-97.79%25-yellow)
Missing keys in uk_UA.axaml +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject @@ -302,4 +365,17 @@ This document shows the translation status of each locale file in the repository ### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen) -### ![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen) \ No newline at end of file +### ![zh__TW](https://img.shields.io/badge/zh__TW-99.09%25-yellow) + +
+Missing keys in zh_TW.axaml + +- Text.Bisect +- Text.Bisect.Abort +- Text.Bisect.Bad +- Text.Bisect.Detecting +- Text.Bisect.Good +- Text.Bisect.Skip +- Text.Bisect.WaitingForRange + +
\ No newline at end of file From 7be37424e10f596d61049d114e5e5e0b73474169 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 16:02:10 +0800 Subject: [PATCH 10/45] fix: modal dialog did not take focus after show (#1225) Co-authored-by: Gadfly Signed-off-by: leo --- src/Views/ChromelessWindow.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Views/ChromelessWindow.cs b/src/Views/ChromelessWindow.cs index 647c657e..dd2485d4 100644 --- a/src/Views/ChromelessWindow.cs +++ b/src/Views/ChromelessWindow.cs @@ -18,6 +18,8 @@ namespace SourceGit.Views public ChromelessWindow() { + Focusable = true; + if (OperatingSystem.IsLinux()) { if (UseSystemWindowFrame) From 34e0ea3bcbb74f9ad3b15f32f656f159c1dca7dc Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 16:07:23 +0800 Subject: [PATCH 11/45] enhance: raise bisect error manually Signed-off-by: leo --- src/Commands/Bisect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Commands/Bisect.cs b/src/Commands/Bisect.cs index 20beeab9..a3bf1a97 100644 --- a/src/Commands/Bisect.cs +++ b/src/Commands/Bisect.cs @@ -6,6 +6,7 @@ { WorkingDirectory = repo; Context = repo; + RaiseError = false; Args = $"bisect {subcmd}"; } } From 9a6c671a964f19df393ab223a5e4429a351bddd5 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 16:50:46 +0800 Subject: [PATCH 12/45] refactor: `--ignore-cr-at-eol` is not necessary when `--ignore-all-space` is enabled Signed-off-by: leo --- src/Commands/Diff.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 8df8cbaa..1434c1a5 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -28,7 +28,7 @@ namespace SourceGit.Commands Context = repo; if (ignoreWhitespace) - Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --ignore-all-space --unified={unified} {opt}"; + Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-all-space --unified={unified} {opt}"; else Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --unified={unified} {opt}"; } From f2000b4a845373e057658cffb623c9ee15e08c19 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 17:51:55 +0800 Subject: [PATCH 13/45] enhance: show git log without command itself for `git bisect` Signed-off-by: leo --- src/ViewModels/Repository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index ddc967fd..1db1d6f3 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -965,9 +965,9 @@ namespace SourceGit.ViewModels Dispatcher.UIThread.Invoke(() => { if (!succ) - App.RaiseException(_fullpath, log.Content); + App.RaiseException(_fullpath, log.Content.Substring(log.Content.IndexOf('\n')).Trim()); else if (log.Content.Contains("is the first bad commit")) - App.SendNotification(_fullpath, log.Content); + App.SendNotification(_fullpath, log.Content.Substring(log.Content.IndexOf('\n')).Trim()); MarkBranchesDirtyManually(); SetWatcherEnabled(true); From 87ebe3741df33375ae380c28bfcd838d2f973d5b Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 18:45:14 +0800 Subject: [PATCH 14/45] fix: for init-commit, app will crash with `COMMIT & PUSH` due to local branch has not been updated (#1229) Signed-off-by: leo --- src/ViewModels/Push.cs | 3 +++ src/ViewModels/WorkingCopy.cs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ViewModels/Push.cs b/src/ViewModels/Push.cs index 5bbb9858..917935b0 100644 --- a/src/ViewModels/Push.cs +++ b/src/ViewModels/Push.cs @@ -114,6 +114,9 @@ namespace SourceGit.ViewModels // Set default selected local branch. if (localBranch != null) { + if (LocalBranches.Count == 0) + LocalBranches.Add(localBranch); + _selectedLocalBranch = localBranch; HasSpecifiedLocalBranch = true; } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 29c8a13f..ef6f0996 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1733,7 +1733,18 @@ namespace SourceGit.ViewModels UseAmend = false; if (autoPush && _repo.Remotes.Count > 0) - _repo.ShowAndStartPopup(new Push(_repo, null)); + { + if (_repo.CurrentBranch == null) + { + var currentBranchName = Commands.Branch.ShowCurrent(_repo.FullPath); + var tmp = new Models.Branch() { Name = currentBranchName }; + _repo.ShowAndStartPopup(new Push(_repo, tmp)); + } + else + { + _repo.ShowAndStartPopup(new Push(_repo, null)); + } + } } _repo.MarkBranchesDirtyManually(); From 78f480987544001cbb4459a6901929d49a7b7e8c Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 19:04:40 +0800 Subject: [PATCH 15/45] fix: no changes were displayed when try to amend a commit without parent (branch first commit) (#1231) Signed-off-by: leo --- src/Commands/QueryStagedChangesWithAmend.cs | 4 ++-- src/ViewModels/WorkingCopy.cs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs index cfea5e35..93dcdb37 100644 --- a/src/Commands/QueryStagedChangesWithAmend.cs +++ b/src/Commands/QueryStagedChangesWithAmend.cs @@ -11,11 +11,11 @@ namespace SourceGit.Commands [GeneratedRegex(@"^:[\d]{6} ([\d]{6}) ([0-9a-f]{40}) [0-9a-f]{40} R\d{0,6}\t(.*\t.*)$")] private static partial Regex REG_FORMAT2(); - public QueryStagedChangesWithAmend(string repo) + public QueryStagedChangesWithAmend(string repo, string parent) { WorkingDirectory = repo; Context = repo; - Args = "diff-index --cached -M HEAD^"; + Args = $"diff-index --cached -M {parent}"; } public List Result() diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index ef6f0996..906248eb 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1524,7 +1524,10 @@ namespace SourceGit.ViewModels private List GetStagedChanges() { if (_useAmend) - return new Commands.QueryStagedChangesWithAmend(_repo.FullPath).Result(); + { + var head = new Commands.QuerySingleCommit(_repo.FullPath, "HEAD").Result(); + return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : "HEAD^").Result(); + } var rs = new List(); foreach (var c in _cached) From 345ad06aba29053db643f6afeb5790fe99fe8023 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 22 Apr 2025 19:20:27 +0800 Subject: [PATCH 16/45] refactor: diff for staged file with `--amend` enabled (#1231) Signed-off-by: leo --- src/Commands/QueryStagedChangesWithAmend.cs | 5 +++++ src/Models/Change.cs | 1 + src/Models/DiffOption.cs | 2 +- src/ViewModels/WorkingCopy.cs | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs index 93dcdb37..8f8456c9 100644 --- a/src/Commands/QueryStagedChangesWithAmend.cs +++ b/src/Commands/QueryStagedChangesWithAmend.cs @@ -16,6 +16,7 @@ namespace SourceGit.Commands WorkingDirectory = repo; Context = repo; Args = $"diff-index --cached -M {parent}"; + _parent = parent; } public List Result() @@ -37,6 +38,7 @@ namespace SourceGit.Commands { FileMode = match.Groups[1].Value, ObjectHash = match.Groups[2].Value, + ParentSHA = _parent, }, }; change.Set(Models.ChangeState.Renamed); @@ -54,6 +56,7 @@ namespace SourceGit.Commands { FileMode = match.Groups[1].Value, ObjectHash = match.Groups[2].Value, + ParentSHA = _parent, }, }; @@ -88,5 +91,7 @@ namespace SourceGit.Commands return []; } + + private string _parent = string.Empty; } } diff --git a/src/Models/Change.cs b/src/Models/Change.cs index e9d07181..0c96ec95 100644 --- a/src/Models/Change.cs +++ b/src/Models/Change.cs @@ -26,6 +26,7 @@ namespace SourceGit.Models { public string FileMode { get; set; } = ""; public string ObjectHash { get; set; } = ""; + public string ParentSHA { get; set; } = ""; } public class Change diff --git a/src/Models/DiffOption.cs b/src/Models/DiffOption.cs index 98387e7f..31d83cea 100644 --- a/src/Models/DiffOption.cs +++ b/src/Models/DiffOption.cs @@ -40,7 +40,7 @@ namespace SourceGit.Models else { if (change.DataForAmend != null) - _extra = "--cached HEAD^"; + _extra = $"--cached {change.DataForAmend.ParentSHA}"; else _extra = "--cached"; diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 906248eb..6402878a 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1526,8 +1526,8 @@ namespace SourceGit.ViewModels if (_useAmend) { var head = new Commands.QuerySingleCommit(_repo.FullPath, "HEAD").Result(); - return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : "HEAD^").Result(); - } + return new Commands.QueryStagedChangesWithAmend(_repo.FullPath, head.Parents.Count == 0 ? "4b825dc642cb6eb9a060e54bf8d69288fbee4904" : $"{head.SHA}^").Result(); + } var rs = new List(); foreach (var c in _cached) From 7890f7abbf38f356722e548cec549163c1c71927 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 23 Apr 2025 10:17:14 +0800 Subject: [PATCH 17/45] refactor: use `PointerPressed` event instead of `ListBox.SelectionChanged` event to navigate to commit (#1230) Signed-off-by: leo --- src/Views/BranchTree.axaml | 96 ++++++++++++++++++----------------- src/Views/BranchTree.axaml.cs | 28 ++++++++-- src/Views/TagsView.axaml | 83 +++++++++++++++--------------- src/Views/TagsView.axaml.cs | 27 ++++++---- 4 files changed, 133 insertions(+), 101 deletions(-) diff --git a/src/Views/BranchTree.axaml b/src/Views/BranchTree.axaml index 0ac09e6c..c1fecf63 100644 --- a/src/Views/BranchTree.axaml +++ b/src/Views/BranchTree.axaml @@ -32,61 +32,63 @@ - + + - - + + - - + + - - + + - - + + - - - - + + + + - - + + - - + + + - + diff --git a/src/Views/BranchTree.axaml.cs b/src/Views/BranchTree.axaml.cs index 51bb01e0..8542157d 100644 --- a/src/Views/BranchTree.axaml.cs +++ b/src/Views/BranchTree.axaml.cs @@ -318,6 +318,31 @@ namespace SourceGit.Views } } + private void OnNodePointerPressed(object sender, PointerPressedEventArgs e) + { + var p = e.GetCurrentPoint(this); + if (!p.Properties.IsLeftButtonPressed) + return; + + if (DataContext is not ViewModels.Repository repo) + return; + + if (sender is not Border { DataContext: ViewModels.BranchTreeNode node }) + return; + + if (node.Backend is not Models.Branch branch) + return; + + if (BranchesPresenter.SelectedItems is { Count: > 0 }) + { + var ctrl = OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control; + if (e.KeyModifiers.HasFlag(ctrl) || e.KeyModifiers.HasFlag(KeyModifiers.Shift)) + return; + } + + repo.NavigateToCommit(branch.Head); + } + private void OnNodesSelectionChanged(object _, SelectionChangedEventArgs e) { if (_disableSelectionChangingEvent) @@ -343,9 +368,6 @@ namespace SourceGit.Views if (selected == null || selected.Count == 0) return; - if (selected.Count == 1 && selected[0] is ViewModels.BranchTreeNode { Backend: Models.Branch branch }) - repo.NavigateToCommit(branch.Head); - var prev = null as ViewModels.BranchTreeNode; foreach (var row in Rows) { diff --git a/src/Views/TagsView.axaml b/src/Views/TagsView.axaml index b5384c8f..2a575cb3 100644 --- a/src/Views/TagsView.axaml +++ b/src/Views/TagsView.axaml @@ -26,36 +26,36 @@ SelectionChanged="OnRowSelectionChanged"> - - + + + - + - + - - - - - - - - + + + + + + + + + @@ -69,23 +69,22 @@ SelectionChanged="OnRowSelectionChanged"> - - + + + - + - - + + + diff --git a/src/Views/TagsView.axaml.cs b/src/Views/TagsView.axaml.cs index c83cfd28..ba6740c0 100644 --- a/src/Views/TagsView.axaml.cs +++ b/src/Views/TagsView.axaml.cs @@ -199,15 +199,27 @@ namespace SourceGit.Views private void OnDoubleTappedNode(object sender, TappedEventArgs e) { - if (sender is Grid { DataContext: ViewModels.TagTreeNode node }) - { - if (node.IsFolder) - ToggleNodeIsExpanded(node); - } + if (sender is Control { DataContext: ViewModels.TagTreeNode { IsFolder: true } node }) + ToggleNodeIsExpanded(node); e.Handled = true; } + private void OnRowPointerPressed(object sender, PointerPressedEventArgs e) + { + var p = e.GetCurrentPoint(this); + if (!p.Properties.IsLeftButtonPressed) + return; + + if (DataContext is not ViewModels.Repository repo) + return; + + if (sender is Control { DataContext: Models.Tag tag }) + repo.NavigateToCommit(tag.SHA); + else if (sender is Control { DataContext: ViewModels.TagTreeNode { Tag: { } nodeTag } }) + repo.NavigateToCommit(nodeTag.SHA); + } + private void OnRowContextRequested(object sender, ContextRequestedEventArgs e) { var control = sender as Control; @@ -240,11 +252,8 @@ namespace SourceGit.Views else if (selected is Models.Tag tag) selectedTag = tag; - if (selectedTag != null && DataContext is ViewModels.Repository repo) - { + if (selectedTag != null) RaiseEvent(new RoutedEventArgs(SelectionChangedEvent)); - repo.NavigateToCommit(selectedTag.SHA); - } } private void MakeTreeRows(List rows, List nodes) From fafa2a53aece00da9749524446d31afa57d8560d Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 23 Apr 2025 10:33:49 +0800 Subject: [PATCH 18/45] enhance: show commit full message tooltip when hover commit subject in `FileHistories` view (#1232) Signed-off-by: leo --- src/ViewModels/FileHistories.cs | 12 ++++++++++++ src/Views/FileHistories.axaml | 7 ++++++- src/Views/FileHistories.axaml.cs | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs index 417b816d..9f91205e 100644 --- a/src/ViewModels/FileHistories.cs +++ b/src/ViewModels/FileHistories.cs @@ -305,11 +305,23 @@ namespace SourceGit.ViewModels _repo.NavigateToCommit(commit.SHA); } + public string GetCommitFullMessage(Models.Commit commit) + { + var sha = commit.SHA; + if (_fullCommitMessages.TryGetValue(sha, out var msg)) + return msg; + + msg = new Commands.QueryCommitFullMessage(_repo.FullPath, sha).Result(); + _fullCommitMessages[sha] = msg; + return msg; + } + private readonly Repository _repo = null; private readonly string _file = null; private bool _isLoading = true; private bool _prevIsDiffMode = true; private List _commits = null; + private Dictionary _fullCommitMessages = new Dictionary(); private object _viewContent = null; } } diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml index e33156fb..f597fc04 100644 --- a/src/Views/FileHistories.axaml +++ b/src/Views/FileHistories.axaml @@ -93,7 +93,12 @@ - + diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs index be5affc3..a183182e 100644 --- a/src/Views/FileHistories.axaml.cs +++ b/src/Views/FileHistories.axaml.cs @@ -1,3 +1,5 @@ +using System; + using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; @@ -57,5 +59,22 @@ namespace SourceGit.Views e.Handled = true; } } + + private void OnCommitSubjectDataContextChanged(object sender, EventArgs e) + { + if (sender is TextBlock textBlock) + ToolTip.SetTip(textBlock, null); + } + + private void OnCommitSubjectPointerMoved(object sender, PointerEventArgs e) + { + if (sender is TextBlock { DataContext: Models.Commit commit } textBlock && + DataContext is ViewModels.FileHistories vm) + { + var tooltip = ToolTip.GetTip(textBlock); + if (tooltip == null) + ToolTip.SetTip(textBlock, vm.GetCommitFullMessage(commit)); + } + } } } From 17c08d42a0ea721a35b99393e10a245578483a72 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 23 Apr 2025 10:38:01 +0800 Subject: [PATCH 19/45] enhance: ignore all sub-directories those names start with '.' (#1234) Signed-off-by: leo --- src/ViewModels/ScanRepositories.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ViewModels/ScanRepositories.cs b/src/ViewModels/ScanRepositories.cs index 322c2cda..09c3559f 100644 --- a/src/ViewModels/ScanRepositories.cs +++ b/src/ViewModels/ScanRepositories.cs @@ -87,11 +87,8 @@ namespace SourceGit.ViewModels var subdirs = dir.GetDirectories("*", opts); foreach (var subdir in subdirs) { - if (subdir.Name.Equals("node_modules", StringComparison.Ordinal) || - subdir.Name.Equals(".svn", StringComparison.Ordinal) || - subdir.Name.Equals(".vs", StringComparison.Ordinal) || - subdir.Name.Equals(".vscode", StringComparison.Ordinal) || - subdir.Name.Equals(".idea", StringComparison.Ordinal)) + if (subdir.Name.StartsWith(".", StringComparison.Ordinal) || + subdir.Name.Equals("node_modules", StringComparison.Ordinal)) continue; CallUIThread(() => ProgressDescription = $"Scanning {subdir.FullName}..."); From 9bdbf475220cd9cfb148d00c2459d1f41e4d2b5c Mon Sep 17 00:00:00 2001 From: AquariusStar <48148723+AquariusStar@users.noreply.github.com> Date: Wed, 23 Apr 2025 05:39:30 +0300 Subject: [PATCH 20/45] localization: update russian localization (#1233) --- src/Resources/Locales/ru_RU.axaml | 40 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index b8c86415..35125369 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -14,8 +14,8 @@ Отслеживание ветки: Отслеживание внешней ветки Переключиться на: - создать новую ветку - ветку из списка + Создать новую ветку + Ветку из списка Помощник OpenAI ПЕРЕСОЗДАТЬ Использовать OpenAI для создания сообщения о ревизии @@ -40,9 +40,16 @@ СПИСОК ПУСТ УДАЛИТЬ ДВОИЧНЫЙ ФАЙЛ НЕ ПОДДЕРЖИВАЕТСЯ!!! + Раздвоить + О + Плохая + Раздвоение. Текущая ГОЛОВА (HEAD) хорошая или плохая? + Хорошая + Пропустить + Раздвоение. Сделать текущую ревизию хорошей или плохой и переключиться на другой. Расследование РАССЛЕДОВАНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!! - Проверить ${0}$... + Переключиться на ${0}$... Сравнить с ГОЛОВОЙ (HEAD) Сравнить с рабочим каталогом Копировать имя ветки @@ -55,8 +62,8 @@ Поток Git - Завершение ${0}$ Влить ${0}$ в ${1}$... Влить {0} выделенных веток в текущую - Забрать ${0}$ - Забрать ${0}$ в ${1}$... + Загрузить ${0}$ + Загрузить ${0}$ в ${1}$... Выложить ${0}$ Переместить ${0}$ на ${1}$... Переименовать ${0}$... @@ -103,8 +110,11 @@ Применить несколько ревизий ... Сравнить c ГОЛОВОЙ (HEAD) Сравнить с рабочим каталогом + Автор + Ревизор Информацию SHA + Субъект Пользовательское действие Интерактивное перемещение (rebase -i) ${0}$ сюда Влить в ${0}$ @@ -136,6 +146,7 @@ SHA Открыть в браузере Описание + СУБЪЕКТ Введите тему ревизии Настройка репозитория ШАБЛОН РЕВИЗИИ @@ -199,7 +210,7 @@ Копировать путь Создать ветку... Основан на: - Проверить созданную ветку + Переключиться на созданную ветку Локальные изменения: Отклонить Отложить и применить повторно @@ -348,9 +359,9 @@ Принудительно разблокировать Обрезать Запустить (git lfs prune), чтобы удалить старые файлы LFS из локального хранилища - Забрать + Загрузить Запустить (git lfs pull), чтобы загрузить все файлы LFS Git для текущей ссылки и проверить - Забрать объекты LFS + Загрузить объекты LFS Выложить Отправляйте большие файлы, помещенные в очередь, в конечную точку LFS Git Выложить объекты LFS @@ -385,7 +396,7 @@ Извлечение, запускается сразу Режим доски (по умолчанию) Режим поиска ревизий - Забрать, запускается сразу + Загрузить, запускается сразу Выложить, запускается сразу Принудительно перезагрузить репозиторий Подготовленные/Неподготовленные выбранные изменения @@ -512,16 +523,16 @@ Цель: Удалить рабочий каталог Информация об обрезке рабочего каталога в «$GIT_COMMON_DIR/worktrees» - Забрать + Загрузить Ветка внешнего репозитория: Извлечь все ветки В: Локальные изменения: Отклонить Отложить и применить повторно - Забрать без меток + Загрузить без меток Внешний репозиторий: - Забрать (Получить и слить) + Загрузить (Получить и слить) Использовать перемещение вместо слияния Выложить Убедитесь, что подмодули были вставлены @@ -615,6 +626,7 @@ Сортировать Открыть в терминале Использовать относительное время в историях + Просмотр логов РАБОЧИЕ КАТАЛОГИ ДОБАВИТЬ РАБОЧИЙ КАТАЛОГ ОБРЕЗАТЬ @@ -700,6 +712,10 @@ Подмодуль: Использовать опцию (--remote) Сетевой адрес: + Логи + ОЧИСТИТЬ ВСЁ + Копировать + Удалить Предупреждение Приветствие Создать группу From 586ff39da1d51d79fa4d53ec2fcb15ed8762842c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 23 Apr 2025 02:39:41 +0000 Subject: [PATCH 21/45] doc: Update translation status and sort locale files --- TRANSLATION.md | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 3fe63403..fb96afdb 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -280,29 +280,7 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-97.92%25-yellow) - -
-Missing keys in ru_RU.axaml - -- Text.Bisect -- Text.Bisect.Abort -- Text.Bisect.Bad -- Text.Bisect.Detecting -- Text.Bisect.Good -- Text.Bisect.Skip -- Text.Bisect.WaitingForRange -- Text.CommitCM.CopyAuthor -- Text.CommitCM.CopyCommitter -- Text.CommitCM.CopySubject -- Text.CommitMessageTextBox.SubjectCount -- Text.Repository.ViewLogs -- Text.ViewLogs -- Text.ViewLogs.Clear -- Text.ViewLogs.CopyLog -- Text.ViewLogs.Delete - -
+### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) ### ![ta__IN](https://img.shields.io/badge/ta__IN-96.62%25-yellow) From f72f1894c3f5bd15d3ab1a22f8e1706149fbbd76 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 23 Apr 2025 15:34:21 +0800 Subject: [PATCH 22/45] feature: supports to enable `--ignore-cr-at-eol` in diff by default Signed-off-by: leo --- src/Commands/Diff.cs | 2 ++ src/Models/DiffOption.cs | 9 +++++++++ src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/ViewModels/Preferences.cs | 13 +++++++++++++ src/Views/Preferences.axaml | 7 ++++++- 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 1434c1a5..a60f4cc5 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -29,6 +29,8 @@ namespace SourceGit.Commands if (ignoreWhitespace) Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-all-space --unified={unified} {opt}"; + else if (Models.DiffOption.IgnoreCRAtEOL) + Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}"; else Args = $"-c core.autocrlf=false diff --no-ext-diff --patch --unified={unified} {opt}"; } diff --git a/src/Models/DiffOption.cs b/src/Models/DiffOption.cs index 31d83cea..5f491d58 100644 --- a/src/Models/DiffOption.cs +++ b/src/Models/DiffOption.cs @@ -5,6 +5,15 @@ namespace SourceGit.Models { public class DiffOption { + /// + /// Enable `--ignore-cr-at-eol` by default? + /// + public static bool IgnoreCRAtEOL + { + get; + set; + } = false; + public Change WorkingCopyChange => _workingCopyChange; public bool IsUnstaged => _isUnstaged; public List Revisions => _revisions; diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 3c710727..538ac1f1 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -497,6 +497,7 @@ User Email Global git user email Enable --prune on fetch + Enable --ignore-cr-at-eol in diff Git (>= 2.23.0) is required by this app Install Path Enable HTTP SSL Verify diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 843c3735..db77a3ed 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -501,6 +501,7 @@ 邮箱 默认GIT用户邮箱 拉取更新时启用修剪(--prune) + 文件对比时默认启用 --ignore-cr-at-eol 选项 本软件要求GIT最低版本为2.23.0 安装路径 启用HTTP SSL验证 diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs index a1830d07..d1e13f38 100644 --- a/src/ViewModels/Preferences.cs +++ b/src/ViewModels/Preferences.cs @@ -212,6 +212,19 @@ namespace SourceGit.ViewModels set => SetProperty(ref _useSyntaxHighlighting, value); } + public bool IgnoreCRAtEOLInDiff + { + get => Models.DiffOption.IgnoreCRAtEOL; + set + { + if (Models.DiffOption.IgnoreCRAtEOL != value) + { + Models.DiffOption.IgnoreCRAtEOL = value; + OnPropertyChanged(); + } + } + } + public bool IgnoreWhitespaceChangesInDiff { get => _ignoreWhitespaceChangesInDiff; diff --git a/src/Views/Preferences.axaml b/src/Views/Preferences.axaml index 702ec20f..6742bcfc 100644 --- a/src/Views/Preferences.axaml +++ b/src/Views/Preferences.axaml @@ -273,7 +273,7 @@ - + + + From 210767605818dc46f4f5f5c7a5b3c3c24e1c805e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 23 Apr 2025 07:34:37 +0000 Subject: [PATCH 23/45] doc: Update translation status and sort locale files --- TRANSLATION.md | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index fb96afdb..9e590d21 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-95.32%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-95.19%25-yellow)
Missing keys in de_DE.axaml @@ -36,6 +36,7 @@ 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.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.ViewLogs - Text.StashCM.SaveAsPatch - Text.ViewLogs @@ -50,7 +51,7 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-98.05%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-97.92%25-yellow)
Missing keys in es_ES.axaml @@ -65,6 +66,7 @@ This document shows the translation status of each locale file in the repository - Text.CommitCM.CopyAuthor - Text.CommitCM.CopyCommitter - Text.CommitCM.CopySubject +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -73,7 +75,7 @@ This document shows the translation status of each locale file in the repository
-### ![fr__FR](https://img.shields.io/badge/fr__FR-96.62%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-96.49%25-yellow)
Missing keys in fr_FR.axaml @@ -94,6 +96,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.NoLocalChanges - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -107,7 +110,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-96.36%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-96.23%25-yellow)
Missing keys in it_IT.axaml @@ -130,6 +133,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.WithLocalChanges - Text.CopyFullPath - Text.Preferences.General.ShowTagsInGraph +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -143,7 +147,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-96.36%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-96.23%25-yellow)
Missing keys in ja_JP.axaml @@ -164,6 +168,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.NoLocalChanges - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.FilterCommits - Text.Repository.Tags.OrderByNameDes - Text.Repository.ViewLogs @@ -179,7 +184,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-87.91%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-87.79%25-yellow)
Missing keys in pt_BR.axaml @@ -243,6 +248,7 @@ This document shows the translation status of each locale file in the repository - Text.Preferences.General.DateFormat - Text.Preferences.General.ShowChildren - Text.Preferences.General.ShowTagsInGraph +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Preferences.Git.SSLVerify - Text.Repository.FilterCommits - Text.Repository.HistoriesLayout @@ -280,9 +286,16 @@ This document shows the translation status of each locale file in the repository
-### ![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-96.62%25-yellow) +
+Missing keys in ru_RU.axaml + +- Text.Preferences.Git.IgnoreCRAtEOLInDiff + +
+ +### ![ta__IN](https://img.shields.io/badge/ta__IN-96.49%25-yellow)
Missing keys in ta_IN.axaml @@ -303,6 +316,7 @@ This document shows the translation status of each locale file in the repository - Text.ConfirmEmptyCommit.NoLocalChanges - Text.ConfirmEmptyCommit.StageAllThenCommit - Text.ConfirmEmptyCommit.WithLocalChanges +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.ViewLogs - Text.UpdateSubmodules.Target - Text.ViewLogs @@ -316,7 +330,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-97.79%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-97.66%25-yellow)
Missing keys in uk_UA.axaml @@ -333,6 +347,7 @@ This document shows the translation status of each locale file in the repository - Text.CommitCM.CopySubject - Text.CommitMessageTextBox.SubjectCount - Text.ConfigureWorkspace.Name +- Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.ViewLogs - Text.ViewLogs - Text.ViewLogs.Clear @@ -343,7 +358,7 @@ This document shows the translation status of each locale file in the repository ### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen) -### ![zh__TW](https://img.shields.io/badge/zh__TW-99.09%25-yellow) +### ![zh__TW](https://img.shields.io/badge/zh__TW-98.96%25-yellow)
Missing keys in zh_TW.axaml @@ -355,5 +370,6 @@ This document shows the translation status of each locale file in the repository - Text.Bisect.Good - Text.Bisect.Skip - Text.Bisect.WaitingForRange +- Text.Preferences.Git.IgnoreCRAtEOLInDiff
\ No newline at end of file From 1386ca30e3bfb14e55e426eb466e3cc1b2b0938e Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 23 Apr 2025 20:52:41 +0800 Subject: [PATCH 24/45] fix: typo in conventional commit type (#1239) Signed-off-by: leo --- src/Models/ConventionalCommitType.cs | 35 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/Models/ConventionalCommitType.cs b/src/Models/ConventionalCommitType.cs index cd09453a..531a16c0 100644 --- a/src/Models/ConventionalCommitType.cs +++ b/src/Models/ConventionalCommitType.cs @@ -4,25 +4,24 @@ namespace SourceGit.Models { public class ConventionalCommitType { - public string Name { get; set; } = string.Empty; - public string Type { get; set; } = string.Empty; - public string Description { get; set; } = string.Empty; + public string Name { get; set; } + public string Type { get; set; } + public string Description { get; set; } - public static readonly List Supported = new List() - { - new ConventionalCommitType("Features", "feat", "Adding a new feature"), - new ConventionalCommitType("Bug Fixes", "fix", "Fixing a bug"), - new ConventionalCommitType("Work In Progress", "wip", "Still being developed and not yet complete"), - new ConventionalCommitType("Reverts", "revert", "Undoing a previous commit"), - new ConventionalCommitType("Code Refactoring", "refactor", "Restructuring code without changing its external behavior"), - new ConventionalCommitType("Performance Improvements", "pref", "Improves performance"), - new ConventionalCommitType("Builds", "build", "Changes that affect the build system or external dependencies"), - new ConventionalCommitType("Continuous Integrations", "ci", "Changes to CI configuration files and scripts"), - new ConventionalCommitType("Documentations", "docs", "Updating documentation"), - new ConventionalCommitType("Styles", "style", "Elements or code styles without changing the code logic"), - new ConventionalCommitType("Tests", "test", "Adding or updating tests"), - new ConventionalCommitType("Chores", "chore", "Other changes that don't modify src or test files"), - }; + public static readonly List Supported = [ + new("Features", "feat", "Adding a new feature"), + new("Bug Fixes", "fix", "Fixing a bug"), + new("Work In Progress", "wip", "Still being developed and not yet complete"), + new("Reverts", "revert", "Undoing a previous commit"), + new("Code Refactoring", "refactor", "Restructuring code without changing its external behavior"), + new("Performance Improvements", "perf", "Improves performance"), + new("Builds", "build", "Changes that affect the build system or external dependencies"), + new("Continuous Integrations", "ci", "Changes to CI configuration files and scripts"), + new("Documentations", "docs", "Updating documentation"), + new("Styles", "style", "Elements or code styles without changing the code logic"), + new("Tests", "test", "Adding or updating tests"), + new("Chores", "chore", "Other changes that don't modify src or test files"), + ]; public ConventionalCommitType(string name, string type, string description) { From 7e282b13fa30d2d9737e5261f3c9e05744bc3f92 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 23 Apr 2025 20:59:39 +0800 Subject: [PATCH 25/45] code_style: run `dotnet format` Signed-off-by: leo --- src/Models/Bisect.cs | 2 +- src/ViewModels/ScanRepositories.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Models/Bisect.cs b/src/Models/Bisect.cs index 8ef5ec78..3dd28681 100644 --- a/src/Models/Bisect.cs +++ b/src/Models/Bisect.cs @@ -13,7 +13,7 @@ namespace SourceGit.Models { None = 0, Good = 1, - Bad = 2, + Bad = 2, } public class Bisect diff --git a/src/ViewModels/ScanRepositories.cs b/src/ViewModels/ScanRepositories.cs index 09c3559f..307694ea 100644 --- a/src/ViewModels/ScanRepositories.cs +++ b/src/ViewModels/ScanRepositories.cs @@ -87,7 +87,7 @@ namespace SourceGit.ViewModels var subdirs = dir.GetDirectories("*", opts); foreach (var subdir in subdirs) { - if (subdir.Name.StartsWith(".", StringComparison.Ordinal) || + if (subdir.Name.StartsWith(".", StringComparison.Ordinal) || subdir.Name.Equals("node_modules", StringComparison.Ordinal)) continue; From ea680782fee8816924f179a20d4f3f76ed4d979b Mon Sep 17 00:00:00 2001 From: qiufengshe <172344058@qq.com> Date: Wed, 23 Apr 2025 21:14:41 +0800 Subject: [PATCH 26/45] perf: minimize temporary strings for better performance (#1240) (cherry picked from commit f4dad2bf551ead5640a500297a4a6f408aef1350) --- src/ViewModels/WorkingCopy.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 6402878a..63d6df47 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -635,7 +635,7 @@ namespace SourceGit.ViewModels } else if (_inProgressContext is RevertInProgress revert) { - useTheirs.Header = App.Text("FileCM.ResolveUsing", revert.Head.SHA.Substring(0, 10) + " (revert)"); + useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan().Slice(0, 10)} (revert)"); useMine.Header = App.Text("FileCM.ResolveUsing", _repo.CurrentBranch.Name); } else if (_inProgressContext is MergeInProgress merge) @@ -771,7 +771,7 @@ namespace SourceGit.ViewModels byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension); byExtension.Click += (_, e) => { - Commands.GitIgnore.Add(_repo.FullPath, "*" + extension); + Commands.GitIgnore.Add(_repo.FullPath, $"*{extension}"); e.Handled = true; }; addToIgnore.Items.Add(byExtension); @@ -782,7 +782,7 @@ namespace SourceGit.ViewModels byExtensionInSameFolder.Click += (_, e) => { var dir = Path.GetDirectoryName(change.Path).Replace("\\", "/"); - Commands.GitIgnore.Add(_repo.FullPath, dir + "/*" + extension); + Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}"); e.Handled = true; }; addToIgnore.Items.Add(byExtensionInSameFolder); @@ -824,7 +824,7 @@ namespace SourceGit.ViewModels lfsTrackByExtension.Click += async (_, e) => { var log = _repo.CreateLog("Track LFS"); - var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track("*" + extension, false, log)); + var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track($"*{extension}", false, log)); if (succ) App.SendNotification(_repo.FullPath, $"Tracking all *{extension} files successfully!"); @@ -993,7 +993,7 @@ namespace SourceGit.ViewModels } else if (_inProgressContext is RevertInProgress revert) { - useTheirs.Header = App.Text("FileCM.ResolveUsing", revert.Head.SHA.Substring(0, 10) + " (revert)"); + useTheirs.Header = App.Text("FileCM.ResolveUsing", $"{revert.Head.SHA.AsSpan().Slice(0, 10)} (revert)"); useMine.Header = App.Text("FileCM.ResolveUsing", _repo.CurrentBranch.Name); } else if (_inProgressContext is MergeInProgress merge) @@ -1417,7 +1417,7 @@ namespace SourceGit.ViewModels var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length; if (gitTemplate.StartsWith(home, StringComparison.Ordinal)) - friendlyName = "~" + gitTemplate.Substring(prefixLen); + friendlyName = $"~{gitTemplate.AsSpan().Slice(prefixLen)}"; } var gitTemplateItem = new MenuItem(); From f73e0687a112046c6d0b455940823e5fad31415b 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, 23 Apr 2025 19:22:32 -0600 Subject: [PATCH 27/45] localization: update spanish translations (#1241) add missing translations. `Bisect`/`Bisecting` stays the same because they reference command names. --- src/Resources/Locales/es_ES.axaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 204cfc1a..82913d24 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -40,6 +40,13 @@ NO HAY ARCHIVOS ASUMIDOS COMO SIN CAMBIOS REMOVER ¡ARCHIVO BINARIO NO SOPORTADO! + Bisect + Abortar + Malo + Bisecting. ¿Es el HEAD actual bueno o malo? + Bueno + Saltar + Bisecting. Marcar el commit actual cómo bueno o malo y revisar otro. Blame ¡BLAME EN ESTE ARCHIVO NO SOPORTADO! Checkout ${0}$... @@ -103,8 +110,11 @@ Cherry-Pick ... Comparar con HEAD Comparar con Worktree + Autor + Committer Información SHA + Asunto Acción personalizada Rebase Interactivo ${0}$ hasta Aquí Merge a ${0}$ @@ -491,6 +501,7 @@ Email de usuario Email global del usuario git Habilitar --prune para fetch + Habilitar --ignore-cr-at-eol en diff Se requiere Git (>= 2.23.0) para esta aplicación Ruta de instalación Habilitar verificación HTTP SSL @@ -616,6 +627,7 @@ Ordenar Abrir en Terminal Usar tiempo relativo en las historias + Ver Logs WORKTREES AÑADIR WORKTREE PRUNE @@ -701,6 +713,10 @@ Submódulo: Usar opción --remote URL: + Logs + LIMPIAR TODO + Copiar + Borrar Advertencia Página de Bienvenida Crear Grupo From ad6ed1512b4c9f6411d73170807fb6f74d797e09 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 24 Apr 2025 01:22:43 +0000 Subject: [PATCH 28/45] doc: Update translation status and sort locale files --- TRANSLATION.md | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 9e590d21..a81ae006 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -51,29 +51,7 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-97.92%25-yellow) - -
-Missing keys in es_ES.axaml - -- Text.Bisect -- Text.Bisect.Abort -- Text.Bisect.Bad -- Text.Bisect.Detecting -- Text.Bisect.Good -- Text.Bisect.Skip -- Text.Bisect.WaitingForRange -- Text.CommitCM.CopyAuthor -- Text.CommitCM.CopyCommitter -- Text.CommitCM.CopySubject -- Text.Preferences.Git.IgnoreCRAtEOLInDiff -- Text.Repository.ViewLogs -- Text.ViewLogs -- Text.ViewLogs.Clear -- Text.ViewLogs.CopyLog -- Text.ViewLogs.Delete - -
+### ![es__ES](https://img.shields.io/badge/es__ES-%E2%88%9A-brightgreen) ### ![fr__FR](https://img.shields.io/badge/fr__FR-96.49%25-yellow) From 65908126349a44de5aba0b79874ecd43321e659c Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 24 Apr 2025 10:00:07 +0800 Subject: [PATCH 29/45] localization: update translations for Chinese Signed-off-by: leo --- src/Resources/Locales/zh_CN.axaml | 6 +++--- src/Resources/Locales/zh_TW.axaml | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index db77a3ed..39bf38e4 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -43,9 +43,9 @@ 二分定位(bisect) 终止 标记错误 - 二分定位进行中。当前提交是 '正确' 还是 '错误'? + 二分定位进行中。当前提交是 '正确' 还是 '错误' ? 标记正确 - 该提交无法判定 + 无法判定 二分定位进行中。请标记当前的提交是 '正确' 还是 '错误',然后检出另一个提交。 逐行追溯(blame) 选中文件不支持该操作!!! @@ -501,7 +501,7 @@ 邮箱 默认GIT用户邮箱 拉取更新时启用修剪(--prune) - 文件对比时默认启用 --ignore-cr-at-eol 选项 + 对比文件时,默认忽略换行符变更 (--ignore-cr-at-eol) 本软件要求GIT最低版本为2.23.0 安装路径 启用HTTP SSL验证 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 3a10f6ca..4e2b9e20 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -40,6 +40,13 @@ 沒有不追蹤變更的檔案 移除 二進位檔案不支援該操作! + 二元搜尋(bisect) + 中止 + 標記為錯誤 + 二元搜尋進行中。目前的提交是「良好」是「錯誤」? + 標記為良好 + 無法確認 + 二元搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後檢查另一個。。 逐行溯源 (blame) 所選擇的檔案不支援該操作! 簽出 (checkout) ${0}$... @@ -494,6 +501,7 @@ 電子郵件 預設 Git 使用者電子郵件 拉取變更時進行清理 (--prune) + 對比檔案時,預設忽略行尾的 CR 變更 (--ignore-cr-at-eol) 本軟體要求 Git 最低版本為 2.23.0 安裝路徑 啟用 HTTP SSL 驗證 From c51938164565d2ef265e2a11668a56a164f7d435 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 24 Apr 2025 02:00:26 +0000 Subject: [PATCH 30/45] doc: Update translation status and sort locale files --- TRANSLATION.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index a81ae006..e2693e64 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -336,18 +336,4 @@ This document shows the translation status of each locale file in the repository ### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen) -### ![zh__TW](https://img.shields.io/badge/zh__TW-98.96%25-yellow) - -
-Missing keys in zh_TW.axaml - -- Text.Bisect -- Text.Bisect.Abort -- Text.Bisect.Bad -- Text.Bisect.Detecting -- Text.Bisect.Good -- Text.Bisect.Skip -- Text.Bisect.WaitingForRange -- Text.Preferences.Git.IgnoreCRAtEOLInDiff - -
\ No newline at end of file +### ![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen) \ No newline at end of file From 9efbc7dd7a6181626c14b4e4bc75ad5f0be67d4a Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 24 Apr 2025 10:01:57 +0800 Subject: [PATCH 31/45] localization: update translations for Chinese Signed-off-by: leo --- src/Resources/Locales/zh_TW.axaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 4e2b9e20..63052d35 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -40,13 +40,13 @@ 沒有不追蹤變更的檔案 移除 二進位檔案不支援該操作! - 二元搜尋(bisect) + 二元搜尋 (bisect) 中止 標記為錯誤 二元搜尋進行中。目前的提交是「良好」是「錯誤」? 標記為良好 無法確認 - 二元搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後檢查另一個。。 + 二元搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後簽出另一個提交。 逐行溯源 (blame) 所選擇的檔案不支援該操作! 簽出 (checkout) ${0}$... From 8c4362a98d757c4dab53a1a4f48a1b09e39c2448 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 25 Apr 2025 13:24:13 +0800 Subject: [PATCH 32/45] feature: subject presenter supports inline codeblock Signed-off-by: leo --- src/Models/Commit.cs | 2 +- src/Models/{Hyperlink.cs => InlineElement.cs} | 17 +- src/Models/IssueTrackerRule.cs | 5 +- src/ViewModels/CommitDetail.cs | 20 +- src/Views/CommitMessagePresenter.cs | 14 +- src/Views/CommitSubjectPresenter.cs | 345 +++++++++++++----- src/Views/Histories.axaml | 5 +- 7 files changed, 289 insertions(+), 119 deletions(-) rename src/Models/{Hyperlink.cs => InlineElement.cs} (60%) diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs index 0bad8376..1980e622 100644 --- a/src/Models/Commit.cs +++ b/src/Models/Commit.cs @@ -117,6 +117,6 @@ namespace SourceGit.Models public class CommitFullMessage { public string Message { get; set; } = string.Empty; - public List Links { get; set; } = []; + public List Inlines { get; set; } = []; } } diff --git a/src/Models/Hyperlink.cs b/src/Models/InlineElement.cs similarity index 60% rename from src/Models/Hyperlink.cs rename to src/Models/InlineElement.cs index 81dc980e..53761403 100644 --- a/src/Models/Hyperlink.cs +++ b/src/Models/InlineElement.cs @@ -1,18 +1,27 @@ namespace SourceGit.Models { - public class Hyperlink + public enum InlineElementType { + None = 0, + Keyword, + Link, + CommitSHA, + Code, + } + + public class InlineElement + { + public InlineElementType Type { get; set; } = InlineElementType.None; public int Start { get; set; } = 0; public int Length { get; set; } = 0; public string Link { get; set; } = ""; - public bool IsCommitSHA { get; set; } = false; - public Hyperlink(int start, int length, string link, bool isCommitSHA = false) + public InlineElement(InlineElementType type, int start, int length, string link) { + Type = type; Start = start; Length = length; Link = link; - IsCommitSHA = isCommitSHA; } public bool Intersect(int start, int length) diff --git a/src/Models/IssueTrackerRule.cs b/src/Models/IssueTrackerRule.cs index 29487a16..fe0fe8e0 100644 --- a/src/Models/IssueTrackerRule.cs +++ b/src/Models/IssueTrackerRule.cs @@ -46,7 +46,7 @@ namespace SourceGit.Models set => SetProperty(ref _urlTemplate, value); } - public void Matches(List outs, string message) + public void Matches(List outs, string message) { if (_regex == null || string.IsNullOrEmpty(_urlTemplate)) return; @@ -81,8 +81,7 @@ namespace SourceGit.Models link = link.Replace($"${j}", group.Value); } - var range = new Hyperlink(start, len, link); - outs.Add(range); + outs.Add(new InlineElement(InlineElementType.Link, start, len, link)); } } diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 69b2c53d..6581d7bb 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -578,10 +578,10 @@ namespace SourceGit.ViewModels Task.Run(() => { var message = new Commands.QueryCommitFullMessage(_repo.FullPath, _commit.SHA).Result(); - var links = ParseLinksInMessage(message); + var inlines = ParseInlinesInMessage(message); if (!token.IsCancellationRequested) - Dispatcher.UIThread.Invoke(() => FullMessage = new Models.CommitFullMessage { Message = message, Links = links }); + Dispatcher.UIThread.Invoke(() => FullMessage = new Models.CommitFullMessage { Message = message, Inlines = inlines }); }); Task.Run(() => @@ -633,13 +633,13 @@ namespace SourceGit.ViewModels }); } - private List ParseLinksInMessage(string message) + private List ParseInlinesInMessage(string message) { - var links = new List(); + var inlines = new List(); if (_repo.Settings.IssueTrackerRules is { Count: > 0 } rules) { foreach (var rule in rules) - rule.Matches(links, message); + rule.Matches(inlines, message); } var matches = REG_SHA_FORMAT().Matches(message); @@ -652,7 +652,7 @@ namespace SourceGit.ViewModels var start = match.Index; var len = match.Length; var intersect = false; - foreach (var link in links) + foreach (var link in inlines) { if (link.Intersect(start, len)) { @@ -667,13 +667,13 @@ namespace SourceGit.ViewModels var sha = match.Groups[1].Value; var isCommitSHA = new Commands.IsCommitSHA(_repo.FullPath, sha).Result(); if (isCommitSHA) - links.Add(new Models.Hyperlink(start, len, sha, true)); + inlines.Add(new Models.InlineElement(Models.InlineElementType.CommitSHA, start, len, sha)); } - if (links.Count > 0) - links.Sort((l, r) => l.Start - r.Start); + if (inlines.Count > 0) + inlines.Sort((l, r) => l.Start - r.Start); - return links; + return inlines; } private void RefreshVisibleChanges() diff --git a/src/Views/CommitMessagePresenter.cs b/src/Views/CommitMessagePresenter.cs index c71c9687..0858640b 100644 --- a/src/Views/CommitMessagePresenter.cs +++ b/src/Views/CommitMessagePresenter.cs @@ -39,7 +39,7 @@ namespace SourceGit.Views if (string.IsNullOrEmpty(message)) return; - var links = FullMessage?.Links; + var links = FullMessage?.Inlines; if (links == null || links.Count == 0) { Inlines.Add(new Run(message)); @@ -54,7 +54,7 @@ namespace SourceGit.Views inlines.Add(new Run(message.Substring(pos, link.Start - pos))); var run = new Run(message.Substring(link.Start, link.Length)); - run.Classes.Add(link.IsCommitSHA ? "commit_link" : "issue_link"); + run.Classes.Add(link.Type == Models.InlineElementType.CommitSHA ? "commit_link" : "issue_link"); inlines.Add(run); pos = link.Start + link.Length; @@ -87,7 +87,7 @@ namespace SourceGit.Views scrollViewer.LineDown(); } } - else if (FullMessage is { Links: { Count: > 0 } links }) + else if (FullMessage is { Inlines: { Count: > 0 } links }) { var point = e.GetPosition(this) - new Point(Padding.Left, Padding.Top); var x = Math.Min(Math.Max(point.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0)); @@ -106,7 +106,7 @@ namespace SourceGit.Views SetCurrentValue(CursorProperty, Cursor.Parse("Hand")); _lastHover = link; - if (!link.IsCommitSHA) + if (link.Type == Models.InlineElementType.Link) ToolTip.SetTip(this, link.Link); else ProcessHoverCommitLink(link); @@ -127,7 +127,7 @@ namespace SourceGit.Views var link = _lastHover.Link; e.Pointer.Capture(null); - if (_lastHover.IsCommitSHA) + if (_lastHover.Type == Models.InlineElementType.CommitSHA) { var parentView = this.FindAncestorOfType(); if (parentView is { DataContext: ViewModels.CommitDetail detail }) @@ -252,7 +252,7 @@ namespace SourceGit.Views ClearHoveredIssueLink(); } - private void ProcessHoverCommitLink(Models.Hyperlink link) + private void ProcessHoverCommitLink(Models.InlineElement link) { var sha = link.Link; @@ -301,7 +301,7 @@ namespace SourceGit.Views } } - private Models.Hyperlink _lastHover = null; + private Models.InlineElement _lastHover = null; private Dictionary _inlineCommits = new(); } } diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index 83d79fe4..bfa2d9ea 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -1,18 +1,72 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text.RegularExpressions; + using Avalonia; using Avalonia.Collections; using Avalonia.Controls; -using Avalonia.Controls.Documents; using Avalonia.Input; using Avalonia.Media; -using Avalonia.Media.TextFormatting; namespace SourceGit.Views { - public partial class CommitSubjectPresenter : TextBlock + public partial class CommitSubjectPresenter : Control { + public static readonly StyledProperty FontFamilyProperty = + AvaloniaProperty.Register(nameof(FontFamily)); + + public FontFamily FontFamily + { + get => GetValue(FontFamilyProperty); + set => SetValue(FontFamilyProperty, value); + } + + public static readonly StyledProperty CodeFontFamilyProperty = + AvaloniaProperty.Register(nameof(CodeFontFamily)); + + public FontFamily CodeFontFamily + { + get => GetValue(CodeFontFamilyProperty); + set => SetValue(CodeFontFamilyProperty, value); + } + + public static readonly StyledProperty FontSizeProperty = + TextBlock.FontSizeProperty.AddOwner(); + + public double FontSize + { + get => GetValue(FontSizeProperty); + set => SetValue(FontSizeProperty, value); + } + + public static readonly StyledProperty FontWeightProperty = + TextBlock.FontWeightProperty.AddOwner(); + + public FontWeight FontWeight + { + get => GetValue(FontWeightProperty); + set => SetValue(FontWeightProperty, value); + } + + public static readonly StyledProperty ForegroundProperty = + AvaloniaProperty.Register(nameof(Foreground), Brushes.White); + + public IBrush Foreground + { + get => GetValue(ForegroundProperty); + set => SetValue(ForegroundProperty, value); + } + + public static readonly StyledProperty LinkForegroundProperty = + AvaloniaProperty.Register(nameof(LinkForeground), Brushes.White); + + public IBrush LinkForeground + { + get => GetValue(LinkForegroundProperty); + set => SetValue(LinkForegroundProperty, value); + } + public static readonly StyledProperty SubjectProperty = AvaloniaProperty.Register(nameof(Subject)); @@ -31,7 +85,33 @@ namespace SourceGit.Views set => SetValue(IssueTrackerRulesProperty, value); } - protected override Type StyleKeyOverride => typeof(TextBlock); + public override void Render(DrawingContext context) + { + if (_needRebuildInlines) + { + _needRebuildInlines = false; + GenerateFormattedTextElements(); + } + + if (_inlines.Count == 0) + return; + + var height = Bounds.Height; + foreach (var inline in _inlines) + { + if (inline.Element is { Type: Models.InlineElementType.Code}) + { + var rect = new Rect(inline.X, (height - inline.Text.Height - 2) * 0.5, inline.Text.WidthIncludingTrailingWhitespace + 8, inline.Text.Height + 2); + var roundedRect = new RoundedRect(rect, new CornerRadius(4)); + context.DrawRectangle(new SolidColorBrush(new Color(52, 101, 108, 118)), null, roundedRect); + context.DrawText(inline.Text, new Point(inline.X + 4, (height - inline.Text.Height) * 0.5)); + } + else + { + context.DrawText(inline.Text, new Point(inline.X, (height - inline.Text.Height) * 0.5)); + } + } + } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { @@ -39,85 +119,65 @@ namespace SourceGit.Views if (change.Property == SubjectProperty || change.Property == IssueTrackerRulesProperty) { - Inlines!.Clear(); - _matches = null; + _elements.Clear(); ClearHoveredIssueLink(); var subject = Subject; if (string.IsNullOrEmpty(subject)) + { + _inlines.Clear(); + InvalidateVisual(); return; + } var keywordMatch = REG_KEYWORD_FORMAT1().Match(subject); if (!keywordMatch.Success) keywordMatch = REG_KEYWORD_FORMAT2().Match(subject); + if (keywordMatch.Success) + _elements.Add(new Models.InlineElement(Models.InlineElementType.Keyword, 0, keywordMatch.Length, string.Empty)); + + var codeMatches = REG_INLINECODE_FORMAT().Matches(subject); + for (var i = 0; i < codeMatches.Count; i++) + { + var match = codeMatches[i]; + if (!match.Success) + continue; + + var start = match.Index; + var len = match.Length; + var intersect = false; + foreach (var exist in _elements) + { + if (exist.Intersect(start, len)) + { + intersect = true; + break; + } + } + + if (intersect) + continue; + + _elements.Add(new Models.InlineElement(Models.InlineElementType.Code, start, len, string.Empty)); + } + var rules = IssueTrackerRules ?? []; - var matches = new List(); foreach (var rule in rules) - rule.Matches(matches, subject); + rule.Matches(_elements, subject); - if (matches.Count == 0) - { - if (keywordMatch.Success) - { - Inlines.Add(new Run(subject.Substring(0, keywordMatch.Length)) { FontWeight = FontWeight.Bold }); - Inlines.Add(new Run(subject.Substring(keywordMatch.Length))); - } - else - { - Inlines.Add(new Run(subject)); - } - return; - } - - matches.Sort((l, r) => l.Start - r.Start); - _matches = matches; - - var inlines = new List(); - var pos = 0; - foreach (var match in matches) - { - if (match.Start > pos) - { - if (keywordMatch.Success && pos < keywordMatch.Length) - { - if (keywordMatch.Length < match.Start) - { - inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold }); - inlines.Add(new Run(subject.Substring(keywordMatch.Length, match.Start - keywordMatch.Length))); - } - else - { - inlines.Add(new Run(subject.Substring(pos, match.Start - pos)) { FontWeight = FontWeight.Bold }); - } - } - else - { - inlines.Add(new Run(subject.Substring(pos, match.Start - pos))); - } - } - - var link = new Run(subject.Substring(match.Start, match.Length)); - link.Classes.Add("issue_link"); - inlines.Add(link); - - pos = match.Start + match.Length; - } - - if (pos < subject.Length) - { - if (keywordMatch.Success && pos < keywordMatch.Length) - { - inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold }); - inlines.Add(new Run(subject.Substring(keywordMatch.Length))); - } - else - { - inlines.Add(new Run(subject.Substring(pos))); - } - } - - Inlines.AddRange(inlines); + _needRebuildInlines = true; + InvalidateVisual(); + } + else if (change.Property == FontFamilyProperty || + change.Property == CodeFontFamilyProperty || + change.Property == FontSizeProperty || + change.Property == FontWeightProperty || + change.Property == ForegroundProperty || + change.Property == LinkForegroundProperty) + { + _needRebuildInlines = true; + InvalidateVisual(); } } @@ -125,31 +185,23 @@ namespace SourceGit.Views { base.OnPointerMoved(e); - if (_matches != null) + var point = e.GetPosition(this); + foreach (var inline in _inlines) { - var point = e.GetPosition(this) - new Point(Padding.Left, Padding.Top); - var x = Math.Min(Math.Max(point.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0)); - var y = Math.Min(Math.Max(point.Y, 0), Math.Max(TextLayout.Height, 0)); - point = new Point(x, y); + if (inline.Element is not { Type: Models.InlineElementType.Link } link) + continue; - var textPosition = TextLayout.HitTestPoint(point).TextPosition; - foreach (var match in _matches) - { - if (!match.Intersect(textPosition, 1)) - continue; + if (inline.X > point.X || inline.X + inline.Text.WidthIncludingTrailingWhitespace < point.X) + continue; - if (match == _lastHover) - return; - - _lastHover = match; - SetCurrentValue(CursorProperty, Cursor.Parse("Hand")); - ToolTip.SetTip(this, match.Link); - e.Handled = true; - return; - } - - ClearHoveredIssueLink(); + _lastHover = link; + SetCurrentValue(CursorProperty, Cursor.Parse("Hand")); + ToolTip.SetTip(this, link.Link); + e.Handled = true; + return; } + + ClearHoveredIssueLink(); } protected override void OnPointerPressed(PointerPressedEventArgs e) @@ -166,6 +218,94 @@ namespace SourceGit.Views ClearHoveredIssueLink(); } + private void GenerateFormattedTextElements() + { + _inlines.Clear(); + + var subject = Subject; + if (string.IsNullOrEmpty(subject)) + return; + + var fontFamily = FontFamily; + var codeFontFamily = CodeFontFamily; + var fontSize = FontSize; + var foreground = Foreground; + var linkForeground = LinkForeground; + var typeface = new Typeface(fontFamily, FontStyle.Normal, FontWeight); + var codeTypeface = new Typeface(codeFontFamily, FontStyle.Normal, FontWeight); + var pos = 0; + var x = 0.0; + foreach (var elem in _elements) + { + if (elem.Start > pos) + { + var normal = new FormattedText( + subject.Substring(pos, elem.Start - pos), + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + typeface, + fontSize, + foreground); + + _inlines.Add(new Inline(x, normal, null)); + x += normal.WidthIncludingTrailingWhitespace; + } + + if (elem.Type == Models.InlineElementType.Keyword) + { + var keyword = new FormattedText( + subject.Substring(elem.Start, elem.Length), + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface(fontFamily, FontStyle.Normal, FontWeight.Bold), + fontSize, + foreground); + _inlines.Add(new Inline(x, keyword, elem)); + x += keyword.WidthIncludingTrailingWhitespace; + } + else if (elem.Type == Models.InlineElementType.Link) + { + var link = new FormattedText( + subject.Substring(elem.Start, elem.Length), + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + typeface, + fontSize, + linkForeground); + _inlines.Add(new Inline(x, link, elem)); + x += link.WidthIncludingTrailingWhitespace; + } + else if (elem.Type == Models.InlineElementType.Code) + { + var link = new FormattedText( + subject.Substring(elem.Start + 1, elem.Length - 2), + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + codeTypeface, + fontSize, + foreground); + _inlines.Add(new Inline(x, link, elem)); + x += link.WidthIncludingTrailingWhitespace + 8; + } + + pos = elem.Start + elem.Length; + } + + if (pos < subject.Length) + { + var normal = new FormattedText( + subject.Substring(pos), + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + typeface, + fontSize, + foreground); + + _inlines.Add(new Inline(x, normal, null)); + x += normal.WidthIncludingTrailingWhitespace; + } + } + private void ClearHoveredIssueLink() { if (_lastHover != null) @@ -176,13 +316,32 @@ namespace SourceGit.Views } } + [GeneratedRegex(@"`.*?`")] + private static partial Regex REG_INLINECODE_FORMAT(); + [GeneratedRegex(@"^\[[\w\s]+\]")] private static partial Regex REG_KEYWORD_FORMAT1(); [GeneratedRegex(@"^\S+([\<\(][\w\s_\-\*,]+[\>\)])?\!?\s?:\s")] private static partial Regex REG_KEYWORD_FORMAT2(); - private List _matches = null; - private Models.Hyperlink _lastHover = null; + private class Inline + { + public double X { get; set; } = 0; + public FormattedText Text { get; set; } = null; + public Models.InlineElement Element { get; set; } = null; + + public Inline(double x, FormattedText text, Models.InlineElement elem) + { + X = x; + Text = text; + Element = elem; + } + } + + private List _elements = []; + private List _inlines = []; + private Models.InlineElement _lastHover = null; + private bool _needRebuildInlines = false; } } diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index c6c43aa9..2f5e2ffd 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -160,7 +160,10 @@ Date: Fri, 25 Apr 2025 13:30:00 +0800 Subject: [PATCH 33/45] enhance: stop render next inline elements when it is out of bounds Signed-off-by: leo --- src/Views/CommitSubjectPresenter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index bfa2d9ea..d1aeab3f 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -97,8 +97,12 @@ namespace SourceGit.Views return; var height = Bounds.Height; + var width = Bounds.Width; foreach (var inline in _inlines) { + if (inline.X > width) + return; + if (inline.Element is { Type: Models.InlineElementType.Code}) { var rect = new Rect(inline.X, (height - inline.Text.Height - 2) * 0.5, inline.Text.WidthIncludingTrailingWhitespace + 8, inline.Text.Height + 2); From a94c7f55cea48962374948f7557aafa30952fbb8 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 25 Apr 2025 13:37:11 +0800 Subject: [PATCH 34/45] ux: remove tips in commit list Signed-off-by: leo --- src/Views/Histories.axaml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index 2f5e2ffd..e58d8349 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -126,11 +126,7 @@ - + - + Date: Fri, 25 Apr 2025 14:31:14 +0800 Subject: [PATCH 35/45] code_style: run `dotnet format` Signed-off-by: leo --- src/Views/CommitSubjectPresenter.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index d1aeab3f..d00d3951 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Text.RegularExpressions; @@ -91,7 +90,7 @@ namespace SourceGit.Views { _needRebuildInlines = false; GenerateFormattedTextElements(); - } + } if (_inlines.Count == 0) return; @@ -103,7 +102,7 @@ namespace SourceGit.Views if (inline.X > width) return; - if (inline.Element is { Type: Models.InlineElementType.Code}) + if (inline.Element is { Type: Models.InlineElementType.Code }) { var rect = new Rect(inline.X, (height - inline.Text.Height - 2) * 0.5, inline.Text.WidthIncludingTrailingWhitespace + 8, inline.Text.Height + 2); var roundedRect = new RoundedRect(rect, new CornerRadius(4)); @@ -129,7 +128,7 @@ namespace SourceGit.Views var subject = Subject; if (string.IsNullOrEmpty(subject)) { - _inlines.Clear(); + _needRebuildInlines = true; InvalidateVisual(); return; } From 00e56ce9d139da58493f3193eb70ec3d510f2577 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 25 Apr 2025 15:56:37 +0800 Subject: [PATCH 36/45] fix: `System.NullReferenceException` raised after popup stop (success or not) running Signed-off-by: leo --- src/Views/PopupRunningStatus.axaml | 3 +-- src/Views/PopupRunningStatus.axaml.cs | 14 ++++---------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/Views/PopupRunningStatus.axaml b/src/Views/PopupRunningStatus.axaml index a8467415..6a0dbdb4 100644 --- a/src/Views/PopupRunningStatus.axaml +++ b/src/Views/PopupRunningStatus.axaml @@ -15,8 +15,7 @@
- Date: Fri, 25 Apr 2025 10:56:28 +0200 Subject: [PATCH 37/45] fix: Append UserName to the SourceGitIPCChannel NamedPipeServerStream to allow multiple users usage on the same server (#1244) (#1246) --- src/Models/IpcChannel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs index 2ecfb771..d47a46bd 100644 --- a/src/Models/IpcChannel.cs +++ b/src/Models/IpcChannel.cs @@ -22,7 +22,7 @@ namespace SourceGit.Models _singletoneLock = File.Open(Path.Combine(Native.OS.DataDir, "process.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); _isFirstInstance = true; _server = new NamedPipeServerStream( - "SourceGitIPCChannel", + "SourceGitIPCChannel" + Environment.UserName, PipeDirection.In, -1, PipeTransmissionMode.Byte, @@ -40,7 +40,7 @@ namespace SourceGit.Models { try { - using (var client = new NamedPipeClientStream(".", "SourceGitIPCChannel", PipeDirection.Out)) + using (var client = new NamedPipeClientStream(".", "SourceGitIPCChannel" + Environment.UserName, PipeDirection.Out, PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly)) { client.Connect(1000); if (!client.IsConnected) From d44d2b977042ad2e1ded55b6ed52202fe5703a35 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 25 Apr 2025 18:50:56 +0800 Subject: [PATCH 38/45] ux: use a outer border to hold tooltip of commit message in `FileHistories` view (#1232) Signed-off-by: leo --- src/Views/FileHistories.axaml | 9 +++------ src/Views/FileHistories.axaml.cs | 10 +++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml index f597fc04..e7a5c072 100644 --- a/src/Views/FileHistories.axaml +++ b/src/Views/FileHistories.axaml @@ -93,12 +93,9 @@ - + + +
diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs index a183182e..3631eb71 100644 --- a/src/Views/FileHistories.axaml.cs +++ b/src/Views/FileHistories.axaml.cs @@ -62,18 +62,18 @@ namespace SourceGit.Views private void OnCommitSubjectDataContextChanged(object sender, EventArgs e) { - if (sender is TextBlock textBlock) - ToolTip.SetTip(textBlock, null); + if (sender is Border border) + ToolTip.SetTip(border, null); } private void OnCommitSubjectPointerMoved(object sender, PointerEventArgs e) { - if (sender is TextBlock { DataContext: Models.Commit commit } textBlock && + if (sender is Border { DataContext: Models.Commit commit } border && DataContext is ViewModels.FileHistories vm) { - var tooltip = ToolTip.GetTip(textBlock); + var tooltip = ToolTip.GetTip(border); if (tooltip == null) - ToolTip.SetTip(textBlock, vm.GetCommitFullMessage(commit)); + ToolTip.SetTip(border, vm.GetCommitFullMessage(commit)); } } } From 91acf0a32a9cee70ef125cb5c8a88a8e4979a8b7 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 25 Apr 2025 20:55:11 +0800 Subject: [PATCH 39/45] enhance: fore invalidate measure after data context of `BisectStateIndicator` changed Signed-off-by: leo --- src/Models/Bisect.cs | 4 +++- src/Views/BisectStateIndicator.cs | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Models/Bisect.cs b/src/Models/Bisect.cs index 3dd28681..d1021113 100644 --- a/src/Models/Bisect.cs +++ b/src/Models/Bisect.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace SourceGit.Models { @@ -9,6 +10,7 @@ namespace SourceGit.Models Detecting, } + [Flags] public enum BisectCommitFlag { None = 0, diff --git a/src/Views/BisectStateIndicator.cs b/src/Views/BisectStateIndicator.cs index c93192a6..0a581f53 100644 --- a/src/Views/BisectStateIndicator.cs +++ b/src/Views/BisectStateIndicator.cs @@ -65,6 +65,12 @@ namespace SourceGit.Views RenderImpl(context, Brushes.Red, _bad, x); } + protected override void OnDataContextChanged(EventArgs e) + { + base.OnDataContextChanged(e); + InvalidateMeasure(); + } + protected override Size MeasureOverride(Size availableSize) { var desiredFlags = Models.BisectCommitFlag.None; From d2e688908c107e3daf5246be8bf2f6532a84eada Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 25 Apr 2025 21:26:21 +0800 Subject: [PATCH 40/45] ux: use different inline code background for different themes Signed-off-by: leo --- src/Resources/Themes.axaml | 3 +++ src/Views/CommitSubjectPresenter.cs | 15 ++++++++++++++- src/Views/Histories.axaml | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Resources/Themes.axaml b/src/Resources/Themes.axaml index ff4c0374..f33e71d2 100644 --- a/src/Resources/Themes.axaml +++ b/src/Resources/Themes.axaml @@ -25,6 +25,7 @@ #A7E1A7 #F19B9D #0000EE + #FFE5E5E5 @@ -51,6 +52,7 @@ #A0308D3C #A09F4247 #4DAAFC + #FF2E2E2E @@ -79,6 +81,7 @@ + fonts:Inter#Inter fonts:SourceGit#JetBrains Mono diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index d00d3951..abb08a3b 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -47,6 +47,15 @@ namespace SourceGit.Views get => GetValue(FontWeightProperty); set => SetValue(FontWeightProperty, value); } + + public static readonly StyledProperty InlineCodeBackgroundProperty = + AvaloniaProperty.Register(nameof(InlineCodeBackground), Brushes.Transparent); + + public IBrush InlineCodeBackground + { + get => GetValue(InlineCodeBackgroundProperty); + set => SetValue(InlineCodeBackgroundProperty, value); + } public static readonly StyledProperty ForegroundProperty = AvaloniaProperty.Register(nameof(Foreground), Brushes.White); @@ -106,7 +115,7 @@ namespace SourceGit.Views { var rect = new Rect(inline.X, (height - inline.Text.Height - 2) * 0.5, inline.Text.WidthIncludingTrailingWhitespace + 8, inline.Text.Height + 2); var roundedRect = new RoundedRect(rect, new CornerRadius(4)); - context.DrawRectangle(new SolidColorBrush(new Color(52, 101, 108, 118)), null, roundedRect); + context.DrawRectangle(InlineCodeBackground, null, roundedRect); context.DrawText(inline.Text, new Point(inline.X + 4, (height - inline.Text.Height) * 0.5)); } else @@ -182,6 +191,10 @@ namespace SourceGit.Views _needRebuildInlines = true; InvalidateVisual(); } + else if (change.Property == InlineCodeBackgroundProperty) + { + InvalidateVisual(); + } } protected override void OnPointerMoved(PointerEventArgs e) diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index e58d8349..568854fd 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -158,6 +158,7 @@ Date: Sun, 27 Apr 2025 04:38:09 +0300 Subject: [PATCH 41/45] locallization: update russian translate (#1248) --- src/Resources/Locales/ru_RU.axaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 35125369..a3fe2b3a 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -501,6 +501,7 @@ Электроная почта пользователя Общая электроная почта пользователя git Разрешить (--prune) при скачивании + Разрешить (--ignore-cr-at-eol) в различии Для работы программы требуется версия Git (>= 2.23.0) Путь установки Разрешить верификацию HTTP SSL From f39048df773b5f01dee85f153642bf1240ebb44a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 27 Apr 2025 01:38:20 +0000 Subject: [PATCH 42/45] doc: Update translation status and sort locale files --- TRANSLATION.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index e2693e64..21706eb2 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -264,14 +264,7 @@ 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) - -
-Missing keys in ru_RU.axaml - -- Text.Preferences.Git.IgnoreCRAtEOLInDiff - -
+### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) ### ![ta__IN](https://img.shields.io/badge/ta__IN-96.49%25-yellow) From 21cb87cec5c27c0c4627379f44235ff27d08a076 Mon Sep 17 00:00:00 2001 From: Chiahong <36815907+ChiahongHong@users.noreply.github.com> Date: Sun, 27 Apr 2025 09:38:28 +0800 Subject: [PATCH 43/45] localization: update zh_TW.axaml (#1249) --- src/Resources/Locales/zh_TW.axaml | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 63052d35..181adb69 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -40,13 +40,13 @@ 沒有不追蹤變更的檔案 移除 二進位檔案不支援該操作! - 二元搜尋 (bisect) + 二分搜尋 (bisect) 中止 標記為錯誤 - 二元搜尋進行中。目前的提交是「良好」是「錯誤」? + 二分搜尋進行中。目前的提交是「良好」是「錯誤」? 標記為良好 無法確認 - 二元搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後簽出另一個提交。 + 二分搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後簽出另一個提交。 逐行溯源 (blame) 所選擇的檔案不支援該操作! 簽出 (checkout) ${0}$... @@ -69,7 +69,7 @@ 重新命名 ${0}$... 切換上游分支... 分支比較 - 追蹤上游分支不存在或已刪除! + 追蹤上游分支不存在或已刪除! 位元組 取 消 重設檔案到上一版本 @@ -168,7 +168,7 @@ 啟用定時自動提取 (fetch) 遠端更新 分鐘 預設遠端存放庫 - 首選合併模式 + 預設合併模式 Issue 追蹤 新增符合 Azure DevOps 規則 新增符合 Gitee 議題規則 @@ -193,10 +193,10 @@ 顏色 名稱 啟動時還原上次開啟的存放庫 - 确认继续 + 確認繼續 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)? - 自动暂存并提交 - 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)或者自動暫存全部變更並提交? + 自動暫存並提交 + 未包含任何檔案變更! 您是否仍要提交 (--allow-empty) 或者自動暫存全部變更並提交? 產生約定式提交訊息 破壞性變更: 關閉的 Issue: @@ -257,7 +257,7 @@ 複製 檔案權限已變更 第一個差異 - 忽略空白符號變化和EOL + 忽略空白符號變化和 EOL 最後一個差異 LFS 物件變更 下一個差異 @@ -313,8 +313,8 @@ 取消暫存 從暫存中移除 {0} 個檔案 取消暫存選取的變更 - 使用我方版本 (checkout --ours) - 使用對方版本 (checkout --theirs) + 使用我方版本 (ours) + 使用對方版本 (theirs) 檔案歷史 檔案變更 檔案内容 @@ -472,7 +472,7 @@ 啟用串流輸出 外觀設定 預設字型 - 編輯器制表符寬度 + 編輯器 Tab 寬度 字型大小 預設 程式碼 @@ -627,7 +627,7 @@ 排序 在終端機中開啟 在提交列表中使用相對時間 - 檢視 GIT 指令的日誌 + 檢視 Git 指令記錄 工作區列表 新增工作區 清理 @@ -713,8 +713,8 @@ 子模組: 啟用 [--remote] 選項 存放庫網址: - 日誌清單 - 清除所有日誌 + 記錄 + 清除所有記錄 複製 刪除 警告 @@ -746,13 +746,13 @@ 觸發點擊事件 提交 (修改原始提交) 自動暫存全部變更並提交 - 您已暫存 {0} 檔案,但只顯示 {1} 檔案 ({2} 檔案被篩選器隱藏)。您要繼續嗎? - 檢測到衝突 + 您已暫存 {0} 個檔案,但只顯示 {1} 個檔案 ({2} 個檔案被篩選器隱藏)。您確定要繼續提交嗎? + 偵測到衝突 使用外部合併工具開啟 使用外部合併工具開啟 檔案衝突已解決 - 使用 MINE - 使用 THEIRS + 使用我方版本 (ours) + 使用對方版本 (theirs) 顯示未追蹤檔案 沒有提交訊息記錄 沒有可套用的提交訊息範本 From 951ea8f0887e9653279721dbb948f07926aa2a48 Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 27 Apr 2025 11:20:44 +0800 Subject: [PATCH 44/45] fix: use subject as context menu item header to fix vertical alignment (#1251) Signed-off-by: leo --- src/ViewModels/WorkingCopy.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 63d6df47..4d35b5c2 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1449,9 +1449,11 @@ namespace SourceGit.ViewModels { for (int i = 0; i < historiesCount; i++) { - var message = _repo.Settings.CommitMessages[i]; + var message = _repo.Settings.CommitMessages[i].Trim().ReplaceLineEndings("\n"); + var subjectEndIdx = message.IndexOf('\n'); + var subject = subjectEndIdx > 0 ? message.Substring(0, subjectEndIdx) : message; var item = new MenuItem(); - item.Header = message; + item.Header = subject; item.Icon = App.CreateMenuIcon("Icons.Histories"); item.Click += (_, e) => { From 2e1cf76c8295b6f325348522fe850f183b166108 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 28 Apr 2025 09:16:37 +0800 Subject: [PATCH 45/45] version: Release 2025.15 Signed-off-by: leo --- VERSION | 2 +- src/Views/CommitSubjectPresenter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 89f9e970..70f2a59f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2025.14 \ No newline at end of file +2025.15 \ No newline at end of file diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index abb08a3b..f64323c0 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -47,7 +47,7 @@ namespace SourceGit.Views get => GetValue(FontWeightProperty); set => SetValue(FontWeightProperty, value); } - + public static readonly StyledProperty InlineCodeBackgroundProperty = AvaloniaProperty.Register(nameof(InlineCodeBackground), Brushes.Transparent);