patchMake function
Compute a List of Patches to turn text1
into text2
.
Use diffs if provided, otherwise compute it ourselves. There are four ways to call this function, depending on what data is available to the caller:
- Method 1:
a
= text1,b
= text2 - Method 2:
a
= diffs - Method 3 (optimal):
a
= text1,b
= diffs - Method 4 (deprecated, use method 3):
a
= text1,b
= text2,c
= diffs
Returns a List of Patch objects.
Implementation
List<Patch> patchMake(Object? a, {Object? b, Object? c, double diffTimeout: 1.0, DateTime? diffDeadline,
int diffEditCost: 4, double deleteThreshold: 0.5, int margin: 4}) {
String text1;
List<Diff> diffs;
if (a is String && b is String && c == null) {
// Method 1: text1, text2
// Compute diffs from text1 and text2.
text1 = a;
diffs = diff(text1, b, checklines: true, timeout: diffTimeout,
deadline: diffDeadline);
if (diffs.length > 2) {
cleanupSemantic(diffs);
cleanupEfficiency(diffs, diffEditCost);
}
} else if (a is List<Diff> && b == null && c == null) {
// Method 2: diffs
// Compute text1 from diffs.
diffs = a;
text1 = diffText1(diffs);
} else if (a is String && b is List<Diff> && c == null) {
// Method 3: text1, diffs
text1 = a;
diffs = b;
} else if (a is String && b is String && c is List<Diff>) {
// Method 4: text1, text2, diffs
// text2 is not used.
text1 = a;
diffs = c;
} else {
throw new ArgumentError('Unknown call format to patch_make.');
}
final patches = <Patch>[];
if (diffs.isEmpty) {
return patches; // Get rid of the null case.
}
Patch patch = new Patch();
final postpatch_buffer = new StringBuffer();
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;
for (Diff aDiff in diffs) {
if (patch.diffs.isEmpty && aDiff.operation != DIFF_EQUAL) {
// A new patch starts here.
patch.start1 = char_count1;
patch.start2 = char_count2;
}
switch (aDiff.operation) {
case DIFF_INSERT:
patch.diffs.add(aDiff);
patch.length2 += aDiff.text.length;
postpatch_buffer.clear();
postpatch_buffer
..write(postpatch_text.substring(0, char_count2))
..write(aDiff.text)
..write(postpatch_text.substring(char_count2));
postpatch_text = postpatch_buffer.toString();
break;
case DIFF_DELETE:
patch.length1 += aDiff.text.length;
patch.diffs.add(aDiff);
postpatch_buffer.clear();
postpatch_buffer
..write(postpatch_text.substring(0, char_count2))
..write(postpatch_text.substring(char_count2 + aDiff.text.length));
postpatch_text = postpatch_buffer.toString();
break;
case DIFF_EQUAL:
if (aDiff.text.length <= 2 * margin
&& !patch.diffs.isEmpty && 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 * margin) {
// Time for a new patch.
if (!patch.diffs.isEmpty) {
patchAddContext(patch, prepatch_text, margin);
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 != DIFF_INSERT) {
char_count1 += aDiff.text.length;
}
if (aDiff.operation != DIFF_DELETE) {
char_count2 += aDiff.text.length;
}
}
// Pick up the leftover patch if not empty.
if (!patch.diffs.isEmpty) {
patchAddContext(patch, prepatch_text, margin);
patches.add(patch);
}
return patches;
}