¿Cómo puedo responder una solicitud de minibúfer de elisp?

10

De vez en cuando me encuentro usando funciones interactivas dentro de una función que estoy escribiendo para mi propio uso. Si una función solicita información (por ejemplo, "Archivo de salida: ~ /"), ¿hay alguna forma general de elisp para agregar texto al minibúfer y luego presione Intro para que el usuario no tenga que hacerlo?

Como ejemplo, suponga que quiero ejecutar org-latex-export-to-pdfdentro de una función pero no quiero que el usuario tenga que especificar un nombre de archivo. Correr (org-latex-export-to-pdf)moverá el punto al minibúfer, pero poner algo como (insert "filename.tex")en la siguiente línea no parece funcionar.

Seth Rothschild
fuente
3
Típicamente, una función interactiva debe solicitar dicha información en su interactivecláusula. Cuando se llama desde elisp, debería poder pasar la información como un argumento de función. Por supuesto, esto no le ayuda, en caso de que la función que está intentando llamar no siga este diseño.
Lindydancer
Sí, he descubierto que ese también es el caso generalmente (desafortunadamente no en este momento), por lo que la respuesta a esto ha sido tan difícil de encontrar. ¿Sabes si hay una razón de diseño para realmente querer que el usuario escriba las respuestas a las indicaciones del minibúfer?
Seth Rothschild
Tu comentario no está claro, para mí. ¿Desea que el usuario sea consultado y responda o no? Si no es así, programe los valores de argumento (nombre del archivo de salida) que desea / necesita y páselos a la función. Le sugiero que muestre algún código o que de alguna otra manera especifique y aclare cuáles son su problema y su pregunta , o la pregunta corre el riesgo de ser cerrada por no estar clara.
Drew
No quiero que el usuario (yo) sea consultado. Puedo aclarar la pregunta. Después de leer parte de un hilo de correo electrónico que lo involucró hace unos años sobre tirar al minibúfer, creo que sé cómo hacerlo. Si lo hago funcionar lo escribiré.
Seth Rothschild
1
Publique un ejemplo específico de una función interactiva que le gustaría usar al escribir su propia función, para que otro participante del foro pueda demostrar cómo pasar un argumento a la función y omitir el minibúfer por completo.
abogados

Respuestas:

3

Interesante problema Parece que el editor se ejecuta post-command-hookcada vez que ingresa un nuevo ciclo de comandos, es decir, a recursive-edit. Pero podemos comenzar con minibuffer-setup-hook, que ejecuta una función después de ingresar al minibúfer. Si bien esto permite la inserción de la entrada, es demasiado pronto para salir del minibúfer, porque aún no se ha configurado la captura.

(defmacro with-minibuffer-input (form &rest inputs)
  (declare (indent 1))
  `(minibuffer-with-setup-hook
       (lambda ()
         (minibuffer-input-provider ',inputs))
     ,form))

Ahí es donde necesitamos envolver los 'argumentos' en nuestro propio 'bucle de comandos', que se ejecuta cada vez que ingresamos a recursive-edit, en ese punto aparece un argumento y sube un nivel, a través de exit-minibuffer.

;; -*- lexical-binding: t -*-
(defun minibuffer-input-provider (inputs)
  (let ((hook (make-symbol "hook")))
    (fset hook (lambda ()
                 (remove-hook 'post-command-hook hook)
                 (when inputs
                   (when (= 0 (minibuffer-depth))
                     (error "Too many inputs"))
                   (when (cdr inputs)
                     (add-hook 'post-command-hook hook))
                   (insert (pop inputs))
                   (exit-minibuffer))))
    (add-hook 'post-command-hook hook)))


(with-minibuffer-input (call-interactively 'find-file)
  "/")

(with-minibuffer-input (call-interactively 'occur)
  "\\(foo\\)\\(bar\\)" "\\1");;C-u C-x C-e

;;foobar

(with-minibuffer-input (call-interactively 'replace-string)
  "foo" "bar")

;; foo
politza
fuente
3

Escribí una macro para esta llamada with-simulated-input, que puedes obtener aquí . Le permite proporcionar una entrada arbitraria, así como ejecutar formularios arbitrarios de lisp para simular la interacción del usuario.

Por ejemplo:

(with-simulated-input '("hello SPC" (insert "world") "RET")
  (read-string "Enter greeting: "))

volvería "hello world", con el "hola" insertado por la primera cadena, el "mundo" insertado a través del código lisp, y finalmente "RET" para finalizar la entrada.

Viene con un conjunto de pruebas que puede consultar para obtener más ejemplos de uso.

Ryan C. Thompson
fuente
0

Parece que usar run-with-timercon inserthará el trabajo.

(run-with-timer .2 nil 'insert "filename.tex")
(run-with-timer .3 nil 'execute-kbd-macro (kbd "RET"))
(org-latex-export-to-pdf)

El comando insertcuando se coloca después aparece demasiado rápido. Intenta insertar la cadena antes de que haya un lugar para insertarla.

Seth Rothschild
fuente
Recomendaría revisar su pregunta para buscar ayuda para pasar un nombre de archivo org-export-output-file-namemediante programación al usar org-latex-export-to-pdfpara que el usuario no solicite el nombre del archivo. Puede poner sus esfuerzos en la pregunta, por ejemplo, run-with-timeretc., sin embargo, no es una buena solución (en mi opinión). La mejor solución es pasar correctamente un nombre de archivo mediante programación para que el minibúfer nunca se abra en primer lugar. Recomendaría eliminar esta respuesta para que alguien con más elispexperiencia obtenga una mejor solución .
abogados
@lawlist la pregunta de cómo pasar un nombre de archivo org-latex-export-to-pdfno es la que me interesa. Es un ejemplo, ya que parecía decidido a agregar uno. La pregunta que hice es a la que me refería: ¿hay alguna manera de responder de manera confiable un aviso de minibúfer a través de elisp? Una solución caso por caso no es lo que estoy buscando. De su comentario, puedo inferir que no se recomienda.
Seth Rothschild