1
0
mirror of https://github.com/golang/go synced 2024-10-01 09:28:37 -06:00
go/internal/lsp/diff/apply_edits.go
Michael Matloob 27d1b4e4f3 internal/lsp/diff: rewrite ApplyEdits to work with sub-line diffs
This replaces the definition of ApplyEdits to be more like that in
go vet -fix, so that we can apply the results of suggested fixes.

Change-Id: Ib5724139464954e3790bc51ed1edc3ce4b2115ff
Reviewed-on: https://go-review.googlesource.com/c/tools/+/193959
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
2019-09-09 18:07:23 +00:00

59 lines
1.6 KiB
Go

package diff
import (
"bytes"
"sort"
"golang.org/x/tools/internal/span"
)
func init() {
ApplyEdits = applyEdits
}
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()
}