Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow multiple language server with lsp-workspace-command #10176

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 60 additions & 35 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1367,37 +1367,51 @@ fn lsp_workspace_command(
if event != PromptEvent::Validate {
return Ok(());
}

struct LsIdCommand(usize, helix_lsp::lsp::Command);

impl ui::menu::Item for LsIdCommand {
type Data = ();

fn format(&self, _data: &Self::Data) -> Row {
self.1.title.as_str().into()
}
}

let doc = doc!(cx.editor);
let Some((language_server_id, options)) = doc
let ls_id_commands = doc
.language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
.find_map(|ls| {
.flat_map(|ls| {
ls.capabilities()
.execute_command_provider
.as_ref()
.map(|options| (ls.id(), options))
})
else {
cx.editor
.set_status("No active language servers for this document support workspace commands");
return Ok(());
};
.iter()
.flat_map(|options| options.commands.iter())
.map(|command| (ls.id(), command))
});

if args.is_empty() {
let commands = options
.commands
.iter()
.map(|command| helix_lsp::lsp::Command {
title: command.clone(),
command: command.clone(),
arguments: None,
let commands = ls_id_commands
.map(|(ls_id, command)| {
LsIdCommand(
ls_id,
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, (), move |cx, command, _action| {
execute_lsp_command(cx.editor, language_server_id, command.clone());
});
let picker = ui::Picker::new(
commands,
(),
move |cx, LsIdCommand(ls_id, command), _action| {
execute_lsp_command(cx.editor, *ls_id, command.clone());
},
);
compositor.push(Box::new(overlaid(picker)))
},
));
Expand All @@ -1406,21 +1420,32 @@ fn lsp_workspace_command(
cx.jobs.callback(callback);
} else {
let command = args.join(" ");
Copy link
Contributor Author

@Schmiddiii Schmiddiii Apr 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unsure about this one. Is there some LSP which has a space in the command name? I would personally like this to be such that the first argument is the command and the remaining ones are arguments to that command. But I have kept it as it was for now.

if options.commands.iter().any(|c| c == &command) {
execute_lsp_command(
cx.editor,
language_server_id,
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(());
let matches: Vec<_> = ls_id_commands
.filter(|(_ls_id, c)| *c == &command)
.collect();

match matches.as_slice() {
[(ls_id, _command)] => {
execute_lsp_command(
cx.editor,
*ls_id,
helix_lsp::lsp::Command {
title: command.clone(),
arguments: None,
command,
},
);
}
[] => {
cx.editor.set_status(format!(
"`{command}` is not supported for any language server"
));
}
_ => {
cx.editor.set_status(format!(
"`{command}` supported by multiple language servers"
));
}
}
}
Ok(())
Expand Down
16 changes: 9 additions & 7 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,14 +366,16 @@ pub mod completers {
}

pub fn lsp_workspace_command(editor: &Editor, input: &str) -> Vec<Completion> {
let Some(options) = doc!(editor)
let commands = doc!(editor)
.language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
.find_map(|ls| ls.capabilities().execute_command_provider.as_ref())
else {
return vec![];
};

fuzzy_match(input, &options.commands, false)
.flat_map(|ls| {
ls.capabilities()
.execute_command_provider
.iter()
.flat_map(|options| options.commands.iter())
});

fuzzy_match(input, commands, false)
.into_iter()
.map(|(name, _)| ((0..), name.to_owned().into()))
.collect()
Expand Down
Loading