diff options
Diffstat (limited to 'gopls/internal/lsp/rename.go')
-rw-r--r-- | gopls/internal/lsp/rename.go | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/gopls/internal/lsp/rename.go b/gopls/internal/lsp/rename.go new file mode 100644 index 000000000..7111e92dc --- /dev/null +++ b/gopls/internal/lsp/rename.go @@ -0,0 +1,78 @@ +// 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 lsp + +import ( + "context" + "path/filepath" + + "golang.org/x/tools/gopls/internal/lsp/protocol" + "golang.org/x/tools/gopls/internal/lsp/source" +) + +func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) { + snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) + defer release() + if !ok { + return nil, err + } + // Because we don't handle directory renaming within source.Rename, source.Rename returns + // boolean value isPkgRenaming to determine whether an DocumentChanges of type RenameFile should + // be added to the return protocol.WorkspaceEdit value. + edits, isPkgRenaming, err := source.Rename(ctx, snapshot, fh, params.Position, params.NewName) + if err != nil { + return nil, err + } + + var docChanges []protocol.DocumentChanges + for uri, e := range edits { + fh, err := snapshot.GetFile(ctx, uri) + if err != nil { + return nil, err + } + docChanges = append(docChanges, documentChanges(fh, e)...) + } + if isPkgRenaming { + // Update the last component of the file's enclosing directory. + oldBase := filepath.Dir(fh.URI().Filename()) + newURI := filepath.Join(filepath.Dir(oldBase), params.NewName) + docChanges = append(docChanges, protocol.DocumentChanges{ + RenameFile: &protocol.RenameFile{ + Kind: "rename", + OldURI: protocol.URIFromPath(oldBase), + NewURI: protocol.URIFromPath(newURI), + }, + }) + } + return &protocol.WorkspaceEdit{ + DocumentChanges: docChanges, + }, nil +} + +// prepareRename implements the textDocument/prepareRename handler. It may +// return (nil, nil) if there is no rename at the cursor position, but it is +// not desirable to display an error to the user. +// +// TODO(rfindley): why wouldn't we want to show an error to the user, if the +// user initiated a rename request at the cursor? +func (s *Server) prepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.PrepareRename2Gn, error) { + snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go) + defer release() + if !ok { + return nil, err + } + // Do not return errors here, as it adds clutter. + // Returning a nil result means there is not a valid rename. + item, usererr, err := source.PrepareRename(ctx, snapshot, fh, params.Position) + if err != nil { + // Return usererr here rather than err, to avoid cluttering the UI with + // internal error details. + return nil, usererr + } + return &protocol.PrepareRename2Gn{ + Range: item.Range, + Placeholder: item.Text, + }, nil +} |