[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 723b0973512 2/2: Add support for running commands via Eshell's "e
From: |
Jim Porter |
Subject: |
master 723b0973512 2/2: Add support for running commands via Eshell's "env" command |
Date: |
Fri, 26 Jan 2024 00:06:54 -0500 (EST) |
branch: master
commit 723b0973512c0e6e9fb0f07678124347ccd44b54
Author: Jim Porter <jporterbugs@gmail.com>
Commit: Jim Porter <jporterbugs@gmail.com>
Add support for running commands via Eshell's "env" command
* (eshell-handle-local-variables): Move most of the code to...
(eshell-parse-local-variables): ... here.
(eshell/env): Call 'eshell-parse-local-variables'.
* test/lisp/eshell/esh-var-tests.el
(esh-var-test/local-variables/env): New test.
* doc/misc/eshell.texi (Built-ins): Describe the new behavior.
* etc/NEWS: Announce this change.
---
doc/misc/eshell.texi | 8 ++++---
etc/NEWS | 7 ++++++
lisp/eshell/esh-var.el | 50 ++++++++++++++++++++++++---------------
test/lisp/eshell/esh-var-tests.el | 7 ++++++
4 files changed, 50 insertions(+), 22 deletions(-)
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index fb9a563b696..da5e1ef1d03 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -624,9 +624,11 @@ each argument as a string, separated by a space.
@item env
@cmindex env
-Prints the current environment variables. Unlike in Bash, this
-command does not yet support running commands with a modified
-environment.
+With no arguments, print the current environment variables. If you
+pass arguments to this command, then @command{env} will execute the
+arguments as a command. If you pass any initial arguments of the form
+@samp{@var{var}=@var{value}}, @command{env} will first set @var{var}
+to @var{value} before running the command.
@item eshell-debug
@cmindex eshell-debug
diff --git a/etc/NEWS b/etc/NEWS
index 0d7d7d5ab60..37264f2f1f1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -656,6 +656,13 @@ appropriate, but still allow piping the output elsewhere
if desired.
For more information, see the "(eshell) Built-ins" node in the Eshell
manual.
++++
+*** Eshell's 'env' command now supports running commands.
+Like in many other shells, Eshell's 'env' command now lets you run a
+command passed as arguments to 'env'. If you pass any initial
+arguments of the form 'VAR=VALUE', 'env' will first set 'VAR' to
+'VALUE' before running the command.
+
+++
*** New special reference type '#<marker POSITION BUFFER>'.
This special reference type returns a marker at 'POSITION' in
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index 1d90fbdd8ee..627cbb17797 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -304,27 +304,36 @@ This is set to t in `eshell-local-variable-bindings'
(which see).")
(add-hook 'pcomplete-try-first-hook
#'eshell-complete-variable-assignment nil t)))
-(defun eshell-handle-local-variables ()
- "Allow for the syntax `VAR=val <command> <args>'."
+(defun eshell-parse-local-variables (args)
+ "Parse a list of ARGS, looking for variable assignments.
+Variable assignments are of the form \"VAR=value\". If ARGS
+begins with any such assignments, throw `eshell-replace-command'
+with a form that will temporarily set those variables.
+Otherwise, return nil."
;; Handle local variable settings by let-binding the entries in
;; `eshell-local-variable-bindings' and calling `eshell-set-variable'
;; for each variable before the command is invoked.
(let ((setvar "\\`\\([A-Za-z_][A-Za-z0-9_]*\\)=\\(.*\\)\\'")
- (command eshell-last-command-name)
- (args eshell-last-arguments))
- (when (and (stringp command) (string-match setvar command))
+ (head (car args))
+ (rest (cdr args)))
+ (when (and (stringp head) (string-match setvar head))
(throw 'eshell-replace-command
`(let ,eshell-local-variable-bindings
,@(let (locals)
- (while (and (stringp command)
- (string-match setvar command))
+ (while (and (stringp head)
+ (string-match setvar head))
(push `(eshell-set-variable
- ,(match-string 1 command)
- ,(match-string 2 command))
+ ,(match-string 1 head)
+ ,(match-string 2 head))
locals)
- (setq command (pop args)))
+ (setq head (pop rest)))
(nreverse locals))
- (eshell-named-command ,command ,(list 'quote args)))))))
+ (eshell-named-command ,head ',rest))))))
+
+(defun eshell-handle-local-variables ()
+ "Allow for the syntax `VAR=val <command> <args>'."
+ (eshell-parse-local-variables (cons eshell-last-command-name
+ eshell-last-arguments)))
(defun eshell-interpolate-variable ()
"Parse a variable interpolation.
@@ -414,19 +423,22 @@ the values of nil for each."
obarray #'boundp))
(pcomplete-here))))
-;; FIXME the real "env" command does more than this, it runs a program
-;; in a modified environment.
(defun eshell/env (&rest args)
"Implementation of `env' in Lisp."
- (eshell-init-print-buffer)
(eshell-eval-using-options
"env" args
- '((?h "help" nil nil "show this usage screen")
+ '(;; FIXME: Support more "env" options, like "--unset".
+ (?h "help" nil nil "show this usage screen")
:external "env"
- :usage "<no arguments>")
- (dolist (setting (sort (eshell-environment-variables) 'string-lessp))
- (eshell-buffered-print setting "\n"))
- (eshell-flush)))
+ :parse-leading-options-only
+ :usage "[NAME=VALUE]... [COMMAND [ARG]...]")
+ (if args
+ (or (eshell-parse-local-variables args)
+ (eshell-named-command (car args) (cdr args)))
+ (eshell-init-print-buffer)
+ (dolist (setting (sort (eshell-environment-variables) 'string-lessp))
+ (eshell-buffered-print setting "\n"))
+ (eshell-flush))))
(defun eshell-insert-envvar (envvar-name)
"Insert ENVVAR-NAME into the current buffer at point."
diff --git a/test/lisp/eshell/esh-var-tests.el
b/test/lisp/eshell/esh-var-tests.el
index bb3d18abf6d..b94e8a276d7 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -661,6 +661,13 @@ nil, use FUNCTION instead."
(eshell-insert-command "VAR=hello cd ..")
(should (equal default-directory parent-directory)))))
+(ert-deftest esh-var-test/local-variables/env ()
+ "Test that \"env VAR=value command\" temporarily sets variables."
+ (with-temp-eshell
+ (push "VAR=value" process-environment)
+ (eshell-match-command-output "env VAR=hello env" "VAR=hello\n")
+ (should (equal (getenv "VAR") "value"))))
+
;; Variable aliases