From ed66d2337b2db3920decb82872a6874ee078ee83 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 16 Jun 2025 12:09:02 +0800 Subject: [PATCH 01/47] ux: show stash message as tooltip when hovering it (#1419) Signed-off-by: leo --- src/Views/StashesPage.axaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Views/StashesPage.axaml b/src/Views/StashesPage.axaml index 30c6e183..daa1ccc7 100644 --- a/src/Views/StashesPage.axaml +++ b/src/Views/StashesPage.axaml @@ -84,7 +84,11 @@ - + From e28b537f899e81b35b5f58e99763ee7d4fcc600f Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Mon, 16 Jun 2025 14:19:14 +1000 Subject: [PATCH 02/47] enhance: darker `ChangeStatusIcon` when using dark theme (#1423) --- src/Views/ChangeStatusIcon.cs | 86 ++++++++++++----------------------- 1 file changed, 30 insertions(+), 56 deletions(-) diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs index d66ac11d..ea88dbb5 100644 --- a/src/Views/ChangeStatusIcon.cs +++ b/src/Views/ChangeStatusIcon.cs @@ -4,57 +4,24 @@ using System.Globalization; using Avalonia; using Avalonia.Controls; using Avalonia.Media; +using Avalonia.Styling; namespace SourceGit.Views { public class ChangeStatusIcon : Control { private static readonly string[] INDICATOR = ["?", "±", "T", "+", "−", "➜", "❏", "★", "!"]; - private static readonly IBrush[] BACKGROUNDS = [ - Brushes.Transparent, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Colors.Tomato, 0), new GradientStop(Color.FromRgb(252, 165, 150), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Colors.Orchid, 0), new GradientStop(Color.FromRgb(248, 161, 245), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(238, 160, 14), 0), new GradientStop(Color.FromRgb(228, 172, 67), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - new LinearGradientBrush - { - GradientStops = new GradientStops() { new GradientStop(Color.FromRgb(47, 185, 47), 0), new GradientStop(Color.FromRgb(75, 189, 75), 1) }, - StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), - EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), - }, - Brushes.OrangeRed, + private static readonly Color[] COLOR = + [ + Colors.Transparent, + Colors.Goldenrod, + Colors.Goldenrod, + Colors.LimeGreen, + Colors.Tomato, + Colors.Orchid, + Colors.Goldenrod, + Colors.LimeGreen, + Colors.OrangeRed, ]; public static readonly StyledProperty IsUnstagedChangeProperty = @@ -75,6 +42,11 @@ namespace SourceGit.Views set => SetValue(ChangeProperty, value); } + public ChangeStatusIcon() + { + ActualThemeVariantChanged += (_, _) => InvalidateVisual(); + } + public override void Render(DrawingContext context) { if (Change == null || Bounds.Width <= 0) @@ -82,18 +54,20 @@ namespace SourceGit.Views var typeface = new Typeface("fonts:SourceGit#JetBrains Mono"); - IBrush background; - string indicator; - if (IsUnstagedChange) + var idx = (int)(IsUnstagedChange ? Change.WorkTree : Change.Index); + var indicator = INDICATOR[idx]; + var color = COLOR[idx]; + var hsl = color.ToHsl(); + var color2 = ActualThemeVariant == ThemeVariant.Dark + ? new HslColor(hsl.A, hsl.H,hsl.S, hsl.L - 0.1).ToRgb() + : new HslColor(hsl.A, hsl.H,hsl.S, hsl.L + 0.1).ToRgb(); + + var background = new LinearGradientBrush { - background = BACKGROUNDS[(int)Change.WorkTree]; - indicator = INDICATOR[(int)Change.WorkTree]; - } - else - { - background = BACKGROUNDS[(int)Change.Index]; - indicator = INDICATOR[(int)Change.Index]; - } + GradientStops = [new GradientStop(color, 0), new GradientStop(color2, 1)], + StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), + EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative), + }; var txt = new FormattedText( indicator, From dcdc52592c1a2b19fff45098cb6e843d126eaf7e Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 16 Jun 2025 12:31:37 +0800 Subject: [PATCH 03/47] code_review: PR #1423 Since we have already used `OnPropertyChanged`, move `ActualThemeVariantProperty` changed handler into it Signed-off-by: leo --- src/Views/ChangeStatusIcon.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs index ea88dbb5..8d43acac 100644 --- a/src/Views/ChangeStatusIcon.cs +++ b/src/Views/ChangeStatusIcon.cs @@ -42,11 +42,6 @@ namespace SourceGit.Views set => SetValue(ChangeProperty, value); } - public ChangeStatusIcon() - { - ActualThemeVariantChanged += (_, _) => InvalidateVisual(); - } - public override void Render(DrawingContext context) { if (Change == null || Bounds.Width <= 0) @@ -87,7 +82,9 @@ namespace SourceGit.Views { base.OnPropertyChanged(change); - if (change.Property == IsUnstagedChangeProperty || change.Property == ChangeProperty) + if (change.Property == IsUnstagedChangeProperty || + change.Property == ChangeProperty || + (change.Property.Name == "ActualThemeVariant" && change.NewValue != null)) InvalidateVisual(); } } From e102e49f4594ca23c20cde096855084962c40b9d Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Jun 2025 11:29:24 +0800 Subject: [PATCH 04/47] code_style: remove unnecessary properties Signed-off-by: leo --- src/ViewModels/Histories.cs | 5 ----- src/Views/Histories.axaml | 4 ++-- src/Views/Histories.axaml.cs | 11 +---------- src/Views/Repository.axaml | 7 +++---- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index db368d80..8f427b54 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -14,11 +14,6 @@ namespace SourceGit.ViewModels { public class Histories : ObservableObject, IDisposable { - public Repository Repo - { - get => _repo; - } - public bool IsLoading { get => _isLoading; diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index 7afe12fa..d19edd0e 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -34,7 +34,7 @@ - + @@ -120,7 +120,7 @@ - + diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 18630e4c..919f8fdb 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -73,15 +73,6 @@ namespace SourceGit.Views public partial class Histories : UserControl { - public static readonly StyledProperty AuthorNameColumnWidthProperty = - AvaloniaProperty.Register(nameof(AuthorNameColumnWidth), new GridLength(120)); - - public GridLength AuthorNameColumnWidth - { - get => GetValue(AuthorNameColumnWidthProperty); - set => SetValue(AuthorNameColumnWidthProperty, value); - } - public static readonly StyledProperty CurrentBranchProperty = AvaloniaProperty.Register(nameof(CurrentBranch)); @@ -150,7 +141,7 @@ namespace SourceGit.Views private void OnCommitListLayoutUpdated(object _1, EventArgs _2) { var y = CommitListContainer.Scroll?.Offset.Y ?? 0; - var authorNameColumnWidth = AuthorNameColumnWidth.Value; + var authorNameColumnWidth = ViewModels.Preferences.Instance.Layout.HistoriesAuthorColumnWidth.Value; if (y != _lastScrollY || authorNameColumnWidth != _lastAuthorNameColumnWidth) { _lastScrollY = y; diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index f1f3fccc..6b26f476 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -829,11 +829,10 @@ - From efa6e46471bd7a700c3fb3c71a54e06b1034342f Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Jun 2025 12:20:02 +0800 Subject: [PATCH 05/47] feature: add a button to open current revision file with default editor Signed-off-by: leo --- src/ViewModels/CommitDetail.cs | 32 +++++++++++++++++++++++++++----- src/Views/RevisionFiles.axaml | 14 ++++++++++++-- src/Views/RevisionFiles.axaml.cs | 9 +++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index fbecf30e..65719293 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -133,6 +133,12 @@ namespace SourceGit.ViewModels private set => SetProperty(ref _revisionFileSearchSuggestion, value); } + public bool CanOpenRevisionFileWithDefaultEditor + { + get => _canOpenRevisionFileWithDefaultEditor; + private set => SetProperty(ref _canOpenRevisionFileWithDefaultEditor, value); + } + public CommitDetail(Repository repo) { _repo = repo; @@ -197,6 +203,7 @@ namespace SourceGit.ViewModels { ViewRevisionFilePath = string.Empty; ViewRevisionFileContent = null; + CanOpenRevisionFileWithDefaultEditor = false; return; } @@ -205,6 +212,7 @@ namespace SourceGit.ViewModels switch (file.Type) { case Models.ObjectType.Blob: + CanOpenRevisionFileWithDefaultEditor = true; Task.Run(() => { var isBinary = new Commands.IsBinary(_repo.FullPath, _commit.SHA, file.Path).Result(); @@ -252,6 +260,7 @@ namespace SourceGit.ViewModels }); break; case Models.ObjectType.Commit: + CanOpenRevisionFileWithDefaultEditor = false; Task.Run(() => { var submoduleRoot = Path.Combine(_repo.FullPath, file.Path).Replace('\\', '/').Trim('/'); @@ -267,11 +276,26 @@ namespace SourceGit.ViewModels }); break; default: + CanOpenRevisionFileWithDefaultEditor = false; ViewRevisionFileContent = null; break; } } + public Task OpenRevisionFileWithDefaultEditor(string file) + { + return Task.Run(() => + { + var fullPath = Native.OS.GetAbsPath(_repo.FullPath, file); + var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; + var fileExt = Path.GetExtension(fullPath) ?? ""; + var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}"); + + Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file, tmpFile); + Native.OS.OpenWithDefaultEditor(tmpFile); + }); + } + public ContextMenu CreateChangeContextMenu(Models.Change change) { var diffWithMerger = new MenuItem(); @@ -421,13 +445,10 @@ namespace SourceGit.ViewModels var openWith = new MenuItem(); openWith.Header = App.Text("OpenWith"); openWith.Icon = App.CreateMenuIcon("Icons.OpenWith"); + openWith.IsEnabled = file.Type == Models.ObjectType.Blob; openWith.Click += async (_, ev) => { - var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; - var fileExt = Path.GetExtension(fullPath) ?? ""; - var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_commit.SHA.Substring(0, 10)}{fileExt}"); - await Task.Run(() => Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, tmpFile)); - Native.OS.OpenWithDefaultEditor(tmpFile); + await OpenRevisionFileWithDefaultEditor(file.Path); ev.Handled = true; }; @@ -887,5 +908,6 @@ namespace SourceGit.ViewModels private List _revisionFiles = null; private string _revisionFileSearchFilter = string.Empty; private List _revisionFileSearchSuggestion = null; + private bool _canOpenRevisionFileWithDefaultEditor = false; } } diff --git a/src/Views/RevisionFiles.axaml b/src/Views/RevisionFiles.axaml index 5b512060..961a05b5 100644 --- a/src/Views/RevisionFiles.axaml +++ b/src/Views/RevisionFiles.axaml @@ -119,7 +119,7 @@ Height="26" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" IsVisible="{Binding ViewRevisionFilePath, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"> - + - + + + diff --git a/src/Views/RevisionFiles.axaml.cs b/src/Views/RevisionFiles.axaml.cs index 3208fbb8..4894d1d4 100644 --- a/src/Views/RevisionFiles.axaml.cs +++ b/src/Views/RevisionFiles.axaml.cs @@ -1,5 +1,6 @@ using Avalonia.Controls; using Avalonia.Input; +using Avalonia.Interactivity; namespace SourceGit.Views { @@ -80,5 +81,13 @@ namespace SourceGit.Views e.Handled = true; } + + private async void OnOpenFileWithDefaultEditor(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.CommitDetail { CanOpenRevisionFileWithDefaultEditor: true } vm) + await vm.OpenRevisionFileWithDefaultEditor(vm.ViewRevisionFilePath); + + e.Handled = true; + } } } From df7375313e49d82f217650d38299e316f24c2537 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Jun 2025 14:12:00 +0800 Subject: [PATCH 06/47] enhance: clear last view revision file info after commit changed Signed-off-by: leo --- src/ViewModels/CommitDetail.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 65719293..decd27dc 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -570,6 +570,8 @@ namespace SourceGit.ViewModels SignInfo = null; ViewRevisionFileContent = null; + ViewRevisionFilePath = string.Empty; + CanOpenRevisionFileWithDefaultEditor = false; Children = null; RevisionFileSearchFilter = string.Empty; RevisionFileSearchSuggestion = null; From a8da8c09acb74886304a696c9ec98addf2d0dea6 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Jun 2025 14:44:12 +0800 Subject: [PATCH 07/47] feature: add a button to open current revision file with default editor in `FileHistories` Signed-off-by: leo --- src/ViewModels/FileHistories.cs | 34 ++++++++++++++++++++++++-------- src/Views/FileHistories.axaml | 11 ++++++++++- src/Views/FileHistories.axaml.cs | 8 ++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs index c3e5aac1..b901700f 100644 --- a/src/ViewModels/FileHistories.cs +++ b/src/ViewModels/FileHistories.cs @@ -9,10 +9,11 @@ using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels { - public class FileHistoriesRevisionFile(string path, object content) + public class FileHistoriesRevisionFile(string path, object content = null, bool canOpenWithDefaultEditor = false) { public string Path { get; set; } = path; public object Content { get; set; } = content; + public bool CanOpenWithDefaultEditor { get; set; } = canOpenWithDefaultEditor; } public class FileHistoriesSingleRevision : ObservableObject @@ -49,6 +50,23 @@ namespace SourceGit.ViewModels return Task.Run(() => new Commands.Checkout(_repo.FullPath).FileWithRevision(_file, $"{_revision.SHA}")); } + public Task OpenWithDefaultEditor() + { + if (_viewContent is not FileHistoriesRevisionFile { CanOpenWithDefaultEditor: true }) + return null; + + return Task.Run(() => + { + var fullPath = Native.OS.GetAbsPath(_repo.FullPath, _file); + var fileName = Path.GetFileNameWithoutExtension(fullPath) ?? ""; + var fileExt = Path.GetExtension(fullPath) ?? ""; + var tmpFile = Path.Combine(Path.GetTempPath(), $"{fileName}~{_revision.SHA.Substring(0, 10)}{fileExt}"); + + Commands.SaveRevisionFile.Run(_repo.FullPath, _revision.SHA, _file, tmpFile); + Native.OS.OpenWithDefaultEditor(tmpFile); + }); + } + private void RefreshViewContent() { if (_isDiffMode) @@ -62,7 +80,7 @@ namespace SourceGit.ViewModels var objs = new Commands.QueryRevisionObjects(_repo.FullPath, _revision.SHA, _file).Result(); if (objs.Count == 0) { - ViewContent = new FileHistoriesRevisionFile(_file, null); + ViewContent = new FileHistoriesRevisionFile(_file); return; } @@ -80,13 +98,13 @@ namespace SourceGit.ViewModels { var source = ImageSource.FromRevision(_repo.FullPath, _revision.SHA, _file, imgDecoder); var image = new Models.RevisionImageFile(_file, source.Bitmap, source.Size); - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image)); + Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, image, true)); } else { var size = new Commands.QueryFileSize(_repo.FullPath, _file, _revision.SHA).Result(); var binaryFile = new Models.RevisionBinaryFile() { Size = size }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile)); + Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, binaryFile, true)); } return; @@ -101,18 +119,18 @@ namespace SourceGit.ViewModels if (imgDecoder != Models.ImageDecoder.None) { var combined = new RevisionLFSImage(_repo.FullPath, _file, lfs, imgDecoder); - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, combined)); + Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, combined, true)); } else { var rlfs = new Models.RevisionLFSObject() { Object = lfs }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs)); + Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, rlfs, true)); } } else { var txt = new Models.RevisionTextFile() { FileName = obj.Path, Content = content }; - Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, txt)); + Dispatcher.UIThread.Invoke(() => ViewContent = new FileHistoriesRevisionFile(_file, txt, true)); } }); break; @@ -132,7 +150,7 @@ namespace SourceGit.ViewModels }); break; default: - ViewContent = new FileHistoriesRevisionFile(_file, null); + ViewContent = new FileHistoriesRevisionFile(_file); break; } } diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml index be0c91a0..790f1ba7 100644 --- a/src/Views/FileHistories.axaml +++ b/src/Views/FileHistories.axaml @@ -139,7 +139,7 @@ - + + diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs index 3e7d5dc6..6a67d120 100644 --- a/src/Views/FileHistories.axaml.cs +++ b/src/Views/FileHistories.axaml.cs @@ -76,5 +76,13 @@ namespace SourceGit.Views ToolTip.SetTip(border, vm.GetCommitFullMessage(commit)); } } + + private async void OnOpenFileWithDefaultEditor(object sender, RoutedEventArgs e) + { + if (DataContext is ViewModels.FileHistories { ViewContent: ViewModels.FileHistoriesSingleRevision revision }) + await revision.OpenWithDefaultEditor(); + + e.Handled = true; + } } } From 90310a704db19e248d5ba1b09ea4775ff2f7d006 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Jun 2025 15:07:55 +0800 Subject: [PATCH 08/47] feature: supports to customize merge message (`--edit`) (#1421) Signed-off-by: leo --- src/Commands/Merge.cs | 13 +++++++++++-- src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/Resources/Locales/zh_TW.axaml | 1 + src/ViewModels/Merge.cs | 8 +++++++- src/Views/Merge.axaml | 8 +++++++- 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Commands/Merge.cs b/src/Commands/Merge.cs index b08377b9..32898593 100644 --- a/src/Commands/Merge.cs +++ b/src/Commands/Merge.cs @@ -5,11 +5,20 @@ namespace SourceGit.Commands { public class Merge : Command { - public Merge(string repo, string source, string mode) + public Merge(string repo, string source, string mode, bool edit) { WorkingDirectory = repo; Context = repo; - Args = $"merge --progress {source} {mode}"; + Editor = EditorType.CoreEditor; + + var builder = new StringBuilder(); + builder.Append("merge --progress "); + builder.Append(edit ? "--edit " : "--no-edit "); + builder.Append(source); + builder.Append(' '); + builder.Append(mode); + + Args = builder.ToString(); } public Merge(string repo, List targets, bool autoCommit, string strategy) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index ee035551..f0ad4b18 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -442,6 +442,7 @@ Workspaces Pages Merge Branch + Customize merge message Into: Merge Option: Source: diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 2a117fb8..f8fa8d90 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -446,6 +446,7 @@ 工作区列表 页面列表 合并分支 + 编辑合并信息 目标分支 : 合并方式 : 合并目标 : diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 29a5346d..a76f4f3a 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -446,6 +446,7 @@ 工作區列表 頁面列表 合併分支 + 編輯合併訊息 目標分支: 合併方式: 合併來源: diff --git a/src/ViewModels/Merge.cs b/src/ViewModels/Merge.cs index eb54418c..d7b6a29c 100644 --- a/src/ViewModels/Merge.cs +++ b/src/ViewModels/Merge.cs @@ -21,6 +21,12 @@ namespace SourceGit.ViewModels set; } + public bool Edit + { + get; + set; + } = false; + public Merge(Repository repo, Models.Branch source, string into, bool forceFastForward) { _repo = repo; @@ -62,7 +68,7 @@ namespace SourceGit.ViewModels return Task.Run(() => { - new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg).Use(log).Exec(); + new Commands.Merge(_repo.FullPath, _sourceName, Mode.Arg, Edit).Use(log).Exec(); log.Complete(); var head = new Commands.QueryRevisionByRefName(_repo.FullPath, "HEAD").Result(); diff --git a/src/Views/Merge.axaml b/src/Views/Merge.axaml index 33d07f02..d4ba5d70 100644 --- a/src/Views/Merge.axaml +++ b/src/Views/Merge.axaml @@ -12,7 +12,7 @@ - + + + From 10569022d77e9d586cb276f8832639e5c8c0b5ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Jun 2025 07:08:25 +0000 Subject: [PATCH 09/47] doc: Update translation status and sort locale files --- TRANSLATION.md | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 051440f0..54dffa63 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-96.14%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-96.02%25-yellow)
Missing keys in de_DE.axaml @@ -28,6 +28,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Pull.RecurseSubmodules - Text.Repository.ClearStashes - Text.Repository.ShowSubmodulesAsTree @@ -45,9 +46,16 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-%E2%88%9A-brightgreen) +### ![es__ES](https://img.shields.io/badge/es__ES-99.88%25-yellow) -### ![fr__FR](https://img.shields.io/badge/fr__FR-92.03%25-yellow) +
+Missing keys in es_ES.axaml + +- Text.Merge.Edit + +
+ +### ![fr__FR](https://img.shields.io/badge/fr__FR-91.92%25-yellow)
Missing keys in fr_FR.axaml @@ -86,6 +94,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Pull.RecurseSubmodules - Text.Repository.BranchSort @@ -119,7 +128,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.38%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-97.26%25-yellow)
Missing keys in it_IT.axaml @@ -138,6 +147,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchTab - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Pull.RecurseSubmodules - Text.Repository.ClearStashes - Text.ResetWithoutCheckout @@ -148,7 +158,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-91.78%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-91.67%25-yellow)
Missing keys in ja_JP.axaml @@ -188,6 +198,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Pull.RecurseSubmodules - Text.Repository.BranchSort @@ -222,7 +233,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-83.81%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-83.71%25-yellow)
Missing keys in pt_BR.axaml @@ -294,6 +305,7 @@ This document shows the translation status of each locale file in the repository - Text.InProgress.Revert.Head - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Merge.Source - Text.MergeMultiple - Text.MergeMultiple.CommitChanges @@ -360,17 +372,18 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.75%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.63%25-yellow)
Missing keys in ru_RU.axaml - Text.Checkout.WithFastForward - Text.Checkout.WithFastForward.Upstream +- Text.Merge.Edit
-### ![ta__IN](https://img.shields.io/badge/ta__IN-91.91%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-91.79%25-yellow)
Missing keys in ta_IN.axaml @@ -410,6 +423,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Pull.RecurseSubmodules - Text.Repository.BranchSort @@ -443,7 +457,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-93.15%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-93.03%25-yellow)
Missing keys in uk_UA.axaml @@ -478,6 +492,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.Launcher.Workspaces - Text.Launcher.Pages +- Text.Merge.Edit - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Pull.RecurseSubmodules - Text.Repository.BranchSort From 957fbbf54f84376caf7703f112b94b0819dd55c6 Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 17 Jun 2025 20:56:02 +0800 Subject: [PATCH 10/47] refactor: rewrite stash local changes Signed-off-by: leo --- src/Models/DealWithChangesAfterStashing.cs | 22 +++++++++ src/Models/RepositorySettings.cs | 10 +--- src/Resources/Locales/de_DE.axaml | 3 -- src/Resources/Locales/en_US.axaml | 4 +- src/Resources/Locales/es_ES.axaml | 3 -- src/Resources/Locales/fr_FR.axaml | 3 -- src/Resources/Locales/it_IT.axaml | 3 -- src/Resources/Locales/ja_JP.axaml | 3 -- src/Resources/Locales/pt_BR.axaml | 1 - src/Resources/Locales/ru_RU.axaml | 3 -- src/Resources/Locales/ta_IN.axaml | 3 -- src/Resources/Locales/uk_UA.axaml | 3 -- src/Resources/Locales/zh_CN.axaml | 4 +- src/Resources/Locales/zh_TW.axaml | 4 +- src/ViewModels/StashChanges.cs | 46 ++++++++++-------- src/Views/StashChanges.axaml | 54 +++++++++++++++------- 16 files changed, 92 insertions(+), 77 deletions(-) create mode 100644 src/Models/DealWithChangesAfterStashing.cs diff --git a/src/Models/DealWithChangesAfterStashing.cs b/src/Models/DealWithChangesAfterStashing.cs new file mode 100644 index 00000000..63889c96 --- /dev/null +++ b/src/Models/DealWithChangesAfterStashing.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace SourceGit.Models +{ + public class DealWithChangesAfterStashing + { + public string Label { get; set; } + public string Desc { get; set; } + + public static readonly List Supported = [ + new ("Discard", "All (or selected) changes will be discarded"), + new ("Keep Index", "Staged changes are left intact"), + new ("Keep All", "All (or selected) changes are left intact"), + ]; + + public DealWithChangesAfterStashing(string label, string desc) + { + Label = label; + Desc = desc; + } + } +} diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs index a54956d3..4e51b368 100644 --- a/src/Models/RepositorySettings.cs +++ b/src/Models/RepositorySettings.cs @@ -176,17 +176,11 @@ namespace SourceGit.Models set; } = false; - public bool KeepIndexWhenStash + public int ChangesAfterStashing { get; set; - } = false; - - public bool AutoRestoreAfterStash - { - get; - set; - } = false; + } = 0; public string PreferredOpenAIService { diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index 032e5ce7..fc596da5 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -669,10 +669,7 @@ Pfad zum privaten SSH Schlüssel START Stash - Automatisch wiederherstellen nach dem Stashen - Die Arbeitsdateien bleiben unverändert, aber ein Stash wird gespeichert. Inklusive nicht-verfolgter Dateien - Behalte gestagte Dateien Name: Optional. Name dieses Stashes Nur gestagte Änderungen diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index f0ad4b18..8c5d1118 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -689,10 +689,8 @@ Private SSH key store path START Stash - Auto-restore after stashing - Your working files remain unchanged, but a stash is saved. + Selected Changes: Include untracked files - Keep staged files Message: Optional. Name of this stash Only staged changes diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index 4f1a4452..616799a4 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -692,10 +692,7 @@ Ruta de almacenamiento de la clave privada SSH INICIAR Stash - Restaurar automáticamente después del stashing - Tus archivos de trabajo permanecen sin cambios, pero se guarda un stash. Incluir archivos no rastreados - Mantener archivos staged Mensaje: Opcional. Nombre de este stash Solo cambios staged diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 635d74c2..f3ff7f25 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -645,10 +645,7 @@ Chemin du magasin de clés privées SSH START Stash - Auto-restauration après le stash - Vos fichiers de travail restent inchangés, mais une sauvegarde est enregistrée. Inclure les fichiers non-suivis - Garder les fichiers indexés Message : Optionnel. Nom de ce stash Seulement les changements indexés diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index 3aef0043..ea9c2c3f 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -673,10 +673,7 @@ Percorso per la chiave SSH privata AVVIA Stasha - Auto-ripristino dopo lo stash - I tuoi file di lavoro rimangono inalterati, ma viene salvato uno stash. Includi file non tracciati - Mantieni file in stage Messaggio: Opzionale. Nome di questo stash Solo modifiche in stage diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index 918a6b4d..635e5a1d 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -643,10 +643,7 @@ プライベートSSHキーストアのパス スタート スタッシュ - スタッシュ後に自動で復元 - 作業ファイルは変更されず、スタッシュが保存されます。 追跡されていないファイルを含める - ステージされたファイルを保持 メッセージ: オプション. このスタッシュの名前を入力 ステージされた変更のみ diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index f448a908..4e65a2b8 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -585,7 +585,6 @@ INICIAR Stash Incluir arquivos não rastreados - Manter arquivos em stage Mensagem: Opcional. Nome deste stash Apenas mudanças em stage diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index a625df98..b1656631 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -690,10 +690,7 @@ Путь хранения приватного ключа SSH ЗАПУСК Отложить - Автоматически восстанавливать после откладывания - Ваши рабочие файлы остаются неизменными, но отложенные сохранятся. Включить неотслеживаемые файлы - Хранить отложенные файлы Сообщение: Имя тайника (необязательно) Только сформированные изменения diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index abe53252..18f86d78 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -644,10 +644,7 @@ தனியார் பாஓடு திறவுகோல் கடை பாதை தொடங்கு பதுக்கிவை - பதுக்கிவைத்த பிறகு தானியங்கி மீட்டமை - உங்கள் செயல்படும் கோப்புகள் மாறாமல் இருக்கும், ஆனால் ஒரு பதுக்கிவைக்கப்படும். கண்காணிக்கப்படாத கோப்புகளைச் சேர் - நிலைப்படுத்தப்பட்ட கோப்புகளை வைத்திரு செய்தி: விருப்பத்தேர்வு. இந்த பதுக்கலின் பெயர் நிலைப்படுத்தப்பட்ட மாற்றங்கள் மட்டும் diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index 096b4398..169e8d68 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -649,10 +649,7 @@ Шлях до сховища приватного ключа SSH ПОЧАТИ Stash (Сховати) - Автоматично відновити після схову - Ваші робочі файли залишаться без змін, але буде збережено схованку. Включити невідстежувані файли - Зберегти проіндексовані файли Повідомлення: Необов'язково. Назва цієї схованки Лише проіндексовані зміни diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index f8fa8d90..ef984806 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -693,10 +693,8 @@ SSH密钥文件 开 始 贮藏(stash) - 贮藏后自动恢复工作区 - 工作区文件保持未修改状态,但贮藏内容已保存。 + 已选择变更 : 包含未跟踪的文件 - 保留暂存区文件 信息 : 选填,用于命名此贮藏 仅贮藏暂存区的变更 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index a76f4f3a..52ee5648 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -693,10 +693,8 @@ SSH 金鑰檔案 開 始 擱置變更 (stash) - 擱置變更後自動復原工作區 - 工作區檔案保持未修改,但擱置內容已儲存。 + 選定變更: 包含未追蹤的檔案 - 保留已暫存的變更 擱置變更訊息: 選填,用於命名此擱置變更 僅擱置已暫存的變更 diff --git a/src/ViewModels/StashChanges.cs b/src/ViewModels/StashChanges.cs index 11e449fb..639a0a7b 100644 --- a/src/ViewModels/StashChanges.cs +++ b/src/ViewModels/StashChanges.cs @@ -27,19 +27,20 @@ namespace SourceGit.ViewModels public bool OnlyStaged { get => _repo.Settings.OnlyStagedWhenStash; - set => _repo.Settings.OnlyStagedWhenStash = value; + set + { + if (_repo.Settings.OnlyStagedWhenStash != value) + { + _repo.Settings.OnlyStagedWhenStash = value; + OnPropertyChanged(); + } + } } - public bool KeepIndex + public int ChangesAfterStashing { - get => _repo.Settings.KeepIndexWhenStash; - set => _repo.Settings.KeepIndexWhenStash = value; - } - - public bool AutoRestore - { - get => _repo.Settings.AutoRestoreAfterStash; - set => _repo.Settings.AutoRestoreAfterStash = value; + get => _repo.Settings.ChangesAfterStashing; + set => _repo.Settings.ChangesAfterStashing = value; } public StashChanges(Repository repo, List changes, bool hasSelectedFiles) @@ -59,6 +60,8 @@ namespace SourceGit.ViewModels return Task.Run(() => { + var mode = (DealWithChangesAfterStashing)ChangesAfterStashing; + var keepIndex = mode == DealWithChangesAfterStashing.KeepIndex; var succ = false; if (!HasSelectedFiles) @@ -67,7 +70,7 @@ namespace SourceGit.ViewModels { if (Native.OS.GitVersion >= Models.GitVersions.STASH_PUSH_ONLY_STAGED) { - succ = new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStaged(Message, KeepIndex); + succ = new Commands.Stash(_repo.FullPath).Use(log).PushOnlyStaged(Message, keepIndex); } else { @@ -78,20 +81,20 @@ namespace SourceGit.ViewModels staged.Add(c); } - succ = StashWithChanges(staged, log); + succ = StashWithChanges(staged, keepIndex, log); } } else { - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, IncludeUntracked, KeepIndex); + succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, IncludeUntracked, keepIndex); } } else { - succ = StashWithChanges(_changes, log); + succ = StashWithChanges(_changes, keepIndex, log); } - if (AutoRestore && succ) + if (mode == DealWithChangesAfterStashing.KeepAll && succ) succ = new Commands.Stash(_repo.FullPath).Use(log).Apply("stash@{0}", true); log.Complete(); @@ -105,7 +108,7 @@ namespace SourceGit.ViewModels }); } - private bool StashWithChanges(List changes, CommandLog log) + private bool StashWithChanges(List changes, bool keepIndex, CommandLog log) { if (changes.Count == 0) return true; @@ -119,7 +122,7 @@ namespace SourceGit.ViewModels var pathSpecFile = Path.GetTempFileName(); File.WriteAllLines(pathSpecFile, paths); - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, pathSpecFile, KeepIndex); + succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, pathSpecFile, keepIndex); File.Delete(pathSpecFile); } else @@ -128,7 +131,7 @@ namespace SourceGit.ViewModels { var count = Math.Min(32, changes.Count - i); var step = changes.GetRange(i, count); - succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, step, KeepIndex); + succ = new Commands.Stash(_repo.FullPath).Use(log).Push(Message, step, keepIndex); if (!succ) break; } @@ -137,6 +140,13 @@ namespace SourceGit.ViewModels return succ; } + private enum DealWithChangesAfterStashing + { + Discard = 0, + KeepIndex, + KeepAll, + } + private readonly Repository _repo = null; private readonly List _changes = null; } diff --git a/src/Views/StashChanges.axaml b/src/Views/StashChanges.axaml index 51ed87ac..148fc489 100644 --- a/src/Views/StashChanges.axaml +++ b/src/Views/StashChanges.axaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:m="using:SourceGit.Models" xmlns:vm="using:SourceGit.ViewModels" xmlns:v="using:SourceGit.Views" mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450" @@ -11,7 +12,7 @@ - + - + + + + + + + + + + + + + + + + + Content="{DynamicResource Text.Stash.IncludeUntracked}" + IsChecked="{Binding IncludeUntracked, Mode=TwoWay}" + ToolTip.Tip="--include-untracked"> + + + + + + + - - - Date: Tue, 17 Jun 2025 12:56:18 +0000 Subject: [PATCH 11/47] doc: Update translation status and sort locale files --- TRANSLATION.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 54dffa63..96fe975b 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-96.02%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-95.89%25-yellow)
Missing keys in de_DE.axaml @@ -35,6 +35,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target +- Text.Stash.Changes - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -46,16 +47,17 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.88%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.75%25-yellow)
Missing keys in es_ES.axaml - Text.Merge.Edit +- Text.Stash.Changes
-### ![fr__FR](https://img.shields.io/badge/fr__FR-91.92%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-91.77%25-yellow)
Missing keys in fr_FR.axaml @@ -108,6 +110,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target +- Text.Stash.Changes - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -128,7 +131,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.26%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-97.13%25-yellow)
Missing keys in it_IT.axaml @@ -153,12 +156,13 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target +- Text.Stash.Changes - Text.Submodule.Deinit - Text.WorkingCopy.ResetAuthor
-### ![ja__JP](https://img.shields.io/badge/ja__JP-91.67%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-91.52%25-yellow)
Missing keys in ja_JP.axaml @@ -213,6 +217,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target +- Text.Stash.Changes - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -233,7 +238,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-83.71%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-83.79%25-yellow)
Missing keys in pt_BR.axaml @@ -347,8 +352,7 @@ This document shows the translation status of each locale file in the repository - Text.SetUpstream.Unset - Text.SetUpstream.Upstream - Text.SHALinkCM.NavigateTo -- Text.Stash.AutoRestore -- Text.Stash.AutoRestore.Tip +- Text.Stash.Changes - Text.StashCM.SaveAsPatch - Text.Submodule.Deinit - Text.Submodule.Status @@ -372,7 +376,7 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.63%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.50%25-yellow)
Missing keys in ru_RU.axaml @@ -380,10 +384,11 @@ This document shows the translation status of each locale file in the repository - Text.Checkout.WithFastForward - Text.Checkout.WithFastForward.Upstream - Text.Merge.Edit +- Text.Stash.Changes
-### ![ta__IN](https://img.shields.io/badge/ta__IN-91.79%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-91.65%25-yellow)
Missing keys in ta_IN.axaml @@ -437,6 +442,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target +- Text.Stash.Changes - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -457,7 +463,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-93.03%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-92.89%25-yellow)
Missing keys in uk_UA.axaml @@ -506,6 +512,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target +- Text.Stash.Changes - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified From d404f6dbe27990acd55c9576d2fa3ded8cb6aa8f Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Wed, 18 Jun 2025 11:29:18 +1000 Subject: [PATCH 12/47] code_style: general cleanup (#1428) --- .editorconfig | 10 +++--- src/App.axaml.cs | 2 +- src/Commands/QueryBranches.cs | 8 ++--- src/Commands/QueryTags.cs | 2 +- src/Commands/SaveRevisionFile.cs | 6 +--- src/Models/AvatarManager.cs | 5 +-- src/Models/DiffResult.cs | 26 ++++----------- src/Models/ExternalTool.cs | 3 +- src/Models/IpcChannel.cs | 10 ++---- src/Models/Null.cs | 4 +-- src/Models/SelfUpdate.cs | 4 +-- src/Models/TemplateEngine.cs | 12 +++---- src/Models/TextInlineChange.cs | 34 ++++++-------------- src/Native/Windows.cs | 6 ++-- src/Resources/Styles.axaml | 15 ++------- src/ViewModels/BranchCompare.cs | 2 +- src/ViewModels/BranchTreeNode.cs | 25 +++++++------- src/ViewModels/CommitDetail.cs | 2 +- src/ViewModels/Fetch.cs | 5 +-- src/ViewModels/Histories.cs | 7 ++-- src/ViewModels/ImageSource.cs | 6 ++-- src/ViewModels/Launcher.cs | 17 +++------- src/ViewModels/LauncherPage.cs | 2 +- src/ViewModels/Pull.cs | 21 ++++++------ src/ViewModels/Repository.cs | 14 +++----- src/ViewModels/RevisionCompare.cs | 10 ++---- src/ViewModels/Welcome.cs | 3 +- src/Views/Blame.axaml | 8 +---- src/Views/Blame.axaml.cs | 2 +- src/Views/BranchCompare.axaml | 8 +---- src/Views/ChangeStatusIcon.cs | 2 +- src/Views/ColorPicker.cs | 2 +- src/Views/CommandLogTime.cs | 2 +- src/Views/CommitDetail.axaml | 2 +- src/Views/CommitMessageTextBox.axaml.cs | 4 +-- src/Views/CommitTimeTextBlock.cs | 2 +- src/Views/Conflict.axaml | 2 +- src/Views/DiffView.axaml | 2 +- src/Views/FileHistories.axaml | 7 +--- src/Views/Histories.axaml.cs | 2 +- src/Views/LauncherPage.axaml.cs | 2 +- src/Views/LauncherTabBar.axaml.cs | 2 +- src/Views/MenuItemExtension.cs | 3 +- src/Views/Repository.axaml.cs | 2 +- src/Views/RepositoryToolbar.axaml.cs | 2 +- src/Views/RevisionFileContentViewer.axaml.cs | 3 +- src/Views/RevisionFileTreeView.axaml.cs | 28 +++++++--------- src/Views/TextDiffView.axaml.cs | 15 +++------ 48 files changed, 123 insertions(+), 240 deletions(-) diff --git a/.editorconfig b/.editorconfig index 56725e7b..f3c9a7bf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -71,20 +71,20 @@ dotnet_style_predefined_type_for_member_access = true:suggestion # name all constant fields using PascalCase dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style -dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_style.pascal_case_style.capitalization = pascal_case # private static fields should have s_ prefix dotnet_naming_rule.private_static_fields_should_have_prefix.severity = suggestion -dotnet_naming_rule.private_static_fields_should_have_prefix.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_should_have_prefix.symbols = private_static_fields dotnet_naming_rule.private_static_fields_should_have_prefix.style = private_static_prefix_style -dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_kinds = field dotnet_naming_symbols.private_static_fields.required_modifiers = static dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private @@ -93,7 +93,7 @@ dotnet_naming_style.private_static_prefix_style.capitalization = camel_case # internal and private fields should be _camelCase dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion -dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields +dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style dotnet_naming_symbols.private_internal_fields.applicable_kinds = field diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 8e579373..ef91ccdb 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -521,7 +521,7 @@ namespace SourceGit private bool TryLaunchAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop) { var args = desktop.Args; - if (args == null || args.Length <= 1 || !args[0].Equals("--core-editor", StringComparison.Ordinal)) + if (args is not { Length: > 1 } || !args[0].Equals("--core-editor", StringComparison.Ordinal)) return false; var file = args[1]; diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs index d0ecd322..f268d709 100644 --- a/src/Commands/QueryBranches.cs +++ b/src/Commands/QueryBranches.cs @@ -48,16 +48,12 @@ namespace SourceGit.Commands if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead)) { b.IsUpstreamGone = false; - - if (b.TrackStatus == null) - b.TrackStatus = new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result(); + b.TrackStatus ??= new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).Result(); } else { b.IsUpstreamGone = true; - - if (b.TrackStatus == null) - b.TrackStatus = new Models.BranchTrackStatus(); + b.TrackStatus ??= new Models.BranchTrackStatus(); } } } diff --git a/src/Commands/QueryTags.cs b/src/Commands/QueryTags.cs index 4b706439..896d555e 100644 --- a/src/Commands/QueryTags.cs +++ b/src/Commands/QueryTags.cs @@ -24,7 +24,7 @@ namespace SourceGit.Commands var records = rs.StdOut.Split(_boundary, StringSplitOptions.RemoveEmptyEntries); foreach (var record in records) { - var subs = record.Split('\0', StringSplitOptions.None); + var subs = record.Split('\0'); if (subs.Length != 6) continue; diff --git a/src/Commands/SaveRevisionFile.cs b/src/Commands/SaveRevisionFile.cs index 550844ef..8ac4ecc7 100644 --- a/src/Commands/SaveRevisionFile.cs +++ b/src/Commands/SaveRevisionFile.cs @@ -22,7 +22,7 @@ namespace SourceGit.Commands } } - private static bool ExecCmd(string repo, string args, string outputFile, Stream input = null) + private static void ExecCmd(string repo, string args, string outputFile, Stream input = null) { var starter = new ProcessStartInfo(); starter.WorkingDirectory = repo; @@ -45,10 +45,7 @@ namespace SourceGit.Commands proc.StandardInput.Write(new StreamReader(input).ReadToEnd()); proc.StandardOutput.BaseStream.CopyTo(sw); proc.WaitForExit(); - var rs = proc.ExitCode == 0; proc.Close(); - - return rs; } catch (Exception e) { @@ -56,7 +53,6 @@ namespace SourceGit.Commands { App.RaiseException(repo, "Save file failed: " + e.Message); }); - return false; } } } diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs index fa07975d..bc9fbe95 100644 --- a/src/Models/AvatarManager.cs +++ b/src/Models/AvatarManager.cs @@ -26,10 +26,7 @@ namespace SourceGit.Models { get { - if (_instance == null) - _instance = new AvatarManager(); - - return _instance; + return _instance ??= new AvatarManager(); } } diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs index b2d91310..71ed2d9e 100644 --- a/src/Models/DiffResult.cs +++ b/src/Models/DiffResult.cs @@ -16,11 +16,10 @@ namespace SourceGit.Models Deleted, } - public class TextInlineRange + public class TextInlineRange(int p, int n) { - public int Start { get; set; } - public int End { get; set; } - public TextInlineRange(int p, int n) { Start = p; End = p + n - 1; } + public int Start { get; set; } = p; + public int End { get; set; } = p + n - 1; } public class TextDiffLine @@ -556,7 +555,7 @@ namespace SourceGit.Models } else if (test.Type == TextDiffLineType.Added) { - if (i < start - 1) + if (i < start - 1 || isOldSide) { if (revert) { @@ -566,18 +565,7 @@ namespace SourceGit.Models } else { - if (isOldSide) - { - if (revert) - { - newCount++; - oldCount++; - } - } - else - { - newCount++; - } + newCount++; } if (i == end - 1 && tailed) @@ -655,9 +643,7 @@ namespace SourceGit.Models public string NewImageSize => New != null ? $"{New.PixelSize.Width} x {New.PixelSize.Height}" : "0 x 0"; } - public class NoOrEOLChange - { - } + public class NoOrEOLChange; public class FileModeDiff { diff --git a/src/Models/ExternalTool.cs b/src/Models/ExternalTool.cs index 103e91bc..697c171a 100644 --- a/src/Models/ExternalTool.cs +++ b/src/Models/ExternalTool.cs @@ -107,8 +107,7 @@ namespace SourceGit.Models // Ignore } - if (_customPaths == null) - _customPaths = new ExternalToolPaths(); + _customPaths ??= new ExternalToolPaths(); } public void TryAdd(string name, string icon, Func finder, Func execArgsGenerator = null) diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs index c2a6c6c7..001c65a6 100644 --- a/src/Models/IpcChannel.cs +++ b/src/Models/IpcChannel.cs @@ -8,10 +8,7 @@ namespace SourceGit.Models { public class IpcChannel : IDisposable { - public bool IsFirstInstance - { - get => _isFirstInstance; - } + public bool IsFirstInstance { get; } public event Action MessageReceived; @@ -20,7 +17,7 @@ namespace SourceGit.Models try { _singletonLock = File.Open(Path.Combine(Native.OS.DataDir, "process.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); - _isFirstInstance = true; + IsFirstInstance = true; _server = new NamedPipeServerStream( "SourceGitIPCChannel" + Environment.UserName, PipeDirection.In, @@ -32,7 +29,7 @@ namespace SourceGit.Models } catch { - _isFirstInstance = false; + IsFirstInstance = false; } } @@ -97,7 +94,6 @@ namespace SourceGit.Models } private FileStream _singletonLock = null; - private bool _isFirstInstance = false; private NamedPipeServerStream _server = null; private CancellationTokenSource _cancellationTokenSource = null; } diff --git a/src/Models/Null.cs b/src/Models/Null.cs index e22ef8b3..1820d4d0 100644 --- a/src/Models/Null.cs +++ b/src/Models/Null.cs @@ -1,6 +1,4 @@ namespace SourceGit.Models { - public class Null - { - } + public class Null; } diff --git a/src/Models/SelfUpdate.cs b/src/Models/SelfUpdate.cs index e02f80d8..05fa6124 100644 --- a/src/Models/SelfUpdate.cs +++ b/src/Models/SelfUpdate.cs @@ -33,9 +33,7 @@ namespace SourceGit.Models } } - public class AlreadyUpToDate - { - } + public class AlreadyUpToDate; public class SelfUpdateFailed { diff --git a/src/Models/TemplateEngine.cs b/src/Models/TemplateEngine.cs index c54f55fb..8f60bd74 100644 --- a/src/Models/TemplateEngine.cs +++ b/src/Models/TemplateEngine.cs @@ -102,7 +102,7 @@ namespace SourceGit.Models private int? Integer() { var start = _pos; - while (Peek() is char c && c >= '0' && c <= '9') + while (Peek() is >= '0' and <= '9') { _pos++; } @@ -118,7 +118,7 @@ namespace SourceGit.Models // text token start var tok = _pos; bool esc = false; - while (Next() is char c) + while (Next() is { } c) { if (esc) { @@ -129,7 +129,7 @@ namespace SourceGit.Models { case ESCAPE: // allow to escape only \ and $ - if (Peek() is char nc && (nc == ESCAPE || nc == VARIABLE_ANCHOR)) + if (Peek() is { } nc && (nc == ESCAPE || nc == VARIABLE_ANCHOR)) { esc = true; FlushText(tok, _pos - 1); @@ -173,7 +173,7 @@ namespace SourceGit.Models if (Next() != VARIABLE_START) return null; int name_start = _pos; - while (Next() is char c) + while (Next() is { } c) { // name character, continue advancing if (IsNameChar(c)) @@ -228,7 +228,7 @@ namespace SourceGit.Models var sb = new StringBuilder(); var tok = _pos; var esc = false; - while (Next() is char c) + while (Next() is { } c) { if (esc) { @@ -277,7 +277,7 @@ namespace SourceGit.Models var sb = new StringBuilder(); var tok = _pos; var esc = false; - while (Next() is char c) + while (Next() is { } c) { if (esc) { diff --git a/src/Models/TextInlineChange.cs b/src/Models/TextInlineChange.cs index 15901d03..afe5bec4 100644 --- a/src/Models/TextInlineChange.cs +++ b/src/Models/TextInlineChange.cs @@ -2,27 +2,19 @@ namespace SourceGit.Models { - public class TextInlineChange + public class TextInlineChange(int dp, int dc, int ap, int ac) { - public int DeletedStart { get; set; } - public int DeletedCount { get; set; } - public int AddedStart { get; set; } - public int AddedCount { get; set; } + public int DeletedStart { get; set; } = dp; + public int DeletedCount { get; set; } = dc; + public int AddedStart { get; set; } = ap; + public int AddedCount { get; set; } = ac; - private class Chunk + private class Chunk(int hash, int start, int size) { - public int Hash; + public readonly int Hash = hash; + public readonly int Start = start; + public readonly int Size = size; public bool Modified; - public int Start; - public int Size; - - public Chunk(int hash, int start, int size) - { - Hash = hash; - Modified = false; - Start = start; - Size = size; - } } private enum Edit @@ -43,14 +35,6 @@ namespace SourceGit.Models public int AddEnd; } - public TextInlineChange(int dp, int dc, int ap, int ac) - { - DeletedStart = dp; - DeletedCount = dc; - AddedStart = ap; - AddedCount = ac; - } - public static List Compare(string oldValue, string newValue) { var hashes = new Dictionary(); diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 07cf51fb..06d80bf0 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -54,7 +54,7 @@ namespace SourceGit.Native public void SetupApp(AppBuilder builder) { // Fix drop shadow issue on Windows 10 - if (!OperatingSystem.IsWindowsVersionAtLeast(10, 22000, 0)) + if (!OperatingSystem.IsWindowsVersionAtLeast(10, 22000)) { Window.WindowStateProperty.Changed.AddClassHandler((w, _) => FixWindowFrameOnWin10(w)); Control.LoadedEvent.AddClassHandler((w, _) => FixWindowFrameOnWin10(w)); @@ -385,11 +385,11 @@ namespace SourceGit.Native Microsoft.Win32.RegistryView.Registry64); // Get default class for VisualStudio.Launcher.sln - the handler for *.sln files - if (localMachine.OpenSubKey(@"SOFTWARE\Classes\VisualStudio.Launcher.sln\CLSID") is Microsoft.Win32.RegistryKey launcher) + if (localMachine.OpenSubKey(@"SOFTWARE\Classes\VisualStudio.Launcher.sln\CLSID") is { } launcher) { // Get actual path to the executable if (launcher.GetValue(string.Empty) is string CLSID && - localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is Microsoft.Win32.RegistryKey devenv && + localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is { } devenv && devenv.GetValue(string.Empty) is string localServer32) return localServer32!.Trim('\"'); } diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index 15704775..f42160a2 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -529,13 +529,7 @@ - - - - - - - +
@@ -110,7 +110,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target -- Text.Stash.Changes +- Text.Stash.Mode - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -156,7 +156,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target -- Text.Stash.Changes +- Text.Stash.Mode - Text.Submodule.Deinit - Text.WorkingCopy.ResetAuthor @@ -217,7 +217,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target -- Text.Stash.Changes +- Text.Stash.Mode - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -352,7 +352,7 @@ This document shows the translation status of each locale file in the repository - Text.SetUpstream.Unset - Text.SetUpstream.Upstream - Text.SHALinkCM.NavigateTo -- Text.Stash.Changes +- Text.Stash.Mode - Text.StashCM.SaveAsPatch - Text.Submodule.Deinit - Text.Submodule.Status @@ -384,7 +384,7 @@ This document shows the translation status of each locale file in the repository - Text.Checkout.WithFastForward - Text.Checkout.WithFastForward.Upstream - Text.Merge.Edit -- Text.Stash.Changes +- Text.Stash.Mode
@@ -442,7 +442,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target -- Text.Stash.Changes +- Text.Stash.Mode - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -512,7 +512,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target -- Text.Stash.Changes +- Text.Stash.Mode - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index c26fcd4d..f9b37619 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -461,8 +461,8 @@ Vor {0} Monaten Vor {0} Jahren Gestern - Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button Einstellungen + Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button OPEN AI Analysierung des Diff Befehl API Schlüssel diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index ebf4f4aa..dc78f6ba 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -478,8 +478,8 @@ Hace {0} meses Hace {0} años Ayer - Usa 'Shift+Enter' para introducir una nueva línea. 'Enter' es el atajo del botón OK Preferencias + Usa 'Shift+Enter' para introducir una nueva línea. 'Enter' es el atajo del botón OK OPEN AI Analizar Diff Prompt Clave API diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 14241cf8..cdf55507 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -444,8 +444,8 @@ il y a {0} mois il y a {0} ans Hier - Utiliser 'Maj+Entrée' pour insérer une nouvelle ligne. 'Entrée' est la touche pour valider Préférences + Utiliser 'Maj+Entrée' pour insérer une nouvelle ligne. 'Entrée' est la touche pour valider IA Analyser Diff Prompt Clé d'API diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index c2072ba5..75b4b47c 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -464,8 +464,8 @@ {0} mesi fa {0} anni fa Ieri - Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK Preferenze + Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK AI Analizza il Prompt Differenza Chiave API diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index 8da546cb..da2480e6 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -443,8 +443,8 @@ {0} ヶ月前 {0} 年前 昨日 - 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。 設定 + 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。 AI 差分分析プロンプト APIキー diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 8b3a5d04..c4312b94 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -406,8 +406,8 @@ {0} meses atrás {0} anos atrás Ontem - Use 'Shift+Enter' para inserir uma nova linha. 'Enter' é a tecla de atalho do botão OK Preferências + Use 'Shift+Enter' para inserir uma nova linha. 'Enter' é a tecla de atalho do botão OK INTELIGÊNCIA ARTIFICIAL Prompt para Analisar Diff Chave da API diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index cce18629..b82bb302 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -476,8 +476,8 @@ {0} месяцев назад {0} лет назад Вчера - Используйте «Shift+Enter» для ввода новой строки. «Enter» - это горячая клавиша кнопки «OK» Параметры + Используйте «Shift+Enter» для ввода новой строки. «Enter» - это горячая клавиша кнопки «OK» ОТКРЫТЬ ИИ Запрос на анализ сравнения Ключ API diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index ec102f19..2e17c880 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -443,8 +443,8 @@ {0} திங்களுக்கு முன்பு {0} ஆண்டுகளுக்கு முன்பு நேற்று - புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும் விருப்பத்தேர்வுகள் + புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும் செநு வேறுபாடு உடனடியாக பகுப்பாய்வு செய் பநிஇ திறவுகோல் diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index ad3b8259..377cf63b 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -448,8 +448,8 @@ {0} місяців тому {0} років тому Вчора - Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK Налаштування + Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK AI Промпт для аналізу різниці Ключ API diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 6adf1c9f..e19b3567 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -479,8 +479,8 @@ {0}个月前 {0}年前 昨天 - 请使用Shift+Enter换行。Enter键已被【确 定】按钮占用。 偏好设置 + 请使用Shift+Enter换行。Enter键已被【确 定】按钮占用。 AI Analyze Diff Prompt API密钥 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 47b4de20..8d504885 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -479,8 +479,8 @@ {0} 個月前 {0} 年前 昨天 - 請使用 Shift + Enter 換行。Enter 鍵已被 [確定] 按鈕佔用。 偏好設定 + 請使用 Shift + Enter 換行。Enter 鍵已被 [確定] 按鈕佔用。 AI 分析變更差異提示詞 API 金鑰 From bad8904edc3f38fc36844c8ea285b99bc9ba5231 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 12:37:39 +0800 Subject: [PATCH 16/47] code_style: make sure translations are ordered by key Signed-off-by: leo --- src/Resources/Locales/en_US.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 5ce5ebea..b5e933c0 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -475,8 +475,8 @@ {0} months ago {0} years ago Yesterday - Preferences Use 'Shift+Enter' to input a new line. 'Enter' is the hotkey of OK button + Preferences AI Analyze Diff Prompt API Key From 5ca1fcfd8f0f292d6d1d197a8d1e89e0b30e784a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 18 Jun 2025 04:37:53 +0000 Subject: [PATCH 17/47] doc: Update translation status and sort locale files --- src/Resources/Locales/de_DE.axaml | 2 +- src/Resources/Locales/es_ES.axaml | 2 +- src/Resources/Locales/fr_FR.axaml | 2 +- src/Resources/Locales/it_IT.axaml | 2 +- src/Resources/Locales/ja_JP.axaml | 2 +- src/Resources/Locales/pt_BR.axaml | 2 +- src/Resources/Locales/ru_RU.axaml | 2 +- src/Resources/Locales/ta_IN.axaml | 2 +- src/Resources/Locales/uk_UA.axaml | 2 +- src/Resources/Locales/zh_CN.axaml | 2 +- src/Resources/Locales/zh_TW.axaml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index f9b37619..c26fcd4d 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -461,8 +461,8 @@ Vor {0} Monaten Vor {0} Jahren Gestern - Einstellungen Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button + Einstellungen OPEN AI Analysierung des Diff Befehl API Schlüssel diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index dc78f6ba..ebf4f4aa 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -478,8 +478,8 @@ Hace {0} meses Hace {0} años Ayer - Preferencias Usa 'Shift+Enter' para introducir una nueva línea. 'Enter' es el atajo del botón OK + Preferencias OPEN AI Analizar Diff Prompt Clave API diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index cdf55507..14241cf8 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -444,8 +444,8 @@ il y a {0} mois il y a {0} ans Hier - Préférences Utiliser 'Maj+Entrée' pour insérer une nouvelle ligne. 'Entrée' est la touche pour valider + Préférences IA Analyser Diff Prompt Clé d'API diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index 75b4b47c..c2072ba5 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -464,8 +464,8 @@ {0} mesi fa {0} anni fa Ieri - Preferenze Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK + Preferenze AI Analizza il Prompt Differenza Chiave API diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index da2480e6..8da546cb 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -443,8 +443,8 @@ {0} ヶ月前 {0} 年前 昨日 - 設定 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。 + 設定 AI 差分分析プロンプト APIキー diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index c4312b94..8b3a5d04 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -406,8 +406,8 @@ {0} meses atrás {0} anos atrás Ontem - Preferências Use 'Shift+Enter' para inserir uma nova linha. 'Enter' é a tecla de atalho do botão OK + Preferências INTELIGÊNCIA ARTIFICIAL Prompt para Analisar Diff Chave da API diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index b82bb302..cce18629 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -476,8 +476,8 @@ {0} месяцев назад {0} лет назад Вчера - Параметры Используйте «Shift+Enter» для ввода новой строки. «Enter» - это горячая клавиша кнопки «OK» + Параметры ОТКРЫТЬ ИИ Запрос на анализ сравнения Ключ API diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index 2e17c880..ec102f19 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -443,8 +443,8 @@ {0} திங்களுக்கு முன்பு {0} ஆண்டுகளுக்கு முன்பு நேற்று - விருப்பத்தேர்வுகள் புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும் + விருப்பத்தேர்வுகள் செநு வேறுபாடு உடனடியாக பகுப்பாய்வு செய் பநிஇ திறவுகோல் diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index 377cf63b..ad3b8259 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -448,8 +448,8 @@ {0} місяців тому {0} років тому Вчора - Налаштування Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK + Налаштування AI Промпт для аналізу різниці Ключ API diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index e19b3567..6adf1c9f 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -479,8 +479,8 @@ {0}个月前 {0}年前 昨天 - 偏好设置 请使用Shift+Enter换行。Enter键已被【确 定】按钮占用。 + 偏好设置 AI Analyze Diff Prompt API密钥 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 8d504885..47b4de20 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -479,8 +479,8 @@ {0} 個月前 {0} 年前 昨天 - 偏好設定 請使用 Shift + Enter 換行。Enter 鍵已被 [確定] 按鈕佔用。 + 偏好設定 AI 分析變更差異提示詞 API 金鑰 From 240db2ea2f45638decdf726c0081f6084c791ecc Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 12:51:39 +0800 Subject: [PATCH 18/47] ux: use small font size for tips Signed-off-by: leo --- src/Views/StashChanges.axaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Views/StashChanges.axaml b/src/Views/StashChanges.axaml index 5422966f..52af4edd 100644 --- a/src/Views/StashChanges.axaml +++ b/src/Views/StashChanges.axaml @@ -82,6 +82,7 @@ Date: Wed, 18 Jun 2025 07:48:39 +0200 Subject: [PATCH 19/47] Add "Copy Message" to context-menu for Stash item (#1430) * Refactor: Simplify parsing in QueryStashes, by passing the `-z` argument to `git stash list` for item separation. * Add "Copy Message" command in stash-item context-menu. --- src/Commands/QueryStashes.cs | 83 ++++++++++++++----------------- src/Resources/Locales/en_US.axaml | 1 + src/ViewModels/StashesPage.cs | 10 ++++ 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs index cbc19bae..184cc347 100644 --- a/src/Commands/QueryStashes.cs +++ b/src/Commands/QueryStashes.cs @@ -7,11 +7,9 @@ namespace SourceGit.Commands { public QueryStashes(string repo) { - _boundary = $"-----BOUNDARY_OF_COMMIT{Guid.NewGuid()}-----"; - WorkingDirectory = repo; Context = repo; - Args = $"stash list --no-show-signature --format=\"%H%n%P%n%ct%n%gd%n%B%n{_boundary}\""; + Args = $"stash list -z --no-show-signature --format=\"%H%n%P%n%ct%n%gd%n%B\""; } public List Result() @@ -21,66 +19,57 @@ namespace SourceGit.Commands if (!rs.IsSuccess) return outs; - var nextPartIdx = 0; - var start = 0; - var end = rs.StdOut.IndexOf('\n', start); - while (end > 0) + var items = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries); + foreach (var item in items) { - var line = rs.StdOut.Substring(start, end - start); + var current = new Models.Stash(); - switch (nextPartIdx) + var nextPartIdx = 0; + var start = 0; + var end = item.IndexOf('\n', start); + while (end > 0 && nextPartIdx < 4) { - case 0: - _current = new Models.Stash() { SHA = line }; - outs.Add(_current); - break; - case 1: - ParseParent(line); - break; - case 2: - _current.Time = ulong.Parse(line); - break; - case 3: - _current.Name = line; - break; - default: - var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal); - if (boundary > end) - { - _current.Message = rs.StdOut.Substring(start, boundary - start - 1); - end = boundary + _boundary.Length; - } - else - { - _current.Message = rs.StdOut.Substring(start); - end = rs.StdOut.Length - 2; - } + var line = item.Substring(start, end - start); - nextPartIdx = -1; + switch (nextPartIdx) + { + case 0: + current.SHA = line; + break; + case 1: + ParseParent(line, ref current); + break; + case 2: + current.Time = ulong.Parse(line); + break; + case 3: + current.Name = line; + break; + } + + nextPartIdx++; + + start = end + 1; + if (start >= item.Length - 1) break; + + end = item.IndexOf('\n', start); } - nextPartIdx++; + if (start < item.Length) + current.Message = item.Substring(start); - start = end + 1; - if (start >= rs.StdOut.Length - 1) - break; - - end = rs.StdOut.IndexOf('\n', start); + outs.Add(current); } - return outs; } - private void ParseParent(string data) + private void ParseParent(string data, ref Models.Stash current) { if (data.Length < 8) return; - _current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries)); + current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries)); } - - private Models.Stash _current = null; - private readonly string _boundary; } } diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index b5e933c0..a4066891 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -697,6 +697,7 @@ Both staged and unstaged changes of selected file(s) will be stashed!!! Stash Local Changes Apply + Copy Message Drop Save as Patch... Drop Stash diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index f039d54e..1f11425d 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -194,11 +194,21 @@ namespace SourceGit.ViewModels e.Handled = true; }; + var copy = new MenuItem(); + copy.Header = App.Text("StashCM.CopyMessage"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); + copy.Click += (_, ev) => + { + App.CopyText(stash.Message); + ev.Handled = true; + }; + var menu = new ContextMenu(); menu.Items.Add(apply); menu.Items.Add(drop); menu.Items.Add(new MenuItem { Header = "-" }); menu.Items.Add(patch); + menu.Items.Add(copy); return menu; } From 3711399c5942c157f8e0bfc2699d56f01e52dd8d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 18 Jun 2025 05:48:50 +0000 Subject: [PATCH 20/47] doc: Update translation status and sort locale files --- TRANSLATION.md | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index b645dc2f..1dbf7d5d 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.89%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-95.77%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.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -47,17 +48,18 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.75%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.63%25-yellow)
Missing keys in es_ES.axaml - Text.Merge.Edit - Text.Stash.Mode +- Text.StashCM.CopyMessage
-### ![fr__FR](https://img.shields.io/badge/fr__FR-91.77%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-91.66%25-yellow)
Missing keys in fr_FR.axaml @@ -111,6 +113,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -131,7 +134,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.13%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-97.01%25-yellow)
Missing keys in it_IT.axaml @@ -157,12 +160,13 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.Submodule.Deinit - Text.WorkingCopy.ResetAuthor
-### ![ja__JP](https://img.shields.io/badge/ja__JP-91.52%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-91.41%25-yellow)
Missing keys in ja_JP.axaml @@ -218,6 +222,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -238,7 +243,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-83.79%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-83.69%25-yellow)
Missing keys in pt_BR.axaml @@ -353,6 +358,7 @@ This document shows the translation status of each locale file in the repository - Text.SetUpstream.Upstream - Text.SHALinkCM.NavigateTo - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.StashCM.SaveAsPatch - Text.Submodule.Deinit - Text.Submodule.Status @@ -376,7 +382,7 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.50%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.38%25-yellow)
Missing keys in ru_RU.axaml @@ -385,10 +391,11 @@ This document shows the translation status of each locale file in the repository - Text.Checkout.WithFastForward.Upstream - Text.Merge.Edit - Text.Stash.Mode +- Text.StashCM.CopyMessage
-### ![ta__IN](https://img.shields.io/badge/ta__IN-91.65%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-91.53%25-yellow)
Missing keys in ta_IN.axaml @@ -443,6 +450,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -463,7 +471,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-92.89%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-92.78%25-yellow)
Missing keys in uk_UA.axaml @@ -513,6 +521,7 @@ This document shows the translation status of each locale file in the repository - Text.ResetWithoutCheckout.MoveTo - Text.ResetWithoutCheckout.Target - Text.Stash.Mode +- Text.StashCM.CopyMessage - Text.Submodule.Deinit - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -528,6 +537,20 @@ 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__CN](https://img.shields.io/badge/zh__CN-99.88%25-yellow) -### ![zh__TW](https://img.shields.io/badge/zh__TW-%E2%88%9A-brightgreen) \ No newline at end of file +
+Missing keys in zh_CN.axaml + +- Text.StashCM.CopyMessage + +
+ +### ![zh__TW](https://img.shields.io/badge/zh__TW-99.88%25-yellow) + +
+Missing keys in zh_TW.axaml + +- Text.StashCM.CopyMessage + +
\ No newline at end of file From 94d25ee6c9af882e6260b23ab81b04e69595f9e3 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 13:55:03 +0800 Subject: [PATCH 21/47] code_review: PR #1430 - add missing Chinese translations - add missing icons for stash context menu Signed-off-by: leo --- src/Resources/Locales/zh_CN.axaml | 1 + src/Resources/Locales/zh_TW.axaml | 1 + src/ViewModels/StashesPage.cs | 3 +++ 3 files changed, 5 insertions(+) diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 6adf1c9f..783cb664 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -701,6 +701,7 @@ 选中文件的所有变更均会被贮藏! 贮藏本地变更 应用(apply) + 复制描述信息 删除(drop) 另存为补丁... 丢弃贮藏确认 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 47b4de20..d8aff0fd 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -701,6 +701,7 @@ 已選取的檔案中的變更均會被擱置! 擱置本機變更 套用 (apply) + 複製描述訊息 刪除 (drop) 另存為修補檔 (patch)... 捨棄擱置變更確認 diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index 1f11425d..05218bc5 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -142,6 +142,7 @@ namespace SourceGit.ViewModels var apply = new MenuItem(); apply.Header = App.Text("StashCM.Apply"); + apply.Icon = App.CreateMenuIcon("Icons.Check"); apply.Click += (_, ev) => { if (_repo.CanCreatePopup()) @@ -152,6 +153,7 @@ namespace SourceGit.ViewModels var drop = new MenuItem(); drop.Header = App.Text("StashCM.Drop"); + drop.Icon = App.CreateMenuIcon("Icons.Clear"); drop.Click += (_, ev) => { if (_repo.CanCreatePopup()) @@ -208,6 +210,7 @@ namespace SourceGit.ViewModels menu.Items.Add(drop); menu.Items.Add(new MenuItem { Header = "-" }); menu.Items.Add(patch); + menu.Items.Add(new MenuItem { Header = "-" }); menu.Items.Add(copy); return menu; } From 3ac803d88c9f62745f96fd8d0784a16f8f458c6c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 18 Jun 2025 05:55:24 +0000 Subject: [PATCH 22/47] doc: Update translation status and sort locale files --- TRANSLATION.md | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 1dbf7d5d..aeeb8a02 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -537,20 +537,6 @@ This document shows the translation status of each locale file in the repository -### ![zh__CN](https://img.shields.io/badge/zh__CN-99.88%25-yellow) +### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen) -
-Missing keys in zh_CN.axaml - -- Text.StashCM.CopyMessage - -
- -### ![zh__TW](https://img.shields.io/badge/zh__TW-99.88%25-yellow) - -
-Missing keys in zh_TW.axaml - -- Text.StashCM.CopyMessage - -
\ 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 2d91fed05ebac3f034b634ce495e93419bea5036 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 14:27:39 +0800 Subject: [PATCH 23/47] code_style: remove unnecessary namespace using Signed-off-by: leo --- src/Commands/QueryStashes.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs index 184cc347..2b8987b6 100644 --- a/src/Commands/QueryStashes.cs +++ b/src/Commands/QueryStashes.cs @@ -19,7 +19,7 @@ namespace SourceGit.Commands if (!rs.IsSuccess) return outs; - var items = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries); + var items = rs.StdOut.Split('\0', StringSplitOptions.RemoveEmptyEntries); foreach (var item in items) { var current = new Models.Stash(); @@ -37,7 +37,8 @@ namespace SourceGit.Commands current.SHA = line; break; case 1: - ParseParent(line, ref current); + if (line.Length > 6) + current.Parents.AddRange(line.Split(' ', StringSplitOptions.RemoveEmptyEntries)); break; case 2: current.Time = ulong.Parse(line); @@ -63,13 +64,5 @@ namespace SourceGit.Commands } return outs; } - - private void ParseParent(string data, ref Models.Stash current) - { - if (data.Length < 8) - return; - - current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries)); - } } } From 5ec8ae12967a2728a4bac22b149f2d41d7bb213a Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 14:37:14 +0800 Subject: [PATCH 24/47] ux: use `CheckCircled` instead of `Check` icon for stash apply context menu Signed-off-by: leo --- src/ViewModels/StashesPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ViewModels/StashesPage.cs b/src/ViewModels/StashesPage.cs index 05218bc5..431f61e6 100644 --- a/src/ViewModels/StashesPage.cs +++ b/src/ViewModels/StashesPage.cs @@ -142,7 +142,7 @@ namespace SourceGit.ViewModels var apply = new MenuItem(); apply.Header = App.Text("StashCM.Apply"); - apply.Icon = App.CreateMenuIcon("Icons.Check"); + apply.Icon = App.CreateMenuIcon("Icons.CheckCircled"); apply.Click += (_, ev) => { if (_repo.CanCreatePopup()) From c67e8e3c6414e80c1fe32f860de256ad06ded517 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 17:12:50 +0800 Subject: [PATCH 25/47] enhance: create only one filesystem watcher when repo's `$GIT_DIR` is the same as `$REPO_ROOT/.git` Signed-off-by: leo --- src/Models/Watcher.cs | 132 +++++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 47 deletions(-) diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs index a3cfc329..abceea9a 100644 --- a/src/Models/Watcher.cs +++ b/src/Models/Watcher.cs @@ -12,27 +12,50 @@ namespace SourceGit.Models { _repo = repo; - _wcWatcher = new FileSystemWatcher(); - _wcWatcher.Path = fullpath; - _wcWatcher.Filter = "*"; - _wcWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime; - _wcWatcher.IncludeSubdirectories = true; - _wcWatcher.Created += OnWorkingCopyChanged; - _wcWatcher.Renamed += OnWorkingCopyChanged; - _wcWatcher.Changed += OnWorkingCopyChanged; - _wcWatcher.Deleted += OnWorkingCopyChanged; - _wcWatcher.EnableRaisingEvents = true; + var testGitDir = new DirectoryInfo(Path.Combine(fullpath, ".git")).FullName; + var desiredDir = new DirectoryInfo(gitDir).FullName; + if (testGitDir.Equals(desiredDir, StringComparison.Ordinal)) + { + var combined = new FileSystemWatcher(); + combined.Path = fullpath; + combined.Filter = "*"; + combined.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime; + combined.IncludeSubdirectories = true; + combined.Created += OnRepositoryChanged; + combined.Renamed += OnRepositoryChanged; + combined.Changed += OnRepositoryChanged; + combined.Deleted += OnRepositoryChanged; + combined.EnableRaisingEvents = true; - _repoWatcher = new FileSystemWatcher(); - _repoWatcher.Path = gitDir; - _repoWatcher.Filter = "*"; - _repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName; - _repoWatcher.IncludeSubdirectories = true; - _repoWatcher.Created += OnRepositoryChanged; - _repoWatcher.Renamed += OnRepositoryChanged; - _repoWatcher.Changed += OnRepositoryChanged; - _repoWatcher.Deleted += OnRepositoryChanged; - _repoWatcher.EnableRaisingEvents = true; + _watchers.Add(combined); + } + else + { + var wc = new FileSystemWatcher(); + wc.Path = fullpath; + wc.Filter = "*"; + wc.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime; + wc.IncludeSubdirectories = true; + wc.Created += OnWorkingCopyChanged; + wc.Renamed += OnWorkingCopyChanged; + wc.Changed += OnWorkingCopyChanged; + wc.Deleted += OnWorkingCopyChanged; + wc.EnableRaisingEvents = true; + + var git = new FileSystemWatcher(); + git.Path = gitDir; + git.Filter = "*"; + git.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName; + git.IncludeSubdirectories = true; + git.Created += OnGitDirChanged; + git.Renamed += OnGitDirChanged; + git.Changed += OnGitDirChanged; + git.Deleted += OnGitDirChanged; + git.EnableRaisingEvents = true; + + _watchers.Add(wc); + _watchers.Add(git); + } _timer = new Timer(Tick, null, 100, 100); } @@ -77,22 +100,13 @@ namespace SourceGit.Models public void Dispose() { - _repoWatcher.EnableRaisingEvents = false; - _repoWatcher.Created -= OnRepositoryChanged; - _repoWatcher.Renamed -= OnRepositoryChanged; - _repoWatcher.Changed -= OnRepositoryChanged; - _repoWatcher.Deleted -= OnRepositoryChanged; - _repoWatcher.Dispose(); - _repoWatcher = null; - - _wcWatcher.EnableRaisingEvents = false; - _wcWatcher.Created -= OnWorkingCopyChanged; - _wcWatcher.Renamed -= OnWorkingCopyChanged; - _wcWatcher.Changed -= OnWorkingCopyChanged; - _wcWatcher.Deleted -= OnWorkingCopyChanged; - _wcWatcher.Dispose(); - _wcWatcher = null; + foreach (var watcher in _watchers) + { + watcher.EnableRaisingEvents = false; + watcher.Dispose(); + } + _watchers.Clear(); _timer.Dispose(); _timer = null; } @@ -153,11 +167,45 @@ namespace SourceGit.Models } private void OnRepositoryChanged(object o, FileSystemEventArgs e) + { + if (string.IsNullOrEmpty(e.Name) || e.Name.Equals(".git", StringComparison.Ordinal)) + return; + + var name = e.Name.Replace('\\', '/').TrimEnd('/'); + if (name.EndsWith("/.git", StringComparison.Ordinal)) + return; + + if (name.StartsWith(".git/", StringComparison.Ordinal)) + HandleGitDirFileChanged(name.Substring(5)); + else + HandleWorkingCopyFileChanged(name); + } + + private void OnGitDirChanged(object o, FileSystemEventArgs e) { if (string.IsNullOrEmpty(e.Name)) return; var name = e.Name.Replace('\\', '/').TrimEnd('/'); + HandleGitDirFileChanged(name); + } + + private void OnWorkingCopyChanged(object o, FileSystemEventArgs e) + { + if (string.IsNullOrEmpty(e.Name)) + return; + + var name = e.Name.Replace('\\', '/').TrimEnd('/'); + if (name.Equals(".git", StringComparison.Ordinal) || + name.StartsWith(".git/", StringComparison.Ordinal) || + name.EndsWith("/.git", StringComparison.Ordinal)) + return; + + HandleWorkingCopyFileChanged(name); + } + + private void HandleGitDirFileChanged(string name) + { if (name.Contains("fsmonitor--daemon/", StringComparison.Ordinal) || name.EndsWith(".lock", StringComparison.Ordinal) || name.StartsWith("lfs/", StringComparison.Ordinal)) @@ -200,17 +248,8 @@ namespace SourceGit.Models } } - private void OnWorkingCopyChanged(object o, FileSystemEventArgs e) + private void HandleWorkingCopyFileChanged(string name) { - if (string.IsNullOrEmpty(e.Name)) - return; - - var name = e.Name.Replace('\\', '/').TrimEnd('/'); - if (name.Equals(".git", StringComparison.Ordinal) || - name.StartsWith(".git/", StringComparison.Ordinal) || - name.EndsWith("/.git", StringComparison.Ordinal)) - return; - if (name.StartsWith(".vs/", StringComparison.Ordinal)) return; @@ -236,8 +275,7 @@ namespace SourceGit.Models } private readonly IRepository _repo = null; - private FileSystemWatcher _repoWatcher = null; - private FileSystemWatcher _wcWatcher = null; + private List _watchers = []; private Timer _timer = null; private int _lockCount = 0; private long _updateWC = 0; From f9f44ae9cb0d2b21e54a1892dd746185173dd287 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 20:33:49 +0800 Subject: [PATCH 26/47] ux: show `Name` of stash instead of `SHA` in `Apply Stash` and `Drop Stash` popup Signed-off-by: leo --- src/Views/ApplyStash.axaml | 5 ++--- src/Views/DropStash.axaml | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Views/ApplyStash.axaml b/src/Views/ApplyStash.axaml index 44a97f42..505e7662 100644 --- a/src/Views/ApplyStash.axaml +++ b/src/Views/ApplyStash.axaml @@ -3,7 +3,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:SourceGit.ViewModels" - xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.ApplyStash" x:DataType="vm:ApplyStash"> @@ -21,8 +20,8 @@ HorizontalAlignment="Left" VerticalAlignment="Center" Data="{StaticResource Icons.Stashes}"/> - - + + @@ -21,8 +20,8 @@ HorizontalAlignment="Left" VerticalAlignment="Center" Data="{StaticResource Icons.Stashes}"/> - - + +
From 6729d4e8968705051d903f1a4b72a92f75cbf09f Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 18 Jun 2025 22:10:23 +0800 Subject: [PATCH 27/47] feature: supports to ignore new files in folder from context menu of selected folder node in change tree (#1432) Signed-off-by: leo --- src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/Resources/Locales/zh_TW.axaml | 1 + src/ViewModels/WorkingCopy.cs | 122 +++++++++++++++++++++--------- src/Views/WorkingCopy.axaml.cs | 8 +- 5 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index a4066891..c459bb88 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -764,6 +764,7 @@ Git Ignore Ignore all *{0} files Ignore *{0} files in the same folder + Ignore files in this folder Ignore files in the same folder Ignore this file only Amend diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 783cb664..988fd329 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -768,6 +768,7 @@ 添加至 .gitignore 忽略列表 忽略所有 *{0} 文件 忽略同目录下所有 *{0} 文件 + 忽略该目录下的新文件 忽略同目录下所有文件 忽略本文件 修补 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index d8aff0fd..4b9e9bb5 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -768,6 +768,7 @@ 加入至 .gitignore 忽略清單 忽略所有 *{0} 檔案 忽略同路徑下所有 *{0} 檔案 + 忽略本路徑下的新增檔案 忽略同路徑下所有檔案 忽略本檔案 修補 diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 09ebc6f6..48a1b206 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -581,7 +581,7 @@ namespace SourceGit.ViewModels DoCommit(false, true); } - public ContextMenu CreateContextMenuForUnstagedChanges() + public ContextMenu CreateContextMenuForUnstagedChanges(string selectedSingleFolder) { if (_selectedUnstaged == null || _selectedUnstaged.Count == 0) return null; @@ -761,52 +761,87 @@ namespace SourceGit.ViewModels var hasExtra = false; if (change.WorkTree == Models.ChangeState.Untracked) { - var isRooted = change.Path.IndexOf('/', StringComparison.Ordinal) <= 0; var addToIgnore = new MenuItem(); addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); - var singleFile = new MenuItem(); - singleFile.Header = App.Text("WorkingCopy.AddToGitIgnore.SingleFile"); - singleFile.Click += (_, e) => + if (!string.IsNullOrEmpty(selectedSingleFolder)) { - Commands.GitIgnore.Add(_repo.FullPath, change.Path); - e.Handled = true; - }; - addToIgnore.Items.Add(singleFile); - - var byParentFolder = new MenuItem(); - byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder"); - byParentFolder.IsVisible = !isRooted; - byParentFolder.Click += (_, e) => - { - var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); - Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); - e.Handled = true; - }; - addToIgnore.Items.Add(byParentFolder); - - if (!string.IsNullOrEmpty(extension)) - { - var byExtension = new MenuItem(); - byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension); - byExtension.Click += (_, e) => + var ignoreFolder = new MenuItem(); + ignoreFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InFolder"); + ignoreFolder.Click += (_, e) => { - Commands.GitIgnore.Add(_repo.FullPath, $"*{extension}"); + Commands.GitIgnore.Add(_repo.FullPath, $"{selectedSingleFolder}/"); e.Handled = true; }; - addToIgnore.Items.Add(byExtension); + addToIgnore.Items.Add(ignoreFolder); + } + else + { + var isRooted = change.Path.IndexOf('/', StringComparison.Ordinal) <= 0; + var singleFile = new MenuItem(); + singleFile.Header = App.Text("WorkingCopy.AddToGitIgnore.SingleFile"); + singleFile.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, change.Path); + e.Handled = true; + }; + addToIgnore.Items.Add(singleFile); - var byExtensionInSameFolder = new MenuItem(); - byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension); - byExtensionInSameFolder.IsVisible = !isRooted; - byExtensionInSameFolder.Click += (_, e) => + var byParentFolder = new MenuItem(); + byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder"); + byParentFolder.IsVisible = !isRooted; + byParentFolder.Click += (_, e) => { var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); - Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}"); + Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); e.Handled = true; }; - addToIgnore.Items.Add(byExtensionInSameFolder); + addToIgnore.Items.Add(byParentFolder); + + if (!string.IsNullOrEmpty(extension)) + { + var byExtension = new MenuItem(); + byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension); + byExtension.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, $"*{extension}"); + e.Handled = true; + }; + addToIgnore.Items.Add(byExtension); + + var byExtensionInSameFolder = new MenuItem(); + byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension); + byExtensionInSameFolder.IsVisible = !isRooted; + byExtensionInSameFolder.Click += (_, e) => + { + var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); + Commands.GitIgnore.Add(_repo.FullPath, $"{dir}/*{extension}"); + e.Handled = true; + }; + addToIgnore.Items.Add(byExtensionInSameFolder); + } + } + + menu.Items.Add(addToIgnore); + hasExtra = true; + } + else if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var addToIgnore = new MenuItem(); + addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); + addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); + + if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var ignoreFolder = new MenuItem(); + ignoreFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InFolder"); + ignoreFolder.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, $"{selectedSingleFolder}/"); + e.Handled = true; + }; + addToIgnore.Items.Add(ignoreFolder); } menu.Items.Add(addToIgnore); @@ -1086,6 +1121,25 @@ namespace SourceGit.ViewModels menu.Items.Add(discard); menu.Items.Add(stash); menu.Items.Add(patch); + + if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var ignoreFolder = new MenuItem(); + ignoreFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InFolder"); + ignoreFolder.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, $"{selectedSingleFolder}/"); + e.Handled = true; + }; + + var addToIgnore = new MenuItem(); + addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); + addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); + addToIgnore.Items.Add(ignoreFolder); + + menu.Items.Add(new MenuItem() { Header = "-" }); + menu.Items.Add(addToIgnore); + } } return menu; diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index ca2ebbb7..93293c68 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -1,6 +1,7 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.VisualTree; namespace SourceGit.Views { @@ -29,7 +30,12 @@ namespace SourceGit.Views { if (DataContext is ViewModels.WorkingCopy vm && sender is Control control) { - var menu = vm.CreateContextMenuForUnstagedChanges(); + var container = control.FindDescendantOfType(); + var selectedSingleFolder = string.Empty; + if (container is { SelectedItems: { Count: 1 }, SelectedItem: ViewModels.ChangeTreeNode { IsFolder: true } node }) + selectedSingleFolder = node.FullPath; + + var menu = vm.CreateContextMenuForUnstagedChanges(selectedSingleFolder); menu?.Open(control); e.Handled = true; } From e81674912c1d185157ade9bd83f675a29ca35022 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Jun 2025 09:12:27 +0800 Subject: [PATCH 28/47] refactor: remove duplicated context menu to ignore untracked files under folder Signed-off-by: leo --- src/Resources/Locales/de_DE.axaml | 1 - src/Resources/Locales/en_US.axaml | 3 +-- src/Resources/Locales/es_ES.axaml | 1 - src/Resources/Locales/fr_FR.axaml | 1 - src/Resources/Locales/it_IT.axaml | 1 - src/Resources/Locales/ja_JP.axaml | 1 - src/Resources/Locales/pt_BR.axaml | 1 - src/Resources/Locales/ru_RU.axaml | 1 - src/Resources/Locales/ta_IN.axaml | 1 - src/Resources/Locales/uk_UA.axaml | 1 - src/Resources/Locales/zh_CN.axaml | 1 - src/Resources/Locales/zh_TW.axaml | 1 - src/ViewModels/WorkingCopy.cs | 11 ----------- 13 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index c26fcd4d..07c2e5f6 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -735,7 +735,6 @@ Git Ignore Ignoriere alle *{0} Dateien Ignoriere *{0} Datein im selben Ordner - Ignoriere Dateien im selben Ordner Ignoriere nur diese Datei Amend Du kannst diese Datei jetzt stagen. diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index c459bb88..d6bdbb93 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -764,8 +764,7 @@ Git Ignore Ignore all *{0} files Ignore *{0} files in the same folder - Ignore files in this folder - Ignore files in the same folder + Ignore untracked files in this folder Ignore this file only Amend You can stage this file now. diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index ebf4f4aa..d66e515a 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -765,7 +765,6 @@ Git Ignore Ignorar todos los archivos *{0} Ignorar archivos *{0} en la misma carpeta - Ignorar archivos en la misma carpeta Ignorar solo este archivo Enmendar Puedes hacer stage a este archivo ahora. diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml index 14241cf8..8e1fd7bd 100644 --- a/src/Resources/Locales/fr_FR.axaml +++ b/src/Resources/Locales/fr_FR.axaml @@ -707,7 +707,6 @@ Git Ignore Ignorer tous les *{0} fichiers Ignorer *{0} fichiers dans le même dossier - Ignorer les fichiers dans le même dossier N'ignorer que ce fichier Amender Vous pouvez indexer ce fichier. diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml index c2072ba5..62f15e38 100644 --- a/src/Resources/Locales/it_IT.axaml +++ b/src/Resources/Locales/it_IT.axaml @@ -745,7 +745,6 @@ Git Ignore Ignora tutti i file *{0} Ignora i file *{0} nella stessa cartella - Ignora i file nella stessa cartella Ignora solo questo file Modifica Puoi aggiungere in stage questo file ora. diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml index 8da546cb..bf9fe586 100644 --- a/src/Resources/Locales/ja_JP.axaml +++ b/src/Resources/Locales/ja_JP.axaml @@ -705,7 +705,6 @@ Git Ignore すべての*{0}ファイルを無視 同じフォルダ内の*{0}ファイルを無視 - 同じフォルダ内のファイルを無視 このファイルのみを無視 Amend このファイルを今すぐステージできます。 diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 8b3a5d04..fecd9540 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -645,7 +645,6 @@ Git Ignore Ignorar todos os arquivos *{0} Ignorar arquivos *{0} na mesma pasta - Ignorar arquivos na mesma pasta Ignorar apenas este arquivo Corrigir Você pode stagear este arquivo agora. diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index cce18629..f84965a1 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -763,7 +763,6 @@ Игнорировать Git Игнорировать все *{0} файлы Игнорировать *{0} файлы в том же каталоге - Игнорировать файлы в том же каталоге Игнорировать только эти файлы Изменить Теперь вы можете сформировать этот файл. diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml index ec102f19..248d5f42 100644 --- a/src/Resources/Locales/ta_IN.axaml +++ b/src/Resources/Locales/ta_IN.axaml @@ -705,7 +705,6 @@ அறிவிலி புறக்கணி எல்லா *{0} கோப்புகளையும் புறக்கணி ஒரே கோப்புறையில் *{0} கோப்புகளைப் புறக்கணி - ஒரே கோப்புறையில் கோப்புகளைப் புறக்கணி இந்த கோப்பை மட்டும் புறக்கணி பின்னொட்டு இந்த கோப்பை இப்போது நீங்கள் நிலைப்படுத்தலாம். diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml index ad3b8259..5d120117 100644 --- a/src/Resources/Locales/uk_UA.axaml +++ b/src/Resources/Locales/uk_UA.axaml @@ -711,7 +711,6 @@ Git Ignore Ігнорувати всі файли *{0} Ігнорувати файли *{0} у цій же теці - Ігнорувати файли у цій же теці Ігнорувати лише цей файл Amend (Доповнити) Тепер ви можете проіндексувати цей файл. diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 988fd329..803f0498 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -769,7 +769,6 @@ 忽略所有 *{0} 文件 忽略同目录下所有 *{0} 文件 忽略该目录下的新文件 - 忽略同目录下所有文件 忽略本文件 修补 现在您已可将其加入暂存区中 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 4b9e9bb5..91ac765d 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -769,7 +769,6 @@ 忽略所有 *{0} 檔案 忽略同路徑下所有 *{0} 檔案 忽略本路徑下的新增檔案 - 忽略同路徑下所有檔案 忽略本檔案 修補 現在您已可將其加入暫存區中 diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 48a1b206..d613a3c1 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -788,17 +788,6 @@ namespace SourceGit.ViewModels }; addToIgnore.Items.Add(singleFile); - var byParentFolder = new MenuItem(); - byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder"); - byParentFolder.IsVisible = !isRooted; - byParentFolder.Click += (_, e) => - { - var dir = Path.GetDirectoryName(change.Path)!.Replace('\\', '/').TrimEnd('/'); - Commands.GitIgnore.Add(_repo.FullPath, dir + "/"); - e.Handled = true; - }; - addToIgnore.Items.Add(byParentFolder); - if (!string.IsNullOrEmpty(extension)) { var byExtension = new MenuItem(); From fcf1107304b700b67b07256f940369258f9d3b7b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 19 Jun 2025 01:13:09 +0000 Subject: [PATCH 29/47] doc: Update translation status and sort locale files --- TRANSLATION.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index aeeb8a02..c0110fe1 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.77%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-95.64%25-yellow)
Missing keys in de_DE.axaml @@ -44,11 +44,12 @@ This document shows the translation status of each locale file in the repository - Text.Submodule.Status.RevisionChanged - Text.Submodule.Status.Unmerged - Text.Submodule.URL +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.ResetAuthor
-### ![es__ES](https://img.shields.io/badge/es__ES-99.63%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.50%25-yellow)
Missing keys in es_ES.axaml @@ -56,10 +57,11 @@ This document shows the translation status of each locale file in the repository - Text.Merge.Edit - Text.Stash.Mode - Text.StashCM.CopyMessage +- Text.WorkingCopy.AddToGitIgnore.InFolder
-### ![fr__FR](https://img.shields.io/badge/fr__FR-91.66%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-91.53%25-yellow)
Missing keys in fr_FR.axaml @@ -125,6 +127,7 @@ This document shows the translation status of each locale file in the repository - Text.ViewLogs.Clear - Text.ViewLogs.CopyLog - Text.ViewLogs.Delete +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -134,7 +137,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-97.01%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-96.89%25-yellow)
Missing keys in it_IT.axaml @@ -162,11 +165,12 @@ This document shows the translation status of each locale file in the repository - Text.Stash.Mode - Text.StashCM.CopyMessage - Text.Submodule.Deinit +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.ResetAuthor
-### ![ja__JP](https://img.shields.io/badge/ja__JP-91.41%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-91.28%25-yellow)
Missing keys in ja_JP.axaml @@ -234,6 +238,7 @@ This document shows the translation status of each locale file in the repository - Text.ViewLogs.Clear - Text.ViewLogs.CopyLog - Text.ViewLogs.Delete +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts @@ -243,7 +248,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-83.69%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-83.56%25-yellow)
Missing keys in pt_BR.axaml @@ -371,6 +376,7 @@ This document shows the translation status of each locale file in the repository - Text.ViewLogs.Clear - Text.ViewLogs.CopyLog - Text.ViewLogs.Delete +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.CommitToEdit - Text.WorkingCopy.ConfirmCommitWithFilter - Text.WorkingCopy.Conflicts.OpenExternalMergeTool @@ -382,7 +388,7 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.38%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.25%25-yellow)
Missing keys in ru_RU.axaml @@ -392,10 +398,11 @@ This document shows the translation status of each locale file in the repository - Text.Merge.Edit - Text.Stash.Mode - Text.StashCM.CopyMessage +- Text.WorkingCopy.AddToGitIgnore.InFolder
-### ![ta__IN](https://img.shields.io/badge/ta__IN-91.53%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-91.41%25-yellow)
Missing keys in ta_IN.axaml @@ -463,6 +470,7 @@ This document shows the translation status of each locale file in the repository - Text.ViewLogs.Clear - Text.ViewLogs.CopyLog - Text.ViewLogs.Delete +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.Conflicts.OpenExternalMergeTool - Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts - Text.WorkingCopy.Conflicts.UseMine @@ -471,7 +479,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-92.78%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-92.65%25-yellow)
Missing keys in uk_UA.axaml @@ -533,6 +541,7 @@ This document shows the translation status of each locale file in the repository - Text.ViewLogs.Clear - Text.ViewLogs.CopyLog - Text.ViewLogs.Delete +- Text.WorkingCopy.AddToGitIgnore.InFolder - Text.WorkingCopy.ResetAuthor
From cadcf40d741304b5d313792c3cf9335d3e9d878a Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Jun 2025 09:32:12 +0800 Subject: [PATCH 30/47] feature: support to open selected folder in file manager Signed-off-by: leo --- src/ViewModels/WorkingCopy.cs | 35 +++++++++++++++++++++++++++++++++- src/Views/WorkingCopy.axaml.cs | 7 ++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index d613a3c1..47b3fae6 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1052,6 +1052,22 @@ namespace SourceGit.ViewModels return menu; } + if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var dir = Path.Combine(_repo.FullPath, selectedSingleFolder); + var explore = new MenuItem(); + explore.Header = App.Text("RevealFile"); + explore.Icon = App.CreateMenuIcon("Icons.Explore"); + explore.IsEnabled = Directory.Exists(dir); + explore.Click += (_, e) => + { + Native.OS.OpenInFileManager(dir, true); + e.Handled = true; + }; + menu.Items.Add(explore); + menu.Items.Add(new MenuItem() { Header = "-" }); + } + var stage = new MenuItem(); stage.Header = App.Text("FileCM.StageMulti", _selectedUnstaged.Count); stage.Icon = App.CreateMenuIcon("Icons.File.Add"); @@ -1134,7 +1150,7 @@ namespace SourceGit.ViewModels return menu; } - public ContextMenu CreateContextMenuForStagedChanges() + public ContextMenu CreateContextMenuForStagedChanges(string selectedSingleFolder) { if (_selectedStaged == null || _selectedStaged.Count == 0) return null; @@ -1383,6 +1399,23 @@ namespace SourceGit.ViewModels } else { + if (!string.IsNullOrEmpty(selectedSingleFolder)) + { + var dir = Path.Combine(_repo.FullPath, selectedSingleFolder); + var explore = new MenuItem(); + explore.IsEnabled = Directory.Exists(dir); + explore.Header = App.Text("RevealFile"); + explore.Icon = App.CreateMenuIcon("Icons.Explore"); + explore.Click += (_, e) => + { + Native.OS.OpenInFileManager(dir, true); + e.Handled = true; + }; + + menu.Items.Add(explore); + menu.Items.Add(new MenuItem() { Header = "-" }); + } + var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.UnstageMulti", _selectedStaged.Count); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index 93293c68..bbc95d8d 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -45,7 +45,12 @@ namespace SourceGit.Views { if (DataContext is ViewModels.WorkingCopy vm && sender is Control control) { - var menu = vm.CreateContextMenuForStagedChanges(); + var container = control.FindDescendantOfType(); + var selectedSingleFolder = string.Empty; + if (container is { SelectedItems: { Count: 1 }, SelectedItem: ViewModels.ChangeTreeNode { IsFolder: true } node }) + selectedSingleFolder = node.FullPath; + + var menu = vm.CreateContextMenuForStagedChanges(selectedSingleFolder); menu?.Open(control); e.Handled = true; } From 88fd8f32f1815606fe7325c9cace675cbd2f55c9 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Thu, 19 Jun 2025 12:27:31 +1000 Subject: [PATCH 31/47] feature: double tap specific branch (#1416) * feature: double tap specific branch * exactly match behavior of left sidebar --- src/ViewModels/Histories.cs | 41 +++++++++++++++++++++++++++++++- src/Views/CommitRefsPresenter.cs | 16 +++++++++++++ src/Views/Histories.axaml.cs | 6 ++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index cb96f52f..ebc23c7f 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -209,8 +209,47 @@ namespace SourceGit.ViewModels } } - public void DoubleTapped(Models.Commit commit) + public void DoubleTapped(Models.Commit commit, Models.Decorator decorator = null) { + if (decorator != null) + { + if (decorator.Type == Models.DecoratorType.LocalBranchHead) + { + var b = _repo.Branches.Find(x => x.FriendlyName == decorator.Name); + if (b != null) + { + _repo.CheckoutBranch(b); + return; + } + } + else if (decorator.Type == Models.DecoratorType.RemoteBranchHead) + { + var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == decorator.Name); + if (remoteBranch != null) + { + var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName); + if (localBranch != null) + { + if (localBranch.IsCurrent) + return; + if (localBranch.TrackStatus.Ahead.Count > 0) + { + if (_repo.CanCreatePopup()) + _repo.ShowPopup(new CreateBranch(_repo, remoteBranch)); + } + else if (localBranch.TrackStatus.Behind.Count > 0) + { + if (_repo.CanCreatePopup()) + _repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch)); + } + else + _repo.CheckoutBranch(localBranch); + return; + } + } + } + } + if (commit == null || commit.IsCurrentHead) return; diff --git a/src/Views/CommitRefsPresenter.cs b/src/Views/CommitRefsPresenter.cs index 507da1c2..e8fa4517 100644 --- a/src/Views/CommitRefsPresenter.cs +++ b/src/Views/CommitRefsPresenter.cs @@ -156,6 +156,22 @@ namespace SourceGit.Views InvalidateMeasure(); } + public Models.Decorator DecoratorAt(Point point) + { + if (DataContext is not Models.Commit commit) + return null; + + var x = 0.0; + for (var i = 0; i < _items.Count; i++) + { + x += _items[i].Width + 4; + if (point.X < x) + return commit.Decorators[i]; + } + + return null; + } + protected override Size MeasureOverride(Size availableSize) { _items.Clear(); diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs index 2f84b318..38036f98 100644 --- a/src/Views/Histories.axaml.cs +++ b/src/Views/Histories.axaml.cs @@ -173,10 +173,14 @@ namespace SourceGit.Views { if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems.Count: 1 }) { + Models.Decorator decorator = null; + if (e.Source is CommitRefsPresenter crp) + decorator = crp.DecoratorAt(e.GetPosition(crp)); + var source = e.Source as Control; var item = source.FindAncestorOfType(); if (item is { DataContext: Models.Commit commit }) - histories.DoubleTapped(commit); + histories.DoubleTapped(commit, decorator); } e.Handled = true; } From af2b644792d80ded48c9477f0a65aef668fe271f Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 19 Jun 2025 11:31:04 +0800 Subject: [PATCH 32/47] code_review: PR #1416 - Split `DoubleTapped` into two methods: `CheckoutBranchByDecorator` and `CheckoutBranchByCommit` - Move `DoubleTappedEvent` from whole ListBox to the row tapped actually - Do nothing if the decorator double-clicked is HEAD - Code-style Signed-off-by: leo --- src/Models/Watcher.cs | 2 +- src/ViewModels/Histories.cs | 116 +++++++++++++++++-------------- src/ViewModels/WorkingCopy.cs | 4 +- src/Views/CommitRefsPresenter.cs | 33 +++++---- src/Views/Histories.axaml | 3 +- src/Views/Histories.axaml.cs | 35 +++++----- 6 files changed, 101 insertions(+), 92 deletions(-) diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs index abceea9a..4d6656e3 100644 --- a/src/Models/Watcher.cs +++ b/src/Models/Watcher.cs @@ -55,7 +55,7 @@ namespace SourceGit.Models _watchers.Add(wc); _watchers.Add(git); - } + } _timer = new Timer(Tick, null, 100, 100); } diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index ebc23c7f..a004ed79 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -209,48 +209,56 @@ namespace SourceGit.ViewModels } } - public void DoubleTapped(Models.Commit commit, Models.Decorator decorator = null) + public bool CheckoutBranchByDecorator(Models.Decorator decorator) { - if (decorator != null) + if (decorator == null) + return false; + + if (decorator.Type == Models.DecoratorType.CurrentBranchHead || + decorator.Type == Models.DecoratorType.CurrentCommitHead) + return true; + + if (decorator.Type == Models.DecoratorType.LocalBranchHead) { - if (decorator.Type == Models.DecoratorType.LocalBranchHead) - { - var b = _repo.Branches.Find(x => x.FriendlyName == decorator.Name); - if (b != null) - { - _repo.CheckoutBranch(b); - return; - } - } - else if (decorator.Type == Models.DecoratorType.RemoteBranchHead) - { - var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == decorator.Name); - if (remoteBranch != null) - { - var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName); - if (localBranch != null) - { - if (localBranch.IsCurrent) - return; - if (localBranch.TrackStatus.Ahead.Count > 0) - { - if (_repo.CanCreatePopup()) - _repo.ShowPopup(new CreateBranch(_repo, remoteBranch)); - } - else if (localBranch.TrackStatus.Behind.Count > 0) - { - if (_repo.CanCreatePopup()) - _repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch)); - } - else - _repo.CheckoutBranch(localBranch); - return; - } - } - } + var b = _repo.Branches.Find(x => x.Name == decorator.Name); + if (b == null) + return false; + + _repo.CheckoutBranch(b); + return true; } - if (commit == null || commit.IsCurrentHead) + if (decorator.Type == Models.DecoratorType.RemoteBranchHead) + { + var rb = _repo.Branches.Find(x => x.FriendlyName == decorator.Name); + if (rb == null) + return false; + + var lb = _repo.Branches.Find(x => x.IsLocal && x.Upstream == rb.FullName); + if (lb == null || lb.TrackStatus.Ahead.Count > 0) + { + if (_repo.CanCreatePopup()) + _repo.ShowPopup(new CreateBranch(_repo, rb)); + } + else if (lb.TrackStatus.Behind.Count > 0) + { + if (_repo.CanCreatePopup()) + _repo.ShowPopup(new CheckoutAndFastForward(_repo, lb, rb)); + } + else if (!lb.IsCurrent) + { + _repo.CheckoutBranch(lb); + } + + return true; + } + + return false; + } + + public void CheckoutBranchByCommit(Models.Commit commit) + { + if (commit.IsCurrentHead) return; var firstRemoteBranch = null as Models.Branch; @@ -258,28 +266,28 @@ namespace SourceGit.ViewModels { if (d.Type == Models.DecoratorType.LocalBranchHead) { - var b = _repo.Branches.Find(x => x.FriendlyName == d.Name); - if (b != null) - { - _repo.CheckoutBranch(b); - return; - } + var b = _repo.Branches.Find(x => x.Name == d.Name); + if (b == null) + continue; + + _repo.CheckoutBranch(b); + return; } else if (d.Type == Models.DecoratorType.RemoteBranchHead) { - var remoteBranch = _repo.Branches.Find(x => x.FriendlyName == d.Name); - if (remoteBranch != null) + var rb = _repo.Branches.Find(x => x.FriendlyName == d.Name); + if (rb == null) + continue; + + var lb = _repo.Branches.Find(x => x.IsLocal && x.Upstream == rb.FullName); + if (lb is { TrackStatus.Ahead.Count: 0 }) { - var localBranch = _repo.Branches.Find(x => x.IsLocal && x.Upstream == remoteBranch.FullName); - if (localBranch is { TrackStatus.Ahead.Count: 0 }) - { - if (_repo.CanCreatePopup()) - _repo.ShowPopup(new CheckoutAndFastForward(_repo, localBranch, remoteBranch)); - return; - } + if (_repo.CanCreatePopup()) + _repo.ShowPopup(new CheckoutAndFastForward(_repo, lb, rb)); + return; } - firstRemoteBranch ??= remoteBranch; + firstRemoteBranch ??= rb; } } diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 47b3fae6..f41bc162 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -810,7 +810,7 @@ namespace SourceGit.ViewModels }; addToIgnore.Items.Add(byExtensionInSameFolder); } - } + } menu.Items.Add(addToIgnore); hasExtra = true; @@ -1414,7 +1414,7 @@ namespace SourceGit.ViewModels menu.Items.Add(explore); menu.Items.Add(new MenuItem() { Header = "-" }); - } + } var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.UnstageMulti", _selectedStaged.Count); diff --git a/src/Views/CommitRefsPresenter.cs b/src/Views/CommitRefsPresenter.cs index e8fa4517..a5717c6c 100644 --- a/src/Views/CommitRefsPresenter.cs +++ b/src/Views/CommitRefsPresenter.cs @@ -17,6 +17,7 @@ namespace SourceGit.Views public IBrush Brush { get; set; } = null; public bool IsHead { get; set; } = false; public double Width { get; set; } = 0.0; + public Models.Decorator Decorator { get; set; } = null; } public static readonly StyledProperty FontFamilyProperty = @@ -93,6 +94,19 @@ namespace SourceGit.Views ShowTagsProperty); } + public Models.Decorator DecoratorAt(Point point) + { + var x = 0.0; + foreach (var item in _items) + { + x += item.Width; + if (point.X < x) + return item.Decorator; + } + + return null; + } + public override void Render(DrawingContext context) { if (_items.Count == 0) @@ -156,22 +170,6 @@ namespace SourceGit.Views InvalidateMeasure(); } - public Models.Decorator DecoratorAt(Point point) - { - if (DataContext is not Models.Commit commit) - return null; - - var x = 0.0; - for (var i = 0; i < _items.Count; i++) - { - x += _items[i].Width + 4; - if (point.X < x) - return commit.Decorators[i]; - } - - return null; - } - protected override Size MeasureOverride(Size availableSize) { _items.Clear(); @@ -214,7 +212,8 @@ namespace SourceGit.Views { Label = label, Brush = normalBG, - IsHead = isHead + IsHead = isHead, + Decorator = decorator, }; StreamGeometry geo; diff --git a/src/Views/Histories.axaml b/src/Views/Histories.axaml index d19edd0e..35951cb1 100644 --- a/src/Views/Histories.axaml +++ b/src/Views/Histories.axaml @@ -70,7 +70,6 @@ LayoutUpdated="OnCommitListLayoutUpdated" SelectionChanged="OnCommitListSelectionChanged" ContextRequested="OnCommitListContextRequested" - DoubleTapped="OnCommitListDoubleTapped" KeyDown="OnCommitListKeyDown">