internal/lsp/symbols.go (103 lines of code) (raw):

package lsp import ( "path/filepath" lsp "github.com/Azure/azapi-lsp/internal/protocol" "github.com/Azure/azapi-lsp/internal/uri" "github.com/hashicorp/hcl-lang/decoder" "github.com/hashicorp/hcl-lang/lang" "github.com/zclconf/go-cty/cty" ) func WorkspaceSymbols(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(s.Path().Path, 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) for _, s := range sbs { symbol, ok := documentSymbol(s, caps) if !ok { // skip symbol not supported by client continue } symbols = append(symbols, symbol) } return symbols } func documentSymbol(symbol decoder.Symbol, caps lsp.DocumentSymbolClientCapabilities) (lsp.DocumentSymbol, bool) { kind, ok := symbolKind(symbol, caps.SymbolKind.ValueSet) if !ok { return lsp.DocumentSymbol{}, false } ds := lsp.DocumentSymbol{ Name: symbol.Name(), Kind: kind, Range: HCLRangeToLSP(symbol.Range()), SelectionRange: HCLRangeToLSP(symbol.Range()), } 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: kind, ok := supportedSymbolKind(supported, lsp.Class) if ok { return kind, true } case *decoder.AttributeSymbol: 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: return supportedSymbolKind(supported, lsp.String) case cty.Number: return supportedSymbolKind(supported, lsp.Number) } 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 supportedSymbolKind(supported, lsp.Variable) } func supportedSymbolKind(supported []lsp.SymbolKind, kind lsp.SymbolKind) (lsp.SymbolKind, bool) { for _, s := range supported { if s == kind { return s, true } } return lsp.SymbolKind(0), false }