Fix evaluation of asynchronous expansions in Eshell indices

Previously, this code passed the indices to a separate function, which
called 'eval' on them, but it should instead make an S-expr that
'eshell-do-eval' can evaluate (bug#60942).

* lisp/eshell/esh-var.el (eshell-eval-indices): Mark obsolete.
(eshell-prepare-indices): New function...
(eshell-parse-variable): ... use it.  Also, remove irrelevant comment.
(eshell-parse-variable-ref): Fix quoting in docstring.
(eshell-parse-indices): Fix typo in docstring.

* test/lisp/eshell/esh-var-tests.el
(esh-var-test/interp-var-indices-subcommand)
(esh-var-test/quoted-interp-var-indices-subcommand): New tests.
This commit is contained in:
Jim Porter 2023-01-18 19:15:38 -08:00
parent 207901457c
commit 54d5ea66c9
2 changed files with 34 additions and 5 deletions

View file

@ -467,9 +467,7 @@ process any indices that come after the variable reference."
indices (and (not (eobp))
(eq (char-after) ?\[)
(eshell-parse-indices))
;; This is an expression that will be evaluated by `eshell-do-eval',
;; which only support let-binding of dynamically-scoped vars
value `(let ((indices (eshell-eval-indices ',indices))) ,value))
value `(let ((indices ,(eshell-prepare-indices indices))) ,value))
(when get-len
(setq value `(length ,value)))
(when eshell-current-quoted
@ -496,7 +494,7 @@ Possible variable references are:
NAME an environment or Lisp variable value
\"LONG-NAME\" disambiguates the length of the name
`LONG-NAME' as above
\\='LONG-NAME\\=' as above
{COMMAND} result of command is variable's value
(LISP-FORM) result of Lisp form is variable's value
<COMMAND> write the output of command to a temporary file;
@ -591,7 +589,7 @@ Possible variable references are:
"Parse and return a list of index-lists.
For example, \"[0 1][2]\" becomes:
((\"0\" \"1\") (\"2\")."
((\"0\" \"1\") (\"2\"))."
(let (indices)
(while (eq (char-after) ?\[)
(let ((end (eshell-find-delimiter ?\[ ?\])))
@ -609,8 +607,14 @@ For example, \"[0 1][2]\" becomes:
(defun eshell-eval-indices (indices)
"Evaluate INDICES, a list of index-lists generated by `eshell-parse-indices'."
(declare (obsolete eshell-prepare-indices "30.1"))
(mapcar (lambda (i) (mapcar #'eval i)) indices))
(defun eshell-prepare-indices (indices)
"Prepare INDICES to be evaluated by Eshell.
INDICES is a list of index-lists generated by `eshell-parse-indices'."
`(list ,@(mapcar (lambda (idx-list) (cons 'list idx-list)) indices)))
(defun eshell-get-variable (name &optional indices quoted)
"Get the value for the variable NAME.
INDICES is a list of index-lists (see `eshell-parse-indices').

View file

@ -82,6 +82,17 @@
(eshell-command-result-equal "echo $eshell-test-value[0 2 4]"
'("zero" "two" "four"))))
(ert-deftest esh-var-test/interp-var-indices-subcommand ()
"Interpolate list variable with subcommand expansion for indices"
(skip-unless (executable-find "echo"))
(let ((eshell-test-value '("zero" "one" "two" "three" "four")))
(eshell-command-result-equal
"echo $eshell-test-value[${*echo 0}]"
"zero")
(eshell-command-result-equal
"echo $eshell-test-value[${*echo 0} ${*echo 2}]"
'("zero" "two"))))
(ert-deftest esh-var-test/interp-var-split-indices ()
"Interpolate string variable with indices"
(let ((eshell-test-value "zero one two three four"))
@ -271,6 +282,20 @@
(eshell-command-result-equal "echo \"$eshell-test-value[1 2 4]\""
"(\"one\" \"two\" \"four\")")))
(ert-deftest esh-var-test/quote-interp-var-indices-subcommand ()
"Interpolate list variable with subcommand expansion for indices
inside double-quotes"
(skip-unless (executable-find "echo"))
(let ((eshell-test-value '("zero" "one" "two" "three" "four")))
(eshell-command-result-equal
"echo \"$eshell-test-value[${*echo 0}]\""
"zero")
;; FIXME: These tests would use the 0th index like the other tests
;; here, but see above.
(eshell-command-result-equal
"echo \"$eshell-test-value[${*echo 1} ${*echo 2}]\""
"(\"one\" \"two\")")))
(ert-deftest esh-var-test/quoted-interp-var-split-indices ()
"Interpolate string variable with indices inside double-quotes"
(let ((eshell-test-value "zero one two three four"))