From 0619c67ac6b2f503750058437ce0af08d17d1018 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Fri, 24 Apr 2020 10:11:57 -0400 Subject: Support returning non-hierarchical symbols If `hierarchicalDocumentSymbolSupport` is not true in the client capabilites then it does not support the `DocumentSymbol[]` return type from the `textDocument/documentSymbol` request and we must fall back to `SymbolInformation[]`. This is one of the few requests that use the client capabilities to differentiate between return types and could cause problems for clients. See https://github.com/microsoft/language-server-protocol/pull/538#issuecomment-442510767 for more context. Found while looking at #144 --- crates/rust-analyzer/src/main_loop/handlers.rs | 37 +++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 41d9fe344..246085005 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -16,7 +16,7 @@ use lsp_types::{ Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, TextDocumentIdentifier, - TextEdit, WorkspaceEdit, + TextEdit, Url, WorkspaceEdit, }; use ra_ide::{ Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, @@ -219,6 +219,7 @@ pub fn handle_document_symbol( let _p = profile("handle_document_symbol"); let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id)?; + let url = file_id.try_conv_with(&world)?; let mut parents: Vec<(DocumentSymbol, Option)> = Vec::new(); @@ -234,10 +235,10 @@ pub fn handle_document_symbol( }; parents.push((doc_symbol, symbol.parent)); } - let mut res = Vec::new(); + let mut document_symbols = Vec::new(); while let Some((node, parent)) = parents.pop() { match parent { - None => res.push(node), + None => document_symbols.push(node), Some(i) => { let children = &mut parents[i].0.children; if children.is_none() { @@ -248,7 +249,35 @@ pub fn handle_document_symbol( } } - Ok(Some(res.into())) + if world.config.client_caps.hierarchical_symbols { + Ok(Some(document_symbols.into())) + } else { + let mut symbol_information = Vec::::new(); + for symbol in document_symbols { + flatten_document_symbol(&symbol, None, &url, &mut symbol_information); + } + + Ok(Some(symbol_information.into())) + } +} + +fn flatten_document_symbol( + symbol: &DocumentSymbol, + container_name: Option, + url: &Url, + res: &mut Vec, +) { + res.push(SymbolInformation { + name: symbol.name.clone(), + kind: symbol.kind, + deprecated: symbol.deprecated, + location: Location::new(url.clone(), symbol.range), + container_name: container_name, + }); + + for child in symbol.children.iter().flatten() { + flatten_document_symbol(child, Some(symbol.name.clone()), url, res); + } } pub fn handle_workspace_symbol( -- cgit v1.2.3