Bagaimana saya bisa menjawab prompt minibuffer dari elisp?

10

Saya kadang-kadang menemukan diri saya menggunakan fungsi interaktif di dalam fungsi yang saya tulis untuk saya gunakan sendiri. Jika suatu fungsi meminta beberapa informasi (mis. "File output: ~ /") apakah ada cara umum untuk menambahkan teks ke minibuffer dan kemudian tekan enter sehingga pengguna tidak harus melakukannya?

Sebagai contoh, misalkan saya ingin menjalankan org-latex-export-to-pdffungsi tetapi saya tidak ingin pengguna harus menentukan nama file. Berlari (org-latex-export-to-pdf)akan memindahkan poin ke minibuffer, tetapi menempatkan sesuatu seperti (insert "filename.tex")pada baris berikutnya tampaknya tidak berfungsi.

Seth Rothschild
sumber
3
Biasanya, fungsi interaktif harus meminta informasi tersebut dalam interactiveklausulnya. Ketika dipanggil dari elisp, Anda harus dapat meneruskan informasi sebagai argumen fungsi. Tentu saja, ini tidak membantu Anda, jika fungsi yang Anda coba panggil tidak mengikuti desain ini.
Lindydancer
Ya, saya telah menemukan bahwa untuk menjadi kasus juga biasanya (sayangnya tidak pada saat ini) yang mungkin menjadi alasan mengapa jawaban untuk ini sangat sulit ditemukan. Apakah Anda tahu jika ada alasan desain untuk benar - benar menginginkan pengguna untuk mengetik jawaban atas permintaan dari minibuffer?
Seth Rothschild
Komentar Anda tidak jelas, bagi saya. Apakah Anda ingin pengguna ditanya dan merespons atau tidak? Jika tidak maka secara programatik muncul dengan nilai argumen (nama file output) yang Anda inginkan / butuhkan dan meneruskannya ke fungsi. Saya sarankan Anda menunjukkan beberapa kode atau dengan cara lain membuat spesifik dan jelas apa masalah & pertanyaan Anda , atau pertanyaan berisiko ditutup sebagai tidak jelas.
Drew
Saya tidak ingin pengguna (saya) ditanyai. Saya bisa mengklarifikasi pertanyaannya. Setelah membaca bagian dari utas email yang melibatkan Anda dari beberapa tahun yang lalu tentang menarik ke minibuffer, saya rasa saya tahu bagaimana melakukan ini. Jika saya membuatnya berfungsi saya akan menuliskannya.
Seth Rothschild
1
Silakan kirim contoh spesifik dari fungsi interaktif yang ingin Anda gunakan saat menulis fungsi Anda sendiri, sehingga peserta forum lain dapat menunjukkan cara menyampaikan argumen ke fungsi dan memotong minibuffer sepenuhnya.
lawlist

Jawaban:

3

Masalah menarik. Sepertinya editor menjalankan post-command-hooksetiap kali memasuki loop-perintah baru, yaitu a recursive-edit. Tapi kita bisa mulai dengan minibuffer-setup-hook, yang menjalankan fungsi setelah memasuki minibuffer. Meskipun ini memungkinkan memasukkan input, masih terlalu cepat untuk keluar dari minibuffer, karena tangkapan belum diatur.

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

Itu adalah bahwa kita perlu untuk membungkus 'argumen' di dalam 'loop perintah' kita sendiri, yang dijalankan setiap kali kita memasukkan a recursive-edit, di mana saat itu muncul satu argumen dan melemparkan satu tingkat ke atas, melalui 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
sumber
3

Saya menulis makro untuk ini disebut with-simulated-input, yang bisa Anda dapatkan di sini . Ini memungkinkan Anda untuk memberikan input sewenang-wenang serta mengeksekusi bentuk-bentuk cadel sewenang-wenang untuk mensimulasikan interaksi pengguna.

Sebagai contoh:

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

akan kembali "hello world", dengan "halo" dimasukkan oleh string pertama, "dunia" dimasukkan melalui kode lisp, dan akhirnya "RET" untuk menyelesaikan input.

Muncul dengan test suite yang dapat Anda lihat untuk contoh penggunaan lebih lanjut.

Ryan C. Thompson
sumber
0

Tampaknya menggunakan run-with-timerdengan insertakan menyelesaikan pekerjaan.

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

Perintah insertketika ditempatkan setelah itu muncul terlalu cepat. Mencoba memasukkan string sebelum ada tempat untuk memasukkannya.

Seth Rothschild
sumber
Saya akan merekomendasikan merevisi pertanyaan Anda untuk mencari bantuan secara terprogram menyampaikan nama file org-export-output-file-nameketika menggunakan org-latex-export-to-pdfsehingga pengguna tidak diminta untuk nama file. Anda dapat menempatkan usaha Anda dalam pertanyaan - misalnya run-with-timer,, dll - namun, itu bukan solusi yang baik (menurut saya). Solusi yang lebih baik adalah dengan meneruskan nama file secara terprogram sehingga minibuffer tidak pernah terbuka. Saya akan merekomendasikan menghapus jawaban ini sehingga Anda mendapatkan solusi yang lebih baik oleh seseorang yang lebih elispberpengalaman.
hukum
@lawlist pertanyaan tentang bagaimana cara mengirimkan nama file org-latex-export-to-pdfbukan yang saya minati. Ini adalah contoh karena Anda sepertinya berniat untuk menambahkan saya. Pertanyaan yang saya ajukan adalah pertanyaan yang saya maksudkan: apakah ada cara untuk secara andal menjawab prompt minibuffer melalui elisp. Solusi kasus demi kasus sangat tidak sesuai dengan yang saya cari. Dari komentar Anda, saya dapat menyimpulkan bahwa itu tidak dianjurkan.
Seth Rothschild