我想在终端中使用类似 Vim 的导航,所以我添加了:
set editing-mode vi
set keymap vi
根据这里,我将我的.inputrc
文件设置为vi导航模式(editing-mode vi
)。那么keymap vi
是做什么的,我需要它吗?
TL;DR
如果你不想在默认键映射中更改/添加绑定,则不需要使用keymap vi
。
keymap vi
的作用是指定任何列在该点之后的绑定适用于该键映射(与vi-command
和vi-move
完全相同)。
如果您想更改插入键映射(例如,添加Ctrl-A
绑定以在输入时转到行的开头),则需要在keymap vi-insert
下执行此操作。
如果您想进一步了解vi
模式和映射,请跳至标题editing-mode vi
(最后一个)。
但是!可能需要一些背景信息,例如editing-mode
和keymap
之间的区别。
特别有用的是混合emacs
键映射的概念,用于插入文本并轻松获取进行更改的vi-command
。
editing-mode
和keymap
之间有什么区别?
只有两种editing-mode
:默认的emacs
和vi
。
GNU Readline Library documentation说:
请注意editing-mode The editing-mode variable controls which default set of key bindings is used. By default, Readline starts up in Emacs editing mode, where the keystrokes are most similar to Emacs. This variable can be set to either `emacs' or `vi'.
editing-mode
和keymap
之间的区别:在editing-mode vi
中,这两个(是的,只有两个,请继续阅读)按键映射会交替使用,以模拟vi
编辑器的不同模式。在editing-mode emacs
中,所有emacs
按键映射同时操作(稍后解释)。
那么editing-mode
到底是做什么的呢?它只是在shell启动时将活动按键映射设置为emacs
或vi-insert
之一。
哪些是独特的按键映射?
Acceptable keymap names are emacs, emacs-standard, emacs-meta, emacs-ctlx,
vi, vi-move, vi-command, and vi-insert.
vi is equivalent to vi-command; emacs is equivalent to emacs-standard.
尽管没有记录,但vi
/vi-command
和vi-move
键位图也是等效的:
+ravi@boxy:~$ diff <(bind -pm vi) <(bind -pm vi-move)
+ravi@boxy:~$
emacs
、emacs-meta
、emacs-ctlx
、vi
和vi-insert
。最好的区分这些按键映射的方法可能是检查它们...
这些按键映射的默认绑定是什么?
要查看(例如)emacs(默认值)的默认按键绑定,请使用:INPUTRC=~/dev/null bash -c 'bind -pm emacs' | grep -v '^#
在上面的示例中,您可以将emacs
替换为任何其他键位图名称。
有许多行包含self-insert
或do-lowercase-version
,它们并不是非常有用,因此要删除它们:
INPUTRC=~/dev/null bash -c 'bind -pm emacs' | grep -vE '^#|: (do-lowercase-version|self-insert)$' | sort
各种emacs
键位图之间有什么区别?
简而言之:它们是应用于editing-mode emacs
的单个映射集的不同视图。
如果将第二个命令的输出分别写入名为emacs-standard
、emacs-meta
、emacs-ctlx
、vi-command
和vi-insert
的文件中,对应其相应的keymap
s,您可以发现:
emacs-meta
和emacs-ctlx
中没有映射的命令在emacs-standard
中也出现了:
$ comm -13 <(sed -r 's/.*: (\S+)/\1/' emacs-standard|sort) <(sed -r 's/.*: (\S+)/\1/' emacs-ctlx|sort)
$ comm -13 <(sed -r 's/.*: (\S+)/\1/' emacs-standard|sort) <(sed -r 's/.*: (\S+)/\1/' emacs-meta|sort)
$
emacs
/emacs-standard
是emacs-ctlx
和emacs-meta
的行为功能上的超集。这意味着:
keymap emacs
"\eg": glob-expand-word
"\C-x\C-r": re-read-init-file
功能上等同于:
keymap emacs-meta
"g": glob-expand-word
keymap emacs-ctlx
"\C-r": re-read-init-file
+ravi@boxy:~/lib/readline$ comm -12 vi-insert emacs-standard |wc -l
28
+ravi@boxy:~/lib/readline$
emacs
/emacs-standard
基本上是 vi-insert
的超集。因此,在输入文本时,只要你可以轻松地在 emacs 和 vi-command 之间切换,最好使用 emacs-standard
键位映射而不是 vi-insert
。
vi-insert
中唯一不在 emacs-standard
中的附加绑定是:
+ravi@boxy:~/lib/readline$ comm -23 vi-insert emacs-standard
"\C-d": vi-eof-maybe
"\C-n": menu-complete
"\C-p": menu-complete-backward
"\e": vi-movement-mode
emacs
绑定冲突:"\C-d": delete-char
"\C-n": next-history
"\C-p": previous-history
set keymap emacs
"\e": "kj" # see https://unix.stackexchange.com/questions/303631/how-can-i-setup-a-hybrid-readline-with-emacs-insert-mode-and-vi-command-mode
"\C-d": delete-char # eof-maybe: ^D does nothing if there is text on the line
"\C-n": menu-complete
"\C-p": menu-complete-backward
"\C-y": previous-history # historY
"\e\C-y": previous-history
编辑模式 vi
正如我们在上面看到的那样,vi
、vi-command
和vi-move
是同一个按键映射:
+ravi@boxy:~$ diff <(bind -pm vi) <(bind -pm vi-move)
+ravi@boxy:~$
如果你不熟悉 vi
编辑器,那么一开始使用 vi-command
键可能会感到很困难,但如果你熟练掌握它,就可以像一个长须巫师一样编辑文本。
从man readline
(我强调)中获取:
合法的按键映射名称包括emacs,emacs-standard,emacs-meta,emacs-ctlx,vi,vi-move,vi-command,以及vi-insert。 vi相当于vi-command。
因此,在你的inputrc
中,你可以为不同的模式指定不同的按键绑定。例如,在command
模式下,你可以使用Altp复制前一个命令的最后一个参数,但是这个绑定在insert
模式下没有效果(在这种简单的设置中)。
set editing-mode vi
set keymap vi-command
# these are for vi-command mode
"\e[A": history-search-backward
"\e[B": history-search-forward
"\ep": yank-last-arg
set keymap vi-insert
# these are for vi-insert mode
"\e[A": history-search-backward
"\e[B": history-search-forward
Control-l: clear-screen
"\ep"
是 ESC
+ p
,而 "\e[A"
是 ESC
+ [
,SHIFT
+ a
。 - Eddie