Jak mogę dowiedzieć się, w której mapie klawiszy jest powiązany klucz?

63

Odebrałem klucz „d” gnus-article-mode, ale jego stare zachowanie jest nadal aktywne, gdy punkt znajduje się na załączniku. Widzę, że ponowne wiązanie nie przyniosło skutku C-h k d, ale nie mówi mi, która mapa klawiszy obowiązuje w tym momencie, abym mógł ją ponownie powiązać.

Czy istnieje sposób, aby się tego dowiedzieć?

Oto dokładny przykład: używam zła i chcę, aby artykuły były w trybie ruchu. Dla mojego układu klawiatury skonfigurowałem „d” jako klawisz do przejścia w górę.

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

Aby upewnić się, że złe klucze są brane pod uwagę, rozbroiłem klucz gnus na lokalnej mapie:

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

Niestety, gdy chodzi o załącznik, klawisz „d” już nie idzie w górę, ale oferuje mi usunięcie załącznika. Wydaje mi się, że w tym momencie aktywne jest inne wiązanie, stąd pytanie.

Rozwiązanie Użyłem keymaps-at-pointponiżej, aby ustalić, że używana mapa klawiszy pochodzi z właściwości text. Następnie spojrzałem na kod powiązanej funkcji, aby znaleźć nazwę mapy klawiszy gnus-mime-button-map. Poniższy kod robi to, co chcę:

(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
źródło
3
Użyj tego pseudokodu Lisp i opisu jako przewodnika wysokiego poziomu o tym, jak Emacs wyszukuje klucz : instrukcja Elisp, węzełSearching Keymaps . Zobacz także węzły Functions for Key Lookupi Active Keymaps.
Drew
Wystąpił dość duży błąd w mojej pierwszej odpowiedzi w drugiej funkcji. Właśnie to naprawiłem, więc powinno być w stanie zlokalizować twoje keybind. Czy możesz spróbować jeszcze raz?
Malabarba

Odpowiedzi:

61

Emacs 25

Jak wspomniano w komentarzach @YoungFrog, poczynając od Emacsa 25.1 , stara, dobra C-h kmetoda opisywania powiązań klawiszy powie ci również, w której mapie klawiszy znaleziono klucz.

Przed Emacsem 25

Jest jakiś kod tutaj na ten temat, ale jest niepełna, gdyż nie obejmuje wszystkiego. Poniżej znajduje się jego ulepszona wersja.

Klucze można powiązać na 9 (!) Sposobów. Dzięki @Drew za ten link (również uzupełniony o to ) z pełną listą. W kolejności pierwszeństwa są to:

  1. Zestaw zacisków specyficznych klawiszy, overriding-terminal-local-map. Jest to określone przez set-transient-mapfunkcję.
  2. Bufor lokalny przesłanianie mapa, overriding-local-map. Jeśli jest ustawiony, pozycje 3–8 są pomijane (prawdopodobnie dlatego nie widzisz ich wielu).
  3. W punkcie za pomocą keymaptekstu-proroctwa (który może dotyczyć samego tekstu lub nakładek).
  4. Zmienna, która zasadniczo symuluje różne możliwe zestawy drobnych-włączonych trybach emulation-mode-map-alists.
  5. Zmienna gdzie major-tryby mogą zastąpić keybinds pomniejszych-trybach minor-mode-overriding-map-alist.
  6. Rzeczywiste tryby drobne , w których skróty klawiszowe są przechowywane minor-mode-map-alist.
  7. W punkcie (ponownie) za pośrednictwem local-mapwłaściwości text. Jeśli tak, pozycja 8 jest pomijana.
  8. Standardowa mapa klawiszy dla bufora lokalnego (gdzie idą skróty klawiszowe trybu lokalnego lub bufora lokalnego), zwracana przez funkcję current-local-map.
  9. Globalny keymap , zwrócony przez current-global-map.

Jest też półpozycja 10. Cokolwiek wydano w powyższej procedurze, mogło zostać również odwzorowane.

Poniższa funkcja sprawdza niektóre z tych możliwości (najbardziej prawdopodobne) i zwraca lub drukuje wynik.

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

Dla każdego z nich są wbudowane funkcje oprócz pierwszej, dlatego musimy je utworzyć (także ulepszoną wersję kodu, do której link podano powyżej).

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

Skoro mówisz, że zachowanie jest aktywne, gdy punkt znajduje się na załączniku, istnieje duże prawdopodobieństwo, że ten skrót klawiszowy ma miejsce na nakładce lub właściwości tekstowej.

Jeśli to nie zadziała , spróbuj również wykonać następujące polecenie. Wystarczy umieścić kursor na załączniku i zrobić 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
źródło
To powie mi, czy klucz ma lokalne powiązanie i jakie polecenie jest związane, ale nadal nie podaje mi nazwy mapy klawiszy , z której pochodzi.
nispio
@nispio, jeśli ma lokalne powiązanie, musi pochodzić z mapy klawiszy trybu głównego lub z połączenia z kluczem lokalnym. Niestety nie ma niezawodnego sposobu na rozróżnienie dwóch przypadków.
Malabarba
1
@Malabarba Czy masz na myśli „Niestety, nie ma łatwego sposobu na rozróżnienie dwóch przypadków?” Na pewno wszystkie informacje są obecne. Ponadto, czy każdy główny tryb ma dokładnie jedną mapę trybu? Jeśli nie, czy istnieje sposób na określenie, która mapa trybu głównego jest aktywna?
nispio
1
Począwszy od jeszcze wydanego emacsa 25, „Ch k” w niektórych (cóż, „w większości” mam nadzieję) przypadkach powie Ci, w której mapie klawiszy (a dokładniej: symbolu, który utrzymuje tę mapę klawiszy jako swoją wartość) dane przypisanie klawiszy jest zdefiniowane. przykładowe dane wyjściowe:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog,
2
Dla wszystkich zainteresowanych, oto odpowiednie zatwierdzenie, które wyświetla mapę klawiszy powiązania klawiszy w emacs 25+.
Kaushal Modi,
2

To dotyczy:

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

Na przykład dla (my-lookup-key (kbd "C-c v v"))Mam listę w *Message*buforze:

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

To podejście jest przydatne do wyszukiwania podklucza, które zawiera mapę klawiszy wyższego poziomu, na przykład danych wyjściowych z:

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

jest vc-prefix-mapzawarta w global-map:

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

Jeśli zmodyfikujesz warunek filtrowania, aby uwzględnić keymapp- będziesz mógł zawsze szukać prefiksów:

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

Więc rst-mode-mapbędzie można znaleźć na obu:

(my-lookup-key-prefix (kbd "C-c C-t"))
(my-lookup-key-prefix (kbd "C-c C-t C-t"))
gavenkoa
źródło
1

Wiem, że poniższe pytanie nie odpowiada na pytanie, w jaki sposób mogę dowiedzieć się, która mapa klawiszy , ale zajmuje się podstawową kwestią w tym przypadku, w jaki sposób upewnić się, że dklucz zachowuje się zgodnie z tym, czego chce użytkownik. Jeśli wolisz, mogę usunąć tę odpowiedź i przekonwertować na inne pytanie + odpowiedź na ten temat.

Jako metodę przesłonięcia text-property/overlaymapy powinieneś móc użyć:

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

Zgodnie z kontrolowaniem aktywnych map , overriding-local-mapma pierwszeństwo przed każdą inną aktywną mapą inną niż overriding-terminal-local-map.

Jonathan Leech-Pepin
źródło
To wszystko psuje: nie mogę już otwierać wiadomości w trybie podsumowania, a zło i sople przestają działać.
brab
To wszystko psuje: nie mogę już otwierać wiadomości w trybie podsumowania, a zło i sople przestają działać.
Emily Hoover
0

emacs-buttons zapewnia buttons-display, że z argumentem przedrostka wyświetla rekurencyjną wizualizację wszystkich bieżących powiązań.

(Zastrzeżenie: Jestem autorem pakietu)

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

erjoalgo
źródło