18

我想为我的终端提供类似 vim 的导航,所以我添加了:

set editing-mode vi
set keymap vi

以我的文件.inputrc为基础。添加 vi 导航。有什么作用,为什么我需要它?editing-mode vikeymap vi

4

2 回答 2

12

来自man readline(我的重点):

合法的键映射名称集是 emacs、emacs-standard、emacs-meta、emacs-ctlx、vi、vi-move、vi-command 和 vi-insert。 vi 等价于 vi 命令

因此,在您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
于 2012-04-03T23:04:51.553 回答
12

TL;博士

如果您不想更改/添加默认键盘映射中的绑定,则不需要keymap vi.

什么keymap vi是声明在该点之后列出的任何绑定都适用于该键映射(与和完全相同的键映射)。vi-commandvi-move

如果您想更改插入键映射(例如,添加Ctrl-A绑定以在您键入时转到行首),您需要在keymap vi-insert一行下方执行此操作。

如果您想了解有关vi模式和地图的更多信息,请跳至标题editing-mode vi(最后一个)。

可是等等!不过,可能需要一些背景信息:例如,anediting-mode和 a之间的区别keymap

特别有用的是混合emacs键盘映射的概念,用于插入文本,同时仍然很容易vi-command进行更改。

editing-modea 和 a 和有什么不一样keymap

只有两个editing-modes:(emacs默认)和vi.

GNU Readline 库文档说:

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编辑器的不同模式。所有这些emacs都在同一时间运行editing-mode emacs(稍后解释)。

那么editing-mode实际上是做什么的呢?它只是将 shell 启动时的活动键盘映射设置为emacsvi-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-commandvi-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-insertdo-lowercase-version不是很有用,所以删除它们:

INPUTRC=~/dev/null bash -c 'bind -pm emacs' | grep -vE '^#|: (do-lowercase-version|self-insert)$' | sort

各种键盘映射有什么区别emacs

TL;DR:它们是对应用于editing-mode emacs.

如果你将第二条命令的输出放到名为emacs-standard, emacs-meta, emacs-ctlx, , 的文件中vi-command,并vi-insert为它们对应keymap的 s ,你可以发现:

没有映射的命令emacs-metaemacs-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-ctlxemacs-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

你可能会争辩说第二种形式更容易阅读。

插入文本:emacsvsvi-insert

emacs-standardnot in 中有 28 个命令vi-insert

+ravi@boxy:~/lib/readline$ comm -12 vi-insert emacs-standard |wc -l
28
+ravi@boxy:~/lib/readline$

emacs/emacs-standard基本上是vi-insert. 因此,对于键入文本,最好使用emacs-standard键盘映射vi-insert,只要您可以轻松地在之间切换emacsvi-command

vi-insertnot in中唯一的附加绑定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

editing-mode vi

正如我们在上面看到的vivi-commandvi-move同一个键映射:

+ravi@boxy:~$ diff <(bind -pm vi) <(bind -pm vi-move)
+ravi@boxy:~$ 

请注意,总共只有两个不同的地图,默认情况下与editing-mode vi.

当 in 时editing-mode vikeymap使用的 s 是vi//vi-commandvi-movevi-insert起始键映射)。一次只有这两张地图中的一张处于活动状态。

editing-mode vi只是在 shell 启动时设置一个默认的键盘映射,标记为vi-insert. 同样,一次只有一个键盘映射处于活动状态。此vi-insert键盘映射将大多数键映射到,self-insert因此当您按下键盘上的塑料按钮时,印在其上的符号会出现在屏幕上。

vi-insert键盘映射允许自己通过使用命令交换到称为//的文本操作键盘映射,默认vi-command绑定vi到键盘映射中的键。vi-movevi-movement-modeESCvi-insert

实际上,即使是emacs键盘映射也可以vi通过使用命令将类似文本操作的键盘映射设置为活动状态vi-movement-mode,就像上面提到的混合解决方案一样。

或者用更简单的语言...

默认情况下,当键盘映射处于活动状态时,按下ESC可更改为键盘映射。vi-commandvi-insert

键盘映射使用标准的vi-command单个按键,如a,bc来移动文本并与之交互,就像vi编辑器的默认或命令模式一样。通常没有Ctrl+key组合。您不能在此模式下插入文本;字母键映射到编辑/移动命令。要输入文本,请切换到vi-insert键盘映射(例如:按下i“插入”)。

输入文本是使用键盘映射完成的,如果你的文件中vi-insert有,它在 shell 启动时是活动的。通过按下“插入”来切换到键盘映射(或以许多其他方式启动进入)。editing-mode vi.inputrcvi-insertivi-commandvi

除非您了解vi编辑器,否则一开始您可能会发现vi-command键很难使用,但如果您熟练使用它,您可以像大胡子巫师一样编辑文本。

于 2016-08-17T06:13:06.707 回答