diff --git a/internal/lsp/source/completion_literal.go b/internal/lsp/source/completion_literal.go index cf59079e7d..9254605013 100644 --- a/internal/lsp/source/completion_literal.go +++ b/internal/lsp/source/completion_literal.go @@ -85,6 +85,13 @@ func (c *completer) literal(literalType types.Type) { switch t := literalType.Underlying().(type) { case *types.Struct, *types.Array, *types.Slice, *types.Map: c.compositeLiteral(t, typeName, float64(score)) + case *types.Basic: + // Add a literal completion for basic types that implement our + // expected interface (e.g. named string type http.Dir + // implements http.FileSystem). + if isInterface(c.expectedType.objType) { + c.basicLiteral(t, typeName, float64(score)) + } } } @@ -261,6 +268,26 @@ func (c *completer) compositeLiteral(T types.Type, typeName string, matchScore f }) } +// basicLiteral adds a literal completion item for the given basic +// type name typeName. +func (c *completer) basicLiteral(T types.Type, typeName string, matchScore float64) { + snip := &snippet.Builder{} + snip.WriteText(typeName + "(") + snip.WriteFinalTabstop() + snip.WriteText(")") + + nonSnippet := typeName + "()" + + c.items = append(c.items, CompletionItem{ + Label: nonSnippet, + InsertText: nonSnippet, + Detail: T.String(), + Score: matchScore * literalCandidateScore, + Kind: VariableCompletionItem, + snippet: snip, + }) +} + // makeCall adds a completion item for a "make()" call given a specific type. func (c *completer) makeCall(typeName string, secondArg string, matchScore float64) { // Keep it simple and don't add any placeholders for optional "make()" arguments. diff --git a/internal/lsp/testdata/snippets/literal_snippets.go b/internal/lsp/testdata/snippets/literal_snippets.go index 92fe6a389d..658baf39cd 100644 --- a/internal/lsp/testdata/snippets/literal_snippets.go +++ b/internal/lsp/testdata/snippets/literal_snippets.go @@ -66,6 +66,10 @@ func (myImpl) foo() {} func (*myImpl) bar() {} +type myBasicImpl string + +func (myBasicImpl) foo() {} + func _() { type myIntf interface { foo() @@ -76,6 +80,10 @@ func _() { var mi myIntf mi = m //@snippet(" //", litImpl, "myImpl{\\}", "myImpl{\\}") + myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var") + + mi = m //@snippet(" //", litBasicImpl, "myBasicImpl($0)", "myBasicImpl($0)") + // only satisfied by pointer to myImpl type myPtrIntf interface { bar() diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index 766ddd33e9..cc134f43bd 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -30,7 +30,7 @@ import ( // are being executed. If a test is added, this number must be changed. const ( ExpectedCompletionsCount = 152 - ExpectedCompletionSnippetCount = 35 + ExpectedCompletionSnippetCount = 36 ExpectedUnimportedCompletionsCount = 1 ExpectedDeepCompletionsCount = 5 ExpectedFuzzyCompletionsCount = 6