Як я можу дізнатися, в якій клавіші пов'язаний ключ?


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, вузолSearching Keymaps . Дивіться також вузли Functions for Key Lookupта Active Keymaps.
Дрю

Був досить великий помилка з моєю початковою відповіддю у другій функції. Я зараз це виправив, тому він повинен мати змогу знайти вашу в'яжучу клавішу. Чи можете ви спробувати ще раз?
Малабарба

Відповіді:


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. Мінлива де-майорів режими можуть мати найвищий пріоритет keybinds незначних-мод, minor-mode-overriding-map-alist.
  6. Фактичні режими мінорного режиму , чиї ключі зберігаються в minor-mode-map-alist.
  7. У точці (знову) через local-mapвластивість тексту. Якщо це існує, пункт 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))

Для кожної з них, крім першої, є вбудовані функції, тому ми повинні створити її (також вдосконалену версію коду, зв'язаного вище).

(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

@nispio, якщо він має локальну прив'язку, він повинен бути з ключової карти основного режиму або від виклику до локального ключа. На жаль, не існує надійного способу розлучити два випадки.
Малабарба

1
@Malabarba Ви маєте на увазі "На жаль, не існує простого способу розповісти про два випадки?" Звичайно, інформація присутня. Також, чи має кожен головний режим рівно одну карту режимів? Якщо ні, чи є спосіб визначити, яка карта основних режимів активна?
nispio

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.


Це все порушує: я більше не можу відкривати повідомлення у стислому режимі, і зло та бурульки перестають працювати.
браб

Це все порушує: я більше не можу відкривати повідомлення у стислому режимі, і зло та бурульки перестають працювати.
Емілі Гувер

0

emacs-кнопки забезпечує buttons-display, що з аргументом префікса відображає рекурсивну візуалізацію всіх поточних прив'язок.

(Відмова: Я автор пакету)

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.