1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Improve handling of Eshell "for" loops

This fixes some errors with more-complex string forms, and also allows
iterating over sequences other than just lists.

* lisp/eshell/esh-cmd.el (eshell-for-iterate): New function...
(eshell-rewrite-for-command): ... use it.

* test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop): Test
multiple values.
(esh-cmd-test/for-loop-string, esh-cmd-test/for-loop-vector): New tests.
(esh-cmd-test/for-loop-mixed-args): Rename.

* test/lisp/eshell/esh-proc-tests.el
(esh-proc-test/sentinel/change-buffer): Make sure all the processes get
cleaned up.
This commit is contained in:
Jim Porter 2024-11-03 11:22:27 -08:00
parent b3c82f939c
commit 08d5994b43
3 changed files with 49 additions and 35 deletions

View file

@ -526,6 +526,20 @@ the second is ignored."
(defvar eshell--local-vars nil
"List of locally bound vars that should take precedence over env-vars.")
(iter-defun eshell-for-iterate (&rest args)
"Iterate over the elements of each sequence in ARGS.
If ARGS is not a sequence, treat it as a list of one element."
(dolist (arg args)
(cond
((stringp arg)
(iter-yield arg))
((listp arg)
(dolist (i arg) (iter-yield i)))
((arrayp arg)
(dotimes (i (length arg)) (iter-yield (aref arg i))))
(t
(iter-yield arg)))))
(defun eshell-rewrite-for-command (terms)
"Rewrite a `for' command into its equivalent Eshell command form.
Because the implementation of `for' relies upon conditional evaluation
@ -533,23 +547,14 @@ of its argument (i.e., use of a Lisp special form), it must be
implemented via rewriting, rather than as a function."
(if (and (equal (car terms) "for")
(equal (nth 2 terms) "in"))
(let ((for-items (make-symbol "for-items"))
(let ((iter-symbol (intern (nth 1 terms)))
(body (car (last terms))))
(setcdr (last terms 2) nil)
`(let ((,for-items
(append
,@(mapcar
(lambda (elem)
(if (listp elem)
(eshell-term-as-value elem)
`(list ,elem)))
(nthcdr 3 terms)))))
(while ,for-items
(let ((,(intern (cadr terms)) (car ,for-items))
(eshell--local-vars (cons ',(intern (cadr terms))
eshell--local-vars)))
,body)
(setq ,for-items (cdr ,for-items)))))))
`(let ((eshell--local-vars (cons ',iter-symbol eshell--local-vars)))
(iter-do (,iter-symbol (eshell-for-iterate
,@(mapcar #'eshell-term-as-value
(nthcdr 3 terms))))
,body)))))
(defun eshell-structure-basic-command (func names keyword test &rest body)
"With TERMS, KEYWORD, and two NAMES, structure a basic command.