Combina due funzioni interattive

Sep 19 2020

Ad esempio, voglio ordinare un file, quindi rimuovere le righe duplicate. Corro M-x sortseguito da M-x delete-duplicate-lines. Volevo combinarli in un'unica funzione interattiva. Ecco un tentativo per risolverlo.

(defun sort-and-dedup ()
 ""
 (interactive)
 (sort)
 (delete-duplicate-lines)
)

Questo dà un errore che dice che le funzioni sottostanti non hanno un numero sufficiente di argomenti. In qualche modo capisco perché è così (l'argomento interattivo vs non interattivo, tra gli altri), ma non so cosa fare esattamente. Puoi dirmi come correggerlo?

Modifica 1:

Il codice sopra è sbagliato in molti modi. Guarda la risposta accettata per informazioni. E grazie per l'aiuto.

Modifica 2:

Questo è ciò che intendevo fare.

(defun sort-and-dedup-region (beg end)
  (interactive "r")
  (sort-lines nil beg end)
  (delete-duplicate-lines beg end nil t))

(defun sort-and-dedup ()
  (interactive)
  (sort-and-dedup-region
   (point-min)
   (point-max)))

Risposte

4 NickD Sep 19 2020 at 01:48

[Credo che tu intendessi sort-lines, no sort- questo è l'unico modo in cui la domanda ha senso, quindi lo presumo.]

Entrambi sort-linese delete-duplicate-linesoperano sulla regione selezionata . Devi selezionare una regione prima di chiamarli, altrimenti si lamenteranno che non esiste una regione. Quindi dovrai fare la stessa cosa nella tua funzione: presumere che ti sia stata assegnata una regione e lamentarti se non ce n'è.

Una regione è specificata da due posizioni nel buffer, denominate convenzionalmente BEGe `END. Quindi la tua funzione sarà simile a questa:

(defun sort-and-dedup (beg end)
   (interactive <mumble>)
   (sort-lines nil beg end)
   (delete-duplicate-lines beg end))

Il primo argomento per ordinare le righe dice se ordinare in ordine inverso.

Quando si chiama la funzione in modo interattivo, si specifica una regione impostando un segno a un'estremità e quindi spostando il punto all'altra estremità (o iniziando da un'estremità e trascinando con il mouse all'altra estremità). Allora come comunichi queste posizioni alla funzione? Dando un argomento a interactive: se guardi la sua doc string (con C-h f interactive RET), scoprirai rcheèquello di cui hai bisogno per specificare una regione - Emacs si occuperà di tradurre la regione che hai scelto (comunque l'hai scelta) in una coppia di posizioni (BEG e END) che verranno passate alla funzione.

Quindi la funzione ha questo aspetto:

(defun sort-and-dedup (beg end)
   (interactive "r")
   (sort-lines nil beg end)
   (delete-duplicate-lines beg end))

In alternativa, come suggerisce @Dan, puoi usare call-interactivelye lasciare che ogni funzione capisca di cosa ha bisogno. Ma dovrai comunque specificare una regione in anticipo:

(defun sort-and-dedup ()
   (interactive)
   (call-interactively #'sort-lines)
   (call-interactively #'delete-duplicate-lines))

EDIT: incorporando il suggerimento di @ phil (e ora vedo che lo hai effettivamente implementato e aggiunto alla tua domanda), puoi scrivere una funzione che chiama (la prima definizione di) sort-and-dedupcon gli argomenti necessari per operare sull'intero buffer:

(defun sort-and-dedup-whole-buffer()
   (interactive)
   (sort-and-dedup (point-min) (point-max)))

Puoi associarlo a una sequenza di tasti se lo farai frequentemente:

(define-key global-map (kbd "M-S-<f10>" #'sort-and-dedup-whole-buffer)

anche se personalmente non lo farei: le sequenze di tasti sono una merce rara, quindi proverei ad usarle M-x sort-and-dedup-whole-buffer RETper un po '; se questo diventa un fastidio, lo assocerei a una sequenza di tasti.

Inoltre rivisito tutte le mie definizioni chiave ogni due anni e rivendico quelle che non uso più. Li tengo nel loro file, caricato esplicitamente dal mio file init, così posso trovarli e rivederli facilmente.