Simplify parsing subcommands slightly

This mainly reduces some overly-deep indentation, but also fixes some
minor issues with the "$<subcmd>" form: it unnecessarily added " >
TEMP" (we already set this later via 'eshell-create-handles'), and it
didn't properly unescape inner double quotes.

* lisp/eshell/esh-cmd.el (eshell-parse-subcommand-argument): Simplify.

* lisp/eshell/esh-var.el (eshell-parse-variable-ref): Simplify and
fix edge cases in "$<subcmd>".

* test/lisp/eshell/esh-var-tests.el
(esh-var-test/quoted-interp-temp-cmd): Adjust test to check behavior
of inner double quotes.
This commit is contained in:
Jim Porter 2023-03-20 17:25:24 -07:00
parent 5b005f26a8
commit bb088885df
3 changed files with 56 additions and 55 deletions

View file

@ -675,13 +675,13 @@ This means an exit code of 0."
(or (= (point-max) (1+ (point)))
(not (eq (char-after (1+ (point))) ?\}))))
(let ((end (eshell-find-delimiter ?\{ ?\})))
(if (not end)
(throw 'eshell-incomplete "{")
(when (eshell-arg-delimiter (1+ end))
(prog1
`(eshell-as-subcommand
,(eshell-parse-command (cons (1+ (point)) end)))
(goto-char (1+ end))))))))
(unless end
(throw 'eshell-incomplete "{"))
(when (eshell-arg-delimiter (1+ end))
(prog1
`(eshell-as-subcommand
,(eshell-parse-command (cons (1+ (point)) end)))
(goto-char (1+ end)))))))
(defun eshell-parse-lisp-argument ()
"Parse a Lisp expression which is specified as an argument."

View file

@ -507,55 +507,56 @@ Possible variable references are:
(cond
((eq (char-after) ?{)
(let ((end (eshell-find-delimiter ?\{ ?\})))
(if (not end)
(throw 'eshell-incomplete "${")
(forward-char)
(prog1
`(eshell-apply-indices
(eshell-convert
(eshell-command-to-value
(eshell-as-subcommand
,(let ((subcmd (or (eshell-unescape-inner-double-quote end)
(cons (point) end)))
(eshell-current-quoted nil))
(eshell-parse-command subcmd))))
;; If this is a simple double-quoted form like
;; "${COMMAND}" (i.e. no indices after the subcommand
;; and no `#' modifier before), ensure we convert to a
;; single string. This avoids unnecessary work
;; (e.g. splitting the output by lines) when it would
;; just be joined back together afterwards.
,(when (and (not modifier-p) eshell-current-quoted)
'(not indices)))
indices ,eshell-current-quoted)
(goto-char (1+ end))))))
(unless end
(throw 'eshell-incomplete "${"))
(forward-char)
(prog1
`(eshell-apply-indices
(eshell-convert
(eshell-command-to-value
(eshell-as-subcommand
,(let ((subcmd (or (eshell-unescape-inner-double-quote end)
(cons (point) end)))
(eshell-current-quoted nil))
(eshell-parse-command subcmd))))
;; If this is a simple double-quoted form like
;; "${COMMAND}" (i.e. no indices after the subcommand and
;; no `#' modifier before), ensure we convert to a single
;; string. This avoids unnecessary work (e.g. splitting
;; the output by lines) when it would just be joined back
;; together afterwards.
,(when (and (not modifier-p) eshell-current-quoted)
'(not indices)))
indices ,eshell-current-quoted)
(goto-char (1+ end)))))
((eq (char-after) ?\<)
(let ((end (eshell-find-delimiter ?\< ?\>)))
(if (not end)
(throw 'eshell-incomplete "$<")
(let* ((temp (make-temp-file temporary-file-directory))
(cmd (concat (buffer-substring (1+ (point)) end)
" > " temp)))
(prog1
`(let ((eshell-current-handles
(eshell-create-handles ,temp 'overwrite)))
(progn
(eshell-as-subcommand
,(let ((eshell-current-quoted nil))
(eshell-parse-command cmd)))
(ignore
(nconc eshell-this-command-hook
;; Quote this lambda; it will be evaluated
;; by `eshell-do-eval', which requires very
;; particular forms in order to work
;; properly. See bug#54190.
(list (function
(lambda ()
(delete-file ,temp)
(when-let ((buffer (get-file-buffer ,temp)))
(kill-buffer buffer)))))))
(eshell-apply-indices ,temp indices ,eshell-current-quoted)))
(goto-char (1+ end)))))))
(unless end
(throw 'eshell-incomplete "$<"))
(forward-char)
(let* ((temp (make-temp-file temporary-file-directory))
(subcmd (or (eshell-unescape-inner-double-quote end)
(cons (point) end))))
(prog1
`(let ((eshell-current-handles
(eshell-create-handles ,temp 'overwrite)))
(progn
(eshell-as-subcommand
,(let ((eshell-current-quoted nil))
(eshell-parse-command subcmd)))
(ignore
(nconc eshell-this-command-hook
;; Quote this lambda; it will be evaluated by
;; `eshell-do-eval', which requires very
;; particular forms in order to work
;; properly. See bug#54190.
(list (function
(lambda ()
(delete-file ,temp)
(when-let ((buffer (get-file-buffer ,temp)))
(kill-buffer buffer)))))))
(eshell-apply-indices ,temp indices ,eshell-current-quoted)))
(goto-char (1+ end))))))
((eq (char-after) ?\()
(condition-case nil
`(eshell-apply-indices

View file

@ -454,7 +454,7 @@ nil, use FUNCTION instead."
(let ((temporary-file-directory
(file-name-as-directory (make-temp-file "esh-vars-tests" t))))
(unwind-protect
(eshell-command-result-equal "cat \"$<echo hi>\"" "hi")
(eshell-command-result-equal "cat \"$<echo \\\"hi\\\">\"" "hi")
(delete-directory temporary-file-directory t))))
(ert-deftest esh-var-test/quoted-interp-concat-cmd ()