4

I'm using emacs version 25.1.1.

I would like to run a process synchronously and have its stdout and stderr end up in two different buffers. I know I can use make-process to separate stdout and stderr in this way, but make-process runs the process asynchronously.

For synchronous process invocation, I know I could use call-process with DESTINATION being set to (list stdout-buffer stderr-file), but then I would have to manage a temporary file to catch the stderr output, and that is inefficient.

Is there any function in emacs 25.x which will allow me to run a process synchronously with its stdout and stderr ending up in different buffers?

I also see this question being raised within a comment that was posted at the end of Capturing stderr of subprocesses more than 2 years after the original query, but it isn't answered there. Perhaps that short comment was overlooked, and that's why I'm posting this as a full-fledged question here.

Thank you in advance.

HippoMan
  • 582
  • 2
  • 11

2 Answers2

3

The c-function call-process is the basis for creating synchronous processes in Emacs. So you don't get more with any other functions.

The info page (elisp) Synchronous Processes contains the following section:

You can’t directly specify a buffer to put the error output in; that is too difficult to implement. But you can achieve this result by sending the error output to a temporary file and then inserting the file into a buffer when the subprocess finishes.

So the answer to your question

Is there any function in emacs 25.x which will allow me to run a process synchronously with its stdout and stderr ending up in different buffers?

is no if you do not allow temporary files.

Tobias
  • 32,569
  • 1
  • 34
  • 75
  • Yes, I know that's what the documentation states, but `make-process` was introduced, and it has no problems writing stderr to a buffer. Therefore, it couldn't possibly that difficult to implement that functionality. And looking at `process.c` within the emacs-25.1 code base, it indeed shows that this functionality is actually quite simple to code. But emacs is what it is, and since no one has implemented a synchronous way to capture stderr in a buffer, I can see that I have to live with this reality. – HippoMan Jun 04 '18 at 23:10
  • ... however, maybe in my spare time I'll write a patch to the C code that implements `call-process` – HippoMan Jun 04 '18 at 23:12
1

Another way I could do this without rewriting the C code for call-process would be to use make-process and go into a busy-wait loop that is similar to the following:

(defvar my-process-finished nil
  "*set when my process is finished")
(setq my-process-finished nil)
(defun my-sentinel (process event)
  (when (eq 'exit (process-status process))
    (setq my-process-finished t))
(make-process
   :name ...
   :command ...
   :buffer ...
   :stderr ...
   :sentinel 'my-sentinel)
(while (not my-process-finished)
  (sleep-for 0.25))
;;; continue from here

... or maybe even this:

(setq proc (make-process ... etc. ...))
(while (not (eq 'exit (process-status proc)))
  (sleep-for 0.25))
;;; continue from here

It's ugly, because I really should also check for 'failed, 'signal, and possibly other conditions. But I guess it can do the job.

... and here's my first cut at a function which will do this:

;; Does the same as `make-process`, but runs it                                                                                 
;; synchronously. Returns the exit code of                                                                                      
;; the process that is specified, or nil if                                                                                      
;; the process could not even be started.                                                                                       
(defun make-process-sync (&rest args)
  (let ((proc (apply 'make-process args)))
    (when proc
        (while (not (memq (process-status proc) '(exit failed signal)))
          (sleep-for 0.1))
        (process-exit-status proc))))
HippoMan
  • 582
  • 2
  • 11