Exemplo n.º 1
0
        private Chunk CreateChunk(Diff.Item change, CompareOptions options)
        {
            var chunk = new Chunk();

            chunk.start1  = change.StartA;
            chunk.start2  = change.StartB;
            chunk.length1 = change.deletedA + options.ContextSize;
            chunk.length2 = change.insertedB + options.ContextSize;
            chunk.diffs   = new List <Line>();
            return(chunk);
        }
Exemplo n.º 2
0
 public void patch_patchObjTest()
 {
     // Patch Object.
     var p = new Patch{
         start1 = 20, start2 = 21, length1 = 18, length2 = 17, diffs = new List<Diff>{
             new Diff(Operation.Equal, "jump"),
             new Diff(Operation.Delete, "s"),
             new Diff(Operation.Insert, "ed"),
             new Diff(Operation.Equal, " over "),
             new Diff(Operation.Delete, "the"),
             new Diff(Operation.Insert, "a"),
             new Diff(Operation.Equal, "\nlaz")
         }
     };
     const string strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n %0alaz\n";
     Assert.AreEqual(strp, p.ToString(), "Patch: toString.");
 }
Exemplo n.º 3
0
 public void patch_patchObjTest() {
   // Patch Object.
   Patch p = new Patch();
   p.start1 = 20;
   p.start2 = 21;
   p.length1 = 18;
   p.length2 = 17;
   p.diffs = new List<Diff> {
       new Diff(Operation.EQUAL, "jump"),
       new Diff(Operation.DELETE, "s"),
       new Diff(Operation.INSERT, "ed"),
       new Diff(Operation.EQUAL, " over "),
       new Diff(Operation.DELETE, "the"),
       new Diff(Operation.INSERT, "a"),
       new Diff(Operation.EQUAL, "\nlaz")};
   string strp = "@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n  over \n-the\n+a\n %0alaz\n";
   Assert.AreEqual(strp, p.ToString(), "Patch: toString.");
 }
Exemplo n.º 4
0
        public IEnumerable <DiffMatchPatch.Patch> MakePatch(string contentOne, string contentTwo, CompareOptions options)
        {
            var diff            = new my.utils.Diff();
            var changes         = diff.DiffText(contentOne, contentTwo);
            var contentOneLines = contentOne.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            var contentTwoLines = contentTwo.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            var   chunks       = new HashSet <Chunk>();
            Chunk currentChunk = null;

            for (var i = 0; i < changes.Length; i++)
            {
                var       change     = changes[i];
                Diff.Item?nextChange = null;

                if (changes.Length > i + 1)
                {
                    nextChange = changes.ElementAtOrDefault(i + 1);
                }

                var continuation = currentChunk != null;

                if (!continuation)
                {
                    currentChunk = CreateChunk(change, options);
                    chunks.Add(currentChunk);
                }

                if (change.StartA != 0 && !continuation)
                {
                    // no start context needed
                    currentChunk.start1 = change.StartA - options.ContextSize;
                    currentChunk.start2 = change.StartB - options.ContextSize;

                    // stick some context in
                    var start = change.StartB - options.ContextSize;
                    for (var j = start; j < change.StartB; j++)
                    {
                        currentChunk.diffs.Add(new Line(Operation.EQUAL, contentTwoLines[j]));
                    }
                }

                if (change.deletedA > 0)
                {
                    for (var j = 0; j < change.deletedA; j++)
                    {
                        var line = contentOneLines[j + change.StartA];
                        currentChunk.diffs.Add(new Line(Operation.DELETE, line));
                    }
                }

                if (change.insertedB > 0)
                {
                    for (var j = 0; j < change.insertedB; j++)
                    {
                        var line = contentTwoLines[j + change.StartB];
                        currentChunk.diffs.Add(new Line(Operation.INSERT, line));
                    }
                }

                var start2 = change.StartB + change.insertedB;
                int end;

                if (nextChange.HasValue)
                {
                    end = Min(start2 + options.ContextSize, contentTwoLines.Length, nextChange.Value.StartB);
                }
                else
                {
                    end = Min(start2 + options.ContextSize, contentTwoLines.Length);
                }

                for (var j = start2; j < end; j++)
                {
                    currentChunk.diffs.Add(new Line(Operation.EQUAL, contentTwoLines[j]));
                }

                if (nextChange.HasValue && nextChange.Value.StartB - end > 0)
                {
                    // need to split the diff into multiple chunks
                    currentChunk = null;
                }
            }

            foreach (var chunk in chunks)
            {
                chunk.length1 = chunk.diffs.Count(x => x.operation == Operation.EQUAL || x.operation == Operation.DELETE);
                chunk.length2 = chunk.diffs.Count(x => x.operation == Operation.EQUAL || x.operation == Operation.INSERT);
            }

            return(chunks);
        }
Exemplo n.º 5
0
        /**
         * Look through the patches and break up any which are longer than the
         * maximum limit of the match algorithm.
         * Intended to be called only from within patch_apply.
         * @param patches List of Patch objects.
         */
        public void patch_splitMax(List<Patch> patches)
        {
            const short patch_size = Match_MaxBits;
            for (int x = 0; x < patches.Count; x++) {
                if (patches[x].length1 > patch_size) {
                    Patch bigpatch = patches[x];
                    // Remove the big old patch.
                    patches.Splice(x--, 1);
                    int start1 = bigpatch.start1;
                    int start2 = bigpatch.start2;
                    string precontext = string.Empty;
                    while (bigpatch.diffs.Count != 0) {
                        // Create one of several smaller patches.
                        var patch = new Patch();
                        bool empty = true;
                        patch.start1 = start1 - precontext.Length;
                        patch.start2 = start2 - precontext.Length;
                        if (precontext.Length != 0) {
                            patch.length1 = patch.length2 = precontext.Length;
                            patch.diffs.Add(new Diff(Operation.Equal, precontext));
                        }
                        while (bigpatch.diffs.Count != 0
                            && patch.length1 < patch_size - Patch_Margin) {
                            Operation diff_type = bigpatch.diffs[0].operation;
                            if (bigpatch.diffs[0].text == null) throw new Exception("Diff text null");
                            string diff_text = bigpatch.diffs[0].text;
                            if (diff_type == Operation.Insert) {
                                // Insertions are harmless.
                                patch.length2 += diff_text.Length;
                                start2 += diff_text.Length;
                                patch.diffs.Add(bigpatch.diffs.First());
                                bigpatch.diffs.RemoveAt(0);
                                empty = false;
                            } else if (diff_type == Operation.Delete && patch.diffs.Count == 1
                                && patch.diffs.First().operation == Operation.Equal
                                && diff_text.Length > 2 * patch_size) {
                                // This is a large deletion.  Let it pass in one chunk.
                                patch.length1 += diff_text.Length;
                                start1 += diff_text.Length;
                                empty = false;
                                patch.diffs.Add(new Diff(diff_type, diff_text));
                                bigpatch.diffs.RemoveAt(0);
                            } else {
                                // Deletion or equality.  Only take as much as we can stomach.
                                diff_text = diff_text.Substring(0, Math.Min(diff_text.Length,
                                    patch_size - patch.length1 - Patch_Margin));
                                patch.length1 += diff_text.Length;
                                start1 += diff_text.Length;
                                if (diff_type == Operation.Equal) {
                                    patch.length2 += diff_text.Length;
                                    start2 += diff_text.Length;
                                } else {
                                    empty = false;
                                }
                                patch.diffs.Add(new Diff(diff_type, diff_text));
                                if (diff_text == bigpatch.diffs[0].text) {
                                    bigpatch.diffs.RemoveAt(0);
                                } else {
                                    bigpatch.diffs[0].text =
                                        bigpatch.diffs[0].text.Substring(diff_text.Length);
                                }
                            }
                        }
                        // Compute the head context for the next patch.
                        precontext = diff_text2(patch.diffs);
                        precontext = precontext.Substring(Math.Max(0,
                            precontext.Length - Patch_Margin));

                        string postcontext;
                        // Append the end context for this patch.
                        if (diff_text1(bigpatch.diffs).Length > Patch_Margin) {
                            postcontext = diff_text1(bigpatch.diffs)
                                .Substring(0, Patch_Margin);
                        } else {
                            postcontext = diff_text1(bigpatch.diffs);
                        }

                        if (postcontext.Length != 0) {
                            patch.length1 += postcontext.Length;
                            patch.length2 += postcontext.Length;
                            if (patch.diffs.Count != 0
                                && patch.diffs[patch.diffs.Count - 1].operation
                                == Operation.Equal) {
                                patch.diffs[patch.diffs.Count - 1].text += postcontext;
                            } else {
                                patch.diffs.Add(new Diff(Operation.Equal, postcontext));
                            }
                        }
                        if (!empty) {
                            patches.Splice(++x, 0, patch);
                        }
                    }
                }
            }
        }
Exemplo n.º 6
0
        //  PATCH FUNCTIONS
        /**
         * Increase the context until it is unique,
         * but don't let the pattern expand beyond Match_MaxBits.
         * @param patch The patch to grow.
         * @param text Source text.
         */
        protected void patch_addContext(Patch patch, string text)
        {
            if (text.Length == 0) {
                return;
            }
            string pattern = text.Substring(patch.start2, patch.length1);
            int padding = 0;

            // Look for the first and last matches of pattern in text.  If two
            // different matches are found, increase the pattern length.
            while (text.IndexOf(pattern, StringComparison.Ordinal)
                != text.LastIndexOf(pattern, StringComparison.Ordinal)
                && pattern.Length < Match_MaxBits - Patch_Margin - Patch_Margin) {
                padding += Patch_Margin;
                pattern = text.JavaSubstring(Math.Max(0, patch.start2 - padding),
                    Math.Min(text.Length, patch.start2 + patch.length1 + padding));
            }
            // Add one chunk for good luck.
            padding += Patch_Margin;

            // Add the prefix.
            string prefix = text.JavaSubstring(Math.Max(0, patch.start2 - padding),
              patch.start2);
            if (prefix.Length != 0) {
                patch.diffs.Insert(0, new Diff(Operation.Equal, prefix));
            }
            // Add the suffix.
            string suffix = text.JavaSubstring(patch.start2 + patch.length1,
                Math.Min(text.Length, patch.start2 + patch.length1 + padding));
            if (suffix.Length != 0) {
                patch.diffs.Add(new Diff(Operation.Equal, suffix));
            }

            // Roll back the start points.
            patch.start1 -= prefix.Length;
            patch.start2 -= prefix.Length;
            // Extend the lengths.
            patch.length1 += prefix.Length + suffix.Length;
            patch.length2 += prefix.Length + suffix.Length;
        }
Exemplo n.º 7
0
        /**
         * Compute a list of patches to turn text1 into text2.
         * text2 is not provided, diffs are the delta between text1 and text2.
         * @param text1 Old text.
         * @param diffs Array of diff tuples for text1 to text2.
         * @return List of Patch objects.
         */
        public List<Patch> patch_make(string text1, List<Diff> diffs)
        {
            // Check for null inputs not needed since null can't be passed in C#.
            var patches = new List<Patch>();
            if (diffs.Count == 0) {
                return patches;  // Get rid of the null case.
            }
            var patch = new Patch();
            int char_count1 = 0;  // Number of characters into the text1 string.
            int char_count2 = 0;  // Number of characters into the text2 string.
            // Start with text1 (prepatch_text) and apply the diffs until we arrive at
            // text2 (postpatch_text). We recreate the patches one by one to determine
            // context info.
            string prepatch_text = text1;
            string postpatch_text = text1;
            foreach (Diff aDiff in diffs) {
                if (patch.diffs.Count == 0 && aDiff.operation != Operation.Equal) {
                    // A new patch starts here.
                    patch.start1 = char_count1;
                    patch.start2 = char_count2;
                }

                switch (aDiff.operation) {
                    case Operation.Insert:
                        patch.diffs.Add(aDiff);
                        patch.length2 += aDiff.text.Length;
                        postpatch_text = postpatch_text.Insert(char_count2, aDiff.text);
                        break;
                    case Operation.Delete:
                        patch.length1 += aDiff.text.Length;
                        patch.diffs.Add(aDiff);
                        postpatch_text = postpatch_text.Remove(char_count2,
                            aDiff.text.Length);
                        break;
                    case Operation.Equal:
                        if (aDiff.text.Length <= 2 * Patch_Margin
                            && patch.diffs.Count() != 0 && aDiff != diffs.Last()) {
                            // Small equality inside a patch.
                            patch.diffs.Add(aDiff);
                            patch.length1 += aDiff.text.Length;
                            patch.length2 += aDiff.text.Length;
                        }

                        if (aDiff.text.Length >= 2 * Patch_Margin) {
                            // Time for a new patch.
                            if (patch.diffs.Count != 0) {
                                patch_addContext(patch, prepatch_text);
                                patches.Add(patch);
                                patch = new Patch();
                                // Unlike Unidiff, our patch lists have a rolling context.
                                // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
                                // Update prepatch text & pos to reflect the application of the
                                // just completed patch.
                                prepatch_text = postpatch_text;
                                char_count1 = char_count2;
                            }
                        }
                        break;
                }

                // Update the current character count.
                if (aDiff.operation != Operation.Insert) {
                    char_count1 += aDiff.text.Length;
                }
                if (aDiff.operation != Operation.Delete) {
                    char_count2 += aDiff.text.Length;
                }
            }
            // Pick up the leftover patch if not empty.
            if (patch.diffs.Count != 0) {
                patch_addContext(patch, prepatch_text);
                patches.Add(patch);
            }

            return patches;
        }
Exemplo n.º 8
0
        /**
         * Parse a textual representation of patches and return a List of Patch
         * objects.
         * @param textline Text representation of patches.
         * @return List of Patch objects.
         * @throws ArgumentException If invalid input.
         */
        public List<Patch> patch_fromText(string textline)
        {
            var patches = new List<Patch>();
            if (textline.Length == 0) {
                return patches;
            }
            string[] text = textline.Split('\n');
            int textPointer = 0;
            Patch patch;
            var patchHeader = new Regex("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$");
            Match m;
            string line;
            while (textPointer < text.Length) {
                m = patchHeader.Match(text[textPointer]);
                if (!m.Success) {
                    throw new ArgumentException("Invalid patch string: "
                        + text[textPointer]);
                }
                patch = new Patch();
                patches.Add(patch);
                patch.start1 = Convert.ToInt32(m.Groups[1].Value);
                if (m.Groups[2].Length == 0) {
                    patch.start1--;
                    patch.length1 = 1;
                } else if (m.Groups[2].Value == "0") {
                    patch.length1 = 0;
                } else {
                    patch.start1--;
                    patch.length1 = Convert.ToInt32(m.Groups[2].Value);
                }

                patch.start2 = Convert.ToInt32(m.Groups[3].Value);
                if (m.Groups[4].Length == 0) {
                    patch.start2--;
                    patch.length2 = 1;
                } else if (m.Groups[4].Value == "0") {
                    patch.length2 = 0;
                } else {
                    patch.start2--;
                    patch.length2 = Convert.ToInt32(m.Groups[4].Value);
                }
                textPointer++;

                while (textPointer < text.Length) {
                    char sign;
                    try {
                        sign = text[textPointer][0];
                    } catch (IndexOutOfRangeException) {
                        // Blank line?  Whatever.
                        textPointer++;
                        continue;
                    }
                    line = text[textPointer].Substring(1);
                    line = line.Replace("+", "%2b");
                    line = HttpUtility.UrlDecode(line, new UTF8Encoding(false, true));
                    if (sign == '-') {
                        // Deletion.
                        patch.diffs.Add(new Diff(Operation.Delete, line));
                    } else if (sign == '+') {
                        // Insertion.
                        patch.diffs.Add(new Diff(Operation.Insert, line));
                    } else if (sign == ' ') {
                        // Minor equality.
                        patch.diffs.Add(new Diff(Operation.Equal, line));
                    } else if (sign == '@') {
                        // Start of next patch.
                        break;
                    } else {
                        // WTF?
                        throw new ArgumentException(
                            "Invalid patch mode '" + sign + "' in: " + line);
                    }
                    textPointer++;
                }
            }
            return patches;
        }
Exemplo n.º 9
0
 /**
  * Given an array of patches, return another array that is identical.
  * @param patches Array of patch objects.
  * @return Array of patch objects.
  */
 public List<Patch> patch_deepCopy(List<Patch> patches)
 {
     var patchesCopy = new List<Patch>();
     foreach (Patch aPatch in patches) {
         var patchCopy = new Patch();
         foreach (Diff aDiff in aPatch.diffs) {
             var diffCopy = new Diff(aDiff.operation, aDiff.text);
             patchCopy.diffs.Add(diffCopy);
         }
         patchCopy.start1 = aPatch.start1;
         patchCopy.start2 = aPatch.start2;
         patchCopy.length1 = aPatch.length1;
         patchCopy.length2 = aPatch.length2;
         patchesCopy.Add(patchCopy);
     }
     return patchesCopy;
 }
Exemplo n.º 10
0
        /// <summary>
        /// Compute a list of patches to turn text1 into text2.
        /// text2 is not provided, Diffs are the delta between text1 and text2.
        /// </summary>
        /// <param name="text1"></param>
        /// <param name="diffs"></param>
        /// <param name="patchMargin"></param>
        /// <returns></returns>
        public static List <Patch> Compute(string text1, List <Diff> diffs, short patchMargin = 4)
        {
            // Check for null inputs not needed since null can't be passed in C#.
            var patches = new List <Patch>();

            if (diffs.Count == 0)
            {
                return(patches);  // Get rid of the null case.
            }
            var patch      = new Patch();
            var charCount1 = 0;  // Number of characters into the text1 string.
            var charCount2 = 0;  // Number of characters into the text2 string.
            // Start with text1 (prepatch_text) and apply the Diffs until we arrive at
            // text2 (postpatch_text). We recreate the patches one by one to determine
            // context info.
            var prepatchText  = text1;
            var postpatchText = text1;

            foreach (var aDiff in diffs)
            {
                if (!patch.Diffs.Any() && aDiff.Operation != Operation.Equal)
                {
                    // A new patch starts here.
                    patch.Start1 = charCount1;
                    patch.Start2 = charCount2;
                }

                switch (aDiff.Operation)
                {
                case Operation.Insert:
                    patch.Diffs.Add(aDiff);
                    patch.Length2 += aDiff.Text.Length;
                    postpatchText  = postpatchText.Insert(charCount2, aDiff.Text);
                    break;

                case Operation.Delete:
                    patch.Length1 += aDiff.Text.Length;
                    patch.Diffs.Add(aDiff);
                    postpatchText = postpatchText.Remove(charCount2,
                                                         aDiff.Text.Length);
                    break;

                case Operation.Equal:
                    if (aDiff.Text.Length <= 2 * patchMargin &&
                        patch.Diffs.Any() && aDiff != diffs.Last())
                    {
                        // Small equality inside a patch.
                        patch.Diffs.Add(aDiff);
                        patch.Length1 += aDiff.Text.Length;
                        patch.Length2 += aDiff.Text.Length;
                    }

                    if (aDiff.Text.Length >= 2 * patchMargin)
                    {
                        // Time for a new patch.
                        if (patch.Diffs.Any())
                        {
                            patch.AddContext(prepatchText);
                            patches.Add(patch);
                            patch = new Patch();
                            // Unlike Unidiff, our patch lists have a rolling context.
                            // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
                            // Update prepatch text & pos to reflect the application of the
                            // just completed patch.
                            prepatchText = postpatchText;
                            charCount1   = charCount2;
                        }
                    }
                    break;
                }

                // Update the current character count.
                if (aDiff.Operation != Operation.Insert)
                {
                    charCount1 += aDiff.Text.Length;
                }
                if (aDiff.Operation != Operation.Delete)
                {
                    charCount2 += aDiff.Text.Length;
                }
            }
            // Pick up the leftover patch if not empty.
            if (patch.Diffs.Any())
            {
                patch.AddContext(prepatchText);
                patches.Add(patch);
            }

            return(patches);
        }
Exemplo n.º 11
0
 private Chunk CreateChunk(Diff.Item change, CompareOptions options)
 {
     var chunk = new Chunk();
     chunk.start1 = change.StartA;
     chunk.start2 = change.StartB;
     chunk.length1 = change.deletedA + options.ContextSize;
     chunk.length2 = change.insertedB + options.ContextSize;
     chunk.diffs = new List<Line>();
     return chunk;
 }