.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / internal / lsp / cmd / cmd.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/internal/lsp/cmd/cmd.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/internal/lsp/cmd/cmd.go
new file mode 100644 (file)
index 0000000..fd9d6f9
--- /dev/null
@@ -0,0 +1,547 @@
+// 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"
+       "strings"
+       "sync"
+       "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" help:"verbose output"`
+
+       // VeryVerbose enables a higher level of verbosity in logging output.
+       VeryVerbose bool `flag:"vv" 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,
+               },
+       }
+       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 "<command> [command-flags] [command-args]" }
+
+// ShortHelp implements tool.Application returning the main binary help.
+func (app *Application) ShortHelp() string {
+       return "The Go Language source tools."
+}
+
+// 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) {
+       fmt.Fprint(f.Output(), `
+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.
+
+Available commands are:
+`)
+       fmt.Fprint(f.Output(), `
+main:
+`)
+       for _, c := range app.mainCommands() {
+               fmt.Fprintf(f.Output(), "  %s : %v\n", c.Name(), c.ShortHelp())
+       }
+       fmt.Fprint(f.Output(), `
+features:
+`)
+       for _, c := range app.featureCommands() {
+               fmt.Fprintf(f.Output(), "  %s : %v\n", c.Name(), c.ShortHelp())
+       }
+       fmt.Fprint(f.Output(), `
+gopls flags are:
+`)
+       f.PrintDefaults()
+}
+
+// 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)
+       app.Serve.app = app
+       if len(args) == 0 {
+               return tool.Run(ctx, &app.Serve, args)
+       }
+       command, args := args[0], args[1:]
+       for _, c := range app.commands() {
+               if c.Name() == command {
+                       return tool.Run(ctx, 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{},
+               &apiJSON{},
+               &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},
+               &inspect{app: app},
+               &links{app: app},
+               &prepareRename{app: app},
+               &references{app: app},
+               &rename{app: app},
+               &semtok{app: app},
+               &signature{app: app},
+               &suggestedFix{app: app},
+               &symbols{app: app},
+               &workspace{app: app},
+               &workspaceSymbol{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(ctx, 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", app.wd, opts)
+               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)
+       network, addr := parseAddr(remote)
+       conn, err := lsprpc.ConnectToRemote(ctx, network, addr)
+       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)
+       }
+       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.ApplyWorkspaceEditResponse, error) {
+       return &protocol.ApplyWorkspaceEditResponse{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) 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: source.DetectLanguage("", file.uri.Filename()).String(),
+                       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, file span.URI) (*protocol.SemanticTokens, error) {
+       p := &protocol.SemanticTokensParams{
+               TextDocument: protocol.TextDocumentIdentifier{
+                       URI: protocol.URIFromSpanURI(file),
+               },
+       }
+       resp, err := c.Server.SemanticTokensFull(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})
+       <-c.Client.diagnosticsDone
+       return err
+}
+
+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
+}