(defvar eshell-last-command-name nil)
(defvar eshell-last-async-procs nil
"The currently-running foreground process(es).
-When executing a pipeline, this is a cons cell whose CAR is the
-first process (usually reading from stdin) and whose CDR is the
-last process (usually writing to stdout). Otherwise, the CAR and
-CDR are the same process.
-
-When the process in the CDR completes, resume command evaluation.")
+When executing a pipeline, this is a list of all the pipeline's
+processes, with the first usually reading from stdin and last
+usually writing to stdout.")
(defvar eshell-allow-commands t
"If non-nil, allow evaluating command forms (including Lisp forms).
(defsubst eshell-head-process ()
"Return the currently running process at the head of any pipeline.
This only returns external (non-Lisp) processes."
- (car-safe eshell-last-async-procs))
+ (car eshell-last-async-procs))
(defsubst eshell-tail-process ()
"Return the currently running process at the tail of any pipeline.
This only returns external (non-Lisp) processes."
- (cdr-safe eshell-last-async-procs))
+ (car (last eshell-last-async-procs)))
(define-obsolete-function-alias 'eshell-interactive-process
'eshell-tail-process "29.1")
(defmacro eshell-do-pipelines (pipeline &optional notfirst)
"Execute the commands in PIPELINE, connecting each to one another.
+Returns a list of the processes in the pipeline.
+
This macro calls itself recursively, with NOTFIRST non-nil."
(when (setq pipeline (cadr pipeline))
(eshell--unmark-deferrable (car pipeline))
`(eshell-with-copied-handles
- (progn
- ,(when (cdr pipeline)
- `(let ((nextproc
- (eshell-do-pipelines (quote ,(cdr pipeline)) t)))
- (eshell-set-output-handle ,eshell-output-handle
- 'append nextproc)))
- ;; First and last elements in a pipeline may need special treatment.
- ;; (Currently only eshell-ls-files uses 'last.)
- ;; Affects process-connection-type in eshell-gather-process-output.
- (let ((eshell-in-pipeline-p
- ,(cond ((not notfirst) (quote 'first))
- ((cdr pipeline) t)
- (t (quote 'last)))))
- (let ((proc ,(car pipeline)))
- (set headproc (or proc (symbol-value headproc)))
- (set tailproc (or (symbol-value tailproc) proc))
- proc)))
+ (let ((next-procs
+ ,(when (cdr pipeline)
+ `(eshell-do-pipelines (quote ,(cdr pipeline)) t)))
+ ;; First and last elements in a pipeline may need special
+ ;; treatment (currently only `eshell-ls-files' uses
+ ;; `last'). Affects `process-connection-type' in
+ ;; `eshell-gather-process-output'.
+ (eshell-in-pipeline-p
+ ,(cond ((not notfirst) (quote 'first))
+ ((cdr pipeline) t)
+ (t (quote 'last)))))
+ ,(when (cdr pipeline)
+ `(eshell-set-output-handle ,eshell-output-handle
+ 'append (car next-procs)))
+ (let ((proc ,(car pipeline)))
+ (cons proc next-procs)))
;; Steal handles if this is the last item in the pipeline.
,(null (cdr pipeline)))))
(defmacro eshell-do-pipelines-synchronously (pipeline)
"Execute the commands in PIPELINE in sequence synchronously.
-Output of each command is passed as input to the next one in the pipeline.
-This is used on systems where async subprocesses are not supported."
+This collects the output of each command in turn, passing it as
+input to the next one in the pipeline. Returns the result of the
+first command invocation in the pipeline (usually t or nil).
+
+This is used on systems where async subprocesses are not
+supported."
(when (setq pipeline (cadr pipeline))
;; FIXME: is deferrable significant here?
(eshell--unmark-deferrable (car pipeline))
- `(progn
- (eshell-with-copied-handles
- (progn
- ,(when (cdr pipeline)
- `(let ((output-marker ,(point-marker)))
- (eshell-set-output-handle ,eshell-output-handle
- 'append output-marker)))
- (let (;; XXX: `eshell-in-pipeline-p' has a different meaning
- ;; for synchronous processes: it's non-nil only when
- ;; piping *to* a process.
- (eshell-in-pipeline-p ,(and (cdr pipeline) t)))
- (let ((result ,(car pipeline)))
- ;; `tailproc' gets the result of the last successful
- ;; process in the pipeline.
- (set tailproc (or result (symbol-value tailproc))))))
- ;; Steal handles if this is the last item in the pipeline.
- ,(null (cdr pipeline)))
+ `(prog1
+ (eshell-with-copied-handles
+ (progn
+ ,(when (cdr pipeline)
+ `(let ((output-marker ,(point-marker)))
+ (eshell-set-output-handle ,eshell-output-handle
+ 'append output-marker)))
+ (let (;; XXX: `eshell-in-pipeline-p' has a different
+ ;; meaning for synchronous processes: it's non-nil
+ ;; only when piping *to* a process.
+ (eshell-in-pipeline-p ,(and (cdr pipeline) t)))
+ ,(car pipeline)))
+ ;; Steal handles if this is the last item in the pipeline.
+ ,(null (cdr pipeline)))
,(when (cdr pipeline)
`(eshell-do-pipelines-synchronously (quote ,(cdr pipeline)))))))
(defmacro eshell-execute-pipeline (pipeline)
"Execute the commands in PIPELINE, connecting each to one another."
- `(let ((headproc (make-symbol "headproc"))
- (tailproc (make-symbol "tailproc")))
- (set headproc nil)
- (set tailproc nil)
- (progn
- ,(if eshell-supports-asynchronous-processes
- `(eshell-do-pipelines ,pipeline)
- `(eshell-do-pipelines-synchronously ,pipeline))
- (eshell-process-identity (cons (symbol-value headproc)
- (symbol-value tailproc))))))
+ `(eshell-process-identity
+ ,(if eshell-supports-asynchronous-processes
+ `(remove nil (eshell-do-pipelines ,pipeline))
+ `(eshell-do-pipelines-synchronously ,pipeline))))
(defmacro eshell-as-subcommand (command)
"Execute COMMAND as a subcommand.
(setq retval
(eshell-do-eval
eshell-current-command))))))
- (if (eshell-process-pair-p procs)
+ (if (eshell-process-list-p procs)
(ignore (setq eshell-last-async-procs procs))
(cadr retval)))))
(error
(eshell-do-eval form synchronous-p))
(if-let (((memq (car form) eshell-deferrable-commands))
((not eshell-current-subjob-p))
- (procs (eshell-make-process-pair result)))
+ (procs (eshell-make-process-list result)))
(if synchronous-p
- (eshell/wait (cdr procs))
- (eshell-manipulate form "inserting ignore form"
+ (apply #'eshell/wait procs)
+ (eshell-manipulate form "inserting ignore form"
(setcar form 'ignore)
(setcdr form nil))
(throw 'eshell-defer procs))