feature: diff - toggle show all lines (#615) (#652)

* Renamed 1 of 2 SyncScrollOffset props, for clarity

The property "SyncScrollOffset" in TextDiff is distinct from the one with the same name in TwoSideTextDiff. These two properties are used in separate (though slightly related) ways and are not really connected.

The one in TwoSideTextDiff is mainly used to keep the scroll-pos of the two SingleSideTextDiffPresenter views in sync (aligned), while the one in TextDiff is used only to preserve/reset the scroll-pos in the single CombinedTextDiffPresenter view when (re)loading Diff Content (so not really syncing anything).

To clarify this and to make the two properties more distinguishable, I renamed the one in TextDiff to simply "ScrollOffset".

* Added icon and string for "Show All Lines"

New StreamGeometry "Icons.Lines.All" using SVG path from "text_line_spacing_regular" at https://avaloniaui.github.io/icons.html.
New String "Text.Diff.VisualLines.All" for en_US locale (no translations yet).

* Implemented new TextDiff feature "Show All Lines" (toggle)

* Added new ToggleButton in DiffView toolbar, visible when IsTextDiff, disabling the buttons "Increase/Decrease Number of Visible Lines" when on.

* Added new Preference property "UseFullTextDiff".

* Added StyledProperty "UseFullTextDiffProperty" in TextDiffView, with a DataTemplate binding to the corresponding preference property.

* When changed, UseFullTextDiffProperty is handled identically as UseSideBySideDiffProperty (via new helper method RefreshContent(), for unification with OnDataContextChanged()).

* Added new method DiffContext.ToggleFullTextDiff() for changing the preference property and reloading the diff content.

* Implemented the new feature by overriding the "unified" (number of context lines) for Commands.Diff() with a very high number.

NOTE: The number used (~1 billion) is supposed to be the highest one working on Mac, according to this forum comment: https://stackoverflow.com/questions/28727424/for-git-diff-is-there-a-uinfinity-option-to-show-the-whole-file#comment135202820_28846576
This commit is contained in:
Göran W 2024-11-04 09:32:51 +01:00 committed by GitHub
parent 779b38be28
commit 1a8acbf934
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 90 additions and 34 deletions

View file

@ -63,7 +63,7 @@ namespace SourceGit.Models
{
public string File { get; set; } = string.Empty;
public List<TextDiffLine> Lines { get; set; } = new List<TextDiffLine>();
public Vector SyncScrollOffset { get; set; } = Vector.Zero;
public Vector ScrollOffset { get; set; } = Vector.Zero;
public int MaxLineNumber = 0;
public string Repo { get; set; } = null;

View file

@ -65,6 +65,7 @@
<StreamGeometry x:Key="Icons.LayoutHorizontal">M875 117H149C109 117 75 151 75 192v640c0 41 34 75 75 75h725c41 0 75-34 75-75V192c0-41-34-75-75-75zM139 832V192c0-6 4-11 11-11h331v661H149c-6 0-11-4-11-11zm747 0c0 6-4 11-11 11H544v-661H875c6 0 11 4 11 11v640z</StreamGeometry>
<StreamGeometry x:Key="Icons.LayoutVertical">M875 117H149C109 117 75 151 75 192v640c0 41 34 75 75 75h725c41 0 75-34 75-75V192c0-41-34-75-75-75zm-725 64h725c6 0 11 4 11 11v288h-747V192c0-6 4-11 11-11zm725 661H149c-6 0-11-4-11-11V544h747V832c0 6-4 11-11 11z</StreamGeometry>
<StreamGeometry x:Key="Icons.LFS">M40 9 15 23 15 31 9 28 9 20 34 5 24 0 0 14 0 34 25 48 25 28 49 14zM26 29 26 48 49 34 49 15z</StreamGeometry>
<StreamGeometry x:Key="Icons.Lines.All">M19,13 C19.4142,13 19.75,13.3358 19.75,13.75 L19.75,18.4393 L20.4697,17.7197 C20.7626,17.4268 21.2374,17.4268 21.5303,17.7197 C21.8232,18.0126 21.8232,18.4874 21.5303,18.7803 L19.5303,20.7803 C19.4584,20.8522 19.3755,20.9065 19.2871,20.9431 C19.2099,20.9751 19.1262,20.9946 19.0386,20.999 L19,21 L19,21 C18.8983,21 18.8013,20.9798 18.7129,20.9431 C18.6245,20.9065 18.5416,20.8522 18.4697,20.7803 L16.4697,18.7803 C16.1768,18.4874 16.1768,18.0126 16.4697,17.7197 C16.7626,17.4268 17.2374,17.4268 17.5303,17.7197 L18.25,18.4393 L18.25,13.75 C18.25,13.3358 18.5858,13 19,13 Z M11.25,18 C11.6642,18 12,18.3358 12,18.75 C12,19.1296833 11.7178347,19.4434889 11.3517677,19.4931531 L11.25,19.5 L2.75,19.5 C2.33579,19.5 2,19.1642 2,18.75 C2,18.3703167 2.28215688,18.0565111 2.64823019,18.0068469 L2.75,18 L11.25,18 Z M14.25,11.5 C14.6642,11.5 15,11.8358 15,12.25 C15,12.6642 14.6642,13 14.25,13 L2.75,13 C2.33579,13 2,12.6642 2,12.25 C2,11.8358 2.33579,11.5 2.75,11.5 L14.25,11.5 Z M19.0022,3 C19.1031,3.0003 19.1993,3.02051 19.2871,3.05691 C19.3755,3.09351 19.4584,3.14776 19.5303,3.21967 L21.5303,5.21967 C21.8232,5.51256 21.8232,5.98744 21.5303,6.28033 C21.2374,6.57322 20.7626,6.57322 20.4697,6.28033 L19.75,5.56066 L19.75,10.25 C19.75,10.6642 19.4142,11 19,11 C18.5858,11 18.25,10.6642 18.25,10.25 L18.25,5.56066 L17.5303,6.28033 C17.2374,6.57322 16.7626,6.57322 16.4697,6.28033 C16.1768,5.98744 16.1768,5.51256 16.4697,5.21967 L18.4697,3.21967 C18.58634,3.102974 18.731972,3.0327676 18.8834536,3.00906104 L19.0022,3 Z M11.25,5 C11.6642,5 12,5.33579 12,5.75 C12,6.16421 11.6642,6.5 11.25,6.5 L2.75,6.5 C2.33579,6.5 2,6.16421 2,5.75 C2,5.33579 2.33579,5 2.75,5 L11.25,5 Z</StreamGeometry>
<StreamGeometry x:Key="Icons.Lines.Incr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l132 0 0-128 64 0 0 128 132 0 0 64-132 0 0 128-64 0 0-128-132 0Z</StreamGeometry>
<StreamGeometry x:Key="Icons.Lines.Decr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l328 0 0 64-328 0Z</StreamGeometry>
<StreamGeometry x:Key="Icons.Link">M 968 418 l -95 94 c -59 59 -146 71 -218 37 L 874 331 a 64 64 0 0 0 0 -90 L 783 150 a 64 64 0 0 0 -90 0 L 475 368 c -34 -71 -22 -159 37 -218 l 94 -94 c 75 -75 196 -75 271 0 l 90 90 c 75 75 75 196 0 271 z M 332 693 a 64 64 0 0 1 0 -90 l 271 -271 c 25 -25 65 -25 90 0 s 25 65 0 90 L 422 693 a 64 64 0 0 1 -90 0 z M 151 783 l 90 90 a 64 64 0 0 0 90 0 l 218 -218 c 34 71 22 159 -37 218 l -86 94 a 192 192 0 0 1 -271 0 l -98 -98 a 192 192 0 0 1 0 -271 l 94 -86 c 59 -59 146 -71 218 -37 L 151 693 a 64 64 0 0 0 0 90 z</StreamGeometry>

View file

@ -246,6 +246,7 @@
<x:String x:Key="Text.Diff.SyntaxHighlight" xml:space="preserve">Syntax Highlighting</x:String>
<x:String x:Key="Text.Diff.ToggleWordWrap" xml:space="preserve">Line Word Wrap</x:String>
<x:String x:Key="Text.Diff.UseMerger" xml:space="preserve">Open in Merge Tool</x:String>
<x:String x:Key="Text.Diff.VisualLines.All" xml:space="preserve">Show All Lines</x:String>
<x:String x:Key="Text.Diff.VisualLines.Decr" xml:space="preserve">Decrease Number of Visible Lines</x:String>
<x:String x:Key="Text.Diff.VisualLines.Incr" xml:space="preserve">Increase Number of Visible Lines</x:String>
<x:String x:Key="Text.Diff.Welcome" xml:space="preserve">SELECT FILE TO VIEW CHANGES</x:String>

View file

@ -78,6 +78,12 @@ namespace SourceGit.ViewModels
LoadDiffContent();
}
public void ToggleFullTextDiff()
{
Preference.Instance.UseFullTextDiff = !Preference.Instance.UseFullTextDiff;
LoadDiffContent();
}
public void IncrUnified()
{
UnifiedLines = _unifiedLines + 1;
@ -109,7 +115,12 @@ namespace SourceGit.ViewModels
Task.Run(() =>
{
var latest = new Commands.Diff(_repo, _option, _unifiedLines, _ignoreWhitespace).Result();
// NOTE: Here we override the UnifiedLines value (if UseFullTextDiff is on).
// There is no way to tell a git-diff to use "ALL lines of context",
// so instead we set a very high number for the "lines of context" parameter.
var numLines = Preference.Instance.UseFullTextDiff ? 999999999 : _unifiedLines;
var latest = new Commands.Diff(_repo, _option, numLines, _ignoreWhitespace).Result();
var rs = null as object;
if (latest.TextDiff != null)
@ -203,7 +214,7 @@ namespace SourceGit.ViewModels
Dispatcher.UIThread.Post(() =>
{
if (_content is Models.TextDiff old && rs is Models.TextDiff cur && old.File == cur.File)
cur.SyncScrollOffset = old.SyncScrollOffset;
cur.ScrollOffset = old.ScrollOffset;
FileModeChange = latest.FileModeChange;
Content = rs;

View file

@ -186,6 +186,12 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _showHiddenSymbolsInDiffView, value);
}
public bool UseFullTextDiff
{
get => _useFullTextDiff;
set => SetProperty(ref _useFullTextDiff, value);
}
public Models.ChangeViewMode UnstagedChangeViewMode
{
get => _unstagedChangeViewMode;
@ -591,6 +597,7 @@ namespace SourceGit.ViewModels
private bool _useSyntaxHighlighting = false;
private bool _enableDiffViewWordWrap = false;
private bool _showHiddenSymbolsInDiffView = false;
private bool _useFullTextDiff = false;
private Models.ChangeViewMode _unstagedChangeViewMode = Models.ChangeViewMode.List;
private Models.ChangeViewMode _stagedChangeViewMode = Models.ChangeViewMode.List;

View file

@ -34,11 +34,24 @@
<!-- Toolbar Buttons -->
<StackPanel Grid.Column="3" Margin="8,0,0,0" Orientation="Horizontal" VerticalAlignment="Center">
<ToggleButton Classes="line_path"
Width="32" Height="18"
Background="Transparent"
Padding="9,6"
Command="{Binding ToggleFullTextDiff}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFullTextDiff, Mode=OneWay}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.All}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Lines.All}" Margin="0,3,0,0"/>
</ToggleButton>
<Button Classes="icon_button"
Width="32"
Command="{Binding IncrUnified}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Incr}">
<Button.IsEnabled>
<Binding Source="{x:Static vm:Preference.Instance}" Path="UseFullTextDiff" Mode="OneWay" Converter="{x:Static BoolConverters.Not}"/>
</Button.IsEnabled>
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Lines.Incr}"/>
</Button>
@ -46,8 +59,13 @@
Width="32"
Command="{Binding DecrUnified}"
IsVisible="{Binding IsTextDiff}"
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Decr}"
IsEnabled="{Binding UnifiedLines, Converter={x:Static c:IntConverters.IsGreaterThanFour}}">
ToolTip.Tip="{DynamicResource Text.Diff.VisualLines.Decr}">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="UnifiedLines" Mode="OneWay" Converter="{x:Static c:IntConverters.IsGreaterThanFour}"/>
<Binding Source="{x:Static vm:Preference.Instance}" Path="UseFullTextDiff" Mode="OneWay" Converter="{x:Static BoolConverters.Not}"/>
</MultiBinding>
</Button.IsEnabled>
<Path Width="12" Height="12" Stretch="Uniform" Margin="0,6,0,0" Data="{StaticResource Icons.Lines.Decr}"/>
</Button>
@ -211,7 +229,9 @@
<!-- Text Diff -->
<DataTemplate DataType="m:TextDiff">
<v:TextDiffView UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"/>
<v:TextDiffView
UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"
UseFullTextDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseFullTextDiff, Mode=OneWay}"/>
</DataTemplate>
<!-- Empty or only EOL changes -->

View file

@ -902,7 +902,7 @@ namespace SourceGit.Views
var scroller = this.FindDescendantOfType<ScrollViewer>();
if (scroller != null)
{
scroller.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.TwoWay));
scroller.Bind(ScrollViewer.OffsetProperty, new Binding("ScrollOffset", BindingMode.TwoWay));
scroller.GotFocus += OnTextViewScrollGotFocus;
}
}
@ -1205,6 +1205,15 @@ namespace SourceGit.Views
set => SetValue(UseSideBySideDiffProperty, value);
}
public static readonly StyledProperty<bool> UseFullTextDiffProperty =
AvaloniaProperty.Register<TextDiffView, bool>(nameof(UseFullTextDiff));
public bool UseFullTextDiff
{
get => GetValue(UseFullTextDiffProperty);
set => SetValue(UseFullTextDiffProperty, value);
}
public static readonly StyledProperty<TextDiffViewChunk> SelectedChunkProperty =
AvaloniaProperty.Register<TextDiffView, TextDiffViewChunk>(nameof(SelectedChunk));
@ -1232,19 +1241,44 @@ namespace SourceGit.Views
set => SetValue(EnableChunkSelectionProperty, value);
}
private void RefreshContent(Models.TextDiff diff, bool keepScrollOffset = true)
{
if (SelectedChunk != null)
SetCurrentValue(SelectedChunkProperty, null);
if (diff == null)
{
Editor.Content = null;
GC.Collect();
return;
}
if (UseSideBySideDiff)
{
var previousContent = Editor.Content as ViewModels.TwoSideTextDiff;
Editor.Content = new ViewModels.TwoSideTextDiff(diff, keepScrollOffset ? previousContent : null);
}
else
{
if (!keepScrollOffset)
diff.ScrollOffset = Vector.Zero;
Editor.Content = diff;
}
IsUnstagedChange = diff.Option.IsUnstaged;
EnableChunkSelection = diff.Option.WorkingCopyChange != null;
}
static TextDiffView()
{
UseSideBySideDiffProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
{
if (v.DataContext is Models.TextDiff diff)
{
diff.SyncScrollOffset = Vector.Zero;
v.RefreshContent(v.DataContext as Models.TextDiff, false);
});
if (v.UseSideBySideDiff)
v.Editor.Content = new ViewModels.TwoSideTextDiff(diff);
else
v.Editor.Content = diff;
}
UseFullTextDiffProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
{
v.RefreshContent(v.DataContext as Models.TextDiff, false);
});
SelectedChunkProperty.Changed.AddClassHandler<TextDiffView>((v, _) =>
@ -1271,25 +1305,7 @@ namespace SourceGit.Views
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
if (SelectedChunk != null)
SetCurrentValue(SelectedChunkProperty, null);
var diff = DataContext as Models.TextDiff;
if (diff == null)
{
Editor.Content = null;
GC.Collect();
return;
}
if (UseSideBySideDiff)
Editor.Content = new ViewModels.TwoSideTextDiff(diff, Editor.Content as ViewModels.TwoSideTextDiff);
else
Editor.Content = diff;
IsUnstagedChange = diff.Option.IsUnstaged;
EnableChunkSelection = diff.Option.WorkingCopyChange != null;
RefreshContent(DataContext as Models.TextDiff, true);
}
protected override void OnPointerExited(PointerEventArgs e)