mirror of
https://github.com/golang/go
synced 2024-11-18 12:54:44 -07:00
cf2d1e09c8
Assigning a slice to the appendage of itself is common and tedious enough to warrant a special case completion candidate. We now offer smarter "append()" candidates: var foo []int foo = app<> // offer "append(foo, <>)" fo<> // offer "foo = append(foo, <>)" The latter is only offered if the best completion candidate is a slice. It is inserted as the second-best candidate because it seems impossible to avoid annoying false positives if it is ranked first. I added a new debug option to disable literal completions. This was to clean up some test logic that was disabling snippets for all tests just to defeat literal completions. My tests were failing mysteriously due to having snippets disabled, and it was hard to figure out why. Change-Id: I3e8313e00a1409840cb99d5d71c593435a7aeb71 Reviewed-on: https://go-review.googlesource.com/c/tools/+/221777 Run-TryBot: Muir Manders <muir@mnd.rs> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
150 lines
4.5 KiB
Go
150 lines
4.5 KiB
Go
package lsp
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/tools/internal/lsp/protocol"
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
"golang.org/x/tools/internal/lsp/tests"
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
|
got := r.callCompletion(t, src, func(opts *source.Options) {
|
|
opts.DeepCompletion = false
|
|
opts.Matcher = source.CaseInsensitive
|
|
opts.UnimportedCompletion = false
|
|
opts.InsertTextFormat = protocol.SnippetTextFormat
|
|
if !strings.Contains(string(src.URI()), "literal") {
|
|
opts.LiteralCompletions = false
|
|
}
|
|
})
|
|
got = tests.FilterBuiltins(src, got)
|
|
want := expected(t, test, items)
|
|
if diff := tests.DiffCompletionItems(want, got); diff != "" {
|
|
t.Errorf("%s", diff)
|
|
}
|
|
}
|
|
|
|
func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
|
|
list := r.callCompletion(t, src, func(opts *source.Options) {
|
|
opts.Placeholders = placeholders
|
|
opts.DeepCompletion = true
|
|
opts.Matcher = source.Fuzzy
|
|
opts.UnimportedCompletion = false
|
|
})
|
|
got := tests.FindItem(list, *items[expected.CompletionItem])
|
|
want := expected.PlainSnippet
|
|
if placeholders {
|
|
want = expected.PlaceholderSnippet
|
|
}
|
|
if diff := tests.DiffSnippets(want, got); diff != "" {
|
|
t.Errorf("%s", diff)
|
|
}
|
|
}
|
|
|
|
func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
|
got := r.callCompletion(t, src, func(opts *source.Options) {})
|
|
got = tests.FilterBuiltins(src, got)
|
|
want := expected(t, test, items)
|
|
if diff := tests.CheckCompletionOrder(want, got, false); diff != "" {
|
|
t.Errorf("%s", diff)
|
|
}
|
|
}
|
|
|
|
func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
|
got := r.callCompletion(t, src, func(opts *source.Options) {
|
|
opts.DeepCompletion = true
|
|
opts.Matcher = source.CaseInsensitive
|
|
opts.UnimportedCompletion = false
|
|
})
|
|
got = tests.FilterBuiltins(src, got)
|
|
want := expected(t, test, items)
|
|
if msg := tests.DiffCompletionItems(want, got); msg != "" {
|
|
t.Errorf("%s", msg)
|
|
}
|
|
}
|
|
|
|
func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
|
got := r.callCompletion(t, src, func(opts *source.Options) {
|
|
opts.DeepCompletion = true
|
|
opts.Matcher = source.Fuzzy
|
|
opts.UnimportedCompletion = false
|
|
})
|
|
got = tests.FilterBuiltins(src, got)
|
|
want := expected(t, test, items)
|
|
if msg := tests.DiffCompletionItems(want, got); msg != "" {
|
|
t.Errorf("%s", msg)
|
|
}
|
|
}
|
|
|
|
func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
|
got := r.callCompletion(t, src, func(opts *source.Options) {
|
|
opts.Matcher = source.CaseSensitive
|
|
opts.UnimportedCompletion = false
|
|
})
|
|
got = tests.FilterBuiltins(src, got)
|
|
want := expected(t, test, items)
|
|
if msg := tests.DiffCompletionItems(want, got); msg != "" {
|
|
t.Errorf("%s", msg)
|
|
}
|
|
}
|
|
|
|
func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
|
got := r.callCompletion(t, src, func(opts *source.Options) {
|
|
opts.DeepCompletion = true
|
|
opts.Matcher = source.Fuzzy
|
|
opts.UnimportedCompletion = false
|
|
})
|
|
want := expected(t, test, items)
|
|
if msg := tests.CheckCompletionOrder(want, got, true); msg != "" {
|
|
t.Errorf("%s", msg)
|
|
}
|
|
}
|
|
|
|
func expected(t *testing.T, test tests.Completion, items tests.CompletionItems) []protocol.CompletionItem {
|
|
t.Helper()
|
|
|
|
var want []protocol.CompletionItem
|
|
for _, pos := range test.CompletionItems {
|
|
item := items[pos]
|
|
want = append(want, tests.ToProtocolCompletionItem(*item))
|
|
}
|
|
return want
|
|
}
|
|
|
|
func (r *runner) callCompletion(t *testing.T, src span.Span, options func(*source.Options)) []protocol.CompletionItem {
|
|
t.Helper()
|
|
|
|
view, err := r.server.session.ViewOf(src.URI())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
original := view.Options()
|
|
modified := original
|
|
options(&modified)
|
|
view, err = view.SetOptions(r.ctx, modified)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return nil
|
|
}
|
|
defer view.SetOptions(r.ctx, original)
|
|
|
|
list, err := r.server.Completion(r.ctx, &protocol.CompletionParams{
|
|
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
|
TextDocument: protocol.TextDocumentIdentifier{
|
|
URI: protocol.URIFromSpanURI(src.URI()),
|
|
},
|
|
Position: protocol.Position{
|
|
Line: float64(src.Start().Line() - 1),
|
|
Character: float64(src.Start().Column() - 1),
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return list.Items
|
|
}
|