Perché non posso associare la mia funzione a un tasto o chiamarla con Mx?


13

Ho scritto una funzione e voglio chiamarla tramite Mx e associarla a un tasto. Questa è la mia funzione:

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

Se provo a chiamarlo con M-x my-function, ottengo l'errore: [no match]nel mini-buffer.

Se provo a collegarlo a un tasto (o al clic del mouse):

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

Sembra funzionare, ma quando provo a chiamarlo con C-c a, ottengo l'errore

Argomento di tipo errato: commandp, my-function

Perché non posso usare la mia funzione?


5
Offro volontariamente questa domanda come risposta generica a domande frequenti su questo argomento. Sentiti libero di espandere o chiarire, tuttavia ha senso rendere la domanda e la risposta rilevabili e utili a persone con problemi simili!
Tyler,

1
Grazie per averlo fatto, Tyler. Ho contrassegnato la Q per un moderatore per favore convertilo in una domanda della community.
Disegnò il

Una cosa che mi chiedo è se il titolo debba solo citare il messaggio di errore. Questo potrebbe essere più facile da trovare per le persone e potrebbe consentire risposte che non hanno a che fare solo con l'aggiunta interactive- ad esempio, a volte un comando scompare da una nuova versione di una libreria. L'errore può essere generato in qualsiasi contesto in cui Emacs si aspetta un comando.
Disegnò il

Sarebbe bello se la gente ora cercasse nel wiki, diciamo commandp, di cercare altre Q che possono essere chiuse come duplicati di questo. Fai attenzione a leggere le domande e risposte, poiché alcune sono diverse. In alcuni casi, vale la pena ripetere la risposta (e il contesto Q). In altri casi la domanda non è correlata e dovrebbe essere lasciata così com'è (non chiusa).
Disegnò il

1
@Drew Non ero sicuro del modo migliore per "pubblicizzare" questo nel titolo. L'errore commandp viene visualizzato solo con le combinazioni di tasti, quindi le persone che si imbattono in questo dalla direzione Mx non vedranno la connessione. Non sono sicuro di quale sia il miglior equilibrio tra un titolo chiaro e conciso e un titolo che verrà visualizzato per tutte le query di ricerca pertinenti. Sentiti libero di modificare a tuo piacimento!
Tyler,

Risposte:


22

Il punto centrale è che esiste una differenza tra una funzione e un comando .

In Emacs lisp, le funzioni non sono richiamabili in modo interattivo per impostazione predefinita. Ciò significa che non è possibile accedervi tramite M-xo legarli a un tasto o un clic del mouse. Se vuoi farlo, devi dichiarare esplicitamente la funzione interactive, cosa che fai aggiungendo un (interactive)modulo come prima riga nel corpo (seguendo la stringa di documentazione). Una funzione interattiva si chiama comando Questo è spiegato nel manuale: (info "(elisp) Using Interactive") (versione online) .

Il messaggio di errore visualizzato Wrong type argument: commandp, my-functionindica che stai tentando di chiamare una funzione in modo interattivo, ma tale funzione non è un comando .

Per spiegare l'errore reale, la lettera pviene spesso utilizzata in lisp per indicare un predicato o un test. In questo caso, Emacs sta testando my-functionper vedere se si tratta di un comando che utilizza il test commandp. Non lo è, il che porta all'errore. Errori simili compaiono ogni volta che usi un oggetto del tipo sbagliato: se Emacs prevede una stringa e passi un simbolo, potresti vedere un riferimento stringp, ad esempio.

Per rispondere alla domanda come richiesto, è necessario aggiungere la (interactive)linea alla definizione:

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

Esistono molte opzioni per il interactivemodulo, che supporta tutti i tipi di modi per trasmettere informazioni alla tua funzione. Controlla il manuale per tutti i dettagli.

Le macro della tastiera sono un caso speciale in questo contesto. Una macro di tastiera è una sequenza di eventi di input, rappresentata come una stringa. Le macro della tastiera si comportano come comandi, quindi puoi associarle ai tasti senza preoccuparti di aggiungere una interactivedichiarazione. Ad esempio, di seguito:

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

"λ"è una macro di tastiera, quindi possiamo collegarla C-c lsenza problemi. Se proviamo a fare la stessa cosa con una funzione, dobbiamo essere sicuri di definire la funzione come 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 λ

un suggerimento che vorrei aggiungere, chiarire che è necessario fare Cx Ce prima di fare M-x my-functionnel tuo esempio. Inoltre, come principiante di emacs, non sono ancora chiaro al 100% su cosa C-x C-efaccia esattamente o quando è necessario eseguirlo, ma sembra che ... quando lo esegui, analizza il buffer e sovrascrive my-functionin memoria perché se io non eseguire C-x C-e M-xesegue la funzione dall'ultima volta che ho eseguitoC-x C-e
jrh

Sembrerebbe che C-x C-e valuti il ​​buffer , sembra che il risultato della valutazione di un buffer contenente a defunsia la registrazione della funzione, anche se questo articolo sembra farmi pensare che dovrebbe semplicemente eseguire la funzione, eppure l'unica cosa mostrata nel minibuffer è my-function(implica che restituisce la funzione?), no This is a great function. Qui mi sta sfuggendo qualcosa.
giovedì

1
Grazie per i tuoi commenti, @jrh. Questa domanda e risposta stanno affrontando un aspetto particolare di elisp, come rendere interattiva una funzione (cioè trasformare la funzione in un comando). Stai chiedendo di aspetti più fondamentali di elisp, e vanno oltre lo scopo di questa domanda. Raccomando di lavorare su Emacs Lisp Intro. Sembra che tu sia confuso sulla differenza tra la valutazione di una definizione di funzione, che (ri) definisce una funzione ma in realtà non la chiama e la chiamata della funzione, che esegue il codice della funzione.
Tyler,
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.