示例#1
0
        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);
        }