aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-term/src/commands/lsp.rs84
-rw-r--r--helix-term/src/ui/completion.rs2
-rw-r--r--helix-term/src/ui/menu.rs9
3 files changed, 70 insertions, 25 deletions
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 3fa5c96f..5fec38d4 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -452,43 +452,83 @@ pub fn code_action(cx: &mut Context) {
cx.callback(
future,
move |editor, compositor, response: Option<lsp::CodeActionResponse>| {
- let actions = match response {
+ let mut actions = match response {
Some(a) => a,
None => return,
};
+
if actions.is_empty() {
editor.set_status("No code actions available");
return;
}
- let mut picker = ui::Menu::new(actions, (), move |editor, code_action, event| {
- if event != PromptEvent::Validate {
- return;
- }
+ // sort by CodeActionKind
+ // this ensures that the most relevant codeactions (quickfix) show up first
+ // while more situational commands (like refactors) show up later
+ // this behaviour is modeled after the behaviour of vscode (editor/contrib/codeAction/browser/codeActionWidget.ts)
+
+ let mut categories = vec![Vec::new(); 8];
+ for action in actions.drain(..) {
+ let category = match &action {
+ lsp::CodeActionOrCommand::CodeAction(lsp::CodeAction {
+ kind: Some(kind),
+ ..
+ }) => {
+ let mut components = kind.as_str().split('.');
+
+ match components.next() {
+ Some("quickfix") => 0,
+ Some("refactor") => match components.next() {
+ Some("extract") => 1,
+ Some("inline") => 2,
+ Some("rewrite") => 3,
+ Some("move") => 4,
+ Some("surround") => 5,
+ _ => 7,
+ },
+ Some("source") => 6,
+ _ => 7,
+ }
+ }
+ _ => 7,
+ };
+
+ categories[category].push(action);
+ }
- // always present here
- let code_action = code_action.unwrap();
+ for category in categories {
+ actions.extend(category.into_iter())
+ }
- match code_action {
- lsp::CodeActionOrCommand::Command(command) => {
- log::debug!("code action command: {:?}", command);
- execute_lsp_command(editor, command.clone());
+ let mut picker =
+ ui::Menu::new(actions, false, (), move |editor, code_action, event| {
+ if event != PromptEvent::Validate {
+ return;
}
- lsp::CodeActionOrCommand::CodeAction(code_action) => {
- log::debug!("code action: {:?}", code_action);
- if let Some(ref workspace_edit) = code_action.edit {
- log::debug!("edit: {:?}", workspace_edit);
- apply_workspace_edit(editor, offset_encoding, workspace_edit);
- }
- // if code action provides both edit and command first the edit
- // should be applied and then the command
- if let Some(command) = &code_action.command {
+ // always present here
+ let code_action = code_action.unwrap();
+
+ match code_action {
+ lsp::CodeActionOrCommand::Command(command) => {
+ log::debug!("code action command: {:?}", command);
execute_lsp_command(editor, command.clone());
}
+ lsp::CodeActionOrCommand::CodeAction(code_action) => {
+ log::debug!("code action: {:?}", code_action);
+ if let Some(ref workspace_edit) = code_action.edit {
+ log::debug!("edit: {:?}", workspace_edit);
+ apply_workspace_edit(editor, offset_encoding, workspace_edit);
+ }
+
+ // if code action provides both edit and command first the edit
+ // should be applied and then the command
+ if let Some(command) = &code_action.command {
+ execute_lsp_command(editor, command.clone());
+ }
+ }
}
- }
- });
+ });
picker.move_down(); // pre-select the first item
let popup = Popup::new("code-action", picker);
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index 7348dcf4..2e555e4b 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -97,7 +97,7 @@ impl Completion {
start_offset: usize,
trigger_offset: usize,
) -> Self {
- let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| {
+ let menu = Menu::new(items, true, (), move |editor: &mut Editor, item, event| {
fn item_to_transaction(
doc: &Document,
item: &CompletionItem,
diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs
index f77f5e80..b60e6454 100644
--- a/helix-term/src/ui/menu.rs
+++ b/helix-term/src/ui/menu.rs
@@ -74,6 +74,7 @@ impl<T: Item> Menu<T> {
// rendering)
pub fn new(
options: Vec<T>,
+ sort: bool,
editor_data: <T as Item>::Data,
callback_fn: impl Fn(&mut Editor, Option<&T>, MenuEvent) + 'static,
) -> Self {
@@ -91,8 +92,12 @@ impl<T: Item> Menu<T> {
recalculate: true,
};
- // TODO: scoring on empty input should just use a fastpath
- menu.score("");
+ if sort {
+ // TODO: scoring on empty input should just use a fastpath
+ menu.score("");
+ } else {
+ menu.matches = (0..menu.options.len()).map(|i| (i, 0)).collect();
+ }
menu
}