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/gopls: gopls reports Internal error when run from Emacs' eglot #39896

ts4z opened this issue Jun 28, 2020 · 8 comments

x/tools/gopls: gopls reports Internal error when run from Emacs' eglot #39896

ts4z opened this issue Jun 28, 2020 · 8 comments


Copy link

@ts4z ts4z commented Jun 28, 2020

I'm new to eglot (an Emacs interface to language servers), gopls, and Go modules, so I'm not sure how to debug this.

What did you do?

This happens whenever I start eglot from within Emacs on my machine at home.

This happens all the time, but here's a simplfiied version:

  • emacs -q
  • eval (package-initialize)
  • eval (require 'go-mode)
  • find-file ~/go/src/ (or any other Go file I've tried)
  • M-x eglot

If you aren't an Emacs user, this starts Emacs bypassing my config file, inits the package manager (so eglot, an add-on is available), does the same with go-mode. Load any Go file and turn eglot on, and it fails.

What did you expect to see?

Eglot start up and be able to call various language server features.

What did you see instead?

Emacs shows an error, and reports this in its internal log:

[eglot] Connected! Server gopls' now managing go-mode' buffers in project `tools'.
[eglot] Server reports (type=1): Error loading workspace folders (expected 1, got 0)
failed to load view for file:///home/tjs/go/src/ Internal error

If I go a step further, and enable the -rpc.trace option, I can get the following in gopls' log file. In this case, I was trying to run eglot on .../godoc/godoc.go, but I got this to happen on everything I tried to attach to.

[Trace - 21:25:57.758 PM] Sending request 'initialize - (1)'.
Params: {"processId":87694,"rootPath":"/home/tjs/go/src/","rootUri":"file:///home/tjs/go/src/","initializationOptions":null,"capabilities":{"workspace":{"applyEdit":true,"executeCommand":{"dynamicRegistration":false},"workspaceEdit":{"documentChanges":false},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":false},"configuration":true},"textDocument":{"synchronization":{"dynamicRegistration":false,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":false,"completionItem":{"snippetSupport":false},"contextSupport":true},"hover":{"dynamicRegistration":false,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":false,"signatureInformation":{"parameterInformation":{"labelOffsetSupport":true}}},"references":{"dynamicRegistration":false},"definition":{"dynamicRegistration":false},"declaration":{"dynamicRegistration":false},"implementation":{"dynamicRegistration":false},"typeDefinition":{"dynamicRegistration":false},"documentSymbol":{"dynamicRegistration":false,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}},"documentHighlight":{"dynamicRegistration":false},"codeAction":{"dynamicRegistration":false,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"formatting":{"dynamicRegistration":false},"rangeFormatting":{"dynamicRegistration":false},"rename":{"dynamicRegistration":false},"publishDiagnostics":{"relatedInformation":false}},"experimental":null}}

[Trace - 21:25:57.783 PM] Received response 'initialize - (1)' in 25ms.
Result: {"capabilities":{"textDocumentSync":{"openClose":true,"change":2,"save":{}},"completionProvider":{"triggerCharacters":["."]},"hoverProvider":true,"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":true,"referencesProvider":true,"documentHighlightProvider":true,"documentSymbolProvider":true,"codeActionProvider":{"codeActionKinds":["quickfix","refactor.rewrite","source.fixAll","source.organizeImports"]},"codeLensProvider":{},"documentLinkProvider":{},"workspaceSymbolProvider":true,"documentFormattingProvider":true,"documentOnTypeFormattingProvider":{"firstTriggerCharacter":""},"renameProvider":true,"foldingRangeProvider":true,"executeCommandProvider":{"commands":["test","tidy","upgrade_dependency","generate","regenerate_cgo"]},"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":"workspace/didChangeWorkspaceFolders"}}},"serverInfo":{"name":"gopls","version":"Build info\n----------\ master\n\n h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\n h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=\n h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=\n h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=\n =\u003e ../\n h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=\n h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=\n h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=\n\nGo info\n-------\ngo version go1.14.4 linux/amd64\n\n"}}

[Trace - 21:25:57.784 PM] Sending notification 'initialized'.
Params: {}

[Trace - 21:25:57.810 PM] Received request 'workspace/configuration - (1)'.
Params: {"items":[{"scopeUri":"file:///home/tjs/go/src/","section":"gopls"},{"scopeUri":"file:///home/tjs/go/src/","section":"gopls-tools"}]}

[Trace - 21:25:57.811 PM] Received notification 'window/logMessage'.
Params: {"type":3,"message":"2020/06/27 21:25:57 Build info\n----------\ master\n\n h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\n h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=\n h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=\n h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=\n =\u003e ../\n h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=\n h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=\n h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=\n\nGo info\n-------\ngo version go1.14.4 linux/amd64\n\n\n"}

[Trace - 21:25:57.823 PM] Sending notification 'textDocument/didOpen'.
Params: {"textDocument":{"uri":"file:///home/tjs/go/src/","version":0,"languageId":"go","text":"// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// Package godoc is a work-in-progress (2013-07-17) package to\n// begin splitting up the godoc binary into multiple pieces.\n//\n// This package comment will evolve over time as this package splits\n// into smaller pieces.\npackage godoc // import \"\"\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/doc\"\n\t\"go/format\"\n\t\"go/printer\"\n\t\"go/token\"\n\thtmltemplate \"html/template\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\tpathpkg \"path\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\n// Fake relative package path for built-ins. Documentation for all globals\n// (not just exported ones) will be shown for packages in this directory,\n// and there will be no association of consts, vars, and factory functions\n// with types (see issue 6645).\nconst builtinPkgPath = \"builtin\"\n\n// FuncMap defines template functions used in godoc templates.\n//\n// Convention: template function names ending in \"_html\" or \"_url\" produce\n//             HTML- or URL-escaped strings; all other function results may\n//             require explicit escaping in the template.\nfunc (p *Presentation) FuncMap() template.FuncMap {\n\tp.initFuncMapOnce.Do(p.initFuncMap)\n\treturn p.funcMap\n}\n\nfunc (p *Presentation) TemplateFuncs() template.FuncMap {\n\tp.initFuncMapOnce.Do(p.initFuncMap)\n\treturn p.templateFuncs\n}\n\nfunc (p *Presentation) initFuncMap() {\n\tif p.Corpus == nil {\n\t\tpanic(\"nil Presentation.Corpus\")\n\t}\n\tp.templateFuncs = template.FuncMap{\n\t\t\"code\": p.code,\n\t}\n\tp.funcMap = template.FuncMap{\n\t\t// various helpers\n\t\t\"filename\": filenameFunc,\n\t\t\"repeat\":   strings.Repeat,\n\t\t\"since\":    p.Corpus.pkgAPIInfo.sinceVersionFunc,\n\n\t\t// access to FileInfos (directory listings)\n\t\t\"fileInfoName\": fileInfoNameFunc,\n\t\t\"fileInfoTime\": fileInfoTimeFunc,\n\n\t\t// access to search result information\n\t\t\"infoKind_html\":    infoKind_htmlFunc,\n\t\t\"infoLine\":         p.infoLineFunc,\n\t\t\"infoSnippet_html\": p.infoSnippet_htmlFunc,\n\n\t\t// formatting of AST nodes\n\t\t\"node\":         p.nodeFunc,\n\t\t\"node_html\":    p.node_htmlFunc,\n\t\t\"comment_html\": comment_htmlFunc,\n\t\t\"sanitize\":     sanitizeFunc,\n\n\t\t// support for URL attributes\n\t\t\"pkgLink\":       pkgLinkFunc,\n\t\t\"srcLink\":       srcLinkFunc,\n\t\t\"posLink_url\":   newPosLink_urlFunc(srcPosLinkFunc),\n\t\t\"docLink\":       docLinkFunc,\n\t\t\"queryLink\":     queryLinkFunc,\n\t\t\"srcBreadcrumb\": srcBreadcrumbFunc,\n\t\t\"srcToPkgLink\":  srcToPkgLinkFunc,\n\n\t\t// formatting of Examples\n\t\t\"example_html\":   p.example_htmlFunc,\n\t\t\"example_name\":   p.example_nameFunc,\n\t\t\"example_suffix\": p.example_suffixFunc,\n\n\t\t// formatting of analysis information\n\t\t\"callgraph_html\":  p.callgraph_htmlFunc,\n\t\t\"implements_html\": p.implements_htmlFunc,\n\t\t\"methodset_html\":  p.methodset_htmlFunc,\n\n\t\t// formatting of Notes\n\t\t\"noteTitle\": noteTitle,\n\n\t\t// Number operation\n\t\t\"multiply\": multiply,\n\n\t\t// formatting of PageInfoMode query string\n\t\t\"modeQueryString\": modeQueryString,\n\n\t\t// check whether to display third party section or not\n\t\t\"hasThirdParty\": hasThirdParty,\n\n\t\t// get the no. of columns to split the toc in search page\n\t\t\"tocColCount\": tocColCount,\n\t}\n\tif p.URLForSrc != nil {\n\t\tp.funcMap[\"srcLink\"] = p.URLForSrc\n\t}\n\tif p.URLForSrcPos != nil {\n\t\tp.funcMap[\"posLink_url\"] = newPosLink_urlFunc(p.URLForSrcPos)\n\t}\n\tif p.URLForSrcQuery != nil {\n\t\tp.funcMap[\"queryLink\"] = p.URLForSrcQuery\n\t}\n}\n\nfunc multiply(a, b int) int { return a * b }\n\nfunc filenameFunc(path string) string {\n\t_, localname := pathpkg.Split(path)\n\treturn localname\n}\n\nfunc fileInfoNameFunc(fi os.FileInfo) string {\n\tname := fi.Name()\n\tif fi.IsDir() {\n\t\tname += \"/\"\n\t}\n\treturn name\n}\n\nfunc fileInfoTimeFunc(fi os.FileInfo) string {\n\tif t := fi.ModTime(); t.Unix() != 0 {\n\t\treturn t.Local().String()\n\t}\n\treturn \"\" // don't return epoch if time is obviously not set\n}\n\n// The strings in infoKinds must be properly html-escaped.\nvar infoKinds = [nKinds]string{\n\tPackageClause: \"package&nbsp;clause\",\n\tImportDecl:    \"import&nbsp;decl\",\n\tConstDecl:     \"const&nbsp;decl\",\n\tTypeDecl:      \"type&nbsp;decl\",\n\tVarDecl:       \"var&nbsp;decl\",\n\tFuncDecl:      \"func&nbsp;decl\",\n\tMethodDecl:    \"method&nbsp;decl\",\n\tUse:           \"use\",\n}\n\nfunc infoKind_htmlFunc(info SpotInfo) string {\n\treturn infoKinds[info.Kind()] // infoKind entries are html-escaped\n}\n\nfunc (p *Presentation) infoLineFunc(info SpotInfo) int {\n\tline := info.Lori()\n\tif info.IsIndex() {\n\t\tindex, _ := p.Corpus.searchIndex.Get()\n\t\tif index != nil {\n\t\t\tline = index.(*Index).Snippet(line).Line\n\t\t} else {\n\t\t\t// no line information available because\n\t\t\t// we don't have an index - this should\n\t\t\t// never happen; be conservative and don't\n\t\t\t// crash\n\t\t\tline = 0\n\t\t}\n\t}\n\treturn line\n}\n\nfunc (p *Presentation) infoSnippet_htmlFunc(info SpotInfo) string {\n\tif info.IsIndex() {\n\t\tindex, _ := p.Corpus.searchIndex.Get()\n\t\t// Snippet.Text was HTML-escaped when it was generated\n\t\treturn index.(*Index).Snippet(info.Lori()).Text\n\t}\n\treturn `<span class=\"alert\">no snippet text available</span>`\n}\n\nfunc (p *Presentation) nodeFunc(info *PageInfo, node interface{}) string {\n\tvar buf bytes.Buffer\n\tp.writeNode(&buf, info, info.FSet, node)\n\treturn buf.String()\n}\n\nfunc (p *Presentation) node_htmlFunc(info *PageInfo, node interface{}, linkify bool) string {\n\tvar buf1 bytes.Buffer\n\tp.writeNode(&buf1, info, info.FSet, node)\n\n\tvar buf2 bytes.Buffer\n\tif n, _ := node.(ast.Node); n != nil && linkify && p.DeclLinks {\n\t\tLinkifyText(&buf2, buf1.Bytes(), n)\n\t\tif st, name := isStructTypeDecl(n); st != nil {\n\t\t\taddStructFieldIDAttributes(&buf2, name, st)\n\t\t}\n\t} else {\n\t\tFormatText(&buf2, buf1.Bytes(), -1, true, \"\", nil)\n\t}\n\n\treturn buf2.String()\n}\n\n// isStructTypeDecl checks whether n is a struct declaration.\n// It either returns a non-nil StructType and its name, or zero values.\nfunc isStructTypeDecl(n ast.Node) (st *ast.StructType, name string) {\n\tgd, ok := n.(*ast.GenDecl)\n\tif !ok || gd.Tok != token.TYPE {\n\t\treturn nil, \"\"\n\t}\n\tif gd.Lparen > 0 {\n\t\t// Parenthesized type. Who does that, anyway?\n\t\t// TODO: Reportedly gri does. Fix this to handle that too.\n\t\treturn nil, \"\"\n\t}\n\tif len(gd.Specs) != 1 {\n\t\treturn nil, \"\"\n\t}\n\tts, ok := gd.Specs[0].(*ast.TypeSpec)\n\tif !ok {\n\t\treturn nil, \"\"\n\t}\n\tst, ok = ts.Type.(*ast.StructType)\n\tif !ok {\n\t\treturn nil, \"\"\n\t}\n\treturn st, ts.Name.Name\n}\n\n// addStructFieldIDAttributes modifies the contents of buf such that\n// all struct fields of the named struct have <span id='name.Field'>\n// in them, so people can link to /#Struct.Field.\nfunc addStructFieldIDAttributes(buf *bytes.Buffer, name string, st *ast.StructType) {\n\tif st.Fields == nil {\n\t\treturn\n\t}\n\t// needsLink is a set of identifiers that still need to be\n\t// linked, where value == key, to avoid an allocation in func\n\t// linkedField.\n\tneedsLink := make(map[string]string)\n\n\tfor _, f := range st.Fields.List {\n\t\tif len(f.Names) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfieldName := f.Names[0].Name\n\t\tneedsLink[fieldName] = fieldName\n\t}\n\tvar newBuf bytes.Buffer\n\tforeachLine(buf.Bytes(), func(line []byte) {\n\t\tif fieldName := linkedField(line, needsLink); fieldName != \"\" {\n\t\t\tfmt.Fprintf(&newBuf, `<span id=\"%s.%s\"></span>`, name, fieldName)\n\t\t\tdelete(needsLink, fieldName)\n\t\t}\n\t\tnewBuf.Write(line)\n\t})\n\tbuf.Reset()\n\tbuf.Write(newBuf.Bytes())\n}\n\n// foreachLine calls fn for each line of in, where a line includes\n// the trailing \"\\n\", except on the last line, if it doesn't exist.\nfunc foreachLine(in []byte, fn func(line []byte)) {\n\tfor len(in) > 0 {\n\t\tnl := bytes.IndexByte(in, '\\n')\n\t\tif nl == -1 {\n\t\t\tfn(in)\n\t\t\treturn\n\t\t}\n\t\tfn(in[:nl+1])\n\t\tin = in[nl+1:]\n\t}\n}\n\n// commentPrefix is the line prefix for comments after they've been HTMLified.\nvar commentPrefix = []byte(`<span class=\"comment\">// `)\n\n// linkedField determines whether the given line starts with an\n// identifier in the provided ids map (mapping from identifier to the\n// same identifier). The line can start with either an identifier or\n// an identifier in a comment. If one matches, it returns the\n// identifier that matched. Otherwise it returns the empty string.\nfunc linkedField(line []byte, ids map[string]string) string {\n\tline = bytes.TrimSpace(line)\n\n\t// For fields with a doc string of the\n\t// conventional form, we put the new span into\n\t// the comment instead of the field.\n\t// The \"conventional\" form is a complete sentence\n\t// per like:\n\t//\n\t//    // Foo is an optional Fooer to foo the foos.\n\t//    Foo Fooer\n\t//\n\t// In this case, we want the #StructName.Foo\n\t// link to make the browser go to the comment\n\t// line \"Foo is an optional Fooer\" instead of\n\t// the \"Foo Fooer\" line, which could otherwise\n\t// obscure the docs above the browser's \"fold\".\n\t//\n\t// TODO: do this better, so it works for all\n\t// comments, including unconventional ones.\n\tline = bytes.TrimPrefix(line, commentPrefix)\n\tid := scanIdentifier(line)\n\tif len(id) == 0 {\n\t\t// No leading identifier. Avoid map lookup for\n\t\t// somewhat common case.\n\t\treturn \"\"\n\t}\n\treturn ids[string(id)]\n}\n\n// scanIdentifier scans a valid Go identifier off the front of v and\n// either returns a subslice of v if there's a valid identifier, or\n// returns a zero-length slice.\nfunc scanIdentifier(v []byte) []byte {\n\tvar n int // number of leading bytes of v belonging to an identifier\n\tfor {\n\t\tr, width := utf8.DecodeRune(v[n:])\n\t\tif !(isLetter(r) || n > 0 && isDigit(r)) {\n\t\t\tbreak\n\t\t}\n\t\tn += width\n\t}\n\treturn v[:n]\n}\n\nfunc isLetter(ch rune) bool {\n\treturn 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)\n}\n\nfunc isDigit(ch rune) bool {\n\treturn '0' <= ch && ch <= '9' || ch >= utf8.RuneSelf && unicode.IsDigit(ch)\n}\n\nfunc comment_htmlFunc(comment string) string {\n\tvar buf bytes.Buffer\n\t// TODO(gri) Provide list of words (e.g. function parameters)\n\t//           to be emphasized by ToHTML.\n\tdoc.ToHTML(&buf, comment, nil) // does html-escaping\n\treturn buf.String()\n}\n\n// sanitizeFunc sanitizes the argument src by replacing newlines with\n// blanks, removing extra blanks, and by removing trailing whitespace\n// and commas before closing parentheses.\nfunc sanitizeFunc(src string) string {\n\tbuf := make([]byte, len(src))\n\tj := 0      // buf index\n\tcomma := -1 // comma index if >= 0\n\tfor i := 0; i < len(src); i++ {\n\t\tch := src[i]\n\t\tswitch ch {\n\t\tcase '\\t', '\\n', ' ':\n\t\t\t// ignore whitespace at the beginning, after a blank, or after opening parentheses\n\t\t\tif j == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif p := buf[j-1]; p == ' ' || p == '(' || p == '{' || p == '[' {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// replace all whitespace with blanks\n\t\t\tch = ' '\n\t\tcase ',':\n\t\t\tcomma = j\n\t\tcase ')', '}', ']':\n\t\t\t// remove any trailing comma\n\t\t\tif comma >= 0 {\n\t\t\t\tj = comma\n\t\t\t}\n\t\t\t// remove any trailing whitespace\n\t\t\tif j > 0 && buf[j-1] == ' ' {\n\t\t\t\tj--\n\t\t\t}\n\t\tdefault:\n\t\t\tcomma = -1\n\t\t}\n\t\tbuf[j] = ch\n\t\tj++\n\t}\n\t// remove trailing blank, if any\n\tif j > 0 && buf[j-1] == ' ' {\n\t\tj--\n\t}\n\treturn string(buf[:j])\n}\n\ntype PageInfo struct {\n\tDirname  string // directory containing the package\n\tErr      error  // error or nil\n\tGoogleCN bool   // page is being served from\n\n\tMode PageInfoMode // display metadata from query string\n\n\t// package info\n\tFSet       *token.FileSet         // nil if no package documentation\n\tPDoc       *doc.Package           // nil if no package documentation\n\tExamples   []*doc.Example         // nil if no example code\n\tNotes      map[string][]*doc.Note // nil if no package Notes\n\tPAst       map[string]*ast.File   // nil if no AST with package exports\n\tIsMain     bool                   // true for package main\n\tIsFiltered bool                   // true if results were filtered\n\n\t// analysis info\n\tTypeInfoIndex  map[string]int  // index of JSON datum for type T (if -analysis=type)\n\tAnalysisData   htmltemplate.JS // array of TypeInfoJSON values\n\tCallGraph      htmltemplate.JS // array of PCGNodeJSON values    (if -analysis=pointer)\n\tCallGraphIndex map[string]int  // maps func name to index in CallGraph\n\n\t// directory info\n\tDirs    *DirList  // nil if no directory information\n\tDirTime time.Time // directory time stamp\n\tDirFlat bool      // if set, show directory in a flat (non-indented) manner\n}\n\nfunc (info *PageInfo) IsEmpty() bool {\n\treturn info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil\n}\n\nfunc pkgLinkFunc(path string) string {\n\t// because of the irregular mapping under goroot\n\t// we need to correct certain relative paths\n\tpath = strings.TrimPrefix(path, \"/\")\n\tpath = strings.TrimPrefix(path, \"src/\")\n\tpath = strings.TrimPrefix(path, \"pkg/\")\n\treturn \"pkg/\" + path\n}\n\n// srcToPkgLinkFunc builds an <a> tag linking to the package\n// documentation of relpath.\nfunc srcToPkgLinkFunc(relpath string) string {\n\trelpath = pkgLinkFunc(relpath)\n\trelpath = pathpkg.Dir(relpath)\n\tif relpath == \"pkg\" {\n\t\treturn `<a href=\"/pkg\">Index</a>`\n\t}\n\treturn fmt.Sprintf(`<a href=\"/%s\">%s</a>`, relpath, relpath[len(\"pkg/\"):])\n}\n\n// srcBreadcrumbFun converts each segment of relpath to a HTML <a>.\n// Each segment links to its corresponding src directories.\nfunc srcBreadcrumbFunc(relpath string) string {\n\tsegments := strings.Split(relpath, \"/\")\n\tvar buf bytes.Buffer\n\tvar selectedSegment string\n\tvar selectedIndex int\n\n\tif strings.HasSuffix(relpath, \"/\") {\n\t\t// relpath is a directory ending with a \"/\".\n\t\t// Selected segment is the segment before the last slash.\n\t\tselectedIndex = len(segments) - 2\n\t\tselectedSegment = segments[selectedIndex] + \"/\"\n\t} else {\n\t\tselectedIndex = len(segments) - 1\n\t\tselectedSegment = segments[selectedIndex]\n\t}\n\n\tfor i := range segments[:selectedIndex] {\n\t\tbuf.WriteString(fmt.Sprintf(`<a href=\"/%s\">%s</a>/`,\n\t\t\tstrings.Join(segments[:i+1], \"/\"),\n\t\t\tsegments[i],\n\t\t))\n\t}\n\n\tbuf.WriteString(`<span class=\"text-muted\">`)\n\tbuf.WriteString(selectedSegment)\n\tbuf.WriteString(`</span>`)\n\treturn buf.String()\n}\n\nfunc newPosLink_urlFunc(srcPosLinkFunc func(s string, line, low, high int) string) func(info *PageInfo, n interface{}) string {\n\t// n must be an ast.Node or a *doc.Note\n\treturn func(info *PageInfo, n interface{}) string {\n\t\tvar pos, end token.Pos\n\n\t\tswitch n := n.(type) {\n\t\tcase ast.Node:\n\t\t\tpos = n.Pos()\n\t\t\tend = n.End()\n\t\tcase *doc.Note:\n\t\t\tpos = n.Pos\n\t\t\tend = n.End\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"wrong type for posLink_url template formatter: %T\", n))\n\t\t}\n\n\t\tvar relpath string\n\t\tvar line int\n\t\tvar low, high int // selection offset range\n\n\t\tif pos.IsValid() {\n\t\t\tp := info.FSet.Position(pos)\n\t\t\trelpath = p.Filename\n\t\t\tline = p.Line\n\t\t\tlow = p.Offset\n\t\t}\n\t\tif end.IsValid() {\n\t\t\thigh = info.FSet.Position(end).Offset\n\t\t}\n\n\t\treturn srcPosLinkFunc(relpath, line, low, high)\n\t}\n}\n\nfunc srcPosLinkFunc(s string, line, low, high int) string {\n\ts = srcLinkFunc(s)\n\tvar buf bytes.Buffer\n\ttemplate.HTMLEscape(&buf, []byte(s))\n\t// selection ranges are of form \"s=low:high\"\n\tif low < high {\n\t\tfmt.Fprintf(&buf, \"?s=%d:%d\", low, high) // no need for URL escaping\n\t\t// if we have a selection, position the page\n\t\t// such that the selection is a bit below the top\n\t\tline -= 10\n\t\tif line < 1 {\n\t\t\tline = 1\n\t\t}\n\t}\n\t// line id's in html-printed source are of the\n\t// form \"L%d\" where %d stands for the line number\n\tif line > 0 {\n\t\tfmt.Fprintf(&buf, \"#L%d\", line) // no need for URL escaping\n\t}\n\treturn buf.String()\n}\n\nfunc srcLinkFunc(s string) string {\n\ts = pathpkg.Clean(\"/\" + s)\n\tif !strings.HasPrefix(s, \"/src/\") {\n\t\ts = \"/src\" + s\n\t}\n\treturn s\n}\n\n// queryLinkFunc returns a URL for a line in a source file with a highlighted\n// query term.\n// s is expected to be a path to a source file.\n// query is expected to be a string that has already been appropriately escaped\n// for use in a URL query.\nfunc queryLinkFunc(s, query string, line int) string {\n\turl := pathpkg.Clean(\"/\"+s) + \"?h=\" + query\n\tif line > 0 {\n\t\turl += \"#L\" + strconv.Itoa(line)\n\t}\n\treturn url\n}\n\nfunc docLinkFunc(s string, ident string) string {\n\treturn pathpkg.Clean(\"/pkg/\"+s) + \"/#\" + ident\n}\n\nfunc (p *Presentation) example_htmlFunc(info *PageInfo, funcName string) string {\n\tvar buf bytes.Buffer\n\tfor _, eg := range info.Examples {\n\t\tname := stripExampleSuffix(eg.Name)\n\n\t\tif name != funcName {\n\t\t\tcontinue\n\t\t}\n\n\t\t// print code\n\t\tcnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}\n\t\tcode := p.node_htmlFunc(info, cnode, true)\n\t\tout := eg.Output\n\t\twholeFile := true\n\n\t\t// Additional formatting if this is a function body.\n\t\tif n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {\n\t\t\twholeFile = false\n\t\t\t// remove surrounding braces\n\t\t\tcode = code[1 : n-1]\n\t\t\t// unindent\n\t\t\tcode = replaceLeadingIndentation(code, strings.Repeat(\" \", p.TabWidth), \"\")\n\t\t\t// remove output comment\n\t\t\tif loc := exampleOutputRx.FindStringIndex(code); loc != nil {\n\t\t\t\tcode = strings.TrimSpace(code[:loc[0]])\n\t\t\t}\n\t\t}\n\n\t\t// Write out the playground code in standard Go style\n\t\t// (use tabs, no comment highlight, etc).\n\t\tplay := \"\"\n\t\tif eg.Play != nil && p.ShowPlayground {\n\t\t\tvar buf bytes.Buffer\n\t\t\teg.Play.Comments = filterOutBuildAnnotations(eg.Play.Comments)\n\t\t\tif err := format.Node(&buf, info.FSet, eg.Play); err != nil {\n\t\t\t\tlog.Print(err)\n\t\t\t} else {\n\t\t\t\tplay = buf.String()\n\t\t\t}\n\t\t}\n\n\t\t// Drop output, as the output comment will appear in the code.\n\t\tif wholeFile && play == \"\" {\n\t\t\tout = \"\"\n\t\t}\n\n\t\tif p.ExampleHTML == nil {\n\t\t\tout = \"\"\n\t\t\treturn \"\"\n\t\t}\n\n\t\terr := p.ExampleHTML.Execute(&buf, struct {\n\t\t\tName, Doc, Code, Play, Output string\n\t\t\tGoogleCN                      bool\n\t\t}{eg.Name, eg.Doc, code, play, out, info.GoogleCN})\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t}\n\t}\n\treturn buf.String()\n}\n\nfunc filterOutBuildAnnotations(cg []*ast.CommentGroup) []*ast.CommentGroup {\n\tif len(cg) == 0 {\n\t\treturn cg\n\t}\n\n\tfor i := range cg {\n\t\tif !strings.HasPrefix(cg[i].Text(), \"+build \") {\n\t\t\t// Found the first non-build tag, return from here until the end\n\t\t\t// of the slice.\n\t\t\treturn cg[i:]\n\t\t}\n\t}\n\n\t// There weren't any non-build tags, return an empty slice.\n\treturn []*ast.CommentGroup{}\n}\n\n// example_nameFunc takes an example function name and returns its display\n// name. For example, \"Foo_Bar_quux\" becomes \"Foo.Bar (Quux)\".\nfunc (p *Presentation) example_nameFunc(s string) string {\n\tname, suffix := splitExampleName(s)\n\t// replace _ with . for method names\n\tname = strings.Replace(name, \"_\", \".\", 1)\n\t// use \"Package\" if no name provided\n\tif name == \"\" {\n\t\tname = \"Package\"\n\t}\n\treturn name + suffix\n}\n\n// example_suffixFunc takes an example function name and returns its suffix in\n// parenthesized form. For example, \"Foo_Bar_quux\" becomes \" (Quux)\".\nfunc (p *Presentation) example_suffixFunc(name string) string {\n\t_, suffix := splitExampleName(name)\n\treturn suffix\n}\n\n// implements_html returns the \"> Implements\" toggle for a package-level named type.\n// Its contents are populated from JSON data by client-side JS at load time.\nfunc (p *Presentation) implements_htmlFunc(info *PageInfo, typeName string) string {\n\tif p.ImplementsHTML == nil {\n\t\treturn \"\"\n\t}\n\tindex, ok := info.TypeInfoIndex[typeName]\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tvar buf bytes.Buffer\n\terr := p.ImplementsHTML.Execute(&buf, struct{ Index int }{index})\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn buf.String()\n}\n\n// methodset_html returns the \"> Method set\" toggle for a package-level named type.\n// Its contents are populated from JSON data by client-side JS at load time.\nfunc (p *Presentation) methodset_htmlFunc(info *PageInfo, typeName string) string {\n\tif p.MethodSetHTML == nil {\n\t\treturn \"\"\n\t}\n\tindex, ok := info.TypeInfoIndex[typeName]\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tvar buf bytes.Buffer\n\terr := p.MethodSetHTML.Execute(&buf, struct{ Index int }{index})\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn buf.String()\n}\n\n// callgraph_html returns the \"> Call graph\" toggle for a package-level func.\n// Its contents are populated from JSON data by client-side JS at load time.\nfunc (p *Presentation) callgraph_htmlFunc(info *PageInfo, recv, name string) string {\n\tif p.CallGraphHTML == nil {\n\t\treturn \"\"\n\t}\n\tif recv != \"\" {\n\t\t// Format must match (*ssa.Function).RelString().\n\t\tname = fmt.Sprintf(\"(%s).%s\", recv, name)\n\t}\n\tindex, ok := info.CallGraphIndex[name]\n\tif !ok {\n\t\treturn \"\"\n\t}\n\tvar buf bytes.Buffer\n\terr := p.CallGraphHTML.Execute(&buf, struct{ Index int }{index})\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\treturn buf.String()\n}\n\nfunc noteTitle(note string) string {\n\treturn strings.Title(strings.ToLower(note))\n}\n\nfunc startsWithUppercase(s string) bool {\n\tr, _ := utf8.DecodeRuneInString(s)\n\treturn unicode.IsUpper(r)\n}\n\nvar exampleOutputRx = regexp.MustCompile(`(?i)//[[:space:]]*(unordered )?output:`)\n\n// stripExampleSuffix strips lowercase braz in Foo_braz or Foo_Bar_braz from name\n// while keeping uppercase Braz in Foo_Braz.\nfunc stripExampleSuffix(name string) string {\n\tif i := strings.LastIndex(name, \"_\"); i != -1 {\n\t\tif i < len(name)-1 && !startsWithUppercase(name[i+1:]) {\n\t\t\tname = name[:i]\n\t\t}\n\t}\n\treturn name\n}\n\nfunc splitExampleName(s string) (name, suffix string) {\n\ti := strings.LastIndex(s, \"_\")\n\tif 0 <= i && i < len(s)-1 && !startsWithUppercase(s[i+1:]) {\n\t\tname = s[:i]\n\t\tsuffix = \" (\" + strings.Title(s[i+1:]) + \")\"\n\t\treturn\n\t}\n\tname = s\n\treturn\n}\n\n// replaceLeadingIndentation replaces oldIndent at the beginning of each line\n// with newIndent. This is used for formatting examples. Raw strings that\n// span multiple lines are handled specially: oldIndent is not removed (since\n// go/printer will not add any indentation there), but newIndent is added\n// (since we may still want leading indentation).\nfunc replaceLeadingIndentation(body, oldIndent, newIndent string) string {\n\t// Handle indent at the beginning of the first line. After this, we handle\n\t// indentation only after a newline.\n\tvar buf bytes.Buffer\n\tif strings.HasPrefix(body, oldIndent) {\n\t\tbuf.WriteString(newIndent)\n\t\tbody = body[len(oldIndent):]\n\t}\n\n\t// Use a state machine to keep track of whether we're in a string or\n\t// rune literal while we process the rest of the code.\n\tconst (\n\t\tcodeState = iota\n\t\truneState\n\t\tinterpretedStringState\n\t\trawStringState\n\t)\n\tsearchChars := []string{\n\t\t\"'\\\"`\\n\", // codeState\n\t\t`\\'`,     // runeState\n\t\t`\\\"`,     // interpretedStringState\n\t\t\"`\\n\",    // rawStringState\n\t\t// newlineState does not need to search\n\t}\n\tstate := codeState\n\tfor {\n\t\ti := strings.IndexAny(body, searchChars[state])\n\t\tif i < 0 {\n\t\t\tbuf.WriteString(body)\n\t\t\tbreak\n\t\t}\n\t\tc := body[i]\n\t\tbuf.WriteString(body[:i+1])\n\t\tbody = body[i+1:]\n\t\tswitch state {\n\t\tcase codeState:\n\t\t\tswitch c {\n\t\t\tcase '\\'':\n\t\t\t\tstate = runeState\n\t\t\tcase '\"':\n\t\t\t\tstate = interpretedStringState\n\t\t\tcase '`':\n\t\t\t\tstate = rawStringState\n\t\t\tcase '\\n':\n\t\t\t\tif strings.HasPrefix(body, oldIndent) {\n\t\t\t\t\tbuf.WriteString(newIndent)\n\t\t\t\t\tbody = body[len(oldIndent):]\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase runeState:\n\t\t\tswitch c {\n\t\t\tcase '\\\\':\n\t\t\t\tr, size := utf8.DecodeRuneInString(body)\n\t\t\t\tbuf.WriteRune(r)\n\t\t\t\tbody = body[size:]\n\t\t\tcase '\\'':\n\t\t\t\tstate = codeState\n\t\t\t}\n\n\t\tcase interpretedStringState:\n\t\t\tswitch c {\n\t\t\tcase '\\\\':\n\t\t\t\tr, size := utf8.DecodeRuneInString(body)\n\t\t\t\tbuf.WriteRune(r)\n\t\t\t\tbody = body[size:]\n\t\t\tcase '\"':\n\t\t\t\tstate = codeState\n\t\t\t}\n\n\t\tcase rawStringState:\n\t\t\tswitch c {\n\t\t\tcase '`':\n\t\t\t\tstate = codeState\n\t\t\tcase '\\n':\n\t\t\t\tbuf.WriteString(newIndent)\n\t\t\t}\n\t\t}\n\t}\n\treturn buf.String()\n}\n\n// writeNode writes the AST node x to w.\n//\n// The provided fset must be non-nil. The pageInfo is optional. If\n// present, the pageInfo is used to add comments to struct fields to\n// say which version of Go introduced them.\nfunc (p *Presentation) writeNode(w io.Writer, pageInfo *PageInfo, fset *token.FileSet, x interface{}) {\n\t// convert trailing tabs into spaces using a tconv filter\n\t// to ensure a good outcome in most browsers (there may still\n\t// be tabs in comments and strings, but converting those into\n\t// the right number of spaces is much harder)\n\t//\n\t// TODO(gri) rethink printer flags - perhaps tconv can be eliminated\n\t//           with an another printer mode (which is more efficiently\n\t//           implemented in the printer than here with another layer)\n\n\tvar pkgName, structName string\n\tvar apiInfo pkgAPIVersions\n\tif gd, ok := x.(*ast.GenDecl); ok && pageInfo != nil && pageInfo.PDoc != nil &&\n\t\tp.Corpus != nil &&\n\t\tgd.Tok == token.TYPE && len(gd.Specs) != 0 {\n\t\tpkgName = pageInfo.PDoc.ImportPath\n\t\tif ts, ok := gd.Specs[0].(*ast.TypeSpec); ok {\n\t\t\tif _, ok := ts.Type.(*ast.StructType); ok {\n\t\t\t\tstructName = ts.Name.Name\n\t\t\t}\n\t\t}\n\t\tapiInfo = p.Corpus.pkgAPIInfo[pkgName]\n\t}\n\n\tvar out = w\n\tvar buf bytes.Buffer\n\tif structName != \"\" {\n\t\tout = &buf\n\t}\n\n\tmode := printer.TabIndent | printer.UseSpaces\n\terr := (&printer.Config{Mode: mode, Tabwidth: p.TabWidth}).Fprint(&tconv{p: p, output: out}, fset, x)\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\n\t// Add comments to struct fields saying which Go version introduced them.\n\tif structName != \"\" {\n\t\tfieldSince := apiInfo.fieldSince[structName]\n\t\ttypeSince := apiInfo.typeSince[structName]\n\t\t// Add/rewrite comments on struct fields to note which Go version added them.\n\t\tvar buf2 bytes.Buffer\n\t\tbuf2.Grow(buf.Len() + len(\" // Added in Go 1.n\")*10)\n\t\tbs := bufio.NewScanner(&buf)\n\t\tfor bs.Scan() {\n\t\t\tline := bs.Bytes()\n\t\t\tfield := firstIdent(line)\n\t\t\tvar since string\n\t\t\tif field != \"\" {\n\t\t\t\tsince = fieldSince[field]\n\t\t\t\tif since != \"\" && since == typeSince {\n\t\t\t\t\t// Don't highlight field versions if they were the\n\t\t\t\t\t// same as the struct itself.\n\t\t\t\t\tsince = \"\"\n\t\t\t\t}\n\t\t\t}\n\t\t\tif since == \"\" {\n\t\t\t\tbuf2.Write(line)\n\t\t\t} else {\n\t\t\t\tif bytes.Contains(line, slashSlash) {\n\t\t\t\t\tline = bytes.TrimRight(line, \" \\t.\")\n\t\t\t\t\tbuf2.Write(line)\n\t\t\t\t\tbuf2.WriteString(\"; added in Go \")\n\t\t\t\t} else {\n\t\t\t\t\tbuf2.Write(line)\n\t\t\t\t\tbuf2.WriteString(\" // Go \")\n\t\t\t\t}\n\t\t\t\tbuf2.WriteString(since)\n\t\t\t}\n\t\t\tbuf2.WriteByte('\\n')\n\t\t}\n\t\tw.Write(buf2.Bytes())\n\t}\n}\n\nvar slashSlash = []byte(\"//\")\n\n// WriteNode writes x to w.\n// TODO(bgarcia) Is this method needed? It's just a wrapper for p.writeNode.\nfunc (p *Presentation) WriteNode(w io.Writer, fset *token.FileSet, x interface{}) {\n\tp.writeNode(w, nil, fset, x)\n}\n\n// firstIdent returns the first identifier in x.\n// This actually parses \"identifiers\" that begin with numbers too, but we\n// never feed it such input, so it's fine.\nfunc firstIdent(x []byte) string {\n\tx = bytes.TrimSpace(x)\n\ti := bytes.IndexFunc(x, func(r rune) bool { return !unicode.IsLetter(r) && !unicode.IsNumber(r) })\n\tif i == -1 {\n\t\treturn string(x)\n\t}\n\treturn string(x[:i])\n}\n"}}

[Trace - 21:25:57.826 PM] Sending notification 'textDocument/didOpen'.
Params: {"textDocument":{"uri":"file:///home/tjs/go/src/","version":0,"languageId":"go","text":"// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// The gopls command is an LSP server for Go.\n// The Language Server Protocol allows any text editor\n// to be extended with IDE-like features;\n// see for details.\n//\n// See\n// for the most up-to-date information on the gopls status.\npackage main // import \"\"\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"\"\n\t\"\"\n\t\"\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\ttool.Main(ctx, cmd.New(\"gopls\", \"\", nil, hooks.Options), os.Args[1:])\n}\n"}}

[Trace - 21:25:57.827 PM] Sending notification 'workspace/didChangeConfiguration'.
Params: {"settings":null}

[Error - Sent] 21:25:57.830 PM #1 Internal error

[Trace - 21:25:57.830 PM] Received notification 'window/showMessage'.
Params: {"type":1,"message":"Error loading workspace folders (expected 1, got 0)\nfailed to load view for file:///home/tjs/go/src/ Internal error\n"}

Build info

  • Ubuntu Linux 20.04
  • GNU Emacs 26.3 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.14) of 2020-03-26, modified by Debian (
  • eglot-1.6, installed via ELPA. I believe this also happens with the MELPA version.
  • gopls built via go get, with repository at aa94e73 (current HEAD)
  • go version go1.14.4 linux/amd64 (installed via Ubuntu snap, rev 5830, latest/stable) master h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= => ../ h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=

Go info

go version go1.14.4 linux/amd64

Copy link

@gopherbot gopherbot commented Jun 28, 2020

Thank you for filing a gopls issue! Please take a look at the Troubleshooting guide, and make sure that you have provided all of the relevant information here.

@gopherbot gopherbot added this to the Unreleased milestone Jun 28, 2020
Copy link

@ts4z ts4z commented Jun 28, 2020 master```

HEAD of repo for build is aa94e735be7f31b6b12c5acf9c5838e5605455b4

```% gopls -rpc.trace -v check godoc/godoc.go > f
2020/06/28 02:37:53 Info:2020/06/28 02:37:53 Build info
---------- master h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= => ../ h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A=

Go info
go version go1.14.4 linux/amd64

2020/06/28 02:37:53 Info:2020/06/28 02:37:53 go env for /home/tjs/go/src/
(valid build configuration = true)
(build flags: [])
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build097267067=/tmp/go-build -gno-record-gcc-switches"

2020/06/28 02:37:54 Info:2020/06/28 02:37:54 go/packages.Load
	query=[./... builtin]
Copy link

@stamblerre stamblerre commented Jun 30, 2020

At @heschik's suggestion, I wonder if this error response comes from the workspace/configuration response from the Eglot client. One thing I'm noticing is the trailing slash in file:///home/tjs/go/src/ Based on the fact that the gopls check command works fine, I would say this is an issue with Eglot, not gopls.

Copy link

@ts4z ts4z commented Jun 30, 2020

Could be, and I'll investigate. But would it be possible to return invalid argument, or a better log diagnostic, than internal error?

Copy link

@stamblerre stamblerre commented Jun 30, 2020

Sorry if I wasn't clear - I think that Eglot is returning the internal error. We can probably wrap the error message to confirm this, but Internal error doesn't appear anywhere in the gopls codebase.

Copy link

@ts4z ts4z commented Jun 30, 2020

ah, thank you.

Copy link

@gopherbot gopherbot commented Jun 30, 2020

Change mentions this issue: internal/lsp: decorate error message from workspace/configuration

Copy link

@ts4z ts4z commented Jul 21, 2020

FWIW -- I lost track of this, and the most recent version of eglot seems to have fixed it. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants