Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/tools/cmd/gopls: client server calls block indefinitely following CL179157 #32322

Closed
myitcv opened this issue May 30, 2019 · 3 comments
Closed
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@myitcv
Copy link
Member

myitcv commented May 30, 2019

What version of Go are you using (go version)?

$ go version
go version devel +385b2e0cac Fri May 24 21:34:53 2019 +0000 linux/amd64
$ go list -m golang.org/x/tools
golang.org/x/tools v0.0.0-20190528151238-d238219cc233

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN="/home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/.bin"
GOCACHE="/home/myitcv/.cache/go-build"
GOENV="/home/myitcv/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/myitcv/gostuff"
GOPROXY="https://proxy.golang.org/"
GOROOT="/home/myitcv/gos"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/myitcv/gos/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/myitcv/gostuff/src/github.com/myitcv/govim/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build080689529=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Following https://go-review.googlesource.com/c/tools/+/179157, I'm seeing any call to gopls post-Initialized block indefinitely, e.g. consider the following log where I attempt a completion:

gopls log
gopls server start =======================
gopls.Initialize() call; params:
&protocol.InitializeParams{
    ProcessID:    0,
    RootPath:     "",
    RootURI:      "file:///home/myitcv/gostuff/src/github.com/myitcv/govim",
    Capabilities: protocol.ClientCapabilities{
        Workspace: struct { ApplyEdit bool "json:\"applyEdit,omitempty\""; WorkspaceEdit struct { DocumentChanges bool "json:\"documentChanges,omitempty\""; ResourceOperations []protocol.ResourceOperationKind "json:\"resourceOperations,omitempty\""; FailureHandling protocol.FailureHandlingKind "json:\"failureHandling,omitempty\"" } "json:\"workspaceEdit,omitempty\""; DidChangeConfiguration struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"didChangeConfiguration,omitempty\""; DidChangeWatchedFiles struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"didChangeWatchedFiles,omitempty\""; Symbol struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; SymbolKind struct { ValueSet []protocol.SymbolKind "json:\"valueSet,omitempty\"" } "json:\"symbolKind,omitempty\"" } "json:\"symbol,omitempty\""; ExecuteCommand struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"executeCommand,omitempty\""; WorkspaceFolders bool "json:\"workspaceFolders,omitempty\""; Configuration bool "json:\"configuration,omitempty\"" }{
            ApplyEdit:              false,
            WorkspaceEdit:          struct { DocumentChanges bool "json:\"documentChanges,omitempty\""; ResourceOperations []protocol.ResourceOperationKind "json:\"resourceOperations,omitempty\""; FailureHandling protocol.FailureHandlingKind "json:\"failureHandling,omitempty\"" }{},
            DidChangeConfiguration: struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{DynamicRegistration:true},
            DidChangeWatchedFiles:  struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            Symbol:                 struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; SymbolKind struct { ValueSet []protocol.SymbolKind "json:\"valueSet,omitempty\"" } "json:\"symbolKind,omitempty\"" }{},
            ExecuteCommand:         struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            WorkspaceFolders:       false,
            Configuration:          true,
        },
        TextDocument: struct { Synchronization struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; WillSave bool "json:\"willSave,omitempty\""; WillSaveWaitUntil bool "json:\"willSaveWaitUntil,omitempty\""; DidSave bool "json:\"didSave,omitempty\"" } "json:\"synchronization,omitempty\""; Completion struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; CompletionItem struct { SnippetSupport bool "json:\"snippetSupport,omitempty\""; CommitCharactersSupport bool "json:\"commitCharactersSupport,omitempty\""; DocumentationFormat []protocol.MarkupKind "json:\"documentationFormat,omitempty\""; DeprecatedSupport bool "json:\"deprecatedSupport,omitempty\""; PreselectSupport bool "json:\"preselectSupport,omitempty\"" } "json:\"completionItem,omitempty\""; CompletionItemKind struct { ValueSet []protocol.CompletionItemKind "json:\"valueSet,omitempty\"" } "json:\"completionItemKind,omitempty\""; ContextSupport bool "json:\"contextSupport,omitempty\"" } "json:\"completion,omitempty\""; Hover struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; ContentFormat []protocol.MarkupKind "json:\"contentFormat,omitempty\"" } "json:\"hover,omitempty\""; SignatureHelp struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; SignatureInformation struct { DocumentationFormat []protocol.MarkupKind "json:\"documentationFormat,omitempty\""; ParameterInformation struct { LabelOffsetSupport bool "json:\"labelOffsetSupport,omitempty\"" } "json:\"parameterInformation,omitempty\"" } "json:\"signatureInformation,omitempty\"" } "json:\"signatureHelp,omitempty\""; References struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"references,omitempty\""; DocumentHighlight struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"documentHighlight,omitempty\""; DocumentSymbol struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; SymbolKind struct { ValueSet []protocol.SymbolKind "json:\"valueSet,omitempty\"" } "json:\"symbolKind,omitempty\""; HierarchicalDocumentSymbolSupport bool "json:\"hierarchicalDocumentSymbolSupport,omitempty\"" } "json:\"documentSymbol,omitempty\""; Formatting struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"formatting,omitempty\""; RangeFormatting struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"rangeFormatting,omitempty\""; OnTypeFormatting struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"onTypeFormatting,omitempty\""; Definition struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" } "json:\"definition,omitempty\""; CodeAction struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; CodeActionLiteralSupport struct { CodeActionKind struct { ValueSet []protocol.CodeActionKind "json:\"valueSet\"" } "json:\"codeActionKind\"" } "json:\"codeActionLiteralSupport,omitempty\"" } "json:\"codeAction,omitempty\""; CodeLens struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"codeLens,omitempty\""; DocumentLink struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"documentLink,omitempty\""; Rename struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; PrepareSupport bool "json:\"prepareSupport,omitempty\"" } "json:\"rename,omitempty\""; PublishDiagnostics struct { RelatedInformation bool "json:\"relatedInformation,omitempty\""; TagSupport bool "json:\"tagSupport,omitempty\"" } "json:\"publishDiagnostics,omitempty\""; Implementation struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" } "json:\"implementation,omitempty\""; TypeDefinition struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" } "json:\"typeDefinition,omitempty\""; ColorProvider struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" } "json:\"colorProvider,omitempty\""; FoldingRange struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; RangeLimit float64 "json:\"rangeLimit,omitempty\""; LineFoldingOnly bool "json:\"lineFoldingOnly,omitempty\"" } "json:\"foldingRange,omitempty\""; Declaration struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" } "json:\"declaration,omitempty\"" }{
            Synchronization: struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; WillSave bool "json:\"willSave,omitempty\""; WillSaveWaitUntil bool "json:\"willSaveWaitUntil,omitempty\""; DidSave bool "json:\"didSave,omitempty\"" }{},
            Completion:      struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; CompletionItem struct { SnippetSupport bool "json:\"snippetSupport,omitempty\""; CommitCharactersSupport bool "json:\"commitCharactersSupport,omitempty\""; DocumentationFormat []protocol.MarkupKind "json:\"documentationFormat,omitempty\""; DeprecatedSupport bool "json:\"deprecatedSupport,omitempty\""; PreselectSupport bool "json:\"preselectSupport,omitempty\"" } "json:\"completionItem,omitempty\""; CompletionItemKind struct { ValueSet []protocol.CompletionItemKind "json:\"valueSet,omitempty\"" } "json:\"completionItemKind,omitempty\""; ContextSupport bool "json:\"contextSupport,omitempty\"" }{},
            Hover:           struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; ContentFormat []protocol.MarkupKind "json:\"contentFormat,omitempty\"" }{
                DynamicRegistration: false,
                ContentFormat:       {"plaintext"},
            },
            SignatureHelp:      struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; SignatureInformation struct { DocumentationFormat []protocol.MarkupKind "json:\"documentationFormat,omitempty\""; ParameterInformation struct { LabelOffsetSupport bool "json:\"labelOffsetSupport,omitempty\"" } "json:\"parameterInformation,omitempty\"" } "json:\"signatureInformation,omitempty\"" }{},
            References:         struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            DocumentHighlight:  struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            DocumentSymbol:     struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; SymbolKind struct { ValueSet []protocol.SymbolKind "json:\"valueSet,omitempty\"" } "json:\"symbolKind,omitempty\""; HierarchicalDocumentSymbolSupport bool "json:\"hierarchicalDocumentSymbolSupport,omitempty\"" }{},
            Formatting:         struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            RangeFormatting:    struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            OnTypeFormatting:   struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            Definition:         struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" }{},
            CodeAction:         struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; CodeActionLiteralSupport struct { CodeActionKind struct { ValueSet []protocol.CodeActionKind "json:\"valueSet\"" } "json:\"codeActionKind\"" } "json:\"codeActionLiteralSupport,omitempty\"" }{},
            CodeLens:           struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            DocumentLink:       struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            Rename:             struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; PrepareSupport bool "json:\"prepareSupport,omitempty\"" }{},
            PublishDiagnostics: struct { RelatedInformation bool "json:\"relatedInformation,omitempty\""; TagSupport bool "json:\"tagSupport,omitempty\"" }{},
            Implementation:     struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" }{},
            TypeDefinition:     struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" }{},
            ColorProvider:      struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\"" }{},
            FoldingRange:       struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; RangeLimit float64 "json:\"rangeLimit,omitempty\""; LineFoldingOnly bool "json:\"lineFoldingOnly,omitempty\"" }{},
            Declaration:        struct { DynamicRegistration bool "json:\"dynamicRegistration,omitempty\""; LinkSupport bool "json:\"linkSupport,omitempty\"" }{},
        },
        Window:       protocol.WindowClientCapabilities{},
        Experimental: nil,
    },
    InitializationOptions: map[string]interface {}{
        "incrementalSync": bool(true),
        "noDocsOnHover":   bool(true),
    },
    Trace:            "",
    WorkspaceFolders: nil,
}
gopls server end =======================
gopls server start =======================
gopls.Initialize() return; err: ; res:
&protocol.InitializeResult{
    Capabilities: protocol.ServerCapabilities{
        TextDocumentSync: map[string]interface {}{
            "openClose": bool(true),
            "change":    float64(2),
        },
        HoverProvider:      true,
        CompletionProvider: &protocol.CompletionOptions{
            TriggerCharacters:   {"."},
            AllCommitCharacters: nil,
            ResolveProvider:     false,
        },
        SignatureHelpProvider: &protocol.SignatureHelpOptions{
            TriggerCharacters: {"(", ","},
        },
        DefinitionProvider:               true,
        ReferencesProvider:               false,
        DocumentHighlightProvider:        true,
        DocumentSymbolProvider:           true,
        WorkspaceSymbolProvider:          false,
        CodeActionProvider:               true,
        CodeLensProvider:                 (*protocol.CodeLensOptions)(nil),
        DocumentFormattingProvider:       true,
        DocumentRangeFormattingProvider:  false,
        DocumentOnTypeFormattingProvider: (*struct { FirstTriggerCharacter string "json:\"firstTriggerCharacter\""; MoreTriggerCharacter []string "json:\"moreTriggerCharacter,omitempty\"" })(nil),
        RenameProvider:                   (*protocol.RenameOptions)(nil),
        DocumentLinkProvider:             &protocol.DocumentLinkOptions{},
        ExecuteCommandProvider:           (*protocol.ExecuteCommandOptions)(nil),
        Experimental:                     nil,
        ImplementationProvider:           false,
        TypeDefinitionProvider:           true,
        Workspace:                        &struct { WorkspaceFolders *struct { Supported bool "json:\"supported,omitempty\""; ChangeNotifications string "json:\"changeNotifications,omitempty\"" } "json:\"workspaceFolders,omitempty\"" }{
            WorkspaceFolders: &struct { Supported bool "json:\"supported,omitempty\""; ChangeNotifications string "json:\"changeNotifications,omitempty\"" }{Supported:true, ChangeNotifications:"workspace/didChangeWorkspaceFolders"},
        },
        ColorProvider:        false,
        FoldingRangeProvider: false,
        DeclarationProvider:  false,
    },
    Custom: {},
}
gopls server end =======================
gopls server start =======================
gopls.Initialized() call; params:
&protocol.InitializedParams{}
gopls server end =======================
gopls server start =======================
gopls.Initialized() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidOpen() call; params:
&protocol.DidOpenTextDocumentParams{
    TextDocument: protocol.TextDocumentItem{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go", LanguageID:"", Version:0, Text:"// Command govim is a Vim8 channel-based plugin, written in Go, to support the writing of Go code in Vim8\npackage main\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/myitcv/govim\"\n\t\"github.com/myitcv/govim/cmd/govim/config\"\n\t\"github.com/myitcv/govim/cmd/govim/internal/jsonrpc2\"\n\t\"github.com/myitcv/govim/cmd/govim/internal/lsp/protocol\"\n\t\"github.com/myitcv/govim/cmd/govim/internal/span\"\n\t\"github.com/myitcv/govim/cmd/govim/types\"\n\t\"github.com/myitcv/govim/internal/plugin\"\n\t\"github.com/myitcv/govim/testsetup\"\n\t\"gopkg.in/tomb.v2\"\n\n\t\"github.com/rogpeppe/go-internal/semver\"\n)\n\nvar (\n\tfTail = flag.Bool(\"tail\", false, \"whether to also log output to stdout\")\n\n\t// gopls define InitializationOptions; they will make these well defined\n\t// constants at some point\n\tgoplsInitOptIncrementalSync = \"incrementalSync\"\n)\n\nfunc main() {\n\tos.Exit(main1())\n}\n\nfunc main1() int {\n\tswitch err := mainerr(); err {\n\tcase nil:\n\t\treturn 0\n\tcase flag.ErrHelp:\n\t\treturn 2\n\tdefault:\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\treturn 1\n\t}\n}\n\nfunc mainerr() error {\n\tflag.Parse()\n\n\targs := flag.Args()\n\tif len(flag.Args()) == 0 {\n\t\treturn fmt.Errorf(\"missing single argument path to gopls\")\n\t}\n\tgoplspath := args[0]\n\n\tif sock := os.Getenv(testsetup.EnvTestSocket); sock != \"\" {\n\t\tln, err := net.Listen(\"tcp\", sock)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to listen on %v: %v\", sock, err)\n\t\t}\n\t\tfor {\n\t\t\tconn, err := ln.Accept()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to accept connection on %v: %v\", sock, err)\n\t\t\t}\n\n\t\t\tgo func() {\n\t\t\t\tif err := launch(goplspath, conn, conn); err != nil {\n\t\t\t\t\tfmt.Fprintln(os.Stderr, err)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t} else {\n\t\treturn launch(goplspath, os.Stdin, os.Stdout)\n\t}\n}\n\nfunc launch(goplspath string, in io.ReadCloser, out io.WriteCloser) error {\n\tdefer out.Close()\n\n\td := newplugin(goplspath)\n\n\tnowStr := time.Now().Format(\"20060102_1504_05.000000000\")\n\ttf, err := ioutil.TempFile(\"\", \"govim_\"+nowStr+\"_*\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create log file\")\n\t}\n\tdefer tf.Close()\n\n\tvar log io.Writer = tf\n\tif *fTail {\n\t\tlog = io.MultiWriter(tf, os.Stdout)\n\t}\n\n\tif os.Getenv(testsetup.EnvTestSocket) != \"\" {\n\t\tfmt.Fprintf(os.Stderr, \"New connection will log to %v\\n\", tf.Name())\n\t}\n\n\tg, err := govim.NewGovim(d, in, out, log)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create govim instance: %v\", err)\n\t}\n\n\td.tomb.Kill(g.Run())\n\treturn d.tomb.Wait()\n}\n\ntype govimplugin struct {\n\tplugin.Driver\n\t*vimstate\n\n\tgoplspath   string\n\tgopls       *os.Process\n\tgoplsConn   *jsonrpc2.Conn\n\tgoplsCancel context.CancelFunc\n\tserver      protocol.Server\n\n\tisGui bool\n\n\ttomb tomb.Tomb\n\n\tmodWatcher *modWatcher\n}\n\nfunc newplugin(goplspath string) *govimplugin {\n\td := plugin.NewDriver(\"GOVIM\")\n\tres := &govimplugin{\n\t\tgoplspath: goplspath,\n\t\tDriver:    d,\n\t\tvimstate: &vimstate{\n\t\t\tDriver:       d,\n\t\t\tbuffers:      make(map[int]*types.Buffer),\n\t\t\twatchedFiles: make(map[string]*types.WatchedFile),\n\t\t\tdiagnostics:  make(map[span.URI][]protocol.Diagnostic),\n\t\t},\n\t}\n\tres.vimstate.govimplugin = res\n\treturn res\n}\n\nfunc (g *govimplugin) Init(gg govim.Govim, errCh chan error) error {\n\tg.Driver.Govim = gg\n\tg.vimstate.Driver.Govim = gg.Scheduled()\n\tg.ChannelEx(`augroup govim`)\n\tg.ChannelEx(`augroup END`)\n\tg.DefineFunction(string(config.FunctionHello), []string{}, g.hello)\n\tg.DefineCommand(string(config.CommandHello), g.helloComm)\n\tg.DefineFunction(string(config.FunctionBalloonExpr), []string{}, g.balloonExpr)\n\tg.DefineAutoCommand(\"\", govim.Events{govim.EventBufRead, govim.EventBufNewFile}, govim.Patterns{\"*.go\"}, false, g.bufReadPost, exprAutocmdCurrBufInfo)\n\tif !g.doIncrementalSync() {\n\t\tg.DefineAutoCommand(\"\", govim.Events{govim.EventTextChanged, govim.EventTextChangedI}, govim.Patterns{\"*.go\"}, false, g.bufTextChanged, exprAutocmdCurrBufInfo)\n\t}\n\tg.DefineAutoCommand(\"\", govim.Events{govim.EventBufWritePre}, govim.Patterns{\"*.go\"}, false, g.formatCurrentBuffer, \"eval(expand(''))\")\n\tg.DefineFunction(string(config.FunctionComplete), []string{\"findarg\", \"base\"}, g.complete)\n\tg.DefineCommand(string(config.CommandGoToDef), g.gotoDef, govim.NArgsZeroOrOne)\n\tg.DefineCommand(string(config.CommandGoToPrevDef), g.gotoPrevDef, govim.NArgsZeroOrOne, govim.CountN(1))\n\tg.DefineFunction(string(config.FunctionHover), []string{}, g.hover)\n\tg.DefineAutoCommand(\"\", govim.Events{govim.EventCursorHold, govim.EventCursorHoldI}, govim.Patterns{\"*.go\"}, false, g.autoUpdateQuickfix)\n\tg.DefineAutoCommand(\"\", govim.Events{govim.EventBufDelete}, govim.Patterns{\"*.go\"}, false, g.deleteCurrentBuffer, \"eval(expand(''))\")\n\tg.DefineCommand(string(config.CommandGoFmt), g.gofmtCurrentBufferRange, govim.RangeFile)\n\tg.DefineCommand(string(config.CommandGoImports), g.goimportsCurrentBufferRange, govim.RangeFile)\n\tg.DefineCommand(string(config.CommandQuickfixDiagnostics), g.quickfixDiagnostics)\n\tg.DefineFunction(string(config.FunctionBufChanged), []string{\"bufnr\", \"start\", \"end\", \"added\", \"changes\"}, g.bufChanged)\n\n\tg.isGui = g.ParseInt(g.ChannelExpr(`has(\"gui_running\")`)) == 1\n\n\tgopls := exec.Command(g.goplspath)\n\tstderr, err := gopls.StderrPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create stderr pipe for gopls: %v\", err)\n\t}\n\tg.tomb.Go(func() error {\n\t\tscanner := bufio.NewScanner(stderr)\n\t\tfor scanner.Scan() {\n\t\t\tg.Logf(\"gopls stderr: %v\", scanner.Text())\n\t\t}\n\t\tif err := scanner.Err(); err != nil {\n\t\t\treturn fmt.Errorf(\"reading standard input: %v\", err)\n\t\t}\n\t\treturn nil\n\t})\n\tstdout, err := gopls.StdoutPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create stdout pipe for gopls: %v\", err)\n\t}\n\tstdin, err := gopls.StdinPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create stdin pipe for gopls: %v\", err)\n\t}\n\tif err := gopls.Start(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start gopls: %v\", err)\n\t}\n\tg.tomb.Go(func() (err error) {\n\t\tif err = gopls.Wait(); err != nil {\n\t\t\terr = fmt.Errorf(\"got error running gopls: %v\", err)\n\t\t\terrCh <- err\n\t\t}\n\t\treturn\n\t})\n\n\tstream := jsonrpc2.NewHeaderStream(stdout, stdin)\n\tctxt, cancel := context.WithCancel(context.Background())\n\tconn, server, _ := protocol.NewClient(stream, g)\n\t// override the handler with something that can handle the fact\n\t// that we might get a govim.ErrShuttingDown\n\tcurrHandler := conn.Handler\n\tconn.Handler = func(ctxt context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) {\n\t\tdefer func() {\n\t\t\tif r := recover(); r != nil && r != govim.ErrShuttingDown {\n\t\t\t\tpanic(r)\n\t\t\t}\n\t\t}()\n\t\tcurrHandler(ctxt, conn, req)\n\t}\n\tg.tomb.Go(func() error {\n\t\treturn conn.Run(ctxt)\n\t})\n\n\tg.gopls = gopls.Process\n\tg.goplsConn = conn\n\tg.goplsCancel = cancel\n\tg.server = loggingGoplsServer{\n\t\tu: server,\n\t\tg: g,\n\t}\n\n\twd := g.ParseString(g.ChannelCall(\"getcwd\", -1))\n\tinitParams := &protocol.InitializeParams{}\n\tinitParams.RootURI = string(span.FileURI(wd))\n\tinitParams.Capabilities.TextDocument.Hover.ContentFormat = []protocol.MarkupKind{protocol.PlainText}\n\tinitParams.Capabilities.Workspace.Configuration = true\n\tinitParams.Capabilities.Workspace.DidChangeConfiguration.DynamicRegistration = true\n\tinitOpts := make(map[string]interface{})\n\tif g.doIncrementalSync() {\n\t\tinitOpts[goplsInitOptIncrementalSync] = true\n\t}\n\tinitOpts[\"noDocsOnHover\"] = true\n\tinitParams.InitializationOptions = initOpts\n\n\tif _, err := g.server.Initialize(context.Background(), initParams); err != nil {\n\t\treturn fmt.Errorf(\"failed to initialise gopls: %v\", err)\n\t}\n\n\tif err := g.server.Initialized(context.Background(), &protocol.InitializedParams{}); err != nil {\n\t\treturn fmt.Errorf(\"failed to call gopls.Initialized: %v\", err)\n\t}\n\n\t// Temporary fix for the fact that gopls does not yet support watching (via\n\t// the client) changed files: https://github.com/golang/go/issues/31553\n\tgomodpath, err := goModPath(wd)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to derive go.mod path: %v\", err)\n\t}\n\n\tif gomodpath != \"\" {\n\t\t// i.e. we are in a module\n\t\tmw, err := newModWatcher(g, gomodpath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create modWatcher for %v: %v\", gomodpath, err)\n\t\t}\n\t\tg.modWatcher = mw\n\t}\n\n\treturn nil\n}\n\nfunc goModPath(wd string) (string, error) {\n\tcmd := exec.Command(\"go\", \"env\", \"GOMOD\")\n\tcmd.Dir = wd\n\n\tout, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to execute [%v] in %v: %v\\n%s\", strings.Join(cmd.Args, \" \"), wd, err, out)\n\t}\n\n\treturn strings.TrimSpace(string(out)), nil\n}\n\nfunc (g *govimplugin) Shutdown() error {\n\tif err := g.server.Shutdown(context.Background()); err != nil {\n\t\treturn err\n\t}\n\tif g.modWatcher != nil {\n\t\tif err := g.modWatcher.close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (g *govimplugin) doIncrementalSync() bool {\n\tif g.Flavor() != govim.FlavorVim && g.Flavor() != govim.FlavorGvim {\n\t\treturn false\n\t}\n\tif semver.Compare(g.Version(), testsetup.MinVimIncrementalSync) < 0 {\n\t\treturn false\n\t}\n\tif os.Getenv(testsetup.EnvDisableIncrementalSync) == \"true\" {\n\t\treturn false\n\t}\n\treturn true\n}\n"},
}
gopls server end =======================
gopls server start =======================
gopls.DidOpen() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidChange() call; params:
&protocol.DidChangeTextDocumentParams{
    TextDocument: protocol.VersionedTextDocumentIdentifier{
        Version:                1,
        TextDocumentIdentifier: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
    },
    ContentChanges: {
        {
            Range: &protocol.Range{
                Start: protocol.Position{Line:39, Character:0},
                End:   protocol.Position{Line:39, Character:0},
            },
            RangeLength: 0,
            Text:        "\t\n",
        },
    },
}
gopls server end =======================
gopls server start =======================
gopls.DidChange() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidChange() call; params:
&protocol.DidChangeTextDocumentParams{
    TextDocument: protocol.VersionedTextDocumentIdentifier{
        Version:                2,
        TextDocumentIdentifier: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
    },
    ContentChanges: {
        {
            Range: &protocol.Range{
                Start: protocol.Position{Line:39, Character:0},
                End:   protocol.Position{Line:40, Character:0},
            },
            RangeLength: 0,
            Text:        "\t.\n",
        },
    },
}
gopls server end =======================
gopls server start =======================
gopls.DidChange() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidChange() call; params:
&protocol.DidChangeTextDocumentParams{
    TextDocument: protocol.VersionedTextDocumentIdentifier{
        Version:                3,
        TextDocumentIdentifier: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
    },
    ContentChanges: {
        {
            Range: &protocol.Range{
                Start: protocol.Position{Line:39, Character:0},
                End:   protocol.Position{Line:40, Character:0},
            },
            RangeLength: 0,
            Text:        "\t\n",
        },
    },
}
gopls server end =======================
gopls server start =======================
gopls.DidChange() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidChange() call; params:
&protocol.DidChangeTextDocumentParams{
    TextDocument: protocol.VersionedTextDocumentIdentifier{
        Version:                4,
        TextDocumentIdentifier: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
    },
    ContentChanges: {
        {
            Range: &protocol.Range{
                Start: protocol.Position{Line:39, Character:0},
                End:   protocol.Position{Line:40, Character:0},
            },
            RangeLength: 0,
            Text:        "\to\n",
        },
    },
}
gopls server end =======================
gopls server start =======================
gopls.DidChange() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidChange() call; params:
&protocol.DidChangeTextDocumentParams{
    TextDocument: protocol.VersionedTextDocumentIdentifier{
        Version:                5,
        TextDocumentIdentifier: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
    },
    ContentChanges: {
        {
            Range: &protocol.Range{
                Start: protocol.Position{Line:39, Character:0},
                End:   protocol.Position{Line:40, Character:0},
            },
            RangeLength: 0,
            Text:        "\tos\n",
        },
    },
}
gopls server end =======================
gopls server start =======================
gopls.DidChange() return; err: 
gopls server end =======================
gopls server start =======================
gopls.DidChange() call; params:
&protocol.DidChangeTextDocumentParams{
    TextDocument: protocol.VersionedTextDocumentIdentifier{
        Version:                6,
        TextDocumentIdentifier: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
    },
    ContentChanges: {
        {
            Range: &protocol.Range{
                Start: protocol.Position{Line:39, Character:0},
                End:   protocol.Position{Line:40, Character:0},
            },
            RangeLength: 0,
            Text:        "\tos.\n",
        },
    },
}
gopls server end =======================
gopls server start =======================
gopls.DidChange() return; err: 
gopls server end =======================
gopls server start =======================
gopls.Completion() call; params:
&protocol.CompletionParams{
    Context:                    (*protocol.CompletionContext)(nil),
    TextDocumentPositionParams: protocol.TextDocumentPositionParams{
        TextDocument: protocol.TextDocumentIdentifier{URI:"file:///home/myitcv/gostuff/src/github.com/myitcv/govim/cmd/govim/main.go"},
        Position:     protocol.Position{Line:39, Character:4},
    },
}
gopls server end =======================

Perhaps, however, I need to make a corresponding change in my code following the change introduced in https://go-review.googlesource.com/c/tools/+/179157?

What did you expect to see?

Normal gopls behaviour

What did you see instead?

An indefinite hang in a request.


cc @stamblerre @ianthehat

@myitcv myitcv added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. gopls Issues related to the Go language server, gopls. labels May 30, 2019
@gopherbot gopherbot added this to the Unreleased milestone May 30, 2019
@stamblerre
Copy link
Contributor

I believe you will have to make changes on your end. The registerCapability requests are explicitly not notifications. For example, https://microsoft.github.io/language-server-protocol/specification#client_registerCapability refers to it as a request, whereas something like publishDiagnostics is explicitly called a notification (https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics).

@myitcv
Copy link
Member Author

myitcv commented May 30, 2019

@stamblerre - thanks.

I'm using the code that relies on:

https://github.com/golang/tools/blob/12d73424210d5399ae74d7e94f5c464d70d02406/internal/lsp/protocol/tsclient.go#L91-L108

Looks like there is a change required here, because otherwise no response will be sent from the client to the server... and the server will block indefinitely waiting for one (which is what I think I'm seeing)

@myitcv myitcv reopened this May 30, 2019
@gopherbot
Copy link

Change https://golang.org/cl/179359 mentions this issue: internal/lsp: send void client response to client/registerCapapbility

@golang golang locked and limited conversation to collaborators May 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants