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


12

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

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

我在另一篇文章中读到了如何做到这一点zsh,我该如何做到这一点bash

tl; dr

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
重新映射到是什么意思jk?键盘上有一些特殊的键吗?
史蒂芬·哈里斯

请查看编辑
mbigras

首先,.bashrc通常在每个shell上调用(例如,如果您在shell之外vi),但.bash_profile仅在登录shell上调用。所以.bashrc是合适的地方set -o vi。对于您修改后的第二个问题,我没有答案:-(
Stephen Harris

您如何启动bash shell?这是对.bashrc和.bash_profile之间
the_velour_fog

Answers:


11

TL; DR

Bash有一个类似的功能zshbindkey通过bind,但它并没有几个vi模式,如zsh。完成后set -o vi

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

等于zshbindkey -M <all vi modes> jk vi-movement-mode

vi-movement-mode函数来自inputrc(见/etc/inputrc他们的列表)。

全文

正如史蒂芬·哈里斯(Stephen Harris)在评论中指出的那样:

  • .bashrcbash总是被调用(特别是不是由其他shell 调用)。

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

几个发行版附带一个.bash_profile骨架,看起来如下:

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

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

现在,映射jkEsc在shell会话,这是不是真的有可能。当您这样做时:

inoremap jk <esc>

在Vim中,键入之后j,Vim知道需要稍等一下以查看是否键入knext,它应该调用映射(或者键入另一个键,并且不应触发该映射)。作为补充,这由:set timeoutlen=<miliseconds>Vim 控制(请参阅参考资料:h timeoutlen)。

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

set -o vi

不读取.vimrc,它仅模仿可以在shell中使用的某些vi(甚至不是vim)按键组合。可以说同样的话-o emacs,它并不具有强大的能力emacs


zsh支持

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

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

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

但是,我建议不要这样做。我使用vimzsh大部分的时间。我有inoremap jk <esc>,我vimrc确实尝试过使用bindkey以上组合。 zsh等待太久才能j使用它打印,这让我很烦。


bash支持

bash支持readline bind。我相信bash可以在不进行编译的情况下进行编译,readilne因此可能会有一些罕见的系统具有不支持的bash bind(请注意)。要映射jk<esc>in,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功能称为“转义”。现在我们可以做:

# 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的不会看到地图。

参考资料和额外阅读:


感谢您的详细解释。除了映射jk而不是映射,您是否愿意说明相同的过程CapsLock?我已经在osx机器上设置了它;但是,我在周末的余下时间都没有,而且我不记得自己是怎么做到的:)
mbigras

@mbigras-确定要以bash进行吗?Bash没有歧义图。我知道一种做某事的方式zshbindkey -v; bindkey -s jk \\e。但是,这是什么,会回来咬你回来时,你需要jk的,因为计时器是不可配置的,你有没有<leader>zsh
grochmal

我肯定是这样做的zsh,不是bash,bash是不可能的吗?
mbigras

@mbigras-等等,我错了!阅读man bash我发现bind这项工作很相似zshbindkey。我将更新答案。你去了,我用的zsh太多了。
grochmal

2
@Jason-嘿,这是Vi SE,每个人都在这里写一个ALL CAPS单词,其中包含:“ type word” <Esc> viwU :)。无需完成
令人作呕的

2

谢谢,对于以前的答案,我在〜/ .zshrc中将其用于终端中类似于vi的快捷方式。希望对您有所帮助。

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

我来这里寻找答案,该答案适用于在启用vi的zsh中绑定“ ^ G”键以进入“正常模式”,这是唯一可行的方法。
Dalker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.