Skip to content

Commit d58d27d

Browse files
daisuzustamblerre
authored andcommitted
tools/gopls: add cmd support for workspace_symbol
This change adds command line support for workspace/symbol. Symbols are formatted as '{span} {name} {type}'. $ gopls workspace_symbol -matcher fuzzy 'wsymbols' $ $ workspacesymbol/a/a.go:5:7-31 WorkspaceSymbolConstantA Constant $ workspacesymbol/b/b.go:5:6-28 WorkspaceSymbolStructB Struct Optional arguments are: -matcher, which specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive. The default is caseInsensitive. Updates golang/go#32875 Change-Id: Ieef443b13710f9c973210e58f66ab7679f258b30 Reviewed-on: https://go-review.googlesource.com/c/tools/+/224677 Run-TryBot: Rebecca Stambler <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]>
1 parent b1df990 commit d58d27d

File tree

11 files changed

+192
-12
lines changed

11 files changed

+192
-12
lines changed

internal/lsp/cmd/cmd.go

+10
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ func (app *Application) featureCommands() []tool.Application {
184184
&signature{app: app},
185185
&suggestedfix{app: app},
186186
&symbols{app: app},
187+
&workspaceSymbol{app: app},
187188
}
188189
}
189190

@@ -239,6 +240,12 @@ func (app *Application) connectRemote(ctx context.Context, remote string) (*conn
239240
return connection, connection.initialize(ctx, app.options)
240241
}
241242

243+
var matcherString = map[source.Matcher]string{
244+
source.Fuzzy: "fuzzy",
245+
source.CaseSensitive: "caseSensitive",
246+
source.CaseInsensitive: "default",
247+
}
248+
242249
func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error {
243250
params := &protocol.ParamInitialize{}
244251
params.RootURI = protocol.URIFromPath(c.Client.app.wd)
@@ -253,6 +260,9 @@ func (c *connection) initialize(ctx context.Context, options func(*source.Option
253260
ContentFormat: []protocol.MarkupKind{opts.PreferredContentFormat},
254261
}
255262
params.Capabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = opts.HierarchicalDocumentSymbolSupport
263+
params.InitializationOptions = map[string]interface{}{
264+
"matcher": matcherString[opts.Matcher],
265+
}
256266

257267
if _, err := c.Server.Initialize(ctx, params); err != nil {
258268
return err

internal/lsp/cmd/test/cmdtest.go

-12
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,6 @@ func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completi
103103
//TODO: add command line completions tests when it works
104104
}
105105

106-
func (r *runner) WorkspaceSymbols(*testing.T, string, []protocol.SymbolInformation, map[string]struct{}) {
107-
//TODO: add command line workspace symbol tests when it works
108-
}
109-
110-
func (r *runner) FuzzyWorkspaceSymbols(*testing.T, string, []protocol.SymbolInformation, map[string]struct{}) {
111-
//TODO: add command line workspace symbol tests when it works
112-
}
113-
114-
func (r *runner) CaseSensitiveWorkspaceSymbols(*testing.T, string, []protocol.SymbolInformation, map[string]struct{}) {
115-
//TODO: add command line workspace symbol tests when it works
116-
}
117-
118106
func (r *runner) runGoplsCmd(t testing.TB, args ...string) (string, string) {
119107
rStdout, wStdout, err := os.Pipe()
120108
if err != nil {
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package cmdtest
6+
7+
import (
8+
"path"
9+
"sort"
10+
"strings"
11+
"testing"
12+
13+
"golang.org/x/tools/internal/lsp/protocol"
14+
)
15+
16+
func (r *runner) WorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
17+
r.runWorkspaceSymbols(t, "default", query, dirs)
18+
}
19+
20+
func (r *runner) FuzzyWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
21+
r.runWorkspaceSymbols(t, "fuzzy", query, dirs)
22+
}
23+
24+
func (r *runner) CaseSensitiveWorkspaceSymbols(t *testing.T, query string, expectedSymbols []protocol.SymbolInformation, dirs map[string]struct{}) {
25+
r.runWorkspaceSymbols(t, "caseSensitive", query, dirs)
26+
}
27+
28+
func (r *runner) runWorkspaceSymbols(t *testing.T, matcher, query string, dirs map[string]struct{}) {
29+
t.Helper()
30+
31+
out, _ := r.runGoplsCmd(t, "workspace_symbol", "-matcher", matcher, query)
32+
var filtered []string
33+
for _, line := range strings.Split(out, "\n") {
34+
for dir := range dirs {
35+
if strings.HasPrefix(line, dir) {
36+
filtered = append(filtered, line)
37+
break
38+
}
39+
}
40+
}
41+
sort.Strings(filtered)
42+
got := r.Normalize(strings.Join(filtered, "\n"))
43+
44+
expect := string(r.data.Golden("workspace_symbol", workspaceSymbolsGolden(matcher, query), func() ([]byte, error) {
45+
return []byte(got), nil
46+
}))
47+
48+
if expect != got {
49+
t.Errorf("workspace_symbol failed for %s expected:\n%s\ngot:\n%s", query, expect, got)
50+
}
51+
}
52+
53+
var workspaceSymbolsDir = map[string]string{
54+
"default": "",
55+
"fuzzy": "fuzzy",
56+
"caseSensitive": "casesensitive",
57+
}
58+
59+
func workspaceSymbolsGolden(matcher, query string) string {
60+
dir := []string{"workspacesymbol", workspaceSymbolsDir[matcher]}
61+
if query == "" {
62+
return path.Join(append(dir, "EmptyQuery")...)
63+
}
64+
65+
var name []rune
66+
for _, r := range query {
67+
if 'A' <= r && r <= 'Z' {
68+
// Escape uppercase to '!' + lowercase for case insensitive file systems.
69+
name = append(name, '!', r+'a'-'A')
70+
} else {
71+
name = append(name, r)
72+
}
73+
}
74+
return path.Join(append(dir, string(name))...)
75+
}

internal/lsp/cmd/workspace_symbol.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package cmd
6+
7+
import (
8+
"context"
9+
"flag"
10+
"fmt"
11+
12+
"golang.org/x/tools/internal/lsp/protocol"
13+
"golang.org/x/tools/internal/lsp/source"
14+
"golang.org/x/tools/internal/tool"
15+
)
16+
17+
// workspaceSymbol implements the workspace_symbol verb for gopls.
18+
type workspaceSymbol struct {
19+
Matcher string `flag:"matcher" help:"specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive.\nThe default is caseInsensitive."`
20+
21+
app *Application
22+
}
23+
24+
func (r *workspaceSymbol) Name() string { return "workspace_symbol" }
25+
func (r *workspaceSymbol) Usage() string { return "<query>" }
26+
func (r *workspaceSymbol) ShortHelp() string { return "search symbols in workspace" }
27+
func (r *workspaceSymbol) DetailedHelp(f *flag.FlagSet) {
28+
fmt.Fprint(f.Output(), `
29+
Example:
30+
31+
$ gopls workspace_symbol -matcher fuzzy 'wsymbols'
32+
33+
gopls workspace_symbol flags are:
34+
`)
35+
f.PrintDefaults()
36+
}
37+
38+
func (r *workspaceSymbol) Run(ctx context.Context, args ...string) error {
39+
if len(args) != 1 {
40+
return tool.CommandLineErrorf("workspace_symbol expects 1 argument")
41+
}
42+
43+
opts := r.app.options
44+
r.app.options = func(o *source.Options) {
45+
if opts != nil {
46+
opts(o)
47+
}
48+
switch r.Matcher {
49+
case "fuzzy":
50+
o.Matcher = source.Fuzzy
51+
case "caseSensitive":
52+
o.Matcher = source.CaseSensitive
53+
default:
54+
o.Matcher = source.CaseInsensitive
55+
}
56+
}
57+
58+
conn, err := r.app.connect(ctx)
59+
if err != nil {
60+
return err
61+
}
62+
defer conn.terminate(ctx)
63+
64+
p := protocol.WorkspaceSymbolParams{
65+
Query: args[0],
66+
}
67+
68+
symbols, err := conn.Symbol(ctx, &p)
69+
if err != nil {
70+
return err
71+
}
72+
for _, s := range symbols {
73+
f := conn.AddFile(ctx, fileURI(s.Location.URI))
74+
span, err := f.mapper.Span(s.Location)
75+
if err != nil {
76+
return err
77+
}
78+
fmt.Printf("%s %s %s\n", span, s.Name, s.Kind)
79+
}
80+
81+
return nil
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- workspace_symbol --
2+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- workspace_symbol --
2+
symbols/main.go:58:6-10 Dunk Function
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- workspace_symbol --
2+
symbols/main.go:60:6-10 dunk Function
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- workspace_symbol --
2+
workspacesymbol/a/a.go:3:5-29 WorkspaceSymbolVariableA Variable
3+
workspacesymbol/a/a.go:5:7-31 WorkspaceSymbolConstantA Constant
4+
workspacesymbol/a/a.go:8:2-27 workspacesymbolinvariable Constant
5+
workspacesymbol/b/b.go:3:5-29 WorkspaceSymbolVariableB Variable
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- workspace_symbol --
2+
workspacesymbol/a/a.go:3:5-29 WorkspaceSymbolVariableA Variable
3+
workspacesymbol/a/a.go:8:2-27 workspacesymbolinvariable Constant
4+
workspacesymbol/b/b.go:3:5-29 WorkspaceSymbolVariableB Variable
5+
workspacesymbol/b/b.go:5:6-28 WorkspaceSymbolStructB Struct
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- workspace_symbol --
2+
workspacesymbol/a/a.go:3:5-29 WorkspaceSymbolVariableA Variable
3+
workspacesymbol/a/a.go:5:7-31 WorkspaceSymbolConstantA Constant
4+
workspacesymbol/a/a.go:8:2-27 workspacesymbolinvariable Constant
5+
workspacesymbol/b/b.go:3:5-29 WorkspaceSymbolVariableB Variable
6+
workspacesymbol/b/b.go:5:6-28 WorkspaceSymbolStructB Struct
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- workspace_symbol --
2+
workspacesymbol/a/a.go:3:5-29 WorkspaceSymbolVariableA Variable
3+
workspacesymbol/b/b.go:3:5-29 WorkspaceSymbolVariableB Variable

0 commit comments

Comments
 (0)