1
0
mirror of https://github.com/golang/go synced 2024-10-01 05:28:33 -06:00
go/internal/lsp/source/completion_snippet.go
Rebecca Stambler 35ba81b9fb internal/lsp: reorganize and refactor code
This change cleans up internal/lsp/source/view.go to have a more logical
ordering and deletes the view.CheckPackageHandle function. Now, the only
way to get a CheckPackageHandle is through a snapshot (so all of the
corresponding edits).

Also, renamed fuzzy tests to fuzzymatch. Noticed this weird error when
debugging - I had golang.org/x/tools/internal/lsp/fuzzy in my module
cache and it conflicted with the test version.

Change-Id: Ib87836796a8e76e6b6ed1306c2a93e9a5db91cce
Reviewed-on: https://go-review.googlesource.com/c/tools/+/208099
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
2019-11-21 02:33:28 +00:00

103 lines
2.9 KiB
Go

// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package source
import (
"go/ast"
"golang.org/x/tools/internal/lsp/snippet"
)
// structFieldSnippets calculates the snippet for struct literal field names.
func (c *completer) structFieldSnippet(label, detail string) *snippet.Builder {
if !c.wantStructFieldCompletions() {
return nil
}
// If we are in a deep completion then we can't be completing a field
// name (e.g. "Foo{f<>}" completing to "Foo{f.Bar}" should not generate
// a snippet).
if c.inDeepCompletion() {
return nil
}
clInfo := c.enclosingCompositeLiteral
// If we are already in a key-value expression, we don't want a snippet.
if clInfo.kv != nil {
return nil
}
snip := &snippet.Builder{}
// A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>".
snip.WriteText(label + ": ")
snip.WritePlaceholder(func(b *snippet.Builder) {
// A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>".
if c.opts.Placeholders {
b.WriteText(detail)
}
})
fset := c.snapshot.View().Session().Cache().FileSet()
// If the cursor position is on a different line from the literal's opening brace,
// we are in a multiline literal.
if fset.Position(c.pos).Line != fset.Position(clInfo.cl.Lbrace).Line {
snip.WriteText(",")
}
return snip
}
// functionCallSnippets calculates the snippet for function calls.
func (c *completer) functionCallSnippet(name string, params []string) *snippet.Builder {
// If there is no suffix then we need to reuse existing call parens
// "()" if present. If there is an identifier suffix then we always
// need to include "()" since we don't overwrite the suffix.
if c.surrounding != nil && c.surrounding.Suffix() == "" && len(c.path) > 1 {
// If we are the left side (i.e. "Fun") part of a call expression,
// we don't want a snippet since there are already parens present.
switch n := c.path[1].(type) {
case *ast.CallExpr:
// The Lparen != Rparen check detects fudged CallExprs we
// inserted when fixing the AST. In this case, we do still need
// to insert the calling "()" parens.
if n.Fun == c.path[0] && n.Lparen != n.Rparen {
return nil
}
case *ast.SelectorExpr:
if len(c.path) > 2 {
if call, ok := c.path[2].(*ast.CallExpr); ok && call.Fun == c.path[1] && call.Lparen != call.Rparen {
return nil
}
}
}
}
snip := &snippet.Builder{}
snip.WriteText(name + "(")
if c.opts.Placeholders {
// A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)".
for i, p := range params {
if i > 0 {
snip.WriteText(", ")
}
snip.WritePlaceholder(func(b *snippet.Builder) {
b.WriteText(p)
})
}
} else {
// A plain snippet turns "someFun<>" into "someFunc(<>)".
if len(params) > 0 {
snip.WritePlaceholder(nil)
}
}
snip.WriteText(")")
return snip
}