Skip to content

Commit

Permalink
gopls/internal/lsp/source: move edit logic into the protocol package
Browse files Browse the repository at this point in the history
Change-Id: I8a2dcafc109bf298b6edfe7a7029f8b9098880d6
Reviewed-on: https://go-review.googlesource.com/c/tools/+/543920
Reviewed-by: Alan Donovan <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Auto-Submit: Robert Findley <[email protected]>
  • Loading branch information
findleyr authored and gopherbot committed Nov 20, 2023
1 parent 3c677e3 commit 53ad329
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 75 deletions.
3 changes: 1 addition & 2 deletions gopls/internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"golang.org/x/tools/gopls/internal/lsp/filecache"
"golang.org/x/tools/gopls/internal/lsp/lsprpc"
"golang.org/x/tools/gopls/internal/lsp/protocol"
"golang.org/x/tools/gopls/internal/lsp/source"
"golang.org/x/tools/gopls/internal/settings"
"golang.org/x/tools/internal/constraints"
"golang.org/x/tools/internal/diff"
Expand Down Expand Up @@ -585,7 +584,7 @@ func applyTextEdits(mapper *protocol.Mapper, edits []protocol.TextEdit, flags *E
if len(edits) == 0 {
return nil
}
newContent, renameEdits, err := source.ApplyProtocolEdits(mapper, edits)
newContent, renameEdits, err := protocol.ApplyEdits(mapper, edits)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/cache/mod_tidy.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ func switchDirectness(req *modfile.Require, m *protocol.Mapper, computeEdits set
}
// Calculate the edits to be made due to the change.
edits := computeEdits(string(m.Content), string(newContent))
return ToProtocolEdits(m, edits)
return protocol.EditsFromDiffEdits(m, edits)
}

// missingModuleForImport creates an error for a given import path that comes
Expand Down
1 change: 0 additions & 1 deletion gopls/internal/lsp/cache/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ var (
RemoveIntermediateTestVariants = source.RemoveIntermediateTestVariants
IsCommandLineArguments = source.IsCommandLineArguments
BundleQuickFixes = source.BundleQuickFixes
ToProtocolEdits = source.ToProtocolEdits
NewFilterer = source.NewFilterer
)

Expand Down
4 changes: 2 additions & 2 deletions gopls/internal/lsp/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ func dropDependency(snapshot source.Snapshot, pm *source.ParsedModule, modulePat
}
// Calculate the edits to be made due to the change.
diff := snapshot.Options().ComputeEdits(string(pm.Mapper.Content), string(newContent))
return source.ToProtocolEdits(pm.Mapper, diff)
return protocol.EditsFromDiffEdits(pm.Mapper, diff)
}

func (c *commandHandler) Test(ctx context.Context, uri protocol.DocumentURI, tests, benchmarks []string) error {
Expand Down Expand Up @@ -677,7 +677,7 @@ func collectFileEdits(ctx context.Context, snapshot *cache.Snapshot, uri protoco

m := protocol.NewMapper(fh.URI(), oldContent)
diff := snapshot.Options().ComputeEdits(string(oldContent), string(newContent))
edits, err := source.ToProtocolEdits(m, diff)
edits, err := protocol.EditsFromDiffEdits(m, diff)
if err != nil {
return nil, err
}
Expand Down
3 changes: 1 addition & 2 deletions gopls/internal/lsp/fake/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package fake

import (
"golang.org/x/tools/gopls/internal/lsp/protocol"
"golang.org/x/tools/gopls/internal/lsp/source"
"golang.org/x/tools/internal/diff"
)

Expand Down Expand Up @@ -36,7 +35,7 @@ func EditToChangeEvent(e protocol.TextEdit) protocol.TextDocumentContentChangeEv
// and returns a new slice containing the lines of the patched file.
// It is a wrapper around diff.Apply; see that function for preconditions.
func applyEdits(mapper *protocol.Mapper, edits []protocol.TextEdit, windowsLineEndings bool) ([]byte, error) {
diffEdits, err := source.FromProtocolEdits(mapper, edits)
diffEdits, err := protocol.EditsToDiffEdits(mapper, edits)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/mod/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ func Format(ctx context.Context, snapshot source.Snapshot, fh file.Handle) ([]pr
}
// Calculate the edits to be made due to the change.
diffs := snapshot.Options().ComputeEdits(string(pm.Mapper.Content), string(formatted))
return source.ToProtocolEdits(pm.Mapper, diffs)
return protocol.EditsFromDiffEdits(pm.Mapper, diffs)
}
62 changes: 62 additions & 0 deletions gopls/internal/lsp/protocol/edits.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2023 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 protocol

import "golang.org/x/tools/internal/diff"

// EditsFromDiffEdits converts diff.Edits to a non-nil slice of LSP TextEdits.
// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray
func EditsFromDiffEdits(m *Mapper, edits []diff.Edit) ([]TextEdit, error) {
// LSP doesn't require TextEditArray to be sorted:
// this is the receiver's concern. But govim, and perhaps
// other clients have historically relied on the order.
edits = append([]diff.Edit(nil), edits...)
diff.SortEdits(edits)

result := make([]TextEdit, len(edits))
for i, edit := range edits {
rng, err := m.OffsetRange(edit.Start, edit.End)
if err != nil {
return nil, err
}
result[i] = TextEdit{
Range: rng,
NewText: edit.New,
}
}
return result, nil
}

// EditsToDiffEdits converts LSP TextEdits to diff.Edits.
// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray
func EditsToDiffEdits(m *Mapper, edits []TextEdit) ([]diff.Edit, error) {
if edits == nil {
return nil, nil
}
result := make([]diff.Edit, len(edits))
for i, edit := range edits {
start, end, err := m.RangeOffsets(edit.Range)
if err != nil {
return nil, err
}
result[i] = diff.Edit{
Start: start,
End: end,
New: edit.NewText,
}
}
return result, nil
}

// ApplyEdits applies the patch (edits) to m.Content and returns the result.
// It also returns the edits converted to diff-package form.
func ApplyEdits(m *Mapper, edits []TextEdit) ([]byte, []diff.Edit, error) {
diffEdits, err := EditsToDiffEdits(m, edits)
if err != nil {
return nil, nil, err
}
out, err := diff.ApplyBytes(m.Content, diffEdits)
return out, diffEdits, err
}
13 changes: 5 additions & 8 deletions gopls/internal/lsp/regtest/marker.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
"golang.org/x/tools/gopls/internal/lsp/lsprpc"
"golang.org/x/tools/gopls/internal/lsp/protocol"
"golang.org/x/tools/gopls/internal/lsp/safetoken"
"golang.org/x/tools/gopls/internal/lsp/source"
"golang.org/x/tools/gopls/internal/lsp/tests"
"golang.org/x/tools/gopls/internal/lsp/tests/compare"
"golang.org/x/tools/internal/diff"
Expand Down Expand Up @@ -1675,9 +1674,7 @@ func acceptCompletionMarker(mark marker, src protocol.Location, label string, go
}
filename := mark.path()
mapper := mark.mapper()
patched, _, err := source.ApplyProtocolEdits(mapper, append([]protocol.TextEdit{
*selected.TextEdit,
}, selected.AdditionalTextEdits...))
patched, _, err := protocol.ApplyEdits(mapper, append([]protocol.TextEdit{*selected.TextEdit}, selected.AdditionalTextEdits...))

if err != nil {
mark.errorf("ApplyProtocolEdits failed: %v", err)
Expand Down Expand Up @@ -1739,7 +1736,7 @@ func foldingRangeMarker(mark marker, g *Golden) {
mark.errorf("Editor.Mapper(%s) failed: %v", filename, err)
return
}
got, _, err := source.ApplyProtocolEdits(mapper, edits)
got, _, err := protocol.ApplyEdits(mapper, edits)
if err != nil {
mark.errorf("ApplyProtocolEdits failed: %v", err)
return
Expand All @@ -1766,7 +1763,7 @@ func formatMarker(mark marker, golden *Golden) {
mark.errorf("Editor.Mapper(%s) failed: %v", filename, err)
}

got, _, err = source.ApplyProtocolEdits(mapper, edits)
got, _, err = protocol.ApplyEdits(mapper, edits)
if err != nil {
mark.errorf("ApplyProtocolEdits failed: %v", err)
return
Expand Down Expand Up @@ -2008,7 +2005,7 @@ func applyDocumentChanges(env *Env, changes []protocol.DocumentChanges, fileChan
if err != nil {
return err
}
patched, _, err := source.ApplyProtocolEdits(mapper, change.TextDocumentEdit.Edits)
patched, _, err := protocol.ApplyEdits(mapper, change.TextDocumentEdit.Edits)
if err != nil {
return err
}
Expand Down Expand Up @@ -2400,7 +2397,7 @@ func inlayhintsMarker(mark marker, g *Golden) {
}

m := mark.mapper()
got, _, err := source.ApplyProtocolEdits(m, edits)
got, _, err := protocol.ApplyEdits(m, edits)
if err != nil {
mark.errorf("ApplyProtocolEdits: %v", err)
return
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/source/change_quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func ConvertStringLiteral(pgf *ParsedGoFile, fh file.Handle, rng protocol.Range)
End: end,
New: newText,
}}
pedits, err := ToProtocolEdits(pgf.Mapper, edits)
pedits, err := protocol.EditsFromDiffEdits(pgf.Mapper, edits)
if err != nil {
bug.Reportf("failed to convert diff.Edit to protocol.TextEdit:%v", err)
return protocol.CodeAction{}, false
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/source/change_signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func RemoveUnusedParameter(ctx context.Context, fh file.Handle, rng protocol.Ran
}
edits := diff.Bytes(before, after)
mapper := protocol.NewMapper(uri, before)
pedits, err := ToProtocolEdits(mapper, edits)
pedits, err := protocol.EditsFromDiffEdits(mapper, edits)
if err != nil {
return nil, fmt.Errorf("computing edits for %s: %v", uri, err)
}
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/source/completion/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func (c *completer) editText(from, to token.Pos, newText string) ([]protocol.Tex
if err != nil {
return nil, err // can't happen: from/to came from c
}
return source.ToProtocolEdits(c.mapper, []diff.Edit{{
return protocol.EditsFromDiffEdits(c.mapper, []diff.Edit{{
Start: start,
End: end,
New: newText,
Expand Down
55 changes: 2 additions & 53 deletions gopls/internal/lsp/source/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func computeTextEdits(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile,
defer done()

edits := snapshot.Options().ComputeEdits(string(pgf.Src), formatted)
return ToProtocolEdits(pgf.Mapper, edits)
return protocol.EditsFromDiffEdits(pgf.Mapper, edits)
}

// protocolEditsFromSource converts text edits to LSP edits using the original
Expand All @@ -333,57 +333,6 @@ func protocolEditsFromSource(src []byte, edits []diff.Edit) ([]protocol.TextEdit
return result, nil
}

// ToProtocolEdits converts diff.Edits to a non-nil slice of LSP TextEdits.
// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray
func ToProtocolEdits(m *protocol.Mapper, edits []diff.Edit) ([]protocol.TextEdit, error) {
// LSP doesn't require TextEditArray to be sorted:
// this is the receiver's concern. But govim, and perhaps
// other clients have historically relied on the order.
edits = append([]diff.Edit(nil), edits...)
diff.SortEdits(edits)

result := make([]protocol.TextEdit, len(edits))
for i, edit := range edits {
rng, err := m.OffsetRange(edit.Start, edit.End)
if err != nil {
return nil, err
}
result[i] = protocol.TextEdit{
Range: rng,
NewText: edit.New,
}
}
return result, nil
}

// FromProtocolEdits converts LSP TextEdits to diff.Edits.
// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray
func FromProtocolEdits(m *protocol.Mapper, edits []protocol.TextEdit) ([]diff.Edit, error) {
if edits == nil {
return nil, nil
}
result := make([]diff.Edit, len(edits))
for i, edit := range edits {
start, end, err := m.RangeOffsets(edit.Range)
if err != nil {
return nil, err
}
result[i] = diff.Edit{
Start: start,
End: end,
New: edit.NewText,
}
}
return result, nil
}

// ApplyProtocolEdits applies the patch (edits) to m.Content and returns the result.
// It also returns the edits converted to diff-package form.
func ApplyProtocolEdits(m *protocol.Mapper, edits []protocol.TextEdit) ([]byte, []diff.Edit, error) {
diffEdits, err := FromProtocolEdits(m, edits)
if err != nil {
return nil, nil, err
}
out, err := diff.ApplyBytes(m.Content, diffEdits)
return out, diffEdits, err
return protocol.EditsFromDiffEdits(m, edits)
}
2 changes: 1 addition & 1 deletion gopls/internal/lsp/source/rename.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ func Rename(ctx context.Context, snapshot Snapshot, f file.Handle, pp protocol.P
return nil, false, err
}
m := protocol.NewMapper(uri, data)
protocolEdits, err := ToProtocolEdits(m, edits)
protocolEdits, err := protocol.EditsFromDiffEdits(m, edits)
if err != nil {
return nil, false, err
}
Expand Down
2 changes: 1 addition & 1 deletion gopls/internal/lsp/work/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ func Format(ctx context.Context, snapshot source.Snapshot, fh file.Handle) ([]pr
formatted := modfile.Format(pw.File.Syntax)
// Calculate the edits to be made due to the change.
diffs := snapshot.Options().ComputeEdits(string(pw.Mapper.Content), string(formatted))
return source.ToProtocolEdits(pw.Mapper, diffs)
return protocol.EditsFromDiffEdits(pw.Mapper, diffs)
}

0 comments on commit 53ad329

Please sign in to comment.