In bash vi mode, map jk to exit insert mode
TL;DR
Bash has a similar functionality to zsh
's bindkey
through bind
, but it does not have several vi
modes like zsh
. After set -o vi
you can do:
bind '"jk":vi-movement-mode'
which is the equivalent of zsh
's bindkey -M <all vi modes> jk vi-movement-mode
The vi-movement-mode
functions comes from inputrc
(see /etc/inputrc
for a list of them).
Full text
As Stephen Harris points out in his comment:
.bashrc
is called bybash
always (and notably not by other shells)..bash_profile
is only called on login shells (and again, bash only).
Several distros come with a .bash_profile
skeleton that looks as follows:
# ~/.bash_profile
[[ -f ~/.bashrc ]] && . ~/.bashrc
Which is a good content for .bash_profile
since you can simply forget it exists.
Now, to map jk to Esc in the shell session, that is not really possible. When you do:
inoremap jk <esc>
In Vim, after you type j, Vim knows it needs to wait a little bit to see if you type k next and it should invoke the mapping (or that you type another key and the mapping should not be triggered). As an addendum this is controlled by :set timeoutlen=<miliseconds>
in Vim (see :h timeoutlen
).
Several shell's or X11 has no such timeout control and does not allow for multiple character mappings. Only a mapping of a single key is allowed (But see the support notes below.) .
set -o vi
Does not read .vimrc
, it only imitates some vi
(not even vim
) key combinations that can be used in the shell. The same can be said about -o emacs
, it does not come with the full power of emacs
.
zsh support
zsh
actually supports map timeout. And you can use the following to map jk
to <esc>
:
bindkey -v # instead of set -o vi
bindkey -e jk \\e
(That will need to go to ~/.zshrc
not ~/.bashrc
)
Yet, I advise against this. I use vim
and zsh
most of the time. I have inoremap jk <esc>
in my vimrc
and I did try using the bindkey
combination above. zsh
waits too long to print j
when using it, and that annoyed me a lot.
bash support
bash
supports readline
bind
. I believe that bash
can be compiled without readilne
therefore there may be some rare systems that have bash that do not support bind
(be watchful). To map jk
to <esc>
in bash
you need to do:
set -o vi
bind '"jk":"\e"'
(yes that's a double level of quoting, it is needed)
Again, this makes typing j
quite annoying. But somehow less annoying than the zsh
solution on my machine (probably the default timeout is shorter).
Workaround (for non-bash and non-zsh shells)
The reason for remapping the Esc key is that it lies quite far away on the keyboard, and typing it takes time. A trick that can be borrowed from the emacs
guys is to remap CapsLock since it is a useless key anyway. emacs
guys remap it to Ctrl but we will remap it to Esc.
Let's use xev -event keyboard
to check the keycode of CapsLock:
KeyPress event, serial 25, synthetic NO, window 0x1c00001,
root 0x496, subw 0x0, time 8609026, (764,557), root:(765,576),
state 0x0, keycode 66 (keysym 0xffe5, Caps_Lock), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
And to check the function of Esc:
KeyPress event, serial 25, synthetic NO, window 0x1c00001,
root 0x496, subw 0x0, time 9488531, (571,525), root:(572,544),
state 0x0, keycode 9 (keysym 0xff1b, Escape), same_screen YES,
XLookupString gives 1 bytes: (1b) "
XmbLookupString gives 1 bytes: (1b) "
XFilterEvent returns: False
Very good, CapsLock is keycode 66 and Esc's function is called "Escape". Now we can do:
# diable caps lock
xmodmap -e "remove lock = Caps_Lock"
# make an Esc key from the keycode 66
xmodmap -e "keycode 66 = Escape"
The above must be done in this order. Now every time you hit CapsLock it works like an Esc key.
The tricky part is where to set this. A file ~/.Xmodmap
with the content:
remove lock = Caps_Lock
keycode 66 = Escape
Should be respected by most distros (actually display managers, but I'm saying distros for simplicity), but I saw ones that don't respect several ~/X*
files. For such distros you may try something like:
if [ "x" != "x$DISPLAY" ]; then
xmodmap -e "remove lock = Caps_Lock"
xmodmap -e "keycode 66 = Escape"
fi
In your .bashrc
.
(In theory that would be better placed in ~/.xinitrc
but if a display manager does not respect .Xmodmap
it will definitely not respect ~/.xnintrc
.)
Extra note: This only remaps CapsLock to Esc in a X11 session, therefore the map will only work in terminal emulators. Actual tty
's will not see the map.
References and extra reading:
- Disabling CapsLock
- Very detailed answer on how key remapping in X11 works
.bashrc
vs..bash_profile
Thanks, for previous answers, I use this in my ~/.zshrc for vi-like shortcuts in my terminal. I hope it'll help someone.
bindkey -v
bindkey 'jk' vi-cmd-mode