Wie kann ich eine Minibuffer-Eingabeaufforderung von elisp beantworten?

10

Gelegentlich verwende ich interaktive Funktionen innerhalb einer Funktion, die ich für meinen eigenen Gebrauch schreibe. Wenn eine Funktion nach Informationen fragt (z. B. "Ausgabedatei: ~ /"), gibt es eine allgemeine Möglichkeit, dem Minibuffer Text hinzuzufügen und dann die Eingabetaste zu drücken, damit der Benutzer dies nicht tun muss?

Angenommen, ich möchte org-latex-export-to-pdfinnerhalb einer Funktion ausgeführt werden, möchte aber nicht, dass der Benutzer einen Dateinamen angeben muss. Beim Laufen (org-latex-export-to-pdf)wird der Punkt in den Minibuffer verschoben, aber das Setzen (insert "filename.tex")in die nächste Zeile scheint nicht zu funktionieren.

Seth Rothschild
quelle
3
In der Regel sollte eine interaktive Funktion in ihrer interactiveKlausel nach solchen Informationen fragen. Wenn Sie von elisp aufgerufen werden, sollten Sie in der Lage sein, die Informationen als Funktionsargument zu übergeben. Dies hilft Ihnen natürlich nicht weiter, falls die Funktion, die Sie aufrufen möchten, diesem Entwurf nicht folgt.
Lindydancer
Ja, ich habe festgestellt, dass dies normalerweise auch der Fall ist (leider momentan nicht), weshalb die Antwort darauf möglicherweise so schwer zu finden war. Wissen Sie, ob es einen Entwurfsgrund gibt, warum der Benutzer wirklich Antworten auf Eingabeaufforderungen aus dem Minibuffer eingeben soll?
Seth Rothschild
Ihr Kommentar ist mir unklar. Möchten Sie, dass der Benutzer abgefragt wird und antwortet oder nicht? Wenn nicht, erstellen Sie programmgesteuert die gewünschten / benötigten Argumentwerte (Name der Ausgabedatei) und übergeben Sie diese an die Funktion. Ich schlage vor, dass Sie einen Code anzeigen oder auf andere Weise genau und klar machen, was Ihr Problem und Ihre Frage sind , oder dass die Frage als unklar geschlossen wird.
Drew
Ich möchte nicht, dass der Benutzer (ich) abgefragt wird. Ich kann die Frage klären. Nachdem ich einen Teil eines E-Mail-Threads gelesen habe, in dem Sie vor einigen Jahren über das Ziehen an den Minibuffer involviert waren, denke ich, dass ich weiß, wie das geht. Wenn es funktioniert, schreibe ich es auf.
Seth Rothschild
1
Bitte veröffentlichen Sie ein spezielles Beispiel für eine interaktive Funktion, die Sie beim Schreiben Ihrer eigenen Funktion verwenden möchten, damit ein anderer Forumsteilnehmer demonstrieren kann, wie ein Argument an die Funktion übergeben und der Minibuffer vollständig umgangen wird.
Lawlist

Antworten:

3

Interessantes Problem. Es sieht so aus, als würde der Editor post-command-hookjedes Mal ausgeführt, wenn er in eine neue Befehlsschleife eintritt, dh a recursive-edit. Aber wir können damit beginnen minibuffer-setup-hook, dass eine Funktion nach Eingabe des Minibuffers ausgeführt wird. Dies ermöglicht zwar das Einfügen von Eingaben, es ist jedoch zu früh, um den Minibuffer zu verlassen, da der Fang noch nicht eingerichtet wurde.

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

Dort müssen wir die 'Argumente' in unsere eigene 'Befehlsschleife' einbinden, die jedes Mal ausgeführt wird, wenn wir eine eingeben recursive-edit. An diesem Punkt wird ein Argument eingeblendet und eine Ebene nach oben über geworfen 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
quelle
3

Ich habe dafür ein Makro geschrieben with-simulated-input, das Sie hier bekommen können . Sie können beliebige Eingaben vornehmen und beliebige Lisp-Formulare ausführen, um die Benutzerinteraktion zu simulieren.

Beispielsweise:

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

würde zurückkehren "hello world", wobei das "Hallo" durch die erste Zeichenfolge eingefügt wird, die "Welt" über den Lisp-Code eingefügt wird und schließlich "RET", um die Eingabe zu beenden.

Es wird mit einer Testsuite geliefert, in der Sie weitere Anwendungsbeispiele finden.

Ryan C. Thompson
quelle
0

Es scheint, dass die Verwendung run-with-timermit insertden Job erledigt.

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

Der Befehl, insertder danach platziert wird, wird zu schnell angezeigt. Es wird versucht, die Zeichenfolge einzufügen, bevor ein Platz zum Einfügen vorhanden ist.

Seth Rothschild
quelle
Ich würde empfehlen, Ihre Frage zu überarbeiten, um Unterstützung bei der programmgesteuerten Übergabe eines Dateinamens an zu erhalten org-export-output-file-name, org-latex-export-to-pdfdamit der Benutzer nicht zur Eingabe des Dateinamens aufgefordert wird. Sie können Ihre Bemühungen in die Frage stellen - z. B. run-with-timerusw. - es ist jedoch keine gute Lösung (meiner Meinung nach). Die bessere Lösung besteht darin, einen Dateinamen programmgesteuert ordnungsgemäß zu übergeben, damit der Minibuffer überhaupt nicht geöffnet wird. Ich würde empfehlen, diese Antwort zu löschen, damit Sie von jemandem mit mehr elispErfahrung eine bessere Lösung erhalten .
Lawlist
@lawlist Die Frage, wie ein Dateiname übergeben werden soll, org-latex-export-to-pdfinteressiert mich nicht. Es ist ein Beispiel, da Sie anscheinend darauf bedacht waren, dass ich einen hinzufüge. Die Frage, die ich gestellt habe, ist die, die ich gemeint habe: Gibt es eine Möglichkeit, eine Minibuffer-Eingabeaufforderung durch elisp zuverlässig zu beantworten? Eine Lösung von Fall zu Fall ist nicht das, wonach ich suche. Aus Ihrem Kommentar kann ich schließen, dass es nicht empfohlen wird.
Seth Rothschild