1
0
mirror of https://github.com/golang/go synced 2024-09-30 20:28:32 -06:00

internal/lsp: clean up ApplyEdits

This should be a faster but equivalent implementation.

Change-Id: I7bc756644c601b953ba7715e093bfa10ca5ea97b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/198878
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-10-03 14:44:07 -04:00
parent 5bee6a6eb8
commit c9f9432ec4

View File

@ -6,8 +6,8 @@
package diff package diff
import ( import (
"bytes"
"sort" "sort"
"strings"
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
) )
@ -41,44 +41,33 @@ func ApplyEdits(before string, edits []TextEdit) string {
// Preconditions: // Preconditions:
// - all of the edits apply to before // - all of the edits apply to before
// - and all the spans for each TextEdit have the same URI // - and all the spans for each TextEdit have the same URI
if len(edits) == 0 {
// copy edits so we don't make a mess of the caller's slice return before
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
} }
edits = prepareEdits(edits)
// sort the copy c := span.NewContentConverter("", []byte(before))
sort.Slice(edits, func(i, j int) bool { return offset(edits[i].Span.Start()) < offset(edits[j].Span.Start()) }) after := strings.Builder{}
last := 0
var after bytes.Buffer
beforeOffset := 0
for _, edit := range edits { for _, edit := range edits {
if offset(edit.Span.Start()) < beforeOffset { spn, _ := edit.Span.WithAll(c)
panic("overlapping edits") // TODO(matloob): ApplyEdits doesn't return an error. What do we do? start := spn.Start().Offset()
} else if offset(edit.Span.Start()) > beforeOffset { if start > last {
after.WriteString(before[beforeOffset:offset(edit.Span.Start())]) after.WriteString(before[last:start])
beforeOffset = offset(edit.Span.Start()) last = start
} }
// offset(edit.Span.Start) is now equal to beforeOffset
after.WriteString(edit.NewText) after.WriteString(edit.NewText)
beforeOffset += offset(edit.Span.End()) - offset(edit.Span.Start()) last = spn.End().Offset()
} }
if beforeOffset < len(before) { if last < len(before) {
after.WriteString(before[beforeOffset:]) after.WriteString(before[last:])
beforeOffset = len(before[beforeOffset:]) // just to preserve invariants
} }
return after.String() return after.String()
} }
// prepareEdits returns a sorted copy of the edits
func prepareEdits(edits []TextEdit) []TextEdit {
copied := make([]TextEdit, len(edits))
copy(copied, edits)
SortTextEdits(copied)
return copied
}