]> git.eshelyaron.com Git - emacs.git/commitdiff
Keep subcommands in pipelines from clobbering the head/tail processes
authorJim Porter <jporterbugs@gmail.com>
Mon, 23 May 2022 00:27:48 +0000 (17:27 -0700)
committerLars Ingebrigtsen <larsi@gnus.org>
Tue, 24 May 2022 12:58:00 +0000 (14:58 +0200)
* 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).

doc/misc/eshell.texi
lisp/eshell/esh-cmd.el
test/lisp/eshell/eshell-tests.el

index d35a642b62df52303ce693c49853408c030b99b4..85e5a4933fdcdbb3085190fc8f9fe355a8ed2488 100644 (file)
@@ -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
index 42616e7037d34abd544e43f2844e3d2ae4d085a2..73c250632ce4799fb8f1279cedecb2116b0c71cf 100644 (file)
@@ -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.
index 7cdeb017e445593b96cb5362fdb498d8985f8031..c0affed80aa7f3f2ea09ef8d9c3d9beb0e03c642 100644 (file)
@@ -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