Skip to content

Commit

Permalink
Teach next/prev symbol functions to allow multiple symbol kinds
Browse files Browse the repository at this point in the history
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 gluon-lang/lsp-types#224
  • Loading branch information
krobelus authored and Tobias Pisani committed Dec 15, 2021
1 parent ca1d780 commit f53c31f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 55 deletions.
16 changes: 8 additions & 8 deletions README.asciidoc
Expand Up @@ -207,15 +207,15 @@ map global user l %{: enter-user-mode lsp<ret>} -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
Expand Down
70 changes: 29 additions & 41 deletions rc/lsp.kak
Expand Up @@ -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 [<symbol-kind>]: goto the buffer's previous symbol of type <symbol-kind>, 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 [<symbol-kinds>...]: goto the buffer's previous symbol of a type in <symbol-kinds>, 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 [<symbol-kind>]: goto the buffer's next symbol of type <symbol-kind>, 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 [<symbol-kinds>...]: goto the buffer's next symbol of a type in <symbol-kinds>, 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 [<symbol-kind>]: show hover of the buffer's current or previous symbol of type <symbol-kind>, 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 [<symbol-kinds>...]: show hover of the buffer's current or previous symbol of a type in <symbol-kinds>, 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 [<symbol-kind>]: show hover of the buffer's next symbol of type <symbol-kind>, 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 [<symbol-kinds>...]: show hover of the buffer's next symbol of a type in <symbol-kinds>, 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"
Expand All @@ -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" %{
Expand Down
49 changes: 44 additions & 5 deletions src/language_features/document_symbol.rs
Expand Up @@ -154,6 +154,38 @@ pub fn format_symbol<T: Symbol<T>>(items: Vec<T>, meta: &EditorMeta, ctx: &Conte
.join("")
}

fn symbol_kind_from_string(value: &str) -> Option<SymbolKind> {
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,
Expand All @@ -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<SymbolKind> = params
.symbol_kinds
.iter()
.map(|kind_str| symbol_kind_from_string(kind_str).unwrap())
.collect::<Vec<_>>();

let maybe_details = match result {
None => return,
Some(DocumentSymbolResponse::Flat(result)) => {
if result.is_empty() {
return;
}
next_or_prev_symbol_details(result, &params, &meta, ctx)
next_or_prev_symbol_details(result, &params, &symbol_kinds, &meta, ctx)
}
Some(DocumentSymbolResponse::Nested(result)) => {
if result.is_empty() {
return;
}
next_or_prev_symbol_details(result, &params, &meta, ctx)
next_or_prev_symbol_details(result, &params, &symbol_kinds, &meta, ctx)
}
};

Expand Down Expand Up @@ -277,6 +316,7 @@ fn editor_next_or_prev_for_details(
fn next_or_prev_symbol_details<T: Symbol<T> + 'static>(
mut items: Vec<T>,
params: &NextOrPrevSymbolParams,
symbol_kinds: &Vec<SymbolKind>,
meta: &EditorMeta,
ctx: &Context,
) -> Option<(String, KakounePosition, String, SymbolKind)> {
Expand Down Expand Up @@ -313,8 +353,7 @@ fn next_or_prev_symbol_details<T: Symbol<T> + '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
Expand All @@ -326,7 +365,7 @@ fn next_or_prev_symbol_details<T: Symbol<T> + '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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/types.rs
Expand Up @@ -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<String>,
/// If true then searches forward ("next")
/// otherwise searches backward ("previous")
pub search_next: bool,
Expand Down

0 comments on commit f53c31f

Please sign in to comment.