From 54b179fb0b5a2acda8cabef9ae39386cbc67c9ba Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 7 Aug 2026 10:23:45 +0200 Subject: [PATCH] fix(diff): resolve themed brushes and stop recomputing alignment on layout toggle --- .../Views/Controls/DiffTextView.axaml.cs | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/ClaudeDo.Ui/Views/Controls/DiffTextView.axaml.cs b/src/ClaudeDo.Ui/Views/Controls/DiffTextView.axaml.cs index 9149201c..914cb3d7 100644 --- a/src/ClaudeDo.Ui/Views/Controls/DiffTextView.axaml.cs +++ b/src/ClaudeDo.Ui/Views/Controls/DiffTextView.axaml.cs @@ -76,23 +76,34 @@ public partial class DiffTextView : UserControl _leftTm = LeftEditor.InstallTextMate(Registry); _rightTm = RightEditor.InstallTextMate(Registry); InstallRenderers(); - Rebuild(); + ReloadFile(); HookScrollSync(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); - if (change.Property == FileProperty || change.Property == IsSplitProperty) - Rebuild(); + if (change.Property == FileProperty) + ReloadFile(); + else if (change.Property == IsSplitProperty) + RefreshLayout(); else if (change.Property == WrapLinesProperty) ApplyWrap(); } - private void Rebuild() + /// Recomputes the alignment (word-diff LCS) for the current and then + /// refreshes everything downstream of it. Only ever needed when the file actually changes. + private void ReloadFile() { _aligned = DiffAlignment.Build(File?.Lines); + RefreshLayout(); + } + /// Re-applies the current to the editors for the current layout + /// (split vs unified). A single already carries both row sets, + /// so toggling never needs to re-run the alignment. + private void RefreshLayout() + { var split = IsSplit; RightEditor.IsVisible = split; PaneDivider.IsVisible = split; @@ -181,7 +192,7 @@ public partial class DiffTextView : UserControl } private IBrush Brush(string key, Color fallback) => - this.TryGetResource(key, ActualThemeVariant, out var value) && value is IBrush brush + this.TryFindResource(key, out var value) && value is IBrush brush ? brush : new SolidColorBrush(fallback); @@ -235,11 +246,20 @@ public partial class DiffTextView : UserControl if (WrapLines) { // Line heights differ once lines wrap, so anchor on the top visible line. + // ScrollToLine/ScrollTo are "bring into view" primitives (they park the line + // near mid-viewport past a hysteresis threshold) — top-align by computing the + // target's own vertical offset for that document line and assigning it + // directly, the same way the non-wrap branch assigns Offset below. That is + // synchronous, so the same offset-comparison guard makes the echo self-terminate. var topLine = sourceEditor.TextArea.TextView.VisualLines is { Count: > 0 } visualLines ? visualLines[0].FirstDocumentLine.LineNumber : (int?)null; if (topLine is { } line && line >= 1 && line <= targetEditor.Document.LineCount) - targetEditor.ScrollToLine(line); + { + var targetTop = targetEditor.TextArea.TextView.GetVisualTopByDocumentLine(line); + if (Math.Abs(target.Offset.Y - targetTop) > 0.5) + target.Offset = new Vector(target.Offset.X, targetTop); + } } else if (Math.Abs(target.Offset.Y - source.Offset.Y) > 0.5) {