1
0
mirror of https://github.com/golang/go synced 2024-11-18 09:04:49 -07:00

internal/lsp: add config option for SymbolMatch

In preparation for later changes to the workspace Symbol method, we add
a separate configuration option keyed by "symbolMatcher" that specifies
the type of matcher to use for workspace symbol requests. We also define
a new type SymbolMatcher, the type of this new option. We require
SymbolMatcher to be a separate type from Matcher because a later CL adds
a type of symbol matcher that does not make sense in the context of
other uses of Matcher, e.g. completion.

Change-Id: Icde7d270b9efb64444f35675a8d0b48ad3b8b3dd
Reviewed-on: https://go-review.googlesource.com/c/tools/+/228122
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Paul Jolly 2020-04-08 22:56:24 +01:00 committed by Paul Jolly
parent 8b0f8a7919
commit ca5866bcf9
9 changed files with 79 additions and 25 deletions

View File

@ -139,3 +139,23 @@ Default: `true`.
### **staticcheck** *boolean* ### **staticcheck** *boolean*
If true, it enables the use of the staticcheck.io analyzers. If true, it enables the use of the staticcheck.io analyzers.
### **matcher** *string*
Defines the algorithm that is used when calculating completion candidates. Must be one of:
* `"fuzzy"`
* `"caseSensitive"`
* `"caseInsensitive"`
Default: `"caseInsensitive"`.
### **symbolMatcher** *string*
Defines the algorithm that is used when calculating workspace symbol results. Must be one of:
* `"fuzzy"`
* `"caseSensitive"`
* `"caseInsensitive"`
Default: `"caseInsensitive"`.

View File

@ -241,10 +241,10 @@ func (app *Application) connectRemote(ctx context.Context, remote string) (*conn
return connection, connection.initialize(ctx, app.options) return connection, connection.initialize(ctx, app.options)
} }
var matcherString = map[source.Matcher]string{ var matcherString = map[source.SymbolMatcher]string{
source.Fuzzy: "fuzzy", source.SymbolFuzzy: "fuzzy",
source.CaseSensitive: "caseSensitive", source.SymbolCaseSensitive: "caseSensitive",
source.CaseInsensitive: "default", source.SymbolCaseInsensitive: "default",
} }
func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error { func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error {
@ -262,7 +262,7 @@ func (c *connection) initialize(ctx context.Context, options func(*source.Option
} }
params.Capabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = opts.HierarchicalDocumentSymbolSupport params.Capabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = opts.HierarchicalDocumentSymbolSupport
params.InitializationOptions = map[string]interface{}{ params.InitializationOptions = map[string]interface{}{
"matcher": matcherString[opts.Matcher], "symbolMatcher": matcherString[opts.SymbolMatcher],
} }
if _, err := c.Server.Initialize(ctx, params); err != nil { if _, err := c.Server.Initialize(ctx, params); err != nil {
return err return err

View File

@ -47,11 +47,11 @@ func (r *workspaceSymbol) Run(ctx context.Context, args ...string) error {
} }
switch r.Matcher { switch r.Matcher {
case "fuzzy": case "fuzzy":
o.Matcher = source.Fuzzy o.SymbolMatcher = source.SymbolFuzzy
case "caseSensitive": case "caseSensitive":
o.Matcher = source.CaseSensitive o.SymbolMatcher = source.SymbolCaseSensitive
default: default:
o.Matcher = source.CaseInsensitive o.SymbolMatcher = source.SymbolCaseInsensitive
} }
} }

View File

@ -59,6 +59,10 @@ type EditorConfig struct {
// codeLens command. CodeLens which are not present in this map are left in // codeLens command. CodeLens which are not present in this map are left in
// their default state. // their default state.
CodeLens map[string]bool CodeLens map[string]bool
// SymbolMatcher is the config associated with the "symbolMatcher" gopls
// config option.
SymbolMatcher *string
} }
// NewEditor Creates a new Editor. // NewEditor Creates a new Editor.
@ -135,6 +139,10 @@ func (e *Editor) configuration() map[string]interface{} {
config["codelens"] = e.Config.CodeLens config["codelens"] = e.Config.CodeLens
} }
if e.Config.SymbolMatcher != nil {
config["symbolMatcher"] = *e.Config.SymbolMatcher
}
return config return config
} }

View File

@ -820,23 +820,23 @@ func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.
} }
func (r *runner) WorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) { func (r *runner) WorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
r.callWorkspaceSymbols(t, query, source.CaseInsensitive, dirs, expectedSymbols) r.callWorkspaceSymbols(t, query, source.SymbolCaseInsensitive, dirs, expectedSymbols)
} }
func (r *runner) FuzzyWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) { func (r *runner) FuzzyWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
r.callWorkspaceSymbols(t, query, source.Fuzzy, dirs, expectedSymbols) r.callWorkspaceSymbols(t, query, source.SymbolFuzzy, dirs, expectedSymbols)
} }
func (r *runner) CaseSensitiveWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) { func (r *runner) CaseSensitiveWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
r.callWorkspaceSymbols(t, query, source.CaseSensitive, dirs, expectedSymbols) r.callWorkspaceSymbols(t, query, source.SymbolCaseSensitive, dirs, expectedSymbols)
} }
func (r *runner) callWorkspaceSymbols(t *testing.T, query string, matcher source.Matcher, dirs map[string]struct{}, expectedSymbols []protocol.SymbolInformation) { func (r *runner) callWorkspaceSymbols(t *testing.T, query string, matcher source.SymbolMatcher, dirs map[string]struct{}, expectedSymbols []protocol.SymbolInformation) {
t.Helper() t.Helper()
original := r.server.session.Options() original := r.server.session.Options()
modified := original modified := original
modified.Matcher = matcher modified.SymbolMatcher = matcher
r.server.session.SetOptions(modified) r.server.session.SetOptions(modified)
defer r.server.session.SetOptions(original) defer r.server.session.SetOptions(original)

View File

@ -98,6 +98,7 @@ func DefaultOptions() Options {
HoverKind: FullDocumentation, HoverKind: FullDocumentation,
LinkTarget: "pkg.go.dev", LinkTarget: "pkg.go.dev",
Matcher: Fuzzy, Matcher: Fuzzy,
SymbolMatcher: SymbolFuzzy,
DeepCompletion: true, DeepCompletion: true,
UnimportedCompletion: true, UnimportedCompletion: true,
CompletionDocumentation: true, CompletionDocumentation: true,
@ -193,6 +194,9 @@ type UserOptions struct {
// Matcher specifies the type of matcher to use for completion requests. // Matcher specifies the type of matcher to use for completion requests.
Matcher Matcher Matcher Matcher
// SymbolMatcher specifies the type of matcher to use for symbol requests.
SymbolMatcher SymbolMatcher
// DeepCompletion allows completion to perform nested searches through // DeepCompletion allows completion to perform nested searches through
// possible candidates. // possible candidates.
DeepCompletion bool DeepCompletion bool
@ -267,6 +271,14 @@ const (
CaseSensitive CaseSensitive
) )
type SymbolMatcher int
const (
SymbolFuzzy = SymbolMatcher(iota)
SymbolCaseInsensitive
SymbolCaseSensitive
)
type HoverKind int type HoverKind int
const ( const (
@ -399,6 +411,20 @@ func (o *Options) set(name string, value interface{}) OptionResult {
o.Matcher = CaseInsensitive o.Matcher = CaseInsensitive
} }
case "symbolMatcher":
matcher, ok := result.asString()
if !ok {
break
}
switch matcher {
case "fuzzy":
o.SymbolMatcher = SymbolFuzzy
case "caseSensitive":
o.SymbolMatcher = SymbolCaseSensitive
default:
o.SymbolMatcher = SymbolCaseInsensitive
}
case "hoverKind": case "hoverKind":
hoverKind, ok := result.asString() hoverKind, ok := result.asString()
if !ok { if !ok {

View File

@ -805,18 +805,18 @@ func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.
} }
func (r *runner) WorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) { func (r *runner) WorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
r.callWorkspaceSymbols(t, query, source.CaseInsensitive, dirs, expectedSymbols) r.callWorkspaceSymbols(t, query, source.SymbolCaseInsensitive, dirs, expectedSymbols)
} }
func (r *runner) FuzzyWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) { func (r *runner) FuzzyWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
r.callWorkspaceSymbols(t, query, source.Fuzzy, dirs, expectedSymbols) r.callWorkspaceSymbols(t, query, source.SymbolFuzzy, dirs, expectedSymbols)
} }
func (r *runner) CaseSensitiveWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) { func (r *runner) CaseSensitiveWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
r.callWorkspaceSymbols(t, query, source.CaseSensitive, dirs, expectedSymbols) r.callWorkspaceSymbols(t, query, source.SymbolCaseSensitive, dirs, expectedSymbols)
} }
func (r *runner) callWorkspaceSymbols(t *testing.T, query string, matcher source.Matcher, dirs map[string]struct{}, expectedSymbols []protocol.SymbolInformation) { func (r *runner) callWorkspaceSymbols(t *testing.T, query string, matcher source.SymbolMatcher, dirs map[string]struct{}, expectedSymbols []protocol.SymbolInformation) {
t.Helper() t.Helper()
got, err := source.WorkspaceSymbols(r.ctx, matcher, []source.View{r.view}, query) got, err := source.WorkspaceSymbols(r.ctx, matcher, []source.View{r.view}, query)
if err != nil { if err != nil {

View File

@ -19,7 +19,7 @@ import (
const maxSymbols = 100 const maxSymbols = 100
// WorkspaceSymbols matches symbols across views using the given query, // WorkspaceSymbols matches symbols across views using the given query,
// according to the matcher Matcher. // according to the SymbolMatcher matcher.
// //
// The workspace symbol method is defined in the spec as follows: // The workspace symbol method is defined in the spec as follows:
// //
@ -32,10 +32,10 @@ const maxSymbols = 100
// WorkspaceSymbols receives the views []View. // WorkspaceSymbols receives the views []View.
// //
// However, it then becomes unclear what it would mean to call WorkspaceSymbols // However, it then becomes unclear what it would mean to call WorkspaceSymbols
// with a different configured Matcher per View. Therefore we assume that // with a different configured SymbolMatcher per View. Therefore we assume that
// Session level configuration will define the Matcher to be used for the // Session level configuration will define the SymbolMatcher to be used for the
// WorkspaceSymbols method. // WorkspaceSymbols method.
func WorkspaceSymbols(ctx context.Context, matcherType Matcher, views []View, query string) ([]protocol.SymbolInformation, error) { func WorkspaceSymbols(ctx context.Context, matcherType SymbolMatcher, views []View, query string) ([]protocol.SymbolInformation, error) {
ctx, done := event.Start(ctx, "source.WorkspaceSymbols") ctx, done := event.Start(ctx, "source.WorkspaceSymbols")
defer done() defer done()
if query == "" { if query == "" {
@ -102,14 +102,14 @@ type symbolInformation struct {
type matcherFunc func(string) bool type matcherFunc func(string) bool
func makeMatcher(m Matcher, query string) matcherFunc { func makeMatcher(m SymbolMatcher, query string) matcherFunc {
switch m { switch m {
case Fuzzy: case SymbolFuzzy:
fm := fuzzy.NewMatcher(query) fm := fuzzy.NewMatcher(query)
return func(s string) bool { return func(s string) bool {
return fm.Score(s) > 0 return fm.Score(s) > 0
} }
case CaseSensitive: case SymbolCaseSensitive:
return func(s string) bool { return func(s string) bool {
return strings.Contains(s, query) return strings.Contains(s, query)
} }

View File

@ -17,6 +17,6 @@ func (s *Server) symbol(ctx context.Context, params *protocol.WorkspaceSymbolPar
defer done() defer done()
views := s.session.Views() views := s.session.Views()
matcher := s.session.Options().Matcher matcher := s.session.Options().SymbolMatcher
return source.WorkspaceSymbols(ctx, matcher, views, params.Query) return source.WorkspaceSymbols(ctx, matcher, views, params.Query)
} }