/ / pareditのキーバインドを変更できないのはなぜですか-emacs、キーボードショートカット、elisp、paredit

pareditのキーバインドを変更できないのはなぜですか?emacs、keyboard-shortcuts、elisp、paredit

すべてのキーバインディングをロードせずに、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でキーバインディングがどのように機能するかをもっと理解したかったのです。

回答:

回答№1は4

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はとにかくバインディングを追加するため、これを変更しても意味がありません。

私が言ったように、あなたはそのキーのすべてを定義解除することによって既存のキーマップを手動でクリアしなければなりません。

TL; DR:本当にSmartparensを使用してください!それはPareditのすべてをカバーし、柔軟性があり、強力で、拡張可能であり、要するにそれはちょうど良いです。また、必要なキーバインディングを選択できます。


回答№2の場合は3

lunaryornの答えを最初に読んでください。これは単なる説明です。

あなたのコードで正確に何が壊れているのか

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

これは、すでにロードされているモードでは機能しません。 paredit 特別ではありません。

Pareditのdefvarの軽視は、バインドを解除するのが非常に難しいことを意味します あなたが望むようにすべてのキー。


回答№3の場合は3

自分だけのマイナーモードを作ってみませんか?Paredit Modeが行うのはキーバインディングを提供することだけなので、そのキーマップを壊しても何もしません。 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)))