emacs-diffs
[Top][All Lists]
Advanced

[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
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]