--- /dev/null
+// 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 completion
+
+import (
+ "go/ast"
+
+ "golang.org/x/tools/internal/lsp/snippet"
+)
+
+// structFieldSnippets calculates the snippet for struct literal field names.
+func (c *completer) structFieldSnippet(cand candidate, 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 len(cand.path) > 0 {
+ 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.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
+}