Wie kann ich herausfinden, in welcher Keymap ein Key gebunden ist?

63

Ich habe die Taste 'd' erneut gedrückt gnus-article-mode, aber das alte Verhalten ist immer noch aktiv, wenn sich der Punkt auf einem Anhang befindet. Ich kann sehen, dass die erneute Bindung dort dadurch nicht wirksam geworden ist C-h k d, aber sie sagt mir nicht, welche Keymap zu diesem Zeitpunkt wirksam ist, so dass ich sie erneut binden kann.

Gibt es eine Möglichkeit, es herauszufinden?

Hier ist ein genaues Beispiel: Ich verwende das Böse und möchte, dass Artikel im Bewegungsmodus sind. Für mein Tastaturlayout habe ich "d" als die Taste konfiguriert, die nach oben gehen soll.

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

Um sicherzustellen, dass die bösen Schlüssel berücksichtigt werden, habe ich den Gnus-Schlüssel in der lokalen Karte deaktiviert:

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

Wenn sich der Punkt auf einem Anhang befindet, wird die Taste 'd' leider nicht mehr angezeigt, aber ich kann den Anhang löschen. Ich denke, an diesem Punkt ist eine andere Bindung aktiv, daher die Frage.

Lösung Ich habe das keymaps-at-pointFolgende verwendet, um die verwendete Keymap aus einer Texteigenschaft zu ermitteln. Ich habe mir dann den Code der gebundenen Funktion angesehen, um den Namen der Keymap zu finden gnus-mime-button-map. Der folgende Code macht was ich will:

(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)
brab
quelle
3
Verwenden Sie diesen Pseudocode Lisp und die Beschreibung als allgemeine Anleitung, wie Emacs einen Schlüssel sucht : Elisp manual, nodeSearching Keymaps . Siehe auch Knoten Functions for Key Lookupund Active Keymaps.
Drew
Es gab einen ziemlich großen Fehler mit meiner ersten Antwort in der zweiten Funktion. Ich habe es gerade behoben, so dass es in der Lage sein sollte, Ihre Tastenkombination zu finden. Könnten Sie es noch einmal versuchen?
Malabarba

Antworten:

61

Emacs 25

Wie von @YoungFrog in den Kommentaren erwähnt, werden Sie ab Emacs 25.1 anhand der guten alten C-h kMethode zur Beschreibung von Schlüsselbindungen auch darüber informiert, in welcher Schlüsselzuordnung der Schlüssel gefunden wurde.

Vor dem Emacs 25

Es gibt einige Code hier auf das, aber es ist unvollständig , da es nicht alles abdecken. Unten ist eine verbesserte Version davon.

Schlüssel können auf 9 (!) Arten gebunden werden. Vielen Dank an @Drew für diesen Link (auch ergänzt durch diesen ) mit der vollständigen Liste. In der Rangfolge sind dies:

  1. Ein terminal-spezifischer Schlüsselsatz overriding-terminal-local-map. Dies wird durch die set-transient-mapFunktion festgelegt.
  2. Eine pufferlokale Override-Map overriding-local-map. Wenn diese Option aktiviert ist, werden die Punkte 3 bis 8 übersprungen (wahrscheinlich, warum Sie nicht viele davon sehen).
  3. Punkt über die keymapTexteigenschaft (die sich auf den eigentlichen Text oder auf Überlagerungen beziehen kann).
  4. Eine Variable, die im Wesentlichen verschiedene mögliche Sätze aktivierter Nebenmodi simuliert emulation-mode-map-alists.
  5. Eine Variable, bei der Hauptmodi die Tastenkombinationen von Nebenmodi überschreiben können minor-mode-overriding-map-alist.
  6. Die tatsächlichen Moll-Modi , deren keybinds gespeichert sind in minor-mode-map-alist.
  7. Am Punkt (wieder) über die local-mapEigenschaft text. Ist dies der Fall, wird Punkt 8 übersprungen.
  8. Die von der Funktion zurückgegebene standardmäßige pufferlokale Tastaturbelegung (wo die Hauptmodus- oder pufferlokalen Tastaturbelegungen gespeichert werden) current-local-map.
  9. Die globale Keymap , die von zurückgegeben wird current-global-map.

Es gibt auch eine Semi-Item 10. Was auch immer Befehl durch das obige Verfahren gefunden wurde, könnte auch neu zugeordnet worden sein.

Die folgende Funktion fragt einige dieser (wahrscheinlichsten) Möglichkeiten ab und gibt das Ergebnis zurück oder druckt es aus.

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

Für jede dieser Funktionen gibt es integrierte Funktionen, mit Ausnahme der ersten. Daher müssen wir eine erstellen (auch eine verbesserte Version des oben verlinkten Codes).

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

Da Sie sagen, dass das Verhalten aktiv ist, wenn sich der Punkt auf einem Anhang befindet, besteht eine gute Chance, dass diese Tastenkombination auf einem Overlay oder einer Texteigenschaft ausgeführt wird.

Wenn das nicht funktioniert , versuchen Sie auch den folgenden Befehl. Platzieren Sie einfach den Cursor auf dem Anhang und machen Sie 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)))
Malabarba
quelle
Dadurch erfahre ich, ob der Schlüssel eine lokale Bindung hat und an welchen Befehl er gebunden ist. Der Name der Tastaturbelegung , von der er stammt , wird jedoch immer noch nicht angezeigt .
Nispio
@nispio Wenn es eine lokale Bindung hat, muss es aus der Keymap des Hauptmodus oder aus einem Aufruf von local-set-key stammen. Leider gibt es keine narrensichere Möglichkeit, die beiden Fälle voneinander zu unterscheiden.
Malabarba
1
@Malabarba Meinst du "Leider gibt es keine einfache Möglichkeit, die beiden Fälle voneinander zu unterscheiden?" Sicherlich sind alle Informationen vorhanden. Hat jeder Hauptmodus genau eine Modenkarte? Wenn nicht, gibt es eine Möglichkeit, festzustellen, welche Hauptmoduskarte aktiv ist?
Nispio
1
Ausgehend von Emacs 25, das noch nicht veröffentlicht wurde, wird "Ch k" in einigen (hoffentlich "in den meisten" Fällen) angeben, in welcher Tastaturbelegung (genauer: in einem Symbol, das diese Tastaturbelegung als Wert enthält) eine bestimmte Tastaturbelegung vorliegt definiert. Beispielausgabe:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog
2
Für alle Interessierten ist hier das relevante Commit aufgeführt , das die Keymap der Schlüsselbindung in emacs 25+ anzeigt.
Kaushal Modi
2

Das über:

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

Zum Beispiel (my-lookup-key (kbd "C-c v v"))bekomme ich eine Liste im *Message*Puffer:

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

Dieser Ansatz ist nützlich für die Suche nach Sub-Keymaps, die in übergeordneten Keymaps enthalten sind, z. B. Ausgabe von:

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

ist vc-prefix-mapwas ist enthalten in global-map:

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

Wenn Sie die Filterbedingung so ändern, dass sie einschließt, können keymappSie immer nach Präfixen suchen:

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

So rst-mode-mapfindet man auf beiden:

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

Ich bin mir bewusst, dass das Folgende nicht die Frage beantwortet, wie ich herausfinden kann, welche Keymap verwendet wird. In diesem Fall wird jedoch das zugrunde liegende Problem behandelt, wie sichergestellt werden kann, dass sich der dSchlüssel entsprechend den Anforderungen des Benutzers verhält. Falls gewünscht, kann ich diese Antwort entfernen und in eine andere Frage + Antwort bezüglich dieses Problems umwandeln.

Als Methode zum Überschreiben der text-property/overlayKarte sollten Sie Folgendes verwenden können:

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

Wie pro Aktive Karten Controlling , overriding-local-maphat Vorrang vor allen anderen aktiven Karte anders als overriding-terminal-local-map.

Jonathan Leech-Pepin
quelle
Dies zerstört alles: Ich kann eine Nachricht nicht mehr im Zusammenfassungsmodus öffnen, und das Böse und die Eiszapfen hören auf zu arbeiten.
Brab
Dies zerstört alles: Ich kann eine Nachricht nicht mehr im Zusammenfassungsmodus öffnen, und das Böse und die Eiszapfen hören auf zu arbeiten.
Emily Hoover
0

emacs-buttons bietet buttons-displaymit einem Präfix-Argument eine rekursive Visualisierung aller aktuellen Bindungen.

(Haftungsausschluss: Ich bin der Autor des Pakets)

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

Erjoalgo
quelle