diff options
author | Jim Porter <jporterbugs@gmail.com> | 2022-01-20 14:37:54 +0100 |
---|---|---|
committer | Lars Ingebrigtsen <larsi@gnus.org> | 2022-01-20 14:37:54 +0100 |
commit | 4450c8bdd93d1b2e7f276e26be2cc37372034c22 (patch) | |
tree | e45604026d24ea26a1bb7ec342cc6d72edbce505 /lisp/eshell/esh-cmd.el | |
parent | 55c1670bc52c924d80c72e55bf3864023749be29 (diff) | |
download | emacs-4450c8bdd93d1b2e7f276e26be2cc37372034c22.tar.gz emacs-4450c8bdd93d1b2e7f276e26be2cc37372034c22.tar.bz2 emacs-4450c8bdd93d1b2e7f276e26be2cc37372034c22.zip |
Consider subcommands when deciding to invoke Eshell command directly
When an Eshell command contains an asynchronous subcommand (such as
calling an external process), it must be evaluated iteratively. See
bug#30725.
* lisp/eshell/esh-cmd.el (eshell-invoke-command): Move most of the
logic from here...
(eshell--invoke-command-directly): ... to here. Also add checks for
subcommands.
* test/lisp/eshell/eshell-tests.el (eshell-test--max-subprocess-time):
New variable.
(eshell-wait-for-subprocess): New function.
(eshell-command-result-p): Use 'eshell-wait-for-subprocess'.
(eshell-test/interp-cmd-external): New test (bug#30725).
Diffstat (limited to 'lisp/eshell/esh-cmd.el')
-rw-r--r-- | lisp/eshell/esh-cmd.el | 57 |
1 files changed, 43 insertions, 14 deletions
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index a2d7d9431a9..25e3a5a2054 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -903,21 +903,50 @@ at the moment are: "Completion for the `debug' command." (while (pcomplete-here '("errors" "commands")))) +(defun eshell--invoke-command-directly (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. + +* NAME is a string referring to an alias function and isn't a + complex command (see `eshell-complex-commands'). + +* Any argument in ARGS that calls a subcommand 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 + (dolist (arg args t) + (pcase arg + (`(eshell-escape-arg + (let ,_ + (eshell-convert + (eshell-command-to-value + (eshell-as-subcommand ,subcommand))))) + (unless (eshell--invoke-command-directly subcommand) + (throw 'indirect-subcommand nil)))))))))) + (defun eshell-invoke-directly (command) - (let ((base (cadr (nth 2 (nth 2 (cadr command))))) name) - (if (and (eq (car base) 'eshell-trap-errors) - (eq (car (cadr base)) 'eshell-named-command)) - (setq name (cadr (cadr base)))) - (and name (stringp name) - (not (member name eshell-complex-commands)) - (catch 'simple - (progn - (dolist (pred eshell-complex-commands) - (if (and (functionp pred) - (funcall pred name)) - (throw 'simple nil))) - t)) - (eshell-find-alias-function name)))) + "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))) (defun eshell-eval-command (command &optional input) "Evaluate the given COMMAND iteratively." |