Skip to content

Commit 0d7d9c2

Browse files
committed
feature: auto-scroll to first change hunk when diff file changed (#1655) (#1684)
Signed-off-by: leo <[email protected]>
1 parent c76b770 commit 0d7d9c2

File tree

3 files changed

+76
-17
lines changed

3 files changed

+76
-17
lines changed

src/ViewModels/BlockNavigation.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public class BlockNavigation : ObservableObject
77
{
88
public record Block(int Start, int End)
99
{
10-
public bool IsInRange(int line)
10+
public bool Contains(int line)
1111
{
1212
return line >= Start && line <= End;
1313
}
@@ -27,7 +27,7 @@ public string Indicator
2727
}
2828
}
2929

30-
public BlockNavigation(List<Models.TextDiffLine> lines)
30+
public BlockNavigation(List<Models.TextDiffLine> lines, bool gotoFirst)
3131
{
3232
_blocks.Clear();
3333
_current = -1;
@@ -65,6 +65,9 @@ public BlockNavigation(List<Models.TextDiffLine> lines)
6565
blocks.Add(new Block(blockStartIdx, lines.Count));
6666

6767
_blocks.AddRange(blocks);
68+
69+
if (gotoFirst)
70+
GotoFirst();
6871
}
6972

7073
public Block GetCurrentBlock()
@@ -126,7 +129,7 @@ public void UpdateByCaretPosition(int caretLine)
126129
if (_current >= 0 && _current < _blocks.Count)
127130
{
128131
var block = _blocks[_current];
129-
if (block.IsInRange(caretLine))
132+
if (block.Contains(caretLine))
130133
return;
131134
}
132135

src/ViewModels/TextDiffContext.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
namespace SourceGit.ViewModels
77
{
8+
public record TextDiffDisplayRange(int Start, int End);
9+
810
public record TextDiffSelectedChunk(double Y, double Height, int StartIdx, int EndIdx, bool Combined, bool IsOldSide)
911
{
1012
public static bool IsChanged(TextDiffSelectedChunk oldValue, TextDiffSelectedChunk newValue)
@@ -24,10 +26,6 @@ public static bool IsChanged(TextDiffSelectedChunk oldValue, TextDiffSelectedChu
2426
}
2527
}
2628

27-
public record TextDiffDisplayRange(int Start, int End)
28-
{
29-
}
30-
3129
public class TextDiffContext : ObservableObject
3230
{
3331
public Models.TextDiff Data => _data;
@@ -147,10 +145,16 @@ public class CombinedTextDiff : TextDiffContext
147145
public CombinedTextDiff(Models.TextDiff diff, CombinedTextDiff previous = null)
148146
{
149147
_data = diff;
150-
_blockNavigation = new BlockNavigation(_data.Lines);
151148

152149
if (previous != null && previous.File.Equals(File, StringComparison.Ordinal))
153-
_scrollOffset = previous.ScrollOffset;
150+
{
151+
_blockNavigation = new BlockNavigation(_data.Lines, false);
152+
_scrollOffset = previous._scrollOffset;
153+
}
154+
else
155+
{
156+
_blockNavigation = new BlockNavigation(_data.Lines, true);
157+
}
154158
}
155159

156160
public override TextDiffContext SwitchMode()
@@ -187,10 +191,16 @@ public TwoSideTextDiff(Models.TextDiff diff, TwoSideTextDiff previous = null)
187191
}
188192

189193
FillEmptyLines();
190-
_blockNavigation = new BlockNavigation(Old);
191194

192195
if (previous != null && previous.File.Equals(File, StringComparison.Ordinal))
196+
{
197+
_blockNavigation = new BlockNavigation(_data.Lines, false);
193198
_scrollOffset = previous._scrollOffset;
199+
}
200+
else
201+
{
202+
_blockNavigation = new BlockNavigation(_data.Lines, true);
203+
}
194204
}
195205

196206
public override bool IsSideBySide()

src/Views/TextDiffView.axaml.cs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public void Draw(TextView textView, DrawingContext drawingContext)
221221
if (_presenter.Document == null || !textView.VisualLinesValid)
222222
return;
223223

224-
var changeBlock = _presenter.BlockNavigation?.GetCurrentBlock();
224+
var changeBlock = _presenter.BlockNavigation.GetCurrentBlock();
225225
var changeBlockBG = new SolidColorBrush(Colors.Gray, 0.25);
226226
var changeBlockFG = new Pen(Brushes.Gray);
227227

@@ -285,7 +285,7 @@ public void Draw(TextView textView, DrawingContext drawingContext)
285285
}
286286
}
287287

288-
if (changeBlock != null && changeBlock.IsInRange(index))
288+
if (changeBlock != null && changeBlock.Contains(index))
289289
{
290290
drawingContext.DrawRectangle(changeBlockBG, null, new Rect(0, startY, width, endY - startY));
291291
if (index == changeBlock.Start)
@@ -498,7 +498,7 @@ public virtual void UpdateSelectedChunk(double y)
498498

499499
public virtual void GotoFirstChange()
500500
{
501-
var first = BlockNavigation?.GotoFirst();
501+
var first = BlockNavigation.GotoFirst();
502502
if (first != null)
503503
{
504504
TextArea.Caret.Line = first.Start;
@@ -508,7 +508,7 @@ public virtual void GotoFirstChange()
508508

509509
public virtual void GotoPrevChange()
510510
{
511-
var prev = BlockNavigation?.GotoPrev();
511+
var prev = BlockNavigation.GotoPrev();
512512
if (prev != null)
513513
{
514514
TextArea.Caret.Line = prev.Start;
@@ -518,7 +518,7 @@ public virtual void GotoPrevChange()
518518

519519
public virtual void GotoNextChange()
520520
{
521-
var next = BlockNavigation?.GotoNext();
521+
var next = BlockNavigation.GotoNext();
522522
if (next != null)
523523
{
524524
TextArea.Caret.Line = next.Start;
@@ -528,7 +528,7 @@ public virtual void GotoNextChange()
528528

529529
public virtual void GotoLastChange()
530530
{
531-
var next = BlockNavigation?.GotoLast();
531+
var next = BlockNavigation.GotoLast();
532532
if (next != null)
533533
{
534534
TextArea.Caret.Line = next.Start;
@@ -627,6 +627,23 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
627627
}
628628
}
629629

630+
protected override void OnDataContextBeginUpdate()
631+
{
632+
base.OnDataContextBeginUpdate();
633+
AutoScrollToFirstChange();
634+
}
635+
636+
protected override void OnSizeChanged(SizeChangedEventArgs e)
637+
{
638+
base.OnSizeChanged(e);
639+
640+
if (!_execSizeChanged)
641+
{
642+
_execSizeChanged = true;
643+
AutoScrollToFirstChange();
644+
}
645+
}
646+
630647
private async void OnTextAreaKeyDown(object sender, KeyEventArgs e)
631648
{
632649
if (e.KeyModifiers.Equals(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
@@ -644,7 +661,7 @@ private async void OnTextAreaKeyDown(object sender, KeyEventArgs e)
644661

645662
private void OnTextAreaCaretPositionChanged(object sender, EventArgs e)
646663
{
647-
BlockNavigation?.UpdateByCaretPosition(TextArea?.Caret?.Line ?? 0);
664+
BlockNavigation.UpdateByCaretPosition(TextArea?.Caret?.Line ?? 0);
648665
}
649666

650667
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
@@ -783,6 +800,34 @@ private void UpdateTextMate()
783800
}
784801
}
785802

803+
private void AutoScrollToFirstChange()
804+
{
805+
if (Bounds.Height < 0.1)
806+
return;
807+
808+
if (DataContext is not ViewModels.TextDiffContext ctx)
809+
return;
810+
811+
if (ctx.IsSideBySide() && !IsOld)
812+
return;
813+
814+
var curBlock = ctx.BlockNavigation.GetCurrentBlock();
815+
if (curBlock == null)
816+
return;
817+
818+
var lineHeight = TextArea.TextView.DefaultLineHeight;
819+
var vOffset = lineHeight * (curBlock.Start - 1) - Bounds.Height * 0.5;
820+
if (vOffset >= 0)
821+
{
822+
var scroller = this.FindDescendantOfType<ScrollViewer>();
823+
if (scroller != null)
824+
{
825+
ctx.ScrollOffset = new Vector(0, vOffset);
826+
scroller.Offset = ctx.ScrollOffset;
827+
}
828+
}
829+
}
830+
786831
private async Task CopyWithoutIndicatorsAsync()
787832
{
788833
var selection = TextArea.Selection;
@@ -852,6 +897,7 @@ private async Task CopyWithoutIndicatorsAsync()
852897
await App.CopyTextAsync(builder.ToString());
853898
}
854899

900+
private bool _execSizeChanged = false;
855901
private TextMate.Installation _textMate = null;
856902
private TextLocation _lastSelectStart = TextLocation.Empty;
857903
private TextLocation _lastSelectEnd = TextLocation.Empty;

0 commit comments

Comments
 (0)