emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master cccee7e840 3/5: Fix Eshell dollar interpolation inside of double-


From: Lars Ingebrigtsen
Subject: master cccee7e840 3/5: Fix Eshell dollar interpolation inside of double-quotes
Date: Thu, 3 Mar 2022 08:59:49 -0500 (EST)

branch: master
commit cccee7e840102488e01f9bb7c2220392d358f4f0
Author: Jim Porter <jporterbugs@gmail.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Fix Eshell dollar interpolation inside of double-quotes
    
    For example,
    
      echo "${echo hi}"
    
    previously tried to run the program named 'echo hi', instead of 'echo'
    with the argument 'hi'.
    
    * lisp/eshell/esh-arg.el (eshell-parse-inner-double-quote):
    New function.
    
    * lisp/eshell/esh-var.el (eshell-parse-variable-ref): Support parsing
    when wrapped in double-quiotes.
    
    * test/lisp/eshell/esh-var-tests.el (esh-var-test/interp-var)
    (esh-var-test/interp-quoted-var)
    (esh-var-test/interp-quoted-var-concat)
    (esh-var-test/quoted-interp-var)
    (esh-var-test/quoted-interp-quoted-var)
    (esh-var-test/quoted-interp-lisp, esh-var-test/quoted-interp-cmd)
    (esh-var-test/quoted-interp-temp-cmd): New tests.
---
 lisp/eshell/esh-arg.el            | 24 +++++++++++++++++++
 lisp/eshell/esh-var.el            | 27 ++++++++++++++-------
 test/lisp/eshell/esh-var-tests.el | 49 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 9 deletions(-)

diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el
index 1a2f2a57e8..e19481c4ba 100644
--- a/lisp/eshell/esh-arg.el
+++ b/lisp/eshell/esh-arg.el
@@ -354,6 +354,30 @@ after are both returned."
                  (list 'eshell-escape-arg arg))))
          (goto-char (1+ end)))))))
 
+(defun eshell-parse-inner-double-quote (bound)
+  "Parse the inner part of a double quoted string.
+The string to parse starts at point and ends at BOUND.
+
+If Eshell is currently parsing a quoted string and there are any
+backslash-escaped characters, this will return the unescaped
+string, updating point to BOUND.  Otherwise, this returns nil and
+leaves point where it was."
+  (when eshell-current-quoted
+    (let (strings
+          (start (point))
+          (special-char
+           (rx-to-string
+            `(seq "\\" (group (any ,@eshell-special-chars-inside-quoting))))))
+      (while (re-search-forward special-char bound t)
+        (push (concat (buffer-substring start (match-beginning 0))
+                      (match-string 1))
+              strings)
+        (setq start (match-end 0)))
+      (when strings
+        (push (buffer-substring start bound) strings)
+        (goto-char bound)
+        (apply #'concat (nreverse strings))))))
+
 (defun eshell-parse-special-reference ()
   "Parse a special syntax reference, of the form `#<args>'.
 
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index ee3ffbc647..24fdbde3cf 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -440,18 +440,16 @@ Possible options are:
     (let ((end (eshell-find-delimiter ?\{ ?\})))
       (if (not end)
           (throw 'eshell-incomplete ?\{)
+        (forward-char)
         (prog1
             `(eshell-convert
               (eshell-command-to-value
                (eshell-as-subcommand
-                ,(eshell-parse-command (cons (1+ (point)) end)))))
+                ,(let ((subcmd (or (eshell-parse-inner-double-quote end)
+                                   (cons (point) end)))
+                       (eshell-current-quoted nil))
+                   (eshell-parse-command subcmd)))))
           (goto-char (1+ end))))))
-   ((memq (char-after) '(?\' ?\"))
-    (let ((name (if (eq (char-after) ?\')
-                    (eshell-parse-literal-quote)
-                  (eshell-parse-double-quote))))
-      (if name
-         `(eshell-get-variable ,(eval name) indices))))
    ((eq (char-after) ?\<)
     (let ((end (eshell-find-delimiter ?\< ?\>)))
       (if (not end)
@@ -463,7 +461,9 @@ Possible options are:
               `(let ((eshell-current-handles
                       (eshell-create-handles ,temp 'overwrite)))
                  (progn
-                   (eshell-as-subcommand ,(eshell-parse-command cmd))
+                   (eshell-as-subcommand
+                    ,(let ((eshell-current-quoted nil))
+                       (eshell-parse-command cmd)))
                    (ignore
                     (nconc eshell-this-command-hook
                            ;; Quote this lambda; it will be evaluated
@@ -478,9 +478,18 @@ Possible options are:
     (condition-case nil
         `(eshell-command-to-value
           (eshell-lisp-command
-           ',(read (current-buffer))))
+           ',(read (or (eshell-parse-inner-double-quote (point-max))
+                       (current-buffer)))))
       (end-of-file
        (throw 'eshell-incomplete ?\())))
+   ((looking-at (rx (or "'" "\"" "\\\"")))
+    (eshell-with-temp-command (or (eshell-parse-inner-double-quote (point-max))
+                                  (cons (point) (point-max)))
+      (let ((name (if (eq (char-after) ?\')
+                      (eshell-parse-literal-quote)
+                    (eshell-parse-double-quote))))
+        (when name
+         `(eshell-get-variable ,(eval name) indices)))))
    ((assoc (char-to-string (char-after))
            eshell-variable-aliases-list)
     (forward-char)
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 8d803e5ca4..7ec6a97519 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -37,6 +37,25 @@
 
 ;; Variable interpolation
 
+(ert-deftest esh-var-test/interp-var ()
+  "Interpolate variable"
+  (should (equal (eshell-test-command-result "echo $user-login-name")
+                 user-login-name)))
+
+(ert-deftest esh-var-test/interp-quoted-var ()
+  "Interpolate quoted variable"
+  (should (equal (eshell-test-command-result "echo $'user-login-name'")
+                 user-login-name))
+  (should (equal (eshell-test-command-result "echo $\"user-login-name\"")
+                 user-login-name)))
+
+(ert-deftest esh-var-test/interp-quoted-var-concat ()
+  "Interpolate and concat quoted variable"
+  (should (equal (eshell-test-command-result "echo $'user-login-name'-foo")
+                 (concat user-login-name "-foo")))
+  (should (equal (eshell-test-command-result "echo $\"user-login-name\"-foo")
+                 (concat user-login-name "-foo"))))
+
 (ert-deftest esh-var-test/interp-lisp ()
   "Interpolate Lisp form evaluation"
   (should (equal (eshell-test-command-result "+ $(+ 1 2) 3") 6)))
@@ -79,6 +98,36 @@
    (eshell-command-result-p "echo ${echo hi}-${*echo there}"
                             "hi-there\n")))
 
+(ert-deftest esh-var-test/quoted-interp-var ()
+  "Interpolate variable inside double-quotes"
+  (should (equal (eshell-test-command-result "echo \"$user-login-name\"")
+                 user-login-name)))
+
+(ert-deftest esh-var-test/quoted-interp-quoted-var ()
+  "Interpolate quoted variable inside double-quotes"
+  (should (equal (eshell-test-command-result
+                  "echo \"hi, $'user-login-name'\"")
+                 (concat "hi, " user-login-name)))
+  (should (equal (eshell-test-command-result
+                  "echo \"hi, $\\\"user-login-name\\\"\"")
+                 (concat "hi, " user-login-name))))
+
+(ert-deftest esh-var-test/quoted-interp-lisp ()
+  "Interpolate Lisp form evaluation inside double-quotes"
+  (should (equal (eshell-test-command-result
+                  "echo \"hi $(concat \\\"the\\\" \\\"re\\\")\"")
+                 "hi there")))
+
+(ert-deftest esh-var-test/quoted-interp-cmd ()
+  "Interpolate command result inside double-quotes"
+  (should (equal (eshell-test-command-result
+                  "echo \"hi ${echo \\\"there\\\"}\"")
+                 "hi there")))
+
+(ert-deftest esh-var-test/quoted-interp-temp-cmd ()
+  "Interpolate command result redirected to temp file inside double-quotes"
+  (should (equal (eshell-test-command-result "cat \"$<echo hi>\"") "hi")))
+
 
 ;; Built-in variables
 



reply via email to

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