Warum kann ich meine Funktion nicht an eine Taste binden oder mit Mx aufrufen?

12

Ich habe eine Funktion geschrieben und möchte sie über Mx aufrufen und an eine Taste binden. Das ist meine Funktion:

(defun my-function ()
    (message "This is a great function"))

Wenn ich versuche, es mit aufzurufen M-x my-function, erhalte ich den Fehler: [no match]im Minipuffer.

Wenn ich versuche, es an eine Taste (oder einen Mausklick) zu binden:

(global-set-key (kbd "C-c a") 'my-function)

Es scheint zu funktionieren, aber wenn ich versuche, es mit aufzurufen C-c a, erhalte ich den Fehler

Falsches Typargument: commandp, my-function

Warum kann ich meine Funktion nicht nutzen?

Tyler
quelle
5
Ich melde mich freiwillig als allgemeine Antwort auf häufig gestellte Fragen zu diesem Thema. Es ist jedoch sinnvoll, die Frage und Antwort für Personen mit ähnlichen Problemen auffindbar und nützlich zu machen.
Tyler
1
Danke dafür, Tyler. Ich habe das Q für einen Moderator markiert, um dies in eine Community-Frage umzuwandeln.
Drew
Eine Sache, über die ich mich wundere, ist, ob der Titel nur die Fehlermeldung zitieren soll. Dies kann für die Benutzer einfacher zu finden sein und es können Antworten möglich sein, die nicht nur mit Hinzufügen zu tun haben interactive- z. B. verschwindet manchmal ein Befehl aus einer neuen Version einer Bibliothek. Der Fehler kann in jedem Kontext ausgelöst werden, in dem Emacs einen Befehl erwartet.
Drew
Es wäre gut, wenn die Leute jetzt das Wiki durchsuchen würden commandp, um zu versuchen, andere Qs zu finden, die als Duplikate von diesem geschlossen werden können. Lesen Sie jedoch die Fragen und Antworten sorgfältig durch, da sich einige davon unterscheiden. In einigen Fällen lohnt es sich, die Antwort (und den Q-Kontext) hier zu wiederholen. In anderen Fällen hat die Frage keinen Bezug und sollte so belassen werden, wie sie ist (nicht geschlossen).
Drew
1
@Drew Ich war mir nicht sicher, wie ich das am besten im Titel ankündigen sollte. Der Commandp-Fehler wird nur mit Tastenkombinationen angezeigt, sodass Personen, die aus der Mx-Richtung darauf zugreifen, die Verbindung nicht sehen können. Sie sind sich nicht sicher, wie die beste Balance zwischen einem klaren, präzisen Titel und einem Titel aussieht, der bei allen relevanten Suchanfragen angezeigt wird. Fühlen Sie sich frei zu zwicken, wie Sie möchten!
Tyler

Antworten:

21

Der Kernpunkt ist, dass es einen Unterschied zwischen einer Funktion und einem Befehl gibt .

In Emacs lisp können Funktionen standardmäßig nicht interaktiv aufgerufen werden. Das bedeutet, dass Sie nicht über M-xeinen Schlüssel oder Mausklick darauf zugreifen oder sie daran binden können. Wenn Sie das tun möchten, müssen Sie die Funktion explizit deklarieren interactive, indem Sie ein (interactive)Formular als erste Zeile im Hauptteil hinzufügen (nach der Dokumentationszeichenfolge). Eine interaktive Funktion wird als Befehl bezeichnet. Dies wird im Handbuch erklärt: (info "(elisp) Using Interactive") (Online-Version) .

Die angezeigte Fehlermeldung Wrong type argument: commandp, my-functionzeigt an, dass Sie versuchen, eine Funktion interaktiv aufzurufen, diese Funktion jedoch kein Befehl ist .

Um den tatsächlichen Fehler zu erklären, wird der Buchstabe phäufig in Lispeln verwendet, um ein Prädikat oder einen Test anzugeben. In diesem Fall testet Emacs mit dem Test my-function, ob es sich um einen Befehl handelt commandp. Es ist nicht, was zu dem Fehler führt. Ähnliche Fehler treten auf, wenn Sie ein Objekt des falschen Typs verwenden: Wenn Emacs einen String erwartet und Sie ein Symbol übergeben, wird möglicherweise ein Verweis auf stringpangezeigt.

Um die gestellte Frage zu beantworten, müssen Sie die (interactive)Zeile zur Definition hinzufügen :

(defun my-function ()
    (interactive)
    (message "This is a great function"))

Es gibt viele Optionen für das interactiveFormular, die alle Arten der Weitergabe von Informationen an Ihre Funktion unterstützen. Überprüfen Sie das Handbuch für alle Details.

Ein Sonderfall sind in diesem Zusammenhang Tastaturmakros. Ein Tastaturmakro ist eine Folge von Eingabeereignissen, die als Zeichenfolge dargestellt werden. Tastaturmakros verhalten sich wie Befehle, sodass Sie sie an Tasten binden können, ohne sich Gedanken über das Hinzufügen einer interactiveDeklaration machen zu müssen. Zum Beispiel im Folgenden:

(global-set-key (kbd "C-c l") "λ")

"λ"ist ein Tastaturmakro, an das wir es C-c lproblemlos binden können . Wenn wir versuchen, dasselbe mit einer Funktion zu tun, müssen wir die Funktion folgendermaßen definieren interactive:

(global-set-key (kbd "C-c k") 
  (lambda () (insert "λ"))
;; C-c k is undefined! We tried to bind it to a function

(global-set-key (kbd "C-c m") 
  (lambda () (interactive) (insert "λ"))
;; C-c m is bound to a command that inserts λ
Tyler
quelle
Ein Vorschlag, den ich hinzufügen möchte, macht deutlich, dass Sie Cx Ce ausführen müssen, bevor Sie es M-x my-functionin Ihrem Beispiel tun . Auch als Emacs-Anfänger bin ich mir wirklich noch nicht zu 100% klar, was genau C-x C-epassiert oder wann man es ausführen muss, aber es scheint, dass ähm ... wenn man es ausführt, es den Puffer analysiert und my-functionim Speicher überschreibt, wenn ich da bin Nicht rennen C-x C-e M-xführt die Funktion aus dem letzten Mal, als ich rannteC-x C-e
jrh
Es sieht so aus, als würde C-x C-e der Puffer ausgewertet. Das Ergebnis der Auswertung eines Puffers, der a enthält, scheint, dass die defunFunktion registriert wird. In diesem Artikel habe ich jedoch den Eindruck, dass die Funktion nur ausgeführt werden sollte. Der Minipuffer enthält jedoch nur Folgendes my-function(was bedeutet, dass es die Funktion zurückgibt?), nicht This is a great function. Ich muss hier etwas vermissen.
jrh
1
Vielen Dank für Ihre Kommentare, @jrh. Diese Frage und Antwort befasst sich mit einem bestimmten Aspekt von elisp, wie man eine Funktion interaktiv macht (dh aus einer Funktion einen Befehl macht). Sie fragen nach grundlegenderen Aspekten von elisp und sind nicht Gegenstand dieser Frage. Ich empfehle das Emacs Lisp Intro durchzuarbeiten. Sie scheinen verwirrt zu sein über den Unterschied zwischen dem Auswerten einer Funktionsdefinition, die eine Funktion (neu) definiert, sie aber nicht tatsächlich aufruft, und dem Aufrufen der Funktion, die den Funktionscode ausführt.
Tyler