From f53c31fb0daac96a5a88096ba875ebcee6c804f9 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 21 Nov 2021 08:57:13 +0100 Subject: [PATCH] Teach next/prev symbol functions to allow multiple symbol kinds The new next/prev symbol feature is typically used to jump around functions. We even provide a convenience wrapper with a default mapping. Some programming styles use mostly methods instead of functions. To make the default mapping more useful, extend it to jump to functions *or* methods, instead of just methods. Delete the convenience wrapper for methods, since that's now superseded. Swap the argument order of lsp-next-symbol and friends, so we can take a variable number of symbol kinds. Add a deserialization method until this feature becomes part of lsp_types, see https://github.com/gluon-lang/lsp-types/pull/224 --- README.asciidoc | 16 +++--- rc/lsp.kak | 70 ++++++++++-------------- src/language_features/document_symbol.rs | 49 +++++++++++++++-- src/types.rs | 3 +- 4 files changed, 83 insertions(+), 55 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index 6527290a..36b2efd3 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -207,15 +207,15 @@ map global user l %{: enter-user-mode lsp} -docstring "LSP mode" | n | lsp-find-error | p | lsp-find-error --previous | y | lsp-type-definition -| 9 | lsp-hover-previous-symbol Function -| 0 | lsp-hover-next-symbol Function +| 9 | lsp-hover-previous-function +| 0 | lsp-hover-next-function | & | lsp-highlight-references -| ( | lsp-previous-symbol Function -| ) | lsp-next-symbol Function -| [ | lsp-hover-previous-symbol Any -| ] | lsp-hover-next-symbol Any -| { | lsp-previous-symbol Any -| } | lsp-next-symbol Any +| ( | lsp-previous-function +| ) | lsp-next-function +| [ | lsp-hover-previous-symbol +| ] | lsp-hover-next-symbol +| { | lsp-previous-symbol +| } | lsp-next-symbol |=== To know which subset of kak-lsp commands is backed by the current buffer's filetype's language server use diff --git a/rc/lsp.kak b/rc/lsp.kak index 3be83db7..35e6c11a 100644 --- a/rc/lsp.kak +++ b/rc/lsp.kak @@ -271,52 +271,48 @@ position.column = %d declare-option -hidden str lsp_symbol_kind_completion %{ symbol_kinds="\ - Any File Module Namespace Package Class Method Property Field Constructor Enum Interface + File Module Namespace Package Class Method Property Field Constructor Enum Interface Function Variable Constant String Number Boolean Array Object Key Null EnumMember Struct Event Operator TypeParameter" printf '%s\n' ${symbol_kinds} } -define-command lsp-previous-symbol -params 0..1 -shell-script-candidates %opt{lsp_symbol_kind_completion} \ - -docstring "lsp-previous-symbol []: goto the buffer's previous symbol of type , or of any type" %{ - lsp-did-change-and-then "lsp-next-or-previous-symbol %arg{@} previous goto" +define-command lsp-previous-symbol -params 0.. -shell-script-candidates %opt{lsp_symbol_kind_completion} \ + -docstring "lsp-previous-symbol [...]: goto the buffer's previous symbol of a type in , or of any type" %{ + lsp-did-change-and-then "lsp-next-or-previous-symbol previous goto %arg{@}" } -define-command lsp-next-symbol -params 0..1 -shell-script-candidates %opt{lsp_symbol_kind_completion} \ - -docstring "lsp-next-symbol []: goto the buffer's next symbol of type , or of any type" %{ - lsp-did-change-and-then "lsp-next-or-previous-symbol %arg{@} next goto" +define-command lsp-next-symbol -params 0.. -shell-script-candidates %opt{lsp_symbol_kind_completion} \ + -docstring "lsp-next-symbol [...]: goto the buffer's next symbol of a type in , or of any type" %{ + lsp-did-change-and-then "lsp-next-or-previous-symbol next goto %arg{@}" } -define-command lsp-hover-previous-symbol -params 0..1 -shell-script-candidates %opt{lsp_symbol_kind_completion} \ - -docstring "lsp-hover-previous-symbol []: show hover of the buffer's current or previous symbol of type , or of any type" %{ - lsp-did-change-and-then "lsp-next-or-previous-symbol %arg{@} previous hover" +define-command lsp-hover-previous-symbol -params 0.. -shell-script-candidates %opt{lsp_symbol_kind_completion} \ + -docstring "lsp-hover-previous-symbol [...]: show hover of the buffer's current or previous symbol of a type in , or of any type" %{ + lsp-did-change-and-then "lsp-next-or-previous-symbol previous hover %arg{@}" } -define-command lsp-hover-next-symbol -params 0..1 -shell-script-candidates %opt{lsp_symbol_kind_completion} \ - -docstring "lsp-hover-next-symbol []: show hover of the buffer's next symbol of type , or of any type" %{ - lsp-did-change-and-then "lsp-next-or-previous-symbol %arg{@} next hover" +define-command lsp-hover-next-symbol -params 0.. -shell-script-candidates %opt{lsp_symbol_kind_completion} \ + -docstring "lsp-hover-next-symbol [...]: show hover of the buffer's next symbol of a type in , or of any type" %{ + lsp-did-change-and-then "lsp-next-or-previous-symbol next hover %arg{@}" } # Requests for hover/goto next/previous symbol are funneled through this command -define-command lsp-next-or-previous-symbol -hidden -params 0..3 %{ +define-command lsp-next-or-previous-symbol -hidden -params 2.. %{ nop %sh{ - symbol_kind="" # Empty string means *any* symbol - if [ $# -eq 3 ]; then - if [ "$1" != "Any" ]; then - symbol_kind=$1 - fi - shift - fi - forward="false" if [ "$1" = "next" ]; then forward="true" fi + shift hover="true" - if [ "$2" = "goto" ]; then + if [ "$1" = "goto" ]; then hover="false" fi + shift + + symbol_kinds="[ $( [ $# -gt 0 ] && printf '"%s",' "$@" ) ]" (printf ' session = "%s" @@ -328,45 +324,37 @@ method = "kak-lsp/next-or-previous-symbol" [params] position.line = %d position.column = %d -symbolKind = "%s" +symbolKinds = %s searchNext = %s hover = %s -' "${kak_session}" "${kak_client}" "${kak_buffile}" "${kak_opt_filetype}" "${kak_timestamp}" ${kak_cursor_line} ${kak_cursor_column} "$symbol_kind" "$forward" "$hover" | eval "${kak_opt_lsp_cmd} --request") > /dev/null 2>&1 < /dev/null & } +' "${kak_session}" "${kak_client}" "${kak_buffile}" "${kak_opt_filetype}" "${kak_timestamp}" ${kak_cursor_line} ${kak_cursor_column} "$symbol_kinds" "$forward" "$hover" | eval "${kak_opt_lsp_cmd} --request") > /dev/null 2>&1 < /dev/null & } } -shell-script-candidates %{ case $# in - # Which type of symbol? - (1) eval "$kak_opt_lsp_symbol_kind_completion" ;; # Search forward or backward? - (2) printf '%s\n' previous next ;; + (1) printf '%s\n' previous next ;; # Show hover info or goto symbol? - (3) printf '%s\n' hover goto ;; + (2) printf '%s\n' hover goto ;; + # Which symbol types? + (*) eval "$kak_opt_lsp_symbol_kind_completion" ;; esac } ## Convenience methods define-command lsp-hover-next-function -docstring "Show hover of the next function in the buffer" %{ - lsp-hover-next-symbol Function + lsp-hover-next-symbol Method Function } define-command lsp-hover-previous-function -docstring "Show hover of the current or previous function in the buffer" %{ - lsp-hover-previous-symbol Function + lsp-hover-previous-symbol Method Function } define-command lsp-next-function -docstring "Goto the next function in the buffer" %{ - lsp-next-symbol Function + lsp-next-symbol Method Function } define-command lsp-previous-function -docstring "Goto the current or previous function in the buffer" %{ - lsp-previous-symbol Function -} - -define-command lsp-next-method -docstring "Goto the next method in the buffer" %{ - lsp-next-symbol Method -} - -define-command lsp-previous-method -docstring "Goto the current or previous method in the buffer" %{ - lsp-previous-symbol Method + lsp-previous-symbol Method Function } define-command lsp-definition -docstring "Go to definition" %{ diff --git a/src/language_features/document_symbol.rs b/src/language_features/document_symbol.rs index b46c4c55..5ce33fb0 100644 --- a/src/language_features/document_symbol.rs +++ b/src/language_features/document_symbol.rs @@ -154,6 +154,38 @@ pub fn format_symbol>(items: Vec, meta: &EditorMeta, ctx: &Conte .join("") } +fn symbol_kind_from_string(value: &str) -> Option { + match value { + "File" => Some(SymbolKind::FILE), + "Module" => Some(SymbolKind::MODULE), + "Namespace" => Some(SymbolKind::NAMESPACE), + "Package" => Some(SymbolKind::PACKAGE), + "Class" => Some(SymbolKind::CLASS), + "Method" => Some(SymbolKind::METHOD), + "Property" => Some(SymbolKind::PROPERTY), + "Field" => Some(SymbolKind::FIELD), + "Constructor" => Some(SymbolKind::CONSTRUCTOR), + "Enum" => Some(SymbolKind::ENUM), + "Interface" => Some(SymbolKind::INTERFACE), + "Function" => Some(SymbolKind::FUNCTION), + "Variable" => Some(SymbolKind::VARIABLE), + "Constant" => Some(SymbolKind::CONSTANT), + "String" => Some(SymbolKind::STRING), + "Number" => Some(SymbolKind::NUMBER), + "Boolean" => Some(SymbolKind::BOOLEAN), + "Array" => Some(SymbolKind::ARRAY), + "Object" => Some(SymbolKind::OBJECT), + "Key" => Some(SymbolKind::KEY), + "Null" => Some(SymbolKind::NULL), + "EnumMember" => Some(SymbolKind::ENUM_MEMBER), + "Struct" => Some(SymbolKind::STRUCT), + "Event" => Some(SymbolKind::EVENT), + "Operator" => Some(SymbolKind::OPERATOR), + "TypeParameter" => Some(SymbolKind::TYPE_PARAMETER), + _ => None, + } +} + fn editor_next_or_prev_symbol( meta: EditorMeta, editor_params: EditorParams, @@ -162,19 +194,26 @@ fn editor_next_or_prev_symbol( ) { let params = NextOrPrevSymbolParams::deserialize(editor_params).unwrap(); let hover = params.hover; + + let symbol_kinds: Vec = params + .symbol_kinds + .iter() + .map(|kind_str| symbol_kind_from_string(kind_str).unwrap()) + .collect::>(); + let maybe_details = match result { None => return, Some(DocumentSymbolResponse::Flat(result)) => { if result.is_empty() { return; } - next_or_prev_symbol_details(result, ¶ms, &meta, ctx) + next_or_prev_symbol_details(result, ¶ms, &symbol_kinds, &meta, ctx) } Some(DocumentSymbolResponse::Nested(result)) => { if result.is_empty() { return; } - next_or_prev_symbol_details(result, ¶ms, &meta, ctx) + next_or_prev_symbol_details(result, ¶ms, &symbol_kinds, &meta, ctx) } }; @@ -277,6 +316,7 @@ fn editor_next_or_prev_for_details( fn next_or_prev_symbol_details + 'static>( mut items: Vec, params: &NextOrPrevSymbolParams, + symbol_kinds: &Vec, meta: &EditorMeta, ctx: &Context, ) -> Option<(String, KakounePosition, String, SymbolKind)> { @@ -313,8 +353,7 @@ fn next_or_prev_symbol_details + 'static>( let symbol_name = symbol.name().to_owned(); - let want_symbol = - params.symbol_kind.is_empty() || format!("{:?}", kind) == params.symbol_kind; + let want_symbol = symbol_kinds.is_empty() || symbol_kinds.contains(&kind); // Assume that children always have a starting position higher than (or equal to) // their parent's starting position. This means that when searching for the node with @@ -326,7 +365,7 @@ fn next_or_prev_symbol_details + 'static>( } if let Some(from_children) = - next_or_prev_symbol_details(symbol.children(), params, meta, ctx) + next_or_prev_symbol_details(symbol.children(), params, symbol_kinds, meta, ctx) { return Some(from_children); } diff --git a/src/types.rs b/src/types.rs index 152322f9..db20c9b5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -184,7 +184,8 @@ pub struct CodeActionsParams { #[serde(rename_all = "camelCase")] pub struct NextOrPrevSymbolParams { pub position: KakounePosition, - pub symbol_kind: String, + /// Match any of these kinds of symbols, or any symbol if empty. + pub symbol_kinds: Vec, /// If true then searches forward ("next") /// otherwise searches backward ("previous") pub search_next: bool,