diff_cleanupMerge method

void diff_cleanupMerge(
  1. List<Diff> diffs
)

Reorder and merge like edit sections. Merge equalities. Any edit section can move as long as it doesn't cross an equality. diffs is a List of Diff objects.

Implementation

void diff_cleanupMerge(List<Diff> diffs) {
  diffs.add(Diff(Operation.equal, '')); // Add a dummy entry at the end.
  int pointer = 0;
  int count_delete = 0;
  int count_insert = 0;
  String text_delete = '';
  String text_insert = '';
  int commonlength;
  while (pointer < diffs.length) {
    switch (diffs[pointer].operation) {
      case Operation.insert:
        count_insert++;
        text_insert += diffs[pointer].text;
        pointer++;
        break;
      case Operation.delete:
        count_delete++;
        text_delete += diffs[pointer].text;
        pointer++;
        break;
      case Operation.equal:
        // Upon reaching an equality, check for prior redundancies.
        if (count_delete + count_insert > 1) {
          if (count_delete != 0 && count_insert != 0) {
            // Factor out any common prefixies.
            commonlength = diff_commonPrefix(text_insert, text_delete);
            if (commonlength != 0) {
              if ((pointer - count_delete - count_insert) > 0 &&
                  diffs[pointer - count_delete - count_insert - 1]
                          .operation ==
                      Operation.equal) {
                final i = pointer - count_delete - count_insert - 1;
                diffs[i].text =
                    diffs[i].text + text_insert.substring(0, commonlength);
              } else {
                diffs.insert(
                    0,
                    Diff(Operation.equal,
                        text_insert.substring(0, commonlength)));
                pointer++;
              }
              text_insert = text_insert.substring(commonlength);
              text_delete = text_delete.substring(commonlength);
            }

            // Factor out any common suffixies.
            commonlength = diff_commonSuffix(text_insert, text_delete);
            if (commonlength != 0) {
              diffs[pointer].text =
                  text_insert.substring(text_insert.length - commonlength) +
                      diffs[pointer].text;
              text_insert =
                  text_insert.substring(0, text_insert.length - commonlength);
              text_delete =
                  text_delete.substring(0, text_delete.length - commonlength);
            }
          }
          // Delete the offending records and add the merged ones.
          pointer -= count_delete + count_insert;
          diffs.removeRange(pointer, pointer + count_delete + count_insert);
          if (text_delete.isNotEmpty) {
            diffs.insert(pointer, Diff(Operation.delete, text_delete));
            pointer++;
          }
          if (text_insert.isNotEmpty) {
            diffs.insert(pointer, Diff(Operation.insert, text_insert));
            pointer++;
          }
          pointer++;
        } else if (pointer != 0 &&
            diffs[pointer - 1].operation == Operation.equal) {
          // Merge this equality with the previous one.
          diffs[pointer - 1].text =
              diffs[pointer - 1].text + diffs[pointer].text;
          diffs.removeAt(pointer);
        } else {
          pointer++;
        }
        count_insert = 0;
        count_delete = 0;
        text_delete = '';
        text_insert = '';
        break;
    }
  }
  if (diffs.last.text.isEmpty) {
    diffs.removeLast(); // Remove the dummy entry at the end.
  }

  // Second pass: look for single edits surrounded on both sides by equalities
  // which can be shifted sideways to eliminate an equality.
  // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
  bool changes = false;
  pointer = 1;
  // Intentionally ignore the first and last element (don't need checking).
  while (pointer < diffs.length - 1) {
    if (diffs[pointer - 1].operation == Operation.equal &&
        diffs[pointer + 1].operation == Operation.equal) {
      // This is a single edit surrounded by equalities.
      if (diffs[pointer].text.endsWith(diffs[pointer - 1].text)) {
        // Shift the edit over the previous equality.
        diffs[pointer].text = diffs[pointer - 1].text +
            diffs[pointer].text.substring(0,
                diffs[pointer].text.length - diffs[pointer - 1].text.length);
        diffs[pointer + 1].text =
            diffs[pointer - 1].text + diffs[pointer + 1].text;
        diffs.removeAt(pointer - 1);
        changes = true;
      } else if (diffs[pointer].text.startsWith(diffs[pointer + 1].text)) {
        // Shift the edit over the next equality.
        diffs[pointer - 1].text =
            diffs[pointer - 1].text + diffs[pointer + 1].text;
        diffs[pointer].text =
            diffs[pointer].text.substring(diffs[pointer + 1].text.length) +
                diffs[pointer + 1].text;
        diffs.removeAt(pointer + 1);
        changes = true;
      }
    }
    pointer++;
  }
  // If shifts were made, the diff needs reordering and another shift sweep.
  if (changes) {
    diff_cleanupMerge(diffs);
  }
}