キーがバインドされているキーマップを確認するにはどうすればよいですか?


63

で「d」キーをリバウンドgnus-article-modeしましたが、ポイントが添付ファイル上にある場合、その古い動作は引き続きアクティブです。を実行することで再バインドが有効にならなかったことがわかりますが、C-h k dその時点でどのキーマップが有効であるかを教えていないので、再バインドできます。

それを見つける方法はありますか?

正確な例は次のとおりです。私は悪を使用しており、記事をモーションモードにする必要があります。キーボードレイアウトでは、上に移動するキーとして「d」を設定しました。

(evil-mode 1)
(add-to-list 'evil-motion-state-modes 'gnus-article-mode)
(setq evil-emacs-state-modes (remove 'gnus-article-mode evil-emacs-state-modes))
(define-key evil-motion-state-map "d" 'evil-previous-line)

邪悪なキーが確実に考慮されるように、ローカルマップでgnusキーの設定を解除します。

(defun as/alter-article-evil-map ()
  (local-unset-key "d"))
(add-hook 'gnus-article-mode-hook 'as/alter-article-evil-map)

残念ながら、ポイントが添付ファイル上にある場合、「d」キーは表示されなくなりますが、添付ファイルを削除するように求められます。その時点で別のバインディングがアクティブになっていると思うので、質問です。

解決策keymaps-at-point以下を使用して、使用されたキーマップがテキストプロパティからのものであることを見つけました。次に、バインドされた関数のコードを見て、キーマップの名前を見つけましたgnus-mime-button-map。次のコードは私が望むことをします:

(defun as/alter-article-evil-map ()
  (define-key gnus-mime-button-map "d" nil))
(add-hook 'gnus-article-mode-hook 'as/alter-article-evil-map)

3
この擬似コードLispと説明を、Emacsがキーを検索する方法の高レベルのガイドとして使用してください:Elispマニュアル、nodeSearching Keymaps。ノードFunctions for Key Lookupおよびも参照してくださいActive Keymaps
ドリュー

2番目の関数の最初の答えにはかなり大きなバグがありました。今すぐ修正したので、キーバインドを見つけることができるはずです。もう一度試してもらえますか?
マラバルバ14年

回答:


61

Emacs 25

@YoungFrogがコメントで述べたように、Emacs 25.1以降、C-h kキーバインドを記述する古き良き方法は、キーが見つかったキーマップも教えてくれます。

Emacs 25より前

ここ にはいくつかのコードがありますが 、すべてを網羅しているわけではないため不完全です。以下は改善されたバージョンです。

キーは9(!)の方法でバインドできます。以下のため@Drewのおかげ、このリンク(もで補足この完全なリストで)。優先順では、次のとおりです。

  1. 端末固有のキーのセットoverriding-terminal-local-map。これはset-transient-map関数によって定義されます。
  2. バッファローカルオーバーライドマップoverriding-local-map。これが設定されている場合、項目3〜8はスキップされます(おそらくこれらの多くが表示されない理由)。
  3. keymapテキストプロパティを介したポイント(実際のテキストまたはオーバーレイに表示される可能性があります)。
  4. 使用可能なマイナーモードのさまざまな可能なセットを本質的にシミュレートする変数emulation-mode-map-alists
  5. メジャーモードがマイナーモードのキーバインドをオーバーライドできる変数minor-mode-overriding-map-alist
  6. キーバインドがに保存されている実際のマイナーモードminor-mode-map-alist
  7. (再び)ポイントでlocal-maptextプロパティを介して。これが存在する場合、項目8はスキップされます。
  8. 関数によって返される標準のバッファローカルキーマップ(メジャーモードまたはバッファローカルキーバインドが行く)current-local-map
  9. グローバルキーマップで返され、current-global-map

半項目10もあります。上記の手順で見つかったコマンドはすべて、再マップされている可能性があります。

次の関数は、これらの可能性のいくつか(最も可能性の高いもの)を照会し、結果を返すか出力します。

(defun locate-key-binding (key)
  "Determine in which keymap KEY is defined."
  (interactive "kPress key: ")
  (let ((ret
         (list
          (key-binding-at-point key)
          (minor-mode-key-binding key)
          (local-key-binding key)
          (global-key-binding key))))
    (when (called-interactively-p 'any)
      (message "At Point: %s\nMinor-mode: %s\nLocal: %s\nGlobal: %s"
               (or (nth 0 ret) "") 
               (or (mapconcat (lambda (x) (format "%s: %s" (car x) (cdr x)))
                              (nth 1 ret) "\n             ")
                   "")
               (or (nth 2 ret) "")
               (or (nth 3 ret) "")))
    ret))

最初のものを除いて、これらのそれぞれに組み込み関数があります。そのため、1つを作成する必要があります(上記にリンクされたコードの改良版でもあります)。

(defun key-binding-at-point (key)
  (mapcar (lambda (keymap) (when (keymapp keymap)
                             (lookup-key keymap key)))
          (list
           ;; More likely
           (get-text-property (point) 'keymap)
           (mapcar (lambda (overlay)
                     (overlay-get overlay 'keymap))
                   (overlays-at (point)))
           ;; Less likely
           (get-text-property (point) 'local-map)
           (mapcar (lambda (overlay)
                     (overlay-get overlay 'local-map))
                   (overlays-at (point))))))

ポイントが添付ファイル上にあるときに動作がアクティブであると言っているので、このキーバインドがオーバーレイまたはテキストプロパティで実行される可能性が高くなります。

それでもうまくいかない場合は、次のコマンドも試してください。添付ファイルの上にカーソルを置いてくださいM-x keymaps-at-point

(defun keymaps-at-point ()
  "List entire keymaps present at point."
  (interactive)
  (let ((map-list
         (list
          (mapcar (lambda (overlay)
                    (overlay-get overlay 'keymap))
                  (overlays-at (point)))
          (mapcar (lambda (overlay)
                    (overlay-get overlay 'local-map))
                  (overlays-at (point)))
          (get-text-property (point) 'keymap)
          (get-text-property (point) 'local-map))))
    (apply #'message
           (concat 
            "Overlay keymap: %s\n"
            "Overlay local-map: %s\n"
            "Text-property keymap: %s\n"
            "Text-property local-map: %s")
           map-list)))

これにより、キーにローカルバインディングがあるかどうか、およびどのコマンドにバインドされているかがわかりますが、キーマップ名前はまだわかりません。
nispio 14年

@nispioにローカルバインディングがある場合、メジャーモードのキーマップから、またはlocal-set-keyの呼び出しからでなければなりません。残念ながら、2つのケースを区別する確実な方法はありません。
マラバルバ14年

1
@Malabarba「残念ながら、2つのケースを区別する簡単な方法はありませんか?」情報はすべて存在します。また、すべてのメジャーモードにはモードマップが1つだけありますか?そうでない場合、どのメジャーモードマップがアクティブかを知る方法はありますか?
nispio 14年

1
まだリリースされていないemacs 25から始まる「Ch k」は、いくつかの(場合によっては「ほとんどの場合」)、どのキーマップ(より正確には、そのキーマップを値として保持するシンボル)で特定のキーバインディングが定義済み。出力例:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog

2
興味のある方のために、emacs 25+でキーバインディングのキーマップを表示する関連コミットを以下に示します。
カウ

2

それについて:

(defun my-lookup-key (key)
  "Search for KEY in all known keymaps."
  (mapatoms (lambda (ob) (when (and (boundp ob) (keymapp (symbol-value ob)))
                      (when (functionp (lookup-key (symbol-value ob) key))
                        (message "%S" ob))))
            obarray))

たとえば(my-lookup-key (kbd "C-c v v"))*Message*バッファにリストを取得する場合:

global-map
term-pager-break-map
widget-global-map

このアプローチは、より高いレベルのキーマップに含まれるサブキーマップを検索するのに役立ちます。たとえば、次の出力です。

(my-lookup-key (kbd "d"))

vc-prefix-map含まれるglobal-map

(eq (lookup-key global-map (kbd "C-x v")) 'vc-prefix-map)

フィルタリング条件を変更して含めるkeymappと、次のようにプレフィックスを検索できます。

(defun my-lookup-key-prefix (key)
  "Search for KEY as prefix in all known keymaps."
  (mapatoms (lambda (ob) (when (and (boundp ob) (keymapp (symbol-value ob)))
                      (when (let ((m (lookup-key (symbol-value ob) key)))
                              (and m (or (symbolp m) (keymapp m))))
                        (message "%S" ob))))
            obarray))

したがってrst-mode-map、両方にあります:

(my-lookup-key-prefix (kbd "C-c C-t"))
(my-lookup-key-prefix (kbd "C-c C-t C-t"))

1

私はの質問答えていない、次のことに注意してくださいよ、私はどのキーマップを見つけることができますどのようにしかし、それはことを保証する方法のこの場合、根本的な問題を扱う、d鍵はユーザーが何を望んでいるかに応じて動作します。必要に応じて、この回答を削除し、その問題に関する別の質問と回答に変換できます。

text-property/overlayマップをオーバーライドする方法として、次を使用できる必要があります。

(let ((map (make-sparse-keymap)))
  (define-key map "d" 'evil-previous-line)
  (setq overriding-local-map map))

あたりとしてアクティブ地図を制御するoverriding-local-map以外の他のすべてのアクティブマップよりも優先されますoverriding-terminal-local-map


これにより、すべてが壊れます。サマリーモードでメッセージを開くことができなくなり、悪とつららが機能しなくなります。
ブラブ14年

これにより、すべてが壊れます。サマリーモードでメッセージを開くことができなくなり、悪とつららが機能しなくなります。
エミリーフーバー

0

emacs-buttonsはを提供しますbuttons-display。これは、プレフィックス引数を使用して、現在のすべてのバインディングの再帰的な視覚化を表示します。

(免責事項:私はパッケージの著者です)

https://github.com/erjoalgo/emacs-buttons/blob/master/doc/img/sample-visualization.png

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.