blob: 5e430e59ad65c44e968523d7475d82dec5c148c4 [file] [log] [blame]
// 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"
)
// structField calculates the plain and placeholder snippets for struct literal
// field names as in "Foo{Ba<>".
func (c *completer) structFieldSnippet(label, detail string) (*snippet.Builder, *snippet.Builder) {
if !c.inCompositeLiteralField {
return nil, nil
}
cl := c.enclosingCompositeLiteral
kv := c.enclosingKeyValue
// If we aren't in a composite literal or are already in a key/value
// expression, we don't want a snippet.
if cl == nil || kv != nil {
return nil, nil
}
if len(cl.Elts) > 0 {
i := indexExprAtPos(c.pos, cl.Elts)
if i >= len(cl.Elts) {
return nil, nil
}
// If our expression is not an identifer, we know it isn't a
// struct field name.
if _, ok := cl.Elts[i].(*ast.Ident); !ok {
return nil, nil
}
}
// It is a multi-line literal if pos is not on the same line as the literal's
// opening brace.
multiLine := c.fset.Position(c.pos).Line != c.fset.Position(cl.Lbrace).Line
// Plain snippet will turn "Foo{Ba<>" into "Foo{Bar: <>"
plain := &snippet.Builder{}
plain.WriteText(label + ": ")
plain.WritePlaceholder(nil)
if multiLine {
plain.WriteText(",")
}
// Placeholder snippet will turn "Foo{Ba<>" into "Foo{Bar: *int*"
placeholder := &snippet.Builder{}
placeholder.WriteText(label + ": ")
placeholder.WritePlaceholder(func(b *snippet.Builder) {
b.WriteText(detail)
})
if multiLine {
placeholder.WriteText(",")
}
return plain, placeholder
}
// funcCall calculates the plain and placeholder snippets for function calls.
func (c *completer) funcCallSnippet(funcName string, params []string) (*snippet.Builder, *snippet.Builder) {
for i := 1; i <= 2 && i < len(c.path); i++ {
call, ok := c.path[i].(*ast.CallExpr)
// 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 ok && call.Fun == c.path[i-1] {
return nil, nil
}
}
// Plain snippet turns "someFun<>" into "someFunc(<>)"
plain := &snippet.Builder{}
plain.WriteText(funcName + "(")
if len(params) > 0 {
plain.WritePlaceholder(nil)
}
plain.WriteText(")")
// Placeholder snippet turns "someFun<>" into "someFunc(*i int*, s string)"
placeholder := &snippet.Builder{}
placeholder.WriteText(funcName + "(")
for i, p := range params {
if i > 0 {
placeholder.WriteText(", ")
}
placeholder.WritePlaceholder(func(b *snippet.Builder) {
b.WriteText(p)
})
}
placeholder.WriteText(")")
return plain, placeholder
}