旧答案

旧答案

我想要一种混合模式,默认情况下我可以使用所有默认keymap emacs键绑定,并且仍然能够更改为vi-command模式。

我该如何设置?

答案1

我读@汤姆·黑尔的答案 这里这里

我认为更好的方法是将vi-insert绑定移动到,而不是将绑定移动到。原因是因为有切换到的绑定,并且很难模拟功能以使其切换到模式。emacsemacsvi-insertvi-commandvi-insertemacs

例如,A命令 invi-command默认为vi-append-eol(附加在行尾并切换到vi-insert)。

您无法A切换到emacs模式,因为它绑定到函数而不是宏。

例如,这行不通

"A": vi-append-eol emacs-editing-mode

也不是这个,使用@汤姆·黑尔回答

"A": vi-append-eol "\ee"

你可以这样做:

"A": "$a\ee"

但现在这取决于"a",vi-append-mode命令,它也需要反弹。"a"那么就可以继续前进了"i""i"可以切换到emacs.有一个完整的命令链需要转换为宏,这是一件很痛苦的事情。

因此,您最好将emacs绑定移至vi-insert.


因此,我们想要设置vi-insert唯一的绑定,emacs 并且如果它们对于相同的按键序列具有不同的绑定,我们想要决定使用哪个绑定。如果它们具有完全相同的绑定,我们将忽略它们。

可以使用以下命令完成此操作

comm -3\
  <(INPUTRC=/dev/null bash -c 'bind -pm emacs' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) \
  <(INPUTRC=/dev/null bash -c 'bind -pm vi-insert' |
    LC_ALL='C' grep -vE '^#|: (do-lowercase-version|self-insert)$' |
    sort) | cat

| cat解释了存在的原因这里

丢弃-3“完全相同的绑定”,因此您浏览此列表并在左列中查找绑定。对于左列上的每个绑定:

如果同一按键序列存在重复绑定,例如

"\C-d": delete-char
    "\C-d": vi-eof-maybe

选择其中之一。如果您想要vi-insert(右侧),您可以删除这两行,因为我们将添加这些绑定到vi-insert已经具有vi-insert绑定的位置。如果您想要该emacs(左侧),请将其删除vi-insert

如果右列 ( ) 上存在唯一绑定vi-insert,例如

    "\e": vi-movement-mode

删除它,因为 `vi-insert 已经有它了。

其余的绑定将位于左列 ( emacs)。不要管这些,因为我们会将它们添加到vi-insert.


这是我选择添加到的.inputrc绑定。emacsvi-insert

我决定不使用"kj"切换到vi-commandin@汤姆·黑尔回答因为可以用它来完成"\ee"将您从 带到 的任务emacsvi-insert然后再完成另一个"\e"将您从vi-insert带到 的任务vi-command。其实有除 blackjack 外包含 kj 的单词带jk的单词(主要是地名)

我保留"\C-d": delete-char并扔掉了"\C-d": vi-eof-maybe。因为我可以只使用Enterforvi-eof-maybe并且我不想通过按意外退出 readline "\C-d"。这意味着删除"\C-d": vi-eof-maybe绑定,因为我们正在使用绑定覆盖 modevi-eof-maybe中的绑定。vi-insertdelete-char

我保留"\C-n": menu-complete而不是"\C-n": next-history因为我可以使用向下箭头next-history。这意味着删除两个绑定,因为vi-insert已有menu-complete绑定。

我保留"\C-p": menu-complete-backward而不是"\C-p": previous-history因为我可以按向上箭头previous-history。这意味着删除两个绑定,因为vi-insert已有menu-complete-backward绑定。

我保留"\C-w": vi-unix-word-rubout而不是"\C-w": unix-word-rubout.我不知道有什么区别。我只是坚持其中vi-insert一个。这意味着删除两个绑定,因为vi-insert已有vi-unix-word-rubout绑定。

我保留了"\e": vi-movement-mode。这意味着删除此绑定,因为vi-insert已有该vi-movement-mode绑定。

set editing-mode vi

set keymap emacs
"\ee": vi-editing-mode

set keymap vi-command
"\ee": emacs-editing-mode

# key bindings to get out of vi-editing-mode
set keymap vi-insert
"\ee": emacs-editing-mode

# emacs keybindings in vi-insert mode
"\C-@": set-mark
"\C-]": character-search
"\C-_": undo
"\C-a": beginning-of-line
"\C-b": backward-char
"\C-d": delete-char
"\C-e": end-of-line
"\C-f": forward-char
"\C-g": abort
"\C-k": kill-line
"\C-l": clear-screen
"\C-o": operate-and-get-next
"\C-q": quoted-insert
"\C-x!": possible-command-completions
"\C-x$": possible-variable-completions
"\C-x(": start-kbd-macro
"\C-x)": end-kbd-macro
"\C-x*": glob-expand-word
"\C-x/": possible-filename-completions
"\C-x@": possible-hostname-completions
"\C-x\C-?": backward-kill-line
"\C-x\C-e": edit-and-execute-command
"\C-x\C-g": abort
"\C-x\C-r": re-read-init-file
"\C-x\C-u": undo
"\C-x\C-v": display-shell-version
"\C-x\C-x": exchange-point-and-mark
"\C-xe": call-last-kbd-macro
"\C-xg": glob-list-expansions
"\C-x~": possible-username-completions
"\e ": set-mark
"\e!": complete-command
"\e#": insert-comment
"\e$": complete-variable
"\e&": tilde-expand
"\e*": insert-completions
"\e-": digit-argument
"\e.": insert-last-argument
"\e.": yank-last-arg
"\e/": complete-filename
"\e0": digit-argument
"\e1": digit-argument
"\e2": digit-argument
"\e3": digit-argument
"\e4": digit-argument
"\e5": digit-argument
"\e6": digit-argument
"\e7": digit-argument
"\e8": digit-argument
"\e9": digit-argument
"\e<": beginning-of-history
"\e=": possible-completions
"\e>": end-of-history
"\e?": possible-completions
"\e@": complete-hostname
"\e\C-?": backward-kill-word
"\e\C-]": character-search-backward
"\e\C-e": shell-expand-line
"\e\C-g": abort
"\e\C-h": backward-kill-word
"\e\C-i": dynamic-complete-history
"\e\C-r": revert-line
"\e\C-y": yank-nth-arg
"\e\\": delete-horizontal-space
"\e\e": complete
"\e^": history-expand-line
"\e_": insert-last-argument
"\e_": yank-last-arg
"\eb": backward-word
"\ec": capitalize-word
"\ed": kill-word
"\ef": forward-word
"\eg": glob-complete-word
"\el": downcase-word
"\en": non-incremental-forward-search-history
"\ep": non-incremental-reverse-search-history
"\er": revert-line
"\et": transpose-words
"\eu": upcase-word
"\ey": yank-pop
"\e{": complete-into-braces
"\e~": complete-username

更新

我想我做得更好了一点。有一段时间,我重新打开了"jk"切换到的命令,vi command因为按下"\e"切换到vi-command有一个延迟,因为很多emacs命令转移到了作为领导者vi-insert使用。"\e"

这表明"jk"moshing 已被注释掉。我目前使用"\ee"循环模式。我没有解除从到 的"\e"绑定,因为我认为没有必要。因此,它的效果是,如果您按入并等待,您将转到。vi-insertvi-command"\e"vi-insertvi-command

要从 到vi-commandvi-insert您只需按命令之一,例如"A""i"so ,允许在 3 种模式之间循环不会有什么坏处,因为您也可以在 2 种vi模式之间循环。

set keymap emacs
"\ee": vi-editing-mode

set keymap vi-command
"\ee": emacs-editing-mode

# key bindings to get out of vi-editing-mode
set keymap vi-insert
# Choose one of these editor switching modes
# 
# moosh jk to switch
#"\ee": emacs-editing-mode
#"\ejk": vi-movement-mode
#"\ekj": vi-movement-mode
#
# "\ee" to cycle
# can unmap "\e" to switch to vi-command but don't see a need
#"\e":
"\ee": vi-movement-mode

更新

在 中vi-insert"\C-w"绑定到 `vi-unix-word-rubout,它在单词边界或其他地方停止。我不喜欢这个功能。

例如,尝试这个

$ cannot-delete'
# press left arrow to go back behind the single quote
# press \C-w in vi-insert to try to delete cannot-delete, it won't work

这个错误报告描述了问题,尽管我对提供的示例没有问题。

所以你可以绑定"\C-w"到 emacsunix-word-rubout来解决这个问题。

要重新绑定"\C-w",您可能需要取消绑定默认值

# In .bashrc
stty werase undef

如果您想解除所有默认值的绑定:

# In .inputrc
set bind-tty-special-chars off

不确定这是否重要,但我使用的是 macOS,所以有我删除的其他默认绑定

然后在你的.inputrc

"\C-w": unix-word-rubout

答案2

以下.inputrc行允许Meta / Alt+在和模式E之间切换。emacsvi-insert

j同时哞哞k将带你进入vi-command模式。

注意:唯一带有“kj”的英文单词是“blackjack”,没有单词包含“jk”)

set show-mode-in-prompt on

set keymap emacs
"\ee": vi-editing-mode
"jk": "\eejk"
"kj": "\eejk"

set keymap vi-insert
"\ee": emacs-editing-mode
"jk": vi-movement-mode
"kj": vi-movement-mode

set keymap vi-command
"\ee": emacs-editing-mode

注意:在v4.3.11(1) 中,如果您在bashto 下添加绑定以尝试直接切换到键盘映射,则提示不会更新(如果您有 ),因此需要此解决方法。keymap emacsvi-movement-modevi-commandshow-mode-in-prompt on


有趣的事实:

mode特有的绑定只有 4 个vi-insert,可以轻松添加到emacsmode 中:

"\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" # needs to be below "kj" mapping
"\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

旧答案

emacs在我可以直接从to之前,我就是这样做的vi-command。它涉及将所有默认emacs命令导入到vi-insert键盘映射中。

获取默认值emacs-standardvi-insert映射:

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

仅获取来自以下位置的添加内容emacs-standard

comm -23  emacs-standard vi-insert > vi-insert-emacs-additions

然后,在您的 中,在以下行下~/.inputrc添加以下内容:vi-insert-emacs-additions

(echo set editing-mode vi && echo set keymap vi-insert && cat vi-insert-emacs-additions) >> ~/.inputrc

为了您的方便,在 bash 4.3.11(1)-release 上,vi-insert-emacs-additions内容为:

"\C-a": beginning-of-line
"\C-b": backward-char
"\C-]": character-search
"\C-d": delete-char
"\C-e": end-of-line
"\C-f": forward-char
"\C-g": abort
"\C-k": kill-line
"\C-l": clear-screen
"\C-n": next-history
"\C-o": operate-and-get-next
"\C-p": previous-history
"\C-q": quoted-insert
"\C-@": set-mark
"\C-_": undo
"\C-x\C-?": backward-kill-line
"\C-x\C-e": edit-and-execute-command
"\C-x\C-g": abort
"\C-x\C-r": re-read-init-file
"\C-x\C-u": undo
"\C-x\C-v": display-shell-version
"\C-x\C-x": exchange-point-and-mark
"\C-xe": call-last-kbd-macro
"\C-x)": end-kbd-macro
"\C-xg": glob-list-expansions
"\C-x*": glob-expand-word
"\C-x!": possible-command-completions
"\C-x/": possible-filename-completions
"\C-x@": possible-hostname-completions
"\C-x~": possible-username-completions
"\C-x$": possible-variable-completions
"\C-x(": start-kbd-macro
"\e0": digit-argument
"\e1": digit-argument
"\e2": digit-argument
"\e3": digit-argument
"\e4": digit-argument
"\e5": digit-argument
"\e6": digit-argument
"\e7": digit-argument
"\e8": digit-argument
"\e9": digit-argument
"\eb": backward-word
"\e<": beginning-of-history
"\e\C-?": backward-kill-word
"\ec": capitalize-word
"\e\C-]": character-search-backward
"\e\C-e": shell-expand-line
"\e\C-g": abort
"\e\C-h": backward-kill-word
"\e\C-i": dynamic-complete-history
"\e!": complete-command
"\e/": complete-filename
"\e@": complete-hostname
"\e{": complete-into-braces
"\e~": complete-username
"\e$": complete-variable
"\e\C-r": revert-line
"\e\C-y": yank-nth-arg
"\e\\": delete-horizontal-space
"\e-": digit-argument
"\ed": kill-word
"\e\e": complete
"\e>": end-of-history
"\ef": forward-word
"\eg": glob-complete-word
"\e^": history-expand-line
"\e#": insert-comment
"\e*": insert-completions
"\e_": insert-last-argument
"\e.": insert-last-argument
"\el": downcase-word
"\en": non-incremental-forward-search-history
"\ep": non-incremental-reverse-search-history
"\e=": possible-completions
"\e?": possible-completions
"\er": revert-line
"\e ": set-mark
"\e&": tilde-expand
"\et": transpose-words
"\eu": upcase-word
"\e_": yank-last-arg
"\e.": yank-last-arg
"\ey": yank-pop

keymap emacs注意:如果您在 to下添加绑定vi-movement-mode以尝试直接切换到vi-command模式,则提示不会更新(如果您有show-mode-in-prompt on.

这就是为什么上述解决方案将emacs绑定添加到vi-insert.这会导致更长的时间.inputrc,但对于完整的解决方案来说是必需的。

相关内容