| // Copyright 2025 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package diff | |
| import ( | |
| "slices" | |
| ) | |
| // Merge merges two valid, ordered lists of edits. | |
| // It returns zero if there was a conflict. | |
| // | |
| // If corresponding edits in x and y are identical, | |
| // they are coalesced in the result. | |
| // | |
| // If x and y both provide different insertions at the same point, | |
| // the insertions from x will be first in the result. | |
| // | |
| // TODO(adonovan): this algorithm could be improved, for example by | |
| // working harder to coalesce non-identical edits that share a common | |
| // deletion or common prefix of insertion (see the tests). | |
| // Survey the academic literature for insights. | |
| func Merge(x, y []Edit) ([]Edit, bool) { | |
| // Make a defensive (premature) copy of the arrays. | |
| x = slices.Clone(x) | |
| y = slices.Clone(y) | |
| var merged []Edit | |
| add := func(edit Edit) { | |
| merged = append(merged, edit) | |
| } | |
| var xi, yi int | |
| for xi < len(x) && yi < len(y) { | |
| px := &x[xi] | |
| py := &y[yi] | |
| if *px == *py { | |
| // x and y are identical: coalesce. | |
| add(*px) | |
| xi++ | |
| yi++ | |
| } else if px.End <= py.Start { | |
| // x is entirely before y, | |
| // or an insertion at start of y. | |
| add(*px) | |
| xi++ | |
| } else if py.End <= px.Start { | |
| // y is entirely before x, | |
| // or an insertion at start of x. | |
| add(*py) | |
| yi++ | |
| } else if px.Start < py.Start { | |
| // x is partly before y: | |
| // split it into a deletion and an edit. | |
| add(Edit{px.Start, py.Start, ""}) | |
| px.Start = py.Start | |
| } else if py.Start < px.Start { | |
| // y is partly before x: | |
| // split it into a deletion and an edit. | |
| add(Edit{py.Start, px.Start, ""}) | |
| py.Start = px.Start | |
| } else { | |
| // x and y are unequal non-insertions | |
| // at the same point: conflict. | |
| return nil, false | |
| } | |
| } | |
| for ; xi < len(x); xi++ { | |
| add(x[xi]) | |
| } | |
| for ; yi < len(y); yi++ { | |
| add(y[yi]) | |
| } | |
| return merged, true | |
| } |