zed
zed copied to clipboard
vim mapping key to multiple actions
Check for existing issues
- [X] Completed
Describe the feature
Heard a feature request for this functionality referenced in another issue but I couldn't find it. I use map("i", "<C-s>", "<ESC>yiWi<lt><ESC>Ea></><ESC>hpF>")
often to generate tag pairs, so I'd love support for mapping sequences of vim motions. Is this something on the horizon?
If applicable, add mockups / screenshots to help present your vision of the feature
No response
This is something I'd love to build, if you'd like to work on it together please pick a time: https://calendly.com/conradirwin/pairing.
Otherwise, the approach I was going to take was to add a new action that could do this (probably globally as it seems useful outside of vim), so you could do:
[
{
"context": "Editor",
"bindings": {
"ctrl-space": [SimulateInput, "escape y i shift-w i < escape shift-e a, ..."],
}
}
]
There's a bit of impedence mismatch, as I think it makes sense to use Zed's Keybinding syntax instead of vims.
I'm afraid I wouldn't be much help!
I like the new action. Globally it could be worth adding a command sequence action too to allow for sequences that won't get broken by remapped defaults.
Adding a note here to think about the "leader" key in this context
I think it's complicated. in vim
# map
map <before> <after>
# different mode map
nmap <before> <after>
vmap <before> <after>
cmap <before> <after>
omap <before> <after>
# no recursive map
noremap <before> <after>
nnoremap <before> <after>
vnoremap <before> <after>
cnoremap <before> <after>
onoremap <before> <after>
Yeah. I think we can use the existing "context": "Editor && vim_mode == normal"
etc. support for differentiating the various different kinds of maps.
As to the difference between nmap
and nnoremap
, I think we could tackle this in a few ways, but the one that seems best to me is to require different approach for nnoremap
:
-
"ctrl-space": ["SimulateInput", "5 j"]
is equivalent tonmap
-
"ctrl-space": ["DispatchActions", ["vim::Number", 5], ["vim::Down"]]
is equivalent tonnoremap
It's still not as short as vim's syntax. But it does fit into the existing system (and would work for non-vim-users of zed too :D).
I also think that we need to explicitly check for and disallow "ctrl-space": ["SimulateInput", "ctrl-space"]
(or more complicated infinite loops). So while you could trigger a different SimulateInput, we'd prohibit recursion.
This will be fixed in zed 0.124. You can now do things like:
{
"bindings": {
"down": ["workspace::SendKeystrokes", "4 j"],
"cmd-alt-c": ["workspace::SendKeystrokes", ": copy relative path enter"], // *NOTE
}
}
There are some limitations, in particular there's currently no way to wait for an asynchronous event; so you can't open files or do anything that needs to do work on a background threads. There's also a total limit of 100 keystrokes dispatched to avoid accidental recursion.
Obviously the biggest limitation is that you can't call vim keystrokes that we haven't implemented yet – PRs welcome :D
NOTE: The code interprets each space-separated sequence as one key press. If it doesn't recognize a key, then it inputs the text as is. This means that you can do something like ": copy enter"
to run the "copy" command: it is interpreted as ":" then insert the text "copy" then hit "enter". On the other hand ":copy enter"
, would not work because ":copy" will not match ":"
which is needed to open the command palette.
Hey! First of all, thanks for shipping this! I was just testing it out and ran into a problem though, but maybe there is a way to do it: All remaps seem to be recursive remaps. This is my config:
{
"context": "Editor && vim_mode == normal",
"bindings": {
"b": ["workspace::SendKeystrokes", "left"],
"t": ["workspace::SendKeystrokes", "down"],
"r": ["workspace::SendKeystrokes", "up"],
"n": ["workspace::SendKeystrokes", "right"],
"l": ["workspace::SendKeystrokes", "r"],
}
}
What I'm doing here is remap the vim hjkl keys so that they're on the home row of my custom keyboard layout. In that process I have to remap the "r" to "up" - but because i need the r for the replace action, I'd like to remap it to my now unused lowercase "L". This doesn't work because the L gets mapped recursively to "up", too. Is there a way around this? Unfortunately there's also no "vim: replace" action in the command bar, so I can't go that route either.
Edit: Also is there a list of config commands relating to the vim mode (such as "vim_mode == normal") available somewhere? Wondering what else is possible. Thanks!
You can bind l directly instead of using SendKeystrokes:
"l": ["vim::PushOperator", "Replace"],
the contexts are not documented that well. There’s some here under custom key bindings, and some from just reading the source: https://github.com/zed-industries/zed/blob/main/assets/keymaps/vim.json#L361
Ah, PushOperator was the magic word. Awesome, thank you so much for the resources!
-------- Original Message -------- On 25/03/2024 13:17, Conrad Irwin wrote:
You can bind l directly instead of using SendKeystrokes:
"l": ["vim::PushOperator", "Replace"],
the contexts are not documented that well. There’s some here under custom key bindings, and some from just reading the source: https://github.com/zed-industries/zed/blob/main/assets/keymaps/vim.json#L361
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>
Hey, I don't understand how I would do something like this
"ctrl-u": ["vim::ScrollUp", "editor::ScrollCursorCenter"]
@LucaCoduriV Currently you can only do this with workspace::SendKeystrokes
, but it does seem like more ideas are needed to make this work.
The way to do it is something like:
"ctrl-shift-u": "vim::ScrollUp",
"ctrl-u": ["workspace::SendKeystrokes", "ctrl-shift-u z b"]
@LucaCoduriV Currently you can only do this with
workspace::SendKeystrokes
, but it does seem like more ideas are needed to make this work.The way to do it is something like:
"ctrl-shift-u": "vim::ScrollUp", "ctrl-u": ["workspace::SendKeystrokes", "ctrl-shift-u z b"]
Thank you