mirror of
https://github.com/ilyakooo0/helix.git
synced 2024-11-29 05:27:07 +03:00
Add LSP workspace command picker (#3140)
* Add workspace command picker * Make command typable * Add optional argument to lsp-workspace-command
This commit is contained in:
parent
3e84434c69
commit
dee5b2a983
@ -45,6 +45,7 @@
|
||||
| `:encoding` | Set encoding. Based on `https://encoding.spec.whatwg.org`. |
|
||||
| `:reload` | Discard changes and reload from the source file. |
|
||||
| `:update` | Write changes only if the file has been modified. |
|
||||
| `:lsp-workspace-command` | Open workspace command picker |
|
||||
| `:lsp-restart` | Restarts the Language Server that is in use by the current doc |
|
||||
| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
|
||||
| `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. |
|
||||
|
@ -298,6 +298,9 @@ impl Client {
|
||||
dynamic_registration: Some(false),
|
||||
..Default::default()
|
||||
}),
|
||||
execute_command: Some(lsp::DynamicRegistrationClientCapabilities {
|
||||
dynamic_registration: Some(false),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
text_document: Some(lsp::TextDocumentClientCapabilities {
|
||||
|
@ -603,6 +603,14 @@ 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 execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) {
|
||||
let doc = doc!(editor);
|
||||
let language_server = language_server!(editor, doc);
|
||||
|
@ -1052,6 +1052,77 @@ fn update(
|
||||
}
|
||||
}
|
||||
|
||||
fn lsp_workspace_command(
|
||||
cx: &mut compositor::Context,
|
||||
args: &[Cow<str>],
|
||||
event: PromptEvent,
|
||||
) -> anyhow::Result<()> {
|
||||
if event != PromptEvent::Validate {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (_, doc) = current!(cx.editor);
|
||||
|
||||
let language_server = match doc.language_server() {
|
||||
Some(language_server) => language_server,
|
||||
None => {
|
||||
cx.editor
|
||||
.set_status("Language server not active for current buffer");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let options = match &language_server.capabilities().execute_command_provider {
|
||||
Some(options) => options,
|
||||
None => {
|
||||
cx.editor
|
||||
.set_status("Workspace commands are not supported for this language server");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
if args.is_empty() {
|
||||
let commands = options
|
||||
.commands
|
||||
.iter()
|
||||
.map(|command| helix_lsp::lsp::Command {
|
||||
title: command.clone(),
|
||||
command: command.clone(),
|
||||
arguments: None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let callback = async move {
|
||||
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
||||
move |_editor: &mut Editor, compositor: &mut Compositor| {
|
||||
let picker = ui::Picker::new(commands, (), |cx, command, _action| {
|
||||
execute_lsp_command(cx.editor, command.clone());
|
||||
});
|
||||
compositor.push(Box::new(overlayed(picker)))
|
||||
},
|
||||
));
|
||||
Ok(call)
|
||||
};
|
||||
cx.jobs.callback(callback);
|
||||
} else {
|
||||
let command = args.join(" ");
|
||||
if options.commands.iter().any(|c| c == &command) {
|
||||
execute_lsp_command(
|
||||
cx.editor,
|
||||
helix_lsp::lsp::Command {
|
||||
title: command.clone(),
|
||||
arguments: None,
|
||||
command,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
cx.editor.set_status(format!(
|
||||
"`{command}` is not supported for this language server"
|
||||
));
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lsp_restart(
|
||||
cx: &mut compositor::Context,
|
||||
_args: &[Cow<str>],
|
||||
@ -1987,6 +2058,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
|
||||
fun: update,
|
||||
completer: None,
|
||||
},
|
||||
TypableCommand {
|
||||
name: "lsp-workspace-command",
|
||||
aliases: &[],
|
||||
doc: "Open workspace command picker",
|
||||
fun: lsp_workspace_command,
|
||||
completer: Some(completers::lsp_workspace_command),
|
||||
},
|
||||
TypableCommand {
|
||||
name: "lsp-restart",
|
||||
aliases: &[],
|
||||
|
@ -390,6 +390,45 @@ pub mod completers {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn lsp_workspace_command(editor: &Editor, input: &str) -> Vec<Completion> {
|
||||
let matcher = Matcher::default();
|
||||
|
||||
let (_, doc) = current_ref!(editor);
|
||||
|
||||
let language_server = match doc.language_server() {
|
||||
Some(language_server) => language_server,
|
||||
None => {
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
|
||||
let options = match &language_server.capabilities().execute_command_provider {
|
||||
Some(options) => options,
|
||||
None => {
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
|
||||
let mut matches: Vec<_> = options
|
||||
.commands
|
||||
.iter()
|
||||
.filter_map(|command| {
|
||||
matcher
|
||||
.fuzzy_match(command, input)
|
||||
.map(|score| (command, score))
|
||||
})
|
||||
.collect();
|
||||
|
||||
matches.sort_unstable_by(|(command1, score1), (command2, score2)| {
|
||||
(Reverse(*score1), command1).cmp(&(Reverse(*score2), command2))
|
||||
});
|
||||
|
||||
matches
|
||||
.into_iter()
|
||||
.map(|(command, _score)| ((0..), command.clone().into()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn directory(editor: &Editor, input: &str) -> Vec<Completion> {
|
||||
filename_impl(editor, input, |entry| {
|
||||
let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
|
||||
|
Loading…
Reference in New Issue
Block a user