在bash vi模式下,映射jk退出插入模式

在bash vi模式下,映射jk退出插入模式

我正在使用全新安装的 ubuntu 16.04 和 bash shell。我想做两件事:

  1. 设置 vi 模式,以便我可以从终端进行类似 vim 的操作
  2. 通过键入退出插入模式jk

我读到另一个帖子如何做到这一点zsh,我该如何做到这一点bash

太长了;博士

之后放入bind '"jk":vi-movement-mode'您的.bashrc文件中set -o vi:)

server@thinkpad:~$ tail -n 2 .bashrc
set -o vi
bind '"jk":vi-movement-mode'

请参阅@grochmal的回答以获得更详细的解释

答案1

长话短说

Bash 具有与 throughzsh类似的功能,但它没有像.之后您可以执行以下操作:bindkeybindvizshset -o vi

bind '"jk":vi-movement-mode'

这相当于zshbindkey -M <all vi modes> jk vi-movement-mode

这些vi-movement-mode函数来自inputrc(请参阅/etc/inputrc参考资料 中的列表)。

全文

正如斯蒂芬·哈里斯在评论中指出的那样:

  • .bashrc总是被调用bash(尤其是其他 shell 不会调用)。

  • .bash_profile仅在登录 shell 上调用(同样,仅在 bash 上调用)。

几个发行版都带有.bash_profile如下所示的框架:

# ~/.bash_profile
[[ -f ~/.bashrc ]] && . ~/.bashrc

这是一个很好的内容,因为.bash_profile你可以简单地忘记它的存在。

现在,要映射jkEscshell 会话中,这实际上是不可能的。当你这样做时:

inoremap jk <esc>

在 Vim 中,在您键入 后j,Vim 知道它需要等待一段时间才能查看您是否k接下来键入并且它应该调用映射(或者您键入另一个键并且不应触发映射)。作为附录,这是由:set timeoutlen=<miliseconds>Vim 控制的(请参阅 参考资料:h timeoutlen)。

一些 shell 或 X11 没有这样的超时控制,并且不允许多个字符映射。只允许单个键的映射(但请参阅下面的支持说明。)。

set -o vi

不会读取.vimrc,它只是模仿一些vi(甚至不是vim)可以在 shell 中使用的组合键。同样可以这样说-o emacs,它并不具备全部的威力emacs


zsh 支持

zsh实际上支持地图超时。您可以使用以下内容映射jk<esc>

bindkey -v  # instead of set -o vi
bindkey -e jk \\e

(这将需要去~/.zshrc~/.bashrc

然而,我建议不要这样做。我大部分时间都使用vimand 。zsh我已经inoremap jk <esc>尝试vimrc过使用bindkey上面的组合。 使用它时zsh等待打印的时间太长j,这让我很恼火。


bash 支持

bash支持readline bind.我相信bash无需编译即可编译,readilne因此可能有一些罕见的系统不支持 bash bind(请注意)。要映射jk<esc>bash需要执行的操作:

set -o vi
bind '"jk":"\e"'

(是的,这是双层引用,这是必需的)

同样,这使得打字变得j非常烦人。但不知怎的,比我机器上的解决方案更不烦人zsh(可能默认超时更短)。


解决方法(适用于非 bash 和非 zsh shell)

重新映射按键的原因Esc是它距离键盘相当远,并且打字需要时间。可以向这些人借用的一个技巧emacs是重新映射,CapsLock因为无论如何它都是无用的密钥。 emacs大家将其重新映射到,Ctrl但我们会将其重新映射到Esc

让我们用它xev -event keyboard来检查密钥代码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

并检查以下功能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

很好,CapsLock键码是66,Esc它的功能叫“Escape”。现在我们可以这样做:

# diable caps lock
xmodmap -e "remove lock = Caps_Lock"
# make an Esc key from the keycode 66
xmodmap -e "keycode 66 = Escape"

以上必须按此顺序完成。现在,每次你敲击它时,CapsLock它就像一把钥匙一样工作Esc


棘手的部分是在哪里设置它。~/.Xmodmap包含以下内容的文件:

remove lock = Caps_Lock
keycode 66 = Escape

应该受到大多数发行版的尊重(实际上是显示管理器,但为了简单起见,我说的是发行版),但我看到了一些不尊重多个~/X*文件的发行版。对于此类发行版,您可以尝试以下操作:

if [ "x" != "x$DISPLAY" ]; then
    xmodmap -e "remove lock = Caps_Lock"
    xmodmap -e "keycode 66 = Escape"
fi

在你的.bashrc

(理论上这会更好,~/.xinitrc但如果显示管理器不尊重.Xmodmap它肯定不会尊重~/.xnintrc。)

额外注意:这仅在 X11 会话中重新映射CapsLockEsc因此该映射仅在终端模拟器中工作。实际tty的不会看到地图。

参考资料和额外阅读:

答案2

谢谢,之前的回答,我在我的〜/.zshrc在我的终端中使用类似于 vi 的快捷方式。我希望它能帮助别人。

bindkey -v
bindkey 'jk' vi-cmd-mode

相关内容