Jak mogę odpowiedzieć na pytanie o minibufor z Elisp?

10

Czasami używam interaktywnych funkcji wewnątrz funkcji, którą piszę na własny użytek. Jeśli funkcja prosi o pewne informacje (np. „Plik wyjściowy: ~ /”), czy istnieje ogólny sposób dodawania tekstu do minibufora, a następnie naciśnij klawisz Enter, aby użytkownik nie musiał tego robić?

Jako przykład załóżmy, że chcę uruchomić org-latex-export-to-pdfwewnątrz funkcji, ale nie chcę, aby użytkownik musiał określać nazwę pliku. Bieganie (org-latex-export-to-pdf)przeniesie punkt do minibufora, ale umieszczenie czegoś (insert "filename.tex")w następnym wierszu nie wydaje się działać.

Seth Rothschild
źródło
3
Zazwyczaj funkcja interaktywna powinna pytać o takie informacje w swojej interactiveklauzuli. Po wywołaniu z elisp, powinieneś być w stanie przekazać informacje jako argument funkcji. Oczywiście to ci nie pomoże, na wypadek gdyby funkcja, którą próbujesz wywołać, nie spełnia tego założenia.
Lindydancer
Tak, stwierdziłem, że tak też jest zwykle (niestety w tej chwili), dlatego być może tak trudno było znaleźć odpowiedź na to pytanie. Czy wiesz, czy istnieje powód, dla którego naprawdę chcesz, aby użytkownik wpisywał odpowiedzi na pytania z minibufora?
Seth Rothschild
Twój komentarz jest dla mnie niejasny. Czy chcesz, aby użytkownik był pytany i odpowiadał, czy nie? Jeśli nie, to programowo wymyśl wartości argumentów (nazwę pliku wyjściowego), których chcesz / potrzebujesz i przekaż je do funkcji. Sugeruję, abyś pokazał jakiś kod lub w inny sposób sprecyzował i wyjaśnił, na czym polega Twój problem i pytanie, w przeciwnym razie istnieje ryzyko, że zostanie ono zamknięte jako niejasne.
Drew
Nie chcę, aby użytkownik (ja) był pytany. Mogę wyjaśnić pytanie. Po przeczytaniu części wątku e-mailowego dotyczącego twojego szarpania się w minibuforze kilka lat temu, myślę, że wiem, jak to zrobić. Jeśli to zadziała, napiszę to.
Seth Rothschild
1
Proszę podać konkretny przykład funkcji interaktywnej, z której chcielibyście korzystać przy pisaniu własnej funkcji, aby inny uczestnik forum mógł zademonstrować, jak przekazać argument do funkcji i całkowicie ominąć minibufor.
prawnik

Odpowiedzi:

3

Ciekawy problem. Wygląda na to, że edytor działa za post-command-hookkażdym razem, gdy wchodzi w nową pętlę poleceń, tj recursive-edit. Ale możemy zacząć od minibuffer-setup-hook, który wykonuje funkcję po wejściu do minibufora. Chociaż pozwala to na wstawianie danych wejściowych, jest zbyt wcześnie, aby wyjść z minibufora, ponieważ catch nie został jeszcze skonfigurowany.

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

Właśnie dlatego musimy zawinąć „argumenty” w naszą własną „pętlę poleceń”, która jest wykonywana za każdym razem, gdy wchodzimy do recursive-edit, w którym to momencie wyskakuje jeden argument i podnosi poziom o jeden poziom wyżej 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
źródło
3

Napisałem makro dla tego o nazwie with-simulated-input, które można uzyskać tutaj . Umożliwia to wprowadzanie dowolnych danych wejściowych, a także wykonywanie dowolnych formularzy seplenienia w celu symulacji interakcji użytkownika.

Na przykład:

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

zwróci "hello world", z „hello” wstawionym przez pierwszy ciąg, „world” wstawiony za pomocą kodu lisp, a na końcu „RET”, aby zakończyć wprowadzanie.

Jest dostarczany z zestawem testowym, na którym można znaleźć więcej przykładów użycia.

Ryan C. Thompson
źródło
0

Wygląda na to, że użycie run-with-timerz insertspowoduje wykonanie pracy.

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

Polecenie insertpo umieszczeniu później pojawia się zbyt szybko. Próbuje wstawić ciąg, zanim będzie miejsce do wstawienia.

Seth Rothschild
źródło
Zalecam ponowne przeanalizowanie pytania, aby uzyskać pomoc w programowym przekazaniu nazwy pliku org-export-output-file-namepodczas używania, org-latex-export-to-pdfaby użytkownik nie był monitowany o nazwę pliku. Możesz postawić swoje wysiłki w pytaniu - np. run-with-timerItp. - jednak nie jest to dobre rozwiązanie (moim zdaniem). Lepszym rozwiązaniem jest prawidłowe przekazanie nazwy pliku programowo, tak aby minibufor nigdy się nie otwierał. Zalecam usunięcie tej odpowiedzi, aby uzyskać lepsze rozwiązanie przez osobę z większym elispdoświadczeniem.
prawnik
@lawlist pytanie, w jaki sposób przekazać nazwę pliku, org-latex-export-to-pdfnie jest tym, co mnie interesuje. Jest to przykład, ponieważ wydawało się, że chciałem dodać go. Pytanie, które zadałem, było tym, o którym mówiłem: czy istnieje sposób, aby rzetelnie odpowiedzieć na pytanie minibufora za pomocą elisp. Indywidualne rozwiązanie nie jest tym, czego szukam. Z twojego komentarza mogę wywnioskować, że nie jest to zalecane.
Seth Rothschild