2019-04-28 21:19:54 -06:00
|
|
|
// 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"
|
|
|
|
)
|
|
|
|
|
2019-09-04 11:23:14 -06:00
|
|
|
// structFieldSnippets calculates the snippet for struct literal field names.
|
|
|
|
func (c *completer) structFieldSnippet(label, detail string) *snippet.Builder {
|
2019-06-27 11:50:01 -06:00
|
|
|
if !c.wantStructFieldCompletions() {
|
2019-09-04 11:23:14 -06:00
|
|
|
return nil
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
|
|
|
|
2019-06-27 11:50:01 -06:00
|
|
|
// 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() {
|
2019-09-04 11:23:14 -06:00
|
|
|
return nil
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
2019-05-13 15:37:08 -06:00
|
|
|
|
2019-06-27 11:50:01 -06:00
|
|
|
clInfo := c.enclosingCompositeLiteral
|
|
|
|
|
|
|
|
// If we are already in a key-value expression, we don't want a snippet.
|
|
|
|
if clInfo.kv != nil {
|
2019-09-04 11:23:14 -06:00
|
|
|
return nil
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
|
|
|
|
2019-09-04 11:23:14 -06:00
|
|
|
snip := &snippet.Builder{}
|
2019-04-28 21:19:54 -06:00
|
|
|
|
2019-04-29 17:47:54 -06:00
|
|
|
// A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>".
|
2019-09-04 11:23:14 -06:00
|
|
|
snip.WriteText(label + ": ")
|
|
|
|
snip.WritePlaceholder(func(b *snippet.Builder) {
|
|
|
|
// A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>".
|
2019-12-29 00:22:12 -07:00
|
|
|
if c.opts.placeholders {
|
2019-09-04 11:23:14 -06:00
|
|
|
b.WriteText(detail)
|
|
|
|
}
|
2019-04-28 21:19:54 -06:00
|
|
|
})
|
2019-04-29 17:47:54 -06:00
|
|
|
|
2020-07-28 15:00:10 -06:00
|
|
|
fset := c.snapshot.FileSet()
|
2019-09-17 20:48:41 -06:00
|
|
|
|
2019-04-29 17:47:54 -06:00
|
|
|
// If the cursor position is on a different line from the literal's opening brace,
|
|
|
|
// we are in a multiline literal.
|
2019-09-17 20:48:41 -06:00
|
|
|
if fset.Position(c.pos).Line != fset.Position(clInfo.cl.Lbrace).Line {
|
2019-09-04 11:23:14 -06:00
|
|
|
snip.WriteText(",")
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
|
|
|
|
2019-09-04 11:23:14 -06:00
|
|
|
return snip
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
|
|
|
|
2019-09-04 11:23:14 -06:00
|
|
|
// functionCallSnippets calculates the snippet for function calls.
|
|
|
|
func (c *completer) functionCallSnippet(name string, params []string) *snippet.Builder {
|
2019-09-17 20:48:41 -06:00
|
|
|
// If there is no suffix then we need to reuse existing call parens
|
2019-11-19 13:32:09 -07:00
|
|
|
// "()" if present. If there is an identifier suffix then we always
|
2019-09-17 20:48:41 -06:00
|
|
|
// 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.
|
2019-05-13 21:09:27 -06:00
|
|
|
switch n := c.path[1].(type) {
|
|
|
|
case *ast.CallExpr:
|
2019-09-06 15:22:54 -06:00
|
|
|
// 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 {
|
2019-09-04 11:23:14 -06:00
|
|
|
return nil
|
2019-05-13 21:09:27 -06:00
|
|
|
}
|
|
|
|
case *ast.SelectorExpr:
|
|
|
|
if len(c.path) > 2 {
|
2019-09-06 15:22:54 -06:00
|
|
|
if call, ok := c.path[2].(*ast.CallExpr); ok && call.Fun == c.path[1] && call.Lparen != call.Rparen {
|
2019-09-04 11:23:14 -06:00
|
|
|
return nil
|
2019-05-13 21:09:27 -06:00
|
|
|
}
|
|
|
|
}
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
|
|
|
}
|
2019-09-04 11:23:14 -06:00
|
|
|
snip := &snippet.Builder{}
|
|
|
|
snip.WriteText(name + "(")
|
|
|
|
|
2019-12-29 00:22:12 -07:00
|
|
|
if c.opts.placeholders {
|
2019-09-04 11:23:14 -06:00
|
|
|
// 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)
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 11:23:14 -06:00
|
|
|
snip.WriteText(")")
|
|
|
|
|
|
|
|
return snip
|
2019-04-28 21:19:54 -06:00
|
|
|
}
|