diff options
author | Sean Whitton <spwhitton@spwhitton.name> | 2021-02-06 00:48:32 -0700 |
---|---|---|
committer | Sean Whitton <spwhitton@spwhitton.name> | 2021-12-24 14:08:06 -0700 |
commit | 98df5163018b9c99ad8e65f03422f908c6068c78 (patch) | |
tree | 5d43fd03c3df6fab042c926b146eed72eaed2fb8 /lisp/eshell/esh-mode.el | |
parent | d47446cbe7db5c7fb4eba71ab022cfae3de07799 (diff) | |
download | emacs-98df5163018b9c99ad8e65f03422f908c6068c78.tar.gz |
Add eshell-shell-command and eshell-expand-to-eshell-shell-commandseries/unexpanded-input-v2
* lisp/eshell/esh-mode.el (eshell-shell-command,
eshell-expand-to-eshell-shell-command): Define new functions.
Register eshell-expand-to-eshell-shell-command as a customization
option for eshell-expand-input-functions, and add it by default.
* etc/NEWS:
* doc/misc/eshell.texi: Document the new syntax.
Diffstat (limited to 'lisp/eshell/esh-mode.el')
-rw-r--r-- | lisp/eshell/esh-mode.el | 79 |
1 files changed, 78 insertions, 1 deletions
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index 87166ef3bf1..04680e4305c 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -63,6 +63,7 @@ (require 'esh-cmd) (require 'esh-arg) ;For eshell-parse-arguments (require 'cl-lib) +(require 'subr-x) (defgroup eshell-mode nil "This module contains code for handling input from the user." @@ -105,7 +106,8 @@ The input is contained in the region from `eshell-last-input-start' to "If t, send any input immediately to a subprocess." :type 'boolean) -(defcustom eshell-expand-input-functions nil +(defcustom eshell-expand-input-functions + '(eshell-expand-to-eshell-shell-command) "Functions to call before input is parsed. Each function is passed two arguments, which bounds the region of the current input text." @@ -671,6 +673,81 @@ newline." (run-hooks 'eshell-post-command-hook) (insert-and-inherit input))))))))) +(defun eshell-shell-command (command) + "Execute COMMAND using the operating system shell." + (throw 'eshell-replace-command + (with-connection-local-variables + (eshell-parse-command shell-file-name + (list shell-command-switch command))))) + +(defun eshell-expand-to-eshell-shell-command (beg end) + "Expand Eshell input starting with '||' to use `eshell-shell-command'. + +This is intended to provide a convenient way to bypass Eshell's +own pipelining which can be slow when executing shell pipelines +which move a lot of data. It is also useful to avoid +roundtripping data when running pipelines on remote hosts. + +For example, this function expands the input + + || cat *.ogg | my-cool-decoder >file + +to + + eshell-shell-command \"cat *.ogg | my-cool-decoder >file\" + +Executing the latter command will not copy all the data in the +*.ogg files into Emacs buffers, as would normally happen with +Eshell's own pipelining. + +This function tries to extract Eshell-specific redirects and +avoids passing these to the operating system shell. For example, + + || foo | bar >>#<buffer scratch> + +will be expanded to + + eshell-shell-command \"foo | bar\" >>#<buffer scratch> + +This function works well in combination with adding +`eshell-restore-unexpanded-input' to `eshell-input-filter-functions'." + (save-excursion + (goto-char beg) + (when (looking-at "||\\s-*") + (let ((end (copy-marker end)) ; needs to be a marker + redirects) + ;; drop the || + (delete-region beg (match-end 0)) + ;; extract Eshell-specific redirects + (while (search-forward-regexp "[0-9]?>+&?[0-9]?\\s-*\\S-" nil t) + (let ((beg (match-beginning 0))) + (forward-char -1) ; start from the redirect target + (when-let ((end (cond + ;; this is a redirect to a process or a + ;; buffer + ((looking-at "#<") + (forward-char 1) + (1+ (eshell-find-delimiter ?\< ?\>))) + ;; this is a redirect to a virtual target + ((and (looking-at "/\\S-+") + (assoc (match-string 0) + eshell-virtual-targets)) + (match-end 0))))) + (push (buffer-substring-no-properties beg end) redirects) + (delete-region beg end) + (just-one-space)))) + ;; wrap the remaining text and reinstate Eshell redirects + (let ((pipeline (string-trim + (buffer-substring-no-properties beg end)))) + (delete-region beg end) + (insert "eshell-shell-command ") + (prin1 pipeline (current-buffer)) + (when redirects + (insert " " (string-join (nreverse redirects) " ")))))))) + +(custom-add-option 'eshell-expand-input-functions + 'eshell-expand-to-eshell-shell-command) + (defsubst eshell-kill-new () "Add the last input text to the kill ring." (kill-ring-save eshell-last-input-start eshell-last-input-end)) |