Como uso nadvice?

29

Minha configuração está cheia de conselhos e continuo ouvindo sobre o novo nadvice.elpacote minimalista brilhante .

Pesquisei os manuais e li a fonte , mas admito abertamente: ainda não faço ideia de como usá-lo.

Alguém aqui pode me indicar um guia ou me dizer como começar a incluir meus conselhos de estilo antigo?

PythonNut
fonte
7
+1 para a pergunta. Se você já procurou os manuais e não encontrou o que você precisava, por favor considere a apresentação de uma (doc) relatório de bug: M-x report-emacs-bug. Alguns desenvolvedores às vezes preferem desenvolver do que documentar. ;-) É importante que o Emacs se documente.
Drew
2
O manual possui uma seção sobre isso, consulte (info "(elisp) Portando conselhos antigos") . Não está listado no índice detalhado por qualquer motivo.
wasamasa
3
Alguns exemplos usando nadvicedo meu config: : depois , : filtro de retorno , : em torno de , : antes, até
Kaushal Modi
1
@wasamasa Receio que essa seção esteja longe de estar completa. Tenho alguns conselhos (talvez apenas um, veremos) que são mais complexos. Devo apenas fazer uma pergunta para cada um aqui?
precisa saber é o seguinte

Respostas:

22

Todas as informações necessárias estão incluídas, C-h f add-functiondescrevendo o mecanismo subjacente de advice-add.

O novo sistema de aconselhamento basicamente age como substituir a definição atual de uma função pela função descrita na tabela em C-h f add-function, dependendo da sua escolha do WHERE argumento, apenas mais limpa para rastrear qual comportamento foi definido em qual arquivo de origem.

Um exemplo com a :aroundopção

O caso mais geral é a :aroundopção, então eu dou um exemplo para isso. (Provavelmente é melhor usar WHEREparâmetros dedicados quando possível, mas você pode substituir todos os outros por uma :aroundfunção equivalente ).

Apenas como exemplo, digamos que você queira depurar um pouco de uso find-file e queira a printsua lista de argumentos sempre que for chamada. Você poderia escrever

(defun my-find-file-advice-print-arguments (old-function &rest arguments)
  "Print the argument list every time the advised function is called."
  (print arguments)
  (apply old-function arguments))

(advice-add #'find-file :around #'my-find-file-advice-print-arguments)

Com esta nova implementação, tudo o que o conselho precisa é passado como argumento. ad-get-argstorna-se desnecessário, porque os argumentos são passados ​​para o conselho funcionam como argumentos de função normal (para WHEREargumentos para os quais faz sentido). ad-do-ittorna-se desnecessário à medida que o :aroundconselho obtém como argumentos a função e os argumentos, (ad-do-it)sendo substituído pelo formulário

(apply old-function arguments)

ou quando você nomeou os argumentos

(funcall old-function first-arg second-arg)

o que é mais limpo, pois não há formas mágicas envolvidas. A modificação dos argumentos simplesmente acontece passando valores modificados para OLD-FUNCTION.

Outros WHEREvalores

A documentação de add-functioncontém uma tabela de todos os locais de aconselhamento (ou "combinadores") e o que eles equivalem e explica a funcionalidade em termos de um lambdacomportamento equivalente à função recomendada:

`:before'       (lambda (&rest r) (apply FUNCTION r) (apply OLDFUN r))
`:after'        (lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
`:around'       (lambda (&rest r) (apply FUNCTION OLDFUN r))
`:override'     (lambda (&rest r) (apply FUNCTION r))
`:before-while' (lambda (&rest r) (and (apply FUNCTION r) (apply OLDFUN r)))
`:before-until' (lambda (&rest r) (or  (apply FUNCTION r) (apply OLDFUN r)))
`:after-while'  (lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r)))
`:after-until'  (lambda (&rest r) (or  (apply OLDFUN r) (apply FUNCTION r)))
`:filter-args'  (lambda (&rest r) (apply OLDFUN (funcall FUNCTION r)))
`:filter-return'(lambda (&rest r) (funcall FUNCTION (apply OLDFUN r)))

(cited from `C-h f add-function')

onde FUNCTION é a função de aconselhamento e OLDFUN a função em que o conselho é adicionado. Não tente entender todos eles de uma só vez, basta selecionar um WHEREsímbolo que pareça adequado e tentar entendê-lo.

Ou apenas use :around. Tanto quanto posso dizer, a única vantagem de usar WHEREs especializados :aroundpara tudo é que você obtém um pouco mais de informações C-h f ADVISED-FUNCTION antes de ler a documentação do conselho. A menos que você planeje publicar o código que contém os conselhos, provavelmente não importa.

Funções de aconselhamento nomeadas

Recomendo o uso de funções nomeadas como orientação, pois oferece muitas vantagens (algumas também se aplicam ao uso de funções nomeadas para ganchos):

  • Ele aparece C-h f find-filecomo

    :around advice: `my-find-file-advice-print-arguments'
    

    link para a definição da função de aconselhamento, que normalmente contém um link para o arquivo em que foi definido. Se o conselho tivesse sido definido como um lambdaformulário diretamente no advice-add formulário, a doutrina seria mostrada em linha (uma bagunça para longas doutrinas?) E nada indicaria onde foi definida.

  • Você pode remover o aviso com

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • Você pode atualizar a definição do aviso sem executar novamente advice-addou arriscar para manter a versão antiga ativa (a execução de advice-adduma alteração lambdaserá reconhecida como novo aviso, não como uma atualização do antigo).

Observação lateral A #'functionnotação é basicamente equivalente a 'function, exceto que ajuda o compilador de bytes a identificar símbolos como nomes de funções e, assim, a identificar funções ausentes (por exemplo, devido a erros de digitação).

kdb
fonte
De acordo com a discussão que tive com Stephen Monnier, aspas não devem ser usadas aqui em todos os argumentos. Deve ser (advice-add 'find-file :around #'my-find-file-advice-print-arguments)e da mesma forma (advice-remove 'find-file #'my-find-file-advice-print-arguments).
Kaushal Modi
Eu acho que advice-addé um caso de fronteira. Pessoalmente, considero a ' ↔ #'distinção principalmente uma ajuda para identificar erros de digitação nos nomes das funções; portanto, aqui provavelmente dependeria de se esperar que a função seja definida no momento em que o conselho é adicionado.
Kdb
@kdb Acabei descobrindo isso por mim mesmo (depois de me deparar com os documentos para add-function). Eu gostaria que os documentos deixassem isso mais claro. Eu posso tentar fazer um patch para isso.
precisa saber é o seguinte
@kdb Você quer dizer "Ele aparece C-h f find-file, não é C-x?
Peeja
@Peeja Sim, corrigiu.
Kdb 30/03/16