From ffe57b0b752cc19bb51818e23eb5986a6838e253 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Sat, 13 Feb 2021 17:34:03 +0000 Subject: [PATCH] Add support for expressions --- go.mod | 4 +- go.sum | 21 +++--- internal/langserver/handlers/symbols_test.go | 44 ++++++++++-- internal/lsp/completion.go | 12 ++++ internal/lsp/symbols.go | 70 ++++++++++++++------ internal/lsp/token_encoder.go | 11 +++ internal/lsp/token_types.go | 3 + 7 files changed, 128 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index 52d79a5ac..f44628353 100644 --- a/go.mod +++ b/go.mod @@ -10,11 +10,11 @@ require ( github.com/google/uuid v1.2.0 github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-version v1.2.1 - github.com/hashicorp/hcl-lang v0.0.0-20210213170001-bd00c3f68680 + github.com/hashicorp/hcl-lang v0.0.0-20210311072604-8aac80474e33 github.com/hashicorp/hcl/v2 v2.9.1 github.com/hashicorp/terraform-exec v0.13.0 github.com/hashicorp/terraform-json v0.8.0 - github.com/hashicorp/terraform-schema v0.0.0-20210213170531-2b07abee4703 + github.com/hashicorp/terraform-schema v0.0.0-20210305084513-90ae10ade649 github.com/mh-cbon/go-fmt-fail v0.0.0-20160815164508-67765b3fbcb5 github.com/mitchellh/cli v1.1.2 github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index fc07a43aa..fc854c635 100644 --- a/go.sum +++ b/go.sum @@ -42,7 +42,6 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYU github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -184,10 +183,11 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl-lang v0.0.0-20210213170001-bd00c3f68680 h1:QjPFluG2uGJCBKIp5sEFx+UZ98QnuxmVsnLIuHz8a2Y= -github.com/hashicorp/hcl-lang v0.0.0-20210213170001-bd00c3f68680/go.mod h1:TZ5tpvmgJSHfmIndN4WP9SpZvyWK8tHPBY8LDRyU+pI= +github.com/hashicorp/hcl-lang v0.0.0-20210305083102-791d1fc99bad/go.mod h1:Ga5F2eYh9HyR2eHBYBa49VdoTkkC/7ob1cV8Mpvhg5M= +github.com/hashicorp/hcl-lang v0.0.0-20210311072604-8aac80474e33 h1:N84negx8N3nt1IaIGCvraxfL8h+W378fByCfbGjqwiQ= +github.com/hashicorp/hcl-lang v0.0.0-20210311072604-8aac80474e33/go.mod h1:TUGbLnxaJsOmfcJ+hwWTQxLmZX2lZSd+uMFNNphz6hc= github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= -github.com/hashicorp/hcl/v2 v2.6.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= +github.com/hashicorp/hcl/v2 v2.9.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= github.com/hashicorp/hcl/v2 v2.9.1 h1:eOy4gREY0/ZQHNItlfuEZqtcQbXIxzojlP301hDpnac= github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -198,11 +198,10 @@ github.com/hashicorp/terraform-config-inspect v0.0.0-20201102131242-0c45ba392e51 github.com/hashicorp/terraform-config-inspect v0.0.0-20201102131242-0c45ba392e51/go.mod h1:Z0Nnk4+3Cy89smEbrq+sl1bxc9198gIP4I7wcQF6Kqs= github.com/hashicorp/terraform-exec v0.13.0 h1:1Pth+pdWJAufJuWWjaVOVNEkoRTOjGn3hQpAqj4aPdg= github.com/hashicorp/terraform-exec v0.13.0/go.mod h1:SGhto91bVRlgXQWcJ5znSz+29UZIa8kpBbkGwQ+g9E8= -github.com/hashicorp/terraform-json v0.7.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= github.com/hashicorp/terraform-json v0.8.0 h1:XObQ3PgqU52YLQKEaJ08QtUshAfN3yu4u8ebSW0vztc= github.com/hashicorp/terraform-json v0.8.0/go.mod h1:3defM4kkMfttwiE7VakJDwCd4R+umhSQnvJwORXbprE= -github.com/hashicorp/terraform-schema v0.0.0-20210213170531-2b07abee4703 h1:u1otHGsvYAQcQ3aJl+TJjkFRdxJ1I8n7O9uGOlFw6oE= -github.com/hashicorp/terraform-schema v0.0.0-20210213170531-2b07abee4703/go.mod h1:6UFjY3ZeFEExipVkJOLzMJzBBosso6MoAyLRHgDIllw= +github.com/hashicorp/terraform-schema v0.0.0-20210305084513-90ae10ade649 h1:CUn3/SzgU2zCthL6L7e7I4Uo0b5i1GHWe0ivkVVePkE= +github.com/hashicorp/terraform-schema v0.0.0-20210305084513-90ae10ade649/go.mod h1:2cCwkhd2pXBgXtHEomGeQbRE7XbPm8kyV6IXwegt0n0= github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= @@ -257,8 +256,9 @@ github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceT github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.1.1 h1:Bp6x9R1Wn16SIz3OfeDr0b7RnCG2OB66Y7PQyC/cvq4= +github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -273,8 +273,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -367,8 +368,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.6.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= -github.com/zclconf/go-cty v1.7.1-0.20201110003513-1338293a79a9/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA= github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= diff --git a/internal/langserver/handlers/symbols_test.go b/internal/langserver/handlers/symbols_test.go index cb89023c1..32c00f913 100644 --- a/internal/langserver/handlers/symbols_test.go +++ b/internal/langserver/handlers/symbols_test.go @@ -26,9 +26,26 @@ func TestLangServer_symbols_basic(t *testing.T) { ls.Call(t, &langserver.CallRequest{ Method: "initialize", ReqParams: fmt.Sprintf(`{ - "capabilities": {}, - "rootUri": %q, - "processId": 12345 + "capabilities": { + "textDocument": { + "documentSymbol": { + "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 + ] + }, + "hierarchicalDocumentSymbolSupport": true, + "tagSupport": { + "valueSet": [ 1 ] + }, + "labelSupport": true + } + } + }, + "rootUri": %q, + "processId": 12345 }`, tmpDir.URI())}) ls.Notify(t, &langserver.CallRequest{ Method: "initialized", @@ -45,11 +62,28 @@ func TestLangServer_symbols_basic(t *testing.T) { } }`, tmpDir.URI())}) - ls.Call(t, &langserver.CallRequest{ + ls.CallAndExpectResponse(t, &langserver.CallRequest{ Method: "textDocument/documentSymbol", ReqParams: fmt.Sprintf(`{ "textDocument": { "uri": "%s/main.tf" } - }`, tmpDir.URI())}) + }`, tmpDir.URI())}, `{ + "jsonrpc": "2.0", + "id": 3, + "result": [ + { + "name": "provider \"github\"", + "kind": 5, + "range": { + "start": {"line": 0, "character": 0}, + "end": {"line": 0, "character": 20} + }, + "selectionRange": { + "start": {"line": 0, "character": 0}, + "end": {"line": 0, "character": 20} + } + } + ] + }`) } diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go index 8ea37acd2..89422e08f 100644 --- a/internal/lsp/completion.go +++ b/internal/lsp/completion.go @@ -36,6 +36,18 @@ func toCompletionItem(candidate lang.Candidate, caps lsp.CompletionClientCapabil kind = lsp.ClassCompletion case lang.LabelCandidateKind: kind = lsp.FieldCompletion + case lang.BoolCandidateKind: + kind = lsp.EnumMemberCompletion + case lang.StringCandidateKind: + kind = lsp.TextCompletion + case lang.NumberCandidateKind: + kind = lsp.ValueCompletion + case lang.KeywordCandidateKind: + kind = lsp.KeywordCompletion + case lang.ListCandidateKind, lang.SetCandidateKind, lang.TupleCandidateKind: + kind = lsp.EnumCompletion + case lang.MapCandidateKind, lang.ObjectCandidateKind: + kind = lsp.StructCompletion } // TODO: Omit item which uses kind unsupported by the client diff --git a/internal/lsp/symbols.go b/internal/lsp/symbols.go index 555c465e4..acfa9441b 100644 --- a/internal/lsp/symbols.go +++ b/internal/lsp/symbols.go @@ -2,41 +2,69 @@ package lsp import ( "github.com/hashicorp/hcl-lang/decoder" + "github.com/hashicorp/hcl-lang/lang" lsp "github.com/hashicorp/terraform-ls/internal/protocol" "github.com/zclconf/go-cty/cty" ) func DocumentSymbols(sbs []decoder.Symbol, caps lsp.DocumentSymbolClientCapabilities) []lsp.DocumentSymbol { - symbols := make([]lsp.DocumentSymbol, len(sbs)) + symbols := make([]lsp.DocumentSymbol, 0) - for i, s := range sbs { - kind, ok := symbolKind(s, caps.SymbolKind.ValueSet) + for _, s := range sbs { + symbol, ok := documentSymbol(s, caps) if !ok { // skip symbol not supported by client continue } + symbols = append(symbols, symbol) + } + return symbols +} - symbols[i] = lsp.DocumentSymbol{ - Name: s.Name(), - Kind: kind, - Range: HCLRangeToLSP(s.Range()), - SelectionRange: HCLRangeToLSP(s.Range()), - } +func documentSymbol(symbol decoder.Symbol, caps lsp.DocumentSymbolClientCapabilities) (lsp.DocumentSymbol, bool) { + kind, ok := symbolKind(symbol, caps.SymbolKind.ValueSet) + if !ok { + return lsp.DocumentSymbol{}, false + } - if caps.HierarchicalDocumentSymbolSupport { - symbols[i].Children = DocumentSymbols(s.NestedSymbols(), caps) - } + ds := lsp.DocumentSymbol{ + Name: symbol.Name(), + Kind: kind, + Range: HCLRangeToLSP(symbol.Range()), + SelectionRange: HCLRangeToLSP(symbol.Range()), } - return symbols + if caps.HierarchicalDocumentSymbolSupport { + ds.Children = DocumentSymbols(symbol.NestedSymbols(), caps) + } + return ds, true } func symbolKind(symbol decoder.Symbol, supported []lsp.SymbolKind) (lsp.SymbolKind, bool) { switch s := symbol.(type) { case *decoder.BlockSymbol: - return supportedSymbolKind(supported, lsp.Class) + kind, ok := supportedSymbolKind(supported, lsp.Class) + if ok { + return kind, true + } case *decoder.AttributeSymbol: - // Only primitive types are supported at this point - switch s.Type { + kind, ok := exprSymbolKind(s.ExprKind, supported) + if ok { + return kind, true + } + case *decoder.ExprSymbol: + kind, ok := exprSymbolKind(s.ExprKind, supported) + if ok { + return kind, true + } + } + + return lsp.SymbolKind(0), false +} + +func exprSymbolKind(symbolKind lang.SymbolExprKind, supported []lsp.SymbolKind) (lsp.SymbolKind, bool) { + switch k := symbolKind.(type) { + case lang.LiteralTypeKind: + switch k.Type { case cty.Bool: return supportedSymbolKind(supported, lsp.Boolean) case cty.String: @@ -44,11 +72,15 @@ func symbolKind(symbol decoder.Symbol, supported []lsp.SymbolKind) (lsp.SymbolKi case cty.Number: return supportedSymbolKind(supported, lsp.Number) } - - return supportedSymbolKind(supported, lsp.Variable) + case lang.TraversalExprKind: + return supportedSymbolKind(supported, lsp.Constant) + case lang.TupleConsExprKind: + return supportedSymbolKind(supported, lsp.Array) + case lang.ObjectConsExprKind: + return supportedSymbolKind(supported, lsp.Struct) } - return lsp.SymbolKind(0), false + return supportedSymbolKind(supported, lsp.Variable) } func supportedSymbolKind(supported []lsp.SymbolKind, kind lsp.SymbolKind) (lsp.SymbolKind, bool) { diff --git a/internal/lsp/token_encoder.go b/internal/lsp/token_encoder.go index 02fd892d7..e8a4cb470 100644 --- a/internal/lsp/token_encoder.go +++ b/internal/lsp/token_encoder.go @@ -37,6 +37,17 @@ func (te *TokenEncoder) encodeTokenOfIndex(i int) []float64 { tokenType = TokenTypeString case lang.TokenAttrName: tokenType = TokenTypeProperty + case lang.TokenBool: + tokenType = TokenTypeKeyword + case lang.TokenNumber: + tokenType = TokenTypeNumber + case lang.TokenString: + tokenType = TokenTypeString + case lang.TokenObjectKey: + tokenType = TokenTypeParameter + case lang.TokenMapKey: + tokenType = TokenTypeParameter + default: return []float64{} } diff --git a/internal/lsp/token_types.go b/internal/lsp/token_types.go index 6897d5376..ca7d19cd1 100644 --- a/internal/lsp/token_types.go +++ b/internal/lsp/token_types.go @@ -105,6 +105,9 @@ var ( TokenTypeType, TokenTypeString, TokenTypeProperty, + TokenTypeKeyword, + TokenTypeNumber, + TokenTypeParameter, } serverTokenModifiers = TokenModifiers{ TokenModifierDeprecated,