diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index f6cec6aa..42b83e05 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -295,6 +295,9 @@ impl Client { }), workspace_folders: Some(true), apply_edit: Some(true), + execute_command: Some(lsp::DynamicRegistrationClientCapabilities { + dynamic_registration: Some(false), + }), ..Default::default() }), text_document: Some(lsp::TextDocumentClientCapabilities { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 3ee75f6a..123e54eb 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -263,6 +263,7 @@ impl MappableCommand { file_picker, "Open file picker", file_picker_in_current_directory, "Open file picker at current working directory", code_action, "Perform code action", + workspace_command_picker, "Open workspace command picker", buffer_picker, "Open buffer picker", symbol_picker, "Open symbol picker", select_references_to_symbol_under_cursor, "Select symbol references", diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 1785a50c..34d1dcbc 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -497,6 +497,42 @@ pub fn code_action(cx: &mut Context) { }, ) } + +impl ui::menu::Item for lsp::Command { + type Data = (); + fn label(&self, _data: &Self::Data) -> Spans { + self.title.as_str().into() + } +} + +pub fn workspace_command_picker(cx: &mut Context) { + let (_, doc) = current!(cx.editor); + + let language_server = language_server!(cx.editor, doc); + + let execute_command_provider = match &language_server.capabilities().execute_command_provider { + Some(p) => p, + None => return, + }; + let commands = execute_command_provider + .commands + .iter() + .map(|command| lsp::Command { + title: command.clone(), + command: command.clone(), + arguments: None, + }) + .collect::>(); + cx.callback = Some(Box::new( + move |compositor: &mut Compositor, _cx: &mut compositor::Context| { + let picker = ui::Picker::new(commands, (), move |cx, command, _action| { + execute_lsp_command(cx.editor, command.clone()); + }); + compositor.push(Box::new(overlayed(picker))) + }, + )); +} + pub fn execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) { let doc = doc!(editor); let language_server = language_server!(editor, doc);