-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathsnippet.go
126 lines (109 loc) · 3.55 KB
/
snippet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// 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/gopls/internal/golang/completion/snippet"
"golang.org/x/tools/gopls/internal/util/safetoken"
)
// structFieldSnippet calculates the snippet for struct literal field names.
func (c *completer) structFieldSnippet(cand candidate, detail string, snip *snippet.Builder) {
if !wantStructFieldCompletions(c.enclosingCompositeLiteral) {
return
}
// 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
}
clInfo := c.enclosingCompositeLiteral
// If we are already in a key-value expression, we don't want a snippet.
if clInfo.kv != nil {
return
}
// A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>".
snip.WriteText(": ")
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.pkg.FileSet()
// If the cursor position is on a different line from the literal's opening brace,
// we are in a multiline literal. Ignore line directives.
if safetoken.StartPosition(fset, c.pos).Line != safetoken.StartPosition(fset, clInfo.cl.Lbrace).Line {
snip.WriteText(",")
}
}
// functionCallSnippet calculates the snippet for function calls.
//
// Callers should omit the suffix of type parameters that are
// constrained by the argument types, to avoid offering completions
// that contain instantiations that are redundant because of type
// inference, such as f[int](1) for func f[T any](x T).
func (c *completer) functionCallSnippet(name string, tparams, params []string, snip *snippet.Builder) {
if !c.opts.completeFunctionCalls {
snip.WriteText(name)
return
}
// 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
}
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
}
}
}
}
snip.WriteText(name)
if len(tparams) > 0 {
snip.WriteText("[")
if c.opts.placeholders {
for i, tp := range tparams {
if i > 0 {
snip.WriteText(", ")
}
snip.WritePlaceholder(func(b *snippet.Builder) {
b.WriteText(tp)
})
}
} else {
snip.WritePlaceholder(nil)
}
snip.WriteText("]")
}
snip.WriteText("(")
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(")")
}