Come posso rispondere a un prompt del minibuffer da elisp?


10

Occasionalmente mi ritrovo a utilizzare le funzioni interattive all'interno di una funzione che sto scrivendo per uso personale. Se una funzione richiede alcune informazioni (ad es. "File di output: ~ /") esiste un modo elisp generale per aggiungere testo al minibuffer e quindi premere Invio in modo che l'utente non debba farlo?

Ad esempio, supponiamo che io voglia eseguire org-latex-export-to-pdfuna funzione ma non voglio che l'utente debba specificare un nome file. La corsa (org-latex-export-to-pdf)sposterà il punto sul minibuffer, ma mettere qualcosa come (insert "filename.tex")nella riga successiva non sembra funzionare.


3
In genere, una funzione interattiva dovrebbe richiedere tali informazioni nella sua interactiveclausola. Quando viene chiamato da elisp, dovresti essere in grado di passare le informazioni come argomento di funzione. Naturalmente, questo non ti aiuta, nel caso in cui la funzione che stai tentando di chiamare non segua questo disegno.
Lindydancer,

Sì, ho scoperto che questo è il caso anche di solito (purtroppo non al momento) che potrebbe essere il motivo per cui la risposta a questo è stata così difficile da trovare. Sai se c'è un motivo di progettazione per voler davvero che l'utente digiti le risposte alle richieste del minibuffer?
Seth Rothschild,

Il tuo commento non è chiaro, per me. Vuoi che l'utente venga interrogato e risponda o no? In caso contrario, elaborare programmaticamente i valori degli argomenti (nome del file di output) desiderati / necessari e passarli alla funzione. Ti suggerisco di mostrare un po 'di codice o di rendere in qualche modo specifico e chiaro quali sono i tuoi problemi e le tue domande , o che la domanda rischia di essere chiusa come poco chiara.
Ha

Non voglio che l'utente (me) venga interrogato. Posso chiarire la domanda. Dopo aver letto parte di una discussione via e-mail che ti ha coinvolto alcuni anni fa sullo strappo al minibuffer, penso di sapere come farlo. Se lo faccio funzionare lo scrivo.
Seth Rothschild,

1
Si prega di pubblicare un esempio specifico di una funzione interattiva che si desidera utilizzare quando si scrive la propria funzione, in modo che un altro partecipante al forum possa dimostrare come passare un argomento alla funzione e bypassare del tutto il minibuffer.
elenco delle leggi del

Risposte:


3

Problema interessante. Sembra che l'editor post-command-hookvenga eseguito ogni volta che entra in un nuovo ciclo di comandi, ovvero a recursive-edit. Ma possiamo cominciare minibuffer-setup-hook, che esegue una funzione dopo aver inserito il minibuffer. Mentre ciò consente l'inserimento di input, è troppo presto per uscire dal minibuffer, perché il fermo non è stato ancora impostato.

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

È per questo che dobbiamo avvolgere gli "argomenti" nel nostro "ciclo di comandi", che viene eseguito ogni volta che entriamo in a recursive-edit, a quel punto si apre un argomento e si passa di livello 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

3

Ho scritto una macro per questo chiamato with-simulated-input, che puoi ottenere qui . Consente di fornire input arbitrari e di eseguire moduli lisp arbitrari al fine di simulare l'interazione dell'utente.

Per esempio:

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

ritornerebbe "hello world", con il "ciao" inserito dalla prima stringa, il "mondo" inserito tramite il codice lisp, e infine "RET" per terminare l'input.

Viene fornito con una suite di test che è possibile consultare per ulteriori esempi di utilizzo.


0

Sembra che l'uso di run-with-timercon insertfarà il lavoro.

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

Il comando, insertquando viene inserito successivamente, viene emesso troppo rapidamente. Prova a inserire la stringa prima che ci sia un posto dove inserirla.


Consiglierei di rivedere la tua domanda per chiedere assistenza passando a livello di codice un nome file org-export-output-file-namequando lo si utilizza in org-latex-export-to-pdfmodo che all'utente non venga richiesto il nome file. Puoi mettere i tuoi sforzi nella domanda - ad esempio, run-with-timerecc. - Tuttavia, non è una buona soluzione (secondo me). La soluzione migliore è passare correttamente un nome di file a livello di codice in modo che il minibuffer non si apra mai in primo luogo. Consiglierei di eliminare questa risposta in modo da ottenere una soluzione migliore da qualcuno con più elispesperienza.
elenco delle leggi del

@lawlist la domanda su come passare un nome di file org-latex-export-to-pdfnon è quella a cui sono interessato. È un esempio in quanto sembra che tu abbia intenzione di aggiungerne uno. La domanda che ho posto è quella che intendevo dire: esiste un modo per rispondere in modo affidabile alla richiesta di un minibuffer tramite elisp. Una soluzione caso per caso non è proprio quello che sto cercando. Dal tuo commento, posso dedurre che non è raccomandato.
Seth Rothschild,
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.