mirror of
https://github.com/golang/go
synced 2024-11-18 15:04:44 -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(" //")
|
||||
}
|
@ -29,26 +29,27 @@ import (
|
||||
// We hardcode the expected number of test cases to ensure that all tests
|
||||
// are being executed. If a test is added, this number must be changed.
|
||||
const (
|
||||
ExpectedCompletionsCount = 169
|
||||
ExpectedCompletionSnippetCount = 36
|
||||
ExpectedUnimportedCompletionsCount = 1
|
||||
ExpectedDeepCompletionsCount = 5
|
||||
ExpectedFuzzyCompletionsCount = 6
|
||||
ExpectedRankedCompletionsCount = 1
|
||||
ExpectedDiagnosticsCount = 21
|
||||
ExpectedFormatCount = 6
|
||||
ExpectedImportCount = 2
|
||||
ExpectedSuggestedFixCount = 1
|
||||
ExpectedDefinitionsCount = 39
|
||||
ExpectedTypeDefinitionsCount = 2
|
||||
ExpectedFoldingRangesCount = 2
|
||||
ExpectedHighlightsCount = 2
|
||||
ExpectedReferencesCount = 6
|
||||
ExpectedRenamesCount = 20
|
||||
ExpectedPrepareRenamesCount = 8
|
||||
ExpectedSymbolsCount = 1
|
||||
ExpectedSignaturesCount = 21
|
||||
ExpectedLinksCount = 4
|
||||
ExpectedCompletionsCount = 169
|
||||
ExpectedCompletionSnippetCount = 36
|
||||
ExpectedUnimportedCompletionsCount = 1
|
||||
ExpectedDeepCompletionsCount = 5
|
||||
ExpectedFuzzyCompletionsCount = 6
|
||||
ExpectedCaseSensitiveCompletionsCount = 4
|
||||
ExpectedRankedCompletionsCount = 1
|
||||
ExpectedDiagnosticsCount = 21
|
||||
ExpectedFormatCount = 6
|
||||
ExpectedImportCount = 2
|
||||
ExpectedSuggestedFixCount = 1
|
||||
ExpectedDefinitionsCount = 39
|
||||
ExpectedTypeDefinitionsCount = 2
|
||||
ExpectedFoldingRangesCount = 2
|
||||
ExpectedHighlightsCount = 2
|
||||
ExpectedReferencesCount = 6
|
||||
ExpectedRenamesCount = 20
|
||||
ExpectedPrepareRenamesCount = 8
|
||||
ExpectedSymbolsCount = 1
|
||||
ExpectedSignaturesCount = 21
|
||||
ExpectedLinksCount = 4
|
||||
)
|
||||
|
||||
const (
|
||||
@ -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
|
||||
@ -83,29 +85,30 @@ type Signatures map[span.Span]*source.SignatureInformation
|
||||
type Links map[span.URI][]Link
|
||||
|
||||
type Data struct {
|
||||
Config packages.Config
|
||||
Exported *packagestest.Exported
|
||||
Diagnostics Diagnostics
|
||||
CompletionItems CompletionItems
|
||||
Completions Completions
|
||||
CompletionSnippets CompletionSnippets
|
||||
UnimportedCompletions UnimportedCompletions
|
||||
DeepCompletions DeepCompletions
|
||||
FuzzyCompletions FuzzyCompletions
|
||||
RankCompletions RankCompletions
|
||||
FoldingRanges FoldingRanges
|
||||
Formats Formats
|
||||
Imports Imports
|
||||
SuggestedFixes SuggestedFixes
|
||||
Definitions Definitions
|
||||
Highlights Highlights
|
||||
References References
|
||||
Renames Renames
|
||||
PrepareRenames PrepareRenames
|
||||
Symbols Symbols
|
||||
symbolsChildren SymbolsChildren
|
||||
Signatures Signatures
|
||||
Links Links
|
||||
Config packages.Config
|
||||
Exported *packagestest.Exported
|
||||
Diagnostics Diagnostics
|
||||
CompletionItems CompletionItems
|
||||
Completions Completions
|
||||
CompletionSnippets CompletionSnippets
|
||||
UnimportedCompletions UnimportedCompletions
|
||||
DeepCompletions DeepCompletions
|
||||
FuzzyCompletions FuzzyCompletions
|
||||
CaseSensitiveCompletions CaseSensitiveCompletions
|
||||
RankCompletions RankCompletions
|
||||
FoldingRanges FoldingRanges
|
||||
Formats Formats
|
||||
Imports Imports
|
||||
SuggestedFixes SuggestedFixes
|
||||
Definitions Definitions
|
||||
Highlights Highlights
|
||||
References References
|
||||
Renames Renames
|
||||
PrepareRenames PrepareRenames
|
||||
Symbols Symbols
|
||||
symbolsChildren SymbolsChildren
|
||||
Signatures Signatures
|
||||
Links Links
|
||||
|
||||
t testing.TB
|
||||
fragments map[string]string
|
||||
@ -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
|
||||
)
|
||||
@ -209,23 +216,24 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||
t.Helper()
|
||||
|
||||
data := &Data{
|
||||
Diagnostics: make(Diagnostics),
|
||||
CompletionItems: make(CompletionItems),
|
||||
Completions: make(Completions),
|
||||
CompletionSnippets: make(CompletionSnippets),
|
||||
UnimportedCompletions: make(UnimportedCompletions),
|
||||
DeepCompletions: make(DeepCompletions),
|
||||
FuzzyCompletions: make(FuzzyCompletions),
|
||||
RankCompletions: make(RankCompletions),
|
||||
Definitions: make(Definitions),
|
||||
Highlights: make(Highlights),
|
||||
References: make(References),
|
||||
Renames: make(Renames),
|
||||
PrepareRenames: make(PrepareRenames),
|
||||
Symbols: make(Symbols),
|
||||
symbolsChildren: make(SymbolsChildren),
|
||||
Signatures: make(Signatures),
|
||||
Links: make(Links),
|
||||
Diagnostics: make(Diagnostics),
|
||||
CompletionItems: make(CompletionItems),
|
||||
Completions: make(Completions),
|
||||
CompletionSnippets: make(CompletionSnippets),
|
||||
UnimportedCompletions: make(UnimportedCompletions),
|
||||
DeepCompletions: make(DeepCompletions),
|
||||
FuzzyCompletions: make(FuzzyCompletions),
|
||||
RankCompletions: make(RankCompletions),
|
||||
CaseSensitiveCompletions: make(CaseSensitiveCompletions),
|
||||
Definitions: make(Definitions),
|
||||
Highlights: make(Highlights),
|
||||
References: make(References),
|
||||
Renames: make(Renames),
|
||||
PrepareRenames: make(PrepareRenames),
|
||||
Symbols: make(Symbols),
|
||||
symbolsChildren: make(SymbolsChildren),
|
||||
Signatures: make(Signatures),
|
||||
Links: make(Links),
|
||||
|
||||
t: t,
|
||||
dir: dir,
|
||||
@ -295,28 +303,29 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||
|
||||
// Collect any data that needs to be used by subsequent tests.
|
||||
if err := data.Exported.Expect(map[string]interface{}{
|
||||
"diag": data.collectDiagnostics,
|
||||
"item": data.collectCompletionItems,
|
||||
"complete": data.collectCompletions(CompletionDefault),
|
||||
"unimported": data.collectCompletions(CompletionUnimported),
|
||||
"deep": data.collectCompletions(CompletionDeep),
|
||||
"fuzzy": data.collectCompletions(CompletionFuzzy),
|
||||
"rank": data.collectCompletions(CompletionRank),
|
||||
"snippet": data.collectCompletionSnippets,
|
||||
"fold": data.collectFoldingRanges,
|
||||
"format": data.collectFormats,
|
||||
"import": data.collectImports,
|
||||
"godef": data.collectDefinitions,
|
||||
"typdef": data.collectTypeDefinitions,
|
||||
"hover": data.collectHoverDefinitions,
|
||||
"highlight": data.collectHighlights,
|
||||
"refs": data.collectReferences,
|
||||
"rename": data.collectRenames,
|
||||
"prepare": data.collectPrepareRenames,
|
||||
"symbol": data.collectSymbols,
|
||||
"signature": data.collectSignatures,
|
||||
"link": data.collectLinks,
|
||||
"suggestedfix": data.collectSuggestedFixes,
|
||||
"diag": data.collectDiagnostics,
|
||||
"item": data.collectCompletionItems,
|
||||
"complete": data.collectCompletions(CompletionDefault),
|
||||
"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,
|
||||
"format": data.collectFormats,
|
||||
"import": data.collectImports,
|
||||
"godef": data.collectDefinitions,
|
||||
"typdef": data.collectTypeDefinitions,
|
||||
"hover": data.collectHoverDefinitions,
|
||||
"highlight": data.collectHighlights,
|
||||
"refs": data.collectReferences,
|
||||
"rename": data.collectRenames,
|
||||
"prepare": data.collectPrepareRenames,
|
||||
"symbol": data.collectSymbols,
|
||||
"signature": data.collectSignatures,
|
||||
"link": data.collectLinks,
|
||||
"suggestedfix": data.collectSuggestedFixes,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -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