patch_apply method
Merge a set of patches onto the text. Return a patched text, as well
as an array of true/false values indicating which patches were applied.
patches
is a List of Patch objects
text
is the old text.
Returns a two element List, containing the new text and a List of bool values.
Implementation
Pair<String, Map<int, bool>> patch_apply(List<Patch> patches, String text) {
if (patches.isEmpty) {
return Pair(text, const {});
}
// Deep copy the patches so that no changes are made to originals.
patches = patch_deepCopy(patches);
final nullPadding = patch_addPadding(patches);
text = nullPadding + text + nullPadding;
patch_splitMax(patches);
int x = 0;
// delta keeps track of the offset between the expected and actual location
// of the previous patch. If there are patches expected at positions 10 and
// 20, but the first patch was found at 12, delta is 2 and the second patch
// has an effective expected position of 22.
int delta = 0;
final results = <int, bool>{};
for (final aPatch in patches) {
final expected_loc = aPatch.start2 + delta,
text1 = diff_text1(aPatch.diffs);
int? start_loc;
int end_loc = -1;
if (text1.length > Match_MaxBits) {
// patch_splitMax will only provide an oversized pattern in the case of
// a monster delete.
start_loc =
match_main(text, text1.substring(0, Match_MaxBits), expected_loc);
if (start_loc != -1) {
end_loc = match_main(
text,
text1.substring(text1.length - Match_MaxBits),
expected_loc + text1.length - Match_MaxBits);
if (end_loc == -1 || start_loc >= end_loc) {
// Can't find valid trailing context. Drop this patch.
start_loc = -1;
}
}
} else {
start_loc = match_main(text, text1, expected_loc);
}
if (start_loc == -1) {
// No match found. :(
results[x] = false;
// Subtract the delta for this failed patch from subsequent patches.
delta -= aPatch.length2 - aPatch.length1;
} else {
// Found a match. :)
results[x] = true;
delta = start_loc - expected_loc;
String text2;
if (end_loc == -1) {
text2 = text.substring(
start_loc, min(start_loc + text1.length, text.length));
} else {
text2 = text.substring(
start_loc, min(end_loc + Match_MaxBits, text.length));
}
if (text1 == text2) {
// Perfect match, just shove the replacement text in.
text = text.substring(0, start_loc) +
diff_text2(aPatch.diffs) +
text.substring(start_loc + text1.length);
} else {
// Imperfect match. Run a diff to get a framework of equivalent
// indices.
final diffs = diff_main(text1, text2, false);
if (text1.length > Match_MaxBits &&
diff_levenshtein(diffs) / text1.length > Patch_DeleteThreshold) {
// The end points match, but the content is unacceptably bad.
results[x] = false;
} else {
_diff_cleanupSemanticLossless(diffs);
int index1 = 0;
for (Diff aDiff in aPatch.diffs) {
if (aDiff.operation != Operation.equal) {
int index2 = diff_xIndex(diffs, index1);
if (aDiff.operation == Operation.insert) {
// Insertion
text = text.substring(0, start_loc + index2) +
aDiff.text +
text.substring(start_loc + index2);
} else if (aDiff.operation == Operation.delete) {
// Deletion
text = text.substring(0, start_loc + index2) +
text.substring(start_loc +
diff_xIndex(diffs, index1 + aDiff.text.length));
}
}
if (aDiff.operation != Operation.delete) {
index1 += aDiff.text.length;
}
}
}
}
}
x++;
}
// Strip the padding off.
text = text.substring(nullPadding.length, text.length - nullPadding.length);
return Pair(text, results);
}