Don't add trailing space when completing options that take arguments

The space is unhelpful, since the user likely wants to add a value for
that option immediately after the "=" (bug#81689).

* lisp/pcomplete.el (pcomplete-long-option-completion-table): New
function...
(pcomplete-here-using-help):
* lisp/pcmpl-gnu.el (pcomplete/tar):
* lisp/pcmpl-linux.el (pcomplete/systemctl): ... use it.

* test/lisp/pcomplete-tests.el (pcomplete-shell-completion)
(pcomplete/pcmpl-option-test): New functions.
(pcomplete-test-long-options/with-value)
(pcomplete-test-long-options/without-value): New tests.
This commit is contained in:
Jim Porter 2026-08-23 22:25:27 -07:00
parent 8a287a3888
commit 6723797856
4 changed files with 56 additions and 5 deletions

View file

@ -274,7 +274,8 @@ Return the new list."
(if (pcomplete-match "^--" 0)
(cond
((pcomplete-match "^--\\([^= \t\n\f]*\\)\\'" 0)
(pcomplete-here* pcmpl-gnu--tar-long-options))
(pcomplete-here* (pcomplete-long-option-completion-table
pcmpl-gnu--tar-long-options)))
((pcomplete-match "\\`--directory=\\(.*\\)" 0)
(pcomplete-here* (pcomplete-dirs)
(pcomplete-match-string 1 0)))

View file

@ -148,9 +148,10 @@ Test is done using `equal'."
:metavar (rx (group (+ " " (>= 2 (any upper "[]|."))))))))
(while (not (member (pcomplete-arg 1) subcmds))
(if (string-prefix-p "-" (pcomplete-arg 0))
(pcomplete-here (pcomplete-from-help "systemctl --help"
:metavar "[^ ]+"
:separator " \\(\\)-"))
(pcomplete-here (pcomplete-long-option-completion-table
(pcomplete-from-help "systemctl --help"
:metavar "[^ ]+"
:separator " \\(\\)-")))
(pcomplete-here subcmds)))
(let ((subcmd (pcomplete-arg 1))
(context (if (member "--user" pcomplete-args) "--user" "--system")))

View file

@ -1370,6 +1370,26 @@ Sequence should be a vector or list of strings."
(pcomplete-read-hosts pcomplete-hosts-file 'pcomplete--host-name-cache
'pcomplete--host-name-cache-timestamp)))
(defun pcomplete-long-option-completion-table (options)
"Make a completion table for a list of OPTIONS.
OPTIONS should be a list of option strings; if a string ends in
\"=\", it's an option that accepts a value."
(lambda (string pred action)
(pcase action
('nil ; try-completion
(let ((result (try-completion string options pred)))
;; If the completion ends in "=", then it's not really
;; complete yet: we expect a value after the "=". Return the
;; original STRING in this case instead of t to indicate
;; that.
(if (and (eq result t) (string-suffix-p "=" string))
string
result)))
('t ; all-completions
(all-completions string options pred))
('lambda ; test-completion
(test-completion string options pred)))))
;;; Parsing help messages
(defvar pcomplete-from-help (make-hash-table :test #'equal)
@ -1494,7 +1514,8 @@ COMMAND and ARGS as arguments."
(pcomplete-here (pcomplete-entries)
(pcomplete-match-string 1 0)))
((string-prefix-p "-" (pcomplete-arg 0))
(pcomplete-here (apply #'pcomplete-from-help command args)))
(pcomplete-here (pcomplete-long-option-completion-table
(apply #'pcomplete-from-help command args))))
(t (pcomplete-here* (pcomplete-entries))))))
(provide 'pcomplete)

View file

@ -96,5 +96,33 @@ usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
#("--super-prefix=" 0 1 (pcomplete-annotation "<path>"))
#("--config-env=" 0 1 (pcomplete-annotation "<name>")))))))
(defun pcomplete-shell-completion (input)
"Insert INPUT into shell mode, run completion, and return the result."
(with-temp-buffer
(shell (current-buffer))
(unwind-protect
(let ((start (point)))
(insert input)
(completion-at-point)
(buffer-substring start (point)))
(let (kill-buffer-query-functions)
(kill-buffer (current-buffer))))))
(defun pcomplete/pcmpl-option-test ()
"Completion for a test command taking long options."
(while (pcomplete-match "^--" 0)
(pcomplete-here* (pcomplete-long-option-completion-table
'("--version" "--owner=")))))
(ert-deftest pcomplete-test-long-options/with-value ()
"Test that completing long options taking values doesn't insert a space."
(should (string= (pcomplete-shell-completion "pcmpl-option-test --own")
"pcmpl-option-test --owner=")))
(ert-deftest pcomplete-test-long-options/without-value ()
"Test that completing long options without values inserts a space."
(should (string= (pcomplete-shell-completion "pcmpl-option-test --ver")
"pcmpl-option-test --version ")))
(provide 'pcomplete-tests)
;;; pcomplete-tests.el ends here