| // 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 ( |
| "fmt" |
| "go/ast" |
| |
| "golang.org/x/tools/internal/lsp/snippet" |
| ) |
| |
| // structFieldSnippets calculates the plain and placeholder snippets for struct literal field names. |
| func (c *completer) structFieldSnippets(label, detail string) (*snippet.Builder, *snippet.Builder) { |
| if !c.wantStructFieldCompletions() { |
| return nil, 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, 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, nil |
| } |
| |
| plain, placeholder := &snippet.Builder{}, &snippet.Builder{} |
| label = fmt.Sprintf("%s: ", label) |
| |
| // A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>". |
| plain.WriteText(label) |
| plain.WritePlaceholder(nil) |
| |
| // A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>". |
| placeholder.WriteText(label) |
| placeholder.WritePlaceholder(func(b *snippet.Builder) { |
| b.WriteText(detail) |
| }) |
| |
| // If the cursor position is on a different line from the literal's opening brace, |
| // we are in a multiline literal. |
| if c.view.Session().Cache().FileSet().Position(c.pos).Line != c.view.Session().Cache().FileSet().Position(clInfo.cl.Lbrace).Line { |
| plain.WriteText(",") |
| placeholder.WriteText(",") |
| } |
| |
| return plain, placeholder |
| } |
| |
| // functionCallSnippets calculates the plain and placeholder snippets for function calls. |
| func (c *completer) functionCallSnippets(name string, params []string) (*snippet.Builder, *snippet.Builder) { |
| // 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. |
| if len(c.path) > 1 { |
| switch n := c.path[1].(type) { |
| case *ast.CallExpr: |
| if n.Fun == c.path[0] { |
| return nil, nil |
| } |
| case *ast.SelectorExpr: |
| if len(c.path) > 2 { |
| if call, ok := c.path[2].(*ast.CallExpr); ok && call.Fun == c.path[1] { |
| return nil, nil |
| } |
| } |
| } |
| } |
| plain, placeholder := &snippet.Builder{}, &snippet.Builder{} |
| label := fmt.Sprintf("%s(", name) |
| |
| // A plain snippet turns "someFun<>" into "someFunc(<>)". |
| plain.WriteText(label) |
| if len(params) > 0 { |
| plain.WritePlaceholder(nil) |
| } |
| plain.WriteText(")") |
| |
| // A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)". |
| placeholder.WriteText(label) |
| for i, p := range params { |
| if i > 0 { |
| placeholder.WriteText(", ") |
| } |
| placeholder.WritePlaceholder(func(b *snippet.Builder) { |
| b.WriteText(p) |
| }) |
| } |
| placeholder.WriteText(")") |
| |
| return plain, placeholder |
| } |