First of all, a disclaimer. I have researched this many times, and I am pretty sure that I have already found the answer one way or another, but I just don't understand it.
My problem is the following:
- I have a process running through comint
- I want to send a line of input, capture output and see when it is over (when the last line of the output matches the regexp for a prompt)
- only when the process has finished sending output, I want to send another line of input (for example).
For a bit of background, think of a major mode implementing interaction with a program, which may return an arbitrary amount of output, in arbitrarily long time. This should not be an unusual situation, right? Okay, maybe the part where I need to wait between inputs is unusual, but it has a few advantages over sending the input as a whole:
- the output buffer is nicely formatted: input output input output...
- more importantly, when sending a lot of text to a process, the text is cut into pieces and the pieces are pasted back by the process; the cutting points are arbitrary and this sometimes makes invalid input (my process won't paste back correctly an input cut in the middle of an identifier, for example)
Anyway, unusual or not, it turns out that it is complicated. Right now, I am using something along the lines of
(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))))
and I call this every time after sending an input line, and before sending the next one. Well... it works, that's already something.
But it also makes emacs hang
while waiting for the output. The reason is obvious, and I figured
that if I included some kind of asynchronous sleep-for
(for
example 1s) in the loop it would delay the output by 1s, but suppress
the hanging. Except that it seems that this kind of asynchronous
sleep-for
doesn't exist.
Or does it? More generally, is there an idiomatic way of achieving this with emacs? In other words:
How to send input to a process, wait for the output, then send more input, asynchronously?
When searching around (see the related questions), I have mainly seen mentions of sentinels (but I don't think it applies in my case, since the process doesn't finish) and of some comint hooks (but then what? should I make the hook buffer-local, turn my "evaluate the remaining lines" into a function, add this function to the hook and clean the hook afterwards? that sounds really dirty, doesn't it?).
I am sorry if am not making myself clear, or if there is really an obvious answer available somewhere, I am really confused by all the intricaties of process interaction.
If needed, I can make this all a working example, but I am afraid that it would just make one more "specific process question with specific process answer" like all those I found earlier and didn't help me.
Some related questions on SO: