Como descobrir o que realmente faz uma sequência de teclas

14

De tempos em tempos, observo um comportamento inesperado ao editar texto. Meu primeiro recurso é geralmente usar C-h kpara descobrir quais funções estão sendo chamadas por uma determinada sequência de teclas. No entanto, às vezes a documentação está em desacordo com o comportamento observado. Nesses casos, geralmente presumo que algum outro pacote tenha se conectado a essa função ou sequência de teclas e está modificando seu comportamento.

Como posso descobrir quais funções estão conectadas à minha sequência de teclas?

Um exemplo que encontrei recentemente foi o fato de pressionar a "tecla e as aspas foram inseridas no início e no final da região ativa. Eu suspeitava que esse não era o comportamento padrão do Emacs, então eu C-h k "descobri qual função estava realmente sendo chamada.

A describe-keydocumentação me disse que a função self-insert-commandestava sendo chamada, que é uma função interna. Para resumir uma longa história, após algumas tentativas e erros, pude determinar que o comportamento foi causado por electric-pair-mode. No futuro, existe uma maneira mais rápida de chegar a essa conclusão do que desativar pacotes suspeitos um de cada vez até encontrar o culpado?

nispio
fonte
É possível que o electric-pair-modefoi ativado apenas em alguns modos principais? Você ainda vê self-insert-commandpara "quando você faz C-h kenquanto electric-pair-modeestá ativo?
Kaushal Modi
@kaushalmodi: Acontece que electric-pair-modefunciona conectando post-self-insert-hooke não alterando a combinação de teclas.
nispio
C-h kinforma exatamente o que acontece com o pressionamento de tecla. Se você olhar para a documentação self-insert-command, ela diz claramente que post-self-insert-hooké executada após a conclusão do comando.
shosti
@shosti: Neste exemplo simples, sim. Mas e se e se uma extensão usar after-change-functionscomo Jordon menciona em sua resposta? A documentação para uma função provavelmente não mencionará especificamente esse gancho, sim?
Nispio
Desculpe, eu deveria ter sido mais específico. C-h k+ os ganchos padrão == o comportamento completo (mais ou menos). É claro que às vezes isso deixa muitas possibilidades, mas ainda é muito mais transparente do que qualquer outro sistema de software complexo que eu conheça.
shosti

Respostas:

13

Não há uma maneira fácil de saber exatamente o que uma única tecla fará.

Se você vir um comportamento adicional, verifique sempre os ganchos comuns. Veja a lista aqui: http://www.gnu.org/software/emacs/manual/html_node/elisp/Standard-Hooks.html

Na maioria dos casos, os importantes são:

  • funções pós-alteração
  • funções antes da mudança
  • gancho de primeira troca
  • pós-comando-gancho
  • gancho de pré-comando
  • gancho pós-inserção automática

Você precisará inspecionar esses ganchos e examinar as funções que eles contêm para ver qual deles está modificando seu comportamento.

Se as funções nesses ganchos não descreverem completamente o comportamento observado, verifique as funções para obter conselhos que serão exibidos na documentação deles describe-function.


Edit: Escrevi algumas funções para ajudar a descrever um gancho melhor do que passar pelas funções uma por uma: https://gist.github.com/jordonbiondo/bad03e44bb053db0f1eb Você pode usar as describe-hookdefinições definidas como as outras funções de descrição. Aqui está uma amostra de sua saída:

E aqui está todo o código, caso a essência desapareça:

(defun guess-all-hooks ()
  "Return a list of all variables that are probably hook lists."
  (let ((syms '()))
    (mapatoms
     (lambda (sym)
       (if (ignore-errors (symbol-value sym))
           (let ((name (symbol-name sym)))
             (when (string-match "-\\(hook[s]?\\|functions\\)$" name)
               (push sym syms))))))
    syms))

(defun face-it (str face)
  "Apply FACE to STR and return."
  (propertize str 'face face))

(defun describe-hook (hook)
  "Display documentation about a hook variable and the
functions it contains."
  (interactive
   (list (completing-read
          "Hook: " (mapcar (lambda (x) (cons x nil)) (guess-all-hooks)))))
  (let* ((sym (intern hook))
         (sym-doc (documentation-property sym 'variable-documentation))
         (hook-docs (mapcar
                     (lambda (func)
                       (cons func (ignore-errors (documentation func))))
                     (symbol-value sym))))
    (switch-to-buffer
     (with-current-buffer (get-buffer-create "*describe-hook*")
       (let ((inhibit-read-only t))
         (delete-region (point-min) (point-max))
         (insert (face-it "Hook: " 'font-lock-constant-face) "\n\n")
         (insert (face-it (concat "`" hook "'") 'font-lock-variable-name-face))
         (replace-string "\n" "\n\t" nil
                         (point)
                         (save-excursion
                           (insert "\n" sym-doc "\n\n")
                           (1- (point))))
         (goto-char (point-max))
         (insert (face-it "Hook Functions: " 'font-lock-constant-face) "\n\n")
         (dolist (hd hook-docs)
           (insert (face-it (concat "`" (symbol-name (car hd)) "'")
                            'font-lock-function-name-face)
                   ": \n\t")
           (replace-string "\n" "\n\t" nil
                           (point)
                           (save-excursion
                             (insert (or (cdr hd) "No Documentation") "\n\n")
                             (1- (point))))
           (goto-char (point-max))))
       (help-mode)
       (help-make-xrefs)
       (read-only-mode t)
       (setq truncate-lines nil)
       (current-buffer)))))
Jordon Biondo
fonte
Isso significa que, quando uma função é aconselhada, a documentação é atualizada automaticamente para refletir a alteração?
Nispio
Não sei se as propriedades reais são atualizadas, mas o valor retornado por documentationé atualizado para refletir.
Jordon Biondo
1
@nispio sim, é.
Malabarba 24/09
1
O código / função em gist.github.com/jordonbiondo/bad03e44bb053db0f1eb poderia e, na minha opinião, deveria ser incluído na resposta. Eu acho que uma resposta SE tem um limite de 30.000 caracteres.
Faheem Mitha
4

Talvez não seja uma resposta completa para sua pergunta, mas o pacote helm-descbindsajuda a pesquisar todas as ligações de teclado definidas a partir da representação ascii do atalho. Para cada ocorrência, ela mostra a função interativa associada ao atalho do teclado, e você pode pedir helm-descbindspara descrevê- la ou executá- la diretamente a partir dos resultados da pesquisa.

insira a descrição da imagem aqui

Aqui está a descrição do pacote no site do GitHub:

Helm Descbinds fornece uma interface para as ligações de descrição do emacs, tornando as ligações de teclas ativas no momento pesquisáveis ​​interativamente com o leme.

Além disso, você tem as seguintes ações

  • Execute o comando
  • Descreva o comando
  • Encontre o comando

E C-zfornecerá uma descrição persistente do comando atual.

Amelio Vazquez-Reina
fonte
2
Isso é ótimo. Definitivamente vou vincular isso C-h b. O meu único desejo é que eu poderia saltar para o item na lista, digitando a seqüência de teclas real em vez de digitarC - c _ C - p
nispio