mirror of
https://github.com/golang/go
synced 2024-11-19 01:44:40 -07:00
e33b02e766
This change adds support for returning versions along with file URIs, so that the client can know when to apply changes. The version is not yet propagated along to the internal/lsp/cache package, so this change will have no effect (VS Code ignores a version of 0 and still applies the changes). A few minor changes made in the rename code (to remove the view parameter). Some minor staticcheck fixes. Updates golang/go#35243 Change-Id: Icc26bd9d9e5703c699f555424b94034c97b01d6f Reviewed-on: https://go-review.googlesource.com/c/tools/+/206882 Run-TryBot: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
126 lines
3.4 KiB
Go
126 lines
3.4 KiB
Go
// 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 cmd
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
|
|
"golang.org/x/tools/internal/lsp/diff"
|
|
"golang.org/x/tools/internal/lsp/protocol"
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
"golang.org/x/tools/internal/span"
|
|
"golang.org/x/tools/internal/tool"
|
|
errors "golang.org/x/xerrors"
|
|
)
|
|
|
|
// rename implements the rename verb for gopls.
|
|
type rename struct {
|
|
Diff bool `flag:"d" help:"display diffs instead of rewriting files"`
|
|
Write bool `flag:"w" help:"write result to (source) file instead of stdout"`
|
|
|
|
app *Application
|
|
}
|
|
|
|
func (r *rename) Name() string { return "rename" }
|
|
func (r *rename) Usage() string { return "<position>" }
|
|
func (r *rename) ShortHelp() string { return "rename selected identifier" }
|
|
func (r *rename) DetailedHelp(f *flag.FlagSet) {
|
|
fmt.Fprint(f.Output(), `
|
|
Example:
|
|
|
|
$ # 1-based location (:line:column or :#position) of the thing to change
|
|
$ gopls rename helper/helper.go:8:6
|
|
$ gopls rename helper/helper.go:#53
|
|
|
|
gopls rename flags are:
|
|
`)
|
|
f.PrintDefaults()
|
|
}
|
|
|
|
// Run renames the specified identifier and either;
|
|
// - if -w is specified, updates the file(s) in place;
|
|
// - if -d is specified, prints out unified diffs of the changes; or
|
|
// - otherwise, prints the new versions to stdout.
|
|
func (r *rename) Run(ctx context.Context, args ...string) error {
|
|
if len(args) != 2 {
|
|
return tool.CommandLineErrorf("definition expects 2 arguments (position, new name)")
|
|
}
|
|
conn, err := r.app.connect(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.terminate(ctx)
|
|
|
|
from := span.Parse(args[0])
|
|
file := conn.AddFile(ctx, from.URI())
|
|
if file.err != nil {
|
|
return file.err
|
|
}
|
|
loc, err := file.mapper.Location(from)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p := protocol.RenameParams{
|
|
TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
|
|
Position: loc.Range.Start,
|
|
NewName: args[1],
|
|
}
|
|
edit, err := conn.Rename(ctx, &p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var orderedURIs []string
|
|
edits := map[span.URI][]protocol.TextEdit{}
|
|
for _, c := range edit.DocumentChanges {
|
|
uri := span.URI(c.TextDocument.URI)
|
|
edits[uri] = append(edits[uri], c.Edits...)
|
|
orderedURIs = append(orderedURIs, c.TextDocument.URI)
|
|
}
|
|
sort.Strings(orderedURIs)
|
|
changeCount := len(orderedURIs)
|
|
|
|
for _, u := range orderedURIs {
|
|
uri := span.URI(u)
|
|
cmdFile := conn.AddFile(ctx, uri)
|
|
filename := cmdFile.uri.Filename()
|
|
|
|
// convert LSP-style edits to []diff.TextEdit cuz Spans are handy
|
|
renameEdits, err := source.FromProtocolEdits(cmdFile.mapper, edits[uri])
|
|
if err != nil {
|
|
return errors.Errorf("%v: %v", edits, err)
|
|
}
|
|
newContent := diff.ApplyEdits(string(cmdFile.mapper.Content), renameEdits)
|
|
|
|
switch {
|
|
case r.Write:
|
|
fmt.Fprintln(os.Stderr, filename)
|
|
err := os.Rename(filename, filename+".orig")
|
|
if err != nil {
|
|
return errors.Errorf("%v: %v", edits, err)
|
|
}
|
|
ioutil.WriteFile(filename, []byte(newContent), 0644)
|
|
case r.Diff:
|
|
diffs := diff.ToUnified(filename+".orig", filename, string(cmdFile.mapper.Content), renameEdits)
|
|
fmt.Print(diffs)
|
|
default:
|
|
if len(orderedURIs) > 1 {
|
|
fmt.Printf("%s:\n", filepath.Base(filename))
|
|
}
|
|
fmt.Print(string(newContent))
|
|
if changeCount > 1 { // if this wasn't last change, print newline
|
|
fmt.Println()
|
|
}
|
|
changeCount -= 1
|
|
}
|
|
}
|
|
return nil
|
|
}
|