I'm starting to use zsh on macOS Sierra. I would like to have the following key mappings:
Enter => accept-line
Shift-Enter => accept-and-hold
However, I can't seem to differentiate between the two. I'm only able to get Enter, and Esc-Enter, but not Shift-Enter:
bindkey "^M" accept-line # Enter
bindkey "^[^M" accept-and-hold # Esc-Enter
bindkey "????" accept-and-hold # Shift-Enter
Is it possible to detect and handle Shift-Enter?
zsh (as well as other shells) do not act on key bindings but rather on key sequences received from the terminal. Converting key presses and combinations into key sequences is the responsibility of the terminal. You can retrieve the key sequence for a key combination by pressing Ctr+v followed by the key combination, e.g. Shift+Enter.
By default Enter and Shift+Enter (as well as Ctrl+v and Ctrl+Shift+m) all generate the identical key sequence ^M (at least in most common terminal emulators).
Fortunately, some terminal emulators allow to configure the key sequences sent. For example iTerm2 allows you to set customized key bindings that send escape sequences (in Profile > Keys), you should be able to define a sequence for Shift+Enter there, e.g. [[SE and can then make the appropriate settings in zsh: bindkey '^[[[SE' 'accept-and-hold'. (Unfortunately I do not have access to a Mac at the moment, so I could not test this).
This might answer your problem (can't put it into comment, don't have 50 rep). You might try # showkey --scancodes which gives you key codes and take a look into the manual-pages e.g. man zshzle and search for "code". I have tried to map the shift key without success. Might be it's not possible. Also have a look into bindkey -l wich gives you the keymaps and bindkey -M emacs for emacs keymap
Related
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.
My ZSH has at some point been told to bind Delete to some complicated function, key sequence, or macro, and I want to remove this binding from my configuration. In order to better find where this binding is being set, I'd like to see what Zsh is actually doing when I hit Delete.
How can I see a list of all the currently existing key bindings present in my Zsh environment?
Just run bindkey with no arguments:
$ bindkey
"^A"-"^C" self-insert
"^D" list-choices
"^E"-"^F" self-insert
"^G" list-expand
"^H" vi-backward-delete-char
"^I" expand-or-complete
"^J" history-substring-search-down
"^K" self-insert
"^L" clear-screen
...
However, the particular behavior you are describing with regards to Delete can be resolved by adding this to your .zshrc:
bindkey "^[[3~" delete-char
bindkey "^[3;5~" delete-char
Explanation
Depending on the terminal, Delete generates one of the following character sequences:
^[[3~
^[3;5~
You can see which sequence your terminal uses via sed -n l as explained here.
zsh tries to evaluate the longest match. In both cases, zsh matches ^[ first, which matches Esc. If you have vi mode enabled, this tells zsh to turn it on.
After this, vi mode reads the remaining characters, which are one of the following:
[3~ toggle the case of the next 3 characters
3;5~ repeat the last find operation 3 times then toggle the case of the next 5 characters
So if you haven't explicitly used bindkey on this character sequence, every time you press Delete with vi mode enabled, you will enter vi mode and the last character you typed will be uppercased.
Thanks to Adaephon in the comments below for help with this explanation.
I use vim, and so I wanted to change a couple of tmux's default bindings. In particular I wanted to change the resizing commands so that e.g. ctrl-b ctrl-k resize the split up by one position. I entered the following into my .tmux.conf:
bind-key C-k resizep -U
and it works, except that it only allows me to resize by one unit at a time before I have to hit ctrl again. In other words, I can't hold down ctrl and press b followed by k a bunch of times (while still holding down ctrl), whereas I can hold down ctrl, press b, and then press the up arrow key a bunch of times.
Does anyone know exactly why this is, or how I might replicate my desired behavior?
You need to specify the -r parameter in your command:
bind-key -r C-k resizep -U
As explained in tmux man page:
bind-key [-cnr] [-t mode-table] key command [arguments]
(alias: bind)
Bind key key to command. By default (without -t) the primary
key bindings are modified (those normally activated with the
prefix key); in this case, if -n is specified, it is not neces‐
sary to use the prefix key, command is bound to key alone. The
-r flag indicates this key may repeat, see the repeat-time
option.
One of the killer features of the readline line editor is the ability to type the first few characters of a command in one's history and then up-arrow to get to it. For instance, if I have 'grep "te' in the zle buffer, the up-arrow key iterates through grep commands whose first two search characters are 't' and 'e'. In my current zsh configuration, the up arrow key does not do such filtering. Are there zle commands/widgets that would give the type of filtering I want?
The widget you are looking for is history-beginning-search-backward. You can bind it to up arrow using
bindkey "^[OA" history-beginning-search-backward
or
bindkey "^[[A" history-beginning-search-backward
depending on which escape sequence your up-arrow key sends (you can just use both, to be safe).
I usually find interesting zsh keybinding settings (through bindkey command) around the web. My question is how do I interpret what these escaped sequences mapped to? For instance, here is a snippet from oh-my-zsh's key-bindings.zsh
bindkey "^[[H" beginning-of-line
bindkey "^[[1~" beginning-of-line
bindkey "^[[F" end-of-line
bindkey "^[[4~" end-of-line
Is there a reference on how do these keymaps represented? Also, is it zsh-specific or platform specific at all?
I am aware that I can use either cat or Ctrl-V to find the corresponding escaped sequence for certain keys. Given that I could brute force to find the reverse match, but this would not work for the keys that do not exist on my keyboard (e.g. Home/End on Mac laptops). Thus, I'd prefer methods that could determine the keys regardless of the physical keyboard.
If speaking of a typical unix/linux flow of events the picture is roughly the following.
The terminal emulator program recieves the X events such as so and so button pressed, another button is released. Those events can be tracked with xev utility, for example. The terminal emulator then translates those events into escape sequences.
This translation is not set in stone. It can be configured. Different terminal emulators are configured differently. For example xterm translation can be set up in .Xdefaults like that:
XTerm*VT100*Translations:#override \
Ctrl<Key>Left: string(0x1B) string(OD) \n\
Ctrl<Key>Right: string(0x1B) string(OC) \n\
Note 0x1B which is ESC. ESC is also printed as ^[.
Now, zsh uses zle (and bash uses readline library for the same purpose)
which interprets some of the sequences to move around the input line and perform editing actions.
The following texts should provide more additional details.
Zsh Line editor description
Wikipedia article on escape sequences
and
Xterm Control Sequences
My answer is for modern readers in 2021 using MacOSX with default zsh Termnial:
Run your Terminal, press ⌘ + , to open Preferences.
Select Profiles > Keyboard tab, then here you are, there are all your mappings.