From c191af5dc286efd3d3b8a8d66ee280d17ef99853 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Wed, 1 Feb 2023 17:48:47 -0800 Subject: [PATCH 3/3] Don't add a space after the trailing slash when completing ~USER in Eshell This provides a programmed completion function that works similarly to ~USER completion in 'completion-file-name-table'. * lisp/eshell/em-dirs.el (eshell-complete-user-reference): Throw a programmed completion function. * test/lisp/eshell/em-cmpl-tests.el (em-cmpl-test/user-ref-completion): Update test. --- lisp/eshell/em-dirs.el | 37 +++++++++++++++++++++++-------- test/lisp/eshell/em-cmpl-tests.el | 5 ++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el index 0d02b64b084..62d37e8f9fe 100644 --- a/lisp/eshell/em-dirs.el +++ b/lisp/eshell/em-dirs.el @@ -281,15 +281,34 @@ eshell-complete-user-reference (let ((arg (pcomplete-actual-arg))) (when (string-match "\\`~[a-z]*\\'" arg) (setq pcomplete-stub (substring arg 1) - pcomplete-last-completion-raw t) - (throw 'pcomplete-completions - (progn - (eshell-read-user-names) - (pcomplete-uniquify-list - (mapcar - (lambda (user) - (file-name-as-directory (cdr user))) - eshell-user-names))))))) + pcomplete-last-completion-raw t) + ;; pcomplete-exit-function #'eshell-complete-user-ref--exit) + (eshell-read-user-names) + (let ((names (pcomplete-uniquify-list + (mapcar (lambda (user) + (file-name-as-directory (cdr user))) + eshell-user-names)))) + (throw 'pcomplete-completions + ;; Provide a programmed completion table. This works + ;; just like completing over the list of names, except + ;; it always returns the completed string, never `t'. + ;; That's because this is only completing a directory + ;; name, and so the completion isn't actually finished + ;; yet. + (lambda (string pred action) + (pcase action + ('nil ; try-completion + (let ((result (try-completion string names pred))) + (if (eq result t) string result))) + ('t ; all-completions + (all-completions string names pred)) + ('lambda ; test-completion + (let ((result (test-completion string names pred))) + (if (eq result t) string result))) + ('metadata + '(metadata (category . file))) + (`(boundaries . ,suffix) + `(boundaries 0 . ,(string-search "/" suffix)))))))))) (defun eshell/pwd (&rest _args) "Change output from `pwd' to be cleaner." diff --git a/test/lisp/eshell/em-cmpl-tests.el b/test/lisp/eshell/em-cmpl-tests.el index 1f8c571c44c..ecab7332822 100644 --- a/test/lisp/eshell/em-cmpl-tests.el +++ b/test/lisp/eshell/em-cmpl-tests.el @@ -218,15 +218,14 @@ em-cmpl-test/variable-assign-completion "VAR=file.txt "))))) (ert-deftest em-cmpl-test/user-ref-completion () - "Test completeion of user references like \"~user\". + "Test completion of user references like \"~user\". See ." (unwind-protect (with-temp-eshell (cl-letf (((symbol-function 'eshell-read-user-names) (lambda () (setq eshell-user-names '((1234 . "user")))))) - ;; FIXME: Should this really add a space at the end? (should (equal (eshell-insert-and-complete "echo ~us") - "echo ~user/ ")))) + "echo ~user/")))) ;; Clear the cached user names we set above. (setq eshell-user-names nil))) -- 2.25.1