on master help sign in
Re-request workspace symbols on keypress in picker

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.

commitd1f717eb8d02205ce224292f157bfe1bddd1f6db authorGokul Soumya <gokulps15@gmail.com> dateTue 19 Jul 2022, 22:15 (4 years ago) parent914d294
1 file changed+45−5
helix-term/src/commands/lsp.rs+45−5
helix-term/src/commands/lsp.rs+45−5
@@ -1,3 +1,4 @@
1+use futures_util::FutureExt;
12use helix_lsp::{
23 block_on,
34 lsp::{self, CodeAction, CodeActionOrCommand, DiagnosticSeverity, NumberOrString},
@@ -14,7 +15,8 @@ use helix_view::{apply_transaction, document::Mode, editor::Action, theme::Style
1415use crate::{
1516 compositor::{self, Compositor},
1617 ui::{
17− self, lsp::SignatureHelp, overlay::overlayed, FileLocation, FilePicker, Popup, PromptEvent,
18+ self, lsp::SignatureHelp, overlay::overlayed, DynamicPicker, FileLocation, FilePicker,
19+ Popup, PromptEvent,
1820 },
1921};
2022
@@ -384,10 +386,48 @@ pub fn workspace_symbol_picker(cx: &mut Context) {
384386 cx.callback(
385387 future,
386388 move |_editor, compositor, response: Option<Vec<lsp::SymbolInformation>>| {
387− if let Some(symbols) = response {
388− let picker = sym_picker(symbols, current_url, offset_encoding);
389− compositor.push(Box::new(overlayed(picker)))
390− }
389+ let symbols = match response {
390+ Some(s) => s,
391+ None => return,
392+ };
393+ let picker = sym_picker(symbols, current_url, offset_encoding);
394+ let get_symbols = |query: String, editor: &mut Editor| {
395+ let doc = doc!(editor);
396+ let language_server = match doc.language_server() {
397+ Some(s) => s,
398+ None => {
399+ // This should not generally happen since the picker will not
400+ // even open in the first place if there is no server.
401+ return async move { Err(anyhow::anyhow!("LSP not active")) }.boxed();
402+ }
403+ };
404+ let symbol_request = match language_server.workspace_symbols(query) {
405+ Some(future) => future,
406+ None => {
407+ // This should also not happen since the language server must have
408+ // supported workspace symbols before to reach this block.
409+ return async move {
410+ Err(anyhow::anyhow!(
411+ "Language server does not support workspace symbols"
412+ ))
413+ }
414+ .boxed();
415+ }
416+ };
417+
418+ let future = async move {
419+ let json = symbol_request.await?;
420+ let response: Option<Vec<lsp::SymbolInformation>> =
421+ serde_json::from_value(json)?;
422+
423+ response.ok_or_else(|| {
424+ anyhow::anyhow!("No response for workspace symbols from language server")
425+ })
426+ };
427+ future.boxed()
428+ };
429+ let dyn_picker = DynamicPicker::new(picker, Box::new(get_symbols));
430+ compositor.push(Box::new(overlayed(dyn_picker)))
391431 },
392432 )
393433}