Come uso nadvice?


29

La mia configurazione è piena di consigli e continuo a sentir parlare del nuovo brillante nadvice.elpacchetto minimalista .

Ho cercato i manuali e ho letto la fonte , ma lo ammetto apertamente: non ho ancora idea di come usarlo effettivamente.

Qualcuno qui può indicarmi una guida o dirmi come iniziare a eseguire il porting dei miei consigli vecchio stile?


7
+1 per la domanda. Se hai cercato i manuali e non trovato quello che avevi bisogno, perche il deposito di un (doc) bug report: M-x report-emacs-bug. Alcuni sviluppatori a volte preferiscono sviluppare piuttosto che documentare. ;-) È importante che Emacs si documenti.
Estratto l'

2
Il manuale in realtà ha una sezione su questo, vedi (info "(elisp) Porting vecchi consigli") . Non è elencato nell'indice dettagliato per qualunque motivo.
wasamasa,


3
Alcuni esempi che utilizzano nadvicedal mio config: : dopo , : filtro-ritorno , : intorno , : prima, fino a quando
Kaushal Modi

1
@wasamasa Temo che la sezione sia lungi dall'essere completa. Ho alcuni consigli (forse solo uno, vedremo) che sono più complessi. Devo solo fare una domanda per ognuno qui?
PythonNut,

Risposte:


22

Tutte le informazioni necessarie sono incluse in C-h f add-functioncui viene descritto il meccanismo sottostante di advice-add.

Il nuovo sistema di consulenza agisce sostanzialmente come la sostituzione della definizione corrente di una funzione con la funzione descritta nella tabella in C-h f add-function, a seconda della scelta WHERE dell'argomento, solo più pulita per tenere traccia di quale comportamento è stato definito in quale file sorgente.

Un esempio con l' :aroundopzione

Il caso più generale è l' :aroundopzione, quindi do un esempio per questo. (Probabilmente è meglio usare WHEREparametri dedicati quando possibile, ma è possibile sostituirsi a vicenda con una :aroundfunzione equivalente ).

Ad esempio, supponiamo che tu voglia eseguire il debug di un certo uso find-file e desideri il printsuo elenco di argomenti ogni volta che viene chiamato. Potresti scrivere

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

Con questa nuova implementazione, tutto ciò di cui ha bisogno il consiglio viene passato come argomento. ad-get-argsdiventa inutile, perché gli argomenti vengono passati alla funzione di avviso come normali argomenti di funzione (per WHEREargomenti per i quali ha senso). ad-do-itdiventa inutile quando il :aroundconsiglio ottiene come argomenti la funzione e gli argomenti, quindi (ad-do-it)viene sostituito dal modulo

(apply old-function arguments)

o quando hai nominato gli argomenti

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

che è più pulito in quanto non vi sono forme magiche coinvolte. La modifica degli argomenti avviene semplicemente passando a valori modificati OLD-FUNCTION.

Altri WHEREvalori

La documentazione di add-functioncontiene una tabella di tutti i posti di consulenza (o "combinatori"), a cosa sono equivalenti e spiega la funzionalità in termini di lambdacomportamento equivalente alla funzione consigliata:

`: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')

dove FUNCTION è la funzione di avviso e OLDFUN la funzione in cui viene aggiunto l'avviso. Non cercare di capirli tutti in una volta, basta selezionare un WHEREsimbolo che sembra appropriato e provare a capirlo.

O semplicemente usa :around. Per quanto ne so, l'unico vantaggio dell'uso di WHEREs specializzati in :aroundtutto è che puoi ottenere un po 'più di informazioni guardando C-h f ADVISED-FUNCTION prima di leggere la documentazione del consiglio. A meno che tu non preveda di pubblicare il codice contenente i consigli, probabilmente non importa.

Funzioni di consulenza nominate

Consiglio di usare le funzioni nominate come consiglio poiché offre molti vantaggi (alcune si applicano anche all'uso delle funzioni nominate per gli hook):

  • Si presenta in C-h f find-fileas

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

    collegamento alla definizione della funzione di avviso, che come al solito contiene un collegamento al file in cui è stato definito. Se il consiglio fosse stato definito come un lambdamodulo direttamente nel advice-add modulo, il docstring verrebbe mostrato in linea (un pasticcio per lunghi docstring?) E nulla indicherebbe dove è stato definito.

  • Puoi rimuovere il consiglio con

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • Puoi aggiornare la definizione del consiglio senza rieseguire advice-addo rischiare di mantenere attiva la vecchia versione (poiché l'esecuzione advice-addcon una modifica lambdaverrà riconosciuta come nuova consulenza, non come aggiornamento a quella precedente).

Nota laterale La #'functionnotazione è sostanzialmente equivalente a 'function, tranne per il fatto che aiuta il compilatore di byte a identificare i simboli come nomi di funzione e quindi a identificare le funzioni mancanti (ad esempio a causa di errori di battitura).


Come per la discussione che ho avuto con Stephen Monnier, le citazioni di hash non dovrebbero essere usate qui in tutti gli argomenti .. dovrebbe essere (advice-add 'find-file :around #'my-find-file-advice-print-arguments)e allo stesso modo (advice-remove 'find-file #'my-find-file-advice-print-arguments).
Kaushal Modi,

Immagino advice-addsia un caso limite. Personalmente considero la ' ↔ #'distinzione come principalmente un aiuto per identificare errori di battitura nei nomi delle funzioni, quindi qui probabilmente dipenderebbe dal fatto che ci si aspetti che la funzione venga definita al momento dell'aggiunta del consiglio.
kdb,

@kdb Alla fine l'ho scoperto da solo (dopo essermi imbattuto nella documentazione per add-function). Vorrei che i documenti lo chiarissero. Potrei cercare di fare una patch per questo.
PythonNut

@kdb Intendi "Si presenta in C-h f find-file, no C-x?
Peeja,

@Peeja Sì, corretto.
kdb,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.