diff --git a/src/crystalline/controller.cr b/src/crystalline/controller.cr index 6e0ee82..a408fd5 100644 --- a/src/crystalline/controller.cr +++ b/src/crystalline/controller.cr @@ -76,7 +76,15 @@ class Crystalline::Controller when LSP::DocumentSymbolsRequest @documents_lock.synchronize do file_uri = URI.parse message.params.text_document.uri - workspace.document_symbols(@server, file_uri) + document_symbols = workspace.document_symbols(@server, file_uri) + + if @server.client_capabilities.text_document.try &.document_symbol.try &.hierarchical_document_symbol_support + document_symbols + else + document_symbols.try &.reduce([] of LSP::SymbolInformation) { |acc, document_symbol| + acc.concat(document_symbol.to_symbol_information_array(message.params.text_document.uri)) + } + end end else nil diff --git a/src/crystalline/lsp/requests/language_features/document_symbols.cr b/src/crystalline/lsp/requests/language_features/document_symbols.cr index 74bff10..2caf4ac 100644 --- a/src/crystalline/lsp/requests/language_features/document_symbols.cr +++ b/src/crystalline/lsp/requests/language_features/document_symbols.cr @@ -55,6 +55,31 @@ module LSP # Children of this symbol, e.g. properties of a class. property children : Array(DocumentSymbol)? + + def to_symbol_information_array(uri : String) + results = [] of LSP::SymbolInformation + deque = Deque(Tuple(LSP::DocumentSymbol, LSP::DocumentSymbol?)){ {self, nil} } + + loop do + break if deque.size == 0 + symbol, parent = deque.shift + results << LSP::SymbolInformation.new( + name: symbol.name, + kind: symbol.kind, + deprecated: symbol.deprecated, + location: LSP::Location.new( + uri: uri, + range: symbol.range + ), + container_name: parent.try &.name + ) + symbol.children.try { |children| + deque.concat(children.map { |c| {c, self} }) + } + end + + results + end end # Represents information about programming constructs like variables, classes, @@ -67,7 +92,7 @@ module LSP property name : String # The kind of this symbol. - property kind : SymbolKind + property kind : LSP::SymbolKind # Indicates if this symbol is deprecated. property deprecated : Bool? diff --git a/src/crystalline/lsp/server.cr b/src/crystalline/lsp/server.cr index 9d26bad..1095e77 100644 --- a/src/crystalline/lsp/server.cr +++ b/src/crystalline/lsp/server.cr @@ -20,6 +20,8 @@ class LSP::Server getter output : IO # The broadcasted server capabilites. getter server_capabilities : LSP::ServerCapabilities + # The lsp client capabilites. + getter! client_capabilities : LSP::ClientCapabilities # A list of requests that were sent to clients to keep track of the ID and kind. getter requests_sent : Hash(RequestMessage::RequestId, LSP::Message) = {} of RequestMessage::RequestId => LSP::Message # Incremental. @@ -126,6 +128,7 @@ class LSP::Server loop do initialize_message = self.class.read(@input) if initialize_message.is_a? LSP::InitializeRequest + @client_capabilities = initialize_message.params.capabilities if controller.responds_to? :on_init init_result = controller.on_init(initialize_message.params) else