diff options
Diffstat (limited to 'internal/lsp/cmd')
73 files changed, 0 insertions, 4728 deletions
diff --git a/internal/lsp/cmd/call_hierarchy.go b/internal/lsp/cmd/call_hierarchy.go deleted file mode 100644 index c9f9e73e0..000000000 --- a/internal/lsp/cmd/call_hierarchy.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "strings" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// callHierarchy implements the callHierarchy verb for gopls. -type callHierarchy struct { - app *Application -} - -func (c *callHierarchy) Name() string { return "call_hierarchy" } -func (c *callHierarchy) Parent() string { return c.app.Name() } -func (c *callHierarchy) Usage() string { return "<position>" } -func (c *callHierarchy) ShortHelp() string { return "display selected identifier's call hierarchy" } -func (c *callHierarchy) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls call_hierarchy helper/helper.go:8:6 - $ gopls call_hierarchy helper/helper.go:#53 -`) - printFlagDefaults(f) -} - -func (c *callHierarchy) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("call_hierarchy expects 1 argument (position)") - } - - conn, err := c.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - - p := protocol.CallHierarchyPrepareParams{ - TextDocumentPositionParams: protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - }, - } - - callItems, err := conn.PrepareCallHierarchy(ctx, &p) - if err != nil { - return err - } - if len(callItems) == 0 { - return fmt.Errorf("function declaration identifier not found at %v", args[0]) - } - - for _, item := range callItems { - incomingCalls, err := conn.IncomingCalls(ctx, &protocol.CallHierarchyIncomingCallsParams{Item: item}) - if err != nil { - return err - } - for i, call := range incomingCalls { - // From the spec: CallHierarchyIncomingCall.FromRanges is relative to - // the caller denoted by CallHierarchyIncomingCall.from. - printString, err := callItemPrintString(ctx, conn, call.From, call.From.URI, call.FromRanges) - if err != nil { - return err - } - fmt.Printf("caller[%d]: %s\n", i, printString) - } - - printString, err := callItemPrintString(ctx, conn, item, "", nil) - if err != nil { - return err - } - fmt.Printf("identifier: %s\n", printString) - - outgoingCalls, err := conn.OutgoingCalls(ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: item}) - if err != nil { - return err - } - for i, call := range outgoingCalls { - // From the spec: CallHierarchyOutgoingCall.FromRanges is the range - // relative to the caller, e.g the item passed to - printString, err := callItemPrintString(ctx, conn, call.To, item.URI, call.FromRanges) - if err != nil { - return err - } - fmt.Printf("callee[%d]: %s\n", i, printString) - } - } - - return nil -} - -// callItemPrintString returns a protocol.CallHierarchyItem object represented as a string. -// item and call ranges (protocol.Range) are converted to user friendly spans (1-indexed). -func callItemPrintString(ctx context.Context, conn *connection, item protocol.CallHierarchyItem, callsURI protocol.DocumentURI, calls []protocol.Range) (string, error) { - itemFile := conn.AddFile(ctx, item.URI.SpanURI()) - if itemFile.err != nil { - return "", itemFile.err - } - itemSpan, err := itemFile.mapper.Span(protocol.Location{URI: item.URI, Range: item.Range}) - if err != nil { - return "", err - } - - callsFile := conn.AddFile(ctx, callsURI.SpanURI()) - if callsURI != "" && callsFile.err != nil { - return "", callsFile.err - } - var callRanges []string - for _, rng := range calls { - callSpan, err := callsFile.mapper.Span(protocol.Location{URI: item.URI, Range: rng}) - if err != nil { - return "", err - } - - spn := fmt.Sprint(callSpan) - callRanges = append(callRanges, fmt.Sprint(spn[strings.Index(spn, ":")+1:])) - } - - printString := fmt.Sprintf("function %s in %v", item.Name, itemSpan) - if len(calls) > 0 { - printString = fmt.Sprintf("ranges %s in %s from/to %s", strings.Join(callRanges, ", "), callsURI.SpanURI().Filename(), printString) - } - return printString, nil -} diff --git a/internal/lsp/cmd/capabilities_test.go b/internal/lsp/cmd/capabilities_test.go deleted file mode 100644 index 70db8d7d3..000000000 --- a/internal/lsp/cmd/capabilities_test.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "golang.org/x/tools/internal/lsp" - "golang.org/x/tools/internal/lsp/cache" - "golang.org/x/tools/internal/lsp/protocol" - errors "golang.org/x/xerrors" -) - -// TestCapabilities does some minimal validation of the server's adherence to the LSP. -// The checks in the test are added as changes are made and errors noticed. -func TestCapabilities(t *testing.T) { - tmpDir, err := ioutil.TempDir("", "fake") - if err != nil { - t.Fatal(err) - } - tmpFile := filepath.Join(tmpDir, "fake.go") - if err := ioutil.WriteFile(tmpFile, []byte(""), 0775); err != nil { - t.Fatal(err) - } - if err := ioutil.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte("module fake\n\ngo 1.12\n"), 0775); err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - app := New("gopls-test", tmpDir, os.Environ(), nil) - c := newConnection(app) - ctx := context.Background() - defer c.terminate(ctx) - - params := &protocol.ParamInitialize{} - params.RootURI = protocol.URIFromPath(c.Client.app.wd) - params.Capabilities.Workspace.Configuration = true - - // Send an initialize request to the server. - c.Server = lsp.NewServer(cache.New(app.options).NewSession(ctx), c.Client) - result, err := c.Server.Initialize(ctx, params) - if err != nil { - t.Fatal(err) - } - // Validate initialization result. - if err := validateCapabilities(result); err != nil { - t.Error(err) - } - // Complete initialization of server. - if err := c.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil { - t.Fatal(err) - } - - // Open the file on the server side. - uri := protocol.URIFromPath(tmpFile) - if err := c.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ - TextDocument: protocol.TextDocumentItem{ - URI: uri, - LanguageID: "go", - Version: 1, - Text: `package main; func main() {};`, - }, - }); err != nil { - t.Fatal(err) - } - - // If we are sending a full text change, the change.Range must be nil. - // It is not enough for the Change to be empty, as that is ambiguous. - if err := c.Server.DidChange(ctx, &protocol.DidChangeTextDocumentParams{ - TextDocument: protocol.VersionedTextDocumentIdentifier{ - TextDocumentIdentifier: protocol.TextDocumentIdentifier{ - URI: uri, - }, - Version: 2, - }, - ContentChanges: []protocol.TextDocumentContentChangeEvent{ - { - Range: nil, - Text: `package main; func main() { fmt.Println("") }`, - }, - }, - }); err != nil { - t.Fatal(err) - } - - // Send a code action request to validate expected types. - actions, err := c.Server.CodeAction(ctx, &protocol.CodeActionParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: uri, - }, - }) - if err != nil { - t.Fatal(err) - } - for _, action := range actions { - // Validate that an empty command is sent along with import organization responses. - if action.Kind == protocol.SourceOrganizeImports && action.Command != nil { - t.Errorf("unexpected command for import organization") - } - } - - if err := c.Server.DidSave(ctx, &protocol.DidSaveTextDocumentParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: uri, - }, - // LSP specifies that a file can be saved with optional text, so this field must be nil. - Text: nil, - }); err != nil { - t.Fatal(err) - } - - // Send a completion request to validate expected types. - list, err := c.Server.Completion(ctx, &protocol.CompletionParams{ - TextDocumentPositionParams: protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: uri, - }, - Position: protocol.Position{ - Line: 0, - Character: 28, - }, - }, - }) - if err != nil { - t.Fatal(err) - } - for _, item := range list.Items { - // All other completion items should have nil commands. - // An empty command will be treated as a command with the name '' by VS Code. - // This causes VS Code to report errors to users about invalid commands. - if item.Command != nil { - t.Errorf("unexpected command for completion item") - } - // The item's TextEdit must be a pointer, as VS Code considers TextEdits - // that don't contain the cursor position to be invalid. - var textEdit interface{} = item.TextEdit - if _, ok := textEdit.(*protocol.TextEdit); !ok { - t.Errorf("textEdit is not a *protocol.TextEdit, instead it is %T", textEdit) - } - } - if err := c.Server.Shutdown(ctx); err != nil { - t.Fatal(err) - } - if err := c.Server.Exit(ctx); err != nil { - t.Fatal(err) - } -} - -func validateCapabilities(result *protocol.InitializeResult) error { - // If the client sends "false" for RenameProvider.PrepareSupport, - // the server must respond with a boolean. - if v, ok := result.Capabilities.RenameProvider.(bool); !ok { - return errors.Errorf("RenameProvider must be a boolean if PrepareSupport is false (got %T)", v) - } - // The same goes for CodeActionKind.ValueSet. - if v, ok := result.Capabilities.CodeActionProvider.(bool); !ok { - return errors.Errorf("CodeActionSupport must be a boolean if CodeActionKind.ValueSet has length 0 (got %T)", v) - } - return nil -} diff --git a/internal/lsp/cmd/check.go b/internal/lsp/cmd/check.go deleted file mode 100644 index 566924aa6..000000000 --- a/internal/lsp/cmd/check.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - - "golang.org/x/tools/internal/span" - errors "golang.org/x/xerrors" -) - -// check implements the check verb for gopls. -type check struct { - app *Application -} - -func (c *check) Name() string { return "check" } -func (c *check) Parent() string { return c.app.Name() } -func (c *check) Usage() string { return "<filename>" } -func (c *check) ShortHelp() string { return "show diagnostic results for the specified file" } -func (c *check) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: show the diagnostic results of this file: - - $ gopls check internal/lsp/cmd/check.go -`) - printFlagDefaults(f) -} - -// Run performs the check on the files specified by args and prints the -// results to stdout. -func (c *check) Run(ctx context.Context, args ...string) error { - if len(args) == 0 { - // no files, so no results - return nil - } - checking := map[span.URI]*cmdFile{} - var uris []span.URI - // now we ready to kick things off - conn, err := c.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - for _, arg := range args { - uri := span.URIFromPath(arg) - uris = append(uris, uri) - file := conn.AddFile(ctx, uri) - if file.err != nil { - return file.err - } - checking[uri] = file - } - if err := conn.diagnoseFiles(ctx, uris); err != nil { - return err - } - conn.Client.filesMu.Lock() - defer conn.Client.filesMu.Unlock() - - for _, file := range checking { - for _, d := range file.diagnostics { - spn, err := file.mapper.RangeSpan(d.Range) - if err != nil { - return errors.Errorf("Could not convert position %v for %q", d.Range, d.Message) - } - fmt.Printf("%v: %v\n", spn, d.Message) - } - } - return nil -} diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go deleted file mode 100644 index d48398d0d..000000000 --- a/internal/lsp/cmd/cmd.go +++ /dev/null @@ -1,630 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package cmd handles the gopls command line. -// It contains a handler for each of the modes, along with all the flag handling -// and the command line output format. -package cmd - -import ( - "context" - "flag" - "fmt" - "go/token" - "io/ioutil" - "log" - "os" - "reflect" - "sort" - "strings" - "sync" - "text/tabwriter" - "time" - - "golang.org/x/tools/internal/jsonrpc2" - "golang.org/x/tools/internal/lsp" - "golang.org/x/tools/internal/lsp/cache" - "golang.org/x/tools/internal/lsp/debug" - "golang.org/x/tools/internal/lsp/lsprpc" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - "golang.org/x/tools/internal/xcontext" - errors "golang.org/x/xerrors" -) - -// Application is the main application as passed to tool.Main -// It handles the main command line parsing and dispatch to the sub commands. -type Application struct { - // Core application flags - - // Embed the basic profiling flags supported by the tool package - tool.Profile - - // We include the server configuration directly for now, so the flags work - // even without the verb. - // TODO: Remove this when we stop allowing the serve verb by default. - Serve Serve - - // the options configuring function to invoke when building a server - options func(*source.Options) - - // The name of the binary, used in help and telemetry. - name string - - // The working directory to run commands in. - wd string - - // The environment variables to use. - env []string - - // Support for remote LSP server. - Remote string `flag:"remote" help:"forward all commands to a remote lsp specified by this flag. With no special prefix, this is assumed to be a TCP address. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. If 'auto', or prefixed by 'auto;', the remote address is automatically resolved based on the executing environment."` - - // Verbose enables verbose logging. - Verbose bool `flag:"v,verbose" help:"verbose output"` - - // VeryVerbose enables a higher level of verbosity in logging output. - VeryVerbose bool `flag:"vv,veryverbose" help:"very verbose output"` - - // Control ocagent export of telemetry - OCAgent string `flag:"ocagent" help:"the address of the ocagent (e.g. http://localhost:55678), or off"` - - // PrepareOptions is called to update the options when a new view is built. - // It is primarily to allow the behavior of gopls to be modified by hooks. - PrepareOptions func(*source.Options) -} - -func (app *Application) verbose() bool { - return app.Verbose || app.VeryVerbose -} - -// New returns a new Application ready to run. -func New(name, wd string, env []string, options func(*source.Options)) *Application { - if wd == "" { - wd, _ = os.Getwd() - } - app := &Application{ - options: options, - name: name, - wd: wd, - env: env, - OCAgent: "off", //TODO: Remove this line to default the exporter to on - - Serve: Serve{ - RemoteListenTimeout: 1 * time.Minute, - }, - } - app.Serve.app = app - return app -} - -// Name implements tool.Application returning the binary name. -func (app *Application) Name() string { return app.name } - -// Usage implements tool.Application returning empty extra argument usage. -func (app *Application) Usage() string { return "" } - -// ShortHelp implements tool.Application returning the main binary help. -func (app *Application) ShortHelp() string { - return "" -} - -// DetailedHelp implements tool.Application returning the main binary help. -// This includes the short help for all the sub commands. -func (app *Application) DetailedHelp(f *flag.FlagSet) { - w := tabwriter.NewWriter(f.Output(), 0, 0, 2, ' ', 0) - defer w.Flush() - - fmt.Fprint(w, ` -gopls is a Go language server. - -It is typically used with an editor to provide language features. When no -command is specified, gopls will default to the 'serve' command. The language -features can also be accessed via the gopls command-line interface. - -Usage: - gopls help [<subject>] - -Command: -`) - fmt.Fprint(w, "\nMain\t\n") - for _, c := range app.mainCommands() { - fmt.Fprintf(w, " %s\t%s\n", c.Name(), c.ShortHelp()) - } - fmt.Fprint(w, "\t\nFeatures\t\n") - for _, c := range app.featureCommands() { - fmt.Fprintf(w, " %s\t%s\n", c.Name(), c.ShortHelp()) - } - fmt.Fprint(w, "\nflags:\n") - printFlagDefaults(f) -} - -// this is a slightly modified version of flag.PrintDefaults to give us control -func printFlagDefaults(s *flag.FlagSet) { - var flags [][]*flag.Flag - seen := map[flag.Value]int{} - s.VisitAll(func(f *flag.Flag) { - if i, ok := seen[f.Value]; !ok { - seen[f.Value] = len(flags) - flags = append(flags, []*flag.Flag{f}) - } else { - flags[i] = append(flags[i], f) - } - }) - for _, entry := range flags { - sort.SliceStable(entry, func(i, j int) bool { - return len(entry[i].Name) < len(entry[j].Name) - }) - var b strings.Builder - for i, f := range entry { - switch i { - case 0: - b.WriteString(" -") - default: - b.WriteString(",-") - } - b.WriteString(f.Name) - } - - f := entry[0] - name, usage := flag.UnquoteUsage(f) - if len(name) > 0 { - b.WriteString("=") - b.WriteString(name) - } - // Boolean flags of one ASCII letter are so common we - // treat them specially, putting their usage on the same line. - if b.Len() <= 4 { // space, space, '-', 'x'. - b.WriteString("\t") - } else { - // Four spaces before the tab triggers good alignment - // for both 4- and 8-space tab stops. - b.WriteString("\n \t") - } - b.WriteString(strings.ReplaceAll(usage, "\n", "\n \t")) - if !isZeroValue(f, f.DefValue) { - if reflect.TypeOf(f.Value).Elem().Name() == "stringValue" { - fmt.Fprintf(&b, " (default %q)", f.DefValue) - } else { - fmt.Fprintf(&b, " (default %v)", f.DefValue) - } - } - fmt.Fprint(s.Output(), b.String(), "\n") - } -} - -// isZeroValue is copied from the flags package -func isZeroValue(f *flag.Flag, value string) bool { - // Build a zero value of the flag's Value type, and see if the - // result of calling its String method equals the value passed in. - // This works unless the Value type is itself an interface type. - typ := reflect.TypeOf(f.Value) - var z reflect.Value - if typ.Kind() == reflect.Ptr { - z = reflect.New(typ.Elem()) - } else { - z = reflect.Zero(typ) - } - return value == z.Interface().(flag.Value).String() -} - -// Run takes the args after top level flag processing, and invokes the correct -// sub command as specified by the first argument. -// If no arguments are passed it will invoke the server sub command, as a -// temporary measure for compatibility. -func (app *Application) Run(ctx context.Context, args ...string) error { - ctx = debug.WithInstance(ctx, app.wd, app.OCAgent) - if len(args) == 0 { - s := flag.NewFlagSet(app.Name(), flag.ExitOnError) - return tool.Run(ctx, s, &app.Serve, args) - } - command, args := args[0], args[1:] - for _, c := range app.Commands() { - if c.Name() == command { - s := flag.NewFlagSet(app.Name(), flag.ExitOnError) - return tool.Run(ctx, s, c, args) - } - } - return tool.CommandLineErrorf("Unknown command %v", command) -} - -// commands returns the set of commands supported by the gopls tool on the -// command line. -// The command is specified by the first non flag argument. -func (app *Application) Commands() []tool.Application { - var commands []tool.Application - commands = append(commands, app.mainCommands()...) - commands = append(commands, app.featureCommands()...) - return commands -} - -func (app *Application) mainCommands() []tool.Application { - return []tool.Application{ - &app.Serve, - &version{app: app}, - &bug{app: app}, - &apiJSON{app: app}, - &licenses{app: app}, - } -} - -func (app *Application) featureCommands() []tool.Application { - return []tool.Application{ - &callHierarchy{app: app}, - &check{app: app}, - &definition{app: app}, - &foldingRanges{app: app}, - &format{app: app}, - &highlight{app: app}, - &implementation{app: app}, - &imports{app: app}, - newRemote(app, ""), - newRemote(app, "inspect"), - &links{app: app}, - &prepareRename{app: app}, - &references{app: app}, - &rename{app: app}, - &semtok{app: app}, - &signature{app: app}, - &suggestedFix{app: app}, - &symbols{app: app}, - newWorkspace(app), - &workspaceSymbol{app: app}, - &vulncheck{app: app}, - } -} - -var ( - internalMu sync.Mutex - internalConnections = make(map[string]*connection) -) - -func (app *Application) connect(ctx context.Context) (*connection, error) { - switch { - case app.Remote == "": - connection := newConnection(app) - connection.Server = lsp.NewServer(cache.New(app.options).NewSession(ctx), connection.Client) - ctx = protocol.WithClient(ctx, connection.Client) - return connection, connection.initialize(ctx, app.options) - case strings.HasPrefix(app.Remote, "internal@"): - internalMu.Lock() - defer internalMu.Unlock() - opts := source.DefaultOptions().Clone() - if app.options != nil { - app.options(opts) - } - key := fmt.Sprintf("%s %v %v %v", app.wd, opts.PreferredContentFormat, opts.HierarchicalDocumentSymbolSupport, opts.SymbolMatcher) - if c := internalConnections[key]; c != nil { - return c, nil - } - remote := app.Remote[len("internal@"):] - ctx := xcontext.Detach(ctx) //TODO:a way of shutting down the internal server - connection, err := app.connectRemote(ctx, remote) - if err != nil { - return nil, err - } - internalConnections[key] = connection - return connection, nil - default: - return app.connectRemote(ctx, app.Remote) - } -} - -// CloseTestConnections terminates shared connections used in command tests. It -// should only be called from tests. -func CloseTestConnections(ctx context.Context) { - for _, c := range internalConnections { - c.Shutdown(ctx) - c.Exit(ctx) - } -} - -func (app *Application) connectRemote(ctx context.Context, remote string) (*connection, error) { - connection := newConnection(app) - conn, err := lsprpc.ConnectToRemote(ctx, remote) - if err != nil { - return nil, err - } - stream := jsonrpc2.NewHeaderStream(conn) - cc := jsonrpc2.NewConn(stream) - connection.Server = protocol.ServerDispatcher(cc) - ctx = protocol.WithClient(ctx, connection.Client) - cc.Go(ctx, - protocol.Handlers( - protocol.ClientHandler(connection.Client, - jsonrpc2.MethodNotFound))) - return connection, connection.initialize(ctx, app.options) -} - -var matcherString = map[source.SymbolMatcher]string{ - source.SymbolFuzzy: "fuzzy", - source.SymbolCaseSensitive: "caseSensitive", - source.SymbolCaseInsensitive: "caseInsensitive", -} - -func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error { - params := &protocol.ParamInitialize{} - params.RootURI = protocol.URIFromPath(c.Client.app.wd) - params.Capabilities.Workspace.Configuration = true - - // Make sure to respect configured options when sending initialize request. - opts := source.DefaultOptions().Clone() - if options != nil { - options(opts) - } - // If you add an additional option here, you must update the map key in connect. - params.Capabilities.TextDocument.Hover = protocol.HoverClientCapabilities{ - ContentFormat: []protocol.MarkupKind{opts.PreferredContentFormat}, - } - params.Capabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = opts.HierarchicalDocumentSymbolSupport - params.Capabilities.TextDocument.SemanticTokens = protocol.SemanticTokensClientCapabilities{} - params.Capabilities.TextDocument.SemanticTokens.Formats = []string{"relative"} - params.Capabilities.TextDocument.SemanticTokens.Requests.Range = true - params.Capabilities.TextDocument.SemanticTokens.Requests.Full = true - params.Capabilities.TextDocument.SemanticTokens.TokenTypes = lsp.SemanticTypes() - params.Capabilities.TextDocument.SemanticTokens.TokenModifiers = lsp.SemanticModifiers() - params.InitializationOptions = map[string]interface{}{ - "symbolMatcher": matcherString[opts.SymbolMatcher], - } - if _, err := c.Server.Initialize(ctx, params); err != nil { - return err - } - if err := c.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil { - return err - } - return nil -} - -type connection struct { - protocol.Server - Client *cmdClient -} - -type cmdClient struct { - protocol.Server - app *Application - fset *token.FileSet - - diagnosticsMu sync.Mutex - diagnosticsDone chan struct{} - - filesMu sync.Mutex - files map[span.URI]*cmdFile -} - -type cmdFile struct { - uri span.URI - mapper *protocol.ColumnMapper - err error - added bool - diagnostics []protocol.Diagnostic -} - -func newConnection(app *Application) *connection { - return &connection{ - Client: &cmdClient{ - app: app, - fset: token.NewFileSet(), - files: make(map[span.URI]*cmdFile), - }, - } -} - -// fileURI converts a DocumentURI to a file:// span.URI, panicking if it's not a file. -func fileURI(uri protocol.DocumentURI) span.URI { - sURI := uri.SpanURI() - if !sURI.IsFile() { - panic(fmt.Sprintf("%q is not a file URI", uri)) - } - return sURI -} - -func (c *cmdClient) ShowMessage(ctx context.Context, p *protocol.ShowMessageParams) error { return nil } - -func (c *cmdClient) ShowMessageRequest(ctx context.Context, p *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error) { - return nil, nil -} - -func (c *cmdClient) LogMessage(ctx context.Context, p *protocol.LogMessageParams) error { - switch p.Type { - case protocol.Error: - log.Print("Error:", p.Message) - case protocol.Warning: - log.Print("Warning:", p.Message) - case protocol.Info: - if c.app.verbose() { - log.Print("Info:", p.Message) - } - case protocol.Log: - if c.app.verbose() { - log.Print("Log:", p.Message) - } - default: - if c.app.verbose() { - log.Print(p.Message) - } - } - return nil -} - -func (c *cmdClient) Event(ctx context.Context, t *interface{}) error { return nil } - -func (c *cmdClient) RegisterCapability(ctx context.Context, p *protocol.RegistrationParams) error { - return nil -} - -func (c *cmdClient) UnregisterCapability(ctx context.Context, p *protocol.UnregistrationParams) error { - return nil -} - -func (c *cmdClient) WorkspaceFolders(ctx context.Context) ([]protocol.WorkspaceFolder, error) { - return nil, nil -} - -func (c *cmdClient) Configuration(ctx context.Context, p *protocol.ParamConfiguration) ([]interface{}, error) { - results := make([]interface{}, len(p.Items)) - for i, item := range p.Items { - if item.Section != "gopls" { - continue - } - env := map[string]interface{}{} - for _, value := range c.app.env { - l := strings.SplitN(value, "=", 2) - if len(l) != 2 { - continue - } - env[l[0]] = l[1] - } - m := map[string]interface{}{ - "env": env, - "analyses": map[string]bool{ - "fillreturns": true, - "nonewvars": true, - "noresultvalues": true, - "undeclaredname": true, - }, - } - if c.app.VeryVerbose { - m["verboseOutput"] = true - } - results[i] = m - } - return results, nil -} - -func (c *cmdClient) ApplyEdit(ctx context.Context, p *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) { - return &protocol.ApplyWorkspaceEditResult{Applied: false, FailureReason: "not implemented"}, nil -} - -func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishDiagnosticsParams) error { - if p.URI == "gopls://diagnostics-done" { - close(c.diagnosticsDone) - } - // Don't worry about diagnostics without versions. - if p.Version == 0 { - return nil - } - - c.filesMu.Lock() - defer c.filesMu.Unlock() - - file := c.getFile(ctx, fileURI(p.URI)) - file.diagnostics = p.Diagnostics - return nil -} - -func (c *cmdClient) Progress(context.Context, *protocol.ProgressParams) error { - return nil -} - -func (c *cmdClient) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) { - return nil, nil -} - -func (c *cmdClient) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error { - return nil -} - -func (c *cmdClient) getFile(ctx context.Context, uri span.URI) *cmdFile { - file, found := c.files[uri] - if !found || file.err != nil { - file = &cmdFile{ - uri: uri, - } - c.files[uri] = file - } - if file.mapper == nil { - fname := uri.Filename() - content, err := ioutil.ReadFile(fname) - if err != nil { - file.err = errors.Errorf("getFile: %v: %v", uri, err) - return file - } - f := c.fset.AddFile(fname, -1, len(content)) - f.SetLinesForContent(content) - converter := span.NewContentConverter(fname, content) - file.mapper = &protocol.ColumnMapper{ - URI: uri, - Converter: converter, - Content: content, - } - } - return file -} - -func (c *connection) AddFile(ctx context.Context, uri span.URI) *cmdFile { - c.Client.filesMu.Lock() - defer c.Client.filesMu.Unlock() - - file := c.Client.getFile(ctx, uri) - // This should never happen. - if file == nil { - return &cmdFile{ - uri: uri, - err: fmt.Errorf("no file found for %s", uri), - } - } - if file.err != nil || file.added { - return file - } - file.added = true - p := &protocol.DidOpenTextDocumentParams{ - TextDocument: protocol.TextDocumentItem{ - URI: protocol.URIFromSpanURI(uri), - LanguageID: "go", - Version: 1, - Text: string(file.mapper.Content), - }, - } - if err := c.Server.DidOpen(ctx, p); err != nil { - file.err = errors.Errorf("%v: %v", uri, err) - } - return file -} - -func (c *connection) semanticTokens(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) { - // use range to avoid limits on full - resp, err := c.Server.SemanticTokensRange(ctx, p) - if err != nil { - return nil, err - } - return resp, nil -} - -func (c *connection) diagnoseFiles(ctx context.Context, files []span.URI) error { - var untypedFiles []interface{} - for _, file := range files { - untypedFiles = append(untypedFiles, string(file)) - } - c.Client.diagnosticsMu.Lock() - defer c.Client.diagnosticsMu.Unlock() - - c.Client.diagnosticsDone = make(chan struct{}) - _, err := c.Server.NonstandardRequest(ctx, "gopls/diagnoseFiles", map[string]interface{}{"files": untypedFiles}) - if err != nil { - close(c.Client.diagnosticsDone) - return err - } - - <-c.Client.diagnosticsDone - return nil -} - -func (c *connection) terminate(ctx context.Context) { - if strings.HasPrefix(c.Client.app.Remote, "internal@") { - // internal connections need to be left alive for the next test - return - } - //TODO: do we need to handle errors on these calls? - c.Shutdown(ctx) - //TODO: right now calling exit terminates the process, we should rethink that - //server.Exit(ctx) -} - -// Implement io.Closer. -func (c *cmdClient) Close() error { - return nil -} diff --git a/internal/lsp/cmd/cmd_test.go b/internal/lsp/cmd/cmd_test.go deleted file mode 100644 index 29816c83e..000000000 --- a/internal/lsp/cmd/cmd_test.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd_test - -import ( - "os" - "testing" - - cmdtest "golang.org/x/tools/internal/lsp/cmd/test" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/testenv" -) - -func TestMain(m *testing.M) { - testenv.ExitIfSmallMachine() - os.Exit(m.Run()) -} - -func TestCommandLine(t *testing.T) { - cmdtest.TestCommandLine(t, "../testdata", tests.DefaultOptions) -} diff --git a/internal/lsp/cmd/definition.go b/internal/lsp/cmd/definition.go deleted file mode 100644 index f3c71b671..000000000 --- a/internal/lsp/cmd/definition.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "os" - "strings" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// A Definition is the result of a 'definition' query. -type Definition struct { - Span span.Span `json:"span"` // span of the definition - Description string `json:"description"` // description of the denoted object -} - -// These constant is printed in the help, and then used in a test to verify the -// help is still valid. -// They refer to "Set" in "flag.FlagSet" from the DetailedHelp method below. -const ( - exampleLine = 44 - exampleColumn = 47 - exampleOffset = 1270 -) - -// definition implements the definition verb for gopls. -type definition struct { - app *Application - - JSON bool `flag:"json" help:"emit output in JSON format"` - MarkdownSupported bool `flag:"markdown" help:"support markdown in responses"` -} - -func (d *definition) Name() string { return "definition" } -func (d *definition) Parent() string { return d.app.Name() } -func (d *definition) Usage() string { return "[definition-flags] <position>" } -func (d *definition) ShortHelp() string { return "show declaration of selected identifier" } -func (d *definition) DetailedHelp(f *flag.FlagSet) { - fmt.Fprintf(f.Output(), ` -Example: show the definition of the identifier at syntax at offset %[1]v in this file (flag.FlagSet): - - $ gopls definition internal/lsp/cmd/definition.go:%[1]v:%[2]v - $ gopls definition internal/lsp/cmd/definition.go:#%[3]v - -definition-flags: -`, exampleLine, exampleColumn, exampleOffset) - printFlagDefaults(f) -} - -// Run performs the definition query as specified by args and prints the -// results to stdout. -func (d *definition) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("definition expects 1 argument") - } - // Plaintext makes more sense for the command line. - opts := d.app.options - d.app.options = func(o *source.Options) { - if opts != nil { - opts(o) - } - o.PreferredContentFormat = protocol.PlainText - if d.MarkdownSupported { - o.PreferredContentFormat = protocol.Markdown - } - } - conn, err := d.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - tdpp := protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - } - p := protocol.DefinitionParams{ - TextDocumentPositionParams: tdpp, - } - locs, err := conn.Definition(ctx, &p) - if err != nil { - return errors.Errorf("%v: %v", from, err) - } - - if len(locs) == 0 { - return errors.Errorf("%v: not an identifier", from) - } - q := protocol.HoverParams{ - TextDocumentPositionParams: tdpp, - } - hover, err := conn.Hover(ctx, &q) - if err != nil { - return errors.Errorf("%v: %v", from, err) - } - if hover == nil { - return errors.Errorf("%v: not an identifier", from) - } - file = conn.AddFile(ctx, fileURI(locs[0].URI)) - if file.err != nil { - return errors.Errorf("%v: %v", from, file.err) - } - definition, err := file.mapper.Span(locs[0]) - if err != nil { - return errors.Errorf("%v: %v", from, err) - } - description := strings.TrimSpace(hover.Contents.Value) - result := &Definition{ - Span: definition, - Description: description, - } - if d.JSON { - enc := json.NewEncoder(os.Stdout) - enc.SetIndent("", "\t") - return enc.Encode(result) - } - fmt.Printf("%v: defined here as %s", result.Span, result.Description) - return nil -} diff --git a/internal/lsp/cmd/export_test.go b/internal/lsp/cmd/export_test.go deleted file mode 100644 index 05b3cd312..000000000 --- a/internal/lsp/cmd/export_test.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -const ( - ExampleLine = exampleLine - ExampleColumn = exampleColumn - ExampleOffset = exampleOffset -) diff --git a/internal/lsp/cmd/folding_range.go b/internal/lsp/cmd/folding_range.go deleted file mode 100644 index 513c9bdd2..000000000 --- a/internal/lsp/cmd/folding_range.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// foldingRanges implements the folding_ranges verb for gopls -type foldingRanges struct { - app *Application -} - -func (r *foldingRanges) Name() string { return "folding_ranges" } -func (r *foldingRanges) Parent() string { return r.app.Name() } -func (r *foldingRanges) Usage() string { return "<file>" } -func (r *foldingRanges) ShortHelp() string { return "display selected file's folding ranges" } -func (r *foldingRanges) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ gopls folding_ranges helper/helper.go -`) - printFlagDefaults(f) -} - -func (r *foldingRanges) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("folding_ranges expects 1 argument (file)") - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - - p := protocol.FoldingRangeParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(from.URI()), - }, - } - - ranges, err := conn.FoldingRange(ctx, &p) - if err != nil { - return err - } - - for _, r := range ranges { - fmt.Printf("%v:%v-%v:%v\n", - r.StartLine+1, - r.StartCharacter+1, - r.EndLine+1, - r.EndCharacter, - ) - } - - return nil -} diff --git a/internal/lsp/cmd/format.go b/internal/lsp/cmd/format.go deleted file mode 100644 index 2d0f3f7c3..000000000 --- a/internal/lsp/cmd/format.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" - errors "golang.org/x/xerrors" -) - -// format implements the format verb for gopls. -type format struct { - Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` - Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` - List bool `flag:"l,list" help:"list files whose formatting differs from gofmt's"` - - app *Application -} - -func (c *format) Name() string { return "format" } -func (c *format) Parent() string { return c.app.Name() } -func (c *format) Usage() string { return "[format-flags] <filerange>" } -func (c *format) ShortHelp() string { return "format the code according to the go standard" } -func (c *format) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -The arguments supplied may be simple file names, or ranges within files. - -Example: reformat this file: - - $ gopls format -w internal/lsp/cmd/check.go - -format-flags: -`) - printFlagDefaults(f) -} - -// Run performs the check on the files specified by args and prints the -// results to stdout. -func (c *format) Run(ctx context.Context, args ...string) error { - if len(args) == 0 { - // no files, so no results - return nil - } - // now we ready to kick things off - conn, err := c.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - for _, arg := range args { - spn := span.Parse(arg) - file := conn.AddFile(ctx, spn.URI()) - if file.err != nil { - return file.err - } - filename := spn.URI().Filename() - loc, err := file.mapper.Location(spn) - if err != nil { - return err - } - if loc.Range.Start != loc.Range.End { - return errors.Errorf("only full file formatting supported") - } - p := protocol.DocumentFormattingParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - } - edits, err := conn.Formatting(ctx, &p) - if err != nil { - return errors.Errorf("%v: %v", spn, err) - } - sedits, err := source.FromProtocolEdits(file.mapper, edits) - if err != nil { - return errors.Errorf("%v: %v", spn, err) - } - formatted := diff.ApplyEdits(string(file.mapper.Content), sedits) - printIt := true - if c.List { - printIt = false - if len(edits) > 0 { - fmt.Println(filename) - } - } - if c.Write { - printIt = false - if len(edits) > 0 { - ioutil.WriteFile(filename, []byte(formatted), 0644) - } - } - if c.Diff { - printIt = false - u := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) - fmt.Print(u) - } - if printIt { - fmt.Print(formatted) - } - } - return nil -} diff --git a/internal/lsp/cmd/help_test.go b/internal/lsp/cmd/help_test.go deleted file mode 100644 index 536d19dc2..000000000 --- a/internal/lsp/cmd/help_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd_test - -import ( - "bytes" - "context" - "flag" - "io/ioutil" - "path/filepath" - "testing" - - "golang.org/x/tools/internal/lsp/cmd" - "golang.org/x/tools/internal/testenv" - "golang.org/x/tools/internal/tool" -) - -//go:generate go test -run Help -update-help-files - -var updateHelpFiles = flag.Bool("update-help-files", false, "Write out the help files instead of checking them") - -const appName = "gopls" - -func TestHelpFiles(t *testing.T) { - testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code. - app := cmd.New(appName, "", nil, nil) - ctx := context.Background() - for _, page := range append(app.Commands(), app) { - t.Run(page.Name(), func(t *testing.T) { - var buf bytes.Buffer - s := flag.NewFlagSet(page.Name(), flag.ContinueOnError) - s.SetOutput(&buf) - tool.Run(ctx, s, page, []string{"-h"}) - name := page.Name() - if name == appName { - name = "usage" - } - helpFile := filepath.Join("usage", name+".hlp") - got := buf.Bytes() - if *updateHelpFiles { - if err := ioutil.WriteFile(helpFile, got, 0666); err != nil { - t.Errorf("Failed writing %v: %v", helpFile, err) - } - return - } - expect, err := ioutil.ReadFile(helpFile) - switch { - case err != nil: - t.Errorf("Missing help file %q", helpFile) - case !bytes.Equal(expect, got): - t.Errorf("Help file %q did not match, got:\n%q\nwant:\n%q", helpFile, string(got), string(expect)) - } - }) - } -} diff --git a/internal/lsp/cmd/highlight.go b/internal/lsp/cmd/highlight.go deleted file mode 100644 index a325a2d53..000000000 --- a/internal/lsp/cmd/highlight.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "sort" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// highlight implements the highlight verb for gopls. -type highlight struct { - app *Application -} - -func (r *highlight) Name() string { return "highlight" } -func (r *highlight) Parent() string { return r.app.Name() } -func (r *highlight) Usage() string { return "<position>" } -func (r *highlight) ShortHelp() string { return "display selected identifier's highlights" } -func (r *highlight) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls highlight helper/helper.go:8:6 - $ gopls highlight helper/helper.go:#53 -`) - printFlagDefaults(f) -} - -func (r *highlight) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("highlight expects 1 argument (position)") - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - - p := protocol.DocumentHighlightParams{ - TextDocumentPositionParams: protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - }, - } - highlights, err := conn.DocumentHighlight(ctx, &p) - if err != nil { - return err - } - - var results []span.Span - for _, h := range highlights { - l := protocol.Location{Range: h.Range} - s, err := file.mapper.Span(l) - if err != nil { - return err - } - results = append(results, s) - } - // Sort results to make tests deterministic since DocumentHighlight uses a map. - sort.SliceStable(results, func(i, j int) bool { - return span.Compare(results[i], results[j]) == -1 - }) - - for _, s := range results { - fmt.Println(s) - } - return nil -} diff --git a/internal/lsp/cmd/implementation.go b/internal/lsp/cmd/implementation.go deleted file mode 100644 index 7b42d9943..000000000 --- a/internal/lsp/cmd/implementation.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "sort" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// implementation implements the implementation verb for gopls -type implementation struct { - app *Application -} - -func (i *implementation) Name() string { return "implementation" } -func (i *implementation) Parent() string { return i.app.Name() } -func (i *implementation) Usage() string { return "<position>" } -func (i *implementation) ShortHelp() string { return "display selected identifier's implementation" } -func (i *implementation) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls implementation helper/helper.go:8:6 - $ gopls implementation helper/helper.go:#53 -`) - printFlagDefaults(f) -} - -func (i *implementation) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("implementation expects 1 argument (position)") - } - - conn, err := i.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - - p := protocol.ImplementationParams{ - TextDocumentPositionParams: protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - }, - } - - implementations, err := conn.Implementation(ctx, &p) - if err != nil { - return err - } - - var spans []string - for _, impl := range implementations { - f := conn.AddFile(ctx, fileURI(impl.URI)) - span, err := f.mapper.Span(impl) - if err != nil { - return err - } - spans = append(spans, fmt.Sprint(span)) - } - sort.Strings(spans) - - for _, s := range spans { - fmt.Println(s) - } - - return nil -} diff --git a/internal/lsp/cmd/imports.go b/internal/lsp/cmd/imports.go deleted file mode 100644 index 215c57f11..000000000 --- a/internal/lsp/cmd/imports.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// imports implements the import verb for gopls. -type imports struct { - Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` - Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` - - app *Application -} - -func (t *imports) Name() string { return "imports" } -func (t *imports) Parent() string { return t.app.Name() } -func (t *imports) Usage() string { return "[imports-flags] <filename>" } -func (t *imports) ShortHelp() string { return "updates import statements" } -func (t *imports) DetailedHelp(f *flag.FlagSet) { - fmt.Fprintf(f.Output(), ` -Example: update imports statements in a file: - - $ gopls imports -w internal/lsp/cmd/check.go - -imports-flags: -`) - printFlagDefaults(f) -} - -// Run performs diagnostic checks on the file specified and either; -// - if -w is specified, updates the file in place; -// - if -d is specified, prints out unified diffs of the changes; or -// - otherwise, prints the new versions to stdout. -func (t *imports) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("imports expects 1 argument") - } - conn, err := t.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - uri := from.URI() - file := conn.AddFile(ctx, uri) - if file.err != nil { - return file.err - } - actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(uri), - }, - }) - if err != nil { - return errors.Errorf("%v: %v", from, err) - } - var edits []protocol.TextEdit - for _, a := range actions { - if a.Title != "Organize Imports" { - continue - } - for _, c := range a.Edit.DocumentChanges { - if fileURI(c.TextDocument.URI) == uri { - edits = append(edits, c.Edits...) - } - } - } - sedits, err := source.FromProtocolEdits(file.mapper, edits) - if err != nil { - return errors.Errorf("%v: %v", edits, err) - } - newContent := diff.ApplyEdits(string(file.mapper.Content), sedits) - - filename := file.uri.Filename() - switch { - case t.Write: - if len(edits) > 0 { - ioutil.WriteFile(filename, []byte(newContent), 0644) - } - case t.Diff: - diffs := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) - fmt.Print(diffs) - default: - fmt.Print(string(newContent)) - } - return nil -} diff --git a/internal/lsp/cmd/info.go b/internal/lsp/cmd/info.go deleted file mode 100644 index 09f453e1a..000000000 --- a/internal/lsp/cmd/info.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "bytes" - "context" - "encoding/json" - "flag" - "fmt" - "net/url" - "os" - "strings" - - "golang.org/x/tools/internal/lsp/browser" - "golang.org/x/tools/internal/lsp/debug" - "golang.org/x/tools/internal/lsp/source" -) - -// version implements the version command. -type version struct { - JSON bool `flag:"json" help:"outputs in json format."` - - app *Application -} - -func (v *version) Name() string { return "version" } -func (v *version) Parent() string { return v.app.Name() } -func (v *version) Usage() string { return "" } -func (v *version) ShortHelp() string { return "print the gopls version information" } -func (v *version) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ``) - printFlagDefaults(f) -} - -// Run prints version information to stdout. -func (v *version) Run(ctx context.Context, args ...string) error { - var mode = debug.PlainText - if v.JSON { - mode = debug.JSON - } - - return debug.PrintVersionInfo(ctx, os.Stdout, v.app.verbose(), mode) -} - -// bug implements the bug command. -type bug struct { - app *Application -} - -func (b *bug) Name() string { return "bug" } -func (b *bug) Parent() string { return b.app.Name() } -func (b *bug) Usage() string { return "" } -func (b *bug) ShortHelp() string { return "report a bug in gopls" } -func (b *bug) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ``) - printFlagDefaults(f) -} - -const goplsBugPrefix = "x/tools/gopls: <DESCRIBE THE PROBLEM>" -const goplsBugHeader = `ATTENTION: Please answer these questions BEFORE submitting your issue. Thanks! - -#### What did you do? -If possible, provide a recipe for reproducing the error. -A complete runnable program is good. -A link on play.golang.org is better. -A failing unit test is the best. - -#### What did you expect to see? - - -#### What did you see instead? - - -` - -// Run collects some basic information and then prepares an issue ready to -// be reported. -func (b *bug) Run(ctx context.Context, args ...string) error { - buf := &bytes.Buffer{} - fmt.Fprint(buf, goplsBugHeader) - debug.PrintVersionInfo(ctx, buf, true, debug.Markdown) - body := buf.String() - title := strings.Join(args, " ") - if !strings.HasPrefix(title, goplsBugPrefix) { - title = goplsBugPrefix + title - } - if !browser.Open("https://github.com/golang/go/issues/new?title=" + url.QueryEscape(title) + "&body=" + url.QueryEscape(body)) { - fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n") - fmt.Print(body) - } - return nil -} - -type apiJSON struct { - app *Application -} - -func (j *apiJSON) Name() string { return "api-json" } -func (j *apiJSON) Parent() string { return j.app.Name() } -func (j *apiJSON) Usage() string { return "" } -func (j *apiJSON) ShortHelp() string { return "print json describing gopls API" } -func (j *apiJSON) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ``) - printFlagDefaults(f) -} - -func (j *apiJSON) Run(ctx context.Context, args ...string) error { - js, err := json.MarshalIndent(source.GeneratedAPIJSON, "", "\t") - if err != nil { - return err - } - fmt.Fprint(os.Stdout, string(js)) - return nil -} - -type licenses struct { - app *Application -} - -func (l *licenses) Name() string { return "licenses" } -func (l *licenses) Parent() string { return l.app.Name() } -func (l *licenses) Usage() string { return "" } -func (l *licenses) ShortHelp() string { return "print licenses of included software" } -func (l *licenses) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ``) - printFlagDefaults(f) -} - -const licensePreamble = ` -gopls is made available under the following BSD-style license: - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -gopls implements the LSP specification, which is made available under the following license: - -Copyright (c) Microsoft Corporation - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT -OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -gopls also includes software made available under these licenses: -` - -func (l *licenses) Run(ctx context.Context, args ...string) error { - opts := source.DefaultOptions() - l.app.options(opts) - txt := licensePreamble - if opts.LicensesText == "" { - txt += "(development gopls, license information not available)" - } else { - txt += opts.LicensesText - } - fmt.Fprint(os.Stdout, txt) - return nil -} diff --git a/internal/lsp/cmd/links.go b/internal/lsp/cmd/links.go deleted file mode 100644 index d49aabb6f..000000000 --- a/internal/lsp/cmd/links.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "os" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// links implements the links verb for gopls. -type links struct { - JSON bool `flag:"json" help:"emit document links in JSON format"` - - app *Application -} - -func (l *links) Name() string { return "links" } -func (l *links) Parent() string { return l.app.Name() } -func (l *links) Usage() string { return "[links-flags] <filename>" } -func (l *links) ShortHelp() string { return "list links in a file" } -func (l *links) DetailedHelp(f *flag.FlagSet) { - fmt.Fprintf(f.Output(), ` -Example: list links contained within a file: - - $ gopls links internal/lsp/cmd/check.go - -links-flags: -`) - printFlagDefaults(f) -} - -// Run finds all the links within a document -// - if -json is specified, outputs location range and uri -// - otherwise, prints the a list of unique links -func (l *links) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("links expects 1 argument") - } - conn, err := l.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - uri := from.URI() - file := conn.AddFile(ctx, uri) - if file.err != nil { - return file.err - } - results, err := conn.DocumentLink(ctx, &protocol.DocumentLinkParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(uri), - }, - }) - if err != nil { - return errors.Errorf("%v: %v", from, err) - } - if l.JSON { - enc := json.NewEncoder(os.Stdout) - enc.SetIndent("", "\t") - return enc.Encode(results) - } - for _, v := range results { - fmt.Println(v.Target) - } - return nil -} diff --git a/internal/lsp/cmd/prepare_rename.go b/internal/lsp/cmd/prepare_rename.go deleted file mode 100644 index aef0477e8..000000000 --- a/internal/lsp/cmd/prepare_rename.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// prepareRename implements the prepare_rename verb for gopls. -type prepareRename struct { - app *Application -} - -func (r *prepareRename) Name() string { return "prepare_rename" } -func (r *prepareRename) Parent() string { return r.app.Name() } -func (r *prepareRename) Usage() string { return "<position>" } -func (r *prepareRename) ShortHelp() string { return "test validity of a rename operation at location" } -func (r *prepareRename) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls prepare_rename helper/helper.go:8:6 - $ gopls prepare_rename helper/helper.go:#53 -`) - printFlagDefaults(f) -} - -// ErrInvalidRenamePosition is returned when prepareRename is run at a position that -// is not a candidate for renaming. -var ErrInvalidRenamePosition = errors.New("request is not valid at the given position") - -func (r *prepareRename) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("prepare_rename expects 1 argument (file)") - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - p := protocol.PrepareRenameParams{ - TextDocumentPositionParams: protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - }, - } - result, err := conn.PrepareRename(ctx, &p) - if err != nil { - return errors.Errorf("prepare_rename failed: %w", err) - } - if result == nil { - return ErrInvalidRenamePosition - } - - l := protocol.Location{Range: result.Range} - s, err := file.mapper.Span(l) - if err != nil { - return err - } - - fmt.Println(s) - return nil -} diff --git a/internal/lsp/cmd/references.go b/internal/lsp/cmd/references.go deleted file mode 100644 index 0697d2e11..000000000 --- a/internal/lsp/cmd/references.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "sort" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// references implements the references verb for gopls -type references struct { - IncludeDeclaration bool `flag:"d,declaration" help:"include the declaration of the specified identifier in the results"` - - app *Application -} - -func (r *references) Name() string { return "references" } -func (r *references) Parent() string { return r.app.Name() } -func (r *references) Usage() string { return "[references-flags] <position>" } -func (r *references) ShortHelp() string { return "display selected identifier's references" } -func (r *references) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls references helper/helper.go:8:6 - $ gopls references helper/helper.go:#53 - -references-flags: -`) - printFlagDefaults(f) -} - -func (r *references) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("references expects 1 argument (position)") - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - p := protocol.ReferenceParams{ - Context: protocol.ReferenceContext{ - IncludeDeclaration: r.IncludeDeclaration, - }, - TextDocumentPositionParams: protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - }, - } - locations, err := conn.References(ctx, &p) - if err != nil { - return err - } - var spans []string - for _, l := range locations { - f := conn.AddFile(ctx, fileURI(l.URI)) - // convert location to span for user-friendly 1-indexed line - // and column numbers - span, err := f.mapper.Span(l) - if err != nil { - return err - } - spans = append(spans, fmt.Sprint(span)) - } - - sort.Strings(spans) - for _, s := range spans { - fmt.Println(s) - } - return nil -} diff --git a/internal/lsp/cmd/remote.go b/internal/lsp/cmd/remote.go deleted file mode 100644 index f71113576..000000000 --- a/internal/lsp/cmd/remote.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "log" - "os" - - "golang.org/x/tools/internal/lsp/command" - "golang.org/x/tools/internal/lsp/lsprpc" - errors "golang.org/x/xerrors" -) - -type remote struct { - app *Application - subcommands - - // For backward compatibility, allow aliasing this command (it was previously - // called 'inspect'). - // - // TODO(rFindley): delete this after allowing some transition time in case - // there were any users of 'inspect' (I suspect not). - alias string -} - -func newRemote(app *Application, alias string) *remote { - return &remote{ - app: app, - subcommands: subcommands{ - &listSessions{app: app}, - &startDebugging{app: app}, - }, - alias: alias, - } -} - -func (r *remote) Name() string { - if r.alias != "" { - return r.alias - } - return "remote" -} - -func (r *remote) Parent() string { return r.app.Name() } - -func (r *remote) ShortHelp() string { - short := "interact with the gopls daemon" - if r.alias != "" { - short += " (deprecated: use 'remote')" - } - return short -} - -// listSessions is an inspect subcommand to list current sessions. -type listSessions struct { - app *Application -} - -func (c *listSessions) Name() string { return "sessions" } -func (c *listSessions) Parent() string { return c.app.Name() } -func (c *listSessions) Usage() string { return "" } -func (c *listSessions) ShortHelp() string { - return "print information about current gopls sessions" -} - -const listSessionsExamples = ` -Examples: - -1) list sessions for the default daemon: - -$ gopls -remote=auto remote sessions -or just -$ gopls remote sessions - -2) list sessions for a specific daemon: - -$ gopls -remote=localhost:8082 remote sessions -` - -func (c *listSessions) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), listSessionsExamples) - printFlagDefaults(f) -} - -func (c *listSessions) Run(ctx context.Context, args ...string) error { - remote := c.app.Remote - if remote == "" { - remote = "auto" - } - state, err := lsprpc.QueryServerState(ctx, remote) - if err != nil { - return err - } - v, err := json.MarshalIndent(state, "", "\t") - if err != nil { - log.Fatal(err) - } - os.Stdout.Write(v) - return nil -} - -type startDebugging struct { - app *Application -} - -func (c *startDebugging) Name() string { return "debug" } -func (c *startDebugging) Usage() string { return "[host:port]" } -func (c *startDebugging) ShortHelp() string { - return "start the debug server" -} - -const startDebuggingExamples = ` -Examples: - -1) start a debug server for the default daemon, on an arbitrary port: - -$ gopls -remote=auto remote debug -or just -$ gopls remote debug - -2) start for a specific daemon, on a specific port: - -$ gopls -remote=localhost:8082 remote debug localhost:8083 -` - -func (c *startDebugging) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), startDebuggingExamples) - printFlagDefaults(f) -} - -func (c *startDebugging) Run(ctx context.Context, args ...string) error { - if len(args) > 1 { - fmt.Fprintln(os.Stderr, c.Usage()) - return errors.New("invalid usage") - } - remote := c.app.Remote - if remote == "" { - remote = "auto" - } - debugAddr := "" - if len(args) > 0 { - debugAddr = args[0] - } - debugArgs := command.DebuggingArgs{ - Addr: debugAddr, - } - var result command.DebuggingResult - if err := lsprpc.ExecuteCommand(ctx, remote, command.StartDebugging.ID(), debugArgs, &result); err != nil { - return err - } - if len(result.URLs) == 0 { - return errors.New("no debugging URLs") - } - for _, url := range result.URLs { - fmt.Printf("debugging on %s\n", url) - } - return nil -} diff --git a/internal/lsp/cmd/rename.go b/internal/lsp/cmd/rename.go deleted file mode 100644 index b0a22a1b4..000000000 --- a/internal/lsp/cmd/rename.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// rename implements the rename verb for gopls. -type rename struct { - Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` - Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` - Preserve bool `flag:"preserve" help:"preserve original files"` - - app *Application -} - -func (r *rename) Name() string { return "rename" } -func (r *rename) Parent() string { return r.app.Name() } -func (r *rename) Usage() string { return "[rename-flags] <position> <name>" } -func (r *rename) ShortHelp() string { return "rename selected identifier" } -func (r *rename) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-based location (:line:column or :#position) of the thing to change - $ gopls rename helper/helper.go:8:6 Foo - $ gopls rename helper/helper.go:#53 Foo - -rename-flags: -`) - printFlagDefaults(f) -} - -// Run renames the specified identifier and either; -// - if -w is specified, updates the file(s) in place; -// - if -d is specified, prints out unified diffs of the changes; or -// - otherwise, prints the new versions to stdout. -func (r *rename) Run(ctx context.Context, args ...string) error { - if len(args) != 2 { - return tool.CommandLineErrorf("definition expects 2 arguments (position, new name)") - } - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - p := protocol.RenameParams{ - TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI}, - Position: loc.Range.Start, - NewName: args[1], - } - edit, err := conn.Rename(ctx, &p) - if err != nil { - return err - } - var orderedURIs []string - edits := map[span.URI][]protocol.TextEdit{} - for _, c := range edit.DocumentChanges { - uri := fileURI(c.TextDocument.URI) - edits[uri] = append(edits[uri], c.Edits...) - orderedURIs = append(orderedURIs, string(uri)) - } - sort.Strings(orderedURIs) - changeCount := len(orderedURIs) - - for _, u := range orderedURIs { - uri := span.URIFromURI(u) - cmdFile := conn.AddFile(ctx, uri) - filename := cmdFile.uri.Filename() - - // convert LSP-style edits to []diff.TextEdit cuz Spans are handy - renameEdits, err := source.FromProtocolEdits(cmdFile.mapper, edits[uri]) - if err != nil { - return errors.Errorf("%v: %v", edits, err) - } - newContent := diff.ApplyEdits(string(cmdFile.mapper.Content), renameEdits) - - switch { - case r.Write: - fmt.Fprintln(os.Stderr, filename) - if r.Preserve { - if err := os.Rename(filename, filename+".orig"); err != nil { - return errors.Errorf("%v: %v", edits, err) - } - } - ioutil.WriteFile(filename, []byte(newContent), 0644) - case r.Diff: - diffs := diff.ToUnified(filename+".orig", filename, string(cmdFile.mapper.Content), renameEdits) - fmt.Print(diffs) - default: - if len(orderedURIs) > 1 { - fmt.Printf("%s:\n", filepath.Base(filename)) - } - fmt.Print(string(newContent)) - if changeCount > 1 { // if this wasn't last change, print newline - fmt.Println() - } - changeCount -= 1 - } - } - return nil -} diff --git a/internal/lsp/cmd/semantictokens.go b/internal/lsp/cmd/semantictokens.go deleted file mode 100644 index 120f91d36..000000000 --- a/internal/lsp/cmd/semantictokens.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "bytes" - "context" - "flag" - "fmt" - "go/parser" - "go/token" - "io/ioutil" - "log" - "os" - "unicode/utf8" - - "golang.org/x/tools/internal/lsp" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" -) - -// generate semantic tokens and interpolate them in the file - -// The output is the input file decorated with comments showing the -// syntactic tokens. The comments are stylized: -// /*<arrow><length>,<token type>,[<modifiers]*/ -// For most occurrences, the comment comes just before the token it -// describes, and arrow is a right arrow. If the token is inside a string -// the comment comes just after the string, and the arrow is a left arrow. -// <length> is the length of the token in runes, <token type> is one -// of the supported semantic token types, and <modifiers. is a -// (possibly empty) list of token type modifiers. - -// There are 3 coordinate systems for lines and character offsets in lines -// LSP (what's returned from semanticTokens()): -// 0-based: the first line is line 0, the first character of a line -// is character 0, and characters are counted as UTF-16 code points -// gopls (and Go error messages): -// 1-based: the first line is line1, the first chararcter of a line -// is character 0, and characters are counted as bytes -// internal (as used in marks, and lines:=bytes.Split(buf, '\n')) -// 0-based: lines and character positions are 1 less than in -// the gopls coordinate system - -type semtok struct { - app *Application -} - -var colmap *protocol.ColumnMapper - -func (c *semtok) Name() string { return "semtok" } -func (c *semtok) Parent() string { return c.app.Name() } -func (c *semtok) Usage() string { return "<filename>" } -func (c *semtok) ShortHelp() string { return "show semantic tokens for the specified file" } -func (c *semtok) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: show the semantic tokens for this file: - - $ gopls semtok internal/lsp/cmd/semtok.go -`) - printFlagDefaults(f) -} - -// Run performs the semtok on the files specified by args and prints the -// results to stdout in the format described above. -func (c *semtok) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return fmt.Errorf("expected one file name, got %d", len(args)) - } - // perhaps simpler if app had just had a FlagSet member - origOptions := c.app.options - c.app.options = func(opts *source.Options) { - origOptions(opts) - opts.SemanticTokens = true - } - conn, err := c.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - uri := span.URIFromPath(args[0]) - file := conn.AddFile(ctx, uri) - if file.err != nil { - return file.err - } - - buf, err := ioutil.ReadFile(args[0]) - if err != nil { - return err - } - lines := bytes.Split(buf, []byte{'\n'}) - p := &protocol.SemanticTokensRangeParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(uri), - }, - Range: protocol.Range{Start: protocol.Position{Line: 0, Character: 0}, - End: protocol.Position{ - Line: uint32(len(lines) - 1), - Character: uint32(len(lines[len(lines)-1]))}, - }, - } - resp, err := conn.semanticTokens(ctx, p) - if err != nil { - return err - } - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, args[0], buf, 0) - if err != nil { - log.Printf("parsing %s failed %v", args[0], err) - return err - } - tok := fset.File(f.Pos()) - if tok == nil { - // can't happen; just parsed this file - return fmt.Errorf("can't find %s in fset", args[0]) - } - tc := span.NewContentConverter(args[0], buf) - colmap = &protocol.ColumnMapper{ - URI: span.URI(args[0]), - Content: buf, - Converter: tc, - } - err = decorate(file.uri.Filename(), resp.Data) - if err != nil { - return err - } - return nil -} - -type mark struct { - line, offset int // 1-based, from RangeSpan - len int // bytes, not runes - typ string - mods []string -} - -// prefixes for semantic token comments -const ( - SemanticLeft = "/*⇐" - SemanticRight = "/*⇒" -) - -func markLine(m mark, lines [][]byte) { - l := lines[m.line-1] // mx is 1-based - length := utf8.RuneCount(l[m.offset-1 : m.offset-1+m.len]) - splitAt := m.offset - 1 - insert := "" - if m.typ == "namespace" && m.offset-1+m.len < len(l) && l[m.offset-1+m.len] == '"' { - // it is the last component of an import spec - // cannot put a comment inside a string - insert = fmt.Sprintf("%s%d,namespace,[]*/", SemanticLeft, length) - splitAt = m.offset + m.len - } else { - // be careful not to generate //* - spacer := "" - if splitAt-1 >= 0 && l[splitAt-1] == '/' { - spacer = " " - } - insert = fmt.Sprintf("%s%s%d,%s,%v*/", spacer, SemanticRight, length, m.typ, m.mods) - } - x := append([]byte(insert), l[splitAt:]...) - l = append(l[:splitAt], x...) - lines[m.line-1] = l -} - -func decorate(file string, result []uint32) error { - buf, err := ioutil.ReadFile(file) - if err != nil { - return err - } - marks := newMarks(result) - if len(marks) == 0 { - return nil - } - lines := bytes.Split(buf, []byte{'\n'}) - for i := len(marks) - 1; i >= 0; i-- { - mx := marks[i] - markLine(mx, lines) - } - os.Stdout.Write(bytes.Join(lines, []byte{'\n'})) - return nil -} - -func newMarks(d []uint32) []mark { - ans := []mark{} - // the following two loops could be merged, at the cost - // of making the logic slightly more complicated to understand - // first, convert from deltas to absolute, in LSP coordinates - lspLine := make([]uint32, len(d)/5) - lspChar := make([]uint32, len(d)/5) - var line, char uint32 - for i := 0; 5*i < len(d); i++ { - lspLine[i] = line + d[5*i+0] - if d[5*i+0] > 0 { - char = 0 - } - lspChar[i] = char + d[5*i+1] - char = lspChar[i] - line = lspLine[i] - } - // second, convert to gopls coordinates - for i := 0; 5*i < len(d); i++ { - pr := protocol.Range{ - Start: protocol.Position{ - Line: lspLine[i], - Character: lspChar[i], - }, - End: protocol.Position{ - Line: lspLine[i], - Character: lspChar[i] + d[5*i+2], - }, - } - spn, err := colmap.RangeSpan(pr) - if err != nil { - log.Fatal(err) - } - m := mark{ - line: spn.Start().Line(), - offset: spn.Start().Column(), - len: spn.End().Column() - spn.Start().Column(), - typ: lsp.SemType(int(d[5*i+3])), - mods: lsp.SemMods(int(d[5*i+4])), - } - ans = append(ans, m) - } - return ans -} diff --git a/internal/lsp/cmd/serve.go b/internal/lsp/cmd/serve.go deleted file mode 100644 index f6e268397..000000000 --- a/internal/lsp/cmd/serve.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "io" - "log" - "os" - "time" - - "golang.org/x/tools/internal/fakenet" - "golang.org/x/tools/internal/jsonrpc2" - "golang.org/x/tools/internal/lsp/cache" - "golang.org/x/tools/internal/lsp/debug" - "golang.org/x/tools/internal/lsp/lsprpc" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// Serve is a struct that exposes the configurable parts of the LSP server as -// flags, in the right form for tool.Main to consume. -type Serve struct { - Logfile string `flag:"logfile" help:"filename to log to. if value is \"auto\", then logging to a default output file is enabled"` - Mode string `flag:"mode" help:"no effect"` - Port int `flag:"port" help:"port on which to run gopls for debugging purposes"` - Address string `flag:"listen" help:"address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used."` - IdleTimeout time.Duration `flag:"listen.timeout" help:"when used with -listen, shut down the server when there are no connected clients for this duration"` - Trace bool `flag:"rpc.trace" help:"print the full rpc trace in lsp inspector format"` - Debug string `flag:"debug" help:"serve debug information on the supplied address"` - - RemoteListenTimeout time.Duration `flag:"remote.listen.timeout" help:"when used with -remote=auto, the -listen.timeout value used to start the daemon"` - RemoteDebug string `flag:"remote.debug" help:"when used with -remote=auto, the -debug value used to start the daemon"` - RemoteLogfile string `flag:"remote.logfile" help:"when used with -remote=auto, the -logfile value used to start the daemon"` - - app *Application -} - -func (s *Serve) Name() string { return "serve" } -func (s *Serve) Parent() string { return s.app.Name() } -func (s *Serve) Usage() string { return "[server-flags]" } -func (s *Serve) ShortHelp() string { - return "run a server for Go code using the Language Server Protocol" -} -func (s *Serve) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` gopls [flags] [server-flags] - -The server communicates using JSONRPC2 on stdin and stdout, and is intended to be run directly as -a child of an editor process. - -server-flags: -`) - printFlagDefaults(f) -} - -func (s *Serve) remoteArgs(network, address string) []string { - args := []string{"serve", - "-listen", fmt.Sprintf(`%s;%s`, network, address), - } - if s.RemoteDebug != "" { - args = append(args, "-debug", s.RemoteDebug) - } - if s.RemoteListenTimeout != 0 { - args = append(args, "-listen.timeout", s.RemoteListenTimeout.String()) - } - if s.RemoteLogfile != "" { - args = append(args, "-logfile", s.RemoteLogfile) - } - return args -} - -// Run configures a server based on the flags, and then runs it. -// It blocks until the server shuts down. -func (s *Serve) Run(ctx context.Context, args ...string) error { - if len(args) > 0 { - return tool.CommandLineErrorf("server does not take arguments, got %v", args) - } - - di := debug.GetInstance(ctx) - isDaemon := s.Address != "" || s.Port != 0 - if di != nil { - closeLog, err := di.SetLogFile(s.Logfile, isDaemon) - if err != nil { - return err - } - defer closeLog() - di.ServerAddress = s.Address - di.MonitorMemory(ctx) - di.Serve(ctx, s.Debug) - } - var ss jsonrpc2.StreamServer - if s.app.Remote != "" { - var err error - ss, err = lsprpc.NewForwarder(s.app.Remote, s.remoteArgs) - if err != nil { - return errors.Errorf("creating forwarder: %w", err) - } - } else { - ss = lsprpc.NewStreamServer(cache.New(s.app.options), isDaemon) - } - - var network, addr string - if s.Address != "" { - network, addr = lsprpc.ParseAddr(s.Address) - } - if s.Port != 0 { - network = "tcp" - addr = fmt.Sprintf(":%v", s.Port) - } - if addr != "" { - log.Printf("Gopls daemon: listening on %s network, address %s...", network, addr) - defer log.Printf("Gopls daemon: exiting") - return jsonrpc2.ListenAndServe(ctx, network, addr, ss, s.IdleTimeout) - } - stream := jsonrpc2.NewHeaderStream(fakenet.NewConn("stdio", os.Stdin, os.Stdout)) - if s.Trace && di != nil { - stream = protocol.LoggingStream(stream, di.LogWriter) - } - conn := jsonrpc2.NewConn(stream) - err := ss.ServeStream(ctx, conn) - if errors.Is(err, io.EOF) { - return nil - } - return err -} diff --git a/internal/lsp/cmd/signature.go b/internal/lsp/cmd/signature.go deleted file mode 100644 index db9484301..000000000 --- a/internal/lsp/cmd/signature.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// signature implements the signature verb for gopls -type signature struct { - app *Application -} - -func (r *signature) Name() string { return "signature" } -func (r *signature) Parent() string { return r.app.Name() } -func (r *signature) Usage() string { return "<position>" } -func (r *signature) ShortHelp() string { return "display selected identifier's signature" } -func (r *signature) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls signature helper/helper.go:8:6 - $ gopls signature helper/helper.go:#53 -`) - printFlagDefaults(f) -} - -func (r *signature) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("signature expects 1 argument (position)") - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - file := conn.AddFile(ctx, from.URI()) - if file.err != nil { - return file.err - } - - loc, err := file.mapper.Location(from) - if err != nil { - return err - } - - tdpp := protocol.TextDocumentPositionParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(from.URI()), - }, - Position: loc.Range.Start, - } - p := protocol.SignatureHelpParams{ - TextDocumentPositionParams: tdpp, - } - - s, err := conn.SignatureHelp(ctx, &p) - if err != nil { - return err - } - - if s == nil || len(s.Signatures) == 0 { - return tool.CommandLineErrorf("%v: not a function", from) - } - - // there is only ever one possible signature, - // see toProtocolSignatureHelp in lsp/signature_help.go - signature := s.Signatures[0] - fmt.Printf("%s\n", signature.Label) - if signature.Documentation != "" { - fmt.Printf("\n%s\n", signature.Documentation) - } - - return nil -} diff --git a/internal/lsp/cmd/subcommands.go b/internal/lsp/cmd/subcommands.go deleted file mode 100644 index deac5c822..000000000 --- a/internal/lsp/cmd/subcommands.go +++ /dev/null @@ -1,44 +0,0 @@ -// 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 cmd - -import ( - "context" - "flag" - "fmt" - "text/tabwriter" - - "golang.org/x/tools/internal/tool" -) - -// subcommands is a helper that may be embedded for commands that delegate to -// subcommands. -type subcommands []tool.Application - -func (s subcommands) DetailedHelp(f *flag.FlagSet) { - w := tabwriter.NewWriter(f.Output(), 0, 0, 2, ' ', 0) - defer w.Flush() - fmt.Fprint(w, "\nSubcommand:\n") - for _, c := range s { - fmt.Fprintf(w, " %s\t%s\n", c.Name(), c.ShortHelp()) - } - printFlagDefaults(f) -} - -func (s subcommands) Usage() string { return "<subcommand> [arg]..." } - -func (s subcommands) Run(ctx context.Context, args ...string) error { - if len(args) == 0 { - return tool.CommandLineErrorf("must provide subcommand") - } - command, args := args[0], args[1:] - for _, c := range s { - if c.Name() == command { - s := flag.NewFlagSet(c.Name(), flag.ExitOnError) - return tool.Run(ctx, s, c, args) - } - } - return tool.CommandLineErrorf("unknown subcommand %v", command) -} diff --git a/internal/lsp/cmd/suggested_fix.go b/internal/lsp/cmd/suggested_fix.go deleted file mode 100644 index df14631da..000000000 --- a/internal/lsp/cmd/suggested_fix.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" - errors "golang.org/x/xerrors" -) - -// suggestedFix implements the fix verb for gopls. -type suggestedFix struct { - Diff bool `flag:"d,diff" help:"display diffs instead of rewriting files"` - Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"` - All bool `flag:"a,all" help:"apply all fixes, not just preferred fixes"` - - app *Application -} - -func (s *suggestedFix) Name() string { return "fix" } -func (s *suggestedFix) Parent() string { return s.app.Name() } -func (s *suggestedFix) Usage() string { return "[fix-flags] <filename>" } -func (s *suggestedFix) ShortHelp() string { return "apply suggested fixes" } -func (s *suggestedFix) DetailedHelp(f *flag.FlagSet) { - fmt.Fprintf(f.Output(), ` -Example: apply suggested fixes for this file - $ gopls fix -w internal/lsp/cmd/check.go - -fix-flags: -`) - printFlagDefaults(f) -} - -// Run performs diagnostic checks on the file specified and either; -// - if -w is specified, updates the file in place; -// - if -d is specified, prints out unified diffs of the changes; or -// - otherwise, prints the new versions to stdout. -func (s *suggestedFix) Run(ctx context.Context, args ...string) error { - if len(args) < 1 { - return tool.CommandLineErrorf("fix expects at least 1 argument") - } - conn, err := s.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - uri := from.URI() - file := conn.AddFile(ctx, uri) - if file.err != nil { - return file.err - } - - if err := conn.diagnoseFiles(ctx, []span.URI{uri}); err != nil { - return err - } - conn.Client.filesMu.Lock() - defer conn.Client.filesMu.Unlock() - - codeActionKinds := []protocol.CodeActionKind{protocol.QuickFix} - if len(args) > 1 { - codeActionKinds = []protocol.CodeActionKind{} - for _, k := range args[1:] { - codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k)) - } - } - - rng, err := file.mapper.Range(from) - if err != nil { - return err - } - p := protocol.CodeActionParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(uri), - }, - Context: protocol.CodeActionContext{ - Only: codeActionKinds, - Diagnostics: file.diagnostics, - }, - Range: rng, - } - actions, err := conn.CodeAction(ctx, &p) - if err != nil { - return errors.Errorf("%v: %v", from, err) - } - var edits []protocol.TextEdit - for _, a := range actions { - if a.Command != nil { - return fmt.Errorf("ExecuteCommand is not yet supported on the command line") - } - if !a.IsPreferred && !s.All { - continue - } - if !from.HasPosition() { - for _, c := range a.Edit.DocumentChanges { - if fileURI(c.TextDocument.URI) == uri { - edits = append(edits, c.Edits...) - } - } - continue - } - // If the span passed in has a position, then we need to find - // the codeaction that has the same range as the passed in span. - for _, diag := range a.Diagnostics { - spn, err := file.mapper.RangeSpan(diag.Range) - if err != nil { - continue - } - if span.ComparePoint(from.Start(), spn.Start()) == 0 { - for _, c := range a.Edit.DocumentChanges { - if fileURI(c.TextDocument.URI) == uri { - edits = append(edits, c.Edits...) - } - } - break - } - } - - // If suggested fix is not a diagnostic, still must collect edits. - if len(a.Diagnostics) == 0 { - for _, c := range a.Edit.DocumentChanges { - if fileURI(c.TextDocument.URI) == uri { - edits = append(edits, c.Edits...) - } - } - } - } - - sedits, err := source.FromProtocolEdits(file.mapper, edits) - if err != nil { - return errors.Errorf("%v: %v", edits, err) - } - newContent := diff.ApplyEdits(string(file.mapper.Content), sedits) - - filename := file.uri.Filename() - switch { - case s.Write: - if len(edits) > 0 { - ioutil.WriteFile(filename, []byte(newContent), 0644) - } - case s.Diff: - diffs := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits) - fmt.Print(diffs) - default: - fmt.Print(string(newContent)) - } - return nil -} diff --git a/internal/lsp/cmd/symbols.go b/internal/lsp/cmd/symbols.go deleted file mode 100644 index b43a6dcd1..000000000 --- a/internal/lsp/cmd/symbols.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "sort" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -// symbols implements the symbols verb for gopls -type symbols struct { - app *Application -} - -func (r *symbols) Name() string { return "symbols" } -func (r *symbols) Parent() string { return r.app.Name() } -func (r *symbols) Usage() string { return "<file>" } -func (r *symbols) ShortHelp() string { return "display selected file's symbols" } -func (r *symbols) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - $ gopls symbols helper/helper.go -`) - printFlagDefaults(f) -} -func (r *symbols) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("symbols expects 1 argument (position)") - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - from := span.Parse(args[0]) - p := protocol.DocumentSymbolParams{ - TextDocument: protocol.TextDocumentIdentifier{ - URI: protocol.URIFromSpanURI(from.URI()), - }, - } - symbols, err := conn.DocumentSymbol(ctx, &p) - if err != nil { - return err - } - for _, s := range symbols { - if m, ok := s.(map[string]interface{}); ok { - s, err = mapToSymbol(m) - if err != nil { - return err - } - } - switch t := s.(type) { - case protocol.DocumentSymbol: - printDocumentSymbol(t) - case protocol.SymbolInformation: - printSymbolInformation(t) - } - } - return nil -} - -func mapToSymbol(m map[string]interface{}) (interface{}, error) { - b, err := json.Marshal(m) - if err != nil { - return nil, err - } - - if _, ok := m["selectionRange"]; ok { - var s protocol.DocumentSymbol - if err := json.Unmarshal(b, &s); err != nil { - return nil, err - } - return s, nil - } - - var s protocol.SymbolInformation - if err := json.Unmarshal(b, &s); err != nil { - return nil, err - } - return s, nil -} - -func printDocumentSymbol(s protocol.DocumentSymbol) { - fmt.Printf("%s %s %s\n", s.Name, s.Kind, positionToString(s.SelectionRange)) - // Sort children for consistency - sort.Slice(s.Children, func(i, j int) bool { - return s.Children[i].Name < s.Children[j].Name - }) - for _, c := range s.Children { - fmt.Printf("\t%s %s %s\n", c.Name, c.Kind, positionToString(c.SelectionRange)) - } -} - -func printSymbolInformation(s protocol.SymbolInformation) { - fmt.Printf("%s %s %s\n", s.Name, s.Kind, positionToString(s.Location.Range)) -} - -func positionToString(r protocol.Range) string { - return fmt.Sprintf("%v:%v-%v:%v", - r.Start.Line+1, - r.Start.Character+1, - r.End.Line+1, - r.End.Character+1, - ) -} diff --git a/internal/lsp/cmd/test/call_hierarchy.go b/internal/lsp/cmd/test/call_hierarchy.go deleted file mode 100644 index 38f8ed707..000000000 --- a/internal/lsp/cmd/test/call_hierarchy.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2020 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 cmdtest - -import ( - "fmt" - "sort" - "strings" - "testing" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" -) - -func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) { - collectCallSpansString := func(callItems []protocol.CallHierarchyItem) string { - var callSpans []string - for _, call := range callItems { - mapper, err := r.data.Mapper(call.URI.SpanURI()) - if err != nil { - t.Fatal(err) - } - callSpan, err := mapper.Span(protocol.Location{URI: call.URI, Range: call.Range}) - if err != nil { - t.Fatal(err) - } - callSpans = append(callSpans, fmt.Sprint(callSpan)) - } - // to make tests deterministic - sort.Strings(callSpans) - return r.Normalize(strings.Join(callSpans, "\n")) - } - - expectIn, expectOut := collectCallSpansString(expectedCalls.IncomingCalls), collectCallSpansString(expectedCalls.OutgoingCalls) - expectIdent := r.Normalize(fmt.Sprint(spn)) - - uri := spn.URI() - filename := uri.Filename() - target := filename + fmt.Sprintf(":%v:%v", spn.Start().Line(), spn.Start().Column()) - - got, stderr := r.NormalizeGoplsCmd(t, "call_hierarchy", target) - if stderr != "" { - t.Fatalf("call_hierarchy failed for %s: %s", target, stderr) - } - - gotIn, gotIdent, gotOut := cleanCallHierarchyCmdResult(got) - if expectIn != gotIn { - t.Errorf("incoming calls call_hierarchy failed for %s expected:\n%s\ngot:\n%s", target, expectIn, gotIn) - } - if expectIdent != gotIdent { - t.Errorf("call_hierarchy failed for %s expected:\n%s\ngot:\n%s", target, expectIdent, gotIdent) - } - if expectOut != gotOut { - t.Errorf("outgoing calls call_hierarchy failed for %s expected:\n%s\ngot:\n%s", target, expectOut, gotOut) - } - -} - -// parses function URI and Range from call hierarchy cmd output to -// incoming, identifier and outgoing calls (returned in that order) -// ex: "identifier: function d at .../callhierarchy/callhierarchy.go:19:6-7" -> ".../callhierarchy/callhierarchy.go:19:6-7" -func cleanCallHierarchyCmdResult(output string) (incoming, ident, outgoing string) { - var incomingCalls, outgoingCalls []string - for _, out := range strings.Split(output, "\n") { - if out == "" { - continue - } - - callLocation := out[strings.LastIndex(out, " ")+1:] - if strings.HasPrefix(out, "caller") { - incomingCalls = append(incomingCalls, callLocation) - } else if strings.HasPrefix(out, "callee") { - outgoingCalls = append(outgoingCalls, callLocation) - } else { - ident = callLocation - } - } - sort.Strings(incomingCalls) - sort.Strings(outgoingCalls) - incoming, outgoing = strings.Join(incomingCalls, "\n"), strings.Join(outgoingCalls, "\n") - return -} diff --git a/internal/lsp/cmd/test/check.go b/internal/lsp/cmd/test/check.go deleted file mode 100644 index f0e6d8fef..000000000 --- a/internal/lsp/cmd/test/check.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "io/ioutil" - "strings" - "testing" - - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" -) - -func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnostic) { - if len(want) == 1 && want[0].Message == "" { - return - } - fname := uri.Filename() - out, _ := r.runGoplsCmd(t, "check", fname) - // parse got into a collection of reports - got := map[string]struct{}{} - for _, l := range strings.Split(out, "\n") { - if len(l) == 0 { - continue - } - // parse and reprint to normalize the span - bits := strings.SplitN(l, ": ", 2) - if len(bits) == 2 { - spn := span.Parse(strings.TrimSpace(bits[0])) - spn = span.New(spn.URI(), spn.Start(), span.Point{}) - data, err := ioutil.ReadFile(fname) - if err != nil { - t.Fatal(err) - } - converter := span.NewContentConverter(fname, data) - s, err := spn.WithPosition(converter) - if err != nil { - t.Fatal(err) - } - l = fmt.Sprintf("%s: %s", s, strings.TrimSpace(bits[1])) - } - got[r.NormalizePrefix(l)] = struct{}{} - } - for _, diag := range want { - expect := fmt.Sprintf("%v:%v:%v: %v", uri.Filename(), diag.Range.Start.Line+1, diag.Range.Start.Character+1, diag.Message) - if diag.Range.Start.Character == 0 { - expect = fmt.Sprintf("%v:%v: %v", uri.Filename(), diag.Range.Start.Line+1, diag.Message) - } - expect = r.NormalizePrefix(expect) - _, found := got[expect] - if !found { - t.Errorf("missing diagnostic %q, %v", expect, got) - } else { - delete(got, expect) - } - } - for extra := range got { - t.Errorf("extra diagnostic %q", extra) - } -} diff --git a/internal/lsp/cmd/test/cmdtest.go b/internal/lsp/cmd/test/cmdtest.go deleted file mode 100644 index 312f7b8b4..000000000 --- a/internal/lsp/cmd/test/cmdtest.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package cmdtest contains the test suite for the command line behavior of gopls. -package cmdtest - -import ( - "bytes" - "context" - "flag" - "fmt" - "io" - "os" - "sync" - "testing" - - "golang.org/x/tools/internal/jsonrpc2/servertest" - "golang.org/x/tools/internal/lsp/cache" - "golang.org/x/tools/internal/lsp/cmd" - "golang.org/x/tools/internal/lsp/debug" - "golang.org/x/tools/internal/lsp/lsprpc" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/tool" -) - -type runner struct { - data *tests.Data - ctx context.Context - options func(*source.Options) - normalizers []tests.Normalizer - remote string -} - -func TestCommandLine(t *testing.T, testdata string, options func(*source.Options)) { - // On Android, the testdata directory is not copied to the runner. - if stat, err := os.Stat(testdata); err != nil || !stat.IsDir() { - t.Skip("testdata directory not present") - } - tests.RunTests(t, testdata, false, func(t *testing.T, datum *tests.Data) { - ctx := tests.Context(t) - ts := NewTestServer(ctx, options) - tests.Run(t, NewRunner(datum, ctx, ts.Addr, options), datum) - cmd.CloseTestConnections(ctx) - }) -} - -func NewTestServer(ctx context.Context, options func(*source.Options)) *servertest.TCPServer { - ctx = debug.WithInstance(ctx, "", "") - cache := cache.New(options) - ss := lsprpc.NewStreamServer(cache, false) - return servertest.NewTCPServer(ctx, ss, nil) -} - -func NewRunner(data *tests.Data, ctx context.Context, remote string, options func(*source.Options)) *runner { - return &runner{ - data: data, - ctx: ctx, - options: options, - normalizers: tests.CollectNormalizers(data.Exported), - remote: remote, - } -} - -func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) { - //TODO: add command line completions tests when it works -} - -func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { - //TODO: add command line completions tests when it works -} - -func (r *runner) FunctionExtraction(t *testing.T, start span.Span, end span.Span) { - //TODO: function extraction not supported on command line -} - -func (r *runner) MethodExtraction(t *testing.T, start span.Span, end span.Span) { - //TODO: function extraction not supported on command line -} - -func (r *runner) AddImport(t *testing.T, uri span.URI, expectedImport string) { - //TODO: import addition not supported on command line -} - -func (r *runner) Hover(t *testing.T, spn span.Span, info string) { - //TODO: hovering not supported on command line -} - -func (r *runner) runGoplsCmd(t testing.TB, args ...string) (string, string) { - rStdout, wStdout, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - oldStdout := os.Stdout - rStderr, wStderr, err := os.Pipe() - if err != nil { - t.Fatal(err) - } - oldStderr := os.Stderr - stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{} - var wg sync.WaitGroup - wg.Add(2) - go func() { - io.Copy(stdout, rStdout) - wg.Done() - }() - go func() { - io.Copy(stderr, rStderr) - wg.Done() - }() - os.Stdout, os.Stderr = wStdout, wStderr - app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env, r.options) - remote := r.remote - s := flag.NewFlagSet(app.Name(), flag.ExitOnError) - err = tool.Run(tests.Context(t), s, - app, - append([]string{fmt.Sprintf("-remote=internal@%s", remote)}, args...)) - if err != nil { - fmt.Fprint(os.Stderr, err) - } - wStdout.Close() - wStderr.Close() - wg.Wait() - os.Stdout, os.Stderr = oldStdout, oldStderr - rStdout.Close() - rStderr.Close() - return stdout.String(), stderr.String() -} - -// NormalizeGoplsCmd runs the gopls command and normalizes its output. -func (r *runner) NormalizeGoplsCmd(t testing.TB, args ...string) (string, string) { - stdout, stderr := r.runGoplsCmd(t, args...) - return r.Normalize(stdout), r.Normalize(stderr) -} - -func (r *runner) Normalize(s string) string { - return tests.Normalize(s, r.normalizers) -} - -func (r *runner) NormalizePrefix(s string) string { - return tests.NormalizePrefix(s, r.normalizers) -} diff --git a/internal/lsp/cmd/test/definition.go b/internal/lsp/cmd/test/definition.go deleted file mode 100644 index c82d9a6c1..000000000 --- a/internal/lsp/cmd/test/definition.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "runtime" - "strings" - "testing" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/diff/myers" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" -) - -type godefMode int - -const ( - plainGodef = godefMode(1 << iota) - jsonGoDef -) - -var godefModes = []godefMode{ - plainGodef, - jsonGoDef, -} - -func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) { - if d.IsType || d.OnlyHover { - // TODO: support type definition, hover queries - return - } - d.Src = span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{}) - for _, mode := range godefModes { - args := []string{"definition", "-markdown"} - tag := d.Name + "-definition" - if mode&jsonGoDef != 0 { - tag += "-json" - args = append(args, "-json") - } - uri := d.Src.URI() - args = append(args, fmt.Sprint(d.Src)) - got, _ := r.NormalizeGoplsCmd(t, args...) - if mode&jsonGoDef != 0 && runtime.GOOS == "windows" { - got = strings.Replace(got, "file:///", "file://", -1) - } - expect := strings.TrimSpace(string(r.data.Golden(tag, uri.Filename(), func() ([]byte, error) { - return []byte(got), nil - }))) - if expect != "" && !strings.HasPrefix(got, expect) { - d, err := myers.ComputeEdits("", expect, got) - if err != nil { - t.Fatal(err) - } - t.Errorf("definition %v failed with %#v\n%s", tag, args, diff.ToUnified("expect", "got", expect, d)) - } - } -} diff --git a/internal/lsp/cmd/test/folding_range.go b/internal/lsp/cmd/test/folding_range.go deleted file mode 100644 index 4478687b5..000000000 --- a/internal/lsp/cmd/test/folding_range.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "testing" - - "golang.org/x/tools/internal/span" -) - -func (r *runner) FoldingRanges(t *testing.T, spn span.Span) { - goldenTag := "foldingRange-cmd" - uri := spn.URI() - filename := uri.Filename() - got, _ := r.NormalizeGoplsCmd(t, "folding_ranges", filename) - expect := string(r.data.Golden(goldenTag, filename, func() ([]byte, error) { - return []byte(got), nil - })) - - if expect != got { - t.Errorf("folding_ranges failed failed for %s expected:\n%s\ngot:\n%s", filename, expect, got) - } -} diff --git a/internal/lsp/cmd/test/format.go b/internal/lsp/cmd/test/format.go deleted file mode 100644 index 77eedd440..000000000 --- a/internal/lsp/cmd/test/format.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "bytes" - exec "golang.org/x/sys/execabs" - "io/ioutil" - "os" - "regexp" - "strings" - "testing" - - "golang.org/x/tools/internal/span" - "golang.org/x/tools/internal/testenv" -) - -func (r *runner) Format(t *testing.T, spn span.Span) { - tag := "gofmt" - uri := spn.URI() - filename := uri.Filename() - expect := string(r.data.Golden(tag, filename, func() ([]byte, error) { - cmd := exec.Command("gofmt", filename) - contents, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files - contents = []byte(r.Normalize(fixFileHeader(string(contents)))) - return contents, nil - })) - if expect == "" { - //TODO: our error handling differs, for now just skip unformattable files - t.Skip("Unformattable file") - } - got, _ := r.NormalizeGoplsCmd(t, "format", filename) - if expect != got { - t.Errorf("format failed for %s expected:\n%s\ngot:\n%s", filename, expect, got) - } - // now check we can build a valid unified diff - unified, _ := r.NormalizeGoplsCmd(t, "format", "-d", filename) - checkUnified(t, filename, expect, unified) -} - -var unifiedHeader = regexp.MustCompile(`^diff -u.*\n(---\s+\S+\.go\.orig)\s+[\d-:. ]+(\n\+\+\+\s+\S+\.go)\s+[\d-:. ]+(\n@@)`) - -func fixFileHeader(s string) string { - match := unifiedHeader.FindStringSubmatch(s) - if match == nil { - return s - } - return strings.Join(append(match[1:], s[len(match[0]):]), "") -} - -func checkUnified(t *testing.T, filename string, expect string, patch string) { - testenv.NeedsTool(t, "patch") - if strings.Count(patch, "\n+++ ") > 1 { - // TODO(golang/go/#34580) - t.Skip("multi-file patch tests not supported yet") - } - applied := "" - if patch == "" { - applied = expect - } else { - temp, err := ioutil.TempFile("", "applied") - if err != nil { - t.Fatal(err) - } - temp.Close() - defer os.Remove(temp.Name()) - cmd := exec.Command("patch", "-u", "-p0", "-o", temp.Name(), filename) - cmd.Stdin = bytes.NewBuffer([]byte(patch)) - msg, err := cmd.CombinedOutput() - if err != nil { - t.Errorf("failed applying patch to %s: %v\ngot:\n%s\npatch:\n%s", filename, err, msg, patch) - return - } - out, err := ioutil.ReadFile(temp.Name()) - if err != nil { - t.Errorf("failed reading patched output for %s: %v\n", filename, err) - return - } - applied = string(out) - } - if expect != applied { - t.Errorf("apply unified gave wrong result for %s expected:\n%s\ngot:\n%s\npatch:\n%s", filename, expect, applied, patch) - } -} diff --git a/internal/lsp/cmd/test/highlight.go b/internal/lsp/cmd/test/highlight.go deleted file mode 100644 index 99e8b2c3f..000000000 --- a/internal/lsp/cmd/test/highlight.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "testing" - - "fmt" - - "golang.org/x/tools/internal/span" -) - -func (r *runner) Highlight(t *testing.T, spn span.Span, spans []span.Span) { - var expect string - for _, l := range spans { - expect += fmt.Sprintln(l) - } - expect = r.Normalize(expect) - - uri := spn.URI() - filename := uri.Filename() - target := filename + ":" + fmt.Sprint(spn.Start().Line()) + ":" + fmt.Sprint(spn.Start().Column()) - got, _ := r.NormalizeGoplsCmd(t, "highlight", target) - if expect != got { - t.Errorf("highlight failed for %s expected:\n%s\ngot:\n%s", target, expect, got) - } -} diff --git a/internal/lsp/cmd/test/implementation.go b/internal/lsp/cmd/test/implementation.go deleted file mode 100644 index 189452466..000000000 --- a/internal/lsp/cmd/test/implementation.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "sort" - "testing" - - "golang.org/x/tools/internal/span" -) - -func (r *runner) Implementation(t *testing.T, spn span.Span, imps []span.Span) { - var itemStrings []string - for _, i := range imps { - itemStrings = append(itemStrings, fmt.Sprint(i)) - } - sort.Strings(itemStrings) - var expect string - for _, i := range itemStrings { - expect += i + "\n" - } - expect = r.Normalize(expect) - - uri := spn.URI() - filename := uri.Filename() - target := filename + fmt.Sprintf(":%v:%v", spn.Start().Line(), spn.Start().Column()) - - got, stderr := r.NormalizeGoplsCmd(t, "implementation", target) - if stderr != "" { - t.Errorf("implementation failed for %s: %s", target, stderr) - } else if expect != got { - t.Errorf("implementation failed for %s expected:\n%s\ngot:\n%s", target, expect, got) - } -} diff --git a/internal/lsp/cmd/test/imports.go b/internal/lsp/cmd/test/imports.go deleted file mode 100644 index ce8aee55d..000000000 --- a/internal/lsp/cmd/test/imports.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "testing" - - "golang.org/x/tools/internal/lsp/diff" - "golang.org/x/tools/internal/lsp/diff/myers" - "golang.org/x/tools/internal/span" -) - -func (r *runner) Import(t *testing.T, spn span.Span) { - uri := spn.URI() - filename := uri.Filename() - got, _ := r.NormalizeGoplsCmd(t, "imports", filename) - want := string(r.data.Golden("goimports", filename, func() ([]byte, error) { - return []byte(got), nil - })) - if want != got { - d, err := myers.ComputeEdits(uri, want, got) - if err != nil { - t.Fatal(err) - } - t.Errorf("imports failed for %s, expected:\n%s", filename, diff.ToUnified("want", "got", want, d)) - } -} diff --git a/internal/lsp/cmd/test/links.go b/internal/lsp/cmd/test/links.go deleted file mode 100644 index 88df76832..000000000 --- a/internal/lsp/cmd/test/links.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "encoding/json" - "testing" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" -) - -func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) { - m, err := r.data.Mapper(uri) - if err != nil { - t.Fatal(err) - } - out, _ := r.NormalizeGoplsCmd(t, "links", "-json", uri.Filename()) - var got []protocol.DocumentLink - err = json.Unmarshal([]byte(out), &got) - if err != nil { - t.Fatal(err) - } - if diff := tests.DiffLinks(m, wantLinks, got); diff != "" { - t.Error(diff) - } -} diff --git a/internal/lsp/cmd/test/prepare_rename.go b/internal/lsp/cmd/test/prepare_rename.go deleted file mode 100644 index b5359e57b..000000000 --- a/internal/lsp/cmd/test/prepare_rename.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "testing" - - "golang.org/x/tools/internal/lsp/cmd" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/span" -) - -func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) { - m, err := r.data.Mapper(src.URI()) - if err != nil { - t.Errorf("prepare_rename failed: %v", err) - } - - var ( - target = fmt.Sprintf("%v", src) - args = []string{"prepare_rename", target} - stdOut, stdErr = r.NormalizeGoplsCmd(t, args...) - expect string - ) - - if want.Text == "" { - if stdErr != "" && stdErr != cmd.ErrInvalidRenamePosition.Error() { - t.Errorf("prepare_rename failed for %s,\nexpected:\n`%v`\ngot:\n`%v`", target, expect, stdErr) - } - return - } - - ws, err := m.Span(protocol.Location{Range: want.Range}) - if err != nil { - t.Errorf("prepare_rename failed: %v", err) - } - - expect = r.Normalize(fmt.Sprintln(ws)) - if expect != stdOut { - t.Errorf("prepare_rename failed for %s expected:\n`%s`\ngot:\n`%s`\n", target, expect, stdOut) - } -} diff --git a/internal/lsp/cmd/test/references.go b/internal/lsp/cmd/test/references.go deleted file mode 100644 index 66d0d0662..000000000 --- a/internal/lsp/cmd/test/references.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "sort" - "testing" - - "golang.org/x/tools/internal/span" -) - -func (r *runner) References(t *testing.T, spn span.Span, itemList []span.Span) { - for _, includeDeclaration := range []bool{true, false} { - t.Run(fmt.Sprintf("refs-declaration-%v", includeDeclaration), func(t *testing.T) { - var itemStrings []string - for i, s := range itemList { - // We don't want the first result if we aren't including the declaration. - if i == 0 && !includeDeclaration { - continue - } - itemStrings = append(itemStrings, fmt.Sprint(s)) - } - sort.Strings(itemStrings) - var expect string - for _, s := range itemStrings { - expect += s + "\n" - } - expect = r.Normalize(expect) - - uri := spn.URI() - filename := uri.Filename() - target := filename + fmt.Sprintf(":%v:%v", spn.Start().Line(), spn.Start().Column()) - args := []string{"references"} - if includeDeclaration { - args = append(args, "-d") - } - args = append(args, target) - got, stderr := r.NormalizeGoplsCmd(t, args...) - if stderr != "" { - t.Errorf("references failed for %s: %s", target, stderr) - } else if expect != got { - t.Errorf("references failed for %s expected:\n%s\ngot:\n%s", target, expect, got) - } - }) - } -} diff --git a/internal/lsp/cmd/test/rename.go b/internal/lsp/cmd/test/rename.go deleted file mode 100644 index 0fe2d1e18..000000000 --- a/internal/lsp/cmd/test/rename.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "testing" - - "golang.org/x/tools/internal/span" -) - -func (r *runner) Rename(t *testing.T, spn span.Span, newText string) { - filename := spn.URI().Filename() - goldenTag := newText + "-rename" - loc := fmt.Sprintf("%v", spn) - got, err := r.NormalizeGoplsCmd(t, "rename", loc, newText) - got += err - expect := string(r.data.Golden(goldenTag, filename, func() ([]byte, error) { - return []byte(got), nil - })) - if expect != got { - t.Errorf("rename failed with %v %v\nexpected:\n%s\ngot:\n%s", loc, newText, expect, got) - } - // now check we can build a valid unified diff - unified, _ := r.NormalizeGoplsCmd(t, "rename", "-d", loc, newText) - checkUnified(t, filename, expect, unified) -} diff --git a/internal/lsp/cmd/test/semanticdriver.go b/internal/lsp/cmd/test/semanticdriver.go deleted file mode 100644 index 80dc61e3d..000000000 --- a/internal/lsp/cmd/test/semanticdriver.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 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 cmdtest - -import ( - "strings" - "testing" - - "golang.org/x/tools/internal/span" -) - -func (r *runner) SemanticTokens(t *testing.T, spn span.Span) { - uri := spn.URI() - filename := uri.Filename() - got, stderr := r.NormalizeGoplsCmd(t, "semtok", filename) - if stderr != "" { - t.Fatalf("%s: %q", filename, stderr) - } - want := string(r.data.Golden("semantic", filename, func() ([]byte, error) { - return []byte(got), nil - })) - if want != got { - lwant := strings.Split(want, "\n") - lgot := strings.Split(got, "\n") - t.Errorf("want(%d-%d) != got(%d-%d) for %s", len(want), len(lwant), len(got), len(lgot), r.Normalize(filename)) - for i := 0; i < len(lwant) && i < len(lgot); i++ { - if lwant[i] != lgot[i] { - t.Errorf("line %d:\nwant%q\ngot %q\n", i, lwant[i], lgot[i]) - } - } - } -} diff --git a/internal/lsp/cmd/test/signature.go b/internal/lsp/cmd/test/signature.go deleted file mode 100644 index f6bdaebf3..000000000 --- a/internal/lsp/cmd/test/signature.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "testing" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" -) - -func (r *runner) SignatureHelp(t *testing.T, spn span.Span, want *protocol.SignatureHelp) { - uri := spn.URI() - filename := uri.Filename() - target := filename + fmt.Sprintf(":%v:%v", spn.Start().Line(), spn.Start().Column()) - got, _ := r.NormalizeGoplsCmd(t, "signature", target) - if want == nil { - if got != "" { - t.Fatalf("want nil, but got %s", got) - } - return - } - goldenTag := want.Signatures[0].Label + "-signature" - expect := string(r.data.Golden(goldenTag, filename, func() ([]byte, error) { - return []byte(got), nil - })) - if tests.NormalizeAny(expect) != tests.NormalizeAny(got) { - t.Errorf("signature failed for %s expected:\n%q\ngot:\n%q'", filename, expect, got) - } -} diff --git a/internal/lsp/cmd/test/suggested_fix.go b/internal/lsp/cmd/test/suggested_fix.go deleted file mode 100644 index c819e0517..000000000 --- a/internal/lsp/cmd/test/suggested_fix.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "fmt" - "testing" - - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" -) - -func (r *runner) SuggestedFix(t *testing.T, spn span.Span, actionKinds []string, expectedActions int) { - uri := spn.URI() - filename := uri.Filename() - args := []string{"fix", "-a", fmt.Sprintf("%s", spn)} - for _, kind := range actionKinds { - if kind == "refactor.rewrite" { - t.Skip("refactor.rewrite is not yet supported on the command line") - } - } - args = append(args, actionKinds...) - got, stderr := r.NormalizeGoplsCmd(t, args...) - if stderr == "ExecuteCommand is not yet supported on the command line" { - return // don't skip to keep the summary counts correct - } - want := string(r.data.Golden("suggestedfix_"+tests.SpanName(spn), filename, func() ([]byte, error) { - return []byte(got), nil - })) - if want != got { - t.Errorf("suggested fixes failed for %s:\n%s", filename, tests.Diff(t, want, got)) - } -} diff --git a/internal/lsp/cmd/test/symbols.go b/internal/lsp/cmd/test/symbols.go deleted file mode 100644 index 055be0308..000000000 --- a/internal/lsp/cmd/test/symbols.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmdtest - -import ( - "testing" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/span" -) - -func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) { - filename := uri.Filename() - got, _ := r.NormalizeGoplsCmd(t, "symbols", filename) - expect := string(r.data.Golden("symbols", filename, func() ([]byte, error) { - return []byte(got), nil - })) - if expect != got { - t.Errorf("symbols failed for %s expected:\n%s\ngot:\n%s", filename, expect, got) - } -} diff --git a/internal/lsp/cmd/test/workspace_symbol.go b/internal/lsp/cmd/test/workspace_symbol.go deleted file mode 100644 index ce965f03a..000000000 --- a/internal/lsp/cmd/test/workspace_symbol.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2020 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 cmdtest - -import ( - "fmt" - "path/filepath" - "sort" - "strings" - "testing" - - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/lsp/tests" - "golang.org/x/tools/internal/span" -) - -func (r *runner) WorkspaceSymbols(t *testing.T, uri span.URI, query string, typ tests.WorkspaceSymbolsTestType) { - var matcher string - switch typ { - case tests.WorkspaceSymbolsFuzzy: - matcher = "fuzzy" - case tests.WorkspaceSymbolsCaseSensitive: - matcher = "caseSensitive" - case tests.WorkspaceSymbolsDefault: - matcher = "caseInsensitive" - } - r.runWorkspaceSymbols(t, uri, matcher, query) -} - -func (r *runner) runWorkspaceSymbols(t *testing.T, uri span.URI, matcher, query string) { - t.Helper() - - out, _ := r.runGoplsCmd(t, "workspace_symbol", "-matcher", matcher, query) - var filtered []string - dir := filepath.Dir(uri.Filename()) - for _, line := range strings.Split(out, "\n") { - if source.InDir(dir, line) { - filtered = append(filtered, filepath.ToSlash(line)) - } - } - sort.Strings(filtered) - got := r.Normalize(strings.Join(filtered, "\n") + "\n") - - expect := string(r.data.Golden(fmt.Sprintf("workspace_symbol-%s-%s", strings.ToLower(string(matcher)), query), uri.Filename(), func() ([]byte, error) { - return []byte(got), nil - })) - - if expect != got { - t.Errorf("workspace_symbol failed for %s:\n%s", query, tests.Diff(t, expect, got)) - } -} diff --git a/internal/lsp/cmd/usage/api-json.hlp b/internal/lsp/cmd/usage/api-json.hlp deleted file mode 100644 index cb9fbfbea..000000000 --- a/internal/lsp/cmd/usage/api-json.hlp +++ /dev/null @@ -1,4 +0,0 @@ -print json describing gopls API - -Usage: - gopls [flags] api-json diff --git a/internal/lsp/cmd/usage/bug.hlp b/internal/lsp/cmd/usage/bug.hlp deleted file mode 100644 index 772d54d5f..000000000 --- a/internal/lsp/cmd/usage/bug.hlp +++ /dev/null @@ -1,4 +0,0 @@ -report a bug in gopls - -Usage: - gopls [flags] bug diff --git a/internal/lsp/cmd/usage/call_hierarchy.hlp b/internal/lsp/cmd/usage/call_hierarchy.hlp deleted file mode 100644 index 07fccc828..000000000 --- a/internal/lsp/cmd/usage/call_hierarchy.hlp +++ /dev/null @@ -1,10 +0,0 @@ -display selected identifier's call hierarchy - -Usage: - gopls [flags] call_hierarchy <position> - -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls call_hierarchy helper/helper.go:8:6 - $ gopls call_hierarchy helper/helper.go:#53 diff --git a/internal/lsp/cmd/usage/check.hlp b/internal/lsp/cmd/usage/check.hlp deleted file mode 100644 index ba89588d5..000000000 --- a/internal/lsp/cmd/usage/check.hlp +++ /dev/null @@ -1,8 +0,0 @@ -show diagnostic results for the specified file - -Usage: - gopls [flags] check <filename> - -Example: show the diagnostic results of this file: - - $ gopls check internal/lsp/cmd/check.go diff --git a/internal/lsp/cmd/usage/definition.hlp b/internal/lsp/cmd/usage/definition.hlp deleted file mode 100644 index 500e6c9a4..000000000 --- a/internal/lsp/cmd/usage/definition.hlp +++ /dev/null @@ -1,15 +0,0 @@ -show declaration of selected identifier - -Usage: - gopls [flags] definition [definition-flags] <position> - -Example: show the definition of the identifier at syntax at offset 44 in this file (flag.FlagSet): - - $ gopls definition internal/lsp/cmd/definition.go:44:47 - $ gopls definition internal/lsp/cmd/definition.go:#1270 - -definition-flags: - -json - emit output in JSON format - -markdown - support markdown in responses diff --git a/internal/lsp/cmd/usage/fix.hlp b/internal/lsp/cmd/usage/fix.hlp deleted file mode 100644 index 4789a6c5b..000000000 --- a/internal/lsp/cmd/usage/fix.hlp +++ /dev/null @@ -1,15 +0,0 @@ -apply suggested fixes - -Usage: - gopls [flags] fix [fix-flags] <filename> - -Example: apply suggested fixes for this file - $ gopls fix -w internal/lsp/cmd/check.go - -fix-flags: - -a,-all - apply all fixes, not just preferred fixes - -d,-diff - display diffs instead of rewriting files - -w,-write - write result to (source) file instead of stdout diff --git a/internal/lsp/cmd/usage/folding_ranges.hlp b/internal/lsp/cmd/usage/folding_ranges.hlp deleted file mode 100644 index 4af2da615..000000000 --- a/internal/lsp/cmd/usage/folding_ranges.hlp +++ /dev/null @@ -1,8 +0,0 @@ -display selected file's folding ranges - -Usage: - gopls [flags] folding_ranges <file> - -Example: - - $ gopls folding_ranges helper/helper.go diff --git a/internal/lsp/cmd/usage/format.hlp b/internal/lsp/cmd/usage/format.hlp deleted file mode 100644 index 7ef0bbe43..000000000 --- a/internal/lsp/cmd/usage/format.hlp +++ /dev/null @@ -1,18 +0,0 @@ -format the code according to the go standard - -Usage: - gopls [flags] format [format-flags] <filerange> - -The arguments supplied may be simple file names, or ranges within files. - -Example: reformat this file: - - $ gopls format -w internal/lsp/cmd/check.go - -format-flags: - -d,-diff - display diffs instead of rewriting files - -l,-list - list files whose formatting differs from gofmt's - -w,-write - write result to (source) file instead of stdout diff --git a/internal/lsp/cmd/usage/highlight.hlp b/internal/lsp/cmd/usage/highlight.hlp deleted file mode 100644 index e128eb7de..000000000 --- a/internal/lsp/cmd/usage/highlight.hlp +++ /dev/null @@ -1,10 +0,0 @@ -display selected identifier's highlights - -Usage: - gopls [flags] highlight <position> - -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls highlight helper/helper.go:8:6 - $ gopls highlight helper/helper.go:#53 diff --git a/internal/lsp/cmd/usage/implementation.hlp b/internal/lsp/cmd/usage/implementation.hlp deleted file mode 100644 index 09414f190..000000000 --- a/internal/lsp/cmd/usage/implementation.hlp +++ /dev/null @@ -1,10 +0,0 @@ -display selected identifier's implementation - -Usage: - gopls [flags] implementation <position> - -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls implementation helper/helper.go:8:6 - $ gopls implementation helper/helper.go:#53 diff --git a/internal/lsp/cmd/usage/imports.hlp b/internal/lsp/cmd/usage/imports.hlp deleted file mode 100644 index 295f4daa2..000000000 --- a/internal/lsp/cmd/usage/imports.hlp +++ /dev/null @@ -1,14 +0,0 @@ -updates import statements - -Usage: - gopls [flags] imports [imports-flags] <filename> - -Example: update imports statements in a file: - - $ gopls imports -w internal/lsp/cmd/check.go - -imports-flags: - -d,-diff - display diffs instead of rewriting files - -w,-write - write result to (source) file instead of stdout diff --git a/internal/lsp/cmd/usage/inspect.hlp b/internal/lsp/cmd/usage/inspect.hlp deleted file mode 100644 index 3d0a0f3c4..000000000 --- a/internal/lsp/cmd/usage/inspect.hlp +++ /dev/null @@ -1,8 +0,0 @@ -interact with the gopls daemon (deprecated: use 'remote') - -Usage: - gopls [flags] inspect <subcommand> [arg]... - -Subcommand: - sessions print information about current gopls sessions - debug start the debug server diff --git a/internal/lsp/cmd/usage/licenses.hlp b/internal/lsp/cmd/usage/licenses.hlp deleted file mode 100644 index ab60ebc2f..000000000 --- a/internal/lsp/cmd/usage/licenses.hlp +++ /dev/null @@ -1,4 +0,0 @@ -print licenses of included software - -Usage: - gopls [flags] licenses diff --git a/internal/lsp/cmd/usage/links.hlp b/internal/lsp/cmd/usage/links.hlp deleted file mode 100644 index 7f7612ce7..000000000 --- a/internal/lsp/cmd/usage/links.hlp +++ /dev/null @@ -1,12 +0,0 @@ -list links in a file - -Usage: - gopls [flags] links [links-flags] <filename> - -Example: list links contained within a file: - - $ gopls links internal/lsp/cmd/check.go - -links-flags: - -json - emit document links in JSON format diff --git a/internal/lsp/cmd/usage/prepare_rename.hlp b/internal/lsp/cmd/usage/prepare_rename.hlp deleted file mode 100644 index 7f8a6f32d..000000000 --- a/internal/lsp/cmd/usage/prepare_rename.hlp +++ /dev/null @@ -1,10 +0,0 @@ -test validity of a rename operation at location - -Usage: - gopls [flags] prepare_rename <position> - -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls prepare_rename helper/helper.go:8:6 - $ gopls prepare_rename helper/helper.go:#53 diff --git a/internal/lsp/cmd/usage/references.hlp b/internal/lsp/cmd/usage/references.hlp deleted file mode 100644 index c55ef0337..000000000 --- a/internal/lsp/cmd/usage/references.hlp +++ /dev/null @@ -1,14 +0,0 @@ -display selected identifier's references - -Usage: - gopls [flags] references [references-flags] <position> - -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls references helper/helper.go:8:6 - $ gopls references helper/helper.go:#53 - -references-flags: - -d,-declaration - include the declaration of the specified identifier in the results diff --git a/internal/lsp/cmd/usage/remote.hlp b/internal/lsp/cmd/usage/remote.hlp deleted file mode 100644 index dd6034f46..000000000 --- a/internal/lsp/cmd/usage/remote.hlp +++ /dev/null @@ -1,8 +0,0 @@ -interact with the gopls daemon - -Usage: - gopls [flags] remote <subcommand> [arg]... - -Subcommand: - sessions print information about current gopls sessions - debug start the debug server diff --git a/internal/lsp/cmd/usage/rename.hlp b/internal/lsp/cmd/usage/rename.hlp deleted file mode 100644 index ae58cbf60..000000000 --- a/internal/lsp/cmd/usage/rename.hlp +++ /dev/null @@ -1,18 +0,0 @@ -rename selected identifier - -Usage: - gopls [flags] rename [rename-flags] <position> <name> - -Example: - - $ # 1-based location (:line:column or :#position) of the thing to change - $ gopls rename helper/helper.go:8:6 Foo - $ gopls rename helper/helper.go:#53 Foo - -rename-flags: - -d,-diff - display diffs instead of rewriting files - -preserve - preserve original files - -w,-write - write result to (source) file instead of stdout diff --git a/internal/lsp/cmd/usage/semtok.hlp b/internal/lsp/cmd/usage/semtok.hlp deleted file mode 100644 index 459ed596c..000000000 --- a/internal/lsp/cmd/usage/semtok.hlp +++ /dev/null @@ -1,8 +0,0 @@ -show semantic tokens for the specified file - -Usage: - gopls [flags] semtok <filename> - -Example: show the semantic tokens for this file: - - $ gopls semtok internal/lsp/cmd/semtok.go diff --git a/internal/lsp/cmd/usage/serve.hlp b/internal/lsp/cmd/usage/serve.hlp deleted file mode 100644 index 370cbce83..000000000 --- a/internal/lsp/cmd/usage/serve.hlp +++ /dev/null @@ -1,30 +0,0 @@ -run a server for Go code using the Language Server Protocol - -Usage: - gopls [flags] serve [server-flags] - gopls [flags] [server-flags] - -The server communicates using JSONRPC2 on stdin and stdout, and is intended to be run directly as -a child of an editor process. - -server-flags: - -debug=string - serve debug information on the supplied address - -listen=string - address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used. - -listen.timeout=duration - when used with -listen, shut down the server when there are no connected clients for this duration - -logfile=string - filename to log to. if value is "auto", then logging to a default output file is enabled - -mode=string - no effect - -port=int - port on which to run gopls for debugging purposes - -remote.debug=string - when used with -remote=auto, the -debug value used to start the daemon - -remote.listen.timeout=duration - when used with -remote=auto, the -listen.timeout value used to start the daemon (default 1m0s) - -remote.logfile=string - when used with -remote=auto, the -logfile value used to start the daemon - -rpc.trace - print the full rpc trace in lsp inspector format diff --git a/internal/lsp/cmd/usage/signature.hlp b/internal/lsp/cmd/usage/signature.hlp deleted file mode 100644 index f9fd0bfb7..000000000 --- a/internal/lsp/cmd/usage/signature.hlp +++ /dev/null @@ -1,10 +0,0 @@ -display selected identifier's signature - -Usage: - gopls [flags] signature <position> - -Example: - - $ # 1-indexed location (:line:column or :#offset) of the target identifier - $ gopls signature helper/helper.go:8:6 - $ gopls signature helper/helper.go:#53 diff --git a/internal/lsp/cmd/usage/symbols.hlp b/internal/lsp/cmd/usage/symbols.hlp deleted file mode 100644 index 2aa36aa84..000000000 --- a/internal/lsp/cmd/usage/symbols.hlp +++ /dev/null @@ -1,7 +0,0 @@ -display selected file's symbols - -Usage: - gopls [flags] symbols <file> - -Example: - $ gopls symbols helper/helper.go diff --git a/internal/lsp/cmd/usage/usage.hlp b/internal/lsp/cmd/usage/usage.hlp deleted file mode 100644 index 1d0fb8d4c..000000000 --- a/internal/lsp/cmd/usage/usage.hlp +++ /dev/null @@ -1,77 +0,0 @@ - -gopls is a Go language server. - -It is typically used with an editor to provide language features. When no -command is specified, gopls will default to the 'serve' command. The language -features can also be accessed via the gopls command-line interface. - -Usage: - gopls help [<subject>] - -Command: - -Main - serve run a server for Go code using the Language Server Protocol - version print the gopls version information - bug report a bug in gopls - api-json print json describing gopls API - licenses print licenses of included software - -Features - call_hierarchy display selected identifier's call hierarchy - check show diagnostic results for the specified file - definition show declaration of selected identifier - folding_ranges display selected file's folding ranges - format format the code according to the go standard - highlight display selected identifier's highlights - implementation display selected identifier's implementation - imports updates import statements - remote interact with the gopls daemon - inspect interact with the gopls daemon (deprecated: use 'remote') - links list links in a file - prepare_rename test validity of a rename operation at location - references display selected identifier's references - rename rename selected identifier - semtok show semantic tokens for the specified file - signature display selected identifier's signature - fix apply suggested fixes - symbols display selected file's symbols - workspace manage the gopls workspace (experimental: under development) - workspace_symbol search symbols in workspace - vulncheck run experimental vulncheck analysis (experimental: under development) - -flags: - -debug=string - serve debug information on the supplied address - -listen=string - address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used. - -listen.timeout=duration - when used with -listen, shut down the server when there are no connected clients for this duration - -logfile=string - filename to log to. if value is "auto", then logging to a default output file is enabled - -mode=string - no effect - -ocagent=string - the address of the ocagent (e.g. http://localhost:55678), or off (default "off") - -port=int - port on which to run gopls for debugging purposes - -profile.cpu=string - write CPU profile to this file - -profile.mem=string - write memory profile to this file - -profile.trace=string - write trace log to this file - -remote=string - forward all commands to a remote lsp specified by this flag. With no special prefix, this is assumed to be a TCP address. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. If 'auto', or prefixed by 'auto;', the remote address is automatically resolved based on the executing environment. - -remote.debug=string - when used with -remote=auto, the -debug value used to start the daemon - -remote.listen.timeout=duration - when used with -remote=auto, the -listen.timeout value used to start the daemon (default 1m0s) - -remote.logfile=string - when used with -remote=auto, the -logfile value used to start the daemon - -rpc.trace - print the full rpc trace in lsp inspector format - -v,-verbose - verbose output - -vv,-veryverbose - very verbose output diff --git a/internal/lsp/cmd/usage/version.hlp b/internal/lsp/cmd/usage/version.hlp deleted file mode 100644 index 3a09ddedf..000000000 --- a/internal/lsp/cmd/usage/version.hlp +++ /dev/null @@ -1,6 +0,0 @@ -print the gopls version information - -Usage: - gopls [flags] version - -json - outputs in json format. diff --git a/internal/lsp/cmd/usage/vulncheck.hlp b/internal/lsp/cmd/usage/vulncheck.hlp deleted file mode 100644 index 4bfdc4b47..000000000 --- a/internal/lsp/cmd/usage/vulncheck.hlp +++ /dev/null @@ -1,9 +0,0 @@ -run experimental vulncheck analysis (experimental: under development) - -Usage: - gopls [flags] vulncheck - - WARNING: this command is experimental. - - Example: - $ gopls vulncheck <packages> diff --git a/internal/lsp/cmd/usage/workspace.hlp b/internal/lsp/cmd/usage/workspace.hlp deleted file mode 100644 index 912cf2946..000000000 --- a/internal/lsp/cmd/usage/workspace.hlp +++ /dev/null @@ -1,7 +0,0 @@ -manage the gopls workspace (experimental: under development) - -Usage: - gopls [flags] workspace <subcommand> [arg]... - -Subcommand: - generate generate a gopls.mod file for a workspace diff --git a/internal/lsp/cmd/usage/workspace_symbol.hlp b/internal/lsp/cmd/usage/workspace_symbol.hlp deleted file mode 100644 index a61b47b33..000000000 --- a/internal/lsp/cmd/usage/workspace_symbol.hlp +++ /dev/null @@ -1,13 +0,0 @@ -search symbols in workspace - -Usage: - gopls [flags] workspace_symbol [workspace_symbol-flags] <query> - -Example: - - $ gopls workspace_symbol -matcher fuzzy 'wsymbols' - -workspace_symbol-flags: - -matcher=string - specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive. - The default is caseInsensitive. diff --git a/internal/lsp/cmd/vulncheck.go b/internal/lsp/cmd/vulncheck.go deleted file mode 100644 index adf59cecb..000000000 --- a/internal/lsp/cmd/vulncheck.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "encoding/json" - "flag" - "fmt" - "os" - - "golang.org/x/tools/internal/lsp/command" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/tool" -) - -// vulncheck implements the vulncheck command. -type vulncheck struct { - app *Application -} - -func (v *vulncheck) Name() string { return "vulncheck" } -func (v *vulncheck) Parent() string { return v.app.Name() } -func (v *vulncheck) Usage() string { return "" } -func (v *vulncheck) ShortHelp() string { - return "run experimental vulncheck analysis (experimental: under development)" -} -func (v *vulncheck) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` - WARNING: this command is experimental. - - Example: - $ gopls vulncheck <packages> -`) - printFlagDefaults(f) -} - -func (v *vulncheck) Run(ctx context.Context, args ...string) error { - if len(args) > 1 { - return tool.CommandLineErrorf("vulncheck accepts at most one package pattern") - } - pattern := "." - if len(args) == 1 { - pattern = args[0] - } - - conn, err := v.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - cwd, err := os.Getwd() - if err != nil { - return err - } - - cmd, err := command.NewRunVulncheckExpCommand("", command.VulncheckArgs{ - Dir: protocol.URIFromPath(cwd), - Pattern: pattern, - }) - if err != nil { - return err - } - - params := &protocol.ExecuteCommandParams{Command: cmd.Command, Arguments: cmd.Arguments} - res, err := conn.ExecuteCommand(ctx, params) - if err != nil { - return fmt.Errorf("executing server command: %v", err) - } - data, err := json.MarshalIndent(res, " ", " ") - if err != nil { - return fmt.Errorf("failed to decode results: %v", err) - } - fmt.Printf("%s\n", data) - return nil -} diff --git a/internal/lsp/cmd/workspace.go b/internal/lsp/cmd/workspace.go deleted file mode 100644 index c0ddd9eb4..000000000 --- a/internal/lsp/cmd/workspace.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - - "golang.org/x/tools/internal/lsp/command" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" -) - -// workspace is a top-level command for working with the gopls workspace. This -// is experimental and subject to change. The idea is that subcommands could be -// used for manipulating the workspace mod file, rather than editing it -// manually. -type workspace struct { - app *Application - subcommands -} - -func newWorkspace(app *Application) *workspace { - return &workspace{ - app: app, - subcommands: subcommands{ - &generateWorkspaceMod{app: app}, - }, - } -} - -func (w *workspace) Name() string { return "workspace" } -func (w *workspace) Parent() string { return w.app.Name() } -func (w *workspace) ShortHelp() string { - return "manage the gopls workspace (experimental: under development)" -} - -// generateWorkspaceMod (re)generates the gopls.mod file for the current -// workspace. -type generateWorkspaceMod struct { - app *Application -} - -func (c *generateWorkspaceMod) Name() string { return "generate" } -func (c *generateWorkspaceMod) Usage() string { return "" } -func (c *generateWorkspaceMod) ShortHelp() string { - return "generate a gopls.mod file for a workspace" -} - -func (c *generateWorkspaceMod) DetailedHelp(f *flag.FlagSet) { - printFlagDefaults(f) -} - -func (c *generateWorkspaceMod) Run(ctx context.Context, args ...string) error { - origOptions := c.app.options - c.app.options = func(opts *source.Options) { - origOptions(opts) - opts.ExperimentalWorkspaceModule = true - } - conn, err := c.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - cmd, err := command.NewGenerateGoplsModCommand("", command.URIArg{}) - if err != nil { - return err - } - params := &protocol.ExecuteCommandParams{Command: cmd.Command, Arguments: cmd.Arguments} - if _, err := conn.ExecuteCommand(ctx, params); err != nil { - return fmt.Errorf("executing server command: %v", err) - } - return nil -} diff --git a/internal/lsp/cmd/workspace_symbol.go b/internal/lsp/cmd/workspace_symbol.go deleted file mode 100644 index 38fe5decf..000000000 --- a/internal/lsp/cmd/workspace_symbol.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package cmd - -import ( - "context" - "flag" - "fmt" - - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/source" - "golang.org/x/tools/internal/tool" -) - -// workspaceSymbol implements the workspace_symbol verb for gopls. -type workspaceSymbol struct { - Matcher string `flag:"matcher" help:"specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive.\nThe default is caseInsensitive."` - - app *Application -} - -func (r *workspaceSymbol) Name() string { return "workspace_symbol" } -func (r *workspaceSymbol) Parent() string { return r.app.Name() } -func (r *workspaceSymbol) Usage() string { return "[workspace_symbol-flags] <query>" } -func (r *workspaceSymbol) ShortHelp() string { return "search symbols in workspace" } -func (r *workspaceSymbol) DetailedHelp(f *flag.FlagSet) { - fmt.Fprint(f.Output(), ` -Example: - - $ gopls workspace_symbol -matcher fuzzy 'wsymbols' - -workspace_symbol-flags: -`) - printFlagDefaults(f) -} - -func (r *workspaceSymbol) Run(ctx context.Context, args ...string) error { - if len(args) != 1 { - return tool.CommandLineErrorf("workspace_symbol expects 1 argument") - } - - opts := r.app.options - r.app.options = func(o *source.Options) { - if opts != nil { - opts(o) - } - switch r.Matcher { - case "fuzzy": - o.SymbolMatcher = source.SymbolFuzzy - case "caseSensitive": - o.SymbolMatcher = source.SymbolCaseSensitive - case "fastfuzzy": - o.SymbolMatcher = source.SymbolFastFuzzy - default: - o.SymbolMatcher = source.SymbolCaseInsensitive - } - } - - conn, err := r.app.connect(ctx) - if err != nil { - return err - } - defer conn.terminate(ctx) - - p := protocol.WorkspaceSymbolParams{ - Query: args[0], - } - - symbols, err := conn.Symbol(ctx, &p) - if err != nil { - return err - } - for _, s := range symbols { - f := conn.AddFile(ctx, fileURI(s.Location.URI)) - span, err := f.mapper.Span(s.Location) - if err != nil { - return err - } - fmt.Printf("%s %s %s\n", span, s.Name, s.Kind) - } - - return nil -} |