diff options
| author | Jim Porter | 2023-01-15 16:44:23 -0800 |
|---|---|---|
| committer | Jim Porter | 2023-01-30 17:49:11 -0800 |
| commit | cc5a2ed457eb34543bb7aaf6b39663af2599805d (patch) | |
| tree | 21f3755be4249b38a49b68429cd7538821ea1411 | |
| parent | 79154f625cc4f1db3cd2b9df1a3d88def27e0d56 (diff) | |
| download | emacs-cc5a2ed457eb34543bb7aaf6b39663af2599805d.tar.gz emacs-cc5a2ed457eb34543bb7aaf6b39663af2599805d.zip | |
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.
| -rw-r--r-- | lisp/eshell/em-cmpl.el | 56 | ||||
| -rw-r--r-- | 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." | |||
| 306 | (insert-and-inherit "\t") | 306 | (insert-and-inherit "\t") |
| 307 | (throw 'pcompleted t))) | 307 | (throw 'pcompleted t))) |
| 308 | 308 | ||
| 309 | (defun eshell-complete--eval-argument-form (arg) | ||
| 310 | "Evaluate a single Eshell argument form ARG for the purposes of completion." | ||
| 311 | (let ((result (eshell-do-eval `(eshell-commands ,arg) t))) | ||
| 312 | (cl-assert (eq (car result) 'quote)) | ||
| 313 | (cadr result))) | ||
| 314 | |||
| 309 | (defun eshell-complete-parse-arguments () | 315 | (defun eshell-complete-parse-arguments () |
| 310 | "Parse the command line arguments for `pcomplete-argument'." | 316 | "Parse the command line arguments for `pcomplete-argument'." |
| 311 | (when (and eshell-no-completion-during-jobs | 317 | (when (and eshell-no-completion-during-jobs |
| @@ -344,11 +350,6 @@ to writing a completion function." | |||
| 344 | (cl-assert (= (length args) (length posns))) | 350 | (cl-assert (= (length args) (length posns))) |
| 345 | (let ((a args) (i 0) new-start) | 351 | (let ((a args) (i 0) new-start) |
| 346 | (while a | 352 | (while a |
| 347 | ;; Remove any top-level `eshell-splice-args' sigils. These | ||
| 348 | ;; are meant to be rewritten and can't actually be called. | ||
| 349 | (when (and (consp (car a)) | ||
| 350 | (eq (caar a) 'eshell-splice-args)) | ||
| 351 | (setcar a (cadar a))) | ||
| 352 | ;; If there's an unreplaced `eshell-operator' sigil, consider | 353 | ;; If there's an unreplaced `eshell-operator' sigil, consider |
| 353 | ;; the token after it the new start of our arguments. | 354 | ;; the token after it the new start of our arguments. |
| 354 | (when (and (consp (car a)) | 355 | (when (and (consp (car a)) |
| @@ -364,23 +365,38 @@ to writing a completion function." | |||
| 364 | (not (eq (char-before (1- end)) ?\\))) | 365 | (not (eq (char-before (1- end)) ?\\))) |
| 365 | (nconc args (list "")) | 366 | (nconc args (list "")) |
| 366 | (nconc posns (list (point)))) | 367 | (nconc posns (list (point)))) |
| 368 | ;; Evaluate and expand Eshell forms. | ||
| 369 | (let (evaled-args evaled-posns) | ||
| 370 | (cl-mapc | ||
| 371 | (lambda (arg posn) | ||
| 372 | (pcase arg | ||
| 373 | (`(eshell-splice-args ,val) | ||
| 374 | (dolist (subarg (eshell-complete--eval-argument-form val)) | ||
| 375 | (push subarg evaled-args) | ||
| 376 | (push posn evaled-posns))) | ||
| 377 | ((pred listp) | ||
| 378 | (push (eshell-complete--eval-argument-form arg) evaled-args) | ||
| 379 | (push posn evaled-posns)) | ||
| 380 | (_ | ||
| 381 | (push arg evaled-args) | ||
| 382 | (push posn evaled-posns)))) | ||
| 383 | args posns) | ||
| 384 | (setq args (nreverse evaled-args) | ||
| 385 | posns (nreverse evaled-posns))) | ||
| 386 | ;; Convert arguments to forms that Pcomplete can understand. | ||
| 367 | (cons (mapcar | 387 | (cons (mapcar |
| 368 | (lambda (arg) | 388 | (lambda (arg) |
| 369 | (let ((val | 389 | (cond |
| 370 | (if (listp arg) | 390 | ((numberp arg) |
| 371 | (let ((result | 391 | (number-to-string arg)) |
| 372 | (eshell-do-eval | 392 | ;; Expand ".../" etc that only Eshell understands to the |
| 373 | (list 'eshell-commands arg) t))) | 393 | ;; standard "../../". |
| 374 | (cl-assert (eq (car result) 'quote)) | 394 | ((and (stringp arg) (string-match "\\.\\.\\.+/" arg)) |
| 375 | (cadr result)) | 395 | (eshell-expand-multiple-dots arg)) |
| 376 | arg))) | 396 | ((null arg) |
| 377 | (cond ((numberp val) | 397 | "") |
| 378 | (setq val (number-to-string val))) | 398 | (t |
| 379 | ;; expand .../ etc that only eshell understands to | 399 | arg))) |
| 380 | ;; standard ../../ | ||
| 381 | ((and (stringp val)) (string-match "\\.\\.\\.+/" val) | ||
| 382 | (setq val (eshell-expand-multiple-dots val)))) | ||
| 383 | (or val ""))) | ||
| 384 | args) | 400 | args) |
| 385 | posns))) | 401 | posns))) |
| 386 | 402 | ||
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 @@ | |||
| 85 | (should (equal (car (eshell-complete-parse-arguments)) | 85 | (should (equal (car (eshell-complete-parse-arguments)) |
| 86 | '("echo" ("foo" "bar"))))))) | 86 | '("echo" ("foo" "bar"))))))) |
| 87 | 87 | ||
| 88 | (ert-deftest em-cmpl-test/parse-arguments/variable/splice () | ||
| 89 | "Test parsing arguments with a spliced variable interpolation." | ||
| 90 | (with-temp-eshell | ||
| 91 | (let ((eshell-test-value '("foo" "bar"))) | ||
| 92 | (insert "echo $@eshell-test-value") | ||
| 93 | (should (equal (car (eshell-complete-parse-arguments)) | ||
| 94 | '("echo" "foo" "bar")))))) | ||
| 95 | |||
| 88 | (ert-deftest em-cmpl-test/file-completion/unique () | 96 | (ert-deftest em-cmpl-test/file-completion/unique () |
| 89 | "Test completion of file names when there's a unique result." | 97 | "Test completion of file names when there's a unique result." |
| 90 | (with-temp-eshell | 98 | (with-temp-eshell |