zed icon indicating copy to clipboard operation
zed copied to clipboard

vim mapping key to multiple actions

Open LORE-D-NATO opened this issue 1 year ago • 3 comments

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

LORE-D-NATO avatar Jan 30 '24 01:01 LORE-D-NATO

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.

ConradIrwin avatar Jan 30 '24 02:01 ConradIrwin

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.

LORE-D-NATO avatar Jan 30 '24 06:01 LORE-D-NATO

Adding a note here to think about the "leader" key in this context

ConradIrwin avatar Feb 02 '24 04:02 ConradIrwin

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>

0x2CA avatar Feb 07 '24 04:02 0x2CA

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 to nmap
  • "ctrl-space": ["DispatchActions", ["vim::Number", 5], ["vim::Down"]] is equivalent to nnoremap

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.

ConradIrwin avatar Feb 07 '24 04:02 ConradIrwin

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.

ConradIrwin avatar Feb 20 '24 22:02 ConradIrwin

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!

liam-k avatar Mar 24 '24 13:03 liam-k

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

ConradIrwin avatar Mar 25 '24 12:03 ConradIrwin

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: @.***>

liam-k avatar Mar 25 '24 15:03 liam-k

Hey, I don't understand how I would do something like this "ctrl-u": ["vim::ScrollUp", "editor::ScrollCursorCenter"]

LucaCoduriV avatar Jul 06 '24 14:07 LucaCoduriV

@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"]

ConradIrwin avatar Jul 08 '24 15:07 ConradIrwin

@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

LucaCoduriV avatar Jul 08 '24 16:07 LucaCoduriV