Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/Commands/Diff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public partial class Diff : Command
private const int MAX_INLINE_CONTENT_LENGTH = 1024;
private const int MAX_INLINE_CHUNKS_PER_LINE = 16;

public const long MAX_TEXT_DIFF_SIZE = 5 * 1024 * 1024;

public bool IgnoreSizeLimit { get; set; } = false;

public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignoreWhitespace, bool ignoreCRAtEOL)
{
_result.TextDiff = new Models.TextDiff();
Expand Down Expand Up @@ -66,7 +70,22 @@ public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignore
proc.Start();

using var ms = new MemoryStream();
await proc.StandardOutput.BaseStream.CopyToAsync(ms, CancellationToken).ConfigureAwait(false);
var stdout = proc.StandardOutput.BaseStream;
var chunk = new byte[81920];
int read;
while ((read = await stdout.ReadAsync(chunk, CancellationToken).ConfigureAwait(false)) > 0)
{
ms.Write(chunk, 0, read);

// Stop reading huge diffs (generated files, minified bundles, data dumps, etc.). Only
// the diff headers will be parsed.
if (!IgnoreSizeLimit && ms.Length > MAX_TEXT_DIFF_SIZE)
{
_result.IsTooLarge = true;
proc.Kill(true);
break;
}
}

if (ms.TryGetBuffer(out var buffer))
{
Expand All @@ -82,7 +101,7 @@ public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignore
}

ParseLine(buffer[start..lineEnd]);
if (_result.IsBinary)
if (_result.IsBinary || (_result.IsTooLarge && _isInChunk))
break;

start = lineEnd + 1;
Expand All @@ -96,7 +115,7 @@ public Diff(string repo, Models.DiffOption opt, int numContextLines, bool ignore
// Ignore exceptions.
}

if (_isLFS || _result.IsBinary || _result.TextDiff.Lines.Count == 0)
if (_isLFS || _result.IsBinary || _result.IsTooLarge || _result.TextDiff.Lines.Count == 0)
{
_result.TextDiff = null;
}
Expand Down
6 changes: 6 additions & 0 deletions src/Models/DiffResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ public class EmptyFile

public class NoOrEOLChange;

public class TooLargeDiff
{
public long MaxSizeInMB { get; set; } = 0;
}

public class SubmoduleDiff
{
public string FullPath { get; set; } = string.Empty;
Expand All @@ -107,6 +112,7 @@ public class DiffResult
{
public bool IsBinary { get; set; } = false;
public bool IsSubmoduleChange { get; set; } = false;
public bool IsTooLarge { get; set; } = false;
public string OldHash { get; set; } = string.Empty;
public string NewHash { get; set; } = string.Empty;
public int OldMode { get; set; } = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/Resources/Locales/en_US.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@
<x:String x:Key="Text.Diff.SwapCommits" xml:space="preserve">Swap</x:String>
<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.TooLarge" xml:space="preserve">DIFF TOO LARGE TO DISPLAY</x:String>
<x:String x:Key="Text.Diff.TooLarge.ShowAnyway" xml:space="preserve">SHOW ANYWAY</x:String>
<x:String x:Key="Text.Diff.TooLarge.Tip" xml:space="preserve">The diff output exceeds {0} MB. Loading it may make SourceGit unresponsive for a while.</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>
Expand Down
15 changes: 14 additions & 1 deletion src/ViewModels/DiffContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public DiffContext(string repo, Models.DiffOption option, DiffContext previous =
_newMode = previous._newMode;
_unifiedLines = previous._unifiedLines;
_info = previous._info;
_ignoreSizeLimit = previous._ignoreSizeLimit && previous._option.ToString().Equals(_option.ToString(), StringComparison.Ordinal);
}

if (string.IsNullOrEmpty(_option.OrgPath) || _option.OrgPath == "/dev/null")
Expand All @@ -85,6 +86,13 @@ public void DecrUnified()
LoadContent();
}

public void ShowTooLargeDiff()
{
_ignoreSizeLimit = true;
_info = null;
LoadContent();
}

public void OpenExternalMergeTool()
{
new Commands.DiffTool(_repo, _option).Open();
Expand Down Expand Up @@ -134,7 +142,7 @@ private void LoadContent()
var ignoreWhitespace = pref.IgnoreWhitespaceChangesInDiff;
var ignoreCRAtEOL = pref.IgnoreCRAtEOLInDiff;

var latest = await new Commands.Diff(_repo, _option, numLines, ignoreWhitespace, ignoreCRAtEOL)
var latest = await new Commands.Diff(_repo, _option, numLines, ignoreWhitespace, ignoreCRAtEOL) { IgnoreSizeLimit = _ignoreSizeLimit }
.ReadAsync()
.ConfigureAwait(false);

Expand All @@ -149,6 +157,10 @@ private void LoadContent()
{
rs = textDiff;
}
else if (latest.IsTooLarge)
{
rs = new Models.TooLargeDiff() { MaxSizeInMB = Commands.Diff.MAX_TEXT_DIFF_SIZE / 1024 / 1024 };
}
else if (latest.LFSDiff is { } lfs)
{
var imgDecoder = ImageSource.GetDecoder(_option.Path);
Expand Down Expand Up @@ -388,6 +400,7 @@ public bool IsSame(Info other)
private int _unifiedLines = 4;
private bool _isTextDiff = false;
private bool _isIgnoreWhitespaceVisible = true;
private bool _ignoreSizeLimit = false;
private object _content = null;
private Info _info = null;
}
Expand Down
21 changes: 21 additions & 0 deletions src/Views/DiffView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,27 @@
</StackPanel>
</DataTemplate>

<!-- Too Large Diff -->
<DataTemplate DataType="m:TooLargeDiff">
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<Path Width="64" Height="64" Data="{StaticResource Icons.Error}" Fill="{DynamicResource Brush.FG2}"/>
<TextBlock Margin="0,16,0,0"
Text="{DynamicResource Text.Diff.TooLarge}"
FontSize="18" FontWeight="Bold"
Foreground="{DynamicResource Brush.FG2}"
HorizontalAlignment="Center"/>
<TextBlock Margin="0,8,0,0"
Text="{Binding MaxSizeInMB, Converter={x:Static c:StringConverters.FormatByResourceKey}, ConverterParameter='Diff.TooLarge.Tip'}"
Foreground="{DynamicResource Brush.FG2}"
HorizontalAlignment="Center"/>
<Button Classes="flat"
Margin="0,16,0,0"
HorizontalAlignment="Center"
Content="{DynamicResource Text.Diff.TooLarge.ShowAnyway}"
Click="OnShowTooLargeDiff"/>
</StackPanel>
</DataTemplate>

<!-- Only EOL changes -->
<DataTemplate DataType="m:NoOrEOLChange">
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
Expand Down
8 changes: 8 additions & 0 deletions src/Views/DiffView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,13 @@ private async void OnOpenBinaryFileViewer(object sender, RoutedEventArgs e)
e.Handled = true;
}
}

private void OnShowTooLargeDiff(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.DiffContext vm)
vm.ShowTooLargeDiff();

e.Handled = true;
}
}
}