Comment savoir dans quelle keymap une clé est liée?


63

J'ai rebondi sur la touche 'd' gnus-article-mode, mais son ancien comportement est toujours actif lorsque le point est sur une pièce jointe. Je peux voir que la reconsolidation n’a pas pris effet là-bas C-h k d, mais cela ne me dit pas quelle est la keymap en vigueur à ce moment-là, afin que je puisse la recréer.

Y a-t-il un moyen de le savoir?

Voici un exemple précis: J'utilise le mal et je veux que les articles soient en mode mouvement. Pour ma configuration de clavier, j'ai configuré la clé pour monter.

(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)

Pour m'assurer que les clés maléfiques sont prises en compte, je désactive les clés gnus dans la carte locale:

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

Malheureusement, lorsque le point est sur une pièce jointe, la touche 'd' ne monte plus, mais elle me propose de supprimer la pièce jointe. Je suppose qu'une autre liaison est active à ce moment-là, d'où la question.

Solution J'ai utilisé ce qui keymaps-at-pointsuit pour trouver que le keymap utilisé était issu d'une propriété de texte. J'ai ensuite regardé le code de la fonction liée pour trouver le nom du keymap gnus-mime-button-map. Le code suivant fait ce que je veux:

(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
Utilisez ce pseudo-code Lisp et cette description comme guide de haut niveau sur la manière dont Emacs recherche une clé : Manuel Elisp, noeudSearching Keymaps . Voir aussi les nœuds Functions for Key Lookupet Active Keymaps.
Dessiné

Il y avait un gros problème avec ma première réponse dans la deuxième fonction. Je viens de le corriger maintenant, il devrait donc être capable de localiser votre keybind. Pourriez-vous réessayer?
Malabarba

Réponses:


61

Emacs 25

Comme mentionné par @YoungFrog dans les commentaires, à commencer par Emacs 25.1 , la bonne vieille C-h kméthode de description des raccourcis clavier vous indiquera également le type de clavier dans lequel la clé a été trouvée.

Avant Emacs 25

Il y a du code ici , mais il est incomplet car il ne couvre pas tout. Vous trouverez ci-dessous une version améliorée de celle-ci.

Les clés peuvent être liées de 9 (!) Façons. Merci à @Drew pour ce lien (également complété par celui-ci ) avec la liste complète. Par ordre de priorité, ils sont:

  1. Un ensemble spécifique terminal de clés, overriding-terminal-local-map. Ceci est défini par la set-transient-mapfonction.
  2. Une carte de commande prioritaire tampon local, overriding-local-map. Si celui-ci est défini, les éléments 3 à 8 sont ignorés (probablement pourquoi vous n'en voyez pas beaucoup).
  3. Au point via la keymappropriété text (qui peut aller sur du texte réel ou sur des superpositions).
  4. Une variable qui simule essentiellement différents ensembles possibles de petits-modes activés, emulation-mode-map-alists.
  5. Une variable où les grands-modes peuvent remplacer les keybinds de modes mineur, minor-mode-overriding-map-alist.
  6. Les modes mineurs réels , dont les combinaisons de clés sont stockées dans minor-mode-map-alist.
  7. Au point ( à nouveau), via la local-mappropriété text. Si cela existe, le point 8 est ignoré.
  8. Le mappage de clés tampon-local standard (où les raccourcis clavier en mode majeur ou tampon-local sont renvoyés), renvoyé par la fonction current-local-map.
  9. Le clavier global , renvoyé par current-global-map.

Il existe également un semi-élément 10. Toute commande trouvée dans le cadre de la procédure ci-dessus aurait également pu être remappée.

La fonction suivante interroge certaines de ces possibilités (les plus probables) et renvoie ou affiche le résultat.

(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))

Il existe des fonctions intégrées pour chacun d’eux, à l’exception de la première; nous devons donc en créer une (également une version améliorée du code lié ci-dessus).

(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))))))

Puisque vous dites que le comportement est actif lorsque le point est sur une pièce jointe, il y a de fortes chances pour que ce raccourci clavier se produise sur une superposition ou une propriété de texte.

Si cela ne fonctionne pas , essayez également la commande suivante. Il suffit de placer le curseur sur la pièce jointe et de le faire 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)))

Cela me dira si la clé a une liaison locale et la commande à laquelle elle est liée, mais elle ne me dit toujours pas le nom de la carte de clé dont elle provient.
nispio

@nispio s'il a une liaison locale, elle doit provenir du clavier en mode majeur ou d'un appel à local-set-key. Malheureusement, il n'y a pas de moyen infaillible de distinguer les deux cas.
Malabarba

1
@Malabarba Voulez-vous dire "Malheureusement, il n'y a pas de moyen facile de distinguer les deux affaires?" Toutes les informations sont sûrement présentes. En outre, chaque mode majeur a-t-il exactement une carte de mode? Sinon, y a-t-il un moyen de savoir quelle carte de mode majeur est active?
nispio

1
En commençant par emacs 25 à venir, "Ch k" vous indiquera dans quel (et même si, dans la plupart des cas) dans quel keymap (plus précisément: un symbole qui tient ce keymap comme valeur) un raccourci donné défini. Exemple de sortie:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog

2
Pour les personnes intéressées, voici le commit pertinent qui affiche le keymap de la liaison de clé dans emacs 25+.
Kaushal Modi

2

C'est à propos de:

(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))

Par exemple pour la (my-lookup-key (kbd "C-c v v"))liste dans la *Message*mémoire tampon:

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

Cette approche est utile pour rechercher un sous-clavier associé à un clavier supérieur, par exemple les résultats suivants:

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

est vc-prefix-mapce qui est inclus dans global-map:

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

Si vous modifiez la condition de filtrage pour inclure keymapp- vous pourrez rechercher à tout moment les préfixes:

(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))

On rst-mode-maptrouvera donc à la fois:

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

1

Je suis conscient que ce qui suit ne répond pas à la question Comment puis-je trouver quelle carte de clavier , mais elle traite du problème sous-jacent dans ce cas, comment faire en sorte que la dclé se comporte conformément à ce que l'utilisateur souhaite. Si je le souhaite, je peux supprimer cette réponse et la convertir en une autre question + réponse concernant ce problème.

En tant que méthode pour remplacer la text-property/overlaycarte, vous devriez pouvoir utiliser:

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

Comme indiqué dans Controlling Active Maps , overriding-local-mapa la priorité sur toutes les autres cartes actives autres que overriding-terminal-local-map.


Cela casse tout: je ne peux plus ouvrir un message en mode résumé, et le mal et les glaçons ne fonctionnent plus.
brab

Cela casse tout: je ne peux plus ouvrir un message en mode résumé, et le mal et les glaçons ne fonctionnent plus.
Emily Hoover

0

emacs-buttons fournit buttons-displayce qui, avec un argument de préfixe, affiche une visualisation récursive de toutes les liaisons en cours.

(Avertissement: je suis l'auteur du package)

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.