diff options
| author | Jim Porter | 2022-05-22 17:27:48 -0700 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2022-05-24 14:58:00 +0200 |
| commit | a49ecdd0ff2b2526fcc519bb23ce1f5113c8fb1d (patch) | |
| tree | d8ac3f279ad977d2ae21f42d27a389b6b53ecddd | |
| parent | be17333acee2086d1c729197dfe64432f6ad6625 (diff) | |
| download | emacs-a49ecdd0ff2b2526fcc519bb23ce1f5113c8fb1d.tar.gz emacs-a49ecdd0ff2b2526fcc519bb23ce1f5113c8fb1d.zip | |
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).
| -rw-r--r-- | doc/misc/eshell.texi | 8 | ||||
| -rw-r--r-- | lisp/eshell/esh-cmd.el | 15 | ||||
| -rw-r--r-- | test/lisp/eshell/eshell-tests.el | 16 |
3 files changed, 26 insertions, 13 deletions
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 | |||
| 1758 | function arg () @{ blah $* @} | 1758 | function arg () @{ blah $* @} |
| 1759 | @end example | 1759 | @end example |
| 1760 | 1760 | ||
| 1761 | @item @samp{for i in 1 2 3 @{ grep -q a b && *echo has it @} | wc -l} outputs result after prompt | ||
| 1762 | |||
| 1763 | In fact, piping to a process from a looping construct doesn't work in | ||
| 1764 | general. If I change the call to @code{eshell-copy-handles} in | ||
| 1765 | @code{eshell-rewrite-for-command} to use @code{eshell-protect}, it seems | ||
| 1766 | to work, but the output occurs after the prompt is displayed. The whole | ||
| 1767 | structured command thing is too complicated at present. | ||
| 1768 | |||
| 1769 | @item Pcomplete sometimes gets stuck | 1761 | @item Pcomplete sometimes gets stuck |
| 1770 | 1762 | ||
| 1771 | You press @key{TAB}, but no completions appear, even though the | 1763 | 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." | |||
| 827 | ((cdr pipeline) t) | 827 | ((cdr pipeline) t) |
| 828 | (t (quote 'last))))) | 828 | (t (quote 'last))))) |
| 829 | (let ((proc ,(car pipeline))) | 829 | (let ((proc ,(car pipeline))) |
| 830 | (setq headproc (or proc headproc)) | 830 | (set headproc (or proc (symbol-value headproc))) |
| 831 | (setq tailproc (or tailproc proc)) | 831 | (set tailproc (or (symbol-value tailproc) proc)) |
| 832 | proc)))))) | 832 | proc)))))) |
| 833 | 833 | ||
| 834 | (defmacro eshell-do-pipelines-synchronously (pipeline) | 834 | (defmacro eshell-do-pipelines-synchronously (pipeline) |
| @@ -861,7 +861,7 @@ This is used on systems where async subprocesses are not supported." | |||
| 861 | (let ((result ,(car pipeline))) | 861 | (let ((result ,(car pipeline))) |
| 862 | ;; tailproc gets the result of the last successful process in | 862 | ;; tailproc gets the result of the last successful process in |
| 863 | ;; the pipeline. | 863 | ;; the pipeline. |
| 864 | (setq tailproc (or result tailproc)) | 864 | (set tailproc (or result (symbol-value tailproc))) |
| 865 | ,(if (cdr pipeline) | 865 | ,(if (cdr pipeline) |
| 866 | `(eshell-do-pipelines-synchronously (quote ,(cdr pipeline)))) | 866 | `(eshell-do-pipelines-synchronously (quote ,(cdr pipeline)))) |
| 867 | result)))) | 867 | result)))) |
| @@ -870,7 +870,11 @@ This is used on systems where async subprocesses are not supported." | |||
| 870 | 870 | ||
| 871 | (defmacro eshell-execute-pipeline (pipeline) | 871 | (defmacro eshell-execute-pipeline (pipeline) |
| 872 | "Execute the commands in PIPELINE, connecting each to one another." | 872 | "Execute the commands in PIPELINE, connecting each to one another." |
| 873 | `(let ((eshell-in-pipeline-p t) headproc tailproc) | 873 | `(let ((eshell-in-pipeline-p t) |
| 874 | (headproc (make-symbol "headproc")) | ||
| 875 | (tailproc (make-symbol "tailproc"))) | ||
| 876 | (set headproc nil) | ||
| 877 | (set tailproc nil) | ||
| 874 | (progn | 878 | (progn |
| 875 | ,(if (fboundp 'make-process) | 879 | ,(if (fboundp 'make-process) |
| 876 | `(eshell-do-pipelines ,pipeline) | 880 | `(eshell-do-pipelines ,pipeline) |
| @@ -880,7 +884,8 @@ This is used on systems where async subprocesses are not supported." | |||
| 880 | (car (aref eshell-current-handles | 884 | (car (aref eshell-current-handles |
| 881 | ,eshell-error-handle)) nil))) | 885 | ,eshell-error-handle)) nil))) |
| 882 | (eshell-do-pipelines-synchronously ,pipeline))) | 886 | (eshell-do-pipelines-synchronously ,pipeline))) |
| 883 | (eshell-process-identity (cons headproc tailproc))))) | 887 | (eshell-process-identity (cons (symbol-value headproc) |
| 888 | (symbol-value tailproc)))))) | ||
| 884 | 889 | ||
| 885 | (defmacro eshell-as-subcommand (command) | 890 | (defmacro eshell-as-subcommand (command) |
| 886 | "Execute COMMAND using a temp buffer. | 891 | "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" | |||
| 114 | (eshell-wait-for-subprocess) | 114 | (eshell-wait-for-subprocess) |
| 115 | (eshell-match-result "OLLEH\n"))) | 115 | (eshell-match-result "OLLEH\n"))) |
| 116 | 116 | ||
| 117 | (ert-deftest eshell-test/pipe-subcommand () | ||
| 118 | "Check that piping with an asynchronous subcommand works" | ||
| 119 | (skip-unless (and (executable-find "echo") | ||
| 120 | (executable-find "cat"))) | ||
| 121 | (with-temp-eshell | ||
| 122 | (eshell-command-result-p "echo ${*echo hi} | *cat" | ||
| 123 | "hi"))) | ||
| 124 | |||
| 125 | (ert-deftest eshell-test/pipe-subcommand-with-pipe () | ||
| 126 | "Check that piping with an asynchronous subcommand with its own pipe works" | ||
| 127 | (skip-unless (and (executable-find "echo") | ||
| 128 | (executable-find "cat"))) | ||
| 129 | (with-temp-eshell | ||
| 130 | (eshell-command-result-p "echo ${*echo hi | *cat} | *cat" | ||
| 131 | "hi"))) | ||
| 132 | |||
| 117 | (ert-deftest eshell-test/redirect-buffer () | 133 | (ert-deftest eshell-test/redirect-buffer () |
| 118 | "Check that piping to a buffer works" | 134 | "Check that piping to a buffer works" |
| 119 | (with-temp-buffer | 135 | (with-temp-buffer |