フックを使用したメジャーモードキーの設定とモードマップへの追加の違い


13

と呼ばれるメジャーモードをダウンロードしmagical-mode、それに独自の魔法のキーマップがありmagical-mode-mapます。このモードは、バッファのメジャーモードになるmagical-mode-hookたびに実行されるフックも提供しますmagical-mode。次に、initファイルを変更して、そのモードで使用するいくつかのカスタムキーバインディングを追加します。

のカスタムキーバインディングをセットアップする方法は(少なくとも)2つあるようですmagical-mode。私が最も一般的に見るものはこれです:

(defun my-magical-keys ()
  (local-set-key (kbd "C-i") 'previous-line)
  (local-set-key (kbd "C-k") 'next-line)
  (local-set-key (kbd "C-j") 'backward-char)
  (local-set-key (kbd "C-l") 'forward-char))
(add-hook 'magical-mode-hook 'my-magical-keys)

ただし、次のようにすることもできます。

(define-key magical-mode-map (kbd "C-i") 'previous-line)
(define-key magical-mode-map (kbd "C-k") 'next-line)
(define-key magical-mode-map (kbd "C-j") 'backward-char)
(define-key magical-mode-map (kbd "C-l") 'forward-char)

2番目の方法は、実際には私にとってはきれいに見えます。 ある方法を他の方法よりも有利にすることはありますか?


基本的な移動コマンドにも同じキーを使用します。注意してください。これは困難な戦いであり、これを始める前にキーバインディングについてもう少し学びたいかもしれません。
メガネザル

@tarsius本当に苦しい戦い。私は前にそのパスをダウンしたが、今私は戻って、古き良きのだC-nC-p。例は単なるダミーコードです。バインディング自体が質問の実際の目的を妨げないように、非常に単純なサンプルモードとバインディングの例をいくつか考えました。
nispio

回答:


15

2番目の方法は、モードのキーマップを1回だけ変更するため、望ましい方法です。

モードのフックを使用してそれを行う場合、そのモードが何らかのバッファーで有効になるたびに呼び出されます。通常、キーを再度バインドしても、キーは既にバインドされているものに再びバインドされるため、実際には効果がありません。メジャーモードキーマップは、そのモードを使用する個々のバッファーではなく、メジャーモードに対して「ローカル」です。したがって、local-set-keythenを使用してこれらのバッファーのいずれかのバインディングを変更すると、同じメジャーモードのすべてのバッファーに影響します。

local-set-key主にコマンドとして使用することを目的としています。何らかの変更を永続化することを決定したらdefine-key、モードキーマップを最初の引数として使用します。

フックを使用してキーマップを何度も変更すると、意図した使用と競合する可能性がありlocal-set-keyます。のM-x local-set-key RET C-i fancy-previous-line RETバリアントを試してみたいので、あなたが使ったとしましょうprevious-line。同じメジャーモードを使用する新しいバッファーを開くと、フックは再度実行され、以前に使用していたバッファーを含む、そのメジャーモードを使用するすべてのバッファーで一時バインディングがオーバーライドされますlocal-set-key


私はこの答えが好きですが、モードが自動ロードされたらどうなりますか?
14:

2
ライブラリのロードが完了するまで、コードのロードを遅らせることができます(eval-after-load 'magical '(progn (define-key magical-mode-map ...) ...))
メガネザル

4

使用(define-key my-magical-mode-map …)は通常の方法です。

フックとを使用するとlocal-set-key、バッファでMy Magicalモードに入るたびにキーが追加されます。これはlocal-set-key、同じモードのすべてのバッファー(より一般的には、同じキーマップを使用するすべてのバッファー)に影響するため、奇妙です。そのため、キーマップに変更を加えた場合、バッファでMy Magicalモードに入るたびにそれらは上書きされます。

別の場所でキーマップをカスタマイズする場合、2番目の方法も混乱する可能性があります。フックは、追加された順序と逆の順序で実行されます。最初に実行されるまで、カスタマイズのトレースは表示されません。


2

どうやら、メジャーモードキーマップの定義についてではなく既存のメジャーモードキーマップにいくつかのキーバインディングを追加または変更するユーザーコードについて尋ねているのです。あなたはこれを示唆する「カスタム」と言いますが、それを明確にすることもできます。

確かに、これについて最もよく見られると言うのは、メジャーモードキーマップを定義するために一般的に使用されるものではありません。たとえば、Emacsのソースコードにあるものではありません。また、Elispマニュアル(ノード)で推奨されているものではありませんMajor Mode Conventions

他の人にわかりやすくするために、それを邪魔にならないようにしたかっただけです。通常、メジャーモードマップを定義するためにモードフックを使用することは望ましくありません。


ユーザーキーのカスタマイズに関する質問-

いずれにしてもlocal-set-key、モードフックで使用する必要はありません。define-key最初の例とまったく同じように、メジャーモードキーマップで使用します。@tarsiusはすでにこれをうまく説明しています。

それ以外の答えは、キーを(モードマップで使用して)一度だけバインドするか、モードに入るたびにフックを使用してバインドするかどうかにかかわらず、一般にほとんど違いはありませんdefine-key

ただし、マップ内のバインディングが変更された場合、たとえば、バインディングを変更する他のコードをロードすることにより、違いが生じる可能性があります。その場合、メジャーモードフックにバインディングを配置すると、モードに入るときにバインディングが確立されます。つまり、それらが作成されることを保証しますが、後でそれらを変更するものが他にないことを保証しません(たとえば、同じフックの別の関数、後で呼び出される)。フックで何を実行するのか、いつ実行するのかはほとんど制御できないことに注意してください-もちろん、自分のコードだけがそれを台無しにすることが確実な場合を除きます。

それが効果の唯一の違いであり、私が考えることができます。その違いをどちらの方法の利点と考えるかを決めるのはあなたです。FWIW、私自身のコードを見て、モードフックにキーをバインドすることはないと思います。


ありがとう。質問を修正して、メジャーモードを作成していないという事実を明確に説明し、既存のメジャーモードに独自のキーバインディングを追加するだけです。
nispio 14年

0

あなたの命名は少し混乱します(my質問の2番目の部分で削除する必要があると思います)。

とにかくmy-magical-keys、のユーザーカスタマイズ機能であるmagical-modeと仮定すると、明らかな利点が1つあります。remove-hookフックを1回で簡単に(byで)削除できます。

2番目の利点は、関数の目的です。再利用可能であるということです。他のモードにフックできます。

編集:

@tarsiusが指摘したように、フックを削除しても元の動作は復元されず、関数をマイナーモードに変更する方がよい場合があります。


という仮想のメジャーモードをカスタマイズしていますmy-magical-mode。ただし、my-プレフィックスの使用がわかりにくい場合は、間違いなく質問を編集できます。
nispio 14年

はい、それはより良いでしょう、通常(少なくとも私が野生で見るように)my-ユーザー機能に追加されます。
kindahero

1
同意した。を適用したmy-ので、実際のモードmagical-mode(存在する場合)を設定する方法を尋ねているとは誰も思わないでしょう。
nispio 14年

1
いいえ、フックを削除しても古いバインディングは復元されません。少なくとも、Emacsが再起動されるまでは、そういう大きな改善として4行ではなく1行だけをコメントアウトする必要はないと思います。
メガネザル

2
2番目の利点については、ここで、マイナーモードを作成してから、さまざまなメジャーモードおよび/または特定のメジャーモードを使用する一部のバッファーのみに対して有効にすることをお勧めします。
メガネザル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.