1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:04:44 -07:00
go/internal/lsp/diff/apply_edits.go
Ian Cottrell f7bb6f12f0 internal/lsp: do not allow diff.ApplyEdits to be replaced
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>
2019-10-04 02:16:33 +00:00

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