private Patch ApplyExactAt(int loc, WorkingPatch patch) { if (!patch.ContextLines.SequenceEqual(lines.GetRange(loc, patch.length1))) { throw new Exception("Patch engine failure"); } if (!CanApplySafelyAt(loc, patch)) { throw new Exception("Patch affects another patch"); } lines.RemoveRange(loc, patch.length1); lines.InsertRange(loc, patch.PatchedLines); //update the lineModeText if (lmText != null) { lmText = lmText.Remove(loc) + patch.lmPatched + lmText.Substring(loc + patch.length1); } //update the wordModeLines if (wmLines != null) { wmLines.RemoveRange(loc, patch.length1); wmLines.InsertRange(loc, patch.wmPatched); } int patchedDelta = patches.Where(p => p.KeepoutRange2?.end <= loc).Sum(p => p.AppliedDelta.Value); Patch appliedPatch = patch; if (appliedPatch.start2 != loc || appliedPatch.start1 != loc - patchedDelta) { appliedPatch = new Patch(patch) //create a new patch with different applied position if necessary { start1 = loc - patchedDelta, start2 = loc } } ; // update the applied location for patches following this one in the file, but preceding it in the patch list // can only happen if fuzzy matching causes a patch to move before one of the previously applied patches if (loc < ModifiedRange.end) { foreach (var p in patches.Where(p => p.KeepoutRange2?.start > loc)) { p.result.appliedPatch.start2 += appliedPatch.length2 - appliedPatch.length1; } } else { lastAppliedPatch = appliedPatch; } searchOffset = appliedPatch.start2 - patch.start2; return(appliedPatch); }
private bool ApplyOffset(WorkingPatch patch) { if (lmText == null) { LinesToChars(); } if (patch.length1 > lines.Count) { return(false); } int loc = patch.start2 + searchOffset; if (loc < 0) { loc = 0; } else if (loc >= lines.Count) { loc = lines.Count - 1; } int forward = lmText.IndexOf(patch.lmContext, loc, StringComparison.Ordinal); int reverse = lmText.LastIndexOf(patch.lmContext, Math.Min(loc + patch.lmContext.Length, lines.Count - 1), StringComparison.Ordinal); if (!CanApplySafelyAt(forward, patch)) { forward = -1; } if (!CanApplySafelyAt(reverse, patch)) { reverse = -1; } if (forward < 0 && reverse < 0) { return(false); } int found = reverse < 0 || forward >= 0 && (forward - loc) < (loc - reverse) ? forward : reverse; patch.Succeed(Mode.OFFSET, ApplyExactAt(found, patch)); patch.AddOffsetResult(found - loc, lines.Count); return(true); }
private bool ApplyExact(WorkingPatch patch) { int loc = patch.start2 + searchOffset; if (loc + patch.length1 > lines.Count) { return(false); } if (!patch.ContextLines.SequenceEqual(lines.GetRange(loc, patch.length1))) { return(false); } patch.Succeed(Mode.EXACT, ApplyExactAt(loc, patch)); return(true); }
private Patch ApplyExactAt(int loc, WorkingPatch patch) { if (!patch.ContextLines.SequenceEqual(textLines.GetRange(loc, patch.length1))) { throw new Exception("Patch engine failure"); } textLines.RemoveRange(loc, patch.length1); textLines.InsertRange(loc, patch.PatchedLines); //update the lineModeText if (lmText != null) { lmText = lmText.Remove(loc) + patch.lmPatched + lmText.Substring(loc + patch.length1); } //update the wordModeLines if (wmLines != null) { wmLines.RemoveRange(loc, patch.length1); wmLines.InsertRange(loc, patch.wmPatched); } Patch applied = patch; if (applied.start2 != loc || applied.start1 != loc - patchedDelta) { applied = new Patch(patch) //create a new patch with different applied position if necessary { start1 = loc - patchedDelta, start2 = loc } } ; //update the patchedDelta and searchOffset searchOffset = loc - patch.start2; patchedDelta += patch.length2 - patch.length1; lastPatchedLine = loc + patch.length2; return(applied); }
private bool ApplyFuzzy(WorkingPatch patch) { if (wmLines == null) { WordsToChars(); } int loc = patch.start2 + searchOffset; if (loc + patch.length1 > wmLines.Count) //initialise search at end of file if loc is past file length { loc = wmLines.Count - patch.length1; } (int[] match, float matchQuality) = FindMatch(loc, patch.wmContext); if (match == null) { return(false); } var fuzzyPatch = new WorkingPatch(AdjustPatchToMatchedLines(patch, match, lines)); if (wmLines != null) { fuzzyPatch.WordsToChars(charRep); } if (lmText != null) { fuzzyPatch.LinesToChars(charRep); } int at = match.First(i => i >= 0); //if the patch needs lines trimmed off it, the early match entries will be negative patch.Succeed(Mode.FUZZY, ApplyExactAt(at, fuzzyPatch)); patch.AddOffsetResult(fuzzyPatch.start2 - loc, lines.Count); patch.AddFuzzyResult(matchQuality); return(true); }
private bool ApplyFuzzy(WorkingPatch patch) { if (wmLines == null) { WordsToChars(); } int loc = patch.start2 + searchOffset; if (loc + patch.length1 > wmLines.Count) //initialise search at end of file if loc is past file length { loc = wmLines.Count - patch.length1; } int[] match = FindMatch(loc, patch.wmContext, out float matchQuality); if (match == null) { return(false); } //replace the patch with a copy var fuzzyPatch = new WorkingPatch(patch); var diffs = fuzzyPatch.diffs; //for convenience //keep operations, but replace lines with lines in source text //unmatched patch lines (-1) are deleted //unmatched target lines (increasing offset) are added to the patch for (int i = 0, j = 0, ploc = -1; i < patch.length1; i++) { int mloc = match[i]; //insert extra target lines into patch if (mloc >= 0 && ploc >= 0 && mloc - ploc > 1) { //delete an unmatched target line if the surrounding diffs are also DELETE, otherwise use it as context var op = diffs[j - 1].op == Operation.DELETE && diffs[j].op == Operation.DELETE ? Operation.DELETE : Operation.EQUAL; for (int l = ploc + 1; l < mloc; l++) { diffs.Insert(j++, new Diff(op, textLines[l])); } } ploc = mloc; //keep insert lines the same while (diffs[j].op == Operation.INSERT) { j++; } if (mloc < 0) //unmatched context line { diffs.RemoveAt(j); } else //update context to match target file (may be the same, doesn't matter) { diffs[j++].text = textLines[mloc]; } } //finish our new patch fuzzyPatch.RecalculateLength(); if (wmLines != null) { fuzzyPatch.WordsToChars(charRep); } if (lmText != null) { fuzzyPatch.LinesToChars(charRep); } int at = match.First(i => i >= 0); //if the patch needs lines trimmed off it, the early match entries will be negative patch.Succeed(Mode.FUZZY, ApplyExactAt(at, fuzzyPatch)); patch.AddOffsetResult(fuzzyPatch.start2 - loc, textLines.Count); patch.AddFuzzyResult(matchQuality); return(true); }