File: completion.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.0~git20190125.d66bd3c%2Bds-4
  • links: PTS, VCS
  • area: main
  • in suites: buster, buster-backports
  • size: 8,912 kB
  • sloc: asm: 1,394; yacc: 155; makefile: 109; sh: 108; ansic: 17; xml: 11
file content (138 lines) | stat: -rw-r--r-- 4,633 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2018 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 lsp

import (
	"bytes"
	"fmt"
	"sort"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
)

func toProtocolCompletionItems(candidates []source.CompletionItem, prefix string, pos protocol.Position, snippetsSupported, signatureHelpEnabled bool) []protocol.CompletionItem {
	insertTextFormat := protocol.PlainTextFormat
	if snippetsSupported {
		insertTextFormat = protocol.SnippetTextFormat
	}
	sort.SliceStable(candidates, func(i, j int) bool {
		return candidates[i].Score > candidates[j].Score
	})
	var items []protocol.CompletionItem
	for i, candidate := range candidates {
		// Matching against the label.
		if !strings.HasPrefix(candidate.Label, prefix) {
			continue
		}
		insertText, triggerSignatureHelp := labelToProtocolSnippets(candidate.Label, candidate.Kind, insertTextFormat, signatureHelpEnabled)
		if strings.HasPrefix(insertText, prefix) {
			insertText = insertText[len(prefix):]
		}
		item := protocol.CompletionItem{
			Label:            candidate.Label,
			Detail:           candidate.Detail,
			Kind:             float64(toProtocolCompletionItemKind(candidate.Kind)),
			InsertTextFormat: insertTextFormat,
			TextEdit: &protocol.TextEdit{
				NewText: insertText,
				Range: protocol.Range{
					Start: pos,
					End:   pos,
				},
			},
			// InsertText is deprecated in favor of TextEdit.
			InsertText: insertText,
			// This is a hack so that the client sorts completion results in the order
			// according to their score. This can be removed upon the resolution of
			// https://github.com/Microsoft/language-server-protocol/issues/348.
			SortText: fmt.Sprintf("%05d", i),
		}
		// If we are completing a function, we should trigger signature help if possible.
		if triggerSignatureHelp && signatureHelpEnabled {
			item.Command = &protocol.Command{
				Command: "editor.action.triggerParameterHints",
			}
		}
		items = append(items, item)
	}
	return items
}

func toProtocolCompletionItemKind(kind source.CompletionItemKind) protocol.CompletionItemKind {
	switch kind {
	case source.InterfaceCompletionItem:
		return protocol.InterfaceCompletion
	case source.StructCompletionItem:
		return protocol.StructCompletion
	case source.TypeCompletionItem:
		return protocol.TypeParameterCompletion // ??
	case source.ConstantCompletionItem:
		return protocol.ConstantCompletion
	case source.FieldCompletionItem:
		return protocol.FieldCompletion
	case source.ParameterCompletionItem, source.VariableCompletionItem:
		return protocol.VariableCompletion
	case source.FunctionCompletionItem:
		return protocol.FunctionCompletion
	case source.MethodCompletionItem:
		return protocol.MethodCompletion
	case source.PackageCompletionItem:
		return protocol.ModuleCompletion // ??
	default:
		return protocol.TextCompletion
	}
}

func labelToProtocolSnippets(label string, kind source.CompletionItemKind, insertTextFormat protocol.InsertTextFormat, signatureHelpEnabled bool) (string, bool) {
	switch kind {
	case source.ConstantCompletionItem:
		// The label for constants is of the format "<identifier> = <value>".
		// We should not insert the " = <value>" part of the label.
		if i := strings.Index(label, " ="); i >= 0 {
			return label[:i], false
		}
	case source.FunctionCompletionItem, source.MethodCompletionItem:
		var trimmed, params string
		if i := strings.Index(label, "("); i >= 0 {
			trimmed = label[:i]
			params = strings.Trim(label[i:], "()")
		}
		if params == "" || trimmed == "" {
			return label, true
		}
		// Don't add parameters or parens for the plaintext insert format.
		if insertTextFormat == protocol.PlainTextFormat {
			return trimmed, true
		}
		// If we do have signature help enabled, the user can see parameters as
		// they type in the function, so we just return empty parentheses.
		if signatureHelpEnabled {
			return trimmed + "($1)", true
		}
		// If signature help is not enabled, we should give the user parameters
		// that they can tab through. The insert text format follows the
		// specification defined by Microsoft for LSP. The "$", "}, and "\"
		// characters should be escaped.
		r := strings.NewReplacer(
			`\`, `\\`,
			`}`, `\}`,
			`$`, `\$`,
		)
		b := bytes.NewBufferString(trimmed)
		b.WriteByte('(')
		for i, p := range strings.Split(params, ",") {
			if i != 0 {
				b.WriteString(", ")
			}
			fmt.Fprintf(b, "${%v:%v}", i+1, r.Replace(strings.Trim(p, " ")))
		}
		b.WriteByte(')')
		return b.String(), false

	}
	return label, false
}