Wie nutze ich nadvice?

29

Meine Konfiguration ist voller Ratschläge, und ich höre immer wieder von dem neuen, glänzenden, minimalistischen nadvice.elPaket.

Ich habe die Handbücher durchsucht und die Quelle gelesen , aber ich gebe offen zu: Ich habe immer noch keine Ahnung, wie ich sie tatsächlich verwenden soll.

Kann mich hier jemand auf einen Leitfaden hinweisen oder mir sagen, wie ich anfangen kann, meine Ratschläge nach alter Art zu portieren?

PythonNut
quelle
7
+1 für die Frage. Wenn Sie die Handbücher haben gesucht und nicht gefunden , was Sie brauchen, denken Sie (doc) Bugreport Einreichung: M-x report-emacs-bug. Einige Entwickler bevorzugen manchmal die Entwicklung gegenüber der Dokumentation. ;-) Es ist wichtig, dass sich Emacs selbst dokumentiert.
Drew
2
Das Handbuch hat tatsächlich einen Abschnitt dazu, siehe (info "(elisp) Porting old advices") . Es ist jedoch aus irgendeinem Grund nicht im detaillierten Index aufgeführt.
Wasamasa
3
Einige Beispiele unter Verwendung nadvicevon meinem config: : nach , : Filter-Rückkehr , : um , : vor-bis
Kaushal Modi
1
@wasamasa Ich fürchte, dieser Abschnitt ist noch lange nicht vollständig. Ich habe ein paar Ratschläge (vielleicht nur einen, wir werden sehen), die komplexer sind. Sollte ich hier nur für jeden eine Frage stellen?
PythonNut

Antworten:

22

Alle Informationen, die Sie benötigen, sind enthalten und C-h f add-functionbeschreiben den zugrunde liegenden Mechanismus von advice-add.

Das neue Hinweissystem ersetzt im Grunde genommen die aktuelle Definition einer Funktion durch die in der Tabelle beschriebene Funktion. C-h f add-functionAbhängig von Ihrer Wahl des WHERE Arguments wird nur die Funktion übersichtlicher, um nachzuverfolgen, welches Verhalten in welcher Quelldatei definiert wurde.

Ein Beispiel mit der :aroundOption

Der allgemeinste Fall ist die :aroundOption, also gebe ich ein Beispiel dafür. (Es ist wahrscheinlich besser, WHEREwenn möglich dedizierte Parameter zu verwenden, aber Sie können jede andere durch eine entsprechende :aroundFunktion ersetzen .)

Nehmen wir als Beispiel an, Sie möchten bei jedem Aufruf die Verwendung von debuggen find-file und die printArgumentliste ändern. Du könntest schreiben

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

Mit dieser neuen Implementierung wird alles, was der Rat benötigt, als Argument übergeben. ad-get-argswird unnötig, da die Argumente als normale Funktionsargumente (für WHEREArgumente, für die es Sinn macht) an die Hinweisfunktion übergeben werden. ad-do-itwird unnötig, da :aroundBeratung als Argumente die Funktion und die Argumente erhält, also (ad-do-it)durch die Form ersetzt wird

(apply old-function arguments)

oder wenn Sie die Argumente benannt haben

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

Das ist sauberer, da keine magischen Formen beteiligt sind. Das Ändern der Argumente erfolgt einfach durch Übergeben geänderter Werte an OLD-FUNCTION.

Andere WHEREWerte

Der docstring von add-functionenthält eine Tabelle aller Beratungsstellen (oder "Kombinatoren") und deren Entsprechung und erläutert die Funktionsweise in Form eines lambdaVerhaltens, das der empfohlenen Funktion entspricht:

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

Dabei ist FUNCTION die Hinweisfunktion und OLDFUN die Funktion, in der der Hinweis hinzugefügt wird. Versuchen Sie nicht, alle auf einmal zu verstehen, wählen Sie einfach ein WHERESymbol aus, das passend klingt, und versuchen Sie, dieses zu verstehen.

Oder einfach benutzen :around. Soweit ich das beurteilen kann, besteht der einzige Vorteil der Verwendung von spezialisierten WHEREs :aroundfür alles darin, dass Sie ein bisschen mehr Informationen erhalten, wenn Sie C-h f ADVISED-FUNCTIONnachschlagen , bevor Sie die Dokumentation des Ratschlags lesen. Sofern Sie nicht vorhaben, den Code mit den Ratschlägen zu veröffentlichen, spielt dies wahrscheinlich keine Rolle.

Benannte Beratungsfunktionen

Ich empfehle die Verwendung benannter Funktionen als Hinweis, da dies viele Vorteile bietet (einige davon gelten auch für die Verwendung benannter Funktionen für Hooks):

  • Es zeigt sich in C-h f find-fileals

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

    Verknüpfung mit der Definition der Hinweisfunktion, die wie üblich eine Verknüpfung zu der Datei enthält, in der sie definiert wurde. Wenn der Hinweis als lambdaFormular direkt im advice-add Formular definiert worden wäre, würde der Docstring inline angezeigt (ein Durcheinander für lange Docstrings?) Und nichts würde darauf hinweisen, wo er definiert worden wäre.

  • Sie können den Hinweis mit entfernen

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • Sie können die Definition des Hinweises aktualisieren, ohne advice-adddie alte Version erneut ausführen zu müssen oder zu riskieren, sie aktiv zu halten (da das Ausführen advice-addmit einer geänderten Version lambdaals neuer Hinweis und nicht als Aktualisierung des alten Hinweises anerkannt wird).

Randbemerkung Die #'functionNotation ist im Wesentlichen gleichbedeutend mit 'function, mit dem Unterschied, dass sie dem Byte-Compiler hilft, Symbole als Funktionsnamen zu identifizieren und somit fehlende Funktionen (z. B. aufgrund von Tippfehlern) zu identifizieren.

kdb
quelle
Gemäß der Diskussion hatte ich mit Stephen Monnier, Hash-Zitate sollten hier nicht alle Argumente verwendet werden .. es sollte sein (advice-add 'find-file :around #'my-find-file-advice-print-arguments)und in ähnlicher Weise (advice-remove 'find-file #'my-find-file-advice-print-arguments).
Kaushal Modi
Ich denke, das advice-addist ein Grenzfall. Ich persönlich betrachte die ' ↔ #'Unterscheidung hauptsächlich als Hilfe bei der Identifizierung von Tippfehlern in Funktionsnamen, daher hängt es hier wahrscheinlich davon ab, ob man erwartet, dass die Funktion zum Zeitpunkt des Hinzufügens des Hinweises definiert wird.
kdb
@kdb Ich habe das schließlich selbst herausgefunden (nachdem ich die Dokumente für gelesen hatte add-function). Ich wünschte, die Dokumente würden das klarer machen. Ich könnte versuchen, einen Patch dafür zu machen.
PythonNut
@ kdb Meinen Sie "Es zeigt sich in C-h f find-file, nicht C-x?
Peeja
@Peeja Ja, das wurde korrigiert.
kdb