summaryrefslogtreecommitdiff
path: root/lisp/eshell
diff options
context:
space:
mode:
authorJim Porter <jporterbugs@gmail.com>2023-01-15 16:44:23 -0800
committerJim Porter <jporterbugs@gmail.com>2023-01-30 17:49:11 -0800
commitcc5a2ed457eb34543bb7aaf6b39663af2599805d (patch)
tree21f3755be4249b38a49b68429cd7538821ea1411 /lisp/eshell
parent79154f625cc4f1db3cd2b9df1a3d88def27e0d56 (diff)
downloademacs-cc5a2ed457eb34543bb7aaf6b39663af2599805d.tar.gz
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.
Diffstat (limited to 'lisp/eshell')
-rw-r--r--lisp/eshell/em-cmpl.el56
1 files changed, 36 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)))