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  }