patch_apply method

Pair<String, Map<int, bool>> patch_apply(
  1. List<Patch> patches,
  2. String text
)

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);
}