mirror of
https://github.com/golang/go
synced 2024-11-18 14:54:40 -07:00
internal/lsp: merge completion options into source.Options
This change flattens the completion options type into UserOptions and DebuggingOptions, which will enable us to generate documentation for these options more effectively. This results in some modifications in the tests. Additionally, the fuzzyMatching and caseSensitive boolean flags are merged into one setting, matcher, which can be used to specify the type of matcher that is used for completion. Other requests (notably workspaceSymbols) may need to use a matcher in the future. Change-Id: I185875e50351be4090c7a2b3340d40286dc9f4a0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/212635 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
6316571e2c
commit
8f45075ebc
@ -24,7 +24,6 @@ func (s *Server) completion(ctx context.Context, params *protocol.CompletionPara
|
||||
return nil, err
|
||||
}
|
||||
snapshot := view.Snapshot()
|
||||
options := view.Options()
|
||||
fh, err := snapshot.GetFile(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -33,8 +32,7 @@ func (s *Server) completion(ctx context.Context, params *protocol.CompletionPara
|
||||
var surrounding *source.Selection
|
||||
switch fh.Identity().Kind {
|
||||
case source.Go:
|
||||
options.Completion.FullDocumentation = options.HoverKind == source.FullDocumentation
|
||||
candidates, surrounding, err = source.Completion(ctx, snapshot, fh, params.Position, options.Completion)
|
||||
candidates, surrounding, err = source.Completion(ctx, snapshot, fh, params.Position)
|
||||
case source.Mod:
|
||||
candidates, surrounding = nil, nil
|
||||
}
|
||||
@ -62,7 +60,8 @@ func (s *Server) completion(ctx context.Context, params *protocol.CompletionPara
|
||||
|
||||
// When using deep completions/fuzzy matching, report results as incomplete so
|
||||
// client fetches updated completions after every key stroke.
|
||||
incompleteResults := options.Completion.Deep || options.Completion.FuzzyMatching
|
||||
options := view.Options()
|
||||
incompleteResults := options.DeepCompletion || options.Matcher == source.Fuzzy
|
||||
|
||||
items := toProtocolCompletionItems(candidates, rng, options)
|
||||
|
||||
@ -94,7 +93,7 @@ func toProtocolCompletionItems(candidates []source.CompletionItem, rng protocol.
|
||||
// Limit the number of deep completions to not overwhelm the user in cases
|
||||
// with dozens of deep completion matches.
|
||||
if candidate.Depth > 0 {
|
||||
if !options.Completion.Deep {
|
||||
if !options.DeepCompletion {
|
||||
continue
|
||||
}
|
||||
if numDeepCompletionsSeen >= source.MaxDeepCompletions {
|
||||
|
@ -11,11 +11,10 @@ import (
|
||||
)
|
||||
|
||||
func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Deep: false,
|
||||
FuzzyMatching: false,
|
||||
Documentation: true,
|
||||
Literal: strings.Contains(string(src.URI()), "literal"),
|
||||
got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = false
|
||||
opts.Matcher = source.CaseInsensitive
|
||||
opts.Literal = strings.Contains(string(src.URI()), "literal")
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -27,11 +26,11 @@ func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion,
|
||||
}
|
||||
|
||||
func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
|
||||
list := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Placeholders: placeholders,
|
||||
Deep: true,
|
||||
FuzzyMatching: true,
|
||||
Literal: true,
|
||||
list := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.Placeholders = placeholders
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.Fuzzy
|
||||
opts.Literal = true
|
||||
})
|
||||
got := tests.FindItem(list, *items[expected.CompletionItem])
|
||||
want := expected.PlainSnippet
|
||||
@ -44,8 +43,8 @@ func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.C
|
||||
}
|
||||
|
||||
func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Unimported: true,
|
||||
got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.UnimportedCompletion = true
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -57,9 +56,9 @@ func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Co
|
||||
}
|
||||
|
||||
func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Deep: true,
|
||||
Documentation: true,
|
||||
got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.CaseInsensitive
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -71,9 +70,9 @@ func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completi
|
||||
}
|
||||
|
||||
func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
FuzzyMatching: true,
|
||||
Deep: true,
|
||||
got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.Fuzzy
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -85,8 +84,8 @@ func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Complet
|
||||
}
|
||||
|
||||
func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
CaseSensitive: true,
|
||||
got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.Matcher = source.CaseSensitive
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -98,10 +97,10 @@ func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests
|
||||
}
|
||||
|
||||
func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
|
||||
got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
FuzzyMatching: true,
|
||||
Deep: true,
|
||||
Literal: true,
|
||||
got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.Fuzzy
|
||||
opts.Literal = true
|
||||
})
|
||||
want := expected(t, test, items)
|
||||
if msg := tests.CheckCompletionOrder(want, got, true); msg != "" {
|
||||
@ -120,7 +119,7 @@ func expected(t *testing.T, test tests.Completion, items tests.CompletionItems)
|
||||
return want
|
||||
}
|
||||
|
||||
func (r *runner) callCompletion(t *testing.T, src span.Span, options source.CompletionOptions) []protocol.CompletionItem {
|
||||
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())
|
||||
@ -129,8 +128,7 @@ func (r *runner) callCompletion(t *testing.T, src span.Span, options source.Comp
|
||||
}
|
||||
original := view.Options()
|
||||
modified := original
|
||||
modified.InsertTextFormat = protocol.SnippetTextFormat
|
||||
modified.Completion = options
|
||||
options(&modified)
|
||||
view, err = view.SetOptions(r.ctx, modified)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -131,9 +131,8 @@ func (ipm insensitivePrefixMatcher) Score(candidateLabel string) float32 {
|
||||
type completer struct {
|
||||
snapshot Snapshot
|
||||
pkg Package
|
||||
|
||||
qf types.Qualifier
|
||||
opts CompletionOptions
|
||||
qf types.Qualifier
|
||||
opts *completionOptions
|
||||
|
||||
// ctx is the context associated with this completion request.
|
||||
ctx context.Context
|
||||
@ -247,10 +246,10 @@ func (p Selection) Suffix() string {
|
||||
}
|
||||
|
||||
func (c *completer) deepCompletionContext() (context.Context, context.CancelFunc) {
|
||||
if c.opts.Budget == 0 {
|
||||
if c.opts.budget == 0 {
|
||||
return context.WithCancel(c.ctx)
|
||||
}
|
||||
return context.WithDeadline(c.ctx, c.startTime.Add(c.opts.Budget))
|
||||
return context.WithDeadline(c.ctx, c.startTime.Add(c.opts.budget))
|
||||
}
|
||||
|
||||
func (c *completer) setSurrounding(ident *ast.Ident) {
|
||||
@ -268,11 +267,12 @@ func (c *completer) setSurrounding(ident *ast.Ident) {
|
||||
mappedRange: newMappedRange(c.snapshot.View().Session().Cache().FileSet(), c.mapper, ident.Pos(), ident.End()),
|
||||
}
|
||||
|
||||
if c.opts.FuzzyMatching {
|
||||
switch c.opts.matcher {
|
||||
case Fuzzy:
|
||||
c.matcher = fuzzy.NewMatcher(c.surrounding.Prefix())
|
||||
} else if c.opts.CaseSensitive {
|
||||
case CaseSensitive:
|
||||
c.matcher = prefixMatcher(c.surrounding.Prefix())
|
||||
} else {
|
||||
default:
|
||||
c.matcher = insensitivePrefixMatcher(strings.ToLower(c.surrounding.Prefix()))
|
||||
}
|
||||
}
|
||||
@ -405,7 +405,7 @@ func (e ErrIsDefinition) Error() string {
|
||||
// The selection is computed based on the preceding identifier and can be used by
|
||||
// the client to score the quality of the completion. For instance, some clients
|
||||
// may tolerate imperfect matches as valid completion results, since users may make typos.
|
||||
func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position, opts CompletionOptions) ([]CompletionItem, *Selection, error) {
|
||||
func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]CompletionItem, *Selection, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.Completion")
|
||||
defer done()
|
||||
|
||||
@ -439,6 +439,7 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos proto
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
opts := snapshot.View().Options()
|
||||
c := &completer{
|
||||
pkg: pkg,
|
||||
snapshot: snapshot,
|
||||
@ -451,7 +452,16 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos proto
|
||||
seen: make(map[types.Object]bool),
|
||||
enclosingFunc: enclosingFunction(path, rng.Start, pkg.GetTypesInfo()),
|
||||
enclosingCompositeLiteral: enclosingCompositeLiteral(path, rng.Start, pkg.GetTypesInfo()),
|
||||
opts: opts,
|
||||
opts: &completionOptions{
|
||||
matcher: opts.Matcher,
|
||||
deepCompletion: opts.DeepCompletion,
|
||||
unimported: opts.UnimportedCompletion,
|
||||
documentation: opts.CompletionDocumentation,
|
||||
fullDocumentation: opts.HoverKind == FullDocumentation,
|
||||
placeholders: opts.Placeholders,
|
||||
literal: opts.Literal,
|
||||
budget: opts.CompletionBudget,
|
||||
},
|
||||
// default to a matcher that always matches
|
||||
matcher: prefixMatcher(""),
|
||||
methodSetCache: make(map[methodSetKey]*types.MethodSet),
|
||||
@ -459,7 +469,7 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos proto
|
||||
startTime: startTime,
|
||||
}
|
||||
|
||||
if opts.Deep {
|
||||
if c.opts.deepCompletion {
|
||||
// Initialize max search depth to unlimited.
|
||||
c.deepState.maxDepth = -1
|
||||
}
|
||||
@ -629,7 +639,7 @@ func (c *completer) selector(sel *ast.SelectorExpr) error {
|
||||
}
|
||||
|
||||
// Try unimported packages.
|
||||
if id, ok := sel.X.(*ast.Ident); ok && c.opts.Unimported && len(c.items) < unimportedTarget {
|
||||
if id, ok := sel.X.(*ast.Ident); ok && c.opts.unimported && len(c.items) < unimportedTarget {
|
||||
if err := c.unimportedMembers(id); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -862,7 +872,7 @@ func (c *completer) lexical() error {
|
||||
}
|
||||
}
|
||||
|
||||
if c.opts.Unimported && len(c.items) < unimportedTarget {
|
||||
if c.opts.unimported && len(c.items) < unimportedTarget {
|
||||
ctx, cancel := c.deepCompletionContext()
|
||||
defer cancel()
|
||||
// Suggest packages that have not been imported yet.
|
||||
|
@ -168,7 +168,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
snippet: snip,
|
||||
}
|
||||
// If the user doesn't want documentation for completion items.
|
||||
if !c.opts.Documentation {
|
||||
if !c.opts.documentation {
|
||||
return item, nil
|
||||
}
|
||||
pos := c.snapshot.View().Session().Cache().FileSet().Position(obj.Pos())
|
||||
@ -200,7 +200,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
return item, nil
|
||||
}
|
||||
item.Documentation = hover.Synopsis
|
||||
if c.opts.FullDocumentation {
|
||||
if c.opts.fullDocumentation {
|
||||
item.Documentation = hover.FullDocumentation
|
||||
}
|
||||
return item, nil
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
// literal generates composite literal, function literal, and make()
|
||||
// completion items.
|
||||
func (c *completer) literal(literalType types.Type, imp *importInfo) {
|
||||
if !c.opts.Literal {
|
||||
if !c.opts.literal {
|
||||
return
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ func (c *completer) functionLiteral(sig *types.Signature, matchScore float64) {
|
||||
// Our parameter names are guesses, so they must be placeholders
|
||||
// for easy correction. If placeholders are disabled, don't
|
||||
// offer the completion.
|
||||
if !c.opts.Placeholders {
|
||||
if !c.opts.placeholders {
|
||||
return
|
||||
}
|
||||
|
||||
@ -367,7 +367,7 @@ func (c *completer) makeCall(typeName string, secondArg string, matchScore float
|
||||
if secondArg != "" {
|
||||
snip.WriteText(", ")
|
||||
snip.WritePlaceholder(func(b *snippet.Builder) {
|
||||
if c.opts.Placeholders {
|
||||
if c.opts.placeholders {
|
||||
b.WriteText(secondArg)
|
||||
}
|
||||
})
|
||||
|
@ -36,7 +36,7 @@ func (c *completer) structFieldSnippet(label, detail string) *snippet.Builder {
|
||||
snip.WriteText(label + ": ")
|
||||
snip.WritePlaceholder(func(b *snippet.Builder) {
|
||||
// A placeholder snippet turns "Foo{Ba<>" into "Foo{Bar: <*int*>".
|
||||
if c.opts.Placeholders {
|
||||
if c.opts.placeholders {
|
||||
b.WriteText(detail)
|
||||
}
|
||||
})
|
||||
@ -79,7 +79,7 @@ func (c *completer) functionCallSnippet(name string, params []string) *snippet.B
|
||||
snip := &snippet.Builder{}
|
||||
snip.WriteText(name + "(")
|
||||
|
||||
if c.opts.Placeholders {
|
||||
if c.opts.placeholders {
|
||||
// A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)".
|
||||
for i, p := range params {
|
||||
if i > 0 {
|
||||
|
@ -107,8 +107,8 @@ func (c *completer) shouldPrune() bool {
|
||||
}
|
||||
|
||||
// Check our remaining budget every 100 candidates.
|
||||
if c.opts.Budget > 0 && c.deepState.candidateCount%100 == 0 {
|
||||
spent := float64(time.Since(c.startTime)) / float64(c.opts.Budget)
|
||||
if c.opts.budget > 0 && c.deepState.candidateCount%100 == 0 {
|
||||
spent := float64(time.Since(c.startTime)) / float64(c.opts.budget)
|
||||
|
||||
switch {
|
||||
case spent >= 0.90:
|
||||
|
@ -74,16 +74,13 @@ var (
|
||||
},
|
||||
}
|
||||
DefaultUserOptions = UserOptions{
|
||||
Env: os.Environ(),
|
||||
HoverKind: SynopsisDocumentation,
|
||||
Completion: CompletionOptions{
|
||||
Documentation: true,
|
||||
Deep: true,
|
||||
FuzzyMatching: true,
|
||||
Literal: true,
|
||||
Budget: 100 * time.Millisecond,
|
||||
},
|
||||
LinkTarget: "pkg.go.dev",
|
||||
Env: os.Environ(),
|
||||
HoverKind: SynopsisDocumentation,
|
||||
LinkTarget: "pkg.go.dev",
|
||||
Matcher: Fuzzy,
|
||||
DeepCompletion: true,
|
||||
CompletionDocumentation: true,
|
||||
Literal: true,
|
||||
}
|
||||
DefaultHooks = Hooks{
|
||||
ComputeEdits: myers.ComputeEdits,
|
||||
@ -94,7 +91,9 @@ var (
|
||||
DefaultExperimentalOptions = ExperimentalOptions{
|
||||
TempModfile: false,
|
||||
}
|
||||
DefaultDebuggingOptions = DebuggingOptions{}
|
||||
DefaultDebuggingOptions = DebuggingOptions{
|
||||
CompletionBudget: 100 * time.Millisecond,
|
||||
}
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
@ -142,7 +141,37 @@ type UserOptions struct {
|
||||
// LocalPrefix is used to specify goimports's -local behavior.
|
||||
LocalPrefix string
|
||||
|
||||
Completion CompletionOptions
|
||||
// Matcher specifies the type of matcher to use for completion requests.
|
||||
Matcher Matcher
|
||||
|
||||
// DeepCompletion allows completion to perform nested searches through
|
||||
// possible candidates.
|
||||
DeepCompletion bool
|
||||
|
||||
// UnimportedCompletion enables completion for unimported packages.
|
||||
UnimportedCompletion bool
|
||||
|
||||
// CompletionDocumentation returns additional documentation with completion
|
||||
// requests.
|
||||
CompletionDocumentation bool
|
||||
|
||||
// Placeholders adds placeholders to parameters and structs in completion
|
||||
// results.
|
||||
Placeholders bool
|
||||
|
||||
// Literal enables completion for map, slice, and function literals.
|
||||
Literal bool
|
||||
}
|
||||
|
||||
type completionOptions struct {
|
||||
deepCompletion bool
|
||||
unimported bool
|
||||
documentation bool
|
||||
fullDocumentation bool
|
||||
placeholders bool
|
||||
literal bool
|
||||
matcher Matcher
|
||||
budget time.Duration
|
||||
}
|
||||
|
||||
type Hooks struct {
|
||||
@ -161,26 +190,23 @@ type ExperimentalOptions struct {
|
||||
|
||||
type DebuggingOptions struct {
|
||||
VerboseOutput bool
|
||||
}
|
||||
|
||||
type CompletionOptions struct {
|
||||
Deep bool
|
||||
FuzzyMatching bool
|
||||
CaseSensitive bool
|
||||
Unimported bool
|
||||
Documentation bool
|
||||
FullDocumentation bool
|
||||
Placeholders bool
|
||||
Literal bool
|
||||
|
||||
// Budget is the soft latency goal for completion requests. Most
|
||||
// CompletionBudget is the soft latency goal for completion requests. Most
|
||||
// requests finish in a couple milliseconds, but in some cases deep
|
||||
// completions can take much longer. As we use up our budget we
|
||||
// dynamically reduce the search scope to ensure we return timely
|
||||
// results. Zero means unlimited.
|
||||
Budget time.Duration
|
||||
CompletionBudget time.Duration
|
||||
}
|
||||
|
||||
type Matcher int
|
||||
|
||||
const (
|
||||
Fuzzy = Matcher(iota)
|
||||
CaseInsensitive
|
||||
CaseSensitive
|
||||
)
|
||||
|
||||
type HoverKind int
|
||||
|
||||
const (
|
||||
@ -280,17 +306,13 @@ func (o *Options) set(name string, value interface{}) OptionResult {
|
||||
o.BuildFlags = flags
|
||||
|
||||
case "completionDocumentation":
|
||||
result.setBool(&o.Completion.Documentation)
|
||||
result.setBool(&o.CompletionDocumentation)
|
||||
case "usePlaceholders":
|
||||
result.setBool(&o.Completion.Placeholders)
|
||||
result.setBool(&o.Placeholders)
|
||||
case "deepCompletion":
|
||||
result.setBool(&o.Completion.Deep)
|
||||
case "fuzzyMatching":
|
||||
result.setBool(&o.Completion.FuzzyMatching)
|
||||
case "caseSensitiveCompletion":
|
||||
result.setBool(&o.Completion.CaseSensitive)
|
||||
result.setBool(&o.DeepCompletion)
|
||||
case "completeUnimported":
|
||||
result.setBool(&o.Completion.Unimported)
|
||||
result.setBool(&o.UnimportedCompletion)
|
||||
case "completionBudget":
|
||||
if v, ok := result.asString(); ok {
|
||||
d, err := time.ParseDuration(v)
|
||||
@ -298,13 +320,26 @@ func (o *Options) set(name string, value interface{}) OptionResult {
|
||||
result.errorf("failed to parse duration %q: %v", v, err)
|
||||
break
|
||||
}
|
||||
o.Completion.Budget = d
|
||||
o.CompletionBudget = d
|
||||
}
|
||||
|
||||
case "matcher":
|
||||
matcher, ok := result.asString()
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
switch matcher {
|
||||
case "fuzzy":
|
||||
o.Matcher = Fuzzy
|
||||
case "caseSensitive":
|
||||
o.Matcher = CaseSensitive
|
||||
default:
|
||||
o.Matcher = CaseInsensitive
|
||||
}
|
||||
|
||||
case "hoverKind":
|
||||
hoverKind, ok := value.(string)
|
||||
hoverKind, ok := result.asString()
|
||||
if !ok {
|
||||
result.errorf("invalid type %T for string option %q", value, name)
|
||||
break
|
||||
}
|
||||
switch hoverKind {
|
||||
@ -378,6 +413,14 @@ func (o *Options) set(name string, value interface{}) OptionResult {
|
||||
result.State = OptionDeprecated
|
||||
result.Replacement = "completeUnimported"
|
||||
|
||||
case "fuzzyMatching":
|
||||
result.State = OptionDeprecated
|
||||
result.Replacement = "matcher"
|
||||
|
||||
case "caseSensitiveCompletion":
|
||||
result.State = OptionDeprecated
|
||||
result.Replacement = "matcher"
|
||||
|
||||
case "noIncrementalSync":
|
||||
result.State = OptionDeprecated
|
||||
|
||||
|
@ -107,10 +107,10 @@ func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion,
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
prefix, list := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Documentation: true,
|
||||
FuzzyMatching: true,
|
||||
Literal: strings.Contains(string(src.URI()), "literal"),
|
||||
prefix, list := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.Matcher = source.Fuzzy
|
||||
opts.Literal = strings.Contains(string(src.URI()), "literal")
|
||||
opts.DeepCompletion = false
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
list = tests.FilterBuiltins(list)
|
||||
@ -128,10 +128,10 @@ func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion,
|
||||
}
|
||||
|
||||
func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
|
||||
_, list := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Placeholders: placeholders,
|
||||
Deep: true,
|
||||
Literal: true,
|
||||
_, list := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.Placeholders = placeholders
|
||||
opts.DeepCompletion = true
|
||||
opts.Literal = true
|
||||
})
|
||||
got := tests.FindItem(list, *items[expected.CompletionItem])
|
||||
want := expected.PlainSnippet
|
||||
@ -148,8 +148,8 @@ func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Co
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
_, got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Unimported: true,
|
||||
_, got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.UnimportedCompletion = true
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -164,9 +164,9 @@ func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completi
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
prefix, list := r.callCompletion(t, src, source.CompletionOptions{
|
||||
Deep: true,
|
||||
Documentation: true,
|
||||
prefix, list := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.CaseInsensitive
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
list = tests.FilterBuiltins(list)
|
||||
@ -189,9 +189,9 @@ func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Complet
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
_, got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
FuzzyMatching: true,
|
||||
Deep: true,
|
||||
_, got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.Fuzzy
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
got = tests.FilterBuiltins(got)
|
||||
@ -206,8 +206,8 @@ func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
_, list := r.callCompletion(t, src, source.CompletionOptions{
|
||||
CaseSensitive: true,
|
||||
_, list := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.Matcher = source.CaseSensitive
|
||||
})
|
||||
if !strings.Contains(string(src.URI()), "builtins") {
|
||||
list = tests.FilterBuiltins(list)
|
||||
@ -222,25 +222,34 @@ func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completi
|
||||
for _, pos := range test.CompletionItems {
|
||||
want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
|
||||
}
|
||||
_, got := r.callCompletion(t, src, source.CompletionOptions{
|
||||
FuzzyMatching: true,
|
||||
Deep: true,
|
||||
Literal: true,
|
||||
_, got := r.callCompletion(t, src, func(opts *source.Options) {
|
||||
opts.DeepCompletion = true
|
||||
opts.Matcher = source.Fuzzy
|
||||
opts.Literal = true
|
||||
})
|
||||
if msg := tests.CheckCompletionOrder(want, got, true); msg != "" {
|
||||
t.Errorf("%s: %s", src, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) callCompletion(t *testing.T, src span.Span, options source.CompletionOptions) (string, []protocol.CompletionItem) {
|
||||
func (r *runner) callCompletion(t *testing.T, src span.Span, options func(*source.Options)) (string, []protocol.CompletionItem) {
|
||||
fh, err := r.view.Snapshot().GetFile(src.URI())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list, surrounding, err := source.Completion(r.ctx, r.view.Snapshot(), fh, protocol.Position{
|
||||
original := r.view.Options()
|
||||
modified := original
|
||||
options(&modified)
|
||||
view, err := r.view.SetOptions(r.ctx, modified)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer r.view.SetOptions(r.ctx, original)
|
||||
|
||||
list, surrounding, err := source.Completion(r.ctx, view.Snapshot(), fh, protocol.Position{
|
||||
Line: float64(src.Start().Line() - 1),
|
||||
Character: float64(src.Start().Column() - 1),
|
||||
}, options)
|
||||
})
|
||||
if err != nil && !errors.As(err, &source.ErrIsDefinition{}) {
|
||||
t.Fatalf("failed for %v: %v", src, err)
|
||||
}
|
||||
@ -261,7 +270,7 @@ func (r *runner) callCompletion(t *testing.T, src span.Span, options source.Comp
|
||||
// Apply deep completion filtering.
|
||||
for _, item := range list {
|
||||
if item.Depth > 0 {
|
||||
if !options.Deep {
|
||||
if !modified.DeepCompletion {
|
||||
continue
|
||||
}
|
||||
if numDeepCompletionsSeen >= source.MaxDeepCompletions {
|
||||
|
@ -191,7 +191,7 @@ func DefaultOptions() source.Options {
|
||||
}
|
||||
o.HoverKind = source.SynopsisDocumentation
|
||||
o.InsertTextFormat = protocol.SnippetTextFormat
|
||||
o.Completion.Budget = time.Minute
|
||||
o.CompletionBudget = time.Minute
|
||||
return o
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user