public static void RunDiff(TextSection oldText, TextSection newText, RichTextBox rtb) { // Longest common subsequence, simple edition. If/when something faster is needed, // should probably take a dependency on a proper diff package. Other than shorter // comparison windows, other things to look for are avoiding creating strings here, // working on the RichTextBox buffer directly for color, and unique'ing lines. string[] oldLines = oldText.Lines; string[] newLines = newText.Lines; // Reduce strings to hashes. int[] oldHashes = oldText.LineHashes; int[] newHashes = newText.LineHashes; // Reduce by trimming prefix and suffix. int diffStart = 0; while (diffStart < oldHashes.Length && diffStart < newHashes.Length && oldHashes[diffStart] == newHashes[diffStart]) { diffStart++; } int newDiffEndExc = newLines.Length, oldDiffEndExc = oldLines.Length; while (newDiffEndExc > diffStart && oldDiffEndExc > diffStart) { if (oldHashes[oldDiffEndExc - 1] == newHashes[newDiffEndExc - 1]) { oldDiffEndExc--; newDiffEndExc--; } else { break; } } int suffixLength = (newLines.Length - newDiffEndExc); // Build LCS table. int oldLen = oldDiffEndExc - diffStart, newLen = newDiffEndExc - diffStart; int[,] lcs = new int[oldLen + 1, newLen + 1]; // already zero-initialized for (int i = 0; i < oldLen; i++) { for (int j = 0; j < newLen; j++) { if (oldHashes[i + diffStart] == newHashes[j + diffStart]) { lcs[i + 1, j + 1] = lcs[i, j] + 1; } else { lcs[i + 1, j + 1] = Math.Max(lcs[i, j + 1], lcs[i + 1, j]); } } } // Print the diff - common prefix, backtracked diff and common suffix. rtb.AppendLines(" ", newLines, 0, diffStart, Color.White); { int i = oldLen, j = newLen; Stack <string> o = new Stack <string>(); for (;;) { if (i > 0 && j > 0 && oldHashes[diffStart + i - 1] == newHashes[diffStart + j - 1]) { o.Push(" " + oldLines[diffStart + i - 1]); i--; j--; } else if (j > 0 && (i == 0 || lcs[i, j - 1] >= lcs[i - 1, j])) { o.Push("+ " + newLines[diffStart + j - 1]); j--; } else if (i > 0 && (j == 0 || lcs[i, j - 1] < lcs[i - 1, j])) { o.Push("- " + oldLines[diffStart + i - 1]); i--; } else { break; } } while (o.Count != 0) { string line = o.Pop(); Color c = (line[0] == ' ') ? Color.White : ((line[0] == '+') ? Color.Yellow : Color.Red); rtb.AppendLine(line, c); } } rtb.AppendLines(" ", newLines, newDiffEndExc, (newLines.Length - newDiffEndExc), Color.White); }