Como posso descobrir em qual mapa de teclas uma chave está vinculada?

63

Eu recuperei a tecla 'd' gnus-article-mode, mas seu antigo comportamento ainda está ativo quando o ponto está em um anexo. Percebo que a religação não teve efeito lá C-h k d, mas não está me dizendo qual mapa de teclas está em vigor naquele momento, para que eu possa religá-lo.

Existe uma maneira de descobrir isso?

Aqui está um exemplo preciso: estou usando o mal e quero que os artigos estejam no modo de movimento. Para o layout do meu teclado, eu 'configurei' como a tecla para subir.

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

Para garantir que as chaves malignas sejam levadas em consideração, desmarquei a chave gnus no mapa local:

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

Infelizmente, quando o ponto está em um anexo, a tecla 'd' não aumenta mais, mas ela me oferece a exclusão do anexo. Eu acho que outra ligação está ativa nesse ponto, daí a questão.

Solução Usei o keymaps-at-pointabaixo para encontrar o mapa de teclas usado era de uma propriedade de texto. Olhei o código da função vinculada para encontrar o nome do mapa de teclas gnus-mime-button-map. O código a seguir faz o que eu quero:

(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
fonte
3
Use este pseudocódigo Lisp e descrição como seu guia de alto nível sobre como o Emacs procura uma chave : Elisp manual, nóSearching Keymaps . Veja também nós Functions for Key Lookupe Active Keymaps.
Tirou
Houve um erro muito grande na minha resposta inicial na segunda função. Eu o corrigi agora, então ele deve ser capaz de localizar seu teclado. Você poderia tentar de novo?
Malabarba 30/10

Respostas:

61

Emacs 25

Conforme mencionado pelo @YoungFrog nos comentários, começando com o Emacs 25.1 , o C-h kmétodo antigo de descrever as combinações de teclas também informará em qual mapa de teclas a chave foi encontrada.

Antes do Emacs 25

Há algum código aqui sobre isso, mas é incompleto, pois não cobre tudo. Abaixo está uma versão melhorada.

As chaves podem ser vinculadas de 9 (!) Maneiras. Obrigado a @Drew por este link (também complementado por isso ) com a lista completa. Por ordem de precedência, são eles:

  1. Um conjunto de chaves específico do terminal overriding-terminal-local-map. Isso é definido pela set-transient-mapfunção
  2. Um mapa de substituição local do buffer overriding-local-map,. Se este estiver definido, os itens 3 a 8 são ignorados (provavelmente por que você não vê muitos deles).
  3. No momento, através da propriedade do keymaptexto (que pode ser feita em texto real ou em sobreposições).
  4. Uma variável que simula essencialmente diferentes conjuntos possíveis de modos menores habilitados emulation-mode-map-alists,.
  5. Uma variável em que os modos principais podem substituir os atalhos de teclado dos modos secundários minor-mode-overriding-map-alist,.
  6. Os modos secundários reais , cujas teclas são armazenadas minor-mode-map-alist.
  7. No ponto (novamente), através da local-mappropriedade de texto. Se isso existir, o item 8 será ignorado.
  8. O mapa de teclas padrão do buffer local (para onde vão os atalhos de teclado do modo principal ou do buffer local), retornado pela função current-local-map.
  9. O mapa de teclas global , retornado por current-global-map.

Também há um semi-item 10. Qualquer comando encontrado através do procedimento acima também pode ter sido remapeado.

A função a seguir consulta algumas dessas possibilidades (as mais prováveis) e retorna ou imprime o resultado.

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

Existem funções internas para cada uma delas, exceto a primeira, portanto, devemos criar uma (também uma versão aprimorada do código vinculado acima).

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

Como você está dizendo que o comportamento está ativo quando point está em um anexo, há uma boa chance de que esse atalho de teclado ocorra em uma sobreposição ou propriedade de texto.

Se isso não funcionar , tente o seguinte comando também. Apenas coloque o cursor no anexo e faça 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
fonte
Isso me dirá se a chave tem uma ligação local e a qual comando está vinculada, mas ainda não me diz o nome do mapa de teclas de onde veio.
Nispio 7/10
@nispio se tiver uma ligação local, deve ser do mapa de teclas do modo principal ou de uma chamada para a chave de configuração local. Infelizmente, não há uma maneira infalível de diferenciar os dois casos.
Malabarba 7/10
11
@ Malabarba Você quer dizer "Infelizmente, não há uma maneira fácil de diferenciar os dois casos?" Certamente a informação está presente. Além disso, todos os modos principais têm exatamente um mapa de modo? Caso contrário, existe uma maneira de saber qual mapa principal de modo está ativo?
Nispio 7/10
11
A partir do emacs 25 ainda a ser lançado, "Ch k", em alguns casos (bem, "na maioria", esperançosamente), dirá em que mapa de teclas (mais precisamente: um símbolo que mantém esse mapa de chaves como seu valor) uma determinada combinação de teclas é definiram. saída de exemplo:k runs the command gnus-summary-kill-same-subject-and-select (found in gnus-summary-mode-map), which is (...)
YoungFrog 12/02
2
Para quem estiver interessado, aqui está o commit relevante que exibe o mapa de teclas da ligação de chave no emacs 25+.
Kaushal Modi
2

Sobre o que:

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

Por exemplo, para (my-lookup-key (kbd "C-c v v"))obter lista no *Message*buffer:

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

Essa abordagem é útil para pesquisar o sub-mapa de teclas incluído no mapa de teclado de nível superior, por exemplo, saída de:

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

é o vc-prefix-mapque está incluído em global-map:

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

Se você modificar a condição de filtragem para incluir keymapp- poderá procurar sempre prefixos:

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

Então rst-mode-map, será encontrado em ambos:

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

Estou ciente de que o seguinte não responde à pergunta de Como posso descobrir qual mapa-chave , mas lida com o problema subjacente neste caso de como garantir que a dchave se comporte de acordo com o que o usuário deseja. Se preferir, posso remover esta resposta e converter em outra pergunta + resposta sobre esse problema.

Como um método para substituir o text-property/overlaymapa, você poderá usar:

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

De acordo com o Controle de mapas ativos , overriding-local-maptem precedência sobre qualquer outro mapa ativo que não seja overriding-terminal-local-map.

Jonathan Leech-Pepin
fonte
Isso quebra tudo: não consigo mais abrir uma mensagem no modo de resumo e o mal e os pingentes de gelo param de funcionar.
BRAB
Isso quebra tudo: não consigo mais abrir uma mensagem no modo de resumo e o mal e os pingentes de gelo param de funcionar.
21716 Emily Hoover
0

O emacs-buttons fornece buttons-display, que com um argumento de prefixo exibe uma visualização recursiva de todas as ligações atuais.

(Isenção de responsabilidade: eu sou o autor do pacote)

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

erjoalgo
fonte