在 Emacs 中全局覆盖键绑定
Posted
技术标签:
【中文标题】在 Emacs 中全局覆盖键绑定【英文标题】:Globally override key binding in Emacs 【发布时间】:2010-10-15 13:37:55 【问题描述】:如何设置全局覆盖并优先于该键的所有其他绑定的键绑定?我想覆盖所有主要/次要模式映射并确保我的绑定始终有效。
这当然行不通:
(global-set-key "\C-i" 'some-function)
它在text-mode
中工作,但是当我使用lisp-mode
时,C-i
会反弹到lisp-indent-line
。
我可以在lisp-mode
和其他所有模式中单独遍历并覆盖此绑定,但必须有更简单的方法。每次我为新文件类型安装新模式时,我都必须返回并检查以确保我的所有键绑定都没有被新模式覆盖。
我想这样做是因为我想模仿我已经从其他编辑器那里学到并根深蒂固的绑定。
【问题讨论】:
交叉引用,随后在emacs.stackexchange.com/questions/352/…复制 【参考方案1】:我对所有“覆盖”键绑定使用次要模式:
(defvar my-keys-minor-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-i") 'some-function)
map)
"my-keys-minor-mode keymap.")
(define-minor-mode my-keys-minor-mode
"A minor mode so that my key settings override annoying major modes."
:init-value t
:lighter " my-keys")
(my-keys-minor-mode 1)
这还有一个额外的好处,就是能够一举关闭我的所有修改(只需禁用次要模式),以防其他人正在使用键盘,或者如果我需要查看默认键绑定的作用。
请注意,您可能需要在 minibuffer 中将其关闭:
(defun my-minibuffer-setup-hook ()
(my-keys-minor-mode 0))
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)
【讨论】:
这似乎是个好主意。有什么方法可以确保您的次要模式不会与其他次要模式发生冲突? 确保您的次要模式在列表 minor-mode-map-alist 的第一个。 特雷是对的。通常把它放在 .emacs 的末尾就足够了。此外,您要覆盖的大多数绑定都是主要模式正在设置的绑定......次要模式通常不会妨碍。 我遵循了这种方法,但后来我意识到我绑定到 C-i 的任何东西也会绑定到 TAB 键。有什么建议吗? Brian Carper:这是处理后续加载的次要模式的增强功能:***.com/questions/683425/…【参考方案2】:作为对scottfrazer's answer 的补充,我编写了以下内容,以便我的键绑定保持优先级,即使随后加载的库引入了它们自己的新键映射。
由于可以在编译时生成键映射,load
似乎是执行此操作的最佳位置。
(add-hook 'after-load-functions 'my-keys-have-priority)
(defun my-keys-have-priority (_file)
"Try to ensure that my keybindings retain priority over other minor modes.
Called via the `after-load-functions' special hook."
(unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
(let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
(assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
(add-to-list 'minor-mode-map-alist mykeys))))
【讨论】:
我粘贴了你的脚本,但没有任何影响:( @alper 我建议您发布一个包含所有相关详细信息的问题,包括您实际使用的代码,以及重现问题的特定示例/配方。【参考方案3】:安装use-package
, eval 就完成了:
(require 'bind-key)
(bind-key* "C-i" 'some-function)
【讨论】:
只安装 bind-key 就足够了,尽管 use-package 依赖于 bind-key。 这个('bind-key'包)似乎是最方便的解决方案;感谢分享。 它在minibuffer-setup-hook
上被禁用了吗?【参考方案4】:
我在搜索“emacs undefine org mode keybindings”时发现了这个问题,因为我想取消绑定现有的 C-c C-b 行为,以允许我的全局映射在 org 缓冲区中工作。
这对我来说是最简单的解决方案:
(add-hook 'org-mode-hook
(lambda ()
(local-unset-key (kbd "C-c C-b"))))
【讨论】:
这是特定于模式的,即使它适用于您的单个用例,也不能解决更大的问题。【参考方案5】:虽然 scottfrazer 的答案正是您所要求的,但我会为后人提及另一种解决方案。
来自The Emacs Manual:
"在 Lisp 程序中不要将 Cc 字母定义为键。由 Cc 和字母(大写或小写)组成的序列是为用户保留的;它们是为用户保留的唯一序列,所以不要阻止它们。”
如果您将您的个人全局绑定绑定到 C-c 加上一个字母,那么您“应该”是安全的。但是,这只是一个约定,任何模式仍然可以覆盖您的绑定。
【讨论】:
我没想到所有模式中的 org-mode 会打破这个规则。 `C-c C-h' 告诉我 C-c a、b、c 和 l 分别绑定到 org-agenda、org-iswitchb、org-capture 和 org-store-link。 Afaik,绑定这些是 org-mode 建议使用它的第一步,但用户必须自己定义它们(即默认情况下不完成),并且可以在执行时选择任何其他所以。 (另外,这是因为这些绑定应该是全局的,而不是绑定到 org 主模式)C-c b
是no longer suggested in the manual。【参考方案6】:
如果您想“始终使用映射中的键绑定,除非我为特定模式映射显式覆盖它们”,并假设您使用的是 scottfrazier's approach,您想要:
(defun locally-override (key cmd)
(unless (local-variable-p 'my-keys-minor-mode-map)
(set (make-variable-buffer-local 'my-keys-minor-mode-map)
(make-sparse-keymap))
(set-keymap-parent my-keys-minor-mode-map
(default-value 'my-keys-minor-mode-map)))
(define-key my-keys-minor-mode-map key cmd))
所以
(locally-override "\C-i" nil)
应仅从当前缓冲区的次要模式中删除“\C-i”绑定。警告:这完全未经测试,但似乎是正确的方法。设置父级而不是仅仅处理 my-keys-minor-mode-map 的全局值的重点是,以后对全局值的任何更改都会自动反映在本地值中。
【讨论】:
【参考方案7】:我不认为你可以。这大致相当于说要定义一个不能被函数中的局部变量声明隐藏的全局变量。 Scope 就不是这样工作的。
但是,可能有一种方法可以编写一个 elisp 函数来遍历模式列表并为您在每个模式列表中重新分配它。
【讨论】:
这种范围界定的想法在技术上是正确的,但overriding-local-map
是专门为覆盖所有其他地图而设计的。但是使用它很危险。【参考方案8】:
除非你真的想自己做,否则你应该四处看看,看看有没有其他人已经做过。
有一个适用于 Emacs 的包,它为您提供类似 Windows 的键绑定。您应该可以通过 google 找到它。
【讨论】:
你想到的包大概是cua-mode
。
是的,就是这个包。【参考方案9】:
在 Emacs 27 中,有
override-global-map
。 然后,您可以执行以下操作:(define-key override-global-map (kbd "M-h") 'backward-kill-word)
这个答案不对,抱歉。
【讨论】:
该键映射在哪里定义? 抱歉,这个键映射是由 Emacs 中不包含的 bind-key 包定义的。我会在我的帖子中声明它。以上是关于在 Emacs 中全局覆盖键绑定的主要内容,如果未能解决你的问题,请参考以下文章