public static void WriteUnifiedDiff(string[] leftLines, string leftName, string[] rightLines, string rightName, TextWriter writer, int context, bool caseSensitive, bool compareWhitespace) { Diff diff = new Diff(leftLines, rightLines, caseSensitive, compareWhitespace); WriteUnifiedDiff(diff, writer, leftName, rightName, context); }
private void RenderDifference(Diff.Hunk hunk) { Range left = hunk.Left; Range right = hunk.Right; if (right.Start == 0) ContextHeader(0, 0); int changes = Math.Min(left.Count, right.Count); for (int i = 0; i < changes; i++) { LineChanged(left.Start + i, right.Start + i); } if (left.Count > right.Count) { for (int i = changes; i < left.Count; i++) { LineDeleted(left.Start + i, right.Start + changes); } } else if (left.Count < right.Count) { for (int i = changes; i < right.Count; i++) { LineAdded(right.Start + i); } } }
/// <summary> /// Renders diff /// </summary> /// <param name="leftText">Earlier version of the text</param> /// <param name="rightText">Later version of the text</param> /// <param name="contextLines">Number of unchanged lines to show around changed ones</param> /// <returns>HTML diff</returns> public string GetDiff(string leftText, string rightText, int contextLines) { Result = new StringBuilder(500000); LeftLines = leftText.Split(new [] { "\r\n" }, StringSplitOptions.None); RightLines = rightText.Split(new [] { "\r\n" }, StringSplitOptions.None); ContextLines = contextLines; diff = new Diff(LeftLines, RightLines, true, true); foreach (Diff.Hunk h in diff) { if (h.Same) RenderContext(h); else RenderDifference(h); } return Result.ToString(); }
public static void WriteUnifiedDiff(Diff diff, TextWriter writer, string fromfile, string tofile, int context) { writer.Write("--- "); writer.WriteLine(fromfile); writer.Write("+++ "); writer.WriteLine(tofile); ArrayList hunkset = new ArrayList(); foreach (Diff.Hunk hunk in diff) { Diff.Hunk lasthunk = null; if (hunkset.Count > 0) lasthunk = (Diff.Hunk)hunkset[hunkset.Count-1]; if (hunk.Same) { // At the start of a hunk set, keep only context lines of context. if (lasthunk == null) { if (hunk.Left.Count > context) hunkset.Add( hunk.Crop(hunk.Left.Count-context, 0) ); else hunkset.Add( hunk ); // Can't have two same hunks in a row, so the last one was a difference. } else { // Small enough context that this unified diff range will not stop. if (hunk.Left.Count <= context*2) { hunkset.Add( hunk ); // Too much of the same. Keep context lines and end this section. // And then keep the last context lines as context for the next section. } else { hunkset.Add( hunk.Crop(0, hunk.Left.Count-context) ); WriteUnifiedDiffSection(writer, hunkset); hunkset.Clear(); if (hunk.Left.Count > context) hunkset.Add( hunk.Crop(hunk.Left.Count-context, 0) ); else hunkset.Add( hunk ); } } } else { hunkset.Add(hunk); } } if (hunkset.Count > 0 && !(hunkset.Count == 1 && ((Diff.Hunk)hunkset[0]).Same)) WriteUnifiedDiffSection(writer, hunkset); }
private void RenderContext(Diff.Hunk hunk) { Range left = hunk.Left; Range right = hunk.Right; int displayed = 0; if (Result.Length > 0) // not the first hunk, adding context for previous change { displayed = Math.Min(ContextLines, right.Count); for (int i = 0; i < displayed; i++) ContextLine(right.Start + i); } int toDisplay = Math.Min(right.Count - displayed, ContextLines); if ((left.End < LeftLines.Length - 1 || right.End < RightLines.Length - 1) && toDisplay > 0) // not the last hunk, adding context for next change { if (right.Count > displayed + toDisplay) ContextHeader(left.End - toDisplay + 1, right.End - toDisplay + 1); for (int i = 0; i < toDisplay; i++) ContextLine(right.End - toDisplay + i + 1); } }
private void LineChanged(int leftLine, int rightLine) { // some kind of glitch with the diff engine if (LeftLines[leftLine] == RightLines[rightLine]) { ContextLine(rightLine); return; } StringBuilder left = new StringBuilder(); StringBuilder right = new StringBuilder(); List<Word> leftList = Word.SplitString(LeftLines[leftLine]); List<Word> rightList = Word.SplitString(RightLines[rightLine]); diff = new Diff(leftList, rightList, Word.Comparer); foreach (Diff.Hunk h in diff) { if (h.Same) { for (int i = 0; i < h.Left.Count; i++) { WhitespaceDiff(left, rightList[h.Right.Start + i], leftList[h.Left.Start + i]); WhitespaceDiff(right, leftList[h.Left.Start + i], rightList[h.Right.Start + i]); } } else { WordDiff(left, h.Left, h.Right, leftList, rightList); WordDiff(right, h.Right, h.Left, rightList, leftList); } } Result.AppendFormat(@"<tr onclick='window.external.GoTo({1})' ondblclick='window.external.UndoChange({0},{1})'> <td>-</td> <td class='diff-deletedline'>", leftLine, rightLine); Result.Append(left); Result.Append(@" </td> <td>+</td> <td class='diff-addedline'>"); Result.Append(right); Result.Append(@" </td> </tr>"); }
private static void WhitespaceDiff(StringBuilder res, Word left, Word right) { if (left.Whitespace == right.Whitespace) res.Append(HttpUtility.HtmlEncode(right.ToString())); else { res.Append(HttpUtility.HtmlEncode(right.TheWord)); char[] leftChars = left.Whitespace.ToCharArray(); char[] rightChars = right.Whitespace.ToCharArray(); Diff diff = new Diff(leftChars, rightChars, Word.Comparer); foreach (Diff.Hunk h in diff) { if (h.Same) res.Append(rightChars, h.Right.Start, h.Right.Count); else { res.Append("<span class='diffchange'>"); res.Append('\x00A0', h.Right.Count); // replace spaces with NBSPs to make 'em visible res.Append("</span>"); } } } }
public static void WriteUnifiedDiff(Diff diff, TextWriter writer) { WriteUnifiedDiff(diff, writer, "Left", "Right", 2); }
public Enumerator(Diff diff) { this.diff = diff; Reset(); }
private void LineChanged(int leftLine, int rightLine) { // some kind of glitch with the diff engine if (LeftLines[leftLine] == RightLines[rightLine]) { ContextLine(rightLine); return; } StringBuilder left = new StringBuilder(); StringBuilder right = new StringBuilder(); List <Word> leftList = Word.SplitString(LeftLines[leftLine]); List <Word> rightList = Word.SplitString(RightLines[rightLine]); diff = new Diff(leftList, rightList, Word.Comparer); foreach (Diff.Hunk h in diff) { if (h.Same) { for (int i = 0; i < h.Left.Count; i++) { WhitespaceDiff(left, rightList[h.Right.Start + i], leftList[h.Left.Start + i]); WhitespaceDiff(right, leftList[h.Left.Start + i], rightList[h.Right.Start + i]); } } else { WordDiff(left, h.Left, h.Right, leftList, rightList); WordDiff(right, h.Right, h.Left, rightList, leftList); } } if (!Variables.RTL) { Result.AppendFormat(@"<tr onclick='window.external.GoTo({1})' ondblclick='window.external.UndoChange({0},{1})'> <td>+</td> <td class='diff-addedline'>", rightLine, leftLine); Result.Append(right); Result.Append(@" </td> <td>-</td> <td class='diff-deletedline'>"); Result.Append(left); Result.Append(@" </td> </tr>"); } else { Result.AppendFormat(@"<tr onclick='window.external.GoTo({1})' ondblclick='window.external.UndoChange({0},{1})'> <td>-</td> <td class='diff-deletedline'>", leftLine, rightLine); Result.Append(left); Result.Append(@" </td> <td>+</td> <td class='diff-addedline'>"); Result.Append(right); Result.Append(@" </td> </tr>"); } }
public static void WriteUnifiedDiff(Diff diff, TextWriter writer, string fromfile, string tofile, int context) { writer.Write("--- "); writer.WriteLine(fromfile); writer.Write("+++ "); writer.WriteLine(tofile); ArrayList hunkset = new ArrayList(); foreach (Diff.Hunk hunk in diff) { Diff.Hunk lasthunk = null; if (hunkset.Count > 0) { lasthunk = (Diff.Hunk)hunkset[hunkset.Count - 1]; } if (hunk.Same) { // At the start of a hunk set, keep only context lines of context. if (lasthunk == null) { if (hunk.Left.Count > context) { hunkset.Add(hunk.Crop(hunk.Left.Count - context, 0)); } else { hunkset.Add(hunk); } // Can't have two same hunks in a row, so the last one was a difference. } else { // Small enough context that this unified diff range will not stop. if (hunk.Left.Count <= context * 2) { hunkset.Add(hunk); // Too much of the same. Keep context lines and end this section. // And then keep the last context lines as context for the next section. } else { hunkset.Add(hunk.Crop(0, hunk.Left.Count - context)); WriteUnifiedDiffSection(writer, hunkset); hunkset.Clear(); if (hunk.Left.Count > context) { hunkset.Add(hunk.Crop(hunk.Left.Count - context, 0)); } else { hunkset.Add(hunk); } } } } else { hunkset.Add(hunk); } } if (hunkset.Count > 0 && !(hunkset.Count == 1 && ((Diff.Hunk)hunkset[0]).Same)) { WriteUnifiedDiffSection(writer, hunkset); } }
public static void WriteUnifiedDiff(string[] leftLines, string leftName, string[] rightLines, string rightName, System.IO.TextWriter writer, int context, bool caseSensitive, bool compareWhitespace) { Diff diff = new Diff(leftLines, rightLines, caseSensitive, compareWhitespace); WriteUnifiedDiff(diff, writer, leftName, rightName, context); }