golang.org/x/tools/gopls@v0.15.3/internal/golang/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  	"golang.org/x/tools/gopls/internal/golang/completion/snippet"
    11  	"golang.org/x/tools/gopls/internal/util/safetoken"
    12  )
    13  
    14  // structFieldSnippet calculates the snippet for struct literal field names.
    15  func (c *completer) structFieldSnippet(cand candidate, detail string, snip *snippet.Builder) {
    16  	if !c.wantStructFieldCompletions() {
    17  		return
    18  	}
    19  
    20  	// If we are in a deep completion then we can't be completing a field
    21  	// name (e.g. "Foo{f<>}" completing to "Foo{f.Bar}" should not generate
    22  	// a snippet).
    23  	if len(cand.path) > 0 {
    24  		return
    25  	}
    26  
    27  	clInfo := c.enclosingCompositeLiteral
    28  
    29  	// If we are already in a key-value expression, we don't want a snippet.
    30  	if clInfo.kv != nil {
    31  		return
    32  	}
    33  
    34  	// A plain snippet turns "Foo{Ba<>" into "Foo{Bar: <>".
    35  	snip.WriteText(": ")
    36  	snip.WritePlaceholder(func(b *snippet.Builder) {
    37  		// A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>".
    38  		if c.opts.placeholders {
    39  			b.WriteText(detail)
    40  		}
    41  	})
    42  
    43  	fset := c.pkg.FileSet()
    44  
    45  	// If the cursor position is on a different line from the literal's opening brace,
    46  	// we are in a multiline literal. Ignore line directives.
    47  	if safetoken.StartPosition(fset, c.pos).Line != safetoken.StartPosition(fset, clInfo.cl.Lbrace).Line {
    48  		snip.WriteText(",")
    49  	}
    50  }
    51  
    52  // functionCallSnippet calculates the snippet for function calls.
    53  //
    54  // Callers should omit the suffix of type parameters that are
    55  // constrained by the argument types, to avoid offering completions
    56  // that contain instantiations that are redundant because of type
    57  // inference, such as f[int](1) for func f[T any](x T).
    58  func (c *completer) functionCallSnippet(name string, tparams, params []string, snip *snippet.Builder) {
    59  	if !c.opts.completeFunctionCalls {
    60  		snip.WriteText(name)
    61  		return
    62  	}
    63  
    64  	// If there is no suffix then we need to reuse existing call parens
    65  	// "()" if present. If there is an identifier suffix then we always
    66  	// need to include "()" since we don't overwrite the suffix.
    67  	if c.surrounding != nil && c.surrounding.Suffix() == "" && len(c.path) > 1 {
    68  		// If we are the left side (i.e. "Fun") part of a call expression,
    69  		// we don't want a snippet since there are already parens present.
    70  		switch n := c.path[1].(type) {
    71  		case *ast.CallExpr:
    72  			// The Lparen != Rparen check detects fudged CallExprs we
    73  			// inserted when fixing the AST. In this case, we do still need
    74  			// to insert the calling "()" parens.
    75  			if n.Fun == c.path[0] && n.Lparen != n.Rparen {
    76  				return
    77  			}
    78  		case *ast.SelectorExpr:
    79  			if len(c.path) > 2 {
    80  				if call, ok := c.path[2].(*ast.CallExpr); ok && call.Fun == c.path[1] && call.Lparen != call.Rparen {
    81  					return
    82  				}
    83  			}
    84  		}
    85  	}
    86  
    87  	snip.WriteText(name)
    88  
    89  	if len(tparams) > 0 {
    90  		snip.WriteText("[")
    91  		if c.opts.placeholders {
    92  			for i, tp := range tparams {
    93  				if i > 0 {
    94  					snip.WriteText(", ")
    95  				}
    96  				snip.WritePlaceholder(func(b *snippet.Builder) {
    97  					b.WriteText(tp)
    98  				})
    99  			}
   100  		} else {
   101  			snip.WritePlaceholder(nil)
   102  		}
   103  		snip.WriteText("]")
   104  	}
   105  
   106  	snip.WriteText("(")
   107  
   108  	if c.opts.placeholders {
   109  		// A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)".
   110  		for i, p := range params {
   111  			if i > 0 {
   112  				snip.WriteText(", ")
   113  			}
   114  			snip.WritePlaceholder(func(b *snippet.Builder) {
   115  				b.WriteText(p)
   116  			})
   117  		}
   118  	} else {
   119  		// A plain snippet turns "someFun<>" into "someFunc(<>)".
   120  		if len(params) > 0 {
   121  			snip.WritePlaceholder(nil)
   122  		}
   123  	}
   124  
   125  	snip.WriteText(")")
   126  }