]> git.eshelyaron.com Git - emacs.git/commitdiff
Simplify usage of 'while' forms in Eshell's iterative evaluation
authorJim Porter <jporterbugs@gmail.com>
Sun, 29 Jan 2023 01:04:11 +0000 (17:04 -0800)
committerJim Porter <jporterbugs@gmail.com>
Fri, 17 Mar 2023 05:17:02 +0000 (22:17 -0700)
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.

lisp/eshell/esh-cmd.el

index 5dbbd770582f0ac42ae99db23fb24ad354aad68a..93f2616020c31cc6d846dbe3d4b73e97631b6a87 100644 (file)
@@ -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)))