internal/lsp: Check if user's editor support rename operation

Change-Id: Iadda768e93eda1d53fa00a5ff8a28013a575ef57
Reviewed-on: https://go-review.googlesource.com/c/tools/+/419774
Run-TryBot: Dylan Le <dungtuanle@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Dylan Le 2022-07-21 15:23:17 -04:00
Родитель f560bc877f
Коммит 9580c84d57
4 изменённых файлов: 77 добавлений и 10 удалений

Просмотреть файл

@ -8,9 +8,49 @@ import (
"strings"
"testing"
"golang.org/x/tools/internal/lsp/protocol"
. "golang.org/x/tools/internal/lsp/regtest"
)
func TestPrepareRenamePackage(t *testing.T) {
const files = `
-- go.mod --
module mod.com
go 1.18
-- main.go --
package main
import (
"fmt"
)
func main() {
fmt.Println(1)
}
`
const wantErr = "can't rename packages: LSP client does not support file renaming"
Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("main.go")
pos := env.RegexpSearch("main.go", `main`)
tdpp := protocol.TextDocumentPositionParams{
TextDocument: env.Editor.TextDocumentIdentifier("main.go"),
Position: pos.ToProtocolPosition(),
}
params := &protocol.PrepareRenameParams{
TextDocumentPositionParams: tdpp,
}
_, err := env.Editor.Server.PrepareRename(env.Ctx, params)
if err == nil {
t.Errorf("missing can't rename package error from PrepareRename")
}
if err.Error() != wantErr {
t.Errorf("got %v, want %v", err.Error(), wantErr)
}
})
}
// Test for golang/go#47564.
func TestRenameInTestVariant(t *testing.T) {
const files = `

Просмотреть файл

@ -428,7 +428,7 @@ func (e *Editor) CloseBuffer(ctx context.Context, path string) error {
if e.Server != nil {
if err := e.Server.DidClose(ctx, &protocol.DidCloseTextDocumentParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
}); err != nil {
return fmt.Errorf("DidClose: %w", err)
}
@ -439,7 +439,7 @@ func (e *Editor) CloseBuffer(ctx context.Context, path string) error {
return nil
}
func (e *Editor) textDocumentIdentifier(path string) protocol.TextDocumentIdentifier {
func (e *Editor) TextDocumentIdentifier(path string) protocol.TextDocumentIdentifier {
return protocol.TextDocumentIdentifier{
URI: e.sandbox.Workdir.URI(path),
}
@ -471,7 +471,7 @@ func (e *Editor) SaveBufferWithoutActions(ctx context.Context, path string) erro
includeText = syncOptions.Save.IncludeText
}
docID := e.textDocumentIdentifier(buf.path)
docID := e.TextDocumentIdentifier(buf.path)
if e.Server != nil {
if err := e.Server.WillSave(ctx, &protocol.WillSaveTextDocumentParams{
TextDocument: docID,
@ -693,7 +693,7 @@ func (e *Editor) setBufferContentLocked(ctx context.Context, path string, dirty
params := &protocol.DidChangeTextDocumentParams{
TextDocument: protocol.VersionedTextDocumentIdentifier{
Version: int32(buf.version),
TextDocumentIdentifier: e.textDocumentIdentifier(buf.path),
TextDocumentIdentifier: e.TextDocumentIdentifier(buf.path),
},
ContentChanges: evts,
}
@ -1008,7 +1008,7 @@ func (e *Editor) CodeLens(ctx context.Context, path string) ([]protocol.CodeLens
return nil, fmt.Errorf("buffer %q is not open", path)
}
params := &protocol.CodeLensParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
}
lens, err := e.Server.CodeLens(ctx, params)
if err != nil {
@ -1030,7 +1030,7 @@ func (e *Editor) Completion(ctx context.Context, path string, pos Pos) (*protoco
}
params := &protocol.CompletionParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
Position: pos.ToProtocolPosition(),
},
}
@ -1080,7 +1080,7 @@ func (e *Editor) InlayHint(ctx context.Context, path string) ([]protocol.InlayHi
return nil, fmt.Errorf("buffer %q is not open", path)
}
params := &protocol.InlayHintParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
}
hints, err := e.Server.InlayHint(ctx, params)
if err != nil {
@ -1102,7 +1102,7 @@ func (e *Editor) References(ctx context.Context, path string, pos Pos) ([]protoc
}
params := &protocol.ReferenceParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
Position: pos.ToProtocolPosition(),
},
Context: protocol.ReferenceContext{
@ -1121,7 +1121,7 @@ func (e *Editor) Rename(ctx context.Context, path string, pos Pos, newName strin
return nil
}
params := &protocol.RenameParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
Position: pos.ToProtocolPosition(),
NewName: newName,
}
@ -1195,7 +1195,7 @@ func (e *Editor) CodeAction(ctx context.Context, path string, rng *protocol.Rang
return nil, fmt.Errorf("buffer %q is not open", path)
}
params := &protocol.CodeActionParams{
TextDocument: e.textDocumentIdentifier(path),
TextDocument: e.TextDocumentIdentifier(path),
Context: protocol.CodeActionContext{
Diagnostics: diagnostics,
},

Просмотреть файл

@ -204,6 +204,7 @@ type ClientOptions struct {
RelatedInformationSupported bool
CompletionTags bool
CompletionDeprecated bool
SupportedResourceOperations []protocol.ResourceOperationKind
}
// ServerOptions holds LSP-specific configuration that is provided by the
@ -701,6 +702,9 @@ func SetOptions(options *Options, opts interface{}) OptionResults {
func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) {
// Check if the client supports snippets in completion items.
if caps.Workspace.WorkspaceEdit != nil {
o.SupportedResourceOperations = caps.Workspace.WorkspaceEdit.ResourceOperations
}
if c := caps.TextDocument.Completion; c.CompletionItem.SnippetSupport {
o.InsertTextFormat = protocol.SnippetTextFormat
}

Просмотреть файл

@ -49,6 +49,29 @@ type PrepareItem struct {
// the prepare fails. Probably we could eliminate the redundancy in returning
// two errors, but for now this is done defensively.
func PrepareRename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position) (_ *PrepareItem, usererr, err error) {
fileRenameSupported := false
for _, op := range snapshot.View().Options().SupportedResourceOperations {
if op == protocol.Rename {
fileRenameSupported = true
break
}
}
// Find position of the package name declaration
pgf, err := snapshot.ParseGo(ctx, f, ParseFull)
if err != nil {
return nil, err, err
}
inPackageName, err := isInPackageName(ctx, snapshot, f, pgf, pp)
if err != nil {
return nil, err, err
}
if inPackageName && !fileRenameSupported {
err := errors.New("can't rename packages: LSP client does not support file renaming")
return nil, err, err
}
ctx, done := event.Start(ctx, "source.PrepareRename")
defer done()