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>
diff --git a/internal/lsp/fake/editor.go b/internal/lsp/fake/editor.go
index 240e35c..a07e9e7 100644
--- a/internal/lsp/fake/editor.go
+++ b/internal/lsp/fake/editor.go
@@ -428,7 +428,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
params := &protocol.CompletionParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
- TextDocument: e.textDocumentIdentifier(path),
+ TextDocument: e.TextDocumentIdentifier(path),
Position: pos.ToProtocolPosition(),
},
}
@@ -1080,7 +1080,7 @@
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 @@
}
params := &protocol.ReferenceParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
- TextDocument: e.textDocumentIdentifier(path),
+ TextDocument: e.TextDocumentIdentifier(path),
Position: pos.ToProtocolPosition(),
},
Context: protocol.ReferenceContext{
@@ -1121,7 +1121,7 @@
return nil
}
params := &protocol.RenameParams{
- TextDocument: e.textDocumentIdentifier(path),
+ TextDocument: e.TextDocumentIdentifier(path),
Position: pos.ToProtocolPosition(),
NewName: newName,
}
@@ -1195,7 +1195,7 @@
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,
},
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 1bb135d..11ba157 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -204,6 +204,7 @@
RelatedInformationSupported bool
CompletionTags bool
CompletionDeprecated bool
+ SupportedResourceOperations []protocol.ResourceOperationKind
}
// ServerOptions holds LSP-specific configuration that is provided by the
@@ -701,6 +702,9 @@
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
}
diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go
index 503422a..b6f0e65 100644
--- a/internal/lsp/source/rename.go
+++ b/internal/lsp/source/rename.go
@@ -49,6 +49,29 @@
// 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()