I have a binding that I would like to make it attempt to run the command, and if the command fails to fall back to a different command.
vim.keymap.set("x", "L", '<cmd>STSSelectNextSiblingNode<cr>', opts)
vim.keymap.set("x", "H", '<cmd>STSSelectPrevSiblingNode<cr>', opts)
vim.keymap.set("x", "K", '<cmd>STSSelectParentNode<cr>', opts)
vim.keymap.set("x", "J", '<cmd>STSSelectChildNode<cr>', opts)
Here, these methods will fail if I e.g. trigger them when my cursor is not intersecting an actual tree-sitter node, e.g. on a comment, it will produce this error:
Error executing Lua callback: .../lazy/syntax-tree-surfer/lua/syntax-tree-surfer/init.lua:82: attempt to index local 'parent' (a nil value)
stack traceback:
.../lazy/syntax-tree-surfer/lua/syntax-tree-surfer/init.lua:82: in function 'get_visual_node'
.../lazy/syntax-tree-surfer/lua/syntax-tree-surfer/init.lua:122: in function 'surf'
.../lazy/syntax-tree-surfer/lua/syntax-tree-surfer/init.lua:301: in function <.../lazy/syntax-tree-surfer/lua/syntax-tree-surfer/init.lua:300>
Press ENTER or type command to continue
(so long as opts
doesn't contain silent = true
)
Now, here's what neovim help has to say about <Cmd>
:
*<Cmd>* *:map-cmd*
The <Cmd> pseudokey begins a "command mapping", which executes the command
directly (without changing modes). Where you might use ":...<CR>" in the
{rhs} of a mapping, you can instead use "<Cmd>...<CR>".
Example:
noremap x <Cmd>echo mode(1)<cr>
This is more flexible than `:<C-U>` in visual and operator-pending mode, or
`<C-O>:` in insert-mode, because the commands are executed directly in the
current mode (instead of always going to normal-mode). Visual-mode is
preserved, so tricks with |gv| are not needed. Commands can be invoked
directly in cmdline-mode (which would otherwise require timer hacks).
Unlike <expr> mappings, there are no special restrictions on the <Cmd>
command: it is executed as if an (unrestricted) |autocommand| was invoked
or an async event event was processed.
Note:
- Because <Cmd> avoids mode-changes (unlike ":") it does not trigger
|CmdlineEnter| and |CmdlineLeave| events. This helps performance.
- For the same reason, |keycodes| like <C-R><C-W> are interpreted as plain,
unmapped keys.
- The command is not echo'ed, no need for <silent>.
- The {rhs} is not subject to abbreviations nor to other mappings, even if the
mapping is recursive.
- In Visual mode you can use `line('v')` and `col('v')` to get one end of the
Visual area, the cursor is at the other end.
*E5520*
<Cmd> commands must terminate, that is, they must be followed by <CR> in the
{rhs} of the mapping definition. |Command-line| mode is never entered.
So I will clearly want to use this with silent = true
but I need a way to detect when the error was produced so I can catch that and implement the fallback behavior (in this case move the cursor along the grid like I usually map these keys to).
It will be acceptable if I have to give up using <Cmd>
and use a different way to implement this, but it's still not clear how to do that.
pcall
wrapper helper function so I will try that and post if it works