"set keymap vi"是什么意思?

19

我想在终端中使用类似 Vim 的导航,所以我添加了:

set editing-mode vi
set keymap vi

根据这里,我将我的.inputrc文件设置为vi导航模式(editing-mode vi)。那么keymap vi是做什么的,我需要它吗?

2个回答

15

TL;DR

如果你不想在默认键映射中更改/添加绑定,则不需要使用keymap vi

keymap vi的作用是指定任何列在该点之后的绑定适用于该键映射(与vi-commandvi-move完全相同)。

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

如果您想进一步了解vi模式和映射,请跳至标题editing-mode vi(最后一个)。

但是!可能需要一些背景信息,例如editing-modekeymap之间的区别。

特别有用的是混合emacs键映射的概念,用于插入文本并轻松获取进行更改的vi-command

editing-modekeymap之间有什么区别?

只有两种editing-mode:默认的emacsvi

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-modekeymap之间的区别:在editing-mode vi中,这两个(是的,只有两个,请继续阅读)按键映射会交替使用,以模拟vi编辑器的不同模式。在editing-mode emacs中,所有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:~$ 

这样,我们就需要解释以下五个唯一的按键映射:emacsemacs-metaemacs-ctlxvivi-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键位图之间有什么区别?

简而言之:它们是应用于editing-mode emacs的单个映射集的不同视图。

如果将第二个命令的输出分别写入名为emacs-standardemacs-metaemacs-ctlxvi-commandvi-insert的文件中,对应其相应的keymaps,您可以发现:

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-standardemacs-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

你可能会认为第二个形式更易读。
插入文本:emacs vs vi-insert
在emacs-standard中有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 和 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

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

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

请注意,只有两个不同的映射与默认情况下的“编辑模式vi”相关联。
在“编辑模式vi”中,使用的键位映射是“vi” / “vi-command” / “vi-move”和“vi-insert”(起始键位映射)。这两个映射中只有一个是活动状态。
“编辑模式vi”仅设置默认键位映射(标记为“vi-insert”)当shell启动时。一次只能有一个键位映射处于活动状态。“vi-insert”键位映射将大多数键映射到“self-insert”,因此当您按下键盘上的塑料按钮时,其上打印的符号将显示在屏幕上。
“vi-insert”键位映射允许通过使用“vi-movement-mode”命令将其切换到称为“vi-command” / “vi” / “vi-move”的文本操作键位映射。
实际上,即使是“emacs”键位映射也可以使用“vi-movement-mode”命令设置“vi”类似的文本操作键位映射处于活动状态,如上面提到的混合解决方案。
更简单地说,当“vi-insert”键位映射处于活动状态时,按ESC键即可切换到“vi-command”键位映射。
“vi-command”键位映射使用标准的单个按键,如abc来移动和与文本交互,就像“vi”编辑器的默认模式或命令模式一样。通常没有Ctrl+key组合键。您无法在此模式中插入文本;字母键映射到编辑/移动命令。要输入文本,请切换到“vi-insert”键位映射(例如:按下i键进行“插入”)。
在您的“.inputrc”文件中有“editing-mode vi”时,使用“vi-insert”键位映射输入文本。通过在“vi-command”中按下i(或以其他多种方式对于那些了解“vi”的人)可以切换到“vi-insert”键位映射。

如果你不熟悉 vi 编辑器,那么一开始使用 vi-command 键可能会感到很困难,但如果你熟练掌握它,就可以像一个长须巫师一样编辑文本。


信息太多,呈现方式又不够吸引人。您能否用相关事实进行总结,或者使用项目符号之类的方式呈现? - Evan Carroll
我给这个点了踩,因为在我的看法中它太过于不必要地复杂。我请求你删除或至少隔离vi命令和vi插入。还有,这里没有人关心emacs吗?我的意思是这些东西应该只是一个脚注。 - Evan Carroll
我很感激这个答案,如果可能的话,就应该这样给出。一个人分享他的知识,即使我没有解决我的问题,现在我也向前迈了一步。谢谢。 - funder7

12

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

2
FYI,"\ep"ESC + p,而 "\e[A"ESC + [SHIFT + a - Eddie
@LETs 谢谢,当我想要理解魔术字符串时,你给了我第一个提示。然后我找到了进一步的文档 ANSI 转义码 - CSI 序列 - Weekend

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接