在Emacs中,如何在缓冲区内覆盖次要模式键绑定?

19
我想使用一个次要模式来重新绑定一个我确实想保留的主模式键。如何在不全局删除该键的情况下重新绑定它到次要模式映射中?我知道可以使用 define-key 来做到这一点,但我希望在其他缓冲区/主模式中保留绑定。能否有人提供帮助?
3个回答

16

这个操作有点繁琐,你可以像这样做:

(add-hook '<major-mode>-hook
  (lambda ()
    (let ((oldmap (cdr (assoc '<minor-mode> minor-mode-map-alist)))
          (newmap (make-sparse-keymap)))
      (set-keymap-parent newmap oldmap)
      (define-key newmap [<thekeyIwanttohide>] nil)
      (make-local-variable 'minor-mode-overriding-map-alist)
      (push `(<minor-mode> . ,newmap) minor-mode-overriding-map-alist))))

太好了,那个起作用了!我很惊讶这个看似简单的任务如此繁琐... - sebhofer
sebhofer:模式特定键映射的整个意图是它们在该模式处于活动状态时确实在所有地方生效,因此我根本不会称规避该行为的任务为“看似简单”。在这些情况下,这个解决方案看起来非常优雅。 - phils
@phils 从一个有点天真的角度来看,这个任务就是:在给定的缓冲区中覆盖一个按键绑定。我觉得这足够简单了。 - sebhofer

14

这里有一个函数可以处理所有繁琐的部分。

(defun local-set-minor-mode-key (mode 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 mode minor-mode-map-alist)))
         (newmap (or (cdr (assoc mode minor-mode-overriding-map-alist))
                     (let ((map (make-sparse-keymap)))
                       (set-keymap-parent map oldmap)
                       (push `(,mode . ,map) minor-mode-overriding-map-alist) 
                       map))))
    (define-key newmap key def)))

之后你可以执行

(local-set-minor-mode-key '<minor-mode> (kbd "key-to-hide") nil)

3
在我的情况下,当Company完成菜单显示时,company-mode覆盖了cider-repl-mode对M-p和M-n的绑定。完成菜单的键位图是company-active-map,但没有对应于它的小模式(company-mode用于菜单激活时),因此我无法使用任何现有答案。以下是我想到的解决方法:
(add-hook 'cider-repl-mode-hook
          (lambda ()
            (make-local-variable 'company-active-map)
            (setq company-active-map (copy-tree company-active-map))
            (define-key company-active-map (kbd "M-p") nil)
            (define-key company-active-map (kbd "M-n") nil)))

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