Add some initial generic functions to support Eshell tasks

* lisp/eshell/esh-util.el (eshell-task-p, eshell-task-status)
(eshell-task-active-p): New generic functions.
(eshell-process-list-p): Obsolete in favor of...
(eshell-task-list-p): ... this.  Update callers.
(eshell-make-process-list): Obsolete in favor of...
(eshell-make-task-list): ... this.  Update callers.

* lisp/eshell/esh-proc.el (eshell-task-p, eshell-task-status)
(eshell-task-active-p): New functions.
This commit is contained in:
Jim Porter 2025-05-26 20:07:36 -07:00
parent c58dd07fc1
commit be067246af
4 changed files with 40 additions and 16 deletions

View file

@ -1083,7 +1083,7 @@ STATUS is its status."
;; element is a list of the form (BACKGROUND FORM PROCESSES) (see
;; `eshell-add-command').
(dolist (command (eshell-commands-for-process proc))
(unless (seq-some #'eshell-process-active-p (nth 2 command))
(unless (seq-some #'eshell-task-active-p (nth 2 command))
(setf (nth 2 command) nil) ; Clear processes from command.
(if (and ;; Check STATUS to determine whether we want to resume or
;; abort the command.
@ -1365,13 +1365,13 @@ have been replaced by constants."
(setcdr form (cdr new-form)))
(eshell-do-eval form synchronous-p))
(if-let* (((memq (car form) eshell-deferrable-commands))
(procs (eshell-make-process-list result)))
(procs (eshell-make-task-list result)))
(if synchronous-p
(funcall #'eshell-wait-for-processes procs)
(eshell-manipulate form "inserting ignore form"
(setcar form 'ignore)
(setcdr form nil))
(when (seq-some #'eshell-process-active-p procs)
(when (seq-some #'eshell-task-active-p procs)
(throw 'eshell-defer procs)))
(list 'quote result))))))))))))

View file

@ -618,7 +618,7 @@ newline."
(let* ((proc-running-p (eshell-head-process))
(send-to-process-p (and proc-running-p (not queue-p))))
(unless (and send-to-process-p
(not (eq (process-status
(not (eq (eshell-task-status
(eshell-head-process))
'run)))
(if (or send-to-process-p

View file

@ -176,15 +176,20 @@ PROC and STATUS to functions on the latter."
(define-obsolete-function-alias 'eshell-reset-after-proc
'eshell--reset-after-signal "30.1")
(defun eshell-process-active-p (process)
"Return non-nil if PROCESS is active.
(cl-defmethod eshell-task-p ((_proc process)) t)
(cl-defmethod eshell-task-status ((proc process))
"Return the status of PROC, as with `process-status'."
(process-status proc))
(cl-defmethod eshell-task-active-p ((proc process))
"Return non-nil if PROC is active.
This is like `process-live-p', but additionally checks whether
`eshell-sentinel' has finished all of its work yet."
(or (process-live-p process)
(or (process-live-p proc)
;; If we have handles, this is an Eshell-managed
;; process. Wait until we're 100% done and have
;; cleared out the handles (see `eshell-sentinel').
(process-get process :eshell-handles)))
(process-get proc :eshell-handles)))
(defun eshell-wait-for-processes (&optional procs timeout)
"Wait until PROCS have completed execution.
@ -193,8 +198,8 @@ if all the processes finished executing before the timeout expired."
(let ((expiration (when timeout (time-add (current-time) timeout))))
(catch 'timeout
(dolist (proc procs)
(while (if (processp proc)
(eshell-process-active-p proc)
(while (if (eshell-task-p proc)
(eshell-task-active-p proc)
(process-attributes proc))
(when (input-pending-p)
(discard-input))
@ -222,7 +227,7 @@ Wait until PROCESS(es) have completed execution.")
(when (stringp timeout)
(setq timeout (string-to-number timeout)))
(dolist (arg args)
(unless (or (processp arg) (natnump arg))
(unless (or (eshell-task-p arg) (natnump arg))
(error "wait: invalid argument type: %s" (type-of arg))))
(unless (eshell-wait-for-processes args timeout)
(error "wait: timed out after %s seconds" timeout))))

View file

@ -869,18 +869,37 @@ gid format. Valid values are `string' and `integer', defaulting to
"If the `processp' function does not exist, PROC is not a process."
(and (fboundp 'processp) (processp proc)))
(defun eshell-process-list-p (procs)
(cl-defgeneric eshell-task-p (_object)
"Return non-nil if OBJECT is a task.
A \"task\" is a process or process-like object."
nil)
(cl-defgeneric eshell-task-status (task)
"Return the status for TASK, similar to `process-status' (which see).")
(cl-defgeneric eshell-task-active-p (task)
"Return non-nil if TASK is still active in Eshell.
An active task is any task that still has work left to do before being
cleaned up.")
(defun eshell-task-list-p (procs)
"Return non-nil if PROCS is a list of process objects."
(and (listp procs)
(seq-every-p #'eshell-processp procs)))
(seq-every-p #'eshell-task-p procs)))
(defun eshell-make-process-list (procs)
(define-obsolete-function-alias 'eshell-process-list-p
'eshell-task-list-p "31.1")
(defun eshell-make-task-list (procs)
"Make a list of process objects from PROCS if possible.
PROCS can be a single process or a list thereof. If PROCS is
anything else, return nil instead."
(pcase procs
((pred eshell-processp) (list procs))
((pred eshell-process-list-p) procs)))
((pred eshell-task-p) (list procs))
((pred eshell-task-list-p) procs)))
(define-obsolete-function-alias 'eshell-make-process-list
'eshell-make-task-list "31.1")
;; (defun eshell-copy-file
;; (file newname &optional ok-if-already-exists keep-date)