临时覆盖(全局覆盖 emacs 中的键绑定)

Override (globally override key binding in emacs) temporarily

我使用此处所述的方法:globally-override-key-binding-in-emacs

(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."
  ;; Define-minor-mode will use `my-keys-minor-mode-map' for us.
  :init-value t
  :lighter " my-keys")

(defun my-keys-keep-on-top (&rest _)
  "Try to ensure that my keybindings always have priority."
  (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))))
(add-hook 'after-load-functions #'my-keys-keep-on-top)

(my-keys-minor-mode 1)

如何明确覆盖它? link 中的方法对我不起作用。

编辑2:

问题不仅适用于只读模式。 eval-after-load 不是一个好方法,因为它会长期改变 my-minor-mode-keymap

我在这里放另一个例子:

我大部分时间都使用程序模式。假设我想让 C-q 绑定到程序模式下的语法检查。但是,有时我会以文本模式记笔记。在文本模式下进行语法检查是没有意义的。所以我决定让 C-q 绑定到拼写检查。

一般情况下,我会这样做

(global-set-key (kbd "C-q") 'syntax-check)
(define-key text-mode-map (kbd "C-q") 'spell-check)

如果我定义my-keys-minor-mode-map怎么会有这样的效果? 假设我把它放在我的键盘映射中:

(define-key 'my-keys-minor-mode-map (kbd "C-q") 'syntax-check)

(define-key text-mode-map (kbd "C-q") 'spell-check) 不起作用,因为我的键盘映射总是优先于其他次要模式映射。

都没有

(eval-after-load "text-mode"
  (define-key my-keys-minor-mode-map (kbd "C-q") 'spell-check))

也不

(add-hook 'text-mode-map (lambda () 
  (define-key my-keys-minor-mode-map (kbd "C-q") 'spell-check)))

做得很好,因为他们会长期更改 my-keys-minor-mode-map。这意味着当我从文本模式切换回程序模式时,我失去了语法检查功能。

编辑:

例如,

(define-key my-keys-minor-mode-map (kbd "<return>") 'newline-and-indent)

这在 99% 的时间都有效,并且可以很好地防止任何其他次要模式或主要模式修改它。

但是,键映射在只读模式下有问题。所以我需要有 "super priority" 函数来重新映射这个键。我想要类似

的东西
(defun super-priority-map()
  (define-key super-my-keys-minor-mode-map (kbd "<return>") 'something-else))
(add-hook 'some-modes 'super-priority-map)

更重要的是,只要离开指定模式,超级优先地图就会起飞。

您是在谈论 read-only 功能?您不能使用键盘映射覆盖它。没有 "read-only" 键盘映射捕获所有击键并发出错误。

要覆盖 read-only-mode,只需关闭 read-only-mode!

在代码中,设置 buffer-read-only 变量。

您还可以 let-bind 代码中的 inhibit-read-only 变量来忽略 所有 read-only 机制(包括特定文本区域的属性 - - 请参阅下面列表中的第 7 级和第 3 级。


Read-only 除了, 其他键盘映射完全有可能优先于您的次要模式映射,但我倾向于说对于任何罕见的冲突使用您的次要模式键映射,您应该直接修改与您自己的键映射冲突的键映射。

您的次要模式键盘映射实际上可以被许多其他键盘映射取代,但您可能通常不希望在更高的优先级上工作。

我建议阅读 Mastering Key Bindings in Emacs,这是对这些东西如何工作的非常易读的解释,我从中获得了以下键盘映射优先级列表:

  1. overriding-terminal-local-map terminal-specific 键绑定。
  2. overriding-local-map 用于应覆盖所有其他本地键盘映射的键。使用这个时要非常小心!
  3. Keymap char 属性 at point for keymaps that is local to the character point is at.这用于 yasnippet 和自定义对话框中的字段之类的东西。
  4. emulation-mode-map-alists 用于高级 multi-mode 键盘映射管理
  5. minor-mode-overriding-map-alist 用于在主要模式中覆盖次要模式使用的键映射。
  6. minor-mode-map-alist 与上面的覆盖版本完全相同,但是为次要模式指定键映射的首选方法。
  7. Keymap text 属性 点类似于上面的字符属性,但仅适用于文本属性。
  8. current-local-map 用于在缓冲区的当前本地映射中定义的键映射
  9. current-global-map 是 Emacs 查找键绑定的最后位置,它是全局键绑定的。

请注意,您的次要模式在级别 6 下工作,高于该级别的所有内容都可以优先。

解除冲突绑定的典型模式是:

(eval-after-load "NAME-OF-LIBRARY"
  '(define-key NAME-OF-KEYMAP (kbd "KEY") nil)) ;; unbind KEY in KEYMAP implemented by LIBRARY

很可能,您还会 添加 原始命令的替换 (non-conflicting) 绑定。

buffer-locally-overriding-minor-mode-key-bindings-in-emacs

将一切结合在一起

(defvar my-keys-minor-mode-map (make-keymap) "my-keys-minor-mode keymap.")

(define-minor-mode my-keys-minor-mode
  "A minor mode so that my key settings override annoying major modes."
  t " my-keys" 'my-keys-minor-mode-map)

(defadvice load (after give-my-keybindings-priority)
  "Try to ensure that my keybindings always have priority."
  (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))))
    (ad-activate 'load)

(defun my-keys-minor-mode-override (key def)
  "Overrides a minor mode keybinding for the local
   buffer, by creating or altering keymaps stored in buffer-local
   `minor-mode-overriding-map-alist'."
    (let* ((oldmap (cdr (assoc 'my-keys-minor-mode minor-mode-map-alist)))
           (newmap (or (cdr (assoc 'my-keys-minor-mode minor-mode-overriding-map-alist))
                     (let ((map (make-sparse-keymap)))
                       (set-keymap-parent map oldmap)
                       (push `(my-keys-minor-mode . ,map) minor-mode-overriding-map-alist) 
                       map))))
  ;; (make-local-variable 'minor-mode-overriding-map-alist)
  (define-key newmap key def)))

(my-keys-minor-mode 1)

它能做的是:

(define-key my-keys-minor-mode-map (kbd "C-i") 'backward-char)

定义比其他次要模式高优先级的键绑定。

(add-hook 'text-mode-hook (lambda ()
    (my-keys-minor-mode-override (kbd "C-i") 'forward-char)))

临时覆盖高优先键绑定。

甜蜜