зеркало из https://github.com/golang/tools.git
gopls/internal/cmd: redesign codeaction subcommand
This CL redesigns the codeaction subcommand (formerly named "fix") to make it more regular and useful: - By default, filtered (matching) code actions are merely printed unless the -exec flag is specified, as with 'gopls codelens'. In particular, this means that the tests no longer have the side effect of executing any action that is always offered, such as the forthcoming "open gopls documentation" action. - By default, all kinds of actions are returned unless explicitly filtered with a -kind flag. - The -all flag, which prevented discarding of non-preferred actions, has gone away. (All gopls actions are non-preferred, at least for now, so no flag is needed; if things change, the flag should be a tristate -preferred=auto|true|bool.) - The "fix" command is retained as a trivial stub for clarity. - Actions may be filtered by -title=regexp. - Disabled actions are discarded. Change-Id: Ic88c1232bbc7ff24ae33e6427c3773cb2564eb06 Reviewed-on: https://go-review.googlesource.com/c/tools/+/596797 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Родитель
cad260e912
Коммит
444aadd6e6
|
@ -103,8 +103,8 @@ Client support for code actions:
|
|||
available (if there are multiple) and execute it.
|
||||
Some action kinds have filtering shortcuts,
|
||||
e.g. [`M-x eglot-code-action-{inline,extract,rewrite}`](https://joaotavora.github.io/eglot/#index-M_002dx-eglot_002dcode_002daction_002dinline).
|
||||
- **CLI**: `gopls fix -a file.go:#123-#456 kinds...` executes code actions of the specified
|
||||
kinds (e.g. `refactor.inline`) on the selected range, specified using zero-based byte offsets.
|
||||
- **CLI**: `gopls codeaction -exec -kind k,... -diff file.go:#123-#456` executes code actions of the specified
|
||||
kinds (e.g. `refactor.inline`) on the selected range, specified using zero-based byte offsets, and displays the diff.
|
||||
|
||||
## Formatting
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ type Application struct {
|
|||
editFlags *EditFlags
|
||||
}
|
||||
|
||||
// EditFlags defines flags common to {fix,format,imports,rename}
|
||||
// EditFlags defines flags common to {code{action,lens},format,imports,rename}
|
||||
// that control how edits are applied to the client's files.
|
||||
//
|
||||
// The type is exported for flag reflection.
|
||||
|
@ -131,6 +131,10 @@ It is typically used with an editor to provide language features. When no
|
|||
command is specified, gopls will default to the 'serve' command. The language
|
||||
features can also be accessed via the gopls command-line interface.
|
||||
|
||||
For documentation of all its features, see:
|
||||
|
||||
https://github.com/golang/tools/blob/master/gopls/doc/features
|
||||
|
||||
Usage:
|
||||
gopls help [<subject>]
|
||||
|
||||
|
@ -280,9 +284,11 @@ func (app *Application) featureCommands() []tool.Application {
|
|||
return []tool.Application{
|
||||
&callHierarchy{app: app},
|
||||
&check{app: app},
|
||||
&codeaction{app: app},
|
||||
&codelens{app: app},
|
||||
&definition{app: app},
|
||||
&execute{app: app},
|
||||
&fix{app: app}, // (non-functional)
|
||||
&foldingRanges{app: app},
|
||||
&format{app: app},
|
||||
&highlight{app: app},
|
||||
|
@ -297,7 +303,6 @@ func (app *Application) featureCommands() []tool.Application {
|
|||
&semtok{app: app},
|
||||
&signature{app: app},
|
||||
&stats{app: app},
|
||||
&suggestedFix{app: app},
|
||||
&symbols{app: app},
|
||||
|
||||
&workspaceSymbol{app: app},
|
||||
|
@ -931,3 +936,17 @@ func pointPosition(m *protocol.Mapper, p point) (protocol.Position, error) {
|
|||
}
|
||||
return protocol.Position{}, fmt.Errorf("point has neither offset nor line/column")
|
||||
}
|
||||
|
||||
// TODO(adonovan): delete in 2025.
|
||||
type fix struct{ app *Application }
|
||||
|
||||
func (*fix) Name() string { return "fix" }
|
||||
func (cmd *fix) Parent() string { return cmd.app.Name() }
|
||||
func (*fix) Usage() string { return "" }
|
||||
func (*fix) ShortHelp() string { return "apply suggested fixes (obsolete)" }
|
||||
func (*fix) DetailedHelp(flags *flag.FlagSet) {
|
||||
fmt.Fprintf(flags.Output(), `No longer supported; use "gopls codeaction" instead.`)
|
||||
}
|
||||
func (*fix) Run(ctx context.Context, args ...string) error {
|
||||
return tool.CommandLineErrorf(`no longer supported; use "gopls codeaction" instead`)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
// Copyright 2024 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"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/gopls/internal/protocol"
|
||||
"golang.org/x/tools/gopls/internal/util/slices"
|
||||
"golang.org/x/tools/internal/tool"
|
||||
)
|
||||
|
||||
// codeaction implements the codeaction verb for gopls.
|
||||
type codeaction struct {
|
||||
EditFlags
|
||||
Kind string `flag:"kind" help:"comma-separated list of code action kinds to filter"`
|
||||
Title string `flag:"title" help:"regular expression to match title"`
|
||||
Exec bool `flag:"exec" help:"execute the first matching code action"`
|
||||
|
||||
app *Application
|
||||
}
|
||||
|
||||
func (cmd *codeaction) Name() string { return "codeaction" }
|
||||
func (cmd *codeaction) Parent() string { return cmd.app.Name() }
|
||||
func (cmd *codeaction) Usage() string { return "[codeaction-flags] filename[:line[:col]]" }
|
||||
func (cmd *codeaction) ShortHelp() string { return "list or execute code actions" }
|
||||
func (cmd *codeaction) DetailedHelp(f *flag.FlagSet) {
|
||||
fmt.Fprintf(f.Output(), `
|
||||
|
||||
The codeaction command lists or executes code actions for the
|
||||
specified file or range of a file. Each code action contains
|
||||
either an edit to be directly applied to the file, or a command
|
||||
to be executed by the server, which may have an effect such as:
|
||||
- requesting that the client apply an edit;
|
||||
- changing the state of the server; or
|
||||
- requesting that the client open a document.
|
||||
|
||||
The -kind and and -title flags filter the list of actions.
|
||||
|
||||
The -kind flag specifies a comma-separated list of LSP CodeAction kinds.
|
||||
Only actions of these kinds will be requested from the server.
|
||||
Valid kinds include:
|
||||
|
||||
quickfix
|
||||
refactor
|
||||
refactor.extract
|
||||
refactor.inline
|
||||
refactor.rewrite
|
||||
source.organizeImports
|
||||
source.fixAll
|
||||
source.assembly
|
||||
source.doc
|
||||
source.freesymbols
|
||||
goTest
|
||||
|
||||
Kinds are hierarchical, so "refactor" includes "refactor.inline".
|
||||
(Note: actions of kind "goTest" are not returned unless explicitly
|
||||
requested.)
|
||||
|
||||
The -title flag specifies a regular expression that must match the
|
||||
action's title. (Ideally kinds would be specific enough that this
|
||||
isn't necessary; we really need to subdivide refactor.rewrite; see
|
||||
gopls/internal/settings/codeactionkind.go.)
|
||||
|
||||
The -exec flag causes the first matching code action to be executed.
|
||||
Without the flag, the matching actions are merely listed.
|
||||
|
||||
It is not currently possible to execute more than one action,
|
||||
as that requires a way to detect and resolve conflicts.
|
||||
TODO(adonovan): support it when golang/go#67049 is resolved.
|
||||
|
||||
If executing an action causes the server to send a patch to the
|
||||
client, the usual -write, -preserve, -diff, and -list flags govern how
|
||||
the client deals with the patch.
|
||||
|
||||
Example: execute the first "quick fix" in the specified file and show the diff:
|
||||
|
||||
$ gopls codeaction -kind=quickfix -exec -diff ./gopls/main.go
|
||||
|
||||
codeaction-flags:
|
||||
`)
|
||||
printFlagDefaults(f)
|
||||
}
|
||||
|
||||
func (cmd *codeaction) Run(ctx context.Context, args ...string) error {
|
||||
if len(args) < 1 {
|
||||
return tool.CommandLineErrorf("codeaction expects at least 1 argument")
|
||||
}
|
||||
cmd.app.editFlags = &cmd.EditFlags
|
||||
conn, err := cmd.app.connect(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.terminate(ctx)
|
||||
|
||||
from := parseSpan(args[0])
|
||||
uri := from.URI()
|
||||
file, err := conn.openFile(ctx, uri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rng, err := file.spanRange(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
titleRE, err := regexp.Compile(cmd.Title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get diagnostics, as they may encode various lazy code actions.
|
||||
if err := conn.diagnoseFiles(ctx, []protocol.DocumentURI{uri}); err != nil {
|
||||
return err
|
||||
}
|
||||
diagnostics := []protocol.Diagnostic{} // LSP wants non-nil slice
|
||||
conn.client.filesMu.Lock()
|
||||
diagnostics = append(diagnostics, file.diagnostics...)
|
||||
conn.client.filesMu.Unlock()
|
||||
|
||||
// Request code actions of the desired kinds.
|
||||
var kinds []protocol.CodeActionKind
|
||||
if cmd.Kind != "" {
|
||||
for _, kind := range strings.Split(cmd.Kind, ",") {
|
||||
kinds = append(kinds, protocol.CodeActionKind(kind))
|
||||
}
|
||||
}
|
||||
actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{URI: uri},
|
||||
Range: rng,
|
||||
Context: protocol.CodeActionContext{
|
||||
Only: kinds,
|
||||
Diagnostics: diagnostics,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %v", from, err)
|
||||
}
|
||||
|
||||
// Gather edits from matching code actions.
|
||||
var edits []protocol.TextEdit
|
||||
for _, act := range actions {
|
||||
if act.Disabled != nil {
|
||||
continue
|
||||
}
|
||||
if !titleRE.MatchString(act.Title) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the provided span has a position (not just offsets),
|
||||
// and the action has diagnostics, the action must have a
|
||||
// diagnostic with the same range as it.
|
||||
if from.HasPosition() && len(act.Diagnostics) > 0 &&
|
||||
!slices.ContainsFunc(act.Diagnostics, func(diag protocol.Diagnostic) bool {
|
||||
return diag.Range.Start == rng.Start
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
if cmd.Exec {
|
||||
// -exec: run the first matching code action.
|
||||
if act.Command != nil {
|
||||
// This may cause the server to make
|
||||
// an ApplyEdit downcall to the client.
|
||||
if _, err := conn.executeCommand(ctx, act.Command); err != nil {
|
||||
return err
|
||||
}
|
||||
// The specification says that commands should
|
||||
// be executed _after_ edits are applied, not
|
||||
// instead of them, but we don't want to
|
||||
// duplicate edits.
|
||||
} else {
|
||||
// Partially apply CodeAction.Edit, a WorkspaceEdit.
|
||||
// (See also conn.Client.applyWorkspaceEdit(a.Edit)).
|
||||
for _, c := range act.Edit.DocumentChanges {
|
||||
tde := c.TextDocumentEdit
|
||||
if tde != nil && tde.TextDocument.URI == uri {
|
||||
// TODO(adonovan): this logic will butcher an edit that spans files.
|
||||
// It will also ignore create/delete/rename operations.
|
||||
// Fix or document. Need a three-way merge.
|
||||
edits = append(edits, protocol.AsTextEdits(tde.Edits)...)
|
||||
}
|
||||
}
|
||||
return applyTextEdits(file.mapper, edits, cmd.app.editFlags)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
// No -exec: list matching code actions.
|
||||
action := "edit"
|
||||
if act.Command != nil {
|
||||
action = "command"
|
||||
}
|
||||
fmt.Printf("%s\t%q [%s]\n",
|
||||
action,
|
||||
act.Title,
|
||||
act.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.Exec {
|
||||
return fmt.Errorf("no matching code action at %s", from)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -941,8 +941,8 @@ package foo
|
|||
}
|
||||
}
|
||||
|
||||
// TestFix tests the 'fix' subcommand (../suggested_fix.go).
|
||||
func TestFix(t *testing.T) {
|
||||
// TestCodeAction tests the 'codeaction' subcommand (../codeaction.go).
|
||||
func TestCodeAction(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tree := writeTree(t, `
|
||||
|
@ -964,29 +964,46 @@ type C struct{}
|
|||
|
||||
// no arguments
|
||||
{
|
||||
res := gopls(t, tree, "fix")
|
||||
res := gopls(t, tree, "codeaction")
|
||||
res.checkExit(false)
|
||||
res.checkStderr("expects at least 1 argument")
|
||||
}
|
||||
// success with default kinds, {quickfix}.
|
||||
// -a is always required because no fix is currently "preferred" (!)
|
||||
// list code actions in file
|
||||
{
|
||||
res := gopls(t, tree, "fix", "-a", "a.go")
|
||||
res := gopls(t, tree, "codeaction", "a.go")
|
||||
res.checkExit(true)
|
||||
res.checkStdout(`edit "Fill in return values" \[quickfix\]`)
|
||||
res.checkStdout(`command "Browse documentation for package a" \[source.doc\]`)
|
||||
}
|
||||
// list code actions in file, filtering by title
|
||||
{
|
||||
res := gopls(t, tree, "codeaction", "-title=Br.wse", "a.go")
|
||||
res.checkExit(true)
|
||||
got := res.stdout
|
||||
want := `
|
||||
package a
|
||||
type T int
|
||||
func f() (int, string) { return 0, "" }
|
||||
|
||||
`[1:]
|
||||
want := `command "Browse documentation for package a" [source.doc]` + "\n"
|
||||
if got != want {
|
||||
t.Errorf("fix: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
|
||||
t.Errorf("codeaction: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
|
||||
}
|
||||
}
|
||||
// list code actions at position (of io.Reader)
|
||||
{
|
||||
res := gopls(t, tree, "codeaction", "b.go:#31")
|
||||
res.checkExit(true)
|
||||
res.checkStdout(`command "Browse documentation for type io.Reader" \[source.doc]`)
|
||||
}
|
||||
// list quick fixes at position (of type T)
|
||||
{
|
||||
res := gopls(t, tree, "codeaction", "-kind=quickfix", "a.go:#15")
|
||||
res.checkExit(true)
|
||||
got := res.stdout
|
||||
want := `edit "Fill in return values" [quickfix]` + "\n"
|
||||
if got != want {
|
||||
t.Errorf("codeaction: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
|
||||
}
|
||||
}
|
||||
// success, with explicit CodeAction kind and diagnostics span.
|
||||
{
|
||||
res := gopls(t, tree, "fix", "-a", "b.go:#40", "quickfix")
|
||||
res := gopls(t, tree, "codeaction", "-kind=quickfix", "-exec", "b.go:#40")
|
||||
res.checkExit(true)
|
||||
got := res.stdout
|
||||
want := `
|
||||
|
@ -1004,7 +1021,7 @@ func (c C) Read(p []byte) (n int, err error) {
|
|||
}
|
||||
`[1:]
|
||||
if got != want {
|
||||
t.Errorf("fix: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
|
||||
t.Errorf("codeaction: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
// 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"
|
||||
|
||||
"golang.org/x/tools/gopls/internal/protocol"
|
||||
"golang.org/x/tools/gopls/internal/util/slices"
|
||||
"golang.org/x/tools/internal/tool"
|
||||
)
|
||||
|
||||
// TODO(adonovan): this command has a very poor user interface. It
|
||||
// should have a way to query the available fixes for a file (without
|
||||
// a span), enumerate the valid fix kinds, enable all fixes, and not
|
||||
// require the pointless -all flag. See issue #60290.
|
||||
|
||||
// suggestedFix implements the fix verb for gopls.
|
||||
type suggestedFix struct {
|
||||
EditFlags
|
||||
All bool `flag:"a,all" help:"apply all fixes, not just preferred fixes"`
|
||||
|
||||
app *Application
|
||||
}
|
||||
|
||||
func (s *suggestedFix) Name() string { return "fix" }
|
||||
func (s *suggestedFix) Parent() string { return s.app.Name() }
|
||||
func (s *suggestedFix) Usage() string { return "[fix-flags] <filename>" }
|
||||
func (s *suggestedFix) ShortHelp() string { return "apply suggested fixes" }
|
||||
func (s *suggestedFix) DetailedHelp(f *flag.FlagSet) {
|
||||
fmt.Fprintf(f.Output(), `
|
||||
Example: apply fixes to this file, rewriting it:
|
||||
|
||||
$ gopls fix -a -w internal/cmd/check.go
|
||||
|
||||
The -a (-all) flag causes all fixes, not just preferred ones, to be
|
||||
applied, but since no fixes are currently preferred, this flag is
|
||||
essentially mandatory.
|
||||
|
||||
Arguments after the filename are interpreted as LSP CodeAction kinds
|
||||
to be applied; the default set is {"quickfix"}, but valid kinds include:
|
||||
|
||||
quickfix
|
||||
refactor
|
||||
refactor.extract
|
||||
refactor.inline
|
||||
refactor.rewrite
|
||||
source.organizeImports
|
||||
source.fixAll
|
||||
|
||||
CodeAction kinds are hierarchical, so "refactor" includes
|
||||
"refactor.inline". There is currently no way to enable or even
|
||||
enumerate all kinds.
|
||||
|
||||
Example: apply any "refactor.rewrite" fixes at the specific byte
|
||||
offset within this file:
|
||||
|
||||
$ gopls fix -a internal/cmd/check.go:#43 refactor.rewrite
|
||||
|
||||
fix-flags:
|
||||
`)
|
||||
printFlagDefaults(f)
|
||||
}
|
||||
|
||||
// Run performs diagnostic checks on the file specified and either;
|
||||
// - if -w is specified, updates the file in place;
|
||||
// - if -d is specified, prints out unified diffs of the changes; or
|
||||
// - otherwise, prints the new versions to stdout.
|
||||
func (s *suggestedFix) Run(ctx context.Context, args ...string) error {
|
||||
if len(args) < 1 {
|
||||
return tool.CommandLineErrorf("fix expects at least 1 argument")
|
||||
}
|
||||
s.app.editFlags = &s.EditFlags
|
||||
conn, err := s.app.connect(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.terminate(ctx)
|
||||
|
||||
from := parseSpan(args[0])
|
||||
uri := from.URI()
|
||||
file, err := conn.openFile(ctx, uri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rng, err := file.spanRange(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get diagnostics.
|
||||
if err := conn.diagnoseFiles(ctx, []protocol.DocumentURI{uri}); err != nil {
|
||||
return err
|
||||
}
|
||||
diagnostics := []protocol.Diagnostic{} // LSP wants non-nil slice
|
||||
conn.client.filesMu.Lock()
|
||||
diagnostics = append(diagnostics, file.diagnostics...)
|
||||
conn.client.filesMu.Unlock()
|
||||
|
||||
// Request code actions
|
||||
codeActionKinds := []protocol.CodeActionKind{protocol.QuickFix}
|
||||
if len(args) > 1 {
|
||||
codeActionKinds = []protocol.CodeActionKind{}
|
||||
for _, k := range args[1:] {
|
||||
codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k))
|
||||
}
|
||||
}
|
||||
p := protocol.CodeActionParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{
|
||||
URI: uri,
|
||||
},
|
||||
Context: protocol.CodeActionContext{
|
||||
Only: codeActionKinds,
|
||||
Diagnostics: diagnostics,
|
||||
},
|
||||
Range: rng,
|
||||
}
|
||||
actions, err := conn.CodeAction(ctx, &p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %v", from, err)
|
||||
}
|
||||
|
||||
// Gather edits from matching code actions.
|
||||
var edits []protocol.TextEdit
|
||||
for _, a := range actions {
|
||||
// Without -all, apply only "preferred" fixes.
|
||||
if !a.IsPreferred && !s.All {
|
||||
continue
|
||||
}
|
||||
|
||||
// Execute any command.
|
||||
// This may cause the server to make
|
||||
// an ApplyEdit downcall to the client.
|
||||
if a.Command != nil {
|
||||
if _, err := conn.executeCommand(ctx, a.Command); err != nil {
|
||||
return err
|
||||
}
|
||||
// The specification says that commands should
|
||||
// be executed _after_ edits are applied, not
|
||||
// instead of them, but we don't want to
|
||||
// duplicate edits.
|
||||
continue
|
||||
}
|
||||
|
||||
// If the provided span has a position (not just offsets),
|
||||
// and the action has diagnostics, the action must have a
|
||||
// diagnostic with the same range as it.
|
||||
if from.HasPosition() && len(a.Diagnostics) > 0 &&
|
||||
!slices.ContainsFunc(a.Diagnostics, func(diag protocol.Diagnostic) bool {
|
||||
return diag.Range.Start == rng.Start
|
||||
}) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Partially apply CodeAction.Edit, a WorkspaceEdit.
|
||||
// (See also conn.Client.applyWorkspaceEdit(a.Edit)).
|
||||
for _, c := range a.Edit.DocumentChanges {
|
||||
tde := c.TextDocumentEdit
|
||||
if tde != nil && tde.TextDocument.URI == uri {
|
||||
// TODO(adonovan): this logic will butcher an edit that spans files.
|
||||
// It will also ignore create/delete/rename operations.
|
||||
// Fix or document.
|
||||
edits = append(edits, protocol.AsTextEdits(tde.Edits)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return applyTextEdits(file.mapper, edits, s.app.editFlags)
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
list or execute code actions
|
||||
|
||||
Usage:
|
||||
gopls [flags] codeaction [codeaction-flags] filename[:line[:col]]
|
||||
|
||||
|
||||
The codeaction command lists or executes code actions for the
|
||||
specified file or range of a file. Each code action contains
|
||||
either an edit to be directly applied to the file, or a command
|
||||
to be executed by the server, which may have an effect such as:
|
||||
- requesting that the client apply an edit;
|
||||
- changing the state of the server; or
|
||||
- requesting that the client open a document.
|
||||
|
||||
The -kind and and -title flags filter the list of actions.
|
||||
|
||||
The -kind flag specifies a comma-separated list of LSP CodeAction kinds.
|
||||
Only actions of these kinds will be requested from the server.
|
||||
Valid kinds include:
|
||||
|
||||
quickfix
|
||||
refactor
|
||||
refactor.extract
|
||||
refactor.inline
|
||||
refactor.rewrite
|
||||
source.organizeImports
|
||||
source.fixAll
|
||||
source.assembly
|
||||
source.doc
|
||||
source.freesymbols
|
||||
goTest
|
||||
|
||||
Kinds are hierarchical, so "refactor" includes "refactor.inline".
|
||||
(Note: actions of kind "goTest" are not returned unless explicitly
|
||||
requested.)
|
||||
|
||||
The -title flag specifies a regular expression that must match the
|
||||
action's title. (Ideally kinds would be specific enough that this
|
||||
isn't necessary; we really need to subdivide refactor.rewrite; see
|
||||
gopls/internal/settings/codeactionkind.go.)
|
||||
|
||||
The -exec flag causes the first matching code action to be executed.
|
||||
Without the flag, the matching actions are merely listed.
|
||||
|
||||
It is not currently possible to execute more than one action,
|
||||
as that requires a way to detect and resolve conflicts.
|
||||
TODO(adonovan): support it when golang/go#67049 is resolved.
|
||||
|
||||
If executing an action causes the server to send a patch to the
|
||||
client, the usual -write, -preserve, -diff, and -list flags govern how
|
||||
the client deals with the patch.
|
||||
|
||||
Example: execute the first "quick fix" in the specified file and show the diff:
|
||||
|
||||
$ gopls codeaction -kind=quickfix -exec -diff ./gopls/main.go
|
||||
|
||||
codeaction-flags:
|
||||
-d,-diff
|
||||
display diffs instead of edited file content
|
||||
-exec
|
||||
execute the first matching code action
|
||||
-kind=string
|
||||
comma-separated list of code action kinds to filter
|
||||
-l,-list
|
||||
display names of edited files
|
||||
-preserve
|
||||
with -write, make copies of original files
|
||||
-title=string
|
||||
regular expression to match title
|
||||
-w,-write
|
||||
write edited content to source files
|
|
@ -1,44 +1,5 @@
|
|||
apply suggested fixes
|
||||
apply suggested fixes (obsolete)
|
||||
|
||||
Usage:
|
||||
gopls [flags] fix [fix-flags] <filename>
|
||||
|
||||
Example: apply fixes to this file, rewriting it:
|
||||
|
||||
$ gopls fix -a -w internal/cmd/check.go
|
||||
|
||||
The -a (-all) flag causes all fixes, not just preferred ones, to be
|
||||
applied, but since no fixes are currently preferred, this flag is
|
||||
essentially mandatory.
|
||||
|
||||
Arguments after the filename are interpreted as LSP CodeAction kinds
|
||||
to be applied; the default set is {"quickfix"}, but valid kinds include:
|
||||
|
||||
quickfix
|
||||
refactor
|
||||
refactor.extract
|
||||
refactor.inline
|
||||
refactor.rewrite
|
||||
source.organizeImports
|
||||
source.fixAll
|
||||
|
||||
CodeAction kinds are hierarchical, so "refactor" includes
|
||||
"refactor.inline". There is currently no way to enable or even
|
||||
enumerate all kinds.
|
||||
|
||||
Example: apply any "refactor.rewrite" fixes at the specific byte
|
||||
offset within this file:
|
||||
|
||||
$ gopls fix -a internal/cmd/check.go:#43 refactor.rewrite
|
||||
|
||||
fix-flags:
|
||||
-a,-all
|
||||
apply all fixes, not just preferred fixes
|
||||
-d,-diff
|
||||
display diffs instead of edited file content
|
||||
-l,-list
|
||||
display names of edited files
|
||||
-preserve
|
||||
with -write, make copies of original files
|
||||
-w,-write
|
||||
write edited content to source files
|
||||
gopls [flags] fix
|
||||
No longer supported; use "gopls codeaction" instead.
|
|
@ -5,6 +5,10 @@ It is typically used with an editor to provide language features. When no
|
|||
command is specified, gopls will default to the 'serve' command. The language
|
||||
features can also be accessed via the gopls command-line interface.
|
||||
|
||||
For documentation of all its features, see:
|
||||
|
||||
https://github.com/golang/tools/blob/master/gopls/doc/features
|
||||
|
||||
Usage:
|
||||
gopls help [<subject>]
|
||||
|
||||
|
@ -21,9 +25,11 @@ Main
|
|||
Features
|
||||
call_hierarchy display selected identifier's call hierarchy
|
||||
check show diagnostic results for the specified file
|
||||
codeaction list or execute code actions
|
||||
codelens List or execute code lenses for a file
|
||||
definition show declaration of selected identifier
|
||||
execute Execute a gopls custom LSP command
|
||||
fix apply suggested fixes (obsolete)
|
||||
folding_ranges display selected file's folding ranges
|
||||
format format the code according to the go standard
|
||||
highlight display selected identifier's highlights
|
||||
|
@ -38,7 +44,6 @@ Features
|
|||
semtok show semantic tokens for the specified file
|
||||
signature display selected identifier's signature
|
||||
stats print workspace statistics
|
||||
fix apply suggested fixes
|
||||
symbols display selected file's symbols
|
||||
workspace_symbol search symbols in workspace
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@ It is typically used with an editor to provide language features. When no
|
|||
command is specified, gopls will default to the 'serve' command. The language
|
||||
features can also be accessed via the gopls command-line interface.
|
||||
|
||||
For documentation of all its features, see:
|
||||
|
||||
https://github.com/golang/tools/blob/master/gopls/doc/features
|
||||
|
||||
Usage:
|
||||
gopls help [<subject>]
|
||||
|
||||
|
@ -21,9 +25,11 @@ Main
|
|||
Features
|
||||
call_hierarchy display selected identifier's call hierarchy
|
||||
check show diagnostic results for the specified file
|
||||
codeaction list or execute code actions
|
||||
codelens List or execute code lenses for a file
|
||||
definition show declaration of selected identifier
|
||||
execute Execute a gopls custom LSP command
|
||||
fix apply suggested fixes (obsolete)
|
||||
folding_ranges display selected file's folding ranges
|
||||
format format the code according to the go standard
|
||||
highlight display selected identifier's highlights
|
||||
|
@ -38,7 +44,6 @@ Features
|
|||
semtok show semantic tokens for the specified file
|
||||
signature display selected identifier's signature
|
||||
stats print workspace statistics
|
||||
fix apply suggested fixes
|
||||
symbols display selected file's symbols
|
||||
workspace_symbol search symbols in workspace
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ func TestEverything(t *testing.T) {
|
|||
t.Logf("callee declared at %v",
|
||||
filepath.Base(calleePosn.String()))
|
||||
|
||||
t.Logf("run this command to reproduce locally:\n$ gopls fix -a -d %s:#%d refactor.inline",
|
||||
t.Logf("run this command to reproduce locally:\n$ gopls codeaction -kind=refactor.inline -exec -diff %s:#%d",
|
||||
callPosn.Filename, callPosn.Offset)
|
||||
|
||||
callee, err := inline.AnalyzeCallee(
|
||||
|
|
|
@ -261,7 +261,7 @@ func addFlag(f *flag.FlagSet, value reflect.Value, flagName string, help string)
|
|||
case *uint64:
|
||||
f.Uint64Var(v, flagName, *v, help)
|
||||
default:
|
||||
log.Fatalf("Cannot understand flag of type %T", v)
|
||||
log.Fatalf("field %q of type %T is not assignable to flag.Value", flagName, v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче