Skip to content

Commit e634df7

Browse files
committed
Cherrypick - feature: add buttons to go to prev/next change in text diff view (#616)
Signed-off-by: leo <[email protected]> (cherry picked from commit 134c710) # Conflicts: # src/Views/DiffView.axaml # src/Views/TextDiffView.axaml.cs
1 parent c772545 commit e634df7

File tree

3 files changed

+153
-22
lines changed

3 files changed

+153
-22
lines changed

src/Views/DiffView.axaml

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,23 @@
3535
<!-- Toolbar Buttons -->
3636
<StackPanel Grid.Column="3" Margin="8,0,0,0" Orientation="Horizontal" VerticalAlignment="Center">
3737
<Button Classes="icon_button"
38-
Width="32"
39-
Command="{Binding PrevChange}"
38+
Width="28"
39+
Click="OnGotoPrevChange"
4040
IsVisible="{Binding IsTextDiff}"
4141
ToolTip.Tip="{DynamicResource Text.Diff.Prev}">
42-
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Diff.Prev}"/>
42+
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Up}"/>
4343
</Button>
44+
4445
<Button Classes="icon_button"
45-
Width="32"
46-
Command="{Binding NextChange}"
46+
Width="28"
47+
Click="OnGotoNextChange"
4748
IsVisible="{Binding IsTextDiff}"
4849
ToolTip.Tip="{DynamicResource Text.Diff.Next}">
49-
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Diff.Next}"/>
50+
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Down}"/>
5051
</Button>
52+
5153
<Button Classes="icon_button"
52-
Width="32"
54+
Width="28"
5355
Command="{Binding IncrUnified}"
5456
IsVisible="{Binding IsTextDiff}"
5557
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Incr}">
@@ -60,7 +62,7 @@
6062
</Button>
6163

6264
<Button Classes="icon_button"
63-
Width="32"
65+
Width="28"
6466
Command="{Binding DecrUnified}"
6567
IsVisible="{Binding IsTextDiff}"
6668
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Decr}">
@@ -74,9 +76,7 @@
7476
</Button>
7577

7678
<ToggleButton Classes="line_path"
77-
Width="32" Height="18"
78-
Background="Transparent"
79-
Padding="9,6"
79+
Width="28"
8080
Command="{Binding ToggleFullTextDiff}"
8181
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFullTextDiff, Mode=OneWay}"
8282
IsVisible="{Binding IsTextDiff}"
@@ -85,19 +85,16 @@
8585
</ToggleButton>
8686

8787
<ToggleButton Classes="line_path"
88-
Width="32" Height="18"
88+
Width="28"
8989
Background="Transparent"
90-
Padding="9,6"
9190
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting, Mode=TwoWay}"
9291
IsVisible="{Binding IsTextDiff}"
9392
ToolTip.Tip="{DynamicResource Text.Diff.SyntaxHighlight}">
9493
<Path Width="13" Height="13" Data="{StaticResource Icons.SyntaxHighlight}" Margin="0,3,0,0"/>
9594
</ToggleButton>
9695

9796
<ToggleButton Classes="line_path"
98-
Width="32" Height="18"
99-
Background="Transparent"
100-
Padding="9,6"
97+
Width="28"
10198
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap, Mode=TwoWay}"
10299
ToolTip.Tip="{DynamicResource Text.Diff.ToggleWordWrap}">
103100
<ToggleButton.IsVisible>
@@ -111,31 +108,29 @@
111108
</ToggleButton>
112109

113110
<ToggleButton Classes="line_path"
114-
Width="32"
111+
Width="28"
115112
IsChecked="{Binding IgnoreWhitespace, Mode=TwoWay}"
116113
ToolTip.Tip="{DynamicResource Text.Diff.IgnoreWhitespace}">
117114
<Path Width="14" Height="14" Stretch="Uniform" Data="{StaticResource Icons.Whitespace}"/>
118115
</ToggleButton>
119116

120117
<ToggleButton Classes="line_path"
121-
Width="32"
118+
Width="28"
122119
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView, Mode=TwoWay}"
123120
IsVisible="{Binding IsTextDiff}"
124121
ToolTip.Tip="{DynamicResource Text.Diff.ShowHiddenSymbols}">
125122
<Path Width="11" Height="11" Stretch="Uniform" Data="{StaticResource Icons.HiddenSymbol}" Margin="0,1,0,0"/>
126123
</ToggleButton>
127124

128125
<ToggleButton Classes="line_path"
129-
Width="32" Height="18"
130-
Background="Transparent"
131-
Padding="9,6"
126+
Width="28" Height="18"
132127
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=TwoWay}"
133128
IsVisible="{Binding IsTextDiff}"
134129
ToolTip.Tip="{DynamicResource Text.Diff.SideBySide}">
135130
<Path Width="12" Height="12" Data="{StaticResource Icons.LayoutHorizontal}" Margin="0,2,0,0"/>
136131
</ToggleButton>
137132

138-
<Button Classes="icon_button" Width="32" Command="{Binding OpenExternalMergeTool}" ToolTip.Tip="{DynamicResource Text.Diff.UseMerger}">
133+
<Button Classes="icon_button" Width="28" Command="{Binding OpenExternalMergeTool}" ToolTip.Tip="{DynamicResource Text.Diff.UseMerger}">
139134
<Path Width="12" Height="12" Stretch="Uniform" Data="{StaticResource Icons.OpenWith}"/>
140135
</Button>
141136
</StackPanel>

src/Views/DiffView.axaml.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Avalonia.Controls;
2+
using Avalonia.Interactivity;
3+
using Avalonia.VisualTree;
24

35
namespace SourceGit.Views
46
{
@@ -8,5 +10,31 @@ public DiffView()
810
{
911
InitializeComponent();
1012
}
13+
14+
private void OnGotoPrevChange(object _, RoutedEventArgs e)
15+
{
16+
var textDiff = this.FindDescendantOfType<ThemedTextDiffPresenter>();
17+
if (textDiff == null)
18+
return;
19+
20+
textDiff.GotoPrevChange();
21+
if (textDiff is SingleSideTextDiffPresenter presenter)
22+
presenter.ForceSyncScrollOffset();
23+
24+
e.Handled = true;
25+
}
26+
27+
private void OnGotoNextChange(object _, RoutedEventArgs e)
28+
{
29+
var textDiff = this.FindDescendantOfType<ThemedTextDiffPresenter>();
30+
if (textDiff == null)
31+
return;
32+
33+
textDiff.GotoNextChange();
34+
if (textDiff is SingleSideTextDiffPresenter presenter)
35+
presenter.ForceSyncScrollOffset();
36+
37+
e.Handled = true;
38+
}
1139
}
1240
}

src/Views/TextDiffView.axaml.cs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,108 @@ public void JumpToChangeBlock(int changeBlockIdx)
545545
}
546546
}
547547

548+
public void GotoPrevChange()
549+
{
550+
var view = TextArea.TextView;
551+
var lines = GetLines();
552+
var firstLineIdx = lines.Count;
553+
foreach (var line in view.VisualLines)
554+
{
555+
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
556+
continue;
557+
558+
var index = line.FirstDocumentLine.LineNumber - 1;
559+
if (index >= lines.Count)
560+
continue;
561+
562+
if (firstLineIdx > index)
563+
firstLineIdx = index;
564+
}
565+
566+
var firstLineType = lines[firstLineIdx].Type;
567+
var isChangeFirstLine = firstLineType != Models.TextDiffLineType.Normal && firstLineType != Models.TextDiffLineType.Indicator;
568+
if (isChangeFirstLine)
569+
{
570+
for (var i = firstLineIdx - 1; i >= 0; i--)
571+
{
572+
var prevType = lines[i].Type;
573+
if (prevType == Models.TextDiffLineType.Normal || prevType == Models.TextDiffLineType.Indicator)
574+
{
575+
ScrollToLine(i + 2);
576+
return;
577+
}
578+
}
579+
}
580+
else
581+
{
582+
var prevChangeEnd = -1;
583+
for (var i = firstLineIdx - 1; i >= 0; i--)
584+
{
585+
var prevType = lines[i].Type;
586+
if (prevType == Models.TextDiffLineType.None ||
587+
prevType == Models.TextDiffLineType.Added ||
588+
prevType == Models.TextDiffLineType.Deleted)
589+
{
590+
prevChangeEnd = i;
591+
break;
592+
}
593+
}
594+
595+
if (prevChangeEnd <= 0)
596+
return;
597+
598+
for (var i = prevChangeEnd - 1; i >= 0; i--)
599+
{
600+
var prevType = lines[i].Type;
601+
if (prevType == Models.TextDiffLineType.Normal || prevType == Models.TextDiffLineType.Indicator)
602+
{
603+
ScrollToLine(i + 2);
604+
return;
605+
}
606+
}
607+
}
608+
}
609+
610+
public void GotoNextChange()
611+
{
612+
var view = TextArea.TextView;
613+
var lines = GetLines();
614+
var lastLineIdx = -1;
615+
foreach (var line in view.VisualLines)
616+
{
617+
if (line.IsDisposed || line.FirstDocumentLine == null || line.FirstDocumentLine.IsDeleted)
618+
continue;
619+
620+
var index = line.FirstDocumentLine.LineNumber - 1;
621+
if (index >= lines.Count)
622+
continue;
623+
624+
if (lastLineIdx < index)
625+
lastLineIdx = index;
626+
}
627+
628+
var lastLineType = lines[lastLineIdx].Type;
629+
var findNormalLine = lastLineType == Models.TextDiffLineType.Normal || lastLineType == Models.TextDiffLineType.Indicator;
630+
for (var idx = lastLineIdx + 1; idx < lines.Count; idx++)
631+
{
632+
var nextType = lines[idx].Type;
633+
if (nextType == Models.TextDiffLineType.None ||
634+
nextType == Models.TextDiffLineType.Added ||
635+
nextType == Models.TextDiffLineType.Deleted)
636+
{
637+
if (findNormalLine)
638+
{
639+
ScrollToLine(idx + 1);
640+
return;
641+
}
642+
}
643+
else if (!findNormalLine)
644+
{
645+
findNormalLine = true;
646+
}
647+
}
648+
}
649+
548650
public override void Render(DrawingContext context)
549651
{
550652
base.Render(context);
@@ -1025,6 +1127,12 @@ public class SingleSideTextDiffPresenter : ThemedTextDiffPresenter
10251127
TextArea.LeftMargins.Add(new LineModifyTypeMargin());
10261128
}
10271129

1130+
public void ForceSyncScrollOffset()
1131+
{
1132+
if (DataContext is ViewModels.TwoSideTextDiff diff)
1133+
diff.SyncScrollOffset = _scrollViewer.Offset;
1134+
}
1135+
10281136
public override List<Models.TextDiffLine> GetLines()
10291137
{
10301138
if (DataContext is ViewModels.TwoSideTextDiff diff)

0 commit comments

Comments
 (0)