golang.org/x/tools/gopls@v0.15.3/internal/server/rename.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package server
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"path/filepath"
    11  
    12  	"golang.org/x/tools/gopls/internal/file"
    13  	"golang.org/x/tools/gopls/internal/golang"
    14  	"golang.org/x/tools/gopls/internal/protocol"
    15  	"golang.org/x/tools/internal/event"
    16  	"golang.org/x/tools/internal/event/tag"
    17  )
    18  
    19  func (s *server) Rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) {
    20  	ctx, done := event.Start(ctx, "lsp.Server.rename", tag.URI.Of(params.TextDocument.URI))
    21  	defer done()
    22  
    23  	fh, snapshot, release, err := s.fileOf(ctx, params.TextDocument.URI)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	defer release()
    28  
    29  	if kind := snapshot.FileKind(fh); kind != file.Go {
    30  		return nil, fmt.Errorf("cannot rename in file of type %s", kind)
    31  	}
    32  
    33  	// Because we don't handle directory renaming within golang.Rename, golang.Rename returns
    34  	// boolean value isPkgRenaming to determine whether an DocumentChanges of type RenameFile should
    35  	// be added to the return protocol.WorkspaceEdit value.
    36  	edits, isPkgRenaming, err := golang.Rename(ctx, snapshot, fh, params.Position, params.NewName)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	docChanges := []protocol.DocumentChanges{} // must be a slice
    42  	for uri, e := range edits {
    43  		fh, err := snapshot.ReadFile(ctx, uri)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  		docChanges = append(docChanges, documentChanges(fh, e)...)
    48  	}
    49  	if isPkgRenaming {
    50  		// Update the last component of the file's enclosing directory.
    51  		oldBase := filepath.Dir(fh.URI().Path())
    52  		newURI := filepath.Join(filepath.Dir(oldBase), params.NewName)
    53  		docChanges = append(docChanges, protocol.DocumentChanges{
    54  			RenameFile: &protocol.RenameFile{
    55  				Kind:   "rename",
    56  				OldURI: protocol.URIFromPath(oldBase),
    57  				NewURI: protocol.URIFromPath(newURI),
    58  			},
    59  		})
    60  	}
    61  	return &protocol.WorkspaceEdit{
    62  		DocumentChanges: docChanges,
    63  	}, nil
    64  }
    65  
    66  // PrepareRename implements the textDocument/prepareRename handler. It may
    67  // return (nil, nil) if there is no rename at the cursor position, but it is
    68  // not desirable to display an error to the user.
    69  //
    70  // TODO(rfindley): why wouldn't we want to show an error to the user, if the
    71  // user initiated a rename request at the cursor?
    72  func (s *server) PrepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.PrepareRenamePlaceholder, error) {
    73  	ctx, done := event.Start(ctx, "lsp.Server.prepareRename", tag.URI.Of(params.TextDocument.URI))
    74  	defer done()
    75  
    76  	fh, snapshot, release, err := s.fileOf(ctx, params.TextDocument.URI)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	defer release()
    81  
    82  	if kind := snapshot.FileKind(fh); kind != file.Go {
    83  		return nil, fmt.Errorf("cannot rename in file of type %s", kind)
    84  	}
    85  
    86  	// Do not return errors here, as it adds clutter.
    87  	// Returning a nil result means there is not a valid rename.
    88  	item, usererr, err := golang.PrepareRename(ctx, snapshot, fh, params.Position)
    89  	if err != nil {
    90  		// Return usererr here rather than err, to avoid cluttering the UI with
    91  		// internal error details.
    92  		return nil, usererr
    93  	}
    94  	return &protocol.PrepareRenamePlaceholder{
    95  		Range:       item.Range,
    96  		Placeholder: item.Text,
    97  	}, nil
    98  }