Skip to content

Commit

Permalink
sort codeaction by their kind instead of alphabetically
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalkuthe committed Oct 6, 2022
1 parent 4d4be0e commit 291fdf3
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 25 deletions.
78 changes: 56 additions & 22 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,43 +452,77 @@ 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),
..
}) => match kind.as_str() {
"quickfix" => 0,
"refactor.extract" => 1,
"refactor.inline" => 2,
"refactor.rewrite" => 3,
"refactor.move" => 4,
"refactor.surround" => 5,
"source" => 6,
_ => 7,
},
_ => 7,
};
log::error!("{category}");

// always present here
let code_action = code_action.unwrap();
categories[category].push(action);
}

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);
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 7 additions & 2 deletions helix-term/src/ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
Expand Down

0 comments on commit 291fdf3

Please sign in to comment.