diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs index 1c270470..0779029f 100644 --- a/src/Models/DiffResult.cs +++ b/src/Models/DiffResult.cs @@ -69,6 +69,80 @@ namespace SourceGit.Models public string Repo { get; set; } = null; public DiffOption Option { get; set; } = null; + public TextDiffSelection MakeSelection(int startLine, int endLine, bool isSideBySide, bool isOldSide) + { + var rs = new TextDiffSelection(); + rs.StartLine = startLine; + rs.EndLine = endLine; + + for (int i = 0; i < startLine - 1; i++) + { + var line = Lines[i]; + if (line.Type == TextDiffLineType.Added) + { + rs.HasLeftChanges = true; + rs.IgnoredAdds++; + } + else if (line.Type == TextDiffLineType.Deleted) + { + rs.HasLeftChanges = true; + rs.IgnoredDeletes++; + } + } + + for (int i = startLine - 1; i < endLine; i++) + { + var line = Lines[i]; + if (line.Type == TextDiffLineType.Added) + { + if (!isSideBySide) + { + rs.HasChanges = true; + break; + } + else if (isOldSide) + { + rs.HasLeftChanges = true; + } + else + { + rs.HasChanges = true; + } + } + else if (line.Type == TextDiffLineType.Deleted) + { + if (!isSideBySide) + { + rs.HasChanges = true; + break; + } + else if (isOldSide) + { + rs.HasChanges = true; + } + else + { + rs.HasLeftChanges = true; + } + } + } + + if (!rs.HasLeftChanges) + { + for (int i = endLine; i < Lines.Count; i++) + { + var line = Lines[i]; + if (line.Type == TextDiffLineType.Added || line.Type == TextDiffLineType.Deleted) + { + rs.HasLeftChanges = true; + break; + } + } + } + + return rs; + } + public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, TextDiffSelection selection, bool revert, string output) { var isTracked = !string.IsNullOrEmpty(fileBlobGuid); @@ -392,9 +466,6 @@ namespace SourceGit.Models System.IO.File.WriteAllText(output, builder.ToString()); } - [GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")] - private static partial Regex REG_INDICATOR(); - private bool ProcessIndicatorForPatch(StringBuilder builder, TextDiffLine indicator, int idx, int start, int end, int ignoreRemoves, int ignoreAdds, bool revert, bool tailed) { var match = REG_INDICATOR().Match(indicator.Content); @@ -554,6 +625,9 @@ namespace SourceGit.Models builder.Append($"\n@@ -{oldStart},{oldCount} +{newStart},{newCount} @@"); return true; } + + [GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")] + private static partial Regex REG_INDICATOR(); } public class LFSDiff diff --git a/src/ViewModels/TwoSideTextDiff.cs b/src/ViewModels/TwoSideTextDiff.cs index 59e70a88..d4d69059 100644 --- a/src/ViewModels/TwoSideTextDiff.cs +++ b/src/ViewModels/TwoSideTextDiff.cs @@ -1,5 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; + using Avalonia; + using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -53,6 +56,45 @@ namespace SourceGit.ViewModels _syncScrollOffset = previous._syncScrollOffset; } + public void ConvertsToCombinedRange(Models.TextDiff combined, ref int startLine, ref int endLine, bool isOldSide) + { + endLine = Math.Min(endLine, combined.Lines.Count); + + var oneSide = isOldSide ? Old : New; + var firstContentLine = -1; + for (int i = startLine - 1; i < endLine; i++) + { + var line = oneSide[i]; + if (line.Type != Models.TextDiffLineType.None) + { + firstContentLine = i; + break; + } + } + + if (firstContentLine < 0) + return; + + var endContentLine = -1; + for (int i = Math.Min(endLine - 1, oneSide.Count - 1); i >= startLine - 1; i--) + { + var line = oneSide[i]; + if (line.Type != Models.TextDiffLineType.None) + { + endContentLine = i; + break; + } + } + + if (endContentLine < 0) + return; + + var firstContent = oneSide[firstContentLine]; + var endContent = oneSide[endContentLine]; + startLine = combined.Lines.IndexOf(firstContent) + 1; + endLine = combined.Lines.IndexOf(endContent) + 1; + } + private void FillEmptyLines() { if (Old.Count < New.Count) diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 0b7a6071..6f68fad4 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1159,10 +1159,10 @@ namespace SourceGit.Views if (startLine > endLine) (startLine, endLine) = (endLine, startLine); - if (UseSideBySideDiff) - (startLine, endLine) = GetUnifiedRange(diff, startLine, endLine, isOldSide); + if (Editor.Content is ViewModels.TwoSideTextDiff twoSides) + twoSides.ConvertsToCombinedRange(diff, ref startLine, ref endLine, isOldSide); - var selection = MakeSelection(diff, startLine, endLine, !UseSideBySideDiff, isOldSide); + var selection = diff.MakeSelection(startLine, endLine, UseSideBySideDiff, isOldSide); if (!selection.HasChanges) return; @@ -1429,7 +1429,7 @@ namespace SourceGit.Views if (change == null) return; - var selection = MakeSelection(diff, chunk.StartIdx + 1, chunk.EndIdx + 1, true, false); + var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, false, false); if (!selection.HasChanges) return; @@ -1487,7 +1487,7 @@ namespace SourceGit.Views if (change == null) return; - var selection = MakeSelection(diff, chunk.StartIdx + 1, chunk.EndIdx + 1, true, false); + var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, false, false); if (!selection.HasChanges) return; @@ -1543,7 +1543,7 @@ namespace SourceGit.Views if (change == null) return; - var selection = MakeSelection(diff, chunk.StartIdx + 1, chunk.EndIdx + 1, true, false); + var selection = diff.MakeSelection(chunk.StartIdx + 1, chunk.EndIdx + 1, false, false); if (!selection.HasChanges) return; @@ -1588,122 +1588,5 @@ namespace SourceGit.Views repo.SetWatcherEnabled(true); } } - - private (int, int) GetUnifiedRange(Models.TextDiff diff, int startLine, int endLine, bool isOldSide) - { - endLine = Math.Min(endLine, diff.Lines.Count); - if (Editor.Content is ViewModels.TwoSideTextDiff twoSides) - { - var target = isOldSide ? twoSides.Old : twoSides.New; - var firstContentLine = -1; - for (int i = startLine - 1; i < endLine; i++) - { - var line = target[i]; - if (line.Type != Models.TextDiffLineType.None) - { - firstContentLine = i; - break; - } - } - - if (firstContentLine < 0) - return (-1, -1); - - var endContentLine = -1; - for (int i = Math.Min(endLine - 1, target.Count - 1); i >= startLine - 1; i--) - { - var line = target[i]; - if (line.Type != Models.TextDiffLineType.None) - { - endContentLine = i; - break; - } - } - - if (endContentLine < 0) - return (-1, -1); - - var firstContent = target[firstContentLine]; - var endContent = target[endContentLine]; - startLine = diff.Lines.IndexOf(firstContent) + 1; - endLine = diff.Lines.IndexOf(endContent) + 1; - } - - return (startLine, endLine); - } - - private Models.TextDiffSelection MakeSelection(Models.TextDiff diff, int startLine, int endLine, bool combined, bool isOldSide) - { - var rs = new Models.TextDiffSelection(); - rs.StartLine = startLine; - rs.EndLine = endLine; - - for (int i = 0; i < startLine - 1; i++) - { - var line = diff.Lines[i]; - if (line.Type == Models.TextDiffLineType.Added) - { - rs.HasLeftChanges = true; - rs.IgnoredAdds++; - } - else if (line.Type == Models.TextDiffLineType.Deleted) - { - rs.HasLeftChanges = true; - rs.IgnoredDeletes++; - } - } - - for (int i = startLine - 1; i < endLine; i++) - { - var line = diff.Lines[i]; - if (line.Type == Models.TextDiffLineType.Added) - { - if (combined) - { - rs.HasChanges = true; - break; - } - else if (isOldSide) - { - rs.HasLeftChanges = true; - } - else - { - rs.HasChanges = true; - } - } - else if (line.Type == Models.TextDiffLineType.Deleted) - { - if (combined) - { - rs.HasChanges = true; - break; - } - else if (isOldSide) - { - rs.HasChanges = true; - } - else - { - rs.HasLeftChanges = true; - } - } - } - - if (!rs.HasLeftChanges) - { - for (int i = endLine; i < diff.Lines.Count; i++) - { - var line = diff.Lines[i]; - if (line.Type == Models.TextDiffLineType.Added || line.Type == Models.TextDiffLineType.Deleted) - { - rs.HasLeftChanges = true; - break; - } - } - } - - return rs; - } } }