internal/lsp, gopls: require a "gopls_" prefix on all commands

Updated the generator to check for this. Necessary to fix command name
collision in VS Code Go. Not the nicest solution, but seemed like the
least invasive one.

The codelens configuration is a little strange now, with the "gopls_"
prefixes, but the alternative is adding the prefix when processing the
config and that would make the default look different from the example.

Fixes golang/go#41187

Change-Id: I5cf42f4a96f6252016dcd5c40a4ac401e1b30a8f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/259204
Trust: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/gopls/doc/commands.md b/gopls/doc/commands.md
index f95358b..5aad84a 100644
--- a/gopls/doc/commands.md
+++ b/gopls/doc/commands.md
@@ -9,7 +9,7 @@
 generate runs `go generate` for a given directory.
 
 
-### **fill_struct**
+### **Fill struct**
 Identifier: `fill_struct`
 
 fill_struct is a gopls command to fill a struct with default
@@ -34,7 +34,7 @@
 tidy runs `go mod tidy` for a module.
 
 
-### **undeclared_name**
+### **Undeclared name**
 Identifier: `undeclared_name`
 
 undeclared_name adds a variable declaration for an undeclared
diff --git a/gopls/doc/implementation.md b/gopls/doc/implementation.md
index 1b0f531..a8f7f0b 100644
--- a/gopls/doc/implementation.md
+++ b/gopls/doc/implementation.md
@@ -46,4 +46,3 @@
 [internal/memoize]: https://github.com/golang/tools/tree/master/internal/memoize
 [internal/span]: https://github.com/golang/tools/tree/master/internal/span
 [x/tools]: https://github.com/golang/tools
-
diff --git a/gopls/internal/regtest/codelens_test.go b/gopls/internal/regtest/codelens_test.go
index d0af635..2fb0f71 100644
--- a/gopls/internal/regtest/codelens_test.go
+++ b/gopls/internal/regtest/codelens_test.go
@@ -50,7 +50,9 @@
 	for _, test := range tests {
 		t.Run(test.label, func(t *testing.T) {
 			withOptions(
-				EditorConfig{CodeLens: test.enabled},
+				EditorConfig{
+					CodeLens: test.enabled,
+				},
 			).run(t, workspace, func(t *testing.T, env *Env) {
 				env.OpenFile("lib.go")
 				lens := env.CodeLens("lib.go")
@@ -251,7 +253,10 @@
 }
 `
 	withOptions(
-		EditorConfig{CodeLens: map[string]bool{"gc_details": true}},
+		EditorConfig{
+			CodeLens: map[string]bool{
+				"gc_details": true,
+			}},
 	).run(t, mod, func(t *testing.T, env *Env) {
 		env.OpenFile("main.go")
 		env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
diff --git a/gopls/internal/regtest/wrappers.go b/gopls/internal/regtest/wrappers.go
index dce92ca..a31fe2a 100644
--- a/gopls/internal/regtest/wrappers.go
+++ b/gopls/internal/regtest/wrappers.go
@@ -275,13 +275,13 @@
 	var lens protocol.CodeLens
 	var found bool
 	for _, l := range lenses {
-		if l.Command.Command == cmd.Name {
+		if l.Command.Command == cmd.ID() {
 			lens = l
 			found = true
 		}
 	}
 	if !found {
-		e.T.Fatalf("found no command with the title %s", cmd.Name)
+		e.T.Fatalf("found no command with the ID %s", cmd.ID())
 	}
 	if _, err := e.Editor.Server.ExecuteCommand(e.Ctx, &protocol.ExecuteCommandParams{
 		Command:   lens.Command.Command,
diff --git a/internal/lsp/cmd/workspace.go b/internal/lsp/cmd/workspace.go
index 1c1151b..88531a7 100644
--- a/internal/lsp/cmd/workspace.go
+++ b/internal/lsp/cmd/workspace.go
@@ -82,7 +82,7 @@
 		return err
 	}
 	defer conn.terminate(ctx)
-	params := &protocol.ExecuteCommandParams{Command: source.CommandGenerateGoplsMod.Name}
+	params := &protocol.ExecuteCommandParams{Command: source.CommandGenerateGoplsMod.ID()}
 	if _, err := conn.ExecuteCommand(ctx, params); err != nil {
 		return fmt.Errorf("executing server command: %v", err)
 	}
diff --git a/internal/lsp/code_action.go b/internal/lsp/code_action.go
index 549cea0..3da9d83 100644
--- a/internal/lsp/code_action.go
+++ b/internal/lsp/code_action.go
@@ -400,7 +400,7 @@
 		Kind:        kind,
 		Diagnostics: diagnostics,
 		Command: &protocol.Command{
-			Command:   analyzer.Command.Name,
+			Command:   analyzer.Command.ID(),
 			Title:     e.Message,
 			Arguments: jsonArgs,
 		},
@@ -431,7 +431,7 @@
 			Title: command.Title,
 			Kind:  protocol.RefactorExtract,
 			Command: &protocol.Command{
-				Command:   command.Name,
+				Command:   command.ID(),
 				Arguments: jsonArgs,
 			},
 		})
diff --git a/internal/lsp/command.go b/internal/lsp/command.go
index 546372f..7292642 100644
--- a/internal/lsp/command.go
+++ b/internal/lsp/command.go
@@ -24,7 +24,7 @@
 func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCommandParams) (interface{}, error) {
 	var command *source.Command
 	for _, c := range source.Commands {
-		if c.Name == params.Command {
+		if c.ID() == params.Command {
 			command = c
 			break
 		}
@@ -40,7 +40,7 @@
 		}
 	}
 	if !match {
-		return nil, fmt.Errorf("%s is not a supported command", command.Name)
+		return nil, fmt.Errorf("%s is not a supported command", command.ID())
 	}
 	title := command.Title
 	if title == "" {
@@ -57,7 +57,7 @@
 	}
 	if unsaved {
 		switch params.Command {
-		case source.CommandTest.Name, source.CommandGenerate.Name, source.CommandToggleDetails.Name:
+		case source.CommandTest.ID(), source.CommandGenerate.ID(), source.CommandToggleDetails.ID():
 			// TODO(PJW): for Toggle, not an error if it is being disabled
 			err := errors.New("unsaved files in the view")
 			s.showCommandError(ctx, title, err)
@@ -95,7 +95,7 @@
 			// message is typically dismissed immediately by LSP clients.
 			s.showCommandError(ctx, title, err)
 		default:
-			work.end(command.Name + ": completed")
+			work.end(command.ID() + ": completed")
 		}
 	}()
 	return nil, nil
@@ -252,7 +252,7 @@
 			return errors.Errorf("writing mod file: %w", err)
 		}
 	default:
-		return fmt.Errorf("unsupported command: %s", command.Name)
+		return fmt.Errorf("unsupported command: %s", command.ID())
 	}
 	return nil
 }
diff --git a/internal/lsp/fake/editor.go b/internal/lsp/fake/editor.go
index 4cc8b13..c2389a5 100644
--- a/internal/lsp/fake/editor.go
+++ b/internal/lsp/fake/editor.go
@@ -782,7 +782,7 @@
 		return err
 	}
 	params := &protocol.ExecuteCommandParams{
-		Command:   source.CommandGenerate.Name,
+		Command:   source.CommandGenerate.ID(),
 		Arguments: jsonArgs,
 	}
 	if _, err := e.Server.ExecuteCommand(ctx, params); err != nil {
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 3bb180f..c4c4918 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -518,7 +518,7 @@
 func commandToEdits(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle, rng protocol.Range, cmd string) ([]protocol.TextDocumentEdit, error) {
 	var command *source.Command
 	for _, c := range source.Commands {
-		if c.Name == cmd {
+		if c.ID() == cmd {
 			command = c
 			break
 		}
@@ -527,7 +527,7 @@
 		return nil, fmt.Errorf("no known command for %s", cmd)
 	}
 	if !command.Applies(ctx, snapshot, fh, rng) {
-		return nil, fmt.Errorf("cannot apply %v", command.Name)
+		return nil, fmt.Errorf("cannot apply %v", command.ID())
 	}
 	return command.SuggestedFix(ctx, snapshot, fh, rng)
 }
diff --git a/internal/lsp/mod/code_lens.go b/internal/lsp/mod/code_lens.go
index a4d06b7..3b3533d 100644
--- a/internal/lsp/mod/code_lens.go
+++ b/internal/lsp/mod/code_lens.go
@@ -60,7 +60,7 @@
 			Range: rng,
 			Command: protocol.Command{
 				Title:     fmt.Sprintf("Upgrade dependency to %s", latest),
-				Command:   source.CommandUpgradeDependency.Name,
+				Command:   source.CommandUpgradeDependency.ID(),
 				Arguments: upgradeDepArgs,
 			},
 		})
@@ -82,7 +82,7 @@
 			Range: moduleRng,
 			Command: protocol.Command{
 				Title:     "Upgrade all dependencies",
-				Command:   source.CommandUpgradeDependency.Name,
+				Command:   source.CommandUpgradeDependency.ID(),
 				Arguments: upgradeDepArgs,
 			},
 		})
@@ -117,7 +117,7 @@
 		Range: rng,
 		Command: protocol.Command{
 			Title:     "Tidy module",
-			Command:   source.CommandTidy.Name,
+			Command:   source.CommandTidy.ID(),
 			Arguments: goModArgs,
 		},
 	}}, err
@@ -150,7 +150,7 @@
 		Range: rng,
 		Command: protocol.Command{
 			Title:     title,
-			Command:   source.CommandVendor.Name,
+			Command:   source.CommandVendor.ID(),
 			Arguments: goModArgs,
 		},
 	}}, nil
diff --git a/internal/lsp/source/api_json.go b/internal/lsp/source/api_json.go
index cc5ed6e..e52beb6 100755
--- a/internal/lsp/source/api_json.go
+++ b/internal/lsp/source/api_json.go
@@ -2,4 +2,4 @@
 
 package source
 
-const GeneratedAPIJSON = "{\"Options\":{\"Debugging\":[{\"Name\":\"verboseOutput\",\"Type\":\"bool\",\"Doc\":\"verboseOutput enables additional debug logging.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"completionBudget\",\"Type\":\"time.Duration\",\"Doc\":\"completionBudget is the soft latency goal for completion requests. Most\\nrequests finish in a couple milliseconds, but in some cases deep\\ncompletions can take much longer. As we use up our budget we\\ndynamically reduce the search scope to ensure we return timely\\nresults. Zero means unlimited.\\n\",\"EnumValues\":null,\"Default\":\"100000000\"}],\"Experimental\":[{\"Name\":\"analyses\",\"Type\":\"map[string]bool\",\"Doc\":\"analyses specify analyses that the user would like to enable or disable.\\nA map of the names of analysis passes that should be enabled/disabled.\\nA full list of analyzers that gopls uses can be found [here](analyzers.md)\\n\\nExample Usage:\\n```json5\\n...\\n\\\"analyses\\\": {\\n  \\\"unreachable\\\": false, // Disable the unreachable analyzer.\\n  \\\"unusedparams\\\": true  // Enable the unusedparams analyzer.\\n}\\n...\\n```\\n\",\"EnumValues\":null,\"Default\":\"{}\"},{\"Name\":\"codelens\",\"Type\":\"map[string]bool\",\"Doc\":\"codelens overrides the enabled/disabled state of code lenses. See the \\\"Code Lenses\\\"\\nsection of settings.md for the list of supported lenses.\\n\\nExample Usage:\\n```json5\\n\\\"gopls\\\": {\\n...\\n  \\\"codelens\\\": {\\n    \\\"generate\\\": false,  // Don't show the `go generate` lens.\\n    \\\"gc_details\\\": true  // Show a code lens toggling the display of gc's choices.\\n  }\\n...\\n}\\n```\\n\",\"EnumValues\":null,\"Default\":\"{\\\"gc_details\\\":false,\\\"generate\\\":true,\\\"regenerate_cgo\\\":true,\\\"tidy\\\":true,\\\"upgrade_dependency\\\":true,\\\"vendor\\\":true}\"},{\"Name\":\"completionDocumentation\",\"Type\":\"bool\",\"Doc\":\"completionDocumentation enables documentation with completion results.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"completeUnimported\",\"Type\":\"bool\",\"Doc\":\"completeUnimported enables completion for packages that you do not currently import.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"deepCompletion\",\"Type\":\"bool\",\"Doc\":\"deepCompletion enables the ability to return completions from deep inside relevant entities, rather than just the locally accessible ones.\\n\\nConsider this example:\\n\\n```go\\npackage main\\n\\nimport \\\"fmt\\\"\\n\\ntype wrapString struct {\\n    str string\\n}\\n\\nfunc main() {\\n    x := wrapString{\\\"hello world\\\"}\\n    fmt.Printf(\\u003c\\u003e)\\n}\\n```\\n\\nAt the location of the `\\u003c\\u003e` in this program, deep completion would suggest the result `x.str`.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"matcher\",\"Type\":\"enum\",\"Doc\":\"matcher sets the algorithm that is used when calculating completion candidates.\\n\",\"EnumValues\":[{\"Value\":\"\\\"CaseInsensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"CaseSensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Fuzzy\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"Fuzzy\\\"\"},{\"Name\":\"annotations\",\"Type\":\"map[string]bool\",\"Doc\":\"annotations suppress various kinds of optimization diagnostics\\nthat would be reported by the gc_details command.\\n * noNilcheck suppresses display of nilchecks.\\n * noEscape suppresses escape choices.\\n * noInline suppresses inlining choices.\\n * noBounds suppresses bounds checking diagnostics.\\n\",\"EnumValues\":null,\"Default\":\"{}\"},{\"Name\":\"staticcheck\",\"Type\":\"bool\",\"Doc\":\"staticcheck enables additional analyses from staticcheck.io.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"symbolMatcher\",\"Type\":\"enum\",\"Doc\":\"symbolMatcher sets the algorithm that is used when finding workspace symbols.\\n\",\"EnumValues\":[{\"Value\":\"\\\"CaseInsensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"CaseSensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Fuzzy\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"Fuzzy\\\"\"},{\"Name\":\"symbolStyle\",\"Type\":\"enum\",\"Doc\":\"symbolStyle controls how symbols are qualified in symbol responses.\\n\\nExample Usage:\\n```json5\\n\\\"gopls\\\": {\\n...\\n  \\\"symbolStyle\\\": \\\"dynamic\\\",\\n...\\n}\\n```\\n\",\"EnumValues\":[{\"Value\":\"\\\"Dynamic\\\"\",\"Doc\":\"`\\\"Dynamic\\\"` uses whichever qualifier results in the highest scoring\\nmatch for the given symbol query. Here a \\\"qualifier\\\" is any \\\"/\\\" or \\\".\\\"\\ndelimited suffix of the fully qualified symbol. i.e. \\\"to/pkg.Foo.Field\\\" or\\njust \\\"Foo.Field\\\".\\n\"},{\"Value\":\"\\\"Full\\\"\",\"Doc\":\"`\\\"Full\\\"` is fully qualified symbols, i.e.\\n\\\"path/to/pkg.Foo.Field\\\".\\n\"},{\"Value\":\"\\\"Package\\\"\",\"Doc\":\"`\\\"Package\\\"` is package qualified symbols i.e.\\n\\\"pkg.Foo.Field\\\".\\n\"}],\"Default\":\"\\\"Package\\\"\"},{\"Name\":\"linksInHover\",\"Type\":\"bool\",\"Doc\":\"linksInHover toggles the presence of links to documentation in hover.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"tempModfile\",\"Type\":\"bool\",\"Doc\":\"tempModfile controls the use of the -modfile flag in Go 1.14.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"importShortcut\",\"Type\":\"enum\",\"Doc\":\"importShortcut specifies whether import statements should link to\\ndocumentation or go to definitions.\\n\",\"EnumValues\":[{\"Value\":\"\\\"Both\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Definition\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Link\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"Both\\\"\"},{\"Name\":\"verboseWorkDoneProgress\",\"Type\":\"bool\",\"Doc\":\"verboseWorkDoneProgress controls whether the LSP server should send\\nprogress reports for all work done outside the scope of an RPC.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"semanticTokens\",\"Type\":\"bool\",\"Doc\":\"semanticTokens controls whether the LSP server will send\\nsemantic tokens to the client.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"expandWorkspaceToModule\",\"Type\":\"bool\",\"Doc\":\"expandWorkspaceToModule instructs `gopls` to expand the scope of the workspace to include the\\nmodules containing the workspace folders. Set this to false to avoid loading\\nyour entire module. This is particularly useful for those working in a monorepo.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"experimentalWorkspaceModule\",\"Type\":\"bool\",\"Doc\":\"experimentalWorkspaceModule opts a user into the experimental support\\nfor multi-module workspaces.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"literalCompletions\",\"Type\":\"bool\",\"Doc\":\"literalCompletions controls whether literal candidates such as\\n\\\"\\u0026someStruct{}\\\" are offered. Tests disable this flag to simplify\\ntheir expected values.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"experimentalDiagnosticsDelay\",\"Type\":\"time.Duration\",\"Doc\":\"experimentalDiagnosticsDelay controls the amount of time that gopls waits\\nafter the most recent file modification before computing deep diagnostics.\\nSimple diagnostics (parsing and type-checking) are always run immediately\\non recently modified packages.\\n\\nThis option must be set to a valid duration string, for example `\\\"250ms\\\"`.\\n\",\"EnumValues\":null,\"Default\":\"0\"},{\"Name\":\"experimentalPackageCacheKey\",\"Type\":\"bool\",\"Doc\":\"experimentalPackageCacheKey controls whether to use a coarser cache key\\nfor package type information to increase cache hits. This setting removes\\nthe user's environment, build flags, and working directory from the cache\\nkey, which should be a safe change as all relevant inputs into the type\\nchecking pass are already hashed into the key. This is temporarily guarded\\nby an experiment because caching behavior is subtle and difficult to\\ncomprehensively test.\\n\",\"EnumValues\":null,\"Default\":\"false\"}],\"User\":[{\"Name\":\"buildFlags\",\"Type\":\"[]string\",\"Doc\":\"buildFlags is the set of flags passed on to the build system when invoked.\\nIt is applied to queries like `go list`, which is used when discovering files.\\nThe most common use is to set `-tags`.\\n\",\"EnumValues\":null,\"Default\":\"[]\"},{\"Name\":\"env\",\"Type\":\"[]string\",\"Doc\":\"env adds environment variables to external commands run by `gopls`, most notably `go list`.\\n\",\"EnumValues\":null,\"Default\":\"[]\"},{\"Name\":\"hoverKind\",\"Type\":\"enum\",\"Doc\":\"hoverKind controls the information that appears in the hover text.\\nSingleLine and Structured are intended for use only by authors of editor plugins.\\n\",\"EnumValues\":[{\"Value\":\"\\\"FullDocumentation\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"NoDocumentation\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"SingleLine\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Structured\\\"\",\"Doc\":\"`\\\"Structured\\\"` is an experimental setting that returns a structured hover format.\\nThis format separates the signature from the documentation, so that the client\\ncan do more manipulation of these fields.\\n\\nThis should only be used by clients that support this behavior.\\n\"},{\"Value\":\"\\\"SynopsisDocumentation\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"FullDocumentation\\\"\"},{\"Name\":\"usePlaceholders\",\"Type\":\"bool\",\"Doc\":\"placeholders enables placeholders for function parameters or struct fields in completion responses.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"linkTarget\",\"Type\":\"string\",\"Doc\":\"linkTarget controls where documentation links go.\\nIt might be one of:\\n\\n* `\\\"godoc.org\\\"`\\n* `\\\"pkg.go.dev\\\"`\\n\\nIf company chooses to use its own `godoc.org`, its address can be used as well.\\n\",\"EnumValues\":null,\"Default\":\"\\\"pkg.go.dev\\\"\"},{\"Name\":\"local\",\"Type\":\"string\",\"Doc\":\"local is the equivalent of the `goimports -local` flag, which puts imports beginning with this string after 3rd-party packages.\\nIt should be the prefix of the import path whose imports should be grouped separately.\\n\",\"EnumValues\":null,\"Default\":\"\\\"\\\"\"},{\"Name\":\"gofumpt\",\"Type\":\"bool\",\"Doc\":\"gofumpt indicates if we should run gofumpt formatting.\\n\",\"EnumValues\":null,\"Default\":\"false\"}]},\"Commands\":[{\"Command\":\"generate\",\"Title\":\"Run go generate\",\"Doc\":\"generate runs `go generate` for a given directory.\\n\"},{\"Command\":\"fill_struct\",\"Title\":\"fill_struct\",\"Doc\":\"fill_struct is a gopls command to fill a struct with default\\nvalues.\\n\"},{\"Command\":\"regenerate_cgo\",\"Title\":\"Regenerate cgo\",\"Doc\":\"regenerate_cgo regenerates cgo definitions.\\n\"},{\"Command\":\"test\",\"Title\":\"Run test(s)\",\"Doc\":\"test runs `go test` for a specific test function.\\n\"},{\"Command\":\"tidy\",\"Title\":\"Run go mod tidy\",\"Doc\":\"tidy runs `go mod tidy` for a module.\\n\"},{\"Command\":\"undeclared_name\",\"Title\":\"undeclared_name\",\"Doc\":\"undeclared_name adds a variable declaration for an undeclared\\nname.\\n\"},{\"Command\":\"upgrade_dependency\",\"Title\":\"Upgrade dependency\",\"Doc\":\"upgrade_dependency upgrades a dependency.\\n\"},{\"Command\":\"vendor\",\"Title\":\"Run go mod vendor\",\"Doc\":\"vendor runs `go mod vendor` for a module.\\n\"},{\"Command\":\"extract_variable\",\"Title\":\"Extract to variable\",\"Doc\":\"extract_variable extracts an expression to a variable.\\n\"},{\"Command\":\"extract_function\",\"Title\":\"Extract to function\",\"Doc\":\"extract_function extracts statements to a function.\\n\"},{\"Command\":\"gc_details\",\"Title\":\"Toggle gc_details\",\"Doc\":\"gc_details controls calculation of gc annotations.\\n\"},{\"Command\":\"generate_gopls_mod\",\"Title\":\"Generate gopls.mod\",\"Doc\":\"generate_gopls_mod (re)generates the gopls.mod file.\\n\"}],\"Lenses\":[{\"Lens\":\"generate\",\"Title\":\"Run go generate\",\"Doc\":\"generate runs `go generate` for a given directory.\\n\"},{\"Lens\":\"regenerate_cgo\",\"Title\":\"Regenerate cgo\",\"Doc\":\"regenerate_cgo regenerates cgo definitions.\\n\"},{\"Lens\":\"test\",\"Title\":\"Run test(s)\",\"Doc\":\"test runs `go test` for a specific test function.\\n\"},{\"Lens\":\"tidy\",\"Title\":\"Run go mod tidy\",\"Doc\":\"tidy runs `go mod tidy` for a module.\\n\"},{\"Lens\":\"upgrade_dependency\",\"Title\":\"Upgrade dependency\",\"Doc\":\"upgrade_dependency upgrades a dependency.\\n\"},{\"Lens\":\"vendor\",\"Title\":\"Run go mod vendor\",\"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\"}]}"
+const GeneratedAPIJSON = "{\"Options\":{\"Debugging\":[{\"Name\":\"verboseOutput\",\"Type\":\"bool\",\"Doc\":\"verboseOutput enables additional debug logging.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"completionBudget\",\"Type\":\"time.Duration\",\"Doc\":\"completionBudget is the soft latency goal for completion requests. Most\\nrequests finish in a couple milliseconds, but in some cases deep\\ncompletions can take much longer. As we use up our budget we\\ndynamically reduce the search scope to ensure we return timely\\nresults. Zero means unlimited.\\n\",\"EnumValues\":null,\"Default\":\"100000000\"}],\"Experimental\":[{\"Name\":\"analyses\",\"Type\":\"map[string]bool\",\"Doc\":\"analyses specify analyses that the user would like to enable or disable.\\nA map of the names of analysis passes that should be enabled/disabled.\\nA full list of analyzers that gopls uses can be found [here](analyzers.md)\\n\\nExample Usage:\\n```json5\\n...\\n\\\"analyses\\\": {\\n  \\\"unreachable\\\": false, // Disable the unreachable analyzer.\\n  \\\"unusedparams\\\": true  // Enable the unusedparams analyzer.\\n}\\n...\\n```\\n\",\"EnumValues\":null,\"Default\":\"{}\"},{\"Name\":\"codelens\",\"Type\":\"map[string]bool\",\"Doc\":\"codelens overrides the enabled/disabled state of code lenses. See the \\\"Code Lenses\\\"\\nsection of settings.md for the list of supported lenses.\\n\\nExample Usage:\\n```json5\\n\\\"gopls\\\": {\\n...\\n  \\\"codelens\\\": {\\n    \\\"generate\\\": false,  // Don't show the `go generate` lens.\\n    \\\"gc_details\\\": true  // Show a code lens toggling the display of gc's choices.\\n  }\\n...\\n}\\n```\\n\",\"EnumValues\":null,\"Default\":\"{\\\"gc_details\\\":false,\\\"generate\\\":true,\\\"regenerate_cgo\\\":true,\\\"tidy\\\":true,\\\"upgrade_dependency\\\":true,\\\"vendor\\\":true}\"},{\"Name\":\"completionDocumentation\",\"Type\":\"bool\",\"Doc\":\"completionDocumentation enables documentation with completion results.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"completeUnimported\",\"Type\":\"bool\",\"Doc\":\"completeUnimported enables completion for packages that you do not currently import.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"deepCompletion\",\"Type\":\"bool\",\"Doc\":\"deepCompletion enables the ability to return completions from deep inside relevant entities, rather than just the locally accessible ones.\\n\\nConsider this example:\\n\\n```go\\npackage main\\n\\nimport \\\"fmt\\\"\\n\\ntype wrapString struct {\\n    str string\\n}\\n\\nfunc main() {\\n    x := wrapString{\\\"hello world\\\"}\\n    fmt.Printf(\\u003c\\u003e)\\n}\\n```\\n\\nAt the location of the `\\u003c\\u003e` in this program, deep completion would suggest the result `x.str`.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"matcher\",\"Type\":\"enum\",\"Doc\":\"matcher sets the algorithm that is used when calculating completion candidates.\\n\",\"EnumValues\":[{\"Value\":\"\\\"CaseInsensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"CaseSensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Fuzzy\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"Fuzzy\\\"\"},{\"Name\":\"annotations\",\"Type\":\"map[string]bool\",\"Doc\":\"annotations suppress various kinds of optimization diagnostics\\nthat would be reported by the gc_details command.\\n * noNilcheck suppresses display of nilchecks.\\n * noEscape suppresses escape choices.\\n * noInline suppresses inlining choices.\\n * noBounds suppresses bounds checking diagnostics.\\n\",\"EnumValues\":null,\"Default\":\"{}\"},{\"Name\":\"staticcheck\",\"Type\":\"bool\",\"Doc\":\"staticcheck enables additional analyses from staticcheck.io.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"symbolMatcher\",\"Type\":\"enum\",\"Doc\":\"symbolMatcher sets the algorithm that is used when finding workspace symbols.\\n\",\"EnumValues\":[{\"Value\":\"\\\"CaseInsensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"CaseSensitive\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Fuzzy\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"Fuzzy\\\"\"},{\"Name\":\"symbolStyle\",\"Type\":\"enum\",\"Doc\":\"symbolStyle controls how symbols are qualified in symbol responses.\\n\\nExample Usage:\\n```json5\\n\\\"gopls\\\": {\\n...\\n  \\\"symbolStyle\\\": \\\"dynamic\\\",\\n...\\n}\\n```\\n\",\"EnumValues\":[{\"Value\":\"\\\"Dynamic\\\"\",\"Doc\":\"`\\\"Dynamic\\\"` uses whichever qualifier results in the highest scoring\\nmatch for the given symbol query. Here a \\\"qualifier\\\" is any \\\"/\\\" or \\\".\\\"\\ndelimited suffix of the fully qualified symbol. i.e. \\\"to/pkg.Foo.Field\\\" or\\njust \\\"Foo.Field\\\".\\n\"},{\"Value\":\"\\\"Full\\\"\",\"Doc\":\"`\\\"Full\\\"` is fully qualified symbols, i.e.\\n\\\"path/to/pkg.Foo.Field\\\".\\n\"},{\"Value\":\"\\\"Package\\\"\",\"Doc\":\"`\\\"Package\\\"` is package qualified symbols i.e.\\n\\\"pkg.Foo.Field\\\".\\n\"}],\"Default\":\"\\\"Package\\\"\"},{\"Name\":\"linksInHover\",\"Type\":\"bool\",\"Doc\":\"linksInHover toggles the presence of links to documentation in hover.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"tempModfile\",\"Type\":\"bool\",\"Doc\":\"tempModfile controls the use of the -modfile flag in Go 1.14.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"importShortcut\",\"Type\":\"enum\",\"Doc\":\"importShortcut specifies whether import statements should link to\\ndocumentation or go to definitions.\\n\",\"EnumValues\":[{\"Value\":\"\\\"Both\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Definition\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Link\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"Both\\\"\"},{\"Name\":\"verboseWorkDoneProgress\",\"Type\":\"bool\",\"Doc\":\"verboseWorkDoneProgress controls whether the LSP server should send\\nprogress reports for all work done outside the scope of an RPC.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"semanticTokens\",\"Type\":\"bool\",\"Doc\":\"semanticTokens controls whether the LSP server will send\\nsemantic tokens to the client.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"expandWorkspaceToModule\",\"Type\":\"bool\",\"Doc\":\"expandWorkspaceToModule instructs `gopls` to expand the scope of the workspace to include the\\nmodules containing the workspace folders. Set this to false to avoid loading\\nyour entire module. This is particularly useful for those working in a monorepo.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"experimentalWorkspaceModule\",\"Type\":\"bool\",\"Doc\":\"experimentalWorkspaceModule opts a user into the experimental support\\nfor multi-module workspaces.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"literalCompletions\",\"Type\":\"bool\",\"Doc\":\"literalCompletions controls whether literal candidates such as\\n\\\"\\u0026someStruct{}\\\" are offered. Tests disable this flag to simplify\\ntheir expected values.\\n\",\"EnumValues\":null,\"Default\":\"true\"},{\"Name\":\"experimentalDiagnosticsDelay\",\"Type\":\"time.Duration\",\"Doc\":\"experimentalDiagnosticsDelay controls the amount of time that gopls waits\\nafter the most recent file modification before computing deep diagnostics.\\nSimple diagnostics (parsing and type-checking) are always run immediately\\non recently modified packages.\\n\\nThis option must be set to a valid duration string, for example `\\\"250ms\\\"`.\\n\",\"EnumValues\":null,\"Default\":\"0\"},{\"Name\":\"experimentalPackageCacheKey\",\"Type\":\"bool\",\"Doc\":\"experimentalPackageCacheKey controls whether to use a coarser cache key\\nfor package type information to increase cache hits. This setting removes\\nthe user's environment, build flags, and working directory from the cache\\nkey, which should be a safe change as all relevant inputs into the type\\nchecking pass are already hashed into the key. This is temporarily guarded\\nby an experiment because caching behavior is subtle and difficult to\\ncomprehensively test.\\n\",\"EnumValues\":null,\"Default\":\"false\"}],\"User\":[{\"Name\":\"buildFlags\",\"Type\":\"[]string\",\"Doc\":\"buildFlags is the set of flags passed on to the build system when invoked.\\nIt is applied to queries like `go list`, which is used when discovering files.\\nThe most common use is to set `-tags`.\\n\",\"EnumValues\":null,\"Default\":\"[]\"},{\"Name\":\"env\",\"Type\":\"[]string\",\"Doc\":\"env adds environment variables to external commands run by `gopls`, most notably `go list`.\\n\",\"EnumValues\":null,\"Default\":\"[]\"},{\"Name\":\"hoverKind\",\"Type\":\"enum\",\"Doc\":\"hoverKind controls the information that appears in the hover text.\\nSingleLine and Structured are intended for use only by authors of editor plugins.\\n\",\"EnumValues\":[{\"Value\":\"\\\"FullDocumentation\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"NoDocumentation\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"SingleLine\\\"\",\"Doc\":\"\"},{\"Value\":\"\\\"Structured\\\"\",\"Doc\":\"`\\\"Structured\\\"` is an experimental setting that returns a structured hover format.\\nThis format separates the signature from the documentation, so that the client\\ncan do more manipulation of these fields.\\n\\nThis should only be used by clients that support this behavior.\\n\"},{\"Value\":\"\\\"SynopsisDocumentation\\\"\",\"Doc\":\"\"}],\"Default\":\"\\\"FullDocumentation\\\"\"},{\"Name\":\"usePlaceholders\",\"Type\":\"bool\",\"Doc\":\"placeholders enables placeholders for function parameters or struct fields in completion responses.\\n\",\"EnumValues\":null,\"Default\":\"false\"},{\"Name\":\"linkTarget\",\"Type\":\"string\",\"Doc\":\"linkTarget controls where documentation links go.\\nIt might be one of:\\n\\n* `\\\"godoc.org\\\"`\\n* `\\\"pkg.go.dev\\\"`\\n\\nIf company chooses to use its own `godoc.org`, its address can be used as well.\\n\",\"EnumValues\":null,\"Default\":\"\\\"pkg.go.dev\\\"\"},{\"Name\":\"local\",\"Type\":\"string\",\"Doc\":\"local is the equivalent of the `goimports -local` flag, which puts imports beginning with this string after 3rd-party packages.\\nIt should be the prefix of the import path whose imports should be grouped separately.\\n\",\"EnumValues\":null,\"Default\":\"\\\"\\\"\"},{\"Name\":\"gofumpt\",\"Type\":\"bool\",\"Doc\":\"gofumpt indicates if we should run gofumpt formatting.\\n\",\"EnumValues\":null,\"Default\":\"false\"}]},\"Commands\":[{\"Command\":\"generate\",\"Title\":\"Run go generate\",\"Doc\":\"generate runs `go generate` for a given directory.\\n\"},{\"Command\":\"fill_struct\",\"Title\":\"Fill struct\",\"Doc\":\"fill_struct is a gopls command to fill a struct with default\\nvalues.\\n\"},{\"Command\":\"regenerate_cgo\",\"Title\":\"Regenerate cgo\",\"Doc\":\"regenerate_cgo regenerates cgo definitions.\\n\"},{\"Command\":\"test\",\"Title\":\"Run test(s)\",\"Doc\":\"test runs `go test` for a specific test function.\\n\"},{\"Command\":\"tidy\",\"Title\":\"Run go mod tidy\",\"Doc\":\"tidy runs `go mod tidy` for a module.\\n\"},{\"Command\":\"undeclared_name\",\"Title\":\"Undeclared name\",\"Doc\":\"undeclared_name adds a variable declaration for an undeclared\\nname.\\n\"},{\"Command\":\"upgrade_dependency\",\"Title\":\"Upgrade dependency\",\"Doc\":\"upgrade_dependency upgrades a dependency.\\n\"},{\"Command\":\"vendor\",\"Title\":\"Run go mod vendor\",\"Doc\":\"vendor runs `go mod vendor` for a module.\\n\"},{\"Command\":\"extract_variable\",\"Title\":\"Extract to variable\",\"Doc\":\"extract_variable extracts an expression to a variable.\\n\"},{\"Command\":\"extract_function\",\"Title\":\"Extract to function\",\"Doc\":\"extract_function extracts statements to a function.\\n\"},{\"Command\":\"gc_details\",\"Title\":\"Toggle gc_details\",\"Doc\":\"gc_details controls calculation of gc annotations.\\n\"},{\"Command\":\"generate_gopls_mod\",\"Title\":\"Generate gopls.mod\",\"Doc\":\"generate_gopls_mod (re)generates the gopls.mod file.\\n\"}],\"Lenses\":[{\"Lens\":\"generate\",\"Title\":\"Run go generate\",\"Doc\":\"generate runs `go generate` for a given directory.\\n\"},{\"Lens\":\"regenerate_cgo\",\"Title\":\"Regenerate cgo\",\"Doc\":\"regenerate_cgo regenerates cgo definitions.\\n\"},{\"Lens\":\"test\",\"Title\":\"Run test(s)\",\"Doc\":\"test runs `go test` for a specific test function.\\n\"},{\"Lens\":\"tidy\",\"Title\":\"Run go mod tidy\",\"Doc\":\"tidy runs `go mod tidy` for a module.\\n\"},{\"Lens\":\"upgrade_dependency\",\"Title\":\"Upgrade dependency\",\"Doc\":\"upgrade_dependency upgrades a dependency.\\n\"},{\"Lens\":\"vendor\",\"Title\":\"Run go mod vendor\",\"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\"}]}"
diff --git a/internal/lsp/source/code_lens.go b/internal/lsp/source/code_lens.go
index 2aee889..6bf3c57 100644
--- a/internal/lsp/source/code_lens.go
+++ b/internal/lsp/source/code_lens.go
@@ -68,7 +68,7 @@
 				Range: rng,
 				Command: protocol.Command{
 					Title:     "run test",
-					Command:   CommandTest.Name,
+					Command:   CommandTest.ID(),
 					Arguments: jsonArgs,
 				},
 			})
@@ -83,7 +83,7 @@
 				Range: rng,
 				Command: protocol.Command{
 					Title:     "run benchmark",
-					Command:   CommandTest.Name,
+					Command:   CommandTest.ID(),
 					Arguments: jsonArgs,
 				},
 			})
@@ -102,7 +102,7 @@
 		Range: rng,
 		Command: protocol.Command{
 			Title:     "run file benchmarks",
-			Command:   CommandTest.Name,
+			Command:   CommandTest.ID(),
 			Arguments: args,
 		},
 	})
@@ -176,7 +176,7 @@
 					Range: rng,
 					Command: protocol.Command{
 						Title:     "run go generate",
-						Command:   CommandGenerate.Name,
+						Command:   CommandGenerate.ID(),
 						Arguments: nonRecursiveArgs,
 					},
 				},
@@ -184,7 +184,7 @@
 					Range: rng,
 					Command: protocol.Command{
 						Title:     "run go generate ./...",
-						Command:   CommandGenerate.Name,
+						Command:   CommandGenerate.ID(),
 						Arguments: recursiveArgs,
 					},
 				},
@@ -222,7 +222,7 @@
 			Range: rng,
 			Command: protocol.Command{
 				Title:     "regenerate cgo definitions",
-				Command:   CommandRegenerateCgo.Name,
+				Command:   CommandRegenerateCgo.ID(),
 				Arguments: jsonArgs,
 			},
 		},
@@ -246,7 +246,7 @@
 		Range: rng,
 		Command: protocol.Command{
 			Title:     "Toggle gc annotation details",
-			Command:   CommandToggleDetails.Name,
+			Command:   CommandToggleDetails.ID(),
 			Arguments: jsonArgs,
 		},
 	}}, nil
diff --git a/internal/lsp/source/command.go b/internal/lsp/source/command.go
index 90cb8ee..f63255d 100644
--- a/internal/lsp/source/command.go
+++ b/internal/lsp/source/command.go
@@ -20,7 +20,8 @@
 )
 
 type Command struct {
-	Name, Title string
+	Title string
+	Name  string
 
 	// Synchronous controls whether the command executes synchronously within the
 	// ExecuteCommand request (applying suggested fixes is always synchronous).
@@ -36,6 +37,12 @@
 	suggestedFixFn SuggestedFixFunc
 }
 
+// ID adds the "gopls_" prefix to the command name, in order to avoid
+// collisions with other language servers.
+func (c Command) ID() string {
+	return "gopls_" + c.Name
+}
+
 type AppliesFunc func(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) bool
 
 // SuggestedFixFunc is a function used to get the suggested fixes for a given
@@ -109,6 +116,7 @@
 	// values.
 	CommandFillStruct = &Command{
 		Name:           "fill_struct",
+		Title:          "Fill struct",
 		suggestedFixFn: fillstruct.SuggestedFix,
 	}
 
@@ -116,6 +124,7 @@
 	// name.
 	CommandUndeclaredName = &Command{
 		Name:           "undeclared_name",
+		Title:          "Undeclared name",
 		suggestedFixFn: undeclaredname.SuggestedFix,
 	}