mirror of
https://github.com/golang/go
synced 2024-11-18 17:34:51 -07:00
internal/lsp: provide option for case sensitive completion
In CL 192137 deep fuzzy matching was enabled by default. We also have options independent options "deepCompletion" and "fuzzyMatching" to control this. When fuzzy matching is disabled, case insensitive prefix matching is used. Provide an option, "caseSensitiveCompletion", which allows for case sensitive prefix matching when fuzzy matching is disabled. Change-Id: I17c8fa310b2ef79e36cc2f7303e98870690b5903 Reviewed-on: https://go-review.googlesource.com/c/tools/+/194757 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
ea99b82c7b
commit
a8d5d34286
@ -53,6 +53,10 @@ func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, ite
|
||||
//TODO: add command line completions tests when it works
|
||||
}
|
||||
|
||||
func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitiveCompletions, items tests.CompletionItems) {
|
||||
//TODO: add command line completions tests when it works
|
||||
}
|
||||
|
||||
func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items tests.CompletionItems) {
|
||||
//TODO: add command line completions tests when it works
|
||||
}
|
||||
|
@ -98,6 +98,21 @@ func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, ite
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitiveCompletions, items tests.CompletionItems) {
|
||||
for src, test := range data {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
CaseSensitive: true,
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
}
|
||||
want := expected(t, test, items)
|
||||
if msg := tests.DiffCompletionItems(want, got); msg != "" {
|
||||
t.Errorf("%s: %s", src, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items tests.CompletionItems) {
|
||||
for src, test := range data {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
|
@ -104,11 +104,21 @@ type matcher interface {
|
||||
Score(candidateLabel string) (score float32)
|
||||
}
|
||||
|
||||
// prefixMatcher implements case insensitive prefix matching.
|
||||
// prefixMatcher implements case sensitive prefix matching.
|
||||
type prefixMatcher string
|
||||
|
||||
func (pm prefixMatcher) Score(candidateLabel string) float32 {
|
||||
if strings.HasPrefix(strings.ToLower(candidateLabel), string(pm)) {
|
||||
if strings.HasPrefix(candidateLabel, string(pm)) {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// insensitivePrefixMatcher implements case insensitive prefix matching.
|
||||
type insensitivePrefixMatcher string
|
||||
|
||||
func (ipm insensitivePrefixMatcher) Score(candidateLabel string) float32 {
|
||||
if strings.HasPrefix(strings.ToLower(candidateLabel), string(ipm)) {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
@ -233,8 +243,10 @@ func (c *completer) setSurrounding(ident *ast.Ident) {
|
||||
|
||||
if c.opts.FuzzyMatching {
|
||||
c.matcher = fuzzy.NewMatcher(c.surrounding.Prefix(), fuzzy.Symbol)
|
||||
} else if c.opts.CaseSensitive {
|
||||
c.matcher = prefixMatcher(c.surrounding.Prefix())
|
||||
} else {
|
||||
c.matcher = prefixMatcher(strings.ToLower(c.surrounding.Prefix()))
|
||||
c.matcher = insensitivePrefixMatcher(strings.ToLower(c.surrounding.Prefix()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,7 @@ type Options struct {
|
||||
type CompletionOptions struct {
|
||||
Deep bool
|
||||
FuzzyMatching bool
|
||||
CaseSensitive bool
|
||||
Unimported bool
|
||||
Documentation bool
|
||||
FullDocumentation bool
|
||||
@ -200,6 +201,8 @@ func (o *Options) set(name string, value interface{}) OptionResult {
|
||||
result.setBool(&o.Completion.Deep)
|
||||
case "fuzzyMatching":
|
||||
result.setBool(&o.Completion.FuzzyMatching)
|
||||
case "caseSensitiveCompletion":
|
||||
result.setBool(&o.Completion.CaseSensitive)
|
||||
case "completeUnimported":
|
||||
result.setBool(&o.Completion.Unimported)
|
||||
|
||||
|
@ -210,6 +210,24 @@ func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, ite
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitiveCompletions, items tests.CompletionItems) {
|
||||
for src, test := range data {
|
||||
var want []protocol.CompletionItem
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
_, list := r.callCompletion(t, src, source.CompletionOptions{
|
||||
CaseSensitive: true,
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
list = tests.FilterBuiltins(list)
|
||||
}
|
||||
if diff := tests.DiffCompletionItems(want, list); diff != "" {
|
||||
t.Errorf("%s: %s", src, diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items tests.CompletionItems) {
|
||||
for src, test := range data {
|
||||
var want []protocol.CompletionItem
|
||||
|
16
internal/lsp/testdata/casesensitive/casesensitive.go
vendored
Normal file
16
internal/lsp/testdata/casesensitive/casesensitive.go
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2019 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 casesensitive
|
||||
|
||||
func _() {
|
||||
var lower int //@item(lower, "lower", "int", "var")
|
||||
var Upper int //@item(upper, "Upper", "int", "var")
|
||||
|
||||
l //@casesensitive(" //", lower)
|
||||
U //@casesensitive(" //", upper)
|
||||
|
||||
L //@casesensitive(" //")
|
||||
u //@casesensitive(" //")
|
||||
}
|
@ -34,6 +34,7 @@ const (
|
||||
ExpectedUnimportedCompletionsCount = 1
|
||||
ExpectedDeepCompletionsCount = 5
|
||||
ExpectedFuzzyCompletionsCount = 6
|
||||
ExpectedCaseSensitiveCompletionsCount = 4
|
||||
ExpectedRankedCompletionsCount = 1
|
||||
ExpectedDiagnosticsCount = 21
|
||||
ExpectedFormatCount = 6
|
||||
@ -67,6 +68,7 @@ type CompletionSnippets map[span.Span]CompletionSnippet
|
||||
type UnimportedCompletions map[span.Span]Completion
|
||||
type DeepCompletions map[span.Span]Completion
|
||||
type FuzzyCompletions map[span.Span]Completion
|
||||
type CaseSensitiveCompletions map[span.Span]Completion
|
||||
type RankCompletions map[span.Span]Completion
|
||||
type FoldingRanges []span.Span
|
||||
type Formats []span.Span
|
||||
@ -92,6 +94,7 @@ type Data struct {
|
||||
UnimportedCompletions UnimportedCompletions
|
||||
DeepCompletions DeepCompletions
|
||||
FuzzyCompletions FuzzyCompletions
|
||||
CaseSensitiveCompletions CaseSensitiveCompletions
|
||||
RankCompletions RankCompletions
|
||||
FoldingRanges FoldingRanges
|
||||
Formats Formats
|
||||
@ -123,6 +126,7 @@ type Tests interface {
|
||||
UnimportedCompletions(*testing.T, UnimportedCompletions, CompletionItems)
|
||||
DeepCompletions(*testing.T, DeepCompletions, CompletionItems)
|
||||
FuzzyCompletions(*testing.T, FuzzyCompletions, CompletionItems)
|
||||
CaseSensitiveCompletions(*testing.T, CaseSensitiveCompletions, CompletionItems)
|
||||
RankCompletions(*testing.T, RankCompletions, CompletionItems)
|
||||
FoldingRange(*testing.T, FoldingRanges)
|
||||
Format(*testing.T, Formats)
|
||||
@ -160,6 +164,9 @@ const (
|
||||
// Fuzzy tests deep completion and fuzzy matching.
|
||||
CompletionFuzzy
|
||||
|
||||
// CaseSensitive tests case sensitive completion
|
||||
CompletionCaseSensitve
|
||||
|
||||
// CompletionRank candidates in test must be valid and in the right relative order.
|
||||
CompletionRank
|
||||
)
|
||||
@ -217,6 +224,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||
DeepCompletions: make(DeepCompletions),
|
||||
FuzzyCompletions: make(FuzzyCompletions),
|
||||
RankCompletions: make(RankCompletions),
|
||||
CaseSensitiveCompletions: make(CaseSensitiveCompletions),
|
||||
Definitions: make(Definitions),
|
||||
Highlights: make(Highlights),
|
||||
References: make(References),
|
||||
@ -301,6 +309,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||
"unimported": data.collectCompletions(CompletionUnimported),
|
||||
"deep": data.collectCompletions(CompletionDeep),
|
||||
"fuzzy": data.collectCompletions(CompletionFuzzy),
|
||||
"casesensitive": data.collectCompletions(CompletionCaseSensitve),
|
||||
"rank": data.collectCompletions(CompletionRank),
|
||||
"snippet": data.collectCompletionSnippets,
|
||||
"fold": data.collectFoldingRanges,
|
||||
@ -382,6 +391,14 @@ func Run(t *testing.T, tests Tests, data *Data) {
|
||||
tests.FuzzyCompletions(t, data.FuzzyCompletions, data.CompletionItems)
|
||||
})
|
||||
|
||||
t.Run("CaseSensitiveCompletion", func(t *testing.T) {
|
||||
t.Helper()
|
||||
if len(data.CaseSensitiveCompletions) != ExpectedCaseSensitiveCompletionsCount {
|
||||
t.Errorf("got %v case sensitive completions expected %v", len(data.CaseSensitiveCompletions), ExpectedCaseSensitiveCompletionsCount)
|
||||
}
|
||||
tests.CaseSensitiveCompletions(t, data.CaseSensitiveCompletions, data.CompletionItems)
|
||||
})
|
||||
|
||||
t.Run("RankCompletions", func(t *testing.T) {
|
||||
t.Helper()
|
||||
if len(data.RankCompletions) != ExpectedRankedCompletionsCount {
|
||||
@ -638,6 +655,10 @@ func (data *Data) collectCompletions(typ CompletionTestType) func(span.Span, []t
|
||||
return func(src span.Span, expected []token.Pos) {
|
||||
result(data.RankCompletions, src, expected)
|
||||
}
|
||||
case CompletionCaseSensitve:
|
||||
return func(src span.Span, expected []token.Pos) {
|
||||
result(data.CaseSensitiveCompletions, src, expected)
|
||||
}
|
||||
default:
|
||||
return func(src span.Span, expected []token.Pos) {
|
||||
result(data.Completions, src, expected)
|
||||
|
Loading…
Reference in New Issue
Block a user