| // 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" | |
| "errors" | |
| "flag" | |
| "fmt" | |
| "log" | |
| "os" | |
| "golang.org/x/tools/gopls/internal/lsprpc" | |
| protocolcommand "golang.org/x/tools/gopls/internal/protocol/command" | |
| ) | |
| type remote struct { | |
| app *application | |
| subcommands | |
| } | |
| func newRemote(app *application) *remote { | |
| return &remote{ | |
| app: app, | |
| subcommands: subcommands{ | |
| &listSessions{app: app}, | |
| &startDebugging{app: app}, | |
| }, | |
| } | |
| } | |
| func (r *remote) Name() string { | |
| return "remote" | |
| } | |
| func (r *remote) Parent() string { return r.app.Name() } | |
| func (r *remote) ShortHelp() string { | |
| return "interact with the gopls daemon" | |
| } | |
| // 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 "gopls remote" } | |
| func (c *listSessions) Usage() string { return "" } | |
| func (c *listSessions) ShortHelp() string { | |
| return "print information about current gopls sessions" | |
| } | |
| const listSessionsExamples = ` | |
| Unlike other subcommands, 'gopls remote' never starts a daemon: it reports an | |
| error if none is listening at the -remote address. | |
| 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) Parent() string { return "gopls remote" } | |
| 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 := protocolcommand.DebuggingArgs{ | |
| Addr: debugAddr, | |
| } | |
| var result protocolcommand.DebuggingResult | |
| if err := lsprpc.ExecuteCommand(ctx, remote, protocolcommand.StartDebugging.String(), 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 | |
| } |