TextApi

Diff

TextDiff computes the minimum edit script between two texts using the Myers O(ND) algorithm. Results come as structured DiffHunk lists, character-level DiffSpan sequences, or rendered unified-diff strings.

Navigation: Overview TextDocument Examples Advanced

Quick Reference

using TextAPI.Core.Diff;

// Line-level diff of two strings
DiffResult result = TextDiff.Diff(oldText, newText);

Console.WriteLine($"+{result.AddedLines} / -{result.DeletedLines}");
Console.WriteLine(result.ToUnifiedDiff());

// Character-level diff
var spans = TextDiff.DiffChars("Hello World", "Hello TextAPI");
foreach (var s in spans)
	Console.WriteLine($"{s.Kind}: \"{s.Text}\"");

TextDiff Static Methods

Method Returns Description
Diff(string old, string new, opts?) DiffResult Line-level diff of two strings.
Diff(string[] old, string[] new, opts?) DiffResult Line-level diff of pre-split line arrays.
Diff(TextDocument old, TextDocument new, opts?) DiffResult Line-level diff of two documents.
DiffChars(string old, string new) IReadOnlyList<DiffSpan> Character-level diff.

DiffOptions

Property Type Default Description
IgnoreCase bool false Treat uppercase and lowercase as equal.
IgnoreWhitespace bool false Trim and collapse runs of whitespace before comparing.
MaxEditDistance int int.MaxValue Abort if edit distance exceeds this. Returns partial result.
var opts = new DiffOptions
{
	IgnoreCase       = true,
	IgnoreWhitespace = true
};

DiffResult r = TextDiff.Diff(a, b, opts);

// Or use the defaults
DiffResult r2 = TextDiff.Diff(a, b, DiffOptions.Default);

DiffResult

Property Type Description
Hunks IReadOnlyList<DiffHunk> All hunks in document order.
AddedLines int Total lines inserted across all hunks.
DeletedLines int Total lines deleted across all hunks.
HasChanges bool True when the two texts differ.
ToUnifiedDiff(old?, new?, ctx?) string Render as unified diff. Default 3 context lines.

DiffHunk

Property Type Description
Kind DiffKind Equal, Insert, or Delete.
OldStart int Zero-based start line in the old document.
OldCount int Number of lines from the old document.
NewStart int Zero-based start line in the new document.
NewCount int Number of lines from the new document.
Lines IReadOnlyList<string> Line content for this hunk.

DiffKind Enum

Value Meaning
Equal Lines are the same in both versions.
Insert Lines were added in the new version.
Delete Lines were removed from the old version.

DiffSpan (Character-Level)

readonly record struct DiffSpan(DiffKind Kind, string Text);

Each DiffSpan is a contiguous run of equal, inserted, or deleted characters. Use this for inline diff rendering in a UI:

var spans = TextDiff.DiffChars("the cat sat", "the bat sat");
// Equal:"the ", Delete:"c", Insert:"b", Equal:"at sat"

foreach (var s in spans)
{
	string prefix = s.Kind switch
	{
		DiffKind.Insert => "+",
		DiffKind.Delete => "-",
		_               => " "
	};
	Console.Write($"{prefix}{s.Text}");
}

Unified Diff Output

var result = TextDiff.Diff(oldText, newText);

// Default: 3 context lines, paths "a" and "b"
string patch = result.ToUnifiedDiff();

// Custom paths and context
string patch2 = result.ToUnifiedDiff(
	oldPath:      "original/file.cs",
	newPath:      "modified/file.cs",
	contextLines: 5
);

Output format:

--- original/file.cs
+++ modified/file.cs
@@ -1,4 +1,4 @@
 line 1
-old line
+new line
 line 3

Iterating Hunks

var result = TextDiff.Diff(oldDoc, newDoc);

foreach (var hunk in result.Hunks.Where(h => h.Kind != DiffKind.Equal))
{
	string symbol = hunk.Kind == DiffKind.Insert ? "+" : "-";
	foreach (var line in hunk.Lines)
		Console.WriteLine($"{symbol} {line}");
}

Performance Notes