[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