From: Jim Porter Date: Mon, 23 May 2022 00:27:48 +0000 (-0700) Subject: Keep subcommands in pipelines from clobbering the head/tail processes X-Git-Tag: emacs-29.0.90~1910^2~461 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=a49ecdd0ff2b2526fcc519bb23ce1f5113c8fb1d;p=emacs.git Keep subcommands in pipelines from clobbering the head/tail processes * lisp/eshell/esh-cmd.el (eshell-execute-pipeline): Use 'make-symbol' for headproc and tailproc. (eshell-do-pipelines, eshell-do-pipelines-synchronously): Adapt to the above. * test/lisp/eshell/eshell-tests.el (eshell-test/pipe-subcommand) (eshell-test/pipe-subcommand-with-pipe): New test. * doc/misc/eshell.texi (Bugs and ideas): Remove item about piping to process from loop; this commit fixes it (bug#55590). --- diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index d35a642b62d..85e5a4933fd 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -1758,14 +1758,6 @@ alias arg=blah function arg () @{ blah $* @} @end example -@item @samp{for i in 1 2 3 @{ grep -q a b && *echo has it @} | wc -l} outputs result after prompt - -In fact, piping to a process from a looping construct doesn't work in -general. If I change the call to @code{eshell-copy-handles} in -@code{eshell-rewrite-for-command} to use @code{eshell-protect}, it seems -to work, but the output occurs after the prompt is displayed. The whole -structured command thing is too complicated at present. - @item Pcomplete sometimes gets stuck You press @key{TAB}, but no completions appear, even though the diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 42616e7037d..73c250632ce 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -827,8 +827,8 @@ This macro calls itself recursively, with NOTFIRST non-nil." ((cdr pipeline) t) (t (quote 'last))))) (let ((proc ,(car pipeline))) - (setq headproc (or proc headproc)) - (setq tailproc (or tailproc proc)) + (set headproc (or proc (symbol-value headproc))) + (set tailproc (or (symbol-value tailproc) proc)) proc)))))) (defmacro eshell-do-pipelines-synchronously (pipeline) @@ -861,7 +861,7 @@ This is used on systems where async subprocesses are not supported." (let ((result ,(car pipeline))) ;; tailproc gets the result of the last successful process in ;; the pipeline. - (setq tailproc (or result tailproc)) + (set tailproc (or result (symbol-value tailproc))) ,(if (cdr pipeline) `(eshell-do-pipelines-synchronously (quote ,(cdr pipeline)))) result)))) @@ -870,7 +870,11 @@ This is used on systems where async subprocesses are not supported." (defmacro eshell-execute-pipeline (pipeline) "Execute the commands in PIPELINE, connecting each to one another." - `(let ((eshell-in-pipeline-p t) headproc tailproc) + `(let ((eshell-in-pipeline-p t) + (headproc (make-symbol "headproc")) + (tailproc (make-symbol "tailproc"))) + (set headproc nil) + (set tailproc nil) (progn ,(if (fboundp 'make-process) `(eshell-do-pipelines ,pipeline) @@ -880,7 +884,8 @@ This is used on systems where async subprocesses are not supported." (car (aref eshell-current-handles ,eshell-error-handle)) nil))) (eshell-do-pipelines-synchronously ,pipeline))) - (eshell-process-identity (cons headproc tailproc))))) + (eshell-process-identity (cons (symbol-value headproc) + (symbol-value tailproc)))))) (defmacro eshell-as-subcommand (command) "Execute COMMAND using a temp buffer. diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el index 7cdeb017e44..c0affed80aa 100644 --- a/test/lisp/eshell/eshell-tests.el +++ b/test/lisp/eshell/eshell-tests.el @@ -114,6 +114,22 @@ e.g. \"{(+ 1 2)} 3\" => 3" (eshell-wait-for-subprocess) (eshell-match-result "OLLEH\n"))) +(ert-deftest eshell-test/pipe-subcommand () + "Check that piping with an asynchronous subcommand works" + (skip-unless (and (executable-find "echo") + (executable-find "cat"))) + (with-temp-eshell + (eshell-command-result-p "echo ${*echo hi} | *cat" + "hi"))) + +(ert-deftest eshell-test/pipe-subcommand-with-pipe () + "Check that piping with an asynchronous subcommand with its own pipe works" + (skip-unless (and (executable-find "echo") + (executable-find "cat"))) + (with-temp-eshell + (eshell-command-result-p "echo ${*echo hi | *cat} | *cat" + "hi"))) + (ert-deftest eshell-test/redirect-buffer () "Check that piping to a buffer works" (with-temp-buffer