1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-23 07:19:15 +00:00

Allow specifying stdout/stderr separately in some Eshell commands

* lisp/eshell/eshell.el (eshell-command): Add ERROR-TARGET.
* lisp/eshell/em-script.el (eshell-execute-file): Make interactive, and
add ERROR-TARGET.

* doc/misc/eshell.texi (One-Off Commands, Scripts): Update
documentation.

* etc/NEWS: Announce this change.
This commit is contained in:
Jim Porter 2024-06-14 20:45:44 -07:00
parent 965be7bc46
commit 99b360bb5a
4 changed files with 73 additions and 26 deletions

View File

@ -235,11 +235,19 @@ Start a new Eshell session, no matter if another one already exists.
You can also run individual Eshell commands from anywhere within Emacs:
@deffn Command eshell-command command &optional to-current-buffer
@deffn Command eshell-command command &optional output-target error-target
Execute the Eshell command string @var{command} and show the output in a
buffer. If @var{to-current-buffer} is non-@code{nil} (interactively,
with the prefix argument), then insert output into the current buffer at
point.
buffer. If @var{output-target} is @code{t} (interactively, with the
prefix argument), write the command's standard output to the current
buffer at point. If @code{nil}, write the output to a new output
buffer. For any other value, output to that Eshell target
(@pxref{Redirection}).
@var{error-target} is similar to @var{output-target}, except that it
controls where to write standard error, and a @code{nil} value means to
write standard error to the same place as standard output. (To suppress
standard error, you can write to the Eshell virtual target
@file{/dev/null}.)
When the command ends with @kbd{&}, Eshell will evaluate the command
asynchronously. Otherwise, it will wait until the command has finished
@ -275,13 +283,20 @@ the special variables @code{$0}, @code{$1}, @dots{}, @code{$9}, and
You can also invoke Eshell scripts from outside of Eshell:
@defun eshell-execute-file file &optional args destination
@deffn Command eshell-execute-file file &optional args output-target error-target
Execute the Eshell commands contained in @var{file}, passing an optional
list of @var{args} to the script. If @var{destination} is @code{t},
write the command output to the current buffer. If @code{nil}, don't
write the output anywhere. For any other value, output to the
corresponding Eshell target (@pxref{Redirection}).
@end defun
list of @var{args} to the script. If @var{output-target} is @code{t}
(interactively, with the prefix argument), write the command output to
the current buffer. If @code{nil}, don't write the output anywhere.
For any other value, output to the corresponding Eshell target
(@pxref{Redirection}).
@var{error-target} is similar to @var{output-target}, except that it
controls where to write standard error, and a @code{nil} value means to
write standard error to the same place as standard output. (To suppress
standard error, you can write to the Eshell virtual target
@file{/dev/null\}.)
@end deffn
@cindex batch scripts
@defun eshell-batch-file

View File

@ -60,6 +60,18 @@ this will prompt for confirmation before creating a new buffer when
necessary. To restore the previous behavior, set this option to
'confirm-kill-process'.
+++
*** 'eshell-execute-file' is now an interactive command.
Interactively, this now prompts for a script file to execute. With the
prefix argument, it will also insert any output into the current buffer
at point.
+++
*** 'eshell-command' and 'eshell-execute-file' can now set where stderr goes.
These functions now take an optional ERROR-TARGET argument to control
where to send the standard error output. See the "(eshell) Entry
Points" node in the Eshell manual for more details.
+++
*** Eshell's built-in "wait" command now accepts a timeout.
By passing "-t" or "--timeout", you can specify a maximum time to wait

View File

@ -106,20 +106,29 @@ Comments begin with `#'."
(eshell--source-file file args subcommand-p)))
;;;###autoload
(defun eshell-execute-file (file &optional args destination)
(defun eshell-execute-file (file &optional args output-target error-target)
"Execute a series of Eshell commands in FILE, passing ARGS.
If DESTINATION is t, write the command output to the current buffer. If
nil, don't write the output anywhere. For any other value, output to
the corresponding Eshell target (see `eshell-get-target').
If OUTPUT-TARGET is t (interactively, with the prefix argument), write
the command's standard output to the current buffer at point. If nil,
don't write the output anywhere. For any other value, output to that
Eshell target (see `eshell-get-target').
ERROR-TARGET is similar to OUTPUT-TARGET, except that it controls where
to write standard error, and a nil value means to write standard error
to the same place as standard output. (To suppress standard error, you
can write to the Eshell virtual target \"/dev/null\".)
Comments begin with `#'."
(interactive (list (read-file-name "Execute file: " nil nil t)
nil (not (not current-prefix-arg))))
(let ((eshell-non-interactive-p t)
(stdout (if (eq destination t) (current-buffer) destination)))
(stdout (if (eq output-target t) (current-buffer) output-target))
(stderr (if (eq error-target t) (current-buffer) error-target)))
(with-temp-buffer
(eshell-mode)
(eshell-do-eval
`(let ((eshell-current-handles
(eshell-create-handles ,stdout 'insert))
(eshell-create-handles ,stdout 'insert ,stderr 'insert))
(eshell-current-subjob-p))
,(eshell--source-file file args))
t))))

View File

@ -327,31 +327,42 @@ information on Eshell, see Info node `(eshell)Top'."
(defvar eshell-command-buffer-name-sync "*Eshell Command Output*")
;;;###autoload
(defun eshell-command (command &optional to-current-buffer)
(defun eshell-command (command &optional output-target error-target)
"Execute the Eshell command string COMMAND.
If TO-CURRENT-BUFFER is non-nil (interactively, with the prefix
argument), then insert output into the current buffer at point.
If OUTPUT-TARGET is t (interactively, with the prefix argument), write
the command's standard output to the current buffer at point. If nil,
write the output to a new output buffer. For any other value, output to
that Eshell target (see `eshell-get-target').
When \"&\" is added at end of command, the command is async and its output
appears in a specific buffer. You can customize
ERROR-TARGET is similar to OUTPUT-TARGET, except that it controls where
to write standard error, and a nil value means to write standard error
to the same place as standard output. (To suppress standard error, you
can write to the Eshell virtual target \"/dev/null\".)
When \"&\" is added at end of command, the command is async and its
output appears in a specific buffer. You can customize
`eshell-command-async-buffer' to specify what to do when this output
buffer is already taken by another running shell command."
(interactive (list (eshell-read-command)
current-prefix-arg))
(not (not current-prefix-arg))))
(save-excursion
(let ((stdout (if to-current-buffer (current-buffer) t))
(let ((stdout (cond ((eq output-target t) (current-buffer))
((not output-target) t)
(t output-target)))
(stderr (if (eq error-target t) (current-buffer) error-target))
(buf (set-buffer (generate-new-buffer " *eshell cmd*")))
(eshell-non-interactive-p t))
(eshell-mode)
(let* ((proc (eshell-eval-command
`(let ((eshell-current-handles
(eshell-create-handles ,stdout 'insert))
(eshell-create-handles ,stdout 'insert
,stderr 'insert))
(eshell-current-subjob-p))
,(eshell-parse-command command))
command))
(async (eq (car-safe proc) :eshell-background))
(bufname (cond
(to-current-buffer nil)
((not (eq stdout t)) nil)
(async eshell-command-buffer-name-async)
(t eshell-command-buffer-name-sync)))
unique)
@ -394,7 +405,7 @@ buffer is already taken by another running shell command."
(while (and (bolp) (not (bobp)))
(delete-char -1)))
(cl-assert (and buf (buffer-live-p buf)))
(unless to-current-buffer
(unless bufname
(let ((len (if async 2
(count-lines (point-min) (point-max)))))
(cond