I'm using the zsh shell, and I'm trying to install a few key bindings to use keys similar to the ones I would use in a Vim buffer, when a completion menu is open.

So, inside the menuselect keymap I've bound the keys j and k to the zle widgets down-line-or-history and up-line-or-history, by adding the following lines inside ~/.zshrc:

bindkey -M menuselect 'j' down-line-or-history
bindkey -M menuselect 'k' up-line-or-history

down-line-or-history and up-line-or-history are described in man zshzle as follows:

down-line-or-history (^N ESC-[B) (j) (ESC-[B)
        Move down a line in the buffer, or if already at the bottom line, move to the next event in  the  his‐
        tory list.

up-line-or-history (^P ESC-[A) (k) (ESC-[A)
        Move up a line in the buffer, or if already at the top line, move to the previous event in the history

Now, I would like to bind C-d and C-u to the same widgets, but repeating them an arbitrary number of times, for example 5.

At first I tried this simple code:

some-widget() {
    zle backward-char -n 5
zle -N some-widget
bindkey '^D' some-widget

It binds C-d to the zle widget backward-char, but repeats it 5 times.

Then, I tried to rewrite the code, moving the key binding from the default keymap to the menuselect keymap:

some-widget() {
    zle backward-char -n 5
zle -N some-widget
bindkey -M menuselect '^D' some-widget

But it doesn't work as I expected, because when I hit C-d while a completion menu is open, zle seems to execute the default widget bound to C-d, which is delete-char-or-list:

delete-char-or-list (^D) (unbound) (unbound)
        Delete the character under the cursor.  If the cursor is at the end of the line, list possible comple‐
        tions for the current word.

It exits the current completion menu, and lists possible completions for the current word, instead of moving the cursor backward 5 times.

If it had worked as I expected, I would probably have ended up using this final code:

fast-down-line-or-history() {
    zle down-line-or-history -n 5
zle -N fast-down-line-or-history
bindkey -M menuselect '^D' fast-down-line-or-history

fast-up-line-or-history() {
    zle up-line-or-history -n 5
zle -N fast-up-line-or-history
bindkey -M menuselect '^U' fast-up-line-or-history

But since it doesn't, I need to find how to repeat a zle widget when a completion menu is open.

How to modify the previous code, so that down-line-or-history is repeated 5 times when hitting C-d while the completion menu is open?

  • 2
    Tricky, this is usually done by the digit-argument widget (bindkey -e; bindkey | grep digit) though simply inserting those into bindkey -M menuselect did not help in some simple testing... – thrig Jul 8 '17 at 18:04
  • @thrig Thank you very much for your comment, I will try to learn more about digit-argument. – user852573 Jul 8 '17 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.