Skip to content

Commit

Permalink
Add workspace-wide symbol navigation (hashicorp#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko authored Mar 11, 2021
1 parent 74bd6b9 commit db5b7aa
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 1 deletion.
1 change: 1 addition & 0 deletions internal/langserver/handlers/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func initializeResponse(t *testing.T, commandPrefix string) string {
"documentSymbolProvider": true,
"codeLensProvider": {},
"documentLinkProvider": {},
"workspaceSymbolProvider": true,
"documentFormattingProvider": true,
"documentOnTypeFormattingProvider": {
"firstTriggerCharacter": ""
Expand Down
1 change: 1 addition & 0 deletions internal/langserver/handlers/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (lh *logHandler) Initialize(ctx context.Context, params lsp.InitializeParam
HoverProvider: true,
DocumentFormattingProvider: true,
DocumentSymbolProvider: true,
WorkspaceSymbolProvider: true,
},
}

Expand Down
12 changes: 12 additions & 0 deletions internal/langserver/handlers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,18 @@ func (svc *service) Assigner() (jrpc2.Assigner, error) {

return handle(ctx, req, lh.WorkspaceExecuteCommand)
},
"workspace/symbol": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := session.CheckInitializationIsConfirmed()
if err != nil {
return nil, err
}

ctx = lsctx.WithDocumentStorage(ctx, svc.fs)
ctx = lsctx.WithClientCapabilities(ctx, cc)
ctx = lsctx.WithModuleFinder(ctx, svc.modMgr)

return handle(ctx, req, lh.WorkspaceSymbol)
},
"shutdown": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := session.Shutdown(req)
if err != nil {
Expand Down
42 changes: 42 additions & 0 deletions internal/langserver/handlers/workspace_symbol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package handlers

import (
"context"

lsctx "github.com/hashicorp/terraform-ls/internal/context"
"github.com/hashicorp/terraform-ls/internal/decoder"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
)

func (h *logHandler) WorkspaceSymbol(ctx context.Context, params lsp.WorkspaceSymbolParams) ([]lsp.SymbolInformation, error) {
var symbols []lsp.SymbolInformation

mm, err := lsctx.ModuleFinder(ctx)
if err != nil {
return symbols, err
}

cc, err := lsctx.ClientCapabilities(ctx)
if err != nil {
return nil, err
}

modules := mm.ListModules()
for _, mod := range modules {
d, err := decoder.DecoderForModule(ctx, mod)
if err != nil {
return symbols, err
}

modSymbols, err := d.Symbols(params.Query)
if err != nil {
continue
}

symbols = append(symbols, ilsp.SymbolInformation(mod.Path(), modSymbols,
cc.Workspace.WorkspaceClientCapabilities.Symbol)...)
}

return symbols, nil
}
148 changes: 148 additions & 0 deletions internal/langserver/handlers/workspace_symbol_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package handlers

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-ls/internal/langserver"
"github.com/hashicorp/terraform-ls/internal/terraform/exec"
"github.com/stretchr/testify/mock"
)

func TestLangServer_workspace_symbol_basic(t *testing.T) {
tmpDir := TempDir(t)
InitPluginCache(t, tmpDir.Dir())

ls := langserver.NewLangServerMock(t, NewMockSession(&MockSessionInput{
TerraformCalls: &exec.TerraformMockCalls{
PerWorkDir: map[string][]*mock.Call{
tmpDir.Dir(): validTfMockCalls(),
},
},
}))
stop := ls.Start(t)
defer stop()

ls.Call(t, &langserver.CallRequest{
Method: "initialize",
ReqParams: fmt.Sprintf(`{
"capabilities": {
"workspace": {
"symbol": {
"symbolKind": {
"valueSet": [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26
]
},
"tagSupport": {
"valueSet": [ 1 ]
}
}
}
},
"rootUri": %q,
"processId": 12345
}`, tmpDir.URI())})
ls.Notify(t, &langserver.CallRequest{
Method: "initialized",
ReqParams: "{}",
})
ls.Call(t, &langserver.CallRequest{
Method: "textDocument/didOpen",
ReqParams: fmt.Sprintf(`{
"textDocument": {
"version": 0,
"languageId": "terraform",
"text": "provider \"github\" {}",
"uri": "%s/first.tf"
}
}`, tmpDir.URI())})
ls.Call(t, &langserver.CallRequest{
Method: "textDocument/didOpen",
ReqParams: fmt.Sprintf(`{
"textDocument": {
"version": 0,
"languageId": "terraform",
"text": "provider \"google\" {}",
"uri": "%s/second.tf"
}
}`, tmpDir.URI())})
ls.Call(t, &langserver.CallRequest{
Method: "textDocument/didOpen",
ReqParams: fmt.Sprintf(`{
"textDocument": {
"version": 0,
"languageId": "terraform",
"text": "myblock \"custom\" {}",
"uri": "%s/blah/third.tf"
}
}`, tmpDir.URI())})

ls.CallAndExpectResponse(t, &langserver.CallRequest{
Method: "workspace/symbol",
ReqParams: `{
"query": ""
}`}, fmt.Sprintf(`{
"jsonrpc": "2.0",
"id": 5,
"result": [
{
"name": "provider \"github\"",
"kind": 5,
"location": {
"uri": "%s/first.tf",
"range": {
"start": {"line": 0, "character": 0},
"end": {"line": 0, "character": 20}
}
}
},
{
"name": "provider \"google\"",
"kind": 5,
"location": {
"uri": "%s/second.tf",
"range": {
"start": {"line": 0, "character": 0},
"end": {"line": 0, "character": 20}
}
}
},
{
"name": "myblock \"custom\"",
"kind": 5,
"location": {
"uri": "%s/blah/third.tf",
"range": {
"start": {"line": 0, "character": 0},
"end": {"line": 0, "character": 19}
}
}
}
]
}`, tmpDir.URI(), tmpDir.URI(), tmpDir.URI()))

ls.CallAndExpectResponse(t, &langserver.CallRequest{
Method: "workspace/symbol",
ReqParams: `{
"query": "myb"
}`}, fmt.Sprintf(`{
"jsonrpc": "2.0",
"id": 6,
"result": [
{
"name": "myblock \"custom\"",
"kind": 5,
"location": {
"uri": "%s/blah/third.tf",
"range": {
"start": {"line": 0, "character": 0},
"end": {"line": 0, "character": 19}
}
}
}
]
}`, tmpDir.URI()))
}
25 changes: 25 additions & 0 deletions internal/lsp/symbols.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
package lsp

import (
"path/filepath"

"github.com/hashicorp/hcl-lang/decoder"
"github.com/hashicorp/hcl-lang/lang"
lsp "github.com/hashicorp/terraform-ls/internal/protocol"
"github.com/hashicorp/terraform-ls/internal/uri"
"github.com/zclconf/go-cty/cty"
)

func SymbolInformation(dirPath string, sbs []decoder.Symbol, caps lsp.WorkspaceSymbolClientCapabilities) []lsp.SymbolInformation {
symbols := make([]lsp.SymbolInformation, len(sbs))
for i, s := range sbs {
kind, ok := symbolKind(s, caps.SymbolKind.ValueSet)
if !ok {
// skip symbol not supported by client
continue
}

path := filepath.Join(dirPath, s.Range().Filename)
symbols[i] = lsp.SymbolInformation{
Name: s.Name(),
Kind: kind,
Location: lsp.Location{
Range: HCLRangeToLSP(s.Range()),
URI: lsp.DocumentURI(uri.FromPath(path)),
},
}
}
return symbols
}

func DocumentSymbols(sbs []decoder.Symbol, caps lsp.DocumentSymbolClientCapabilities) []lsp.DocumentSymbol {
symbols := make([]lsp.DocumentSymbol, 0)

Expand Down
2 changes: 1 addition & 1 deletion internal/terraform/module/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type ModuleFinder interface {
ModuleByPath(path string) (Module, error)
SchemaForModule(path string) (*schema.BodySchema, error)
SchemaSourcesForModule(path string) ([]SchemaSource, error)
ListModules() []Module
}

type ModuleLoader func(dir string) (Module, error)
Expand All @@ -41,7 +42,6 @@ type ModuleManager interface {
AddModule(modPath string) (Module, error)
EnqueueModuleOp(modPath string, opType OpType) error
EnqueueModuleOpWait(modPath string, opType OpType) error
ListModules() []Module
CancelLoading()
}

Expand Down

0 comments on commit db5b7aa

Please sign in to comment.