From: Nicolas Martyanoff <nicolas@n16f.net>
To: emacs-devel@gnu.org
Cc: Nicolas Martyanoff <nicolas@n16f.net>
Subject: [PATCH] em-cmpl: fix completion of command paths
Date: Sat, 7 Jan 2023 13:19:44 +0100 [thread overview]
Message-ID: <20230107121943.44658-1-nicolas@n16f.net> (raw)
Completion was originally broken by 82c76e3.
The use of `completion-table-dynamic' was introduced in 899055e to fix
bug#48995. However the following issue remains: when completing a command
path, absolute ("/usr/bin/") or relative ("./subdir/"), a space is
automatically added at the end.
Bypassing `completion-table-dynamic' for filenames containing a directory
part fixes the final space bug and does not reintroduce bug#48995.
As a result, `eshell--pcomplete-executables' is not needed anymore, it was
only necessary to work around the way `completion-table-dynamic' works.
Thanks to Stefan Monnier for his input on the problem.
---
lisp/eshell/em-cmpl.el | 127 ++++++++++++++++++-----------------------
1 file changed, 56 insertions(+), 71 deletions(-)
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index ca51cee2558..c5427fa1a6d 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -378,88 +378,73 @@ eshell-complete-parse-arguments
args)
posns)))
-(defun eshell--pcomplete-executables ()
- "Complete amongst a list of directories and executables.
-
-Wrapper for `pcomplete-executables' or `pcomplete-dirs-or-entries',
-depending on the value of `eshell-force-execution'.
-
-Adds path prefix to candidates independent of `action' value."
- ;; `pcomplete-entries' returns filenames without path on `action' to
- ;; use current string directory as done in `completion-file-name-table'
- ;; when `action' is nil to construct executable candidates.
- (let ((table (if eshell-force-execution
- (pcomplete-dirs-or-entries nil #'file-readable-p)
- (pcomplete-executables))))
- (lambda (string pred action)
- (let ((cands (funcall table string pred action)))
- (if (eq action t)
- (let ((specdir (file-name-directory string)))
- (mapcar
- (lambda (cand)
- (if (stringp cand)
- (file-name-concat specdir cand)
- cand))
- cands))
- cands)))))
-
(defun eshell--complete-commands-list ()
"Generate list of applicable, visible commands."
;; Building the commands list can take quite a while, especially over Tramp
;; (bug#41423), so do it lazily.
(let ((glob-name
- ;; When a command is specified using `eshell-explicit-command-char',
+ ;; When a command is specified using `eshell-explicit-command-char',
;; that char is not part of the command and hence not part of what
;; we complete. Adjust `pcomplete-stub' accordingly!
- (if (and (> (length pcomplete-stub) 0)
- (eq (aref pcomplete-stub 0) eshell-explicit-command-char))
- (setq pcomplete-stub (substring pcomplete-stub 1)))))
- (completion-table-dynamic
- (lambda (filename)
- (if (file-name-directory filename)
- (eshell--pcomplete-executables)
- (let* ((paths (eshell-get-path))
- (cwd (file-name-as-directory
- (expand-file-name default-directory)))
- (filepath "") (completions ()))
- ;; Go thru each path in the search path, finding completions.
- (dolist (path paths)
- (setq path (file-name-as-directory
- (expand-file-name (or path "."))))
- ;; Go thru each completion found, to see whether it should
- ;; be used.
- (dolist (file (and (file-accessible-directory-p path)
- (file-name-all-completions filename path)))
- (setq filepath (concat path file))
- (if (and (not (member file completions)) ;
- (or (string-equal path cwd)
- (not (file-directory-p filepath)))
- ;; FIXME: Those repeated file tests end up
- ;; very costly over Tramp, we should cache the result.
- (if eshell-force-execution
+ (if (and (> (length pcomplete-stub) 0)
+ (eq (aref pcomplete-stub 0) eshell-explicit-command-char))
+ (setq pcomplete-stub (substring pcomplete-stub 1))))
+ (filename (pcomplete-arg)))
+ ;; Do not use `completion-table-dynamic' when completing a command path
+ ;; (absolute or relative): doing so assumes that the subpath in the input
+ ;; string is always a command, and appends a space character, which is
+ ;; incorrect (i.e. "/usr/bi" should yield "/usr/bin/" after completion,
+ ;; not "/usr/bin/ ").
+ ;;
+ ;; If you work on this function, be careful not to reintroduce bug#48995.
+ (if (file-name-directory filename)
+ (if eshell-force-execution
+ (pcomplete-dirs-or-entries nil #'file-readable-p)
+ (pcomplete-executables))
+ (completion-table-dynamic
+ (lambda (filename)
+ (let* ((paths (eshell-get-path))
+ (cwd (file-name-as-directory
+ (expand-file-name default-directory)))
+ (filepath "") (completions ()))
+ ;; Go thru each path in the search path, finding completions.
+ (dolist (path paths)
+ (setq path (file-name-as-directory
+ (expand-file-name (or path "."))))
+ ;; Go thru each completion found, to see whether it should
+ ;; be used.
+ (dolist (file (and (file-accessible-directory-p path)
+ (file-name-all-completions filename path)))
+ (setq filepath (concat path file))
+ (if (and (not (member file completions)) ;
+ (or (string-equal path cwd)
+ (not (file-directory-p filepath)))
+ ;; FIXME: Those repeated file tests end up
+ ;; very costly over Tramp, we should cache the result.
+ (if eshell-force-execution
(file-readable-p filepath)
(file-executable-p filepath)))
- (push file completions))))
- ;; Add aliases which are currently visible, and Lisp functions.
- (pcomplete-uniquify-list
- (if glob-name
- completions
- (setq completions
- (append (if (fboundp 'eshell-alias-completions)
- (eshell-alias-completions filename))
- (eshell-winnow-list
- (mapcar
+ (push file completions))))
+ ;; Add aliases which are currently visible, and Lisp functions.
+ (pcomplete-uniquify-list
+ (if glob-name
+ completions
+ (setq completions
+ (append (if (fboundp 'eshell-alias-completions)
+ (eshell-alias-completions filename))
+ (eshell-winnow-list
+ (mapcar
(lambda (name)
(substring name 7))
- (all-completions (concat "eshell/" filename)
- obarray #'functionp))
- nil '(eshell-find-alias-function))
- completions))
- (append (and (or eshell-show-lisp-completions
- (and eshell-show-lisp-alternatives
- (null completions)))
- (all-completions filename obarray #'functionp))
- completions)))))))))
+ (all-completions (concat "eshell/" filename)
+ obarray #'functionp))
+ nil '(eshell-find-alias-function))
+ completions))
+ (append (and (or eshell-show-lisp-completions
+ (and eshell-show-lisp-alternatives
+ (null completions)))
+ (all-completions filename obarray #'functionp))
+ completions)))))))))
(define-obsolete-function-alias 'eshell-pcomplete #'completion-at-point "27.1")
--
2.38.1
next reply other threads:[~2023-01-07 12:19 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-07 12:19 Nicolas Martyanoff [this message]
2023-01-07 12:23 ` [PATCH] em-cmpl: fix completion of command paths Nicolas Martyanoff
2023-01-13 10:59 ` Nicolas Martyanoff
2023-01-25 17:03 ` Stefan Monnier
2023-01-25 17:15 ` Eli Zaretskii
2023-01-25 20:32 ` [PATCH] Update compat Nicolas Martyanoff
[not found] ` <87bkmmwcwx.fsf@valhala.localdomain>
2023-01-26 6:02 ` [PATCH] em-cmpl: fix completion of command paths Eli Zaretskii
2023-01-26 9:06 ` Eli Zaretskii
2023-01-26 12:21 ` Nicolas Martyanoff
2023-01-26 12:58 ` Eli Zaretskii
2023-01-28 0:11 ` Stefan Monnier
2023-01-28 8:27 ` Eli Zaretskii
2023-01-28 0:12 ` Stefan Monnier
2023-01-25 21:50 ` Jim Porter
2023-02-08 6:06 ` Jim Porter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230107121943.44658-1-nicolas@n16f.net \
--to=nicolas@n16f.net \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.