From 8ca70fea3ae6a80fee2e5d7baf9a53f95d655af9 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 8 Dec 2022 16:20:06 +0100 Subject: [PATCH] Sort code action completions by importance This is inspired by a recent change in [Helix] that fixes sorting of code actions. We have the same problem; we use ":prompt -shell-script-candidates" to show code actions. For example, on this Rust file: fn main() { let f: FnOnce(HashMap); } with the cursor on "HashMap", a ":lsp-code-actions" will offer two code actions (from rust-analyzer): Extract type as type alias" Import `std::collections::HashMap` The first one is a refactoring and the second one is a quickfix. A proposed Kakoune patch allows users to define completion priorities. Use it to fix the order of such code actions. [Helix]: https://github.com/helix-editor/helix/pull/4134 --- rc/lsp.kak | 19 ++++++++++++++++--- src/language_features/code_action.rs | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/rc/lsp.kak b/rc/lsp.kak index 17b4e57d..9545b67a 100644 --- a/rc/lsp.kak +++ b/rc/lsp.kak @@ -196,10 +196,16 @@ define-command -hidden lsp-menu -params 1.. -docstring "Like menu but with promp cases= completion= nl=$(printf '\n.'); nl=${nl%.} + priority=1 while [ $# -gt 0 ]; do title=$1; shift command=$1; shift - completion="${completion}${title}${nl}" + if $kak_opt_lsp_have_kakoune_feature_completion_priority; then + completion="${completion}$(printf %s "${title}" | sed 's/\\|/\\|/g')|$priority${nl}" + priority=$((priority + 1)) + else + completion="${completion}${title}${nl}" + fi cases="${cases} $(shellquote "$title" s/¶/¶¶/g)) printf '%s\\n' $(shellquote "$command" s/¶/¶¶/g) @@ -214,9 +220,9 @@ define-command -hidden lsp-menu -params 1.. -docstring "Like menu but with promp ¶ §" "$cases" printf ' %s' "$on_abort" - printf ' -menu -shell-script-candidates %%§ + printf ' -menu %s -shell-script-candidates %%§ printf %%s %s - §\n' "$(shellquote "$completion")" + §\n' "$($kak_opt_lsp_have_kakoune_feature_completion_priority && printf %s -priority)" "$(shellquote "$completion")" } } catch %{ evaluate-commands %sh{ @@ -359,6 +365,13 @@ ${lsp_draft}\"\"\" } }} +declare-option -hidden bool lsp_have_kakoune_feature_completion_priority +declare-option -hidden completions lsp_have_kakoune_feature_completion_priority_tmp +try %{ + set-option global lsp_have_kakoune_feature_completion_priority_tmp 1.1@0 insert_text|on_select|menu|1 + set-option global lsp_have_kakoune_feature_completion_priority true +} + define-command -hidden lsp-completion -docstring "Request completions for the main cursor position" %{ try %{ # Fail if preceding character is a whitespace (by default; the trigger could be customized). diff --git a/src/language_features/code_action.rs b/src/language_features/code_action.rs index 1ec1224a..06083ded 100644 --- a/src/language_features/code_action.rs +++ b/src/language_features/code_action.rs @@ -101,7 +101,7 @@ fn editor_code_actions( return; } - let actions = result.unwrap_or_default(); + let mut actions = result.unwrap_or_default(); for cmd in &actions { match cmd { @@ -152,6 +152,24 @@ fn editor_code_actions( return; } + actions.sort_by_key(|ca| { + let empty = CodeActionKind::EMPTY; + let kind = match ca { + CodeActionOrCommand::Command(_) => &empty, + CodeActionOrCommand::CodeAction(action) => action.kind.as_ref().unwrap_or(&empty), + }; + // TODO These loosely follow what VSCode does, we should be more accurate. + match kind.as_str() { + "quickfix" => 0, + "refactor" => 1, + "refactor.extract" => 2, + "refactor.inline" => 3, + "refactor.rewrite" => 4, + "source" => 5, + "source.organizeImports" => 6, + _ => 7, + } + }); let titles_and_commands = actions .iter() .map(|c| {