Approvals:
Heschi Kreinick: Looks good to me, approved
Rebecca Stambler: Trusted; Run TryBots
Go Bot: TryBots succeeded
kokoro: gopls CI succeeded
The change was submitted with unreviewed changes in the following files:
The name of the file: gopls/doc/commands.md
Insertions: 161, Deletions: 0.
@@ -5:7, +5:7 @@
- ### **Run go generate**
- Identifier: `gopls.generate`
+ ### **Add dependency**
+ Identifier: `gopls.add_dependency`
@@ -8:9, +8:9 @@
- generate runs `go generate` for a given directory.
+ Adds a dependency to the go.mod file for a module.
@@ +10:11 @@
+ Args:
@@ -11:13, +12:22 @@
- ### **Fill struct**
- Identifier: `gopls.fill_struct`
+ ```
+ {
+ // The go.mod file URI.
+ "URI": string,
+ // Additional args to pass to the go command.
+ "GoCmdArgs": []string,
+ // Whether to add a require directive.
+ "AddRequire": bool,
+ }
+ ```
@@ -14:16, +23:25 @@
- fill_struct is a gopls command to fill a struct with default
- values.
+ ### **Apply a fix**
+ Identifier: `gopls.apply_fix`
@@ +26:27 @@
+ Applies a fix to a region of source code.
@@ -18:20, +28:29 @@
- ### **Regenerate cgo**
- Identifier: `gopls.regenerate_cgo`
+ Args:
@@ -21:54, +30:49 @@
- regenerate_cgo regenerates cgo definitions.
-
-
- ### **Run test(s)**
- Identifier: `gopls.test`
-
- test runs `go test` for a specific test function.
-
-
- ### **Run go mod tidy**
- Identifier: `gopls.tidy`
-
- tidy runs `go mod tidy` for a module.
-
-
- ### **Update go.sum**
- Identifier: `gopls.update_go_sum`
-
- update_go_sum updates the go.sum file for a module.
-
-
- ### **Undeclared name**
- Identifier: `gopls.undeclared_name`
-
- undeclared_name adds a variable declaration for an undeclared
- name.
-
-
- ### **go get package**
- Identifier: `gopls.go_get_package`
-
- go_get_package runs `go get` to fetch a package.
-
+ ```
+ {
+ // The fix to apply.
+ "Fix": string,
+ // The file URI for the document to fix.
+ "URI": string,
+ // The document range to scan for fixes.
+ "Range": {
+ "start": {
+ "line": uint32,
+ "character": uint32,
+ },
+ "end": {
+ "line": uint32,
+ "character": uint32,
+ },
+ },
+ }
+ ```
@@ -58:59, +53:54 @@
- check_upgrades checks for module upgrades.
+ Checks for module upgrades.
@@ +55:56 @@
+ Args:
@@ -61:96, +57:65 @@
- ### **Add dependency**
- Identifier: `gopls.add_dependency`
-
- add_dependency adds a dependency.
-
-
- ### **Upgrade dependency**
- Identifier: `gopls.upgrade_dependency`
-
- upgrade_dependency upgrades a dependency.
-
-
- ### **Remove dependency**
- Identifier: `gopls.remove_dependency`
-
- remove_dependency removes a dependency.
-
-
- ### **Run go mod vendor**
- Identifier: `gopls.vendor`
-
- vendor runs `go mod vendor` for a module.
-
-
- ### **Extract to variable**
- Identifier: `gopls.extract_variable`
-
- extract_variable extracts an expression to a variable.
-
-
- ### **Extract to function**
- Identifier: `gopls.extract_function`
-
- extract_function extracts statements to a function.
-
+ ```
+ {
+ // The go.mod file URI.
+ "URI": string,
+ // The modules to check.
+ "Modules": []string,
+ }
+ ```
@@ -100:101, +69:70 @@
- gc_details controls calculation of gc annotations.
+ Toggle the calculation of gc annotations.
@@ +71:92 @@
+ Args:
+
+ ```
+ string
+ ```
+
+ ### **Run go generate**
+ Identifier: `gopls.generate`
+
+ Runs `go generate` for a given directory.
+
+ Args:
+
+ ```
+ {
+ // URI for the directory to generate.
+ "Dir": string,
+ // Whether to generate recursively (go generate ./...)
+ "Recursive": bool,
+ }
+ ```
@@ -106:107, +96:97 @@
- generate_gopls_mod (re)generates the gopls.mod file.
+ (Re)generate the gopls.mod file for a workspace.
@@ +98:259 @@
+ Args:
+
+ ```
+ {
+ // The file URI.
+ "URI": string,
+ }
+ ```
+
+ ### **go get package**
+ Identifier: `gopls.go_get_package`
+
+ Runs `go get` to fetch a package.
+
+ Args:
+
+ ```
+ {
+ // Any document URI within the relevant module.
+ "URI": string,
+ // The package to go get.
+ "Pkg": string,
+ "AddRequire": bool,
+ }
+ ```
+
+ ### **Regenerate cgo**
+ Identifier: `gopls.regenerate_cgo`
+
+ Regenerates cgo definitions.
+
+ Args:
+
+ ```
+ {
+ // The file URI.
+ "URI": string,
+ }
+ ```
+
+ ### **Remove dependency**
+ Identifier: `gopls.remove_dependency`
+
+ Removes a dependency from the go.mod file of a module.
+
+ Args:
+
+ ```
+ {
+ // The go.mod file URI.
+ "URI": string,
+ // The module path to remove.
+ "ModulePath": string,
+ "OnlyDiagnostic": bool,
+ }
+ ```
+
+ ### **Run test(s)**
+ Identifier: `gopls.run_tests`
+
+ Runs `go test` for a specific set of test or benchmark functions.
+
+ Args:
+
+ ```
+ {
+ // The test file containing the tests to run.
+ "URI": string,
+ // Specific test names to run, e.g. TestFoo.
+ "Tests": []string,
+ // Specific benchmarks to run, e.g. BenchmarkFoo.
+ "Benchmarks": []string,
+ }
+ ```
+
+ ### **Run test(s) (legacy)**
+ Identifier: `gopls.test`
+
+ Runs `go test` for a specific set of test or benchmark functions.
+
+ Args:
+
+ ```
+ string,
+ []string,
+ []string
+ ```
+
+ ### **Run go mod tidy**
+ Identifier: `gopls.tidy`
+
+ Runs `go mod tidy` for a module.
+
+ Args:
+
+ ```
+ {
+ // The file URI.
+ "URIs": []string,
+ }
+ ```
+
+ ### **Toggle gc_details**
+ Identifier: `gopls.toggle_gc_details`
+
+ Toggle the calculation of gc annotations.
+
+ Args:
+
+ ```
+ {
+ // The file URI.
+ "URI": string,
+ }
+ ```
+
+ ### **Update go.sum**
+ Identifier: `gopls.update_go_sum`
+
+ Updates the go.sum file for a module.
+
+ Args:
+
+ ```
+ {
+ // The file URI.
+ "URIs": []string,
+ }
+ ```
+
+ ### **Upgrade dependency**
+ Identifier: `gopls.upgrade_dependency`
+
+ Upgrades a dependency in the go.mod file for a module.
+
+ Args:
+
+ ```
+ {
+ // The go.mod file URI.
+ "URI": string,
+ // Additional args to pass to the go command.
+ "GoCmdArgs": []string,
+ // Whether to add a require directive.
+ "AddRequire": bool,
+ }
+ ```
+
+ ### **Run go mod vendor**
+ Identifier: `gopls.vendor`
+
+ Runs `go mod vendor` for a module.
+
+ Args:
+
+ ```
+ {
+ // The file URI.
+ "URI": string,
+ }
+ ```
The name of the file: gopls/doc/generate.go
Insertions: 49, Deletions: 0.
@@ +31:33 @@
+ "
golang.org/x/tools/internal/lsp/command"
+ "
golang.org/x/tools/internal/lsp/command/commandmeta"
@@ -89:90, +91:92 @@
- c.Command = source.CommandPrefix + c.Command
+ c.Command = command.ID(c.Command)
@@ -370:390 @@
- // The code that defines commands is much more complicated than the
- // code that defines options, so reading comments for the Doc is very
- // fragile. If this causes problems, we should switch to a dynamic
- // approach and put the doc in the Commands struct rather than reading
- // from the source code.
-
- // Find the Commands slice.
- typesSlice := pkg.Types.Scope().Lookup("Commands")
- f, err := fileForPos(pkg, typesSlice.Pos())
- if err != nil {
- return nil, err
- }
- path, _ := astutil.PathEnclosingInterval(f, typesSlice.Pos(), typesSlice.Pos())
- vspec := path[1].(*ast.ValueSpec)
- var astSlice *ast.CompositeLit
- for i, name := range vspec.Names {
- if name.Name == "Commands" {
- astSlice = vspec.Values[i].(*ast.CompositeLit)
- }
- }
@@ +375:379 @@
+ _, cmds, err := commandmeta.Load()
+ if err != nil {
+ return nil, err
+ }
@@ -394:432, +380:381 @@
- for _, elt := range astSlice.Elts {
- // Find the composite literal of the Command.
- typesCommand := pkg.TypesInfo.ObjectOf(elt.(*ast.Ident))
- path, _ := astutil.PathEnclosingInterval(f, typesCommand.Pos(), typesCommand.Pos())
- vspec := path[1].(*ast.ValueSpec)
-
- var astCommand ast.Expr
- for i, name := range vspec.Names {
- if name.Name == typesCommand.Name() {
- astCommand = vspec.Values[i]
- }
- }
-
- // Read the Name and Title fields of the literal.
- var name, title string
- ast.Inspect(astCommand, func(n ast.Node) bool {
- kv, ok := n.(*ast.KeyValueExpr)
- if ok {
- k := kv.Key.(*ast.Ident).Name
- switch k {
- case "Name":
- name = strings.Trim(kv.Value.(*ast.BasicLit).Value, `"`)
- case "Title":
- title = strings.Trim(kv.Value.(*ast.BasicLit).Value, `"`)
- }
- }
- return true
- })
-
- if title == "" {
- title = name
- }
-
- // Conventionally, the doc starts with the name of the variable.
- // Replace it with the name of the command.
- doc := vspec.Doc.Text()
- doc = strings.Replace(doc, typesCommand.Name(), name, 1)
-
+ for _, cmd := range cmds {
@@ -433:436, +382:386 @@
- Command: name,
- Title: title,
- Doc: doc,
+ Command: cmd.Name,
+ Title: cmd.Title,
+ Doc: cmd.Doc,
+ ArgDoc: argsDoc(cmd.Args),
@@ +391:440 @@
+ func argsDoc(args []*commandmeta.Field) string {
+ var b strings.Builder
+ for i, arg := range args {
+ b.WriteString(argDoc(arg, 0))
+ if i != len(args)-1 {
+ b.WriteString(",\n")
+ }
+ }
+ return b.String()
+ }
+
+ func argDoc(arg *commandmeta.Field, level int) string {
+ // Max level to expand struct fields.
+ const maxLevel = 3
+ if len(arg.Fields) > 0 {
+ if level < maxLevel {
+ return structDoc(arg.Fields, level)
+ }
+ return "{ ... }"
+ }
+ under := arg.Type.Underlying()
+ switch u := under.(type) {
+ case *types.Slice:
+ return fmt.Sprintf("[]%s", u.Elem().Underlying().String())
+ }
+ return types.TypeString(under, nil)
+ }
+
+ func structDoc(fields []*commandmeta.Field, level int) string {
+ var b strings.Builder
+ b.WriteString("{\n")
+ indent := strings.Repeat("\t", level)
+ for _, fld := range fields {
+ if fld.Doc != "" && level == 0 {
+ doclines := strings.Split(fld.Doc, "\n")
+ for _, line := range doclines {
+ fmt.Fprintf(&b, "%s\t// %s\n", indent, line)
+ }
+ }
+ tag := fld.JSONTag
+ if tag == "" {
+ tag = fld.Name
+ }
+ fmt.Fprintf(&b, "%s\t%q: %s,\n", indent, tag, argDoc(fld, level+1))
+ }
+ fmt.Fprintf(&b, "%s}", indent)
+ return b.String()
+ }
+
@@ -442:443, +441:442 @@
- lensNames := map[string]struct{}{}
+ all := map[command.Command]struct{}{}
@@ -444:445, +443:444 @@
- lensNames[k] = struct{}{}
+ all[k] = struct{}{}
@@ -447:448, +446:450 @@
- lensNames[k] = struct{}{}
+ if _, ok := all[k]; ok {
+ panic(fmt.Sprintf("duplicate lens %q", string(k)))
+ }
+ all[k] = struct{}{}
@@ -453:454, +455:456 @@
- if _, ok := lensNames[cmd.Command]; ok {
+ if _, ok := all[command.Command(cmd.Command)]; ok {
@@ +738:741 @@
+ if command.ArgDoc != "" {
+ fmt.Fprintf(section, "Args:\n\n```\n%s\n```\n\n", command.ArgDoc)
+ }
The name of the file: gopls/internal/regtest/codelens/codelens_test.go
Insertions: 1, Deletions: 1.
@@ +10:11 @@
+ "time"
@@ +14:15 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -15:16 @@
- "
golang.org/x/tools/internal/lsp/source"
@@ -54:55, +55:56 @@
- enabled: map[string]bool{
source.CommandGenerate.Name: false},
+ enabled: map[string]bool{string(command.Generate): false},
@@ -162:163, +163:164 @@
- env.ExecuteCodeLensCommand("go.mod", source.CommandCheckUpgrades)
+ env.ExecuteCodeLensCommand("go.mod", command.CheckUpgrades)
@@ -166:167, +167:168 @@
- env.ApplyQuickFixes("go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("go.mod", d.Diagnostics)
@@ -220:221, +221:222 @@
- env.ExecuteCodeLensCommand("go.mod", source.CommandTidy)
+ env.ExecuteCodeLensCommand("go.mod", command.Tidy)
@@ -267:268, +268:269 @@
- env.ExecuteCodeLensCommand("cgo.go", source.CommandRegenerateCgo)
+ env.ExecuteCodeLensCommand("cgo.go", command.RegenerateCgo)
@@ +299:301 @@
+ // TestGCDetails seems to suffer from poor performance on certain builders. Give it some more time to complete.
+ Timeout(60*time.Second),
@@ -300:301, +303:304 @@
- env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
+ env.ExecuteCodeLensCommand("main.go", command.GCDetails)
@@ -333:334, +336:337 @@
- env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
+ env.ExecuteCodeLensCommand("main.go", command.GCDetails)
The name of the file: gopls/internal/regtest/diagnostics/diagnostics_test.go
Insertions: 4, Deletions: 4.
@@ -537:538, +537:538 @@
- env.ApplyQuickFixes("main.go", d.Diagnostics...)
+ env.ApplyQuickFixes("main.go", d.Diagnostics)
@@ -678:679, +678:679 @@
- env.ApplyQuickFixes("main.go", d.Diagnostics...)
+ env.ApplyQuickFixes("main.go", d.Diagnostics)
@@ -698:699, +698:699 @@
- env.ApplyQuickFixes("go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("go.mod", d.Diagnostics)
@@ -738:739, +738:739 @@
- env.DiagnosticAtRegexpWithMessage("main.go", `"
github.com/ardanlabs/conf"`, "your go.mod file"),
+ env.DiagnosticAtRegexpWithMessage("main.go", `"
github.com/ardanlabs/conf"`, "no required module"),
@@ -742:743, +742:743 @@
- env.ApplyQuickFixes("main.go", d.Diagnostics...)
+ env.ApplyQuickFixes("main.go", d.Diagnostics)
The name of the file: gopls/internal/regtest/misc/imports_test.go
Insertions: 1, Deletions: 1.
@@ -210:211, +210:211 @@
- env.ApplyQuickFixes("a/a.go", d.Diagnostics...)
+ env.ApplyQuickFixes("a/a.go", d.Diagnostics)
The name of the file: gopls/internal/regtest/misc/vendor_test.go
Insertions: 1, Deletions: 5.
@@ -12:13 @@
- "
golang.org/x/tools/internal/lsp/source"
@@ -71:76, +70:71 @@
- env.ApplyQuickFixes("go.mod", d.Diagnostics...)
-
- // Check for file changes when the command completes.
- env.Await(CompletedWork(source.CommandVendor.Title, 1))
- env.CheckForFileChanges()
+ env.ApplyQuickFixes("go.mod", d.Diagnostics)
The name of the file: gopls/internal/regtest/modfile/modfile_test.go
Insertions: 11, Deletions: 11.
@@ -182:183, +182:183 @@
- env.ApplyQuickFixes("a/main.go", goGetDiag)
+ env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{goGetDiag})
@@ -232:233, +232:233 @@
- env.ApplyQuickFixes("a/main.go", randomDiag)
+ env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{randomDiag})
@@ -279:280, +279:280 @@
- env.ApplyQuickFixes("a/go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
@@ -324:325, +324:325 @@
- env.ApplyQuickFixes("a/go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
@@ -387:388, +387:388 @@
- env.ApplyQuickFixes("a/main.go", d.Diagnostics...)
+ env.ApplyQuickFixes("a/main.go", d.Diagnostics)
@@ -460:461, +460:461 @@
- var _ = blah.Name
+ var V1Name = blah.Name
@@ -473:474, +473:474 @@
-
example.com/blah/v2 v2.0.0 h1:w5baE9JuuU11s3de3yWx2sU05AhNkgLYdZ4qukv+V0k=
+
example.com/blah/v2 v2.0.0 h1:DNPsFPkKtTdxclRheaMCiYAoYizp6PuBzO0OmLOO0pY=
@@ -488:489 @@
- var d protocol.PublishDiagnosticsParams
@@ -490:494, +489:493 @@
- OnceMet(
- DiagnosticAt("a/go.mod", 0, 0),
- ReadDiagnostics("a/go.mod", &d),
- ),
+ // We would like for the error to appear in the v2 module, but
+ // as of writing non-workspace packages are not diagnosed.
+ env.DiagnosticAtRegexpWithMessage("a/main.go", `"
example.com/blah/v2"`, "cannot find module providing"),
+ env.DiagnosticAtRegexpWithMessage("a/go.mod", `require
example.com/blah/v2`, "cannot find module providing"),
@@ -495:496, +494:495 @@
- env.ApplyQuickFixes("a/main.go", d.Diagnostics...)
+ env.ApplyQuickFixes("a/go.mod", env.DiagnosticsFor("a/go.mod").Diagnostics)
@@ -505:506, +504:505 @@
- env.Await(EmptyDiagnostics("a/go.mod"))
+ env.Await(EmptyDiagnostics("a/main.go"))
@@ -554:555, +553:554 @@
- env.ApplyQuickFixes("a/go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
@@ +719:721 @@
+ require
example.com v1.2.3
+
@@ -736:737 @@
- env.DiagnosticAtRegexpWithMessage("b/go.mod", "module
modb.com", "not in your go.mod file"),
@@ -817:818 @@
- Modes(Singleton), // workspace modules don't use -mod=readonly (golang/go#43346)
@@ -828:829, +827:828 @@
- env.ApplyQuickFixes("go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("go.mod", d.Diagnostics)
@@ -939:940, +938:939 @@
- env.ApplyQuickFixes("go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("go.mod", d.Diagnostics)
@@ -992:993, +991:992 @@
- env.ApplyQuickFixes("go.mod", diagnostics...)
+ env.ApplyQuickFixes("go.mod", diagnostics)
@@ -1045:1046, +1044:1045 @@
- env.ApplyQuickFixes("go.mod", diagnostic)
+ env.ApplyQuickFixes("go.mod", []protocol.Diagnostic{diagnostic})
The name of the file: gopls/internal/regtest/workspace/workspace_test.go
Insertions: 24, Deletions: 21.
@@ -290:302, +290:299 @@
- if testenv.Go1Point() < 14 {
- // On 1.14 and above, the go mod tidy diagnostics accidentally
- // download for us. This is the behavior we actually want.
- d := protocol.PublishDiagnosticsParams{}
- env.Await(
- OnceMet(
- env.DiagnosticAtRegexpWithMessage("moda/a/go.mod", "require
b.com v1.2.3", "b....@v1.2.3"),
- ReadDiagnostics("moda/a/go.mod", &d),
- ),
- )
- env.ApplyQuickFixes("moda/a/go.mod", d.Diagnostics...)
- }
+
+ d := protocol.PublishDiagnosticsParams{}
+ env.Await(
+ OnceMet(
+ env.DiagnosticAtRegexpWithMessage("moda/a/go.mod", "require
b.com v1.2.3", "b....@v1.2.3 has not been downloaded"),
+ ReadDiagnostics("moda/a/go.mod", &d),
+ ),
+ )
+ env.ApplyQuickFixes("moda/a/go.mod", d.Diagnostics)
@@ -510:511, +507:508 @@
- env.ApplyQuickFixes("modb/go.mod", d.Diagnostics...)
+ env.ApplyQuickFixes("modb/go.mod", d.Diagnostics)
@@ -790:791, +787:788 @@
- func TestOneUntidyModule(t *testing.T) {
+ func TestMultiModule_OneBrokenModule(t *testing.T) {
@@ +820:821 @@
+ env.OpenFile("a/go.mod")
@@ -827:829, +825:826 @@
- // TODO(rstambler): The "add dependency" diagnostic is also broken.
- if d.Message != `go.sum is out of sync with go.mod. Please update it or run "go list -mod=mod ./...".` {
+ if d.Message != `go.sum is out of sync with go.mod. Please update it by applying the quick fix.` {
@@ -831:837, +828:840 @@
- env.ApplyQuickFixes("a/go.mod", d)
- env.Await(
- EmptyDiagnostics("a/go.mod"),
- )
- }
-
+ actions, err := env.GetQuickFixes("a/go.mod", []protocol.Diagnostic{d})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(actions) != 2 {
+ t.Fatalf("expected 2 code actions, got %v", len(actions))
+ }
+ env.ApplyQuickFixes("a/go.mod", []protocol.Diagnostic{d})
+ }
+ env.Await(
+ EmptyDiagnostics("a/go.mod"),
+ )
The name of the file: gopls/internal/regtest/wrappers.go
Insertions: 7, Deletions: 1.
@@ +11:12 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -13:14 @@
- "
golang.org/x/tools/internal/lsp/source"
@@ -195:196, +195:196 @@
- func (e *Env) ApplyQuickFixes(path string, diagnostics ...protocol.Diagnostic) {
+ func (e *Env) ApplyQuickFixes(path string, diagnostics []protocol.Diagnostic) {
@@ +202:208 @@
+ // GetQuickFixes returns the available quick fix code actions.
+ func (e *Env) GetQuickFixes(path string, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) {
+ e.T.Helper()
+ return e.Editor.GetQuickFixes(e.Ctx, path, nil, diagnostics)
+ }
+
@@ -301:302, +307:308 @@
- func (e *Env) ExecuteCodeLensCommand(path string, cmd *source.Command) {
+ func (e *Env) ExecuteCodeLensCommand(path string, cmd command.Command) {
The name of the file: internal/lsp/cache/mod.go
Insertions: 0, Deletions: 2.
@@ +17:18 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -220:222 @@
- // If the error message contains a position, use that. Don't pass a file
- // handle in, as it might not be the file associated with the error.
@@ -260:261 @@
- outer:
@@ -274:292, +272:275 @@
-
- for _, req := range pm.File.Require {
- if req.Mod == ver {
- reference = req.Syntax
- break outer
- }
- }
- for _, ex := range pm.File.Exclude {
- if ex.Mod == ver {
- reference = ex.Syntax
- break outer
- }
- }
- for _, rep := range pm.File.Replace {
- if rep.New == ver || rep.Old == ver {
- reference = rep.Syntax
- break outer
- }
+ reference = findModuleReference(pm.File, ver)
+ if reference != nil {
+ break
@@ -311:312, +294:300 @@
- args, err := source.MarshalArgs(fh.URI(), false, []string{fmt.Sprintf("%v@%v", innermost.Path, innermost.Version)})
+ title := fmt.Sprintf("Download %v@%v", innermost.Path, innermost.Version)
+ cmd, err := command.NewAddDependencyCommand(title, command.DependencyArgs{
+ URI: protocol.URIFromSpanURI(fh.URI()),
+ AddRequire: false,
+ GoCmdArgs: []string{fmt.Sprintf("%v@%v", innermost.Path, innermost.Version)},
+ })
@@ -320:333, +308:314 @@
- URI: fh.URI(),
- Range: rng,
- Severity: protocol.SeverityError,
- Message: msg,
- Source: source.ListError,
- SuggestedFixes: []source.SuggestedFix{{
- Title: fmt.Sprintf("Download %v@%v", innermost.Path, innermost.Version),
- Command: &protocol.Command{
- Title: source.CommandAddDependency.Title,
- Command:
source.CommandAddDependency.ID(),
- Arguments: args,
- },
- }},
+ URI: fh.URI(),
+ Range: rng,
+ Severity: protocol.SeverityError,
+ Message: msg,
+ Source: source.ListError,
+ SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd)},
@@ +329:348 @@
+ func findModuleReference(mf *modfile.File, ver module.Version) *modfile.Line {
+ for _, req := range mf.Require {
+ if req.Mod == ver {
+ return req.Syntax
+ }
+ }
+ for _, ex := range mf.Exclude {
+ if ex.Mod == ver {
+ return ex.Syntax
+ }
+ }
+ for _, rep := range mf.Replace {
+ if rep.New == ver || rep.Old == ver {
+ return rep.Syntax
+ }
+ }
+ return nil
+ }
+
The name of the file: internal/lsp/cache/mod_tidy.go
Insertions: 23, Deletions: 42.
@@ -8:9 @@
- "encoding/json"
@@ +20:21 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -110:111, +110:111 @@
- tmpURI, inv, cleanup, err := snapshot.goCommandInvocation(ctx, source.WriteTemporaryModFile|source.AllowNetwork, inv)
+ tmpURI, inv, cleanup, err := snapshot.goCommandInvocation(ctx, source.WriteTemporaryModFile, inv)
@@ -153:154 @@
-
@@ -164:178 @@
- // Don't show inconsistent vendoring errors for multi-module workspaces
- // because the workspace module doesn't support vendoring, and we don't
- // want to accidentally create new vendor directories.
- if isInconsistentVendor && len(s.ModFiles()) > 1 {
- return nil
- }
- var args []json.RawMessage
- for _, uri := range s.ModFiles() {
- arg, err := source.MarshalArgs(uri)
- if err != nil {
- return nil
- }
- args = append(args, arg...)
- }
@@ +166:167 @@
+ args := command.URIArg{URI: protocol.URIFromSpanURI(uri)}
@@ +171:175 @@
+ cmd, err := command.NewVendorCommand("Run go mod vendor", args)
+ if err != nil {
+ return nil
+ }
@@ -192:202, +182:190 @@
- SuggestedFixes: []source.SuggestedFix{{
- Title: source.CommandVendor.Title,
- Command: &protocol.Command{
- Command:
source.CommandVendor.ID(),
- Title: source.CommandVendor.Title,
- Arguments: args,
- },
- }}},
- }
- case isGoSumUpdates:
+ SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd)},
+ }}
+
+ case isGoSumUpdates:
+ var args []protocol.DocumentURI
+ for _, uri := range s.ModFiles() {
+ args = append(args, protocol.URIFromSpanURI(uri))
+ }
@@ +196:204 @@
+ tidyCmd, err := command.NewTidyCommand("Run go mod tidy", command.URIArgs{URIs: args})
+ if err != nil {
+ return nil
+ }
+ updateCmd, err := command.NewUpdateGoSumCommand("Update go.sum", command.URIArgs{URIs: args})
+ if err != nil {
+ return nil
+ }
@@ -213:231, +209:213 @@
- Message: `go.sum is out of sync with go.mod. Please update it or run "go list -mod=mod ./...".`,
- SuggestedFixes: []source.SuggestedFix{
- {
- Title: source.CommandTidy.Title,
- Command: &protocol.Command{
- Command:
source.CommandTidy.ID(),
- Title: source.CommandTidy.Title,
- Arguments: args,
- },
- },
- {
- Title: source.CommandUpdateGoSum.Title,
- Command: &protocol.Command{
- Command:
source.CommandUpdateGoSum.ID(),
- Title: source.CommandUpdateGoSum.Title,
- Arguments: args,
- },
- },
+ Message: `go.sum is out of sync with go.mod. Please update it by applying the quick fix.`,
+ SuggestedFixes: []source.SuggestedFix{
+ source.SuggestedFixFromCommand(tidyCmd),
+ source.SuggestedFixFromCommand(updateCmd),
@@ -414:415, +396:402 @@
- args, err := source.MarshalArgs(m.URI, onlyDiagnostic, req.Mod.Path)
+ title := fmt.Sprintf("Remove dependency: %s", req.Mod.Path)
+ cmd, err := command.NewRemoveDependencyCommand(title, command.RemoveDependencyArgs{
+ URI: protocol.URIFromSpanURI(m.URI),
+ OnlyDiagnostic: onlyDiagnostic,
+ ModulePath: req.Mod.Path,
+ })
@@ -419:432, +406:412 @@
- URI: m.URI,
- Range: rng,
- Severity: protocol.SeverityWarning,
- Source: source.ModTidyError,
- Message: fmt.Sprintf("%s is not used in this module", req.Mod.Path),
- SuggestedFixes: []source.SuggestedFix{{
- Title: fmt.Sprintf("Remove dependency: %s", req.Mod.Path),
- Command: &protocol.Command{
- Title: source.CommandRemoveDependency.Title,
- Command:
source.CommandRemoveDependency.ID(),
- Arguments: args,
- },
- }},
+ URI: m.URI,
+ Range: rng,
+ Severity: protocol.SeverityWarning,
+ Source: source.ModTidyError,
+ Message: fmt.Sprintf("%s is not used in this module", req.Mod.Path),
+ SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd)},
@@ -488:489, +468:474 @@
- args, err := source.MarshalArgs(pm.Mapper.URI, !req.Indirect, []string{req.Mod.Path + "@" + req.Mod.Version})
+ title := fmt.Sprintf("Add %s to your go.mod file", req.Mod.Path)
+ cmd, err := command.NewAddDependencyCommand(title, command.DependencyArgs{
+ URI: protocol.URIFromSpanURI(pm.Mapper.URI),
+ AddRequire: !req.Indirect,
+ GoCmdArgs: []string{req.Mod.Path + "@" + req.Mod.Version},
+ })
@@ -493:506, +478:484 @@
- URI: pm.Mapper.URI,
- Range: rng,
- Severity: protocol.SeverityError,
- Source: source.ModTidyError,
- Message: fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path),
- SuggestedFixes: []source.SuggestedFix{{
- Title: fmt.Sprintf("Add %s to your go.mod file", req.Mod.Path),
- Command: &protocol.Command{
- Title: source.CommandAddDependency.Title,
- Command:
source.CommandAddDependency.ID(),
- Arguments: args,
- },
- }},
+ URI: pm.Mapper.URI,
+ Range: rng,
+ Severity: protocol.SeverityError,
+ Source: source.ModTidyError,
+ Message: fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path),
+ SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd)},
The name of the file: internal/lsp/code_action.go
Insertions: 1, Deletions: 5.
@@ -9:10 @@
- "regexp"
@@ +15:16 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ +21:22 @@
+ errors "
golang.org/x/xerrors"
@@ -107:116 @@
- // Fix unresolved imports with "go get". This is separate from the
- // goimports fixes because goimports will not remove an import
- // that appears to be used, even if currently unresolved.
- actions, err := goGetFixes(ctx, snapshot, fh.URI(), diagnostics)
- if err != nil {
- return nil, err
- }
- codeActions = append(codeActions, actions...)
-
@@ +128:133 @@
+ pkgQuickFixes, err := quickFixesForDiagnostics(ctx, snapshot, diagnostics, pkg.GetDiagnostics())
+ if err != nil {
+ return nil, err
+ }
+ codeActions = append(codeActions, pkgQuickFixes...)
@@ -270:271, +267:268 @@
- if analyzer.Command != nil {
+ if analyzer.Fix != "" {
@@ -362:394 @@
- var importErrorRe = regexp.MustCompile(`could not import ([^\s]+)`)
-
- func goGetFixes(ctx context.Context, snapshot source.Snapshot, uri span.URI, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) {
- if snapshot.GoModForFile(uri) == "" {
- // Go get only supports module mode for now.
- return nil, nil
- }
-
- var actions []protocol.CodeAction
- for _, diag := range diagnostics {
- matches := importErrorRe.FindStringSubmatch(diag.Message)
- if len(matches) == 0 {
- return nil, nil
- }
- args, err := source.MarshalArgs(uri, matches[1])
- if err != nil {
- return nil, err
- }
- actions = append(actions, protocol.CodeAction{
- Title: fmt.Sprintf("go get package %v", matches[1]),
- Diagnostics: []protocol.Diagnostic{diag},
- Kind: protocol.QuickFix,
- Command: &protocol.Command{
- Title: source.CommandGoGetPackage.Title,
- Command:
source.CommandGoGetPackage.ID(),
- Arguments: args,
- },
- })
- }
- return actions, nil
- }
-
@@ -400:401, +365:366 @@
- if a.Command == nil {
+ if a.Fix == "" {
@@ -437:439, +402:404 @@
- if analyzer.Command == nil {
- return nil, fmt.Errorf("no command for convenience analyzer %s",
analyzer.Analyzer.Name)
+ if analyzer.Fix == "" {
+ return nil, fmt.Errorf("no fix for convenience analyzer %s",
analyzer.Analyzer.Name)
@@ -440:441, +405:410 @@
- jsonArgs, err := source.MarshalArgs(sd.URI, sd.Range)
+ cmd, err := command.NewApplyFixCommand(sd.Message, command.ApplyFixArgs{
+ URI: protocol.URIFromSpanURI(sd.URI),
+ Range: sd.Range,
+ Fix: analyzer.Fix,
+ })
@@ -452:457, +421:422 @@
- Command: &protocol.Command{
- Command:
analyzer.Command.ID(),
- Title: sd.Message,
- Arguments: jsonArgs,
- },
+ Command: &cmd,
@@ -468:469, +433:438 @@
- jsonArgs, err := source.MarshalArgs(uri, rng)
+ _, pgf, err := source.GetParsedFile(ctx, snapshot, fh, source.NarrowestPackage)
+ if err != nil {
+ return nil, errors.Errorf("getting file for Identifier: %w", err)
+ }
+ srng, err := pgf.Mapper.RangeToSpanRange(rng)
@@ -472:479, +441:451 @@
- var actions []protocol.CodeAction
- for _, command := range []*source.Command{
- source.CommandExtractFunction,
- source.CommandExtractVariable,
- } {
- if !command.Applies(ctx, snapshot, fh, rng) {
- continue
+ puri := protocol.URIFromSpanURI(uri)
+ var commands []protocol.Command
+ if _, ok, _ := source.CanExtractFunction(snapshot.FileSet(), srng, pgf.Src, pgf.File); ok {
+ cmd, err := command.NewApplyFixCommand("Extract to function", command.ApplyFixArgs{
+ URI: puri,
+ Fix: source.ExtractFunction,
+ Range: rng,
+ })
+ if err != nil {
+ return nil, err
@@ +452:467 @@
+ commands = append(commands, cmd)
+ }
+ if _, _, ok, _ := source.CanExtractVariable(srng, pgf.File); ok {
+ cmd, err := command.NewApplyFixCommand("Extract variable", command.ApplyFixArgs{
+ URI: puri,
+ Fix: source.ExtractVariable,
+ Range: rng,
+ })
+ if err != nil {
+ return nil, err
+ }
+ commands = append(commands, cmd)
+ }
+ var actions []protocol.CodeAction
+ for _, cmd := range commands {
@@ -481:487, +468:471 @@
- Title: command.Title,
- Kind: protocol.RefactorExtract,
- Command: &protocol.Command{
- Command: command.ID(),
- Arguments: jsonArgs,
- },
+ Title: cmd.Title,
+ Kind: protocol.RefactorExtract,
+ Command: &cmd,
@@ -506:507, +490:491 @@
- func moduleQuickFixes(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) {
+ func moduleQuickFixes(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle, pdiags []protocol.Diagnostic) ([]protocol.CodeAction, error) {
@@ -522:523, +506:507 @@
- errors, err := mod.DiagnosticsForMod(ctx, snapshot, modFH)
+ diags, err := mod.DiagnosticsForMod(ctx, snapshot, modFH)
@@ +510:514 @@
+ return quickFixesForDiagnostics(ctx, snapshot, pdiags, diags)
+ }
+
+ func quickFixesForDiagnostics(ctx context.Context, snapshot source.Snapshot, pdiags []protocol.Diagnostic, sdiags []*source.Diagnostic) ([]protocol.CodeAction, error) {
@@ -527:532, +515:516 @@
- for _, e := range errors {
- // Don't offer fixes for diagnostics in other go.mod files.
- if fh.Kind() == source.Mod && e.URI != modFH.URI() {
- continue
- }
+ for _, e := range sdiags {
@@ -533:534, +517:518 @@
- for _, d := range diagnostics {
+ for _, d := range pdiags {
@@ +534:535 @@
+
@@ -551:553, +536:539 @@
- if uri != modFH.URI() {
- continue
+ fh, err := snapshot.GetVersionedFile(ctx, uri)
+ if err != nil {
+ return nil, err
@@ -556:557, +542:543 @@
- Version: modFH.Version(),
+ Version: fh.Version(),
@@ -558:559, +544:545 @@
- URI: protocol.URIFromSpanURI(modFH.URI()),
+ URI: protocol.URIFromSpanURI(uri),
@@ -602:603, +588:589 @@
- jsonArgs, err := source.MarshalArgs(uri, tests, benchmarks)
+ cmd, err := command.NewTestCommand("Run tests and benchmarks", protocol.URIFromSpanURI(uri), tests, benchmarks)
@@ -607:614, +593:596 @@
- Title:
source.CommandTest.Name,
- Kind: protocol.GoTest,
- Command: &protocol.Command{
- Title: source.CommandTest.Title,
- Command:
source.CommandTest.ID(),
- Arguments: jsonArgs,
- },
+ Title: cmd.Title,
+ Kind: protocol.GoTest,
+ Command: &cmd,
The name of the file: internal/lsp/command.go
Insertions: 85, Deletions: 145.
@@ +20:21 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -28:39, +29:30 @@
- var command *source.Command
- for _, c := range source.Commands {
- if c.ID() == params.Command {
- command = c
- break
- }
- }
- if command == nil {
- return nil, fmt.Errorf("no known command")
- }
- var match bool
+ var found bool
@@ -40:42, +31:33 @@
- if command.ID() == name {
- match = true
+ if name == params.Command {
+ found = true
@@ -45:47, +36:38 @@
- if !match {
- return nil, fmt.Errorf("%s is not a supported command", command.ID())
+ if !found {
+ return nil, fmt.Errorf("%s is not a supported command", params.Command)
@@ -48:55, +39:77 @@
- // Some commands require that all files are saved to disk. If we detect
- // unsaved files, warn the user instead of running the commands.
- unsaved := false
- for _, overlay := range s.session.Overlays() {
- if !overlay.Saved() {
- unsaved = true
- break
+
+ handler := &commandHandler{
+ s: s,
+ params: params,
+ }
+ return command.Dispatch(ctx, params, handler)
+ }
+
+ type commandHandler struct {
+ s *Server
+ params *protocol.ExecuteCommandParams
+ }
+
+ // commandConfig configures common command set-up and execution.
+ type commandConfig struct {
+ async bool
+ requireSave bool // whether all files must be saved for the command to work
+ progress string // title to use for progress reporting. If empty, no progress will be reported.
+ forURI protocol.DocumentURI // URI to resolve to a snapshot. If unset, snapshot will be nil.
+ }
+
+ // commandDeps is evaluated from a commandConfig. Note that not all fields may
+ // be populated, depending on which configuration is set. See comments in-line
+ // for details.
+ type commandDeps struct {
+ snapshot source.Snapshot // present if cfg.forURI was set
+ fh source.VersionedFileHandle // present if cfg.forURI was set
+ work *workDone // present cfg.progress was set
+ }
+
+ type commandFunc func(context.Context, commandDeps) error
+
+ func (c *commandHandler) run(ctx context.Context, cfg commandConfig, run commandFunc) (err error) {
+ if cfg.requireSave {
+ for _, overlay := range c.s.session.Overlays() {
+ if !overlay.Saved() {
+ return errors.New("All files must be saved first")
+ }
@@ -57:70, +79:87 @@
- if unsaved {
- switch params.Command {
- case
source.CommandTest.ID(),
-
source.CommandGenerate.ID(),
-
source.CommandToggleDetails.ID(),
-
source.CommandAddDependency.ID(),
-
source.CommandUpgradeDependency.ID(),
-
source.CommandRemoveDependency.ID(),
-
source.CommandVendor.ID():
- // TODO(PJW): for Toggle, not an error if it is being disabled
- err := errors.New("All files must be saved first")
- s.showCommandError(ctx, command.Title, err)
- return nil, nil
+ var deps commandDeps
+ if cfg.forURI != "" {
+ var ok bool
+ var release func()
+ deps.snapshot, deps.fh, ok, release, err = c.s.beginFileRequest(ctx, cfg.forURI, source.UnknownKind)
+ defer release()
+ if !ok {
+ return err
@@ -73:82, +90:92 @@
-
- var work *workDone
- // Don't show progress for suggested fixes. They should be quick.
- if !command.IsSuggestedFix() {
- // Start progress prior to spinning off a goroutine specifically so that
- // clients are aware of the work item before the command completes. This
- // matters for regtests, where having a continuous thread of work is
- // convenient for assertions.
- work = s.progress.start(ctx, command.Title, "Running...", params.WorkDoneToken, cancel)
+ if cfg.progress != "" {
+
deps.work = c.s.progress.start(ctx, cfg.progress, "Running...", c.params.WorkDoneToken, cancel)
@@ -83:85, +93:94 @@
-
- run := func() {
+ runcmd := func() error {
@@ -86:87, +95:96 @@
- err := s.runCommand(ctx, work, command, params.Arguments)
+ err := run(ctx, deps)
@@ -89:90, +98:99 @@
- work.end(command.Title + ": canceled")
+ deps.work.end("canceled")
@@ -91:96, +100:102 @@
- event.Error(ctx, fmt.Sprintf("%s: command error", command.Title), err)
- work.end(command.Title + ": failed")
- // Show a message when work completes with error, because the progress end
- // message is typically dismissed immediately by LSP clients.
- s.showCommandError(ctx, command.Title, err)
+ event.Error(ctx, "command error", err)
+ deps.work.end("failed")
@@ -97:98, +103:104 @@
- work.end(command.ID() + ": completed")
+ deps.work.end("completed")
@@ +105:106 @@
+ return err
@@ -100:104, +107:110 @@
- if command.Async {
- go run()
- } else {
- run()
+ if cfg.async {
+ go runcmd()
+ return nil
@@ -105:108, +111:112 @@
- // Errors running the command are displayed to the user above, so don't
- // return them.
- return nil, nil
+ return runcmd()
@@ -110:239, +114:120 @@
- func (s *Server) runSuggestedFixCommand(ctx context.Context, command *source.Command, args []json.RawMessage) error {
- var uri protocol.DocumentURI
- var rng protocol.Range
- if err := source.UnmarshalArgs(args, &uri, &rng); err != nil {
- return err
- }
- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, uri, source.Go)
- defer release()
- if !ok {
- return err
- }
- edits, err := command.SuggestedFix(ctx, snapshot, fh, rng)
- if err != nil {
- return err
- }
- r, err := s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{
- Edit: protocol.WorkspaceEdit{
- DocumentChanges: edits,
- },
- })
- if err != nil {
- return err
- }
- if !r.Applied {
- return errors.New(r.FailureReason)
- }
- return nil
- }
-
- func (s *Server) showCommandError(ctx context.Context, title string, err error) {
- // Command error messages should not be cancelable.
- ctx = xcontext.Detach(ctx)
- if err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
- Type: protocol.Error,
- Message: fmt.Sprintf("%s failed: %v", title, err),
- }); err != nil {
- event.Error(ctx, title+": failed to show message", err)
- }
- }
-
- func (s *Server) runCommand(ctx context.Context, work *workDone, command *source.Command, args []json.RawMessage) (err error) {
- // If the command has a suggested fix function available, use it and apply
- // the edits to the workspace.
- if command.IsSuggestedFix() {
- return s.runSuggestedFixCommand(ctx, command, args)
- }
- switch command {
- case source.CommandTest:
- var uri protocol.DocumentURI
- var tests, benchmarks []string
- if err := source.UnmarshalArgs(args, &uri, &tests, &benchmarks); err != nil {
- return err
- }
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- return s.runTests(ctx, snapshot, uri, work, tests, benchmarks)
- case source.CommandGenerate:
- var uri protocol.DocumentURI
- var recursive bool
- if err := source.UnmarshalArgs(args, &uri, &recursive); err != nil {
- return err
- }
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- return s.runGoGenerate(ctx, snapshot, uri.SpanURI(), recursive, work)
- case source.CommandRegenerateCgo:
- var uri protocol.DocumentURI
- if err := source.UnmarshalArgs(args, &uri); err != nil {
- return err
- }
- mod := source.FileModification{
- URI: uri.SpanURI(),
- Action: source.InvalidateMetadata,
- }
- return s.didModifyFiles(ctx, []source.FileModification{mod}, FromRegenerateCgo)
- case source.CommandTidy, source.CommandVendor:
- for _, arg := range args {
- var uri protocol.DocumentURI
- if err := json.Unmarshal(arg, &uri); err != nil {
- return err
- }
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- // The flow for `go mod tidy` and `go mod vendor` is almost identical,
- // so we combine them into one case for convenience.
- action := "tidy"
- if command == source.CommandVendor {
- action = "vendor"
- }
- if err := runSimpleGoCommand(ctx, snapshot, source.UpdateUserModFile|source.AllowNetwork, uri.SpanURI(), "mod", []string{action}); err != nil {
- return err
- }
- }
- case source.CommandUpdateGoSum:
- for _, arg := range args {
- var uri protocol.DocumentURI
- if err := json.Unmarshal(arg, &uri); err != nil {
- return err
- }
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- if err := runSimpleGoCommand(ctx, snapshot, source.UpdateUserModFile|source.AllowNetwork, uri.SpanURI(), "list", []string{"all"}); err != nil {
- return err
- }
- }
- case source.CommandCheckUpgrades:
- var uri protocol.DocumentURI
- var modules []string
- if err := source.UnmarshalArgs(args, &uri, &modules); err != nil {
- return err
- }
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- upgrades, err := s.getUpgrades(ctx, snapshot, uri.SpanURI(), modules)
+ func (c *commandHandler) ApplyFix(ctx context.Context, args command.ApplyFixArgs) error {
+ return c.run(ctx, commandConfig{
+ // Note: no progress here. Applying fixes should be quick.
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
+ edits, err := source.ApplyFix(ctx, args.Fix, deps.snapshot, deps.fh, args.Range)
@@ -242:245, +123:134 @@
- snapshot.View().RegisterModuleUpgrades(upgrades)
- // Re-diagnose the snapshot to publish the new module diagnostics.
- s.diagnoseSnapshot(snapshot, nil, false)
+ r, err := c.s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{
+ Edit: protocol.WorkspaceEdit{
+ DocumentChanges: edits,
+ },
+ })
+ if err != nil {
+ return err
+ }
+ if !r.Applied {
+ return errors.New(r.FailureReason)
+ }
@@ -246:251, +135:157 @@
- case source.CommandAddDependency, source.CommandUpgradeDependency:
- var uri protocol.DocumentURI
- var goCmdArgs []string
- var addRequire bool
- if err := source.UnmarshalArgs(args, &uri, &addRequire, &goCmdArgs); err != nil {
+ })
+ }
+
+ func (c *commandHandler) RegenerateCgo(ctx context.Context, args command.URIArg) error {
+ return c.run(ctx, commandConfig{
+ progress: "Regenerating Cgo",
+ }, func(ctx context.Context, deps commandDeps) error {
+ mod := source.FileModification{
+ URI: args.URI.SpanURI(),
+ Action: source.InvalidateMetadata,
+ }
+ return c.s.didModifyFiles(ctx, []source.FileModification{mod}, FromRegenerateCgo)
+ })
+ }
+
+ func (c *commandHandler) CheckUpgrades(ctx context.Context, args command.CheckUpgradesArgs) error {
+ return c.run(ctx, commandConfig{
+ forURI: args.URI,
+ progress: "Checking for upgrades",
+ }, func(ctx context.Context, deps commandDeps) error {
+ upgrades, err := c.s.getUpgrades(ctx, deps.snapshot, args.URI.SpanURI(), args.Modules)
+ if err != nil {
@@ -253:271, +159:240 @@
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- return s.runGoGetModule(ctx, snapshot, uri.SpanURI(), addRequire, goCmdArgs)
- case source.CommandRemoveDependency:
- var uri protocol.DocumentURI
- var modulePath string
- var onlyDiagnostic bool
- if err := source.UnmarshalArgs(args, &uri, &onlyDiagnostic, &modulePath); err != nil {
- return err
- }
- snapshot, fh, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
+ deps.snapshot.View().RegisterModuleUpgrades(upgrades)
+ // Re-diagnose the snapshot to publish the new module diagnostics.
+ c.s.diagnoseSnapshot(deps.snapshot, nil, false)
+ return nil
+ })
+ }
+
+ func (c *commandHandler) AddDependency(ctx context.Context, args command.DependencyArgs) error {
+ return c.GoGetModule(ctx, args)
+ }
+
+ func (c *commandHandler) UpgradeDependency(ctx context.Context, args command.DependencyArgs) error {
+ return c.GoGetModule(ctx, args)
+ }
+
+ func (c *commandHandler) GoGetModule(ctx context.Context, args command.DependencyArgs) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Running go get",
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
+ return runGoGetModule(ctx, deps.snapshot, args.URI.SpanURI(), args.AddRequire, args.GoCmdArgs)
+ })
+ }
+
+ // TODO(rFindley): UpdateGoSum, Tidy, and Vendor could probably all be one command.
+
+ func (c *commandHandler) UpdateGoSum(ctx context.Context, args command.URIArgs) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Updating go.sum",
+ }, func(ctx context.Context, deps commandDeps) error {
+ for _, uri := range args.URIs {
+ snapshot, fh, ok, release, err := c.s.beginFileRequest(ctx, uri, source.UnknownKind)
+ defer release()
+ if !ok {
+ return err
+ }
+ if err := runSimpleGoCommand(ctx, snapshot, source.UpdateUserModFile|source.AllowNetwork, fh.URI(), "list", []string{"all"}); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ }
+
+ func (c *commandHandler) Tidy(ctx context.Context, args command.URIArgs) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Running go mod tidy",
+ }, func(ctx context.Context, deps commandDeps) error {
+ for _, uri := range args.URIs {
+ snapshot, fh, ok, release, err := c.s.beginFileRequest(ctx, uri, source.UnknownKind)
+ defer release()
+ if !ok {
+ return err
+ }
+ if err := runSimpleGoCommand(ctx, snapshot, source.UpdateUserModFile|source.AllowNetwork, fh.URI(), "mod", []string{"tidy"}); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ }
+
+ func (c *commandHandler) Vendor(ctx context.Context, args command.URIArg) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Running go mod vendor",
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
+ return runSimpleGoCommand(ctx, deps.snapshot, source.UpdateUserModFile|source.AllowNetwork, args.URI.SpanURI(), "mod", []string{"vendor"})
+ })
+ }
+
+ func (c *commandHandler) RemoveDependency(ctx context.Context, args command.RemoveDependencyArgs) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Removing dependency",
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
@@ -276:278, +245:247 @@
- if onlyDiagnostic {
- if err := s.runGoGetModule(ctx, snapshot, uri.SpanURI(), false, []string{modulePath + "@none"}); err != nil {
+ if args.OnlyDiagnostic {
+ if err := runGoGetModule(ctx, deps.snapshot, args.URI.SpanURI(), false, []string{args.ModulePath + "@none"}); err != nil {
@@ -280:281, +249:250 @@
- return runSimpleGoCommand(ctx, snapshot, source.UpdateUserModFile|source.AllowNetwork, uri.SpanURI(), "mod", []string{"tidy"})
+ return runSimpleGoCommand(ctx, deps.snapshot, source.UpdateUserModFile|source.AllowNetwork, args.URI.SpanURI(), "mod", []string{"tidy"})
@@ -282:283, +251:252 @@
- pm, err := snapshot.ParseMod(ctx, fh)
+ pm, err := deps.snapshot.ParseMod(ctx, deps.fh)
@@ -286:287, +255:256 @@
- edits, err := dropDependency(snapshot, pm, modulePath)
+ edits, err := dropDependency(deps.snapshot, pm, args.ModulePath)
@@ -290:291, +259:260 @@
- response, err := s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{
+ response, err := c.s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{
@@ -294:295, +263:264 @@
- Version: fh.Version(),
+ Version: deps.fh.Version(),
@@ -296:297, +265:266 @@
- URI: protocol.URIFromSpanURI(fh.URI()),
+ URI: protocol.URIFromSpanURI(deps.fh.URI()),
@@ -309:381, +278:280 @@
- case source.CommandGoGetPackage:
- var uri protocol.DocumentURI
- var pkg string
- if err := source.UnmarshalArgs(args, &uri, &pkg); err != nil {
- return err
- }
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- return s.runGoGetPackage(ctx, snapshot, uri.SpanURI(), pkg)
-
- case source.CommandToggleDetails:
- var fileURI protocol.DocumentURI
- if err := source.UnmarshalArgs(args, &fileURI); err != nil {
- return err
- }
- pkgDir := span.URIFromPath(filepath.Dir(fileURI.SpanURI().Filename()))
- s.gcOptimizationDetailsMu.Lock()
- if _, ok := s.gcOptimizationDetails[pkgDir]; ok {
- delete(s.gcOptimizationDetails, pkgDir)
- s.clearDiagnosticSource(gcDetailsSource)
- } else {
- s.gcOptimizationDetails[pkgDir] = struct{}{}
- }
- s.gcOptimizationDetailsMu.Unlock()
- // need to recompute diagnostics.
- // so find the snapshot
- snapshot, _, ok, release, err := s.beginFileRequest(ctx, fileURI, source.UnknownKind)
- defer release()
- if !ok {
- return err
- }
- s.diagnoseSnapshot(snapshot, nil, false)
- case source.CommandGenerateGoplsMod:
- var v source.View
- if len(args) == 0 {
- views := s.session.Views()
- if len(views) != 1 {
- return fmt.Errorf("cannot resolve view: have %d views", len(views))
- }
- v = views[0]
- } else {
- var uri protocol.DocumentURI
- if err := source.UnmarshalArgs(args, &uri); err != nil {
- return err
- }
- var err error
- v, err = s.session.ViewOf(uri.SpanURI())
- if err != nil {
- return err
- }
- }
- snapshot, release := v.Snapshot(ctx)
- defer release()
- modFile, err := cache.BuildGoplsMod(ctx, v.Folder(), snapshot)
- if err != nil {
- return errors.Errorf("getting workspace mod file: %w", err)
- }
- content, err := modFile.Format()
- if err != nil {
- return errors.Errorf("formatting mod file: %w", err)
- }
- filename := filepath.Join(v.Folder().Filename(), "gopls.mod")
- if err := ioutil.WriteFile(filename, content, 0644); err != nil {
- return errors.Errorf("writing mod file: %w", err)
- }
- default:
- return fmt.Errorf("unsupported command: %s", command.ID())
- }
- return nil
+ return nil
+ })
@@ -408:409, +307:338 @@
- func (s *Server) runTests(ctx context.Context, snapshot source.Snapshot, uri protocol.DocumentURI, work *workDone, tests, benchmarks []string) error {
+ func (c *commandHandler) Test(ctx context.Context, uri protocol.DocumentURI, tests, benchmarks []string) error {
+ return c.RunTests(ctx, command.RunTestsArgs{
+ URI: uri,
+ Tests: tests,
+ Benchmarks: benchmarks,
+ })
+ }
+
+ func (c *commandHandler) RunTests(ctx context.Context, args command.RunTestsArgs) error {
+ return c.run(ctx, commandConfig{
+ async: true,
+ progress: "Running go test",
+ requireSave: true,
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
+ if err := c.runTests(ctx, deps.snapshot,
deps.work, args.URI, args.Tests, args.Benchmarks); err != nil {
+ if err := c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
+ Type: protocol.Error,
+ Message: fmt.Sprintf("Running tests failed: %v", err),
+ }); err != nil {
+ event.Error(ctx, "running tests: failed to show message", err)
+ }
+ }
+ // Since we're running asynchronously, any error returned here would be
+ // ignored.
+ return nil
+ })
+ }
+
+ func (c *commandHandler) runTests(ctx context.Context, snapshot source.Snapshot, work *workDone, uri protocol.DocumentURI, tests, benchmarks []string) error {
+ // TODO: fix the error reporting when this runs async.
@@ -477:478, +406:407 @@
- return s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
+ return c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
@@ -483:492, +412:416 @@
- func (s *Server) runGoGenerate(ctx context.Context, snapshot source.Snapshot, dir span.URI, recursive bool, work *workDone) error {
- ctx, cancel := context.WithCancel(ctx)
- defer cancel()
-
- er := &eventWriter{ctx: ctx, operation: "generate"}
-
- pattern := "."
- if recursive {
- pattern = "./..."
+ func (c *commandHandler) Generate(ctx context.Context, args command.GenerateArgs) error {
+ title := "Running go generate ."
+ if args.Recursive {
+ title = "Running go generate ./..."
@@ +417:423 @@
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: title,
+ forURI: args.Dir,
+ }, func(ctx context.Context, deps commandDeps) error {
+ er := &eventWriter{ctx: ctx, operation: "generate"}
@@ -494:511, +424:438 @@
- inv := &gocommand.Invocation{
- Verb: "generate",
- Args: []string{"-x", pattern},
- WorkingDir: dir.Filename(),
- }
- stderr := io.MultiWriter(er, workDoneWriter{work})
- if err := snapshot.RunGoCommandPiped(ctx, source.Normal, inv, er, stderr); err != nil {
- return err
- }
- return nil
- }
-
- func (s *Server) runGoGetPackage(ctx context.Context, snapshot source.Snapshot, uri span.URI, pkg string) error {
- stdout, err := snapshot.RunGoCommandDirect(ctx, source.WriteTemporaryModFile|source.AllowNetwork, &gocommand.Invocation{
- Verb: "list",
- Args: []string{"-f", "{{.Module.Path}}@{{.Module.Version}}", pkg},
- WorkingDir: filepath.Dir(uri.Filename()),
+ pattern := "."
+ if args.Recursive {
+ pattern = "./..."
+ }
+ inv := &gocommand.Invocation{
+ Verb: "generate",
+ Args: []string{"-x", pattern},
+ WorkingDir: args.Dir.SpanURI().Filename(),
+ }
+ stderr := io.MultiWriter(er, workDoneWriter{
deps.work})
+ if err := deps.snapshot.RunGoCommandPiped(ctx, source.Normal, inv, er, stderr); err != nil {
+ return err
+ }
+ return nil
@@ -512:517 @@
- if err != nil {
- return err
- }
- ver := strings.TrimSpace(stdout.String())
- return s.runGoGetModule(ctx, snapshot, uri, true, []string{ver})
@@ -519:520, +441:461 @@
- func (s *Server) runGoGetModule(ctx context.Context, snapshot source.Snapshot, uri span.URI, addRequire bool, args []string) error {
+ func (c *commandHandler) GoGetPackage(ctx context.Context, args command.GoGetPackageArgs) error {
+ return c.run(ctx, commandConfig{
+ forURI: args.URI,
+ progress: "Running go get",
+ }, func(ctx context.Context, deps commandDeps) error {
+ uri := args.URI.SpanURI()
+ stdout, err := deps.snapshot.RunGoCommandDirect(ctx, source.WriteTemporaryModFile|source.AllowNetwork, &gocommand.Invocation{
+ Verb: "list",
+ Args: []string{"-f", "{{.Module.Path}}@{{.Module.Version}}", args.Pkg},
+ WorkingDir: filepath.Dir(uri.Filename()),
+ })
+ if err != nil {
+ return err
+ }
+ ver := strings.TrimSpace(stdout.String())
+ return runGoGetModule(ctx, deps.snapshot, uri, args.AddRequire, []string{ver})
+ })
+ }
+
+ func runGoGetModule(ctx context.Context, snapshot source.Snapshot, uri span.URI, addRequire bool, args []string) error {
@@ +505:558 @@
+
+ func (c *commandHandler) GCDetails(ctx context.Context, uri protocol.DocumentURI) error {
+ return c.ToggleGCDetails(ctx, command.URIArg{URI: uri})
+ }
+
+ func (c *commandHandler) ToggleGCDetails(ctx context.Context, args command.URIArg) error {
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Toggling GC Details",
+ forURI: args.URI,
+ }, func(ctx context.Context, deps commandDeps) error {
+ pkgDir := span.URIFromPath(filepath.Dir(args.URI.SpanURI().Filename()))
+ c.s.gcOptimizationDetailsMu.Lock()
+ if _, ok := c.s.gcOptimizationDetails[pkgDir]; ok {
+ delete(c.s.gcOptimizationDetails, pkgDir)
+ c.s.clearDiagnosticSource(gcDetailsSource)
+ } else {
+ c.s.gcOptimizationDetails[pkgDir] = struct{}{}
+ }
+ c.s.gcOptimizationDetailsMu.Unlock()
+ c.s.diagnoseSnapshot(deps.snapshot, nil, false)
+ return nil
+ })
+ }
+
+ func (c *commandHandler) GenerateGoplsMod(ctx context.Context, args command.URIArg) error {
+ // TODO: go back to using URI
+ return c.run(ctx, commandConfig{
+ requireSave: true,
+ progress: "Generating gopls.mod",
+ }, func(ctx context.Context, deps commandDeps) error {
+ views := c.s.session.Views()
+ if len(views) != 1 {
+ return fmt.Errorf("cannot resolve view: have %d views", len(views))
+ }
+ v := views[0]
+ snapshot, release := v.Snapshot(ctx)
+ defer release()
+ modFile, err := cache.BuildGoplsMod(ctx, snapshot.View().Folder(), snapshot)
+ if err != nil {
+ return errors.Errorf("getting workspace mod file: %w", err)
+ }
+ content, err := modFile.Format()
+ if err != nil {
+ return errors.Errorf("formatting mod file: %w", err)
+ }
+ filename := filepath.Join(snapshot.View().Folder().Filename(), "gopls.mod")
+ if err := ioutil.WriteFile(filename, content, 0644); err != nil {
+ return errors.Errorf("writing mod file: %w", err)
+ }
+ return nil
+ })
+ }
The name of the file: internal/lsp/command/command_gen.go
Insertions: 368, Deletions: 0.
@@ +0:369 @@
+ // Copyright 2021 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.
+
+ // Don't include this file during code generation, or it will break the build
+ // if existing interface methods have been modified.
+ // +build !generate
+
+ package command
+
+ // Code generated by generate.go. DO NOT EDIT.
+
+ import (
+ "context"
+ "fmt"
+
+ "
golang.org/x/tools/internal/lsp/protocol"
+ )
+
+ const (
+ AddDependency Command = "add_dependency"
+ ApplyFix Command = "apply_fix"
+ CheckUpgrades Command = "check_upgrades"
+ GCDetails Command = "gc_details"
+ Generate Command = "generate"
+ GenerateGoplsMod Command = "generate_gopls_mod"
+ GoGetPackage Command = "go_get_package"
+ RegenerateCgo Command = "regenerate_cgo"
+ RemoveDependency Command = "remove_dependency"
+ RunTests Command = "run_tests"
+ Test Command = "test"
+ Tidy Command = "tidy"
+ ToggleGCDetails Command = "toggle_gc_details"
+ UpdateGoSum Command = "update_go_sum"
+ UpgradeDependency Command = "upgrade_dependency"
+ Vendor Command = "vendor"
+ )
+
+ var Commands = []Command{
+ AddDependency,
+ ApplyFix,
+ CheckUpgrades,
+ GCDetails,
+ Generate,
+ GenerateGoplsMod,
+ GoGetPackage,
+ RegenerateCgo,
+ RemoveDependency,
+ RunTests,
+ Test,
+ Tidy,
+ ToggleGCDetails,
+ UpdateGoSum,
+ UpgradeDependency,
+ Vendor,
+ }
+
+ func Dispatch(ctx context.Context, params *protocol.ExecuteCommandParams, s Interface) (interface{}, error) {
+ switch params.Command {
+ case "gopls.add_dependency":
+ var a0 DependencyArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.AddDependency(ctx, a0)
+ return nil, err
+ case "gopls.apply_fix":
+ var a0 ApplyFixArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.ApplyFix(ctx, a0)
+ return nil, err
+ case "gopls.check_upgrades":
+ var a0 CheckUpgradesArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.CheckUpgrades(ctx, a0)
+ return nil, err
+ case "gopls.gc_details":
+ var a0 protocol.DocumentURI
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.GCDetails(ctx, a0)
+ return nil, err
+ case "gopls.generate":
+ var a0 GenerateArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.Generate(ctx, a0)
+ return nil, err
+ case "gopls.generate_gopls_mod":
+ var a0 URIArg
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.GenerateGoplsMod(ctx, a0)
+ return nil, err
+ case "gopls.go_get_package":
+ var a0 GoGetPackageArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.GoGetPackage(ctx, a0)
+ return nil, err
+ case "gopls.regenerate_cgo":
+ var a0 URIArg
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.RegenerateCgo(ctx, a0)
+ return nil, err
+ case "gopls.remove_dependency":
+ var a0 RemoveDependencyArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.RemoveDependency(ctx, a0)
+ return nil, err
+ case "gopls.run_tests":
+ var a0 RunTestsArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.RunTests(ctx, a0)
+ return nil, err
+ case "gopls.test":
+ var a0 protocol.DocumentURI
+ var a1 []string
+ var a2 []string
+ if err := UnmarshalArgs(params.Arguments, &a0, &a1, &a2); err != nil {
+ return nil, err
+ }
+ err := s.Test(ctx, a0, a1, a2)
+ return nil, err
+ case "gopls.tidy":
+ var a0 URIArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.Tidy(ctx, a0)
+ return nil, err
+ case "gopls.toggle_gc_details":
+ var a0 URIArg
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.ToggleGCDetails(ctx, a0)
+ return nil, err
+ case "gopls.update_go_sum":
+ var a0 URIArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.UpdateGoSum(ctx, a0)
+ return nil, err
+ case "gopls.upgrade_dependency":
+ var a0 DependencyArgs
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.UpgradeDependency(ctx, a0)
+ return nil, err
+ case "gopls.vendor":
+ var a0 URIArg
+ if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+ return nil, err
+ }
+ err := s.Vendor(ctx, a0)
+ return nil, err
+ }
+ return nil, fmt.Errorf("unsupported command %q", params.Command)
+ }
+
+ func NewAddDependencyCommand(title string, a0 DependencyArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.add_dependency",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewApplyFixCommand(title string, a0 ApplyFixArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.apply_fix",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewCheckUpgradesCommand(title string, a0 CheckUpgradesArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.check_upgrades",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewGCDetailsCommand(title string, a0 protocol.DocumentURI) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.gc_details",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewGenerateCommand(title string, a0 GenerateArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.generate",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewGenerateGoplsModCommand(title string, a0 URIArg) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.generate_gopls_mod",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewGoGetPackageCommand(title string, a0 GoGetPackageArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.go_get_package",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewRegenerateCgoCommand(title string, a0 URIArg) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.regenerate_cgo",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewRemoveDependencyCommand(title string, a0 RemoveDependencyArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.remove_dependency",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewRunTestsCommand(title string, a0 RunTestsArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.run_tests",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewTestCommand(title string, a0 protocol.DocumentURI, a1 []string, a2 []string) (protocol.Command, error) {
+ args, err := MarshalArgs(a0, a1, a2)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.test",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewTidyCommand(title string, a0 URIArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.tidy",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewToggleGCDetailsCommand(title string, a0 URIArg) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.toggle_gc_details",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewUpdateGoSumCommand(title string, a0 URIArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.update_go_sum",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewUpgradeDependencyCommand(title string, a0 DependencyArgs) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.upgrade_dependency",
+ Arguments: args,
+ }, nil
+ }
+
+ func NewVendorCommand(title string, a0 URIArg) (protocol.Command, error) {
+ args, err := MarshalArgs(a0)
+ if err != nil {
+ return protocol.Command{}, err
+ }
+ return protocol.Command{
+ Title: title,
+ Command: "gopls.vendor",
+ Arguments: args,
+ }, nil
+ }
+
The name of the file: internal/lsp/command/interface.go
Insertions: 189, Deletions: 0.
@@ +0:190 @@
+ // Copyright 2021 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 command defines the interface provided by gopls for the
+ // workspace/executeCommand LSP request.
+ //
+ // This interface is fully specified by the Interface type, provided it
+ // conforms to the restrictions outlined in its doc string.
+ //
+ // Bindings for server-side command dispatch and client-side serialization are
+ // also provided by this package, via code generation.
+ package command
+
+ //go:generate go run -tags=generate generate.go
+
+ import (
+ "context"
+
+ "
golang.org/x/tools/internal/lsp/protocol"
+ )
+
+ // Interface defines the interface gopls exposes for the
+ // workspace/executeCommand request.
+ //
+ // This interface is used to generate marshaling/unmarshaling code, dispatch,
+ // and documentation, and so has some additional restrictions:
+ // 1. All method arguments must be JSON serializable.
+ // 2. Methods must return either error or (T, error), where T is a
+ // JSON serializable type.
+ // 3. The first line of the doc string is special. Everything after the colon
+ // is considered the command 'Title'.
+ // TODO(rFindley): reconsider this -- Title may be unnecessary.
+ type Interface interface {
+ // ApplyFix: Apply a fix
+ //
+ // Applies a fix to a region of source code.
+ ApplyFix(context.Context, ApplyFixArgs) error
+ // Test: Run test(s) (legacy)
+ //
+ // Runs `go test` for a specific set of test or benchmark functions.
+ Test(context.Context, protocol.DocumentURI, []string, []string) error
+
+ // TODO: deprecate Test in favor of RunTests below.
+
+ // Test: Run test(s)
+ //
+ // Runs `go test` for a specific set of test or benchmark functions.
+ RunTests(context.Context, RunTestsArgs) error
+
+ // Generate: Run go generate
+ //
+ // Runs `go generate` for a given directory.
+ Generate(context.Context, GenerateArgs) error
+
+ // RegenerateCgo: Regenerate cgo
+ //
+ // Regenerates cgo definitions.
+ RegenerateCgo(context.Context, URIArg) error
+
+ // Tidy: Run go mod tidy
+ //
+ // Runs `go mod tidy` for a module.
+ Tidy(context.Context, URIArgs) error
+
+ // Vendor: Run go mod vendor
+ //
+ // Runs `go mod vendor` for a module.
+ Vendor(context.Context, URIArg) error
+
+ // UpdateGoSum: Update go.sum
+ //
+ // Updates the go.sum file for a module.
+ UpdateGoSum(context.Context, URIArgs) error
+
+ // CheckUpgrades: Check for upgrades
+ //
+ // Checks for module upgrades.
+ CheckUpgrades(context.Context, CheckUpgradesArgs) error
+
+ // AddDependency: Add dependency
+ //
+ // Adds a dependency to the go.mod file for a module.
+ AddDependency(context.Context, DependencyArgs) error
+
+ // UpgradeDependency: Upgrade dependency
+ //
+ // Upgrades a dependency in the go.mod file for a module.
+ UpgradeDependency(context.Context, DependencyArgs) error
+
+ // RemoveDependency: Remove dependency
+ //
+ // Removes a dependency from the go.mod file of a module.
+ RemoveDependency(context.Context, RemoveDependencyArgs) error
+
+ // GoGetPackage: go get package
+ //
+ // Runs `go get` to fetch a package.
+ GoGetPackage(context.Context, GoGetPackageArgs) error
+
+ // GCDetails: Toggle gc_details
+ //
+ // Toggle the calculation of gc annotations.
+ GCDetails(context.Context, protocol.DocumentURI) error
+
+ // TODO: deprecate GCDetails in favor of ToggleGCDetails below.
+
+ // ToggleGCDetails: Toggle gc_details
+ //
+ // Toggle the calculation of gc annotations.
+ ToggleGCDetails(context.Context, URIArg) error
+
+ // GenerateGoplsMod: Generate gopls.mod
+ //
+ // (Re)generate the gopls.mod file for a workspace.
+ GenerateGoplsMod(context.Context, URIArg) error
+ }
+
+ type RunTestsArgs struct {
+ // The test file containing the tests to run.
+ URI protocol.DocumentURI
+
+ // Specific test names to run, e.g. TestFoo.
+ Tests []string
+
+ // Specific benchmarks to run, e.g. BenchmarkFoo.
+ Benchmarks []string
+ }
+
+ type GenerateArgs struct {
+ // URI for the directory to generate.
+ Dir protocol.DocumentURI
+
+ // Whether to generate recursively (go generate ./...)
+ Recursive bool
+ }
+
+ // TODO(rFindley): document the rest of these once the docgen is fleshed out.
+
+ type ApplyFixArgs struct {
+ // The fix to apply.
+ Fix string
+ // The file URI for the document to fix.
+ URI protocol.DocumentURI
+ // The document range to scan for fixes.
+ Range protocol.Range
+ }
+
+ type URIArg struct {
+ // The file URI.
+ URI protocol.DocumentURI
+ }
+
+ type URIArgs struct {
+ // The file URI.
+ URIs []protocol.DocumentURI
+ }
+
+ type CheckUpgradesArgs struct {
+ // The go.mod file URI.
+ URI protocol.DocumentURI
+ // The modules to check.
+ Modules []string
+ }
+
+ type DependencyArgs struct {
+ // The go.mod file URI.
+ URI protocol.DocumentURI
+ // Additional args to pass to the go command.
+ GoCmdArgs []string
+ // Whether to add a require directive.
+ AddRequire bool
+ }
+
+ type RemoveDependencyArgs struct {
+ // The go.mod file URI.
+ URI protocol.DocumentURI
+ // The module path to remove.
+ ModulePath string
+ OnlyDiagnostic bool
+ }
+
+ type GoGetPackageArgs struct {
+ // Any document URI within the relevant module.
+ URI protocol.DocumentURI
+ // The package to go get.
+ Pkg string
+ AddRequire bool
+ }
+
The name of the file: internal/lsp/fake/editor.go
Insertions: 23, Deletions: 14.
@@ +17:18 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -18:19 @@
- "
golang.org/x/tools/internal/lsp/source"
@@ -756:772, +756:765 @@
- func (e *Editor) codeAction(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) error {
- if e.Server == nil {
- return nil
- }
- params := &protocol.CodeActionParams{}
- params.TextDocument.URI = e.sandbox.Workdir.URI(path)
- params.Context.Only = only
- if diagnostics != nil {
- params.Context.Diagnostics = diagnostics
- }
- if rng != nil {
- params.Range = *rng
- }
- actions, err := e.Server.CodeAction(ctx, params)
- if err != nil {
- return errors.Errorf("textDocument/codeAction: %w", err)
+ // GetQuickFixes returns the available quick fix code actions.
+ func (e *Editor) GetQuickFixes(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) {
+ return e.getCodeActions(ctx, path, rng, diagnostics, protocol.QuickFix, protocol.SourceFixAll)
+ }
+
+ func (e *Editor) codeAction(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) error {
+ actions, err := e.getCodeActions(ctx, path, rng, diagnostics, only...)
+ if err != nil {
+ return err
@@ +809:825 @@
+ func (e *Editor) getCodeActions(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) ([]protocol.CodeAction, error) {
+ if e.Server == nil {
+ return nil, nil
+ }
+ params := &protocol.CodeActionParams{}
+ params.TextDocument.URI = e.sandbox.Workdir.URI(path)
+ params.Context.Only = only
+ if diagnostics != nil {
+ params.Context.Diagnostics = diagnostics
+ }
+ if rng != nil {
+ params.Range = *rng
+ }
+ return e.Server.CodeAction(ctx, params)
+ }
+
@@ +903:904 @@
+ // TODO(rFindley): this shouldn't be necessary anymore. Delete it.
@@ -899:900, +909:913 @@
- jsonArgs, err := source.MarshalArgs(span.URIFromPath(absDir), false)
+ cmd, err := command.NewGenerateCommand("", command.GenerateArgs{
+ Dir: protocol.URIFromSpanURI(span.URIFromPath(absDir)),
+ Recursive: false,
+ })
@@ -904:906, +917:919 @@
- Command:
source.CommandGenerate.ID(),
- Arguments: jsonArgs,
+ Command: cmd.Command,
+ Arguments: cmd.Arguments,
The name of the file: internal/lsp/mod/code_lens.go
Insertions: 2, Deletions: 1.
@@ +13:14 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -19:24, +20:25 @@
- func LensFuncs() map[string]source.LensFunc {
- return map[string]source.LensFunc{
-
source.CommandUpgradeDependency.Name: upgradeLenses,
-
source.CommandTidy.Name: tidyLens,
-
source.CommandVendor.Name: vendorLens,
+ func LensFuncs() map[command.Command]source.LensFunc {
+ return map[command.Command]source.LensFunc{
+ command.UpgradeDependency: upgradeLenses,
+ command.Tidy: tidyLens,
+ command.Vendor: vendorLens,
@@ -36:40 @@
- upgradeTransitiveArgs, err := source.MarshalArgs(fh.URI(), false, []string{"-u", "all"})
- if err != nil {
- return nil, err
- }
@@ -44:45, +41:46 @@
- checkUpgradeArgs, err := source.MarshalArgs(fh.URI(), requires)
+ uri := protocol.URIFromSpanURI(fh.URI())
+ checkUpgrade, err := command.NewCheckUpgradesCommand("Check for upgrades", command.CheckUpgradesArgs{
+ URI: uri,
+ Modules: requires,
+ })
@@ -48:49, +49:62 @@
- upgradeDirectArgs, err := source.MarshalArgs(fh.URI(), false, requires)
+ upgradeTransitive, err := command.NewUpgradeDependencyCommand("Upgrade transitive dependencies", command.DependencyArgs{
+ URI: uri,
+ AddRequire: false,
+ GoCmdArgs: []string{"-u", "all"},
+ })
+ if err != nil {
+ return nil, err
+ }
+ upgradeDirect, err := command.NewUpgradeDependencyCommand("Upgrade direct dependencies", command.DependencyArgs{
+ URI: uri,
+ AddRequire: false,
+ GoCmdArgs: requires,
+ })
@@ -59:83, +72:75 @@
- {
- Range: rng,
- Command: protocol.Command{
- Title: "Check for upgrades",
- Command:
source.CommandCheckUpgrades.ID(),
- Arguments: checkUpgradeArgs,
- },
- },
- {
- Range: rng,
- Command: protocol.Command{
- Title: "Upgrade transitive dependencies",
- Command:
source.CommandUpgradeDependency.ID(),
- Arguments: upgradeTransitiveArgs,
- },
- },
- {
- Range: rng,
- Command: protocol.Command{
- Title: "Upgrade direct dependencies",
- Command:
source.CommandUpgradeDependency.ID(),
- Arguments: upgradeDirectArgs,
- },
- },
+ {Range: rng, Command: checkUpgrade},
+ {Range: rng, Command: upgradeTransitive},
+ {Range: rng, Command: upgradeDirect},
@@ -95:96, +87:89 @@
- goModArgs, err := source.MarshalArgs(fh.URI())
+ uri := protocol.URIFromSpanURI(fh.URI())
+ cmd, err := command.NewTidyCommand("Run go mod tidy", command.URIArgs{URIs: []protocol.DocumentURI{uri}})
@@ -104:110, +97:99 @@
- Range: rng,
- Command: protocol.Command{
- Title: source.CommandTidy.Title,
- Command:
source.CommandTidy.ID(),
- Arguments: goModArgs,
- },
+ Range: rng,
+ Command: cmd,
@@ -122:123, +111:114 @@
- goModArgs, err := source.MarshalArgs(fh.URI())
+ title := "Create vendor directory"
+ uri := protocol.URIFromSpanURI(fh.URI())
+ cmd, err := command.NewVendorCommand(title, command.URIArg{URI: uri})
@@ -128:129 @@
- title := "Create vendor directory"
@@ -133:141, +123:124 @@
- return []protocol.CodeLens{{
- Range: rng,
- Command: protocol.Command{
- Title: title,
- Command:
source.CommandVendor.ID(),
- Arguments: goModArgs,
- },
- }}, nil
+ return []protocol.CodeLens{{Range: rng, Command: cmd}}, nil
The name of the file: internal/lsp/mod/diagnostics.go
Insertions: 7, Deletions: 2.
@@ +13:14 @@
+ "
golang.org/x/tools/internal/lsp/command"
@@ -67:68, +68:74 @@
- args, err := source.MarshalArgs(fh.URI(), false, []string{req.Mod.Path + "@" + ver})
+ title := fmt.Sprintf("Upgrade to %v", ver)
+ cmd, err := command.NewUpgradeDependencyCommand(title, command.DependencyArgs{
+ URI: protocol.URIFromSpanURI(fh.URI()),
+ AddRequire: false,
+ GoCmdArgs: []string{req.Mod.Path + "@" + ver},
+ })
@@ -72:85, +78:84 @@
- URI: fh.URI(),
- Range: rng,
- Severity: protocol.SeverityInformation,
- Source: source.UpgradeNotification,
- Message: fmt.Sprintf("%v can be upgraded", req.Mod.Path),
- SuggestedFixes: []source.SuggestedFix{{
- Title: fmt.Sprintf("Upgrade to %v", ver),
- Command: &protocol.Command{
- Title: fmt.Sprintf("Upgrade to %v", ver),
- Command:
source.CommandUpgradeDependency.ID(),
- Arguments: args,
- },
- }},
+ URI: fh.URI(),
+ Range: rng,
+ Severity: protocol.SeverityInformation,
+ Source: source.UpgradeNotification,
+ Message: fmt.Sprintf("%v can be upgraded", req.Mod.Path),
+ SuggestedFixes: []source.SuggestedFix{source.SuggestedFixFromCommand(cmd)},
@@ -88:89, +87:101 @@
- tidied, err := snapshot.ModTidy(ctx, pm)
+ // Packages in the workspace can contribute diagnostics to go.mod files.
+ wspkgs, err := snapshot.WorkspacePackages(ctx)
+ if err != nil && !source.IsNonFatalGoModError(err) {
+ event.Error(ctx, "diagnosing go.mod", err)
+ }
+ if err == nil {
+ for _, pkg := range wspkgs {
+ for _, diag := range pkg.GetDiagnostics() {
+ if diag.URI == fh.URI() {
+ diagnostics = append(diagnostics, diag)
+ }
+ }
+ }
+ }
@@ -90:92, +102:105 @@
- if source.IsNonFatalGoModError(err) {
- return diagnostics, nil
+ tidied, err := snapshot.ModTidy(ctx, pm)
+ if err != nil && !source.IsNonFatalGoModError(err) {
+ event.Error(ctx, "diagnosing go.mod", err)
@@ -93:95, +106:113 @@
- if err != nil {
- return nil, err
+ if err == nil {
+ for _, d := range tidied.Diagnostics {
+ if d.URI != fh.URI() {
+ continue
+ }
+ diagnostics = append(diagnostics, d)
+ }
@@ -96:97 @@
- diagnostics = append(diagnostics, tidied.Diagnostics...)
The name of the file: internal/lsp/source/api_json.go
Insertions: 62, Deletions: 1.
@@ +578:583 @@
+ Name: "\"gc_details\"",
+ Doc: "Toggle the calculation of gc annotations.",
+ Default: "false",
+ },
+ {
@@ -579:580, +584:585 @@
- Doc: "generate runs `go generate` for a given directory.\n",
+ Doc: "Runs `go generate` for a given directory.",
@@ -584:585, +589:590 @@
- Doc: "regenerate_cgo regenerates cgo definitions.\n",
+ Doc: "Regenerates cgo definitions.",
@@ -589:590, +594:595 @@
- Doc: "test runs `go test` for a specific test function.\n",
+ Doc: "Runs `go test` for a specific set of test or benchmark functions.",
@@ -594:595, +599:600 @@
- Doc: "tidy runs `go mod tidy` for a module.\n",
+ Doc: "Runs `go mod tidy` for a module.",
@@ -599:600, +604:605 @@
- Doc: "upgrade_dependency upgrades a dependency.\n",
+ Doc: "Upgrades a dependency in the go.mod file for a module.",
@@ -604:605, +609:610 @@
- Doc: "vendor runs `go mod vendor` for a module.\n",
+ Doc: "Runs `go mod vendor` for a module.",
@@ -607:612 @@
- {
- Name: "\"gc_details\"",
- Doc: "gc_details controls calculation of gc annotations.\n",
- Default: "false",
- },
@@ -675:678, +675:679 @@
- Command: "gopls.generate",
- Title: "Run go generate",
- Doc: "generate runs `go generate` for a given directory.\n",
+ Command: "gopls.add_dependency",
+ Title: "Add dependency",
+ Doc: "Adds a dependency to the go.mod file for a module.",
+ ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// Additional args to pass to the go command.\n\t\"GoCmdArgs\": []string,\n\t// Whether to add a require directive.\n\t\"AddRequire\": bool,\n}",
@@ -680:713, +681:685 @@
- Command: "gopls.fill_struct",
- Title: "Fill struct",
- Doc: "fill_struct is a gopls command to fill a struct with default\nvalues.\n",
- },
- {
- Command: "gopls.regenerate_cgo",
- Title: "Regenerate cgo",
- Doc: "regenerate_cgo regenerates cgo definitions.\n",
- },
- {
- Command: "gopls.test",
- Title: "Run test(s)",
- Doc: "test runs `go test` for a specific test function.\n",
- },
- {
- Command: "gopls.tidy",
- Title: "Run go mod tidy",
- Doc: "tidy runs `go mod tidy` for a module.\n",
- },
- {
- Command: "gopls.update_go_sum",
- Title: "Update go.sum",
- Doc: "update_go_sum updates the go.sum file for a module.\n",
- },
- {
- Command: "gopls.undeclared_name",
- Title: "Undeclared name",
- Doc: "undeclared_name adds a variable declaration for an undeclared\nname.\n",
- },
- {
- Command: "gopls.go_get_package",
- Title: "go get package",
- Doc: "go_get_package runs `go get` to fetch a package.\n",
+ Command: "gopls.apply_fix",
+ Title: "Apply a fix",
+ Doc: "Applies a fix to a region of source code.",
+ ArgDoc: "{\n\t// The fix to apply.\n\t\"Fix\": string,\n\t// The file URI for the document to fix.\n\t\"URI\": string,\n\t// The document range to scan for fixes.\n\t\"Range\": {\n\t\t\"start\": {\n\t\t\t\"line\": uint32,\n\t\t\t\"character\": uint32,\n\t\t},\n\t\t\"end\": {\n\t\t\t\"line\": uint32,\n\t\t\t\"character\": uint32,\n\t\t},\n\t},\n}",
@@ -717:748, +689:691 @@
- Doc: "check_upgrades checks for module upgrades.\n",
- },
- {
- Command: "gopls.add_dependency",
- Title: "Add dependency",
- Doc: "add_dependency adds a dependency.\n",
- },
- {
- Command: "gopls.upgrade_dependency",
- Title: "Upgrade dependency",
- Doc: "upgrade_dependency upgrades a dependency.\n",
- },
- {
- Command: "gopls.remove_dependency",
- Title: "Remove dependency",
- Doc: "remove_dependency removes a dependency.\n",
- },
- {
- Command: "gopls.vendor",
- Title: "Run go mod vendor",
- Doc: "vendor runs `go mod vendor` for a module.\n",
- },
- {
- Command: "gopls.extract_variable",
- Title: "Extract to variable",
- Doc: "extract_variable extracts an expression to a variable.\n",
- },
- {
- Command: "gopls.extract_function",
- Title: "Extract to function",
- Doc: "extract_function extracts statements to a function.\n",
+ Doc: "Checks for module upgrades.",
+ ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The modules to check.\n\t\"Modules\": []string,\n}",
@@ -752:753, +695:703 @@
- Doc: "gc_details controls calculation of gc annotations.\n",
+ Doc: "Toggle the calculation of gc annotations.",
+ ArgDoc: "string",
+ },
+ {
+ Command: "gopls.generate",
+ Title: "Run go generate",
+ Doc: "Runs `go generate` for a given directory.",
+ ArgDoc: "{\n\t// URI for the directory to generate.\n\t\"Dir\": string,\n\t// Whether to generate recursively (go generate ./...)\n\t\"Recursive\": bool,\n}",
@@ -757:758, +707:769 @@
- Doc: "generate_gopls_mod (re)generates the gopls.mod file.\n",
+ Doc: "(Re)generate the gopls.mod file for a workspace.",
+ ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}",
+ },
+ {
+ Command: "gopls.go_get_package",
+ Title: "go get package",
+ Doc: "Runs `go get` to fetch a package.",
+ ArgDoc: "{\n\t// Any document URI within the relevant module.\n\t\"URI\": string,\n\t// The package to go get.\n\t\"Pkg\": string,\n\t\"AddRequire\": bool,\n}",
+ },
+ {
+ Command: "gopls.regenerate_cgo",
+ Title: "Regenerate cgo",
+ Doc: "Regenerates cgo definitions.",
+ ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}",
+ },
+ {
+ Command: "gopls.remove_dependency",
+ Title: "Remove dependency",
+ Doc: "Removes a dependency from the go.mod file of a module.",
+ ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The module path to remove.\n\t\"ModulePath\": string,\n\t\"OnlyDiagnostic\": bool,\n}",
+ },
+ {
+ Command: "gopls.run_tests",
+ Title: "Run test(s)",
+ Doc: "Runs `go test` for a specific set of test or benchmark functions.",
+ ArgDoc: "{\n\t// The test file containing the tests to run.\n\t\"URI\": string,\n\t// Specific test names to run, e.g. TestFoo.\n\t\"Tests\": []string,\n\t// Specific benchmarks to run, e.g. BenchmarkFoo.\n\t\"Benchmarks\": []string,\n}",
+ },
+ {
+ Command: "gopls.test",
+ Title: "Run test(s) (legacy)",
+ Doc: "Runs `go test` for a specific set of test or benchmark functions.",
+ ArgDoc: "string,\n[]string,\n[]string",
+ },
+ {
+ Command: "gopls.tidy",
+ Title: "Run go mod tidy",
+ Doc: "Runs `go mod tidy` for a module.",
+ ArgDoc: "{\n\t// The file URI.\n\t\"URIs\": []string,\n}",
+ },
+ {
+ Command: "gopls.toggle_gc_details",
+ Title: "Toggle gc_details",
+ Doc: "Toggle the calculation of gc annotations.",
+ ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}",
+ },
+ {
+ Command: "gopls.update_go_sum",
+ Title: "Update go.sum",
+ Doc: "Updates the go.sum file for a module.",
+ ArgDoc: "{\n\t// The file URI.\n\t\"URIs\": []string,\n}",
+ },
+ {
+ Command: "gopls.upgrade_dependency",
+ Title: "Upgrade dependency",
+ Doc: "Upgrades a dependency in the go.mod file for a module.",
+ ArgDoc: "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// Additional args to pass to the go command.\n\t\"GoCmdArgs\": []string,\n\t// Whether to add a require directive.\n\t\"AddRequire\": bool,\n}",
+ },
+ {
+ Command: "gopls.vendor",
+ Title: "Run go mod vendor",
+ Doc: "Runs `go mod vendor` for a module.",
+ ArgDoc: "{\n\t// The file URI.\n\t\"URI\": string,\n}",
@@ +773:778 @@
+ Lens: "gc_details",
+ Title: "Toggle gc_details",
+ Doc: "Toggle the calculation of gc annotations.",
+ },
+ {
@@ -764:765, +780:781 @@
- Doc: "generate runs `go generate` for a given directory.\n",
+ Doc: "Runs `go generate` for a given directory.",
@@ -769:770, +785:786 @@
- Doc: "regenerate_cgo regenerates cgo definitions.\n",
+ Doc: "Regenerates cgo definitions.",
@@ -773:775, +789:791 @@
- Title: "Run test(s)",
- Doc: "test runs `go test` for a specific test function.\n",
+ Title: "Run test(s) (legacy)",
+ Doc: "Runs `go test` for a specific set of test or benchmark functions.",
@@ -779:780, +795:796 @@
- Doc: "tidy runs `go mod tidy` for a module.\n",
+ Doc: "Runs `go mod tidy` for a module.",
@@ -784:785, +800:801 @@
- Doc: "upgrade_dependency upgrades a dependency.\n",
+ Doc: "Upgrades a dependency in the go.mod file for a module.",
@@ -789:795, +805:806 @@
- Doc: "vendor runs `go mod vendor` for a module.\n",
- },
- {
- Lens: "gc_details",
- Title: "Toggle gc_details",
- Doc: "gc_details controls calculation of gc annotations.\n",
+ Doc: "Runs `go mod vendor` for a module.",