From e603f3fe9bb17a35547e5d76560240282752f47a Mon Sep 17 00:00:00 2001 From: Ivn Nv Date: Tue, 5 May 2026 12:47:02 +0300 Subject: [PATCH] feature: allow copying ref names from commit info panel Adds a small copy button next to each ref pill in the commit info panel. Clicking it copies the ref name (e.g. "main", "origin/feature") to the clipboard, matching the existing copy affordance on the SHA row. CommitRefsPresenter gains an optional Decorator styled property. When set, the presenter renders that single decorator instead of iterating DataContext.Decorators. The existing multi-decorator path is unchanged, so the Histories grid still renders refs the same way it did before. CommitBaseInfo's REFS row, previously a single CommitRefsPresenter rendering all decorators in one custom-drawn run, is now an ItemsControl over Decorators where each item is a single-decorator presenter plus a copy Button. The Button picks up Avalonia's standard tooltip and hover styling. Wrap now happens between pill+button groups instead of inside one continuous presenter. Pill geometry, icons, fills and outlines are unchanged. The Histories grid is intentionally untouched. --- src/Views/CommitBaseInfo.axaml | 35 ++++++++++++++++++++++++------- src/Views/CommitBaseInfo.axaml.cs | 8 +++++++ src/Views/CommitRefsPresenter.cs | 23 ++++++++++++++++---- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml index 67c1c7b60..9b5520f15 100644 --- a/src/Views/CommitBaseInfo.axaml +++ b/src/Views/CommitBaseInfo.axaml @@ -194,13 +194,34 @@ - - - + + + + + + + + + + + + + + + + diff --git a/src/Views/CommitBaseInfo.axaml.cs b/src/Views/CommitBaseInfo.axaml.cs index b617476d0..b8715ce28 100644 --- a/src/Views/CommitBaseInfo.axaml.cs +++ b/src/Views/CommitBaseInfo.axaml.cs @@ -87,6 +87,14 @@ protected override void OnUnloaded(RoutedEventArgs e) _iconResetTimer?.Dispose(); } + private async void OnCopyRefName(object sender, RoutedEventArgs e) + { + if (sender is Button { DataContext: Models.Decorator decorator }) + await this.CopyTextAsync(decorator.Name); + + e.Handled = true; + } + private async void OnCopyCommitSHA(object sender, RoutedEventArgs e) { if (sender is Button { DataContext: Models.Commit commit }) diff --git a/src/Views/CommitRefsPresenter.cs b/src/Views/CommitRefsPresenter.cs index ca8eabdd5..f403c9c0c 100644 --- a/src/Views/CommitRefsPresenter.cs +++ b/src/Views/CommitRefsPresenter.cs @@ -83,6 +83,15 @@ public bool ShowTags set => SetValue(ShowTagsProperty, value); } + public static readonly StyledProperty DecoratorProperty = + AvaloniaProperty.Register(nameof(Decorator)); + + public Models.Decorator Decorator + { + get => GetValue(DecoratorProperty); + set => SetValue(DecoratorProperty, value); + } + static CommitRefsPresenter() { AffectsMeasure( @@ -91,7 +100,8 @@ static CommitRefsPresenter() ForegroundProperty, UseGraphColorProperty, BackgroundProperty, - ShowTagsProperty); + ShowTagsProperty, + DecoratorProperty); } public Models.Decorator DecoratorAt(Point point) @@ -174,16 +184,21 @@ protected override Size MeasureOverride(Size availableSize) { _items.Clear(); - if (DataContext is not Models.Commit commit) + var commit = DataContext as Models.Commit; + IList refs; + if (Decorator != null) + refs = new[] { Decorator }; + else if (commit != null) + refs = commit.Decorators; + else return new Size(0, 0); - var refs = commit.Decorators; if (refs is { Count: > 0 }) { var typeface = new Typeface(FontFamily); var typefaceBold = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Bold); var fg = Foreground; - var normalBG = UseGraphColor ? Models.CommitGraph.Pens[commit.Color].Brush : Brushes.Gray; + var normalBG = UseGraphColor && commit != null ? Models.CommitGraph.Pens[commit.Color].Brush : Brushes.Gray; var labelSize = FontSize; var requiredHeight = 16.0; var x = 0.0;