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:
goran-w 2024-11-01 20:45:06 +01:00
parent f7e37c4781
commit b5072360ed
4 changed files with 85 additions and 31 deletions

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)

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

@ -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.ScrollOffset = 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)