示例#1
0
        /// <summary>
        /// This method creates a unified diff file.
        /// </summary>
        /// <param name="oldInfo">Provides the information for the old file (optional).</param>
        /// <param name="newInfo">Provides the information for the new file (optional).</param>
        /// <param name="streamOut">Stream where the diff file is written.</param>
        /// <param name="contextLines">Number of context lines around hunks.</param>
        /// <returns></returns>
        public static bool Create(UnifiedDiffInfo oldInfo, UnifiedDiffInfo newInfo, Stream streamOut, int contextLines)
        {
            if (streamOut == null)
            {
                throw new ArgumentException("streamOut must not be null");
            }
            if (contextLines < 0)
            {
                throw new ArgumentException("contextLines cannot be negative");
            }

            StreamReader    streamReader1 = new StreamReader(oldInfo != null && oldInfo.Stream != null ? oldInfo.Stream : new MemoryStream());
            StreamReader    streamReader2 = new StreamReader(newInfo != null && newInfo.Stream != null ? newInfo.Stream : new MemoryStream());
            StreamWriter    streamWriter = new StreamWriter(streamOut);
            List <DiffLine> lines1 = new List <DiffLine>();
            List <DiffLine> lines2 = new List <DiffLine>();
            string          line1, line2;
            int             start = 0, end = 0, firstLine = 0;

            // Read text stream into a list. If the beginning of the file matches, this only keeps the
            // the last contextLines number of lines in memory for the unified context of the
            // first hunk.  Diff.CreateDiff() actually would do this for us too, but we don't need
            // to waste a lot of memory if we're not going to use it anyway.

            do
            {
                line1 = streamReader1.ReadLine();
                line2 = streamReader2.ReadLine();

                if (line1 != null && line2 != null && string.Equals(line1, line2))
                {
                    lines1.Add(new DiffLine(firstLine, line1));
                    lines2.Add(new DiffLine(firstLine, line2));

                    if (start == contextLines)
                    {
                        lines1.RemoveAt(0);
                        lines2.RemoveAt(0);
                        firstLine++;
                    }
                    else
                    {
                        start++;
                    }
                    continue;
                }

                while (line1 != null)
                {
                    lines1.Add(new DiffLine(firstLine + lines1.Count, line1));
                    line1 = streamReader1.ReadLine();
                }

                while (line2 != null)
                {
                    lines2.Add(new DiffLine(firstLine + lines2.Count, line2));
                    line2 = streamReader2.ReadLine();
                }
            } while (line1 != null || line2 != null);

            // Also get rid of the last lines of the file if they are equal
            int endCnt    = Math.Min(lines1.Count, lines2.Count) - start;
            int removeEnd = 0;

            for (int i = 0; i < endCnt; i++)
            {
                if (string.Equals(lines1[lines1.Count - i - 1].line, lines2[lines2.Count - i - 1].line))
                {
                    if (end == contextLines)
                    {
                        removeEnd++;
                    }
                    else
                    {
                        end++;
                    }
                }
                else
                {
                    break;
                }
            }

            if (removeEnd > 0)
            {
                lines1.RemoveRange(lines1.Count - removeEnd, removeEnd);
                lines2.RemoveRange(lines2.Count - removeEnd, removeEnd);
            }

            // Now we've got a list of lines to compare.  The list context contains start
            // lines before the first difference, and end lines after the last difference.
            List <DiffEntry <DiffLine> > diffEntries = Diff.CreateDiff <DiffLine>(lines1, lines2, start, end);

            // Create a list of hunks and their lines including the context lines
            List <Hunk> hunks = new List <Hunk>();
            Hunk        hunk  = null;

            int l1 = firstLine, l2 = firstLine;

            for (int i = 0; i < diffEntries.Count; i++)
            {
                DiffEntry <DiffLine> entry = diffEntries[i];

                if (hunk == null)
                {
                    if (entry.EntryType == DiffEntry <DiffLine> .DiffEntryType.Equal)
                    {
                        int cnt = Math.Min(entry.Count, contextLines);
                        hunk = new Hunk(l1 + entry.Count - cnt, l2 + entry.Count - cnt);
                        for (int j = cnt; j > 0; j--)
                        {
                            hunk.AddContext(lines1[l1 + entry.Count - j - firstLine].line);
                        }
                        hunks.Add(hunk);
                        l1 += entry.Count;
                        l2 += entry.Count;
                        continue;
                    }

                    hunk = new Hunk(l1, l2);
                    hunks.Add(hunk);
                }

                switch (entry.EntryType)
                {
                case DiffEntry <DiffLine> .DiffEntryType.Add:
                    hunk.AddNew(lines2[l2 - firstLine].line);
                    l2++;
                    break;

                case DiffEntry <DiffLine> .DiffEntryType.Remove:
                    hunk.AddRemove(lines1[l1 - firstLine].line);
                    l1++;
                    break;

                case DiffEntry <DiffLine> .DiffEntryType.Equal:
                    if (i == diffEntries.Count - 1)
                    {
                        int cnt = Math.Min(contextLines, entry.Count);
                        for (int j = 0; j < cnt; j++)
                        {
                            hunk.AddContext(lines1[l1 + j - firstLine].line);
                        }
                    }
                    else
                    {
                        if (entry.Count > 2 * contextLines)
                        {
                            for (int j = 0; j < contextLines; j++)
                            {
                                hunk.AddContext(lines1[l1 + j - firstLine].line);
                            }
                            l1 += entry.Count;
                            l2 += entry.Count;

                            hunk = new Hunk(l1 - contextLines, l2 - contextLines);
                            for (int j = contextLines; j > 0; j--)
                            {
                                hunk.AddContext(lines1[l1 - j - firstLine].line);
                            }
                            hunks.Add(hunk);
                        }
                        else
                        {
                            for (int j = 0; j < entry.Count; j++)
                            {
                                hunk.AddContext(lines1[l1 + j - firstLine].line);
                            }
                            l1 += entry.Count;
                            l2 += entry.Count;
                        }
                    }
                    break;
                }
            }

            if (hunks.Count > 0)
            {
                // Write the hunks to the output stream
                if (oldInfo != null && !string.IsNullOrEmpty(oldInfo.Label))
                {
                    streamWriter.WriteLine(string.Format("--- {0}", oldInfo.Label));
                }
                if (newInfo != null && !string.IsNullOrEmpty(newInfo.Label))
                {
                    streamWriter.WriteLine(string.Format("+++ {0}", newInfo.Label));
                }

                foreach (var hk in hunks)
                {
                    hk.Write(streamWriter);
                }

                streamWriter.WriteLine();
                streamWriter.Flush();
                return(true);
            }

            return(false);
        }
示例#2
0
        /// <summary>
        /// Creates a list of diff entries that represent the differences between arr1 and arr2.
        /// </summary>
        /// <typeparam name="T">Class that represents the unit to compare</typeparam>
        /// <param name="arr1">Array of units.</param>
        /// <param name="arr2">Array of units.</param>
        /// <param name="skipStart">Number of units to skip at the beginning.</param>
        /// <param name="skipEnd">Number of units to skip at the end.</param>
        /// <returns>List of DiffEntry classes.</returns>
        public static List <DiffEntry <T> > CreateDiff <T>(T[] arr1, T[] arr2, int skipStart, int skipEnd) where T : IComparable
        {
            int start = skipStart;
            int end   = skipEnd;

            // Strip off the beginning and end, if it's equal
            while (start < Math.Min(arr1.Length, arr2.Length) - skipEnd)
            {
                if (arr1[start].CompareTo(arr2[start]) != 0)
                {
                    break;
                }
                start++;
            }

            if (start == arr1.Length - skipEnd && start == arr2.Length - skipEnd)
            {
                return(new List <DiffEntry <T> >());
            }

            for (int i = 0; i < Math.Min(arr1.Length, arr2.Length) - start - skipEnd; i++)
            {
                if (arr1[arr1.Length - i - skipEnd - 1].CompareTo(arr2[arr2.Length - i - skipEnd - 1]) != 0)
                {
                    break;
                }
                end++;
            }

            int lines1_cnt = arr1.Length - start - end;
            int lines2_cnt = arr2.Length - start - end;

            int[,] lcs = new int[lines1_cnt, lines2_cnt];

            // Calculate longest common sequence
            for (int i = 0; i < lines1_cnt; i++)
            {
                for (int j = 0; j < lines2_cnt; j++)
                {
                    int iVal = i + start;
                    int jVal = j + start;

                    if (arr1[iVal].CompareTo(arr2[jVal]) != 0)
                    {
                        if (i == 0 && j == 0)
                        {
                            lcs[i, j] = 0;
                        }
                        else if (i == 0 && j != 0)
                        {
                            lcs[i, j] = Math.Max(0, lcs[i, j - 1]);
                        }
                        else if (i != 0 && j == 0)
                        {
                            lcs[i, j] = Math.Max(lcs[i - 1, j], 0);
                        }
                        else // if (i != 0 && j != 0)
                        {
                            lcs[i, j] = Math.Max(lcs[i - 1, j], lcs[i, j - 1]);
                        }
                    }
                    else
                    {
                        if (i == 0 || j == 0)
                        {
                            lcs[i, j] = 1;
                        }
                        else
                        {
                            lcs[i, j] = 1 + lcs[i - 1, j - 1];
                        }
                    }
                }
            }

            // Build the list of differences
            Stack <int[]>         stck      = new Stack <int[]>();
            List <DiffEntry <T> > diffList  = new List <DiffEntry <T> >();
            DiffEntry <T>         lastEqual = null;

            stck.Push(new int[2] {
                lines1_cnt - 1, lines2_cnt - 1
            });
            do
            {
                int[] data = stck.Pop();

                int i = data[0];
                int j = data[1];

                if (i >= 0 && j >= 0 && arr1[i + start].CompareTo(arr2[j + start]) == 0)
                {
                    stck.Push(new int[2] {
                        i - 1, j - 1
                    });
                    if (lastEqual != null)
                    {
                        lastEqual.Count++;
                    }
                    else
                    {
                        lastEqual = new DiffEntry <T>();
                        diffList.Add(lastEqual);
                    }
                }
                else
                {
                    if (j >= 0 && (i <= 0 || j == 0 || lcs[i, j - 1] >= lcs[i - 1, j]))
                    {
                        stck.Push(new int[2] {
                            i, j - 1
                        });
                        diffList.Add(new DiffEntry <T>(DiffEntry <T> .DiffEntryType.Add, arr2[j + start]));
                        lastEqual = null;
                    }
                    else if (i >= 0 && (j <= 0 || i == 0 || lcs[i, j - 1] < lcs[i - 1, j]))
                    {
                        stck.Push(new int[2] {
                            i - 1, j
                        });
                        diffList.Add(new DiffEntry <T>(DiffEntry <T> .DiffEntryType.Remove, arr1[i + start]));
                        lastEqual = null;
                    }
                }
            } while (stck.Count > 0);

            diffList.Reverse();

            if (skipStart > 0)
            {
                lastEqual       = new DiffEntry <T>();
                lastEqual.Count = skipStart;
                diffList.Insert(0, lastEqual);
            }

            if (skipEnd > 0)
            {
                lastEqual       = new DiffEntry <T>();
                lastEqual.Count = skipEnd;
                diffList.Add(lastEqual);
            }

            return(diffList);
        }