mirror of
https://github.com/golang/go
synced 2024-11-06 00:26:11 -07:00
5bee6a6eb8
Make sure everything is documented and move things to sensible files now all the cross package shuffling is done Change-Id: I884053a207d6741cda066afa5da91b00f1dfd31c Reviewed-on: https://go-review.googlesource.com/c/tools/+/198877 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
85 lines
2.7 KiB
Go
85 lines
2.7 KiB
Go
// Copyright 2019 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 supports a pluggable diff algorithm.
|
|
package diff
|
|
|
|
import (
|
|
"bytes"
|
|
"sort"
|
|
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
// TextEdit represents a change to a section of a document.
|
|
// The text within the specified span should be replaced by the supplied new text.
|
|
type TextEdit struct {
|
|
Span span.Span
|
|
NewText string
|
|
}
|
|
|
|
// ComputeEdits is the type for a function that produces a set of edits that
|
|
// convert from the before content to the after content.
|
|
type ComputeEdits func(uri span.URI, before, after string) []TextEdit
|
|
|
|
// SortTextEdits attempts to order all edits by their starting points.
|
|
// The sort is stable so that edits with the same starting point will not
|
|
// be reordered.
|
|
func SortTextEdits(d []TextEdit) {
|
|
// Use a stable sort to maintain the order of edits inserted at the same position.
|
|
sort.SliceStable(d, func(i int, j int) bool {
|
|
return span.Compare(d[i].Span, d[j].Span) < 0
|
|
})
|
|
}
|
|
|
|
// ApplyEdits applies the set of edits to the before and returns the resulting
|
|
// content.
|
|
// It may panic or produce garbage if the edits are not valid for the provided
|
|
// before content.
|
|
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()
|
|
}
|