mirror of
https://github.com/golang/go
synced 2024-11-18 16:04:44 -07:00
f7bb6f12f0
We only need one implementation of this, it must cope with all inputs, and it has no freedom in it's results, so it does not need to be pluggable. Change-Id: I6fec0c339eb288649a670fc3e2cb00c726467e20 Reviewed-on: https://go-review.googlesource.com/c/tools/+/198377 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
55 lines
1.5 KiB
Go
55 lines
1.5 KiB
Go
package diff
|
|
|
|
import (
|
|
"bytes"
|
|
"sort"
|
|
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
func ApplyEdits(before string, edits []TextEdit) string {
|
|
// Preconditions:
|
|
// - all of the edits apply to before
|
|
// - and all the spans for each TextEdit have the same URI
|
|
|
|
// copy edits so we don't make a mess of the caller's slice
|
|
s := make([]TextEdit, len(edits))
|
|
copy(s, edits)
|
|
edits = s
|
|
|
|
// TODO(matloob): Initialize the Converter Once?
|
|
var conv span.Converter = span.NewContentConverter("", []byte(before))
|
|
offset := func(point span.Point) int {
|
|
if point.HasOffset() {
|
|
return point.Offset()
|
|
}
|
|
offset, err := conv.ToOffset(point.Line(), point.Column())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return offset
|
|
}
|
|
|
|
// sort the copy
|
|
sort.Slice(edits, func(i, j int) bool { return offset(edits[i].Span.Start()) < offset(edits[j].Span.Start()) })
|
|
|
|
var after bytes.Buffer
|
|
beforeOffset := 0
|
|
for _, edit := range edits {
|
|
if offset(edit.Span.Start()) < beforeOffset {
|
|
panic("overlapping edits") // TODO(matloob): ApplyEdits doesn't return an error. What do we do?
|
|
} else if offset(edit.Span.Start()) > beforeOffset {
|
|
after.WriteString(before[beforeOffset:offset(edit.Span.Start())])
|
|
beforeOffset = offset(edit.Span.Start())
|
|
}
|
|
// offset(edit.Span.Start) is now equal to beforeOffset
|
|
after.WriteString(edit.NewText)
|
|
beforeOffset += offset(edit.Span.End()) - offset(edit.Span.Start())
|
|
}
|
|
if beforeOffset < len(before) {
|
|
after.WriteString(before[beforeOffset:])
|
|
beforeOffset = len(before[beforeOffset:]) // just to preserve invariants
|
|
}
|
|
return after.String()
|
|
}
|