Combina dos funciones interactivas

Sep 19 2020

Por ejemplo, quiero ordenar un archivo y luego eliminar las líneas duplicadas. Corro M-x sortseguido por M-x delete-duplicate-lines. Quería combinarlos en una única función interactiva. Aquí hay un intento de resolver esto.

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

Esto da un error que dice que las funciones subyacentes no tienen suficiente número de argumentos. Entiendo por qué ese es el caso (el argumento interactivo frente a no interactivo, entre algunos otros), pero no sé qué hacer exactamente. ¿Puedes decirme cómo corregir esto?

Edición 1:

El código anterior es incorrecto de muchas maneras. Mire la respuesta aceptada para obtener información. Y gracias por la ayuda.

Edición 2:

Esto es lo que pretendía hacer.

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

Respuestas

4 NickD Sep 19 2020 at 01:48

[Creo que quiso decir sort-lines, no sort, esa es la única forma en que la pregunta tiene sentido, así que la asumiré].

Ambos sort-linesy delete-duplicate-linesoperan en la región seleccionada . Debes seleccionar una región antes de llamarlos, de lo contrario se quejarán de que no hay región. Por lo tanto, tendrá que hacer lo mismo en su función: asumir que se le da una región y quejarse si no hay ninguna.

Una región se especifica mediante dos posiciones en el búfer, denominadas convencionalmente BEGy `END. Entonces su función se verá así:

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

El primer argumento para ordenar líneas le dice si debe ordenar en orden inverso.

Cuando llama a la función de forma interactiva, especifica una región colocando una marca en un extremo y luego moviendo el punto al otro extremo (o comenzando en un extremo y arrastrando con el mouse hasta el otro extremo). Entonces, ¿cómo comunica esas posiciones a la función? Al dar un argumento a interactive: si observa su cadena de documentos (con C-h f interactive RET), encontrará que res lo que necesita para especificar una región; Emacs se encargará de traducir la región que eligió (como la eligió) en un par de posiciones (BEG y END) que se pasarán a su función.

Entonces la función se ve así:

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

Alternativamente, como sugiere @Dan, puede usar call-interactivelyy dejar que cada función descubra lo que necesita. Pero aún tendrá que especificar una región de antemano:

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

EDITAR: incorporando la sugerencia de @ phil (y ahora veo que realmente implementó esto y lo agregó a su pregunta), puede escribir una función que llame (la primera definición de) sort-and-dedupcon los argumentos necesarios para operar en todo el búfer:

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

Puede vincularlo a una secuencia de teclas si lo va a hacer con frecuencia:

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

aunque yo personalmente no haría eso: las secuencias de teclas son un bien escaso, así que lo probaría usándolas M-x sort-and-dedup-whole-buffer RETpor un tiempo; si eso se convierte en una molestia, lo vincularía a una secuencia de teclas.

También reviso todas mis definiciones clave cada dos años y recupero las que ya no uso. Los guardo en su propio archivo, cargado explícitamente por mi archivo init, para poder encontrarlos y revisarlos fácilmente.