为什么我不能更改paredit的按键绑定?

9

我想只使用paredit中的几个功能,而不加载所有按键绑定。查看paredit.el文件,我发现唯一的键位映射是paredit-mode-map,所以我尝试了以下方法。

(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-M-left>") 'paredit-backward)

它没有改变按键绑定(通过C-h k检查),但变量paredit-mode-map已经被修改。

我也尝试了

(eval-after-load "paredit"
  '(progn
     (setq paredit-mode-map (make-sparse-keymap))
     (define-key paredit-mode-map (kbd "<C-M-left>") 'paredit-backward)))

然后尝试开启或关闭paredit,但结果相同。

在此之前,我直接更改密钥映射一直有效。这里发生了什么?

编辑:

我通过以下方式成功更改了密钥映射:

; Remove old paredit bindings
(defun take-from-list (condp list)
  "Returns elements in list satisfying condp"
  (delq nil
    (mapcar (lambda (x) (and (funcall condp x) x)) list)))
(setq minor-mode-map-alist 
      (take-from-list 
        (lambda (x) (not (eq (car x) 'paredit-mode))) 
        minor-mode-map-alist))

; Create new paredit-mode-map
(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-kp-enter>") 'paredit-backward)

; Add the new paredit-mode-map to minor-mode-map-alist
(setq minor-mode-map-alist (append
                (list (append (list 'paredit-mode) paredit-mode-map))
                minor-mode-map-alist))

看起来minor-mode-map-alist是用于查找的变量。我相信有更优雅的方法来改变键绑定,但我想更多地了解在emacs中键绑定的工作原理。


你可能想看一下Smartparens。它涵盖了几乎所有的Paredit功能(甚至更多),并且不强制执行特定的按键绑定。你可以选择两个内置的绑定集之间进行选择,但是你也可以轻松地定义自己的绑定 - user355252
3个回答

5
Paredit使用不同的方式定义键映射。大多数次要模式在变量定义中定义键映射,而Paredit在顶层调用“paredit-define-keys”,因此强制初始化键映射。换句话说,您无法阻止Paredit设置其绑定。您需要使用“(define-key paredit-mode-map … nil)”删除键映射中的所有键绑定以摆脱这些绑定。
编辑:通过将新的键映射分配给变量来“重置”键映射是不行的。“(setq paredit-mode-map…)”会更改变量“paredit-mode-map”的值,但不会更改Paredit模式实际使用的键映射。
此变量的绑定仅在定义时计算一次,即在计算“define-minor-mode”期间。此宏在内部调用“add-minor-mode”,并将键映射变量的当前值传递给该函数。将来使用该模式将仅引用此键映射。此次次要模式不会再次计算键映射变量,因此更改其绑定根本没有任何效果。如果要更改键映射,则必须在评估“define-minor-mode”之前重新绑定变量。换句话说,在加载相应的库之前。在“eval-after-load”表单中更改它完全没有用处。通常,在库加载之前更改键映射变量有效,因为大多数模式在“defvar”体内定义键映射。但是,“defvar”不会更改变量的值,如果它已经有一个值。因此,如果变量已经具有键映射,则不会被修改。然而,正如我所说,Paredit不遵守这种模式,而是强制将其绑定添加到键映射中。因此,更改它是无意义的,因为Paredit将无论如何添加其绑定。就像我说的,您必须手动清除现有键映射,取消定义每个键。简而言之:真的用Smartparens吧!它涵盖了所有的Paredit,灵活,强大,可扩展,总之它很好。它让您选择任何想要的键绑定。

但是看看paredit-define-keys,它所做的就是使用(define-key paredit-mode-map ...)来设置键。那么为什么当paredit-mode-map为空时,按键绑定不会消失呢?当paredit-mode-map为空时,按键绑定如何工作? - snowape
换句话说:我知道我不能阻止设置键绑定,但我不明白为什么之后不能更改它们。 - snowape
你不能使用 setq 重置键位映射。我已经更新了我的答案以澄清这一点。 - user355252
3
Smartparens在哲学上与paredit不同。 paredit会改变你的思维方式,使其以S表达式为中心。 Smartparens似乎并不关心这一点。就我个人而言,我曾经非常难以适应paredit的理念,但是现在我已经适应了,我再也不会回去了。 - event_jr
@event_jr 更确切地说,Smartparens不会强加哲学观念给用户。内置的键绑定不会迫使您进行Sexp中心的编辑,而只是增强了编辑器以满足您的要求。但是,通过选择适当的键绑定集,您可以像使用Paredit一样完全使用Smartparens。我已经用Smartparens替换了Paredit,并没有失去方便性。但是,当然,YMMV(因人而异)。 - user355252
3
"force"是准确的。虽然我受益于被迫的经历。 - event_jr

4

请先阅读lunaryorn的回答。这只是一个澄清。

你的代码到底有什么问题

(setq paredit-mode-map (make-sparse-keymap))

这将不适用于任何已加载的模式。paredit并不特别。

Paredit对defvar的不尊重意味着您很难像您希望的那样取消绑定所有按键。


你误解了:Smartparens与Paredit并不以相同的方式定义键。事实上,默认情况下它根本不定义任何键,除非你在init文件中显式调用其中一个按键绑定函数。正如我在对问题的评论中所说,你可以完全忽略内置命令,并定义自己的键位图。我已经这样做了。 - user355252

3
为什么不自己创建一个次要模式?所有Paredit模式提供的只是键绑定,所以如果您覆盖了它的键映射,它对您没有任何作用。无论您是否使用Paredit模式,都可以使用paredit命令。(没有人会强制施加键绑定给您!)
(defvar snowape-mode-map (make-sparse-keymap))
(define-minor-mode snowape-mode
  "Minor mode for snowape's favorite pareditoid key bindings.
\\<snowape-mode-map>"
  :lighter " Snowape")
(define-key snowape-mode-map (kbd "C-M-<left>") 'paredit-backward)
...

或者,您可以在喜欢的模式挂钩中使用 local-set-key

(add-hook 'lisp-mode-hook
  (defun lisp-mode-snowape-setup ()
    (local-set-key (kbd "C-M-<left>") 'paredit-backward)))

是的,我像这样使用local-set-key。我提出这个问题的主要原因是因为我很好奇emacs中的按键绑定是如何工作的。 - snowape
1
根据Emacswiki的说法,“ParEdit帮助保持括号平衡”,因此这个答案可能是不正确的。 - The Unfun Cat

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