emacs-diffs
[Top][All Lists]
Advanced

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

master cc5a2ed457e 2/3: Properly parse Eshell variable splices for inter


From: Jim Porter
Subject: master cc5a2ed457e 2/3: Properly parse Eshell variable splices for interactive completion
Date: Mon, 30 Jan 2023 20:57:15 -0500 (EST)

branch: master
commit cc5a2ed457eb34543bb7aaf6b39663af2599805d
Author: Jim Porter <jporterbugs@gmail.com>
Commit: Jim Porter <jporterbugs@gmail.com>

    Properly parse Eshell variable splices for interactive completion
    
    Previously, the code simply ignored the splice operator, which usually
    worked, but isn't actually correct.
    
    * lisp/eshell/em-cmpl.el (eshell-complete-eval-argument-form): New
    function.
    (eshell-complete-parse-arguments): Properly parse variable splices.
    
    * test/lisp/eshell/em-cmpl-tests.el
    (em-cmpl-test/parse-arguments/variable/splice): New test.
---
 lisp/eshell/em-cmpl.el            | 56 +++++++++++++++++++++++++--------------
 test/lisp/eshell/em-cmpl-tests.el |  8 ++++++
 2 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index 4206ad048fa..d1c7e81090a 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -306,6 +306,12 @@ to writing a completion function."
     (insert-and-inherit "\t")
     (throw 'pcompleted t)))
 
+(defun eshell-complete--eval-argument-form (arg)
+  "Evaluate a single Eshell argument form ARG for the purposes of completion."
+  (let ((result (eshell-do-eval `(eshell-commands ,arg) t)))
+    (cl-assert (eq (car result) 'quote))
+    (cadr result)))
+
 (defun eshell-complete-parse-arguments ()
   "Parse the command line arguments for `pcomplete-argument'."
   (when (and eshell-no-completion-during-jobs
@@ -344,11 +350,6 @@ to writing a completion function."
     (cl-assert (= (length args) (length posns)))
     (let ((a args) (i 0) new-start)
       (while a
-        ;; Remove any top-level `eshell-splice-args' sigils.  These
-        ;; are meant to be rewritten and can't actually be called.
-        (when (and (consp (car a))
-                   (eq (caar a) 'eshell-splice-args))
-          (setcar a (cadar a)))
         ;; If there's an unreplaced `eshell-operator' sigil, consider
         ;; the token after it the new start of our arguments.
         (when (and (consp (car a))
@@ -364,23 +365,38 @@ to writing a completion function."
               (not (eq (char-before (1- end)) ?\\)))
       (nconc args (list ""))
       (nconc posns (list (point))))
+    ;; Evaluate and expand Eshell forms.
+    (let (evaled-args evaled-posns)
+      (cl-mapc
+       (lambda (arg posn)
+         (pcase arg
+           (`(eshell-splice-args ,val)
+            (dolist (subarg (eshell-complete--eval-argument-form val))
+              (push subarg evaled-args)
+              (push posn evaled-posns)))
+           ((pred listp)
+            (push (eshell-complete--eval-argument-form arg) evaled-args)
+            (push posn evaled-posns))
+           (_
+            (push arg evaled-args)
+            (push posn evaled-posns))))
+       args posns)
+      (setq args (nreverse evaled-args)
+            posns (nreverse evaled-posns)))
+    ;; Convert arguments to forms that Pcomplete can understand.
     (cons (mapcar
            (lambda (arg)
-             (let ((val
-                    (if (listp arg)
-                        (let ((result
-                               (eshell-do-eval
-                                (list 'eshell-commands arg) t)))
-                          (cl-assert (eq (car result) 'quote))
-                          (cadr result))
-                      arg)))
-               (cond ((numberp val)
-                      (setq val (number-to-string val)))
-                     ;; expand .../ etc that only eshell understands to
-                     ;; standard ../../
-                     ((and (stringp val)) (string-match "\\.\\.\\.+/" val)
-                      (setq val (eshell-expand-multiple-dots val))))
-               (or val "")))
+             (cond
+              ((numberp arg)
+               (number-to-string arg))
+              ;; Expand ".../" etc that only Eshell understands to the
+              ;; standard "../../".
+              ((and (stringp arg) (string-match "\\.\\.\\.+/" arg))
+               (eshell-expand-multiple-dots arg))
+              ((null arg)
+               "")
+              (t
+               arg)))
           args)
          posns)))
 
diff --git a/test/lisp/eshell/em-cmpl-tests.el 
b/test/lisp/eshell/em-cmpl-tests.el
index 32b0781dd75..3f8f890f6e5 100644
--- a/test/lisp/eshell/em-cmpl-tests.el
+++ b/test/lisp/eshell/em-cmpl-tests.el
@@ -85,6 +85,14 @@
      (should (equal (car (eshell-complete-parse-arguments))
                     '("echo" ("foo" "bar")))))))
 
+(ert-deftest em-cmpl-test/parse-arguments/variable/splice ()
+  "Test parsing arguments with a spliced variable interpolation."
+  (with-temp-eshell
+   (let ((eshell-test-value '("foo" "bar")))
+     (insert "echo $@eshell-test-value")
+     (should (equal (car (eshell-complete-parse-arguments))
+                    '("echo" "foo" "bar"))))))
+
 (ert-deftest em-cmpl-test/file-completion/unique ()
   "Test completion of file names when there's a unique result."
   (with-temp-eshell



reply via email to

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