Pertama-tama, penafian. Saya telah meneliti ini berkali-kali, dan saya cukup yakin bahwa saya sudah menemukan jawabannya, tetapi saya tidak memahaminya.
Masalah saya adalah sebagai berikut:
- Saya memiliki proses yang berjalan melalui comint
- Saya ingin mengirim sederetan input, menangkap output dan melihat kapan usai (ketika baris terakhir dari output cocok dengan regexp untuk prompt)
- hanya ketika prosesnya selesai mengirimkan output, saya ingin mengirim jalur input lain (misalnya).
Untuk sedikit latar belakang, pikirkan mode utama yang menerapkan interaksi dengan suatu program, yang dapat mengembalikan jumlah output yang sewenang-wenang, dalam waktu yang lama secara sewenang-wenang. Ini seharusnya bukan situasi yang tidak biasa, bukan? Oke, mungkin bagian di mana saya harus menunggu di antara input tidak biasa, tetapi memiliki beberapa keunggulan dibandingkan mengirim input secara keseluruhan:
- buffer output diformat dengan baik: input output input output ...
- yang lebih penting, ketika mengirim banyak teks ke suatu proses, teks tersebut dipotong-potong dan potongan-potongan tersebut ditempelkan kembali oleh proses; titik potong sewenang-wenang dan ini kadang-kadang membuat input tidak valid (misalnya, proses saya tidak akan menempelkan kembali dengan benar potongan input di tengah pengenal, misalnya)
Pokoknya, tidak biasa atau tidak, ternyata bahwa itu adalah rumit. Saat ini, saya menggunakan sesuatu di sepanjang baris
(defun mymode--wait-for-output ()
(let ((buffer (mymode-get-buffer)))
(with-current-buffer buffer
(goto-char (point-max))
(forward-line 0)
(while (not (mymode-looking-at-prompt))
(accept-process-output nil 0.001)
(redisplay)
(goto-char (point-max))
(forward-line 0))
(end-of-line))))
dan saya menyebutnya setiap kali setelah mengirim saluran input, dan sebelum mengirim yang berikutnya. Yah ... itu berhasil, itu sudah sesuatu.
Tapi itu juga membuat emacs hang sambil menunggu output. Alasannya jelas, dan saya pikir jika saya memasukkan semacam asinkron sleep-for
(misalnya 1s) dalam loop itu akan menunda output oleh 1s, tetapi menekan penggantinya. Kecuali bahwa tampaknya jenis sinkron
sleep-for
tidak ada .
Atau apakah itu? Secara umum, adakah cara idiomatis untuk mencapai hal ini dengan emacs? Dengan kata lain:
Bagaimana cara mengirim input ke suatu proses, menunggu output, kemudian mengirim lebih banyak input, secara tidak sinkron?
Ketika mencari di sekitar (lihat pertanyaan terkait), saya terutama melihat menyebutkan penjaga (tapi saya tidak berpikir itu berlaku dalam kasus saya, karena prosesnya tidak selesai) dan beberapa kait komint (tapi kemudian apa? Haruskah saya buat hook-buffer lokal, ubah "evaluasi sisa baris" saya menjadi fungsi, tambahkan fungsi ini ke hook dan bersihkan hook sesudahnya? kedengarannya sangat kotor, bukan?).
Saya minta maaf jika saya tidak membuat diri saya jelas, atau jika benar-benar ada jawaban yang jelas di suatu tempat, saya benar-benar bingung dengan semua kerumitan interaksi proses.
Jika perlu, saya bisa menjadikan ini semua contoh yang baik, tetapi saya khawatir itu hanya akan membuat satu lagi "pertanyaan proses spesifik dengan jawaban proses spesifik" seperti semua yang saya temukan sebelumnya dan tidak membantu saya.
Beberapa pertanyaan terkait pada SO:
sumber
Jawaban:
Pertama-tama, Anda tidak boleh menggunakan
accept-process-output
jika Anda ingin pemrosesan asinkron. Emacs akan menerima output setiap kali menunggu input pengguna.Cara yang tepat untuk pergi adalah menggunakan fungsi filter untuk mencegat output. Anda tidak perlu membuat atau menghapus filter tergantung pada apakah Anda masih memiliki jalur untuk dikirim. Sebaliknya, Anda biasanya akan mendeklarasikan filter tunggal untuk masa proses dan menggunakan variabel buffer-lokal untuk melacak negara dan melakukan hal-hal yang berbeda sesuai kebutuhan.
Antarmuka tingkat rendah
Fungsi filter adalah apa yang Anda cari. Fungsi-fungsi filter adalah untuk menampilkan apa yang dimaksud dengan terminasi.
Lihatlah manual atau banyak contoh yang datang dengan Emacs (
grep
untukprocess-filter
dalam.el
file).Daftarkan fungsi filter Anda dengan
Antarmuka comint
Comint mendefinisikan fungsi filter yang melakukan beberapa hal:
comint-preoutput-filter-functions
, berikan teks baru sebagai argumen.comint-prompt-regexp
.comint-output-filter-functions
, berikan teks baru sebagai argumen.Karena mode Anda didasarkan pada comint, Anda harus mendaftarkan filter Anda
comint-output-filter-functions
. Anda harus mengaturcomint-prompt-regexp
agar sesuai dengan permintaan Anda. Saya tidak berpikir Comint memiliki fasilitas built-in untuk mendeteksi chunk output lengkap (yaitu antara dua prompt), tetapi dapat membantu. Markercomint-last-input-end
diatur di akhir potongan input terakhir. Anda memiliki potongan output baru ketika akhir dari prompt terakhir adalah setelahcomint-last-input-end
. Cara menemukan akhir dari prompt terakhir tergantung pada versi Emacs:comint-last-prompt-overlay
mencakup permintaan terakhir.comint-last-prompt
berisi penanda ke awal dan akhir dari prompt terakhir.Anda mungkin ingin menambahkan proteksi jika proses memancarkan output dalam urutan selain dari {menerima input, memancarkan output, menampilkan prompt}.
sumber