2018-11-07 13:21:31 -07:00
|
|
|
// 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.
|
|
|
|
|
2018-11-05 19:23:02 -07:00
|
|
|
package lsp
|
|
|
|
|
|
|
|
import (
|
2018-11-20 14:05:10 -07:00
|
|
|
"fmt"
|
2018-11-07 18:57:08 -07:00
|
|
|
"sort"
|
2018-11-20 14:05:10 -07:00
|
|
|
"strings"
|
2018-11-05 19:23:02 -07:00
|
|
|
|
|
|
|
"golang.org/x/tools/internal/lsp/protocol"
|
|
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
|
|
)
|
|
|
|
|
2018-11-20 14:05:10 -07:00
|
|
|
func toProtocolCompletionItems(items []source.CompletionItem, snippetsSupported, signatureHelpEnabled bool) []protocol.CompletionItem {
|
2018-11-07 18:57:08 -07:00
|
|
|
var results []protocol.CompletionItem
|
|
|
|
sort.Slice(items, func(i, j int) bool {
|
|
|
|
return items[i].Score > items[j].Score
|
|
|
|
})
|
2018-11-20 14:05:10 -07:00
|
|
|
insertTextFormat := protocol.PlainTextFormat
|
|
|
|
if snippetsSupported {
|
|
|
|
insertTextFormat = protocol.SnippetTextFormat
|
|
|
|
}
|
2018-11-07 18:57:08 -07:00
|
|
|
for _, item := range items {
|
2018-11-20 16:18:33 -07:00
|
|
|
insertText, triggerSignatureHelp := labelToProtocolSnippets(item.Label, item.Kind, insertTextFormat, signatureHelpEnabled)
|
|
|
|
i := protocol.CompletionItem{
|
2018-11-20 14:05:10 -07:00
|
|
|
Label: item.Label,
|
2018-11-20 16:18:33 -07:00
|
|
|
InsertText: insertText,
|
2018-11-20 14:05:10 -07:00
|
|
|
Detail: item.Detail,
|
|
|
|
Kind: float64(toProtocolCompletionItemKind(item.Kind)),
|
|
|
|
InsertTextFormat: insertTextFormat,
|
2018-11-20 16:18:33 -07:00
|
|
|
}
|
|
|
|
// If we are completing a function, we should trigger signature help if possible.
|
|
|
|
if triggerSignatureHelp && signatureHelpEnabled {
|
|
|
|
i.Command = &protocol.Command{
|
|
|
|
Command: "editor.action.triggerParameterHints",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
results = append(results, i)
|
2018-11-07 18:57:08 -07:00
|
|
|
}
|
|
|
|
return results
|
|
|
|
}
|
|
|
|
|
|
|
|
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 // ??
|
2018-11-05 19:23:02 -07:00
|
|
|
default:
|
2018-11-07 18:57:08 -07:00
|
|
|
return protocol.TextCompletion
|
2018-11-05 19:23:02 -07:00
|
|
|
}
|
2018-11-20 14:05:10 -07:00
|
|
|
}
|
|
|
|
|
2018-11-20 16:18:33 -07:00
|
|
|
func labelToProtocolSnippets(label string, kind source.CompletionItemKind, insertTextFormat protocol.InsertTextFormat, signatureHelpEnabled bool) (string, bool) {
|
2018-11-20 14:05:10 -07:00
|
|
|
switch kind {
|
|
|
|
case source.ConstantCompletionItem:
|
|
|
|
// The label for constants is of the format "<identifier> = <value>".
|
|
|
|
// We should now insert the " = <value>" part of the label.
|
2018-11-20 16:18:33 -07:00
|
|
|
return label[:strings.Index(label, " =")], false
|
2018-11-20 14:05:10 -07:00
|
|
|
case source.FunctionCompletionItem, source.MethodCompletionItem:
|
|
|
|
trimmed := label[:strings.Index(label, "(")]
|
|
|
|
params := strings.Trim(label[strings.Index(label, "("):], "()")
|
|
|
|
if params == "" {
|
2018-11-20 16:18:33 -07:00
|
|
|
return label, true
|
2018-11-20 14:05:10 -07:00
|
|
|
}
|
|
|
|
// Don't add parameters or parens for the plaintext insert format.
|
|
|
|
if insertTextFormat == protocol.PlainTextFormat {
|
2018-11-20 16:18:33 -07:00
|
|
|
return trimmed, true
|
2018-11-20 14:05:10 -07:00
|
|
|
}
|
|
|
|
// 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 {
|
2018-11-20 16:18:33 -07:00
|
|
|
return trimmed + "($1)", true
|
2018-11-20 14:05:10 -07:00
|
|
|
}
|
|
|
|
// 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(
|
|
|
|
`\`, `\\`,
|
|
|
|
`}`, `\}`,
|
|
|
|
`$`, `\$`,
|
|
|
|
)
|
|
|
|
trimmed += "("
|
|
|
|
for i, p := range strings.Split(params, ",") {
|
|
|
|
if i != 0 {
|
|
|
|
trimmed += ", "
|
|
|
|
}
|
|
|
|
trimmed += fmt.Sprintf("${%v:%v}", i+1, r.Replace(strings.Trim(p, " ")))
|
|
|
|
}
|
2018-11-20 16:18:33 -07:00
|
|
|
return trimmed + ")", false
|
2018-11-05 19:23:02 -07:00
|
|
|
|
2018-11-20 14:05:10 -07:00
|
|
|
}
|
2018-11-20 16:18:33 -07:00
|
|
|
return label, false
|
2018-11-05 19:23:02 -07:00
|
|
|
}
|