Skip to content

Commit

Permalink
Re-request workspace symbols on keypress in picker
Browse files Browse the repository at this point in the history
Most language servers limit the number of workspace symbols that
are returned with an empty query even though all symbols are
supposed to be returned, according to the spec (for perfomance
reasons). This patch adds a workspace symbol picker based on a
dynamic picker that allows re-requesting the symbols on every
keypress (i.e. when the picker query text changes). The old behavior
has been completely replaced, and I have only tested with
rust-analyzer so far.
  • Loading branch information
sudormrfbin authored and archseer committed Dec 15, 2022
1 parent 914d294 commit d1f717e
Showing 1 changed file with 45 additions and 5 deletions.
50 changes: 45 additions & 5 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use futures_util::FutureExt;
use helix_lsp::{
block_on,
lsp::{self, CodeAction, CodeActionOrCommand, DiagnosticSeverity, NumberOrString},
Expand All @@ -14,7 +15,8 @@ use helix_view::{apply_transaction, document::Mode, editor::Action, theme::Style
use crate::{
compositor::{self, Compositor},
ui::{
self, lsp::SignatureHelp, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent,
self, lsp::SignatureHelp, overlay::overlayed, DynamicPicker, FileLocation, FilePicker,
Popup, PromptEvent,
},
};

Expand Down Expand Up @@ -384,10 +386,48 @@ pub fn workspace_symbol_picker(cx: &mut Context) {
cx.callback(
future,
move |_editor, compositor, response: Option<Vec<lsp::SymbolInformation>>| {
if let Some(symbols) = response {
let picker = sym_picker(symbols, current_url, offset_encoding);
compositor.push(Box::new(overlayed(picker)))
}
let symbols = match response {
Some(s) => s,
None => return,
};
let picker = sym_picker(symbols, current_url, offset_encoding);
let get_symbols = |query: String, editor: &mut Editor| {
let doc = doc!(editor);
let language_server = match doc.language_server() {
Some(s) => s,
None => {
// This should not generally happen since the picker will not
// even open in the first place if there is no server.
return async move { Err(anyhow::anyhow!("LSP not active")) }.boxed();
}
};
let symbol_request = match language_server.workspace_symbols(query) {
Some(future) => future,
None => {
// This should also not happen since the language server must have
// supported workspace symbols before to reach this block.
return async move {
Err(anyhow::anyhow!(
"Language server does not support workspace symbols"
))
}
.boxed();
}
};

let future = async move {
let json = symbol_request.await?;
let response: Option<Vec<lsp::SymbolInformation>> =
serde_json::from_value(json)?;

response.ok_or_else(|| {
anyhow::anyhow!("No response for workspace symbols from language server")
})
};
future.boxed()
};
let dyn_picker = DynamicPicker::new(picker, Box::new(get_symbols));
compositor.push(Box::new(overlayed(dyn_picker)))
},
)
}
Expand Down

0 comments on commit d1f717e

Please sign in to comment.