Closed marwan-at-work closed 7 months ago
Are you sure that these snippets are coming from gopls
? Because my suspicion is that they're part of the vscode-go
extension: https://github.com/golang/vscode-go/blob/baab7be148eeba4f130bfaa077f5a401adea61dd/extension/snippets/go.json#L113-L116
@mrnugget 👋🏼 yes they're coming from gopls, specifically from here: https://github.com/golang/tools/blob/1b39a8b6a9ba38b140eb9b84196ddcb4e8f53ce2/gopls/internal/golang/completion/statements.go#L178
What you linked to is the hard-coded snippet completion that returns nil, err
but gopls's error check dynamically returns the zero value of the function signature you're in. So it could be 0, "", err
instead of the blind nil, err
And notice it also does the *testing.T
check which vscode snippets does not have at all.
Thank you! Okay, very interesting. That requires an investigation.
So, first finding after digging into this a bit:
Here's what we show when typing i
(like in your example) here:
VS Code also doesn't show the snippet:
And when I check the traces, we also don't get that snippet sent back from the LSP, meaning we don't filter it out:
{
"jsonrpc": "2.0",
"result": {
"isIncomplete": true,
"items": [
{
"label": "if",
"kind": 14,
"documentation": {
"kind": "markdown",
"value": ""
},
"preselect": true,
"sortText": "00000",
"filterText": "if",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "if"
}
},
{
"label": "imag",
"kind": 3,
"detail": "func(c complex128) float64",
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00001",
"filterText": "imag",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "imag(${1:})"
}
},
{
"label": "int",
"kind": 7,
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00002",
"filterText": "int",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "int"
}
},
{
"label": "int16",
"kind": 7,
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00003",
"filterText": "int16",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "int16"
}
},
{
"label": "int32",
"kind": 7,
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00004",
"filterText": "int32",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "int32"
}
},
{
"label": "int64",
"kind": 7,
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00005",
"filterText": "int64",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "int64"
}
},
{
"label": "int8",
"kind": 7,
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00006",
"filterText": "int8",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "int8"
}
},
{
"label": "io",
"kind": 9,
"detail": "\"io\"",
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00007",
"filterText": "io",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "io"
},
"additionalTextEdits": [
{
"range": { "start": { "line": 2, "character": 7 }, "end": { "line": 2, "character": 7 } },
"newText": "(\n\t"
},
{
"range": { "start": { "line": 2, "character": 8 }, "end": { "line": 2, "character": 9 } },
"newText": ""
},
{
"range": { "start": { "line": 2, "character": 10 }, "end": { "line": 2, "character": 10 } },
"newText": "rror"
},
{
"range": { "start": { "line": 2, "character": 11 }, "end": { "line": 2, "character": 15 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 0 }, "end": { "line": 3, "character": 0 } },
"newText": "\t\""
},
{
"range": { "start": { "line": 3, "character": 1 }, "end": { "line": 3, "character": 3 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 4 }, "end": { "line": 3, "character": 5 } },
"newText": "\"\n\t\""
},
{
"range": { "start": { "line": 3, "character": 6 }, "end": { "line": 3, "character": 8 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 9 }, "end": { "line": 3, "character": 13 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 14 }, "end": { "line": 3, "character": 14 } },
"newText": "ting"
},
{
"range": { "start": { "line": 3, "character": 15 }, "end": { "line": 3, "character": 15 } },
"newText": "\n)"
}
]
},
{
"label": "intern",
"kind": 9,
"detail": "\"internal/intern\"",
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00008",
"filterText": "intern",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "intern"
},
"additionalTextEdits": [
{
"range": { "start": { "line": 2, "character": 7 }, "end": { "line": 2, "character": 7 } },
"newText": "(\n\t"
},
{
"range": { "start": { "line": 2, "character": 8 }, "end": { "line": 2, "character": 9 } },
"newText": ""
},
{
"range": { "start": { "line": 2, "character": 10 }, "end": { "line": 2, "character": 10 } },
"newText": "rror"
},
{
"range": { "start": { "line": 2, "character": 11 }, "end": { "line": 2, "character": 11 } },
"newText": "\"\n\t\"in"
},
{
"range": { "start": { "line": 2, "character": 12 }, "end": { "line": 2, "character": 12 } },
"newText": "ernal/"
},
{
"range": { "start": { "line": 2, "character": 14 }, "end": { "line": 2, "character": 15 } },
"newText": "tern"
},
{
"range": { "start": { "line": 3, "character": 0 }, "end": { "line": 3, "character": 5 } },
"newText": "\t\""
},
{
"range": { "start": { "line": 3, "character": 6 }, "end": { "line": 3, "character": 8 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 9 }, "end": { "line": 3, "character": 13 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 14 }, "end": { "line": 3, "character": 14 } },
"newText": "ting"
},
{
"range": { "start": { "line": 3, "character": 15 }, "end": { "line": 3, "character": 15 } },
"newText": "\n)"
}
]
},
{
"label": "internal",
"kind": 9,
"detail": "\"log/internal\"",
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00009",
"filterText": "internal",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "internal"
},
"additionalTextEdits": [
{
"range": { "start": { "line": 2, "character": 7 }, "end": { "line": 2, "character": 7 } },
"newText": "(\n\t"
},
{
"range": { "start": { "line": 2, "character": 8 }, "end": { "line": 2, "character": 9 } },
"newText": ""
},
{
"range": { "start": { "line": 2, "character": 10 }, "end": { "line": 2, "character": 10 } },
"newText": "rror"
},
{
"range": { "start": { "line": 2, "character": 11 }, "end": { "line": 2, "character": 12 } },
"newText": "\"\n\t\"log/"
},
{
"range": { "start": { "line": 2, "character": 14 }, "end": { "line": 2, "character": 15 } },
"newText": "ternal"
},
{
"range": { "start": { "line": 3, "character": 0 }, "end": { "line": 3, "character": 5 } },
"newText": "\t\""
},
{
"range": { "start": { "line": 3, "character": 6 }, "end": { "line": 3, "character": 8 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 9 }, "end": { "line": 3, "character": 13 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 14 }, "end": { "line": 3, "character": 14 } },
"newText": "ting"
},
{
"range": { "start": { "line": 3, "character": 15 }, "end": { "line": 3, "character": 15 } },
"newText": "\n)"
}
]
},
{
"label": "internal",
"kind": 9,
"detail": "\"net/http/internal\"",
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00010",
"filterText": "internal",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "internal"
},
"additionalTextEdits": [
{ "range": { "start": { "line": 2, "character": 7 }, "end": { "line": 2, "character": 7 } },
"newText": "(\n\t"
},
{
"range": { "start": { "line": 2, "character": 8 }, "end": { "line": 2, "character": 9 } },
"newText": ""
},
{
"range": { "start": { "line": 2, "character": 10 }, "end": { "line": 2, "character": 10 } },
"newText": "rror"
},
{
"range": { "start": { "line": 2, "character": 11 }, "end": { "line": 2, "character": 11 } },
"newText": "\"\n\t\"ne"
},
{
"range": { "start": { "line": 2, "character": 12 }, "end": { "line": 2, "character": 12 } },
"newText": "/http/"
},
{
"range": { "start": { "line": 2, "character": 14 }, "end": { "line": 2, "character": 15 } },
"newText": "ternal"
},
{
"range": { "start": { "line": 3, "character": 0 }, "end": { "line": 3, "character": 5 } },
"newText": "\t\""
},
{
"range": { "start": { "line": 3, "character": 6 }, "end": { "line": 3, "character": 8 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 9 }, "end": { "line": 3, "character": 13 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 14 }, "end": { "line": 3, "character": 14 } },
"newText": "ting"
},
{
"range": { "start": { "line": 3, "character": 15 }, "end": { "line": 3, "character": 15 } },
"newText": "\n)"
}
]
},
{
"label": "itoa",
"kind": 9,
"detail": "\"internal/itoa\"",
"documentation": {
"kind": "markdown",
"value": ""
},
"sortText": "00011",
"filterText": "itoa",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "itoa"
},
"additionalTextEdits": [
{
"range": { "start": { "line": 2, "character": 7 }, "end": { "line": 2, "character": 7 } },
"newText": "(\n\t"
},
{
"range": { "start": { "line": 2, "character": 8 }, "end": { "line": 2, "character": 9 } },
"newText": ""
},
{
"range": { "start": { "line": 2, "character": 10 }, "end": { "line": 2, "character": 10 } },
"newText": "rror"
},
{
"range": { "start": { "line": 2, "character": 11 }, "end": { "line": 2, "character": 15 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 0 }, "end": { "line": 3, "character": 0 } },
"newText": "\t\""
},
{
"range": { "start": { "line": 3, "character": 1 }, "end": { "line": 3, "character": 4 } },
"newText": "nte"
},
{
"range": { "start": { "line": 3, "character": 5 }, "end": { "line": 3, "character": 5 } },
"newText": "nal/i"
},
{
"range": { "start": { "line": 3, "character": 6 }, "end": { "line": 3, "character": 7 } },
"newText": "oa\"\n\t"
},
{
"range": { "start": { "line": 3, "character": 8 }, "end": { "line": 3, "character": 8 } },
"newText": "t"
},
{
"range": { "start": { "line": 3, "character": 9 }, "end": { "line": 3, "character": 13 } },
"newText": ""
},
{
"range": { "start": { "line": 3, "character": 14 }, "end": { "line": 3, "character": 14 } },
"newText": "ting"
},
{
"range": { "start": { "line": 3, "character": 15 }, "end": { "line": 3, "character": 15 } },
"newText": "\n)"
}
]
},
{
"label": "errors.Is",
"kind": 3,
"detail": "func(err error, target error) bool",
"documentation": {
"kind": "markdown",
"value": "Is reports whether any error in err's tree matches target.\n\nThe tree consists of err itself, followed by the errors obtained by repeatedly calling Unwrap. When err wraps multiple errors, Is examines err followed by a depth-first traversal of its children.\n\nAn error is considered to match a target if it is equal to that target or if it implements a method Is(error) bool such that Is(target) returns true.\n\nAn error type might provide an Is method so it can be treated as equivalent to an existing error. For example, if MyError defines\n\n\tfunc (m MyError) Is(target error) bool { return target == fs.ErrExist }\n\nthen Is(MyError{}, fs.ErrExist) returns true. See [syscall.Errno.Is](https://pkg.go.dev/syscall#Errno.Is) for an example in the standard library. An Is method should only shallowly compare err and the target and not call Unwrap on either.\n"
},
"sortText": "00012",
"filterText": "errors.Is",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "errors.Is(${1:})"
}
},
{
"label": "testing.Init",
"kind": 3,
"detail": "func()",
"documentation": {
"kind": "markdown",
"value": "Init registers testing flags. These flags are automatically registered by the \"go test\" command before running test functions, so Init is only needed when calling functions such as Benchmark without using \"go test\".\n\nInit has no effect if it was already called.\n"
},
"sortText": "00013",
"filterText": "testing.Init",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "testing.Init()"
}
},
{
"label": "testing.InternalBenchmark",
"kind": 22,
"detail": "struct{...}",
"documentation": {
"kind": "markdown",
"value": "InternalBenchmark is an internal type but exported because it is cross-package; it is part of the implementation of the \"go test\" command.\n"
},
"sortText": "00014",
"filterText": "testing.InternalBenchmark",
"insertTextFormat": 2,
"textEdit": {
"range": { "start": { "line": 11, "character": 1 }, "end": { "line": 11, "character": 2 } },
"newText": "testing.InternalBenchmark"
}
}
]
},
"id": 11
}
And even if I type more, I don't get that snippet from VS Code:
I'm wondering: do you have some special configuration for gopls?
Okay, I got it. We need to send usePlaceholders: true
to gopls
to enable snippets that have fields/tabstops in it.
See: https://github.com/golang/tools/blob/master/gopls/doc/settings.md#completion
In the Zed settings.json
:
{
// ...
"lsp": {
"gopls": {
"initialization_options": {
"usePlaceholders": true, // <-- important line
"hints": {
"assignVariableTypes": true,
"compositeLiteralFields": true,
"compositeLiteralTypes": true,
"constantValues": true,
"functionTypeParameters": true,
"parameterNames": true,
"rangeVariableTypes": true
}
}
}
}
}
Then we get these:
I also had to turn these on in the vscode-go extension.
BUT I do think there's a case for enabling these by default.
@mrnugget thank you! Those settings names get me every time. I knew it wasn't on-by-default, but I went looking for it before opening this issue and couldn't find anything when looking up the word "snippet" so I assumed they were now on by default.
Thanks for digging and fixing the issue!
Those settings names get me every time.
Yeah, same. The docs also aren't that clear about the effect here.
I see placeHolders are now enabled by default. I am still not getting such code snippets as completion. I tried to manually add it to settings.json but still no luck. please tell me if i am missing something.
I am using Zed 0.128.3, on Macbook pro M2 pro 16gb
@JeetChhatrala can you create a ticket with minimal reproducible example & steps to reproduce? Without example code, your settings, steps to reproduce, Go setup in the repository, it's very hard to reproduce.
See if you need a go.work
file: https://github.com/zed-industries/zed/issues/8460#issuecomment-1971216276
Make sure go
is setup correctly: https://github.com/zed-industries/zed/issues/8861#issuecomment-2015740544
@JeetChhatrala can you create a ticket with minimal reproducible example & steps to reproduce? Without example code, your settings, steps to reproduce, Go setup in the repository, it's very hard to reproduce.
See if you need a
go.work
file: #8460 (comment) Make surego
is setup correctly: #8861 (comment)
I checked both of your concerns, i have installed go using default website's pkg installer. since go to implementation works for me that should not be the issue here. and i am already using go.work in my project.
There are no steps to reproduce since i just installed the zed editor and tried it. Opening Go project and it does not work. for the same project everything works fine in VSCode.
please help me out here, this is the only reason i am still not using zed as daily driver. I really love zed and would like to use it ASAP.
There are no steps to reproduce since i just installed the zed editor and tried it. Opening Go project and it does not work. for the same project everything works fine in VSCode.
Steps to reproduce and a minimal reproducible example would be something like: "when I have this directory structure, these files, then open Zed in this directory, and try to do this, then this not work"
Right now I can't fix anything for you, because I don't know: does gopls start up? does it not startup? are there any logs? is this specific to your project? something in general not working?
Check for existing issues
Describe the bug / provide steps to reproduce it
Hi there,
Go has a few snippet completions that are sent via its gopls LSP server. For example, this VSCode completion triggers an error check inside a test function:
However, the same completion inside Zed simply does not show up.
I know there is https://github.com/zed-industries/zed/issues/4611 but that seems to be more about user-defined snippets versus a snippet that the LSP natively returns for requests.
Environment
Zed: v0.121.5 (Zed) OS: macOS 14.3.0 Memory: 96 GiB Architecture: aarch64
If applicable, add mockups / screenshots to help explain present your vision of the feature
No response
If applicable, attach your
~/Library/Logs/Zed/Zed.log
file to this issue.If you only need the most recent lines, you can run the
zed: open log
command palette action to see the last 1000.No response