How to make zsh keybind between emacs mode and vi mode? - zsh

I want to bind a key to toggle emacs mode and vi mode,which I use oh-my-zsh plugins(vi-mode).
I tried Is there a way to switch Bash or zsh from Emacs mode to vi mode with a keystroke?
I also try to bindkey like
bindkey '^[e' 'set -o emacs'
bindkey '^[v' 'set -o vi'
But it's not work for me.
Does any way to toggle vi/emacs or keybind to set keymap?
Thanks a lot !

bindkey is used for binding keys to ZLE widgets not any random command. So what you have guessed at is not going to work. You could write a custom ZLE widget to switch keymaps:
select-emacs() { set -o emacs }
zle -N select-emacs
bindkey '^[e' select-emacs
In practical terms, I wouldn't recommend this. If you want a hybrid approach, it is better to select emacs mode but bind a key to vi-cmd-mode. In fact Ctrl-X,Ctrl-V is bound to this by default. You might even bind the escape key to vi-cmd-mode - where emacs key sequences involve an initial escape press, that can mostly be replaced by Alt. If you're used to typing it with the actual escape key, you may be able to replace it by a custom widget in vi command mode.

I finally "found out" how to toggle vi and emacs mode with a singel key, e.g. [alt]+[i] in zsh
# in the .zshrc
# toggle vi and emacs mode
vi-mode() { set -o vi; }
emacs-mode() { set -o emacs; }
zle -N vi-mode
zle -N emacs-mode
bindkey '\ei' vi-mode # switch to vi "insert" mode
bindkey -M viins 'jk' vi-cmd-mode # (optionally) switch to vi "cmd" mode
bindkey -M viins '\ei' emacs-mode # switch to emacs mode
now you can toggle from emacs-mode to vi-mode and from vi-mode (both insert or normal mode) to emacs-mode

Related

How to cancel a completion in zsh prezto in vi insert mode?

In zsh, with emacs key mapping mode, Control + _ will cancel a completion.
Example:
echo $EDITOR[tab]
will be completed as:
echo vim
Pressing Control + _ will restore the editor to:
echo $EDITOR
I want to do the same thing with vi key mapping mode.
Is there a way to do it? Is there already a key mapping to do it?
Control + _ does not work neither in insert mode nor in normal mode.
The u (undo) will remove the entire line.
I finally found how to do it.
bindkey -l will print a list of existing keymap names.
bindkey -M <keymap> will list all bindings for a given keymap.
So I compared emacs and viins bindings and added the following line:
bindkey -M viins "$key_info[Control]_" undo
to the .zprezto/modules/editor/init.zsh. And it works.
I made a pull request to add this mapping to prezto:
https://github.com/sorin-ionescu/prezto/pull/1860

Bind delete key in vi mode

I am using the vi-mode plugin of oh-my-zsh. In my .zshrc, I have
bindkey '^[[3~' delete-char
where ^[[3~ is the escape code of my delete key. However, this only works in insert mode, but not in command mode. When I type
$ abcd
move the cursor to the beginning of the line and hit del in command mode, I get
$ ABCd
so apparently the character sequence of the delete key is interpreted literally. How can I make the delete key actually delete a character in command mode?
bindkey -a '^[[3~' delete-char
Zsh has a variety of different keymaps and by default, bindkey will bind keys in the normal insert mode keymap. The command mode keymap is selected with -M vicmd. -a is a shortcut for that. You can list the keymaps with bindkey -l. You'll see that there is also viopp which is used for movements after a key like c or d. There's also visual for visual selection mode.
It's 2020 now, and I'm not sure if #okapi 's answer is out of date or just missing a piece, but for me, I had to use:
bindkey -a '^[[3~' vi-delete-char
delete-char without the vi- prefix didn't do the trick but adding it did.

How do I yank into the system register from v-imode?

I'd like to yank text from a zsh command while in vi-mode with y and paste it into my web-browser/text-editor, etc.
Currently it seems that yanking text while in vi-mode only allows pasting back into zsh- has anyone had success yanking into the system clipboard?
Create a widget that executes the internal vi-yank widget and copies the zle clipboard (current position in kill ring) to the X11 clipboard using xclip(1):
function vi-yank-xclip {
zle vi-yank
echo "$CUTBUFFER" | xclip -i
}
.Replace xclip -i with pbcoby if running Mac OSX.
Make that widget known to zle and bind it to y:
zle -N vi-yank-xclip
bindkey -M vicmd 'y' vi-yank-xclip

In prezto how to get CTRL-RARROW working?

after installing prezto when I press CTRL - RIGHTARROW I can see these characters
source python;5C;5C;5C;5C
Whereas emacs key bindings like ALT- f work fine.
I just want my default keybindings where I can navigate using CTRL keys.
My efforts:
Raised a issue on github + browsed other similar issues as well.
Couldnt figure out how their solution would help my case.
Tried setting zstyle ':prezto:module:editor' key-bindings '' but it did not
work.
I have also checked modeles/editor/init.zsh but the script is
too long n I dont wanna make random changes and later keep
maintaining those.
Can anyone suggest a way so that my keybindings remain "UNCHANGED" even after .zpreztorc is loaded ?
If you're using the prezto editor module, it will override your key bindings. If you have it set to emacs mode with
zstyle ':prezto:module:editor' key-bindings 'emacs'
you will need to add your key bindings to that named keymap. You can do that with
bindkey -M emacs '^[[1;5C' forward-word
bindkey -M emacs '^[[1;5D' backward-word
This will need to be run after the editor module is loaded. You can do that by adding it to the bottom of your .zshrc file. I use the vi keymap, so I need to add the key bindings to both the viins and vicmd keymaps.
for keymap in 'emacs' 'viins' 'vicmd'; do
# [Ctrl-RightArrow] - move forward one word
bindkey -M $keymap '^[[1;5C' forward-word
# [Ctrl-LeftArrow] - move backward one word
bindkey -M $keymap '^[[1;5D' backward-word
done
unset keymap

List of zsh bindkey commands

Where can I find a list of zsh commands that I can use with bindkey, with descriptions?
Each time that I look for name of some standard action (e.g., end-of-line), I need to google and guess that the command found is what I look for.
Related:
Interpret zsh bindkey escaped sequences (SO)
The Z-Shell Line Editor (doc)
bindkey -l will give you a list of existing keymap names.
bindkey -M <keymap> will list all the bindings in a given keymap.
If you use the zsh command line in emacs mode, then the emacs keymap is likely to be most important for you.
If you use it in vi mode, then you’d be interested in viins and vicmd.
(See the zshzle(1) man page for more details.)
Once you have a list of keybindings, you can search the official ZLE documentation for the name of the action (or “widget” in zsh parlance).
zle -al
lists all registered zle commands
Commands available for use in the line editor are referred to as widgets. The standard widgets are listed in the zshzle manpage in the STANDARD WIDGETS section. That manpage is also available from the zsh website
Zsh Line Editor Doc: https://web.cs.elte.hu/local/texinfo/zsh/zsh_10.html
Look up system current bindkey setting: $ bindkey, eg($ bindkey|grep case, looking for down-case);
$ zle -al used for list all registered zle commands;
Bind your personal key for zsh command , $ vim ~/.zshrc, add
# bindkey
bindkey "^U" backward-kill-line
bindkey "^u" backward-kill-line
bindkey "^[l" down-case-word
bindkey "^[L" down-case-word
# alt+<- | alt+->
bindkey "^[f" forward-word
bindkey "^[b" backward-word
# ctrl+<- | ctrl+->
bindkey "^[[1;5D" backward-word
bindkey "^[[1;5C" forward-word
See other things: oh-my-zsh down-case-word bug: https://github.com/robbyrussell/oh-my-zsh/commit/55a9d685fd960390a4f400ac461d901049a78beb
I'm on zsh via putty. For me the bindings were different. You can find this out with CTRL+V followed by for example the left arrow. It will display the used character sequence. So for me it was:
bindkey "^[[D" backward-word
bindkey "^[[C" forward-word
bindkey "^H" backward-kill-word
After installing oh-my-zsh, I typed bindkey 'anything' then press tab, then say yes. The list of available bindkeys will be flushed out

Resources