github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/source/completion/snippet.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package completion 6 7 import ( 8 "go/ast" 9 10 "github.com/powerman/golang-tools/internal/lsp/snippet" 11 ) 12 13 // structFieldSnippets calculates the snippet for struct literal field names. 14 func (c *completer) structFieldSnippet(cand candidate, detail string, snip *snippet.Builder) { 15 if !c.wantStructFieldCompletions() { 16 return 17 } 18 19 // If we are in a deep completion then we can't be completing a field 20 // name (e.g. "Foo{f<>}" completing to "Foo{f.Bar}" should not generate 21 // a snippet). 22 if len(cand.path) > 0 { 23 return 24 } 25 26 clInfo := c.enclosingCompositeLiteral 27 28 // If we are already in a key-value expression, we don't want a snippet. 29 if clInfo.kv != nil { 30 return 31 } 32 33 // A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>". 34 snip.WriteText(": ") 35 snip.WritePlaceholder(func(b *snippet.Builder) { 36 // A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>". 37 if c.opts.placeholders { 38 b.WriteText(detail) 39 } 40 }) 41 42 fset := c.snapshot.FileSet() 43 44 // If the cursor position is on a different line from the literal's opening brace, 45 // we are in a multiline literal. 46 if fset.Position(c.pos).Line != fset.Position(clInfo.cl.Lbrace).Line { 47 snip.WriteText(",") 48 } 49 } 50 51 // functionCallSnippets calculates the snippet for function calls. 52 func (c *completer) functionCallSnippet(name string, tparams, params []string, snip *snippet.Builder) { 53 // If there is no suffix then we need to reuse existing call parens 54 // "()" if present. If there is an identifier suffix then we always 55 // need to include "()" since we don't overwrite the suffix. 56 if c.surrounding != nil && c.surrounding.Suffix() == "" && len(c.path) > 1 { 57 // If we are the left side (i.e. "Fun") part of a call expression, 58 // we don't want a snippet since there are already parens present. 59 switch n := c.path[1].(type) { 60 case *ast.CallExpr: 61 // The Lparen != Rparen check detects fudged CallExprs we 62 // inserted when fixing the AST. In this case, we do still need 63 // to insert the calling "()" parens. 64 if n.Fun == c.path[0] && n.Lparen != n.Rparen { 65 return 66 } 67 case *ast.SelectorExpr: 68 if len(c.path) > 2 { 69 if call, ok := c.path[2].(*ast.CallExpr); ok && call.Fun == c.path[1] && call.Lparen != call.Rparen { 70 return 71 } 72 } 73 } 74 } 75 76 snip.WriteText(name) 77 78 if len(tparams) > 0 { 79 snip.WriteText("[") 80 if c.opts.placeholders { 81 for i, tp := range tparams { 82 if i > 0 { 83 snip.WriteText(", ") 84 } 85 snip.WritePlaceholder(func(b *snippet.Builder) { 86 b.WriteText(tp) 87 }) 88 } 89 } else { 90 snip.WritePlaceholder(nil) 91 } 92 snip.WriteText("]") 93 } 94 95 snip.WriteText("(") 96 97 if c.opts.placeholders { 98 // A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)". 99 for i, p := range params { 100 if i > 0 { 101 snip.WriteText(", ") 102 } 103 snip.WritePlaceholder(func(b *snippet.Builder) { 104 b.WriteText(p) 105 }) 106 } 107 } else { 108 // A plain snippet turns "someFun<>" into "someFunc(<>)". 109 if len(params) > 0 { 110 snip.WritePlaceholder(nil) 111 } 112 } 113 114 snip.WriteText(")") 115 }