Pourquoi ne puis-je pas lier ma fonction à une touche ou l'appeler avec Mx?

13

J'ai écrit une fonction, et je veux l'appeler via Mx, et la lier à une clé. C'est ma fonction:

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

Si j'essaye de l'appeler avec M-x my-function, j'obtiens l'erreur: [no match]dans le mini-tampon.

Si j'essaie de le lier à une clé (ou un clic de souris):

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

Cela semble fonctionner, mais lorsque j'essaie de l'appeler avec C-c a, j'obtiens l'erreur

Argument de type incorrect: commandp, ma-fonction

Pourquoi ne puis-je pas utiliser ma fonction?

Tyler
la source
5
Je propose cette question comme une réponse générique aux questions fréquemment posées à ce sujet. N'hésitez pas à développer ou à clarifier, mais il est logique de rendre la question et la réponse découvrables par et utiles aux personnes ayant des problèmes similaires!
Tyler
1
Merci d'avoir fait ça, Tyler. J'ai signalé le Q pour un modérateur pour convertir ceci en question communautaire.
Drew
Je me demande notamment si le titre doit simplement citer le message d'erreur. Cela pourrait être plus facile à trouver pour les gens, et cela pourrait permettre des réponses qui n'ont pas à voir avec simplement l'ajout interactive- par exemple, parfois une commande disparaît d'une nouvelle version d'une bibliothèque. L'erreur peut être déclenchée dans n'importe quel contexte où Emacs attend une commande.
Drew
Ce serait bien si les gens cherchaient maintenant sur le wiki, par exemple, commandppour essayer de trouver d'autres Q qui peuvent être fermés en tant que doublons de celui-ci. Attention cependant à lire les Q&R, car certains sont différents. Dans certains cas, la réponse (et le contexte Q) peut être utile de répéter ici. Dans d' autres cas, la question n'est pas liée et doit être laissée telle quelle (non fermée).
Drew
1
@Drew Je ne savais pas trop comment «faire de la publicité» dans le titre. L'erreur commandp n'apparaît qu'avec les raccourcis clavier, de sorte que les personnes rencontrant cela depuis la direction Mx ne verront pas la connexion. Vous ne savez pas quel est le meilleur équilibre entre un titre clair et concis et un titre qui apparaîtra pour toutes les requêtes de recherche pertinentes. N'hésitez pas à modifier comme vous le souhaitez!
Tyler

Réponses:

22

L'essentiel est qu'il existe une différence entre une fonction et une commande .

Dans Emacs lisp, les fonctions ne sont pas interactivement appelables par défaut. Cela signifie que vous ne pouvez pas y accéder via M-xou les lier à une touche ou un clic de souris. Si vous voulez le faire, vous devez déclarer explicitement la fonction interactive, ce que vous faites en ajoutant un (interactive)formulaire comme première ligne du corps (après la chaîne de documentation). Une fonction interactive est appelée une commande Ceci est expliqué dans le manuel: (info "(elisp) Using Interactive") (version en ligne) .

Le message d'erreur que vous voyez, Wrong type argument: commandp, my-functionindique que vous essayez d'appeler une fonction de manière interactive, mais que cette fonction n'est pas une commande .

Pour expliquer l'erreur réelle, la lettre pest souvent utilisée dans lisp pour indiquer un prédicat ou un test. Dans ce cas, Emacs teste my-functionpour voir s'il s'agit d'une commande utilisant le test commandp. Ce n'est pas le cas, ce qui conduit à l'erreur. Des erreurs similaires apparaissent chaque fois que vous utilisez un objet de type incorrect: si Emacs attend une chaîne et que vous passez un symbole, vous pouvez voir une référence à stringp, par exemple.

Pour répondre à la question posée, vous devez ajouter la (interactive)ligne à la définition:

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

Il existe de nombreuses options pour le interactiveformulaire, prenant en charge toutes sortes de façons de transmettre des informations à votre fonction. Consultez le manuel pour tous les détails.

Les macros de clavier sont un cas particulier dans ce contexte. Une macro clavier est une séquence d'événements d'entrée, représentée sous forme de chaîne. Les macros de clavier se comportent comme des commandes, vous pouvez donc les lier à des touches sans vous soucier d'ajouter une interactivedéclaration. Par exemple, dans ce qui suit:

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

"λ"est une macro de clavier, nous pouvons donc la lier C-c lsans problème. Si nous essayons de faire la même chose avec une fonction, nous devons être sûrs de définir la fonction comme 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
la source
une suggestion que je voudrais ajouter, il est clair que vous devez faire Cx Ce avant de le faire M-x my-functiondans votre exemple. Aussi en tant que débutant emacs, je ne suis pas encore vraiment sûr à 100% de ce qui se passe exactement C-x C-eou quand vous devez l'exécuter, mais il semble que euh ... lorsque vous l'exécutez, il analyse le tampon et écrase my-functionen mémoire parce que si je ne pas exécuter C-x C-e M-xexécute la fonction depuis la dernière fois que j'ai couruC-x C-e
2018
Il semblerait C-x C-e qu'évalue le tampon , il semble que le résultat de l'évaluation d'un tampon contenant un defunenregistre la fonction, bien que cet article semble me faire penser qu'il devrait simplement exécuter la fonction, et pourtant la seule chose affichée dans le mini-tampon est my-function(ce qui implique qu'il renvoie la fonction?), non This is a great function. Je dois manquer quelque chose ici.
2018
1
Merci pour vos commentaires, @jrh. Cette question et réponse traite d'un aspect particulier d'elisp, comment rendre une fonction interactive (c.-à-d. Transformer une fonction en une commande). Vous posez des questions sur des aspects plus fondamentaux d'elisp et sortez du cadre de cette question. Je recommande de travailler à travers l'Emacs Lisp Intro. Vous semblez confus quant à la différence entre l'évaluation d'une définition de fonction, qui (re) définit une fonction mais ne l'appelle pas réellement, et l'appel de la fonction, qui exécute le code de la fonction.
Tyler