summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorJim Porter <jporterbugs@gmail.com>2023-01-28 17:04:11 -0800
committerJim Porter <jporterbugs@gmail.com>2023-03-16 22:17:02 -0700
commit1565dbcae35c1e42b22066fde226e3b063614a9e (patch)
tree70207fcd35d357263091c916599f1b9f3a92a692 /lisp
parente01660ca50ad360db78e5a0206ed824465c2aada (diff)
downloademacs-1565dbcae35c1e42b22066fde226e3b063614a9e.tar.gz
Simplify usage of 'while' forms in Eshell's iterative evaluation
Now, 'eshell-do-eval' rewrites 'while' forms to let-bind variables for the command and test bodies. This means that external code, such as command rewriting hooks, no longer has to worry about this, making it easier to pass "normal" Lisp forms to 'eshell-do-eval' (bug#61954). * lisp/eshell/esh-cmd.el (eshell-command-body, eshell-test-body): No longer used outside of 'eshell-do-eval', so rename to... (eshell--command-body, eshell--test-body): ... these. (Command evaluation macros): Remove obsolete description about 'if' and 'while' forms. (eshell-rewrite-for-command, eshell-structure-basic-command): Remove 'eshell-command-body' and 'eshell-test-body'. (eshell-do-eval): Reimplement handling of 'while' forms.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/eshell/esh-cmd.el59
1 files changed, 31 insertions, 28 deletions
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 5dbbd770582..93f2616020c 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -494,8 +494,8 @@ hooks should be run before and after the command."
(t
(list sym (car terms))))))
-(defvar eshell-command-body)
-(defvar eshell-test-body)
+(defvar eshell--command-body)
+(defvar eshell--test-body)
(defsubst eshell-invokify-arg (arg &optional share-output silent)
"Change ARG so it can be invoked from a structured command.
@@ -540,9 +540,7 @@ implemented via rewriting, rather than as a function."
(if (listp elem)
elem
`(list ,elem)))
- (nthcdr 3 terms))))
- (eshell-command-body '(nil))
- (eshell-test-body '(nil)))
+ (nthcdr 3 terms)))))
(while for-items
(let ((,(intern (cadr terms)) (car for-items))
(eshell--local-vars (cons ',(intern (cadr terms))
@@ -579,8 +577,7 @@ function."
;; finally, create the form that represents this structured
;; command
- `(let ((eshell-command-body '(nil))
- (eshell-test-body '(nil)))
+ `(progn
(,func ,test ,body ,else)
(eshell-close-handles)))
@@ -745,10 +742,6 @@ if none)."
;; `condition-case', `if', `let', `prog1', `progn', `quote', `setq',
;; `unwind-protect', and `while'.
;;
-;; @ When using `while', first let-bind `eshell-test-body' and
-;; `eshell-command-body' to '(nil). Eshell uses these variables to
-;; handle evaluating its subforms multiple times.
-;;
;; @ The two `special' variables are `eshell-current-handles' and
;; `eshell-current-subjob-p'. Bind them locally with a `let' if you
;; need to change them. Change them directly only if your intention
@@ -1128,24 +1121,34 @@ have been replaced by constants."
(let ((args (cdr form)))
(cond
((eq (car form) 'while)
+ ;; Wrap the `while' form with let-bindings for the command and
+ ;; test bodies. This helps us resume evaluation midway
+ ;; through the loop.
+ (let ((new-form (copy-tree `(let ((eshell--command-body nil)
+ (eshell--test-body nil))
+ (eshell--wrapped-while ,@args)))))
+ (eshell-manipulate "modifying while form"
+ (setcar form (car new-form))
+ (setcdr form (cdr new-form)))
+ (eshell-do-eval form synchronous-p)))
+ ((eq (car form) 'eshell--wrapped-while)
+ (when eshell--command-body
+ (cl-assert (not synchronous-p))
+ (eshell-do-eval eshell--command-body)
+ (setq eshell--command-body nil
+ eshell--test-body nil))
;; `copy-tree' is needed here so that the test argument
- ;; doesn't get modified and thus always yield the same result.
- (when (car eshell-command-body)
- (cl-assert (not synchronous-p))
- (eshell-do-eval (car eshell-command-body))
- (setcar eshell-command-body nil)
- (setcar eshell-test-body nil))
- (unless (car eshell-test-body)
- (setcar eshell-test-body (copy-tree (car args))))
- (while (cadr (eshell-do-eval (car eshell-test-body) synchronous-p))
- (setcar eshell-command-body
- (if (cddr args)
- `(progn ,@(copy-tree (cdr args)))
- (copy-tree (cadr args))))
- (eshell-do-eval (car eshell-command-body) synchronous-p)
- (setcar eshell-command-body nil)
- (setcar eshell-test-body (copy-tree (car args))))
- (setcar eshell-command-body nil))
+ ;; doesn't get modified and thus always yield the same result.
+ (unless eshell--test-body
+ (setq eshell--test-body (copy-tree (car args))))
+ (while (cadr (eshell-do-eval eshell--test-body synchronous-p))
+ (setq eshell--command-body
+ (if (cddr args)
+ `(progn ,@(copy-tree (cdr args)))
+ (copy-tree (cadr args))))
+ (eshell-do-eval eshell--command-body synchronous-p)
+ (setq eshell--command-body nil
+ eshell--test-body (copy-tree (car args)))))
((eq (car form) 'if)
(eshell-manipulate "evaluating if condition"
(setcar args (eshell-do-eval (car args) synchronous-p)))