(dolist (elem haystack)
(cond
((eq (car-safe elem) 'eshell-as-subcommand)
- (iter-yield (cdr elem)))
+ (iter-yield (cadr elem)))
((listp elem)
(iter-yield-from (eshell--find-subcommands elem))))))
-(defun eshell--invoke-command-directly (command)
+(defun eshell--invoke-command-directly-p (command)
"Determine whether the given COMMAND can be invoked directly.
COMMAND should be a non-top-level Eshell command in parsed form.
A command can be invoked directly if all of the following are true:
* The command is of the form
- \"(eshell-trap-errors (eshell-named-command NAME ARGS))\",
- where ARGS is optional.
+ (eshell-with-copied-handles
+ (eshell-trap-errors (eshell-named-command NAME [ARGS])) _).
* NAME is a string referring to an alias function and isn't a
complex command (see `eshell-complex-commands').
* Any subcommands in ARGS can also be invoked directly."
- (when (and (eq (car command) 'eshell-trap-errors)
- (eq (car (cadr command)) 'eshell-named-command))
- (let ((name (cadr (cadr command)))
- (args (cdr-safe (nth 2 (cadr command)))))
- (and name (stringp name)
- (not (member name eshell-complex-commands))
- (catch 'simple
- (dolist (pred eshell-complex-commands t)
- (when (and (functionp pred)
- (funcall pred name))
- (throw 'simple nil))))
- (eshell-find-alias-function name)
- (catch 'indirect-subcommand
- (iter-do (subcommand (eshell--find-subcommands args))
- (unless (eshell--invoke-command-directly subcommand)
- (throw 'indirect-subcommand nil)))
- t)))))
-
-(defun eshell-invoke-directly (command)
+ (pcase command
+ (`(eshell-with-copied-handles
+ (eshell-trap-errors (eshell-named-command ,name . ,args))
+ ,_)
+ (and name (stringp name)
+ (not (member name eshell-complex-commands))
+ (catch 'simple
+ (dolist (pred eshell-complex-commands t)
+ (when (and (functionp pred)
+ (funcall pred name))
+ (throw 'simple nil))))
+ (eshell-find-alias-function name)
+ (catch 'indirect-subcommand
+ (iter-do (subcommand (eshell--find-subcommands (car args)))
+ (unless (eshell--invoke-command-directly-p subcommand)
+ (throw 'indirect-subcommand nil)))
+ t)))))
+
+(defun eshell-invoke-directly-p (command)
"Determine whether the given COMMAND can be invoked directly.
COMMAND should be a top-level Eshell command in parsed form, as
produced by `eshell-parse-command'."
- (let ((base (cadr (nth 2 (nth 2 (cadr command))))))
- (eshell--invoke-command-directly base)))
+ (pcase command
+ (`(eshell-commands (progn ,_ (unwind-protect (progn ,base) . ,_)))
+ (eshell--invoke-command-directly-p base))))
+
+(define-obsolete-function-alias 'eshell-invoke-directly
+ 'eshell-invoke-directly-p "30.1")
(defun eshell-eval-argument (argument)
"Evaluate a single Eshell ARGUMENT and return the result."
newline."
(interactive "P")
;; Note that the input string does not include its terminal newline.
- (let ((proc-running-p (and (eshell-head-process)
- (not queue-p)))
- (inhibit-modification-hooks t))
- (unless (and proc-running-p
+ (let* ((proc-running-p (eshell-head-process))
+ (send-to-process-p (and proc-running-p (not queue-p)))
+ (inhibit-modification-hooks t))
+ (unless (and send-to-process-p
(not (eq (process-status
(eshell-head-process))
'run)))
- (if (or proc-running-p
+ (if (or send-to-process-p
(>= (point) eshell-last-output-end))
(goto-char (point-max))
(let ((copy (eshell-get-old-input use-region)))
(insert-and-inherit copy)))
(unless (or no-newline
(and eshell-send-direct-to-subprocesses
- proc-running-p))
+ send-to-process-p))
(insert-before-markers-and-inherit ?\n))
;; Delete and reinsert input. This seems like a no-op, except
;; for the resulting entries in the undo list: undoing this
(inhibit-read-only t))
(delete-region eshell-last-output-end (point))
(insert text))
- (if proc-running-p
+ (if send-to-process-p
(progn
(eshell-update-markers eshell-last-output-end)
(if (or eshell-send-direct-to-subprocesses
(run-hooks 'eshell-input-filter-functions)
(and (catch 'eshell-terminal
(ignore
- (if (eshell-invoke-directly cmd)
+ (if (and (not proc-running-p)
+ (eshell-invoke-directly-p cmd))
(eval cmd)
(eshell-eval-command cmd input))))
(eshell-life-is-too-much)))))
(eshell-command-result-equal "unless {[ foo = bar ]} {echo no} {echo yes}"
"no"))
+\f
+;; Direct invocation
+
+(defmacro esh-cmd-test--deftest-invoke-directly (name command expected)
+ "FIXME"
+ (declare (indent 2))
+ `(ert-deftest ,(intern (concat "esh-cmd-test/invoke-directly/"
+ (symbol-name name))) ()
+ (with-temp-eshell
+ (should (equal (eshell-invoke-directly
+ (eshell-parse-command ,command nil t))
+ ,expected)))))
+
+(esh-cmd-test--deftest-invoke-directly no-args "echo" t)
+(esh-cmd-test--deftest-invoke-directly with-args "echo hi" t)
+(esh-cmd-test--deftest-invoke-directly multiple-cmds "echo hi; echo bye" nil)
+(esh-cmd-test--deftest-invoke-directly subcmd "echo ${echo hi}" t)
+(esh-cmd-test--deftest-invoke-directly complex "ls ." nil)
+(esh-cmd-test--deftest-invoke-directly complex-subcmd "echo {ls .}" nil)
+
\f
;; Error handling