mirror of
https://github.com/golang/go
synced 2024-11-19 02:24:41 -07:00
7d7faa4812
We were omitting the parens in function completions like "(foo<>)()" because our check thought "foo" was the Fun in the outer CallExpr so it already had parens. Fix by tightening up logic to only omit parens for cases like "foo<>()" and "foo.bar<>()". Change-Id: Ia602b80275f72baa6cdf6d61c22d3f3a6cfc3019 GitHub-Last-Rev: 41fecf92617e0812ee6552d8c43789eae83889bd GitHub-Pull-Request: golang/tools#98 Reviewed-on: https://go-review.googlesource.com/c/tools/+/176944 Reviewed-by: Rebecca Stambler <rstambler@golang.org> Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
100 lines
2.8 KiB
Go
100 lines
2.8 KiB
Go
// 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) {
|
|
clInfo := c.enclosingCompositeLiteral
|
|
|
|
if clInfo == nil || !clInfo.isStruct() {
|
|
return nil, nil
|
|
}
|
|
|
|
// If we are already in a key-value expression, we don't want a snippet.
|
|
if clInfo.kv != nil {
|
|
return nil, nil
|
|
}
|
|
|
|
// We don't want snippet unless we are completing a field name. maybeInFieldName
|
|
// means we _might_ not be a struct field name, but this method is only called for
|
|
// struct fields, so we can ignore that possibility.
|
|
if !clInfo.inKey && !clInfo.maybeInFieldName {
|
|
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.FileSet().Position(c.pos).Line != c.view.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
|
|
}
|