全局覆盖Emacs中的键绑定


100

如何设置全局覆盖并优先于该键的所有其他绑定的键绑定?我想覆盖所有主要/次要模式映射,并确保我的绑定始终有效。

这当然不起作用:

(global-set-key "\C-i" 'some-function)

它起作用text-mode,但是当我使用时lisp-modeC-i反弹到lisp-indent-line

我可以lisp-mode逐个遍历并在其他所有模式下覆盖此绑定,但是必须有一种更简单的方法。每次我为新文件类型安装新模式时,都必须返回并检查以确保所有键绑定都不会被新模式覆盖。

我想这样做是因为我想模仿我已经从其他编辑者那里学到的根深蒂固的绑定。

Answers:


149

我对所有“覆盖”键绑定使用次要模式:

(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)

这样做还有一个好处,就是能够一举关闭我的所有修改(只需禁用次要模式),以防有人驱动键盘或需要查看默认按键绑定的功能。

请注意,您可能需要在迷你缓冲区中将其关闭:

(defun my-minibuffer-setup-hook ()
  (my-keys-minor-mode 0))

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)

1
这似乎是个好主意。有什么方法可以确保您的次要模式与其他次要模式不冲突?
Brian Carper

3
确保您的次要模式在列表minor-mode-map-alist上是第一个。
Trey Jackson

2
特雷是对的。通常,将其放在.emacs末尾就足够了。而且,您将覆盖的大多数绑定都是主要模式正在设置的绑定...次要模式通常不会妨碍您。
scottfrazer

我采用了这种方法,但是后来我意识到我绑定到Ci的任何内容也都绑定到了TAB键。有什么建议?
史蒂夫

3
Brian Carper:这是处理后续加载的次要模式的增强功能:stackoverflow.com/questions/683425/…–
phils

30

作为scottfrazer答案的补充,我编写了以下内容,即使后续加载的库引入了自己的新键映射,我的键绑定也保持优先级。

因为可以在编译时生成键映射,所以这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

@alper我建议您发布一个包含所有相关详细信息的问题,包括您实际使用的代码,以及重现该问题的特定示例/食谱。
phils


14

我在搜索“ emacs undefine org mode keybindings”时发现了这个问题,因为我想解除现有的Cc Cb行为的绑定,以允许我的全局映射能够在org缓冲区中工作。

这最终成为我最简单的解决方案:

(add-hook 'org-mode-hook
      (lambda ()
        (local-unset-key (kbd "C-c C-b"))))

1
这是特定于模式的,即使适用于您的单个用例,也无法解决更大的问题。
RichieHH

12

尽管scottfrazer的答案恰好是您所要的,但我将为后代提及另一种解决方案。

Emacs手册

“不要在Lisp程序中将Cc字母定义为键。由Cc和一个字母(大写或小写)组成的序列是为用户保留的;它们是为用户保留的唯一序列,因此请不要阻塞它们。”

如果您将个人全局绑定绑定到Cc加一个字母,那么“应该”是安全的。但是,这仅仅是一个约定,任何模式仍然可以覆盖您的绑定。


3
我没想到所有模式下的org-mode都会打破这一规则。“ Cc Ch”告诉我Cc a,b,c和l分别绑定到org-agenda,org-iswitchb,org-capture和org-store-link。
内特·帕森斯

7
Afaik绑定这些是组织模式建议的第一步,以便使用它,但是用户必须自己定义它们(即默认情况下未完成),并且可以在选择时进行选择。(也是,因为这些绑定应该是全局的,而不是组织主要模式的绑定)
Nikana Reklawyks 2012年

3

如果要“始终使用映射中的键绑定,除非我为特定的模式映射显式覆盖它们”,并假设您正在使用scottfrazier的方法,则需要:

(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)

应该仅从当前缓冲区的次要模式中删除“ \ Ci”绑定。警告:这是完全未经测试的,但似乎是正确的方法。设置父级而不是仅仅应付my-keys-minor-mode-map的全局值的意义在于,这样以后对全局值的任何更改都会自动反映在本地值中。


2

我认为你不能。这大致相当于说您要定义一个全局变量,该变量不能被函数中的局部变量声明隐藏。范围就是这样。

但是,可能有一种方法可以编写一个elisp函数来浏览模式列表,然后为您重新分配它。


这种范围界定的想法在技术上是正确的,但overriding-local-map经过专门设计可覆盖所有其他地图。但是,使用它很危险。
event_jr 2014年

2

除非您真的想自己做,否则应该检查一下是否有其他人这样做了。

有一个Emacs软件包,它提供了类似于Windows的键绑定。您应该可以通过Google找到它。


4
您正在考虑的软件包可能是cua-mode
德鲁

1
是的,那是包裹。
JesperE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.