feat(diff): highlight changed words inside paired diff lines

This commit is contained in:
mika kuns
2026-08-07 09:17:26 +02:00
parent 3cd0f0879e
commit ebbee6005d
2 changed files with 192 additions and 2 deletions
@@ -164,4 +164,95 @@ public class DiffAlignmentTests
Assert.Single(result.SplitRows);
Assert.Equal("a", result.SplitRows[0].LeftText);
}
[Fact]
public void WordDiff_HighlightsOnlyTheChangedToken()
{
var result = DiffAlignment.Build(new[]
{
Del(1, " var x = 1;"),
Add(1, " var x = 2;"),
});
var row = Assert.Single(result.SplitRows);
var left = Assert.Single(row.LeftSpans);
var right = Assert.Single(row.RightSpans);
Assert.Equal(new TextSpan(12, 1), left);
Assert.Equal(new TextSpan(12, 1), right);
Assert.Equal("1", row.LeftText.Substring(left.Start, left.Length));
Assert.Equal("2", row.RightText.Substring(right.Start, right.Length));
}
[Fact]
public void WordDiff_MergesAdjacentChangedTokensIntoOneSpan()
{
var result = DiffAlignment.Build(new[]
{
Del(1, "call(a, b);"),
Add(1, "call(zz, b);"),
});
var row = Assert.Single(result.SplitRows);
var right = Assert.Single(row.RightSpans);
Assert.Equal("zz", row.RightText.Substring(right.Start, right.Length));
}
[Fact]
public void WordDiff_SkippedWhenTheLinesAreUnrelated()
{
var result = DiffAlignment.Build(new[]
{
Del(1, "public void Alpha()"),
Add(1, "return 42;"),
});
var row = Assert.Single(result.SplitRows);
Assert.Empty(row.LeftSpans);
Assert.Empty(row.RightSpans);
}
[Fact]
public void WordDiff_SkippedOnVeryLongLines()
{
var left = new string('a', DiffAlignment.MaxWordDiffChars + 1);
var result = DiffAlignment.Build(new[] { Del(1, left), Add(1, left + "b") });
var row = Assert.Single(result.SplitRows);
Assert.Empty(row.LeftSpans);
Assert.Empty(row.RightSpans);
}
[Fact]
public void WordDiff_SkippedWhenTokenCountExceedsTheCap()
{
var many = string.Join(" ", Enumerable.Range(0, DiffAlignment.MaxWordDiffTokens + 10).Select(n => $"t{n}"));
var result = DiffAlignment.Build(new[] { Del(1, many), Add(1, many + " x") });
var row = Assert.Single(result.SplitRows);
Assert.Empty(row.LeftSpans);
Assert.Empty(row.RightSpans);
}
[Fact]
public void WordDiff_IdenticalTextYieldsNoSpans()
{
var result = DiffAlignment.Build(new[] { Del(1, "same"), Add(1, "same") });
var row = Assert.Single(result.SplitRows);
Assert.Empty(row.LeftSpans);
Assert.Empty(row.RightSpans);
}
[Fact]
public void WordDiff_UnpairedOverhangRowsHaveNoSpans()
{
var result = DiffAlignment.Build(new[]
{
Del(1, "var x = 1;"),
Add(1, "var x = 2;"), Add(2, "var y = 3;"),
});
Assert.NotEmpty(result.SplitRows[0].RightSpans);
Assert.Empty(result.SplitRows[1].RightSpans);
}
}