diff options
| author | Augusto Stoffel | 2022-09-08 11:09:42 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2022-09-14 21:58:04 +0200 |
| commit | a9941269683fe50673d0aa81feefb7a9d3d8a6b9 (patch) | |
| tree | 566c9ecd3afb90b58607c71ad794cee14ba7b823 | |
| parent | 05971d2b8d47e69e9585d0d6066b8a607555aa48 (diff) | |
| download | emacs-a9941269683fe50673d0aa81feefb7a9d3d8a6b9.tar.gz emacs-a9941269683fe50673d0aa81feefb7a9d3d8a6b9.zip | |
pcomplete: Generate completions from --help messages
* lisp/pcomplete.el (pcomplete-from-help): New function (and hash
table) to get pcomplete candidates from help messages.
(pcomplete-here-using-help): Helper function to define pcomplete for
simple commands
(pcomplete-completions-at-point): Provide annotation-function and
company-docsig properties.
* lisp/pcmpl-git.el: New file, provides pcomplete for Git.
* lisp/pcmpl-gnu.el: Add pcomplete for awk, gpg and gdb, emacs and
emacsclient.
* lisp/pcmpl-linux.el: Add pcomplete for systemctl and journalctl.
* lisp/pcmpl-rpm.el: Add pcomplete for dnf.
* lisp/pcmpl-unix.el: Add pcomplete for sudo and most commands found
in GNU Coreutils.
* lisp/pcmpl-x.el: Add pcomplete for tex, pdftex, latex, pdflatex,
rigrep and rclone.
* test/lisp/pcomplete-tests.el (pcomplete-test-parse-gpg-help,
pcomplete-test-parse-git-help): Tests for the new functions.
| -rw-r--r-- | lisp/pcmpl-git.el | 110 | ||||
| -rw-r--r-- | lisp/pcmpl-gnu.el | 36 | ||||
| -rw-r--r-- | lisp/pcmpl-linux.el | 68 | ||||
| -rw-r--r-- | lisp/pcmpl-rpm.el | 43 | ||||
| -rw-r--r-- | lisp/pcmpl-unix.el | 490 | ||||
| -rw-r--r-- | lisp/pcmpl-x.el | 43 | ||||
| -rw-r--r-- | lisp/pcomplete.el | 138 | ||||
| -rw-r--r-- | test/lisp/pcomplete-tests.el | 100 |
8 files changed, 1004 insertions, 24 deletions
diff --git a/lisp/pcmpl-git.el b/lisp/pcmpl-git.el new file mode 100644 index 00000000000..3584fa06732 --- /dev/null +++ b/lisp/pcmpl-git.el | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | ;;; pcmpl-git.el --- Completions for Git -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2022 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Package: pcomplete | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 12 | ;; (at your option) any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 21 | |||
| 22 | ;;; Commentary: | ||
| 23 | |||
| 24 | ;; This library provides completion rules for the Git program. | ||
| 25 | |||
| 26 | ;;; Code: | ||
| 27 | |||
| 28 | (require 'pcomplete) | ||
| 29 | (require 'vc-git) | ||
| 30 | |||
| 31 | (defun pcmpl-git--expand-flags (args) | ||
| 32 | "In the list of ARGS, expand arguments of the form --[no-]flag." | ||
| 33 | (mapcan (lambda (arg) (if (string-search "[no-]" arg) | ||
| 34 | (list (string-replace "[no-]" "" arg) | ||
| 35 | (string-replace "[no-]" "no-" arg)) | ||
| 36 | (list arg))) | ||
| 37 | args)) | ||
| 38 | |||
| 39 | (defun pcmpl-git--tracked-file-predicate (&rest args) | ||
| 40 | "Return a predicate function determining the Git status of a file. | ||
| 41 | Files listed by `git ls-files ARGS' satisfy the predicate." | ||
| 42 | (when-let ((files (mapcar #'expand-file-name | ||
| 43 | (ignore-errors | ||
| 44 | (apply #'process-lines | ||
| 45 | vc-git-program "ls-files" args))))) | ||
| 46 | (lambda (file) | ||
| 47 | (setq file (expand-file-name file)) | ||
| 48 | (if (string-suffix-p "/" file) | ||
| 49 | (seq-some (lambda (f) (string-prefix-p file f)) | ||
| 50 | files) | ||
| 51 | (member file files))))) | ||
| 52 | |||
| 53 | (defun pcmpl-git--remote-refs (remote) | ||
| 54 | "List the locally known Git revisions from REMOTE." | ||
| 55 | (delq nil | ||
| 56 | (mapcar | ||
| 57 | (let ((re (concat "\\`" (regexp-quote remote) "/\\(.*\\)"))) | ||
| 58 | (lambda (s) (when (string-match re s) (match-string 1 s)))) | ||
| 59 | (vc-git-revision-table nil)))) | ||
| 60 | |||
| 61 | ;;;###autoload | ||
| 62 | (defun pcomplete/git () | ||
| 63 | "Completion for the `git' command." | ||
| 64 | (let ((subcommands (pcomplete-from-help `(,vc-git-program "help" "-a") | ||
| 65 | :margin "^\\( +\\)[a-z]" | ||
| 66 | :argument "[[:alnum:]-]+"))) | ||
| 67 | (while (not (member (pcomplete-arg 1) subcommands)) | ||
| 68 | (if (string-prefix-p "-" (pcomplete-arg)) | ||
| 69 | (pcomplete-here (pcomplete-from-help `(,vc-git-program "help") | ||
| 70 | :margin "\\(\\[\\)-" | ||
| 71 | :separator " | " | ||
| 72 | :description "\\`")) | ||
| 73 | (pcomplete-here (completion-table-merge | ||
| 74 | subcommands | ||
| 75 | (when (string-prefix-p "-" (pcomplete-arg 1)) | ||
| 76 | (pcomplete-entries)))))) | ||
| 77 | (let ((subcmd (pcomplete-arg 1))) | ||
| 78 | (while (pcase subcmd | ||
| 79 | ((guard (string-prefix-p "-" (pcomplete-arg))) | ||
| 80 | (pcomplete-here | ||
| 81 | (pcmpl-git--expand-flags | ||
| 82 | (pcomplete-from-help `(,vc-git-program "help" ,subcmd) | ||
| 83 | :argument | ||
| 84 | "-+\\(?:\\[no-\\]\\)?[a-z-]+=?")))) | ||
| 85 | ;; Complete modified tracked files | ||
| 86 | ((or "add" "commit" "restore") | ||
| 87 | (pcomplete-here | ||
| 88 | (pcomplete-entries | ||
| 89 | nil (pcmpl-git--tracked-file-predicate "-m")))) | ||
| 90 | ;; Complete all tracked files | ||
| 91 | ((or "mv" "rm" "grep" "status") | ||
| 92 | (pcomplete-here | ||
| 93 | (pcomplete-entries nil (pcmpl-git--tracked-file-predicate)))) | ||
| 94 | ;; Complete revisions | ||
| 95 | ((or "branch" "merge" "rebase" "switch") | ||
| 96 | (pcomplete-here (vc-git-revision-table nil))) | ||
| 97 | ;; Complete revisions and tracked files | ||
| 98 | ;; TODO: diff and log accept revision ranges | ||
| 99 | ((or "checkout" "reset" "show" "diff" "log") | ||
| 100 | (pcomplete-here | ||
| 101 | (completion-table-in-turn | ||
| 102 | (vc-git-revision-table nil) | ||
| 103 | (pcomplete-entries nil (pcmpl-git--tracked-file-predicate))))) | ||
| 104 | ;; Complete remotes and their revisions | ||
| 105 | ((or "fetch" "pull" "push") | ||
| 106 | (pcomplete-here (process-lines vc-git-program "remote")) | ||
| 107 | (pcomplete-here (pcmpl-git--remote-refs (pcomplete-arg 1))))))))) | ||
| 108 | |||
| 109 | (provide 'pcmpl-git) | ||
| 110 | ;;; pcmpl-git.el ends here | ||
diff --git a/lisp/pcmpl-gnu.el b/lisp/pcmpl-gnu.el index 3c9bf1ec9d2..cdfde5640a7 100644 --- a/lisp/pcmpl-gnu.el +++ b/lisp/pcmpl-gnu.el | |||
| @@ -394,6 +394,40 @@ Return the new list." | |||
| 394 | (while (pcomplete-here (pcomplete-dirs) nil #'identity)))) | 394 | (while (pcomplete-here (pcomplete-dirs) nil #'identity)))) |
| 395 | 395 | ||
| 396 | ;;;###autoload | 396 | ;;;###autoload |
| 397 | (defalias 'pcomplete/gdb 'pcomplete/xargs) | 397 | (defun pcomplete/awk () |
| 398 | "Completion for the `awk' command." | ||
| 399 | (pcomplete-here-using-help "awk --help" | ||
| 400 | :margin "\t" | ||
| 401 | :separator " +" | ||
| 402 | :description "\0" | ||
| 403 | :metavar "[=a-z]+")) | ||
| 404 | |||
| 405 | ;;;###autoload | ||
| 406 | (defun pcomplete/gpg () | ||
| 407 | "Completion for the `gpg` command." | ||
| 408 | (pcomplete-here-using-help "gpg --help" :narrow-end "^ -se")) | ||
| 409 | |||
| 410 | ;;;###autoload | ||
| 411 | (defun pcomplete/gdb () | ||
| 412 | "Completion for the `gdb' command." | ||
| 413 | (while | ||
| 414 | (cond | ||
| 415 | ((string= "--args" (pcomplete-arg 1)) | ||
| 416 | (funcall pcomplete-command-completion-function) | ||
| 417 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 418 | pcomplete-default-completion-function))) | ||
| 419 | ((string-prefix-p "-" (pcomplete-arg 0)) | ||
| 420 | (pcomplete-here (pcomplete-from-help "gdb --help"))) | ||
| 421 | (t (pcomplete-here (pcomplete-entries)))))) | ||
| 422 | |||
| 423 | ;;;###autoload | ||
| 424 | (defun pcomplete/emacs () | ||
| 425 | "Completion for the `emacs' command." | ||
| 426 | (pcomplete-here-using-help "emacs --help" :margin "^\\(\\)-")) | ||
| 427 | |||
| 428 | ;;;###autoload | ||
| 429 | (defun pcomplete/emacsclient () | ||
| 430 | "Completion for the `emacsclient' command." | ||
| 431 | (pcomplete-here-using-help "emacsclient --help" :margin "^\\(\\)-")) | ||
| 398 | 432 | ||
| 399 | ;;; pcmpl-gnu.el ends here | 433 | ;;; pcmpl-gnu.el ends here |
diff --git a/lisp/pcmpl-linux.el b/lisp/pcmpl-linux.el index 7c072f3d40c..023c655a2a8 100644 --- a/lisp/pcmpl-linux.el +++ b/lisp/pcmpl-linux.el | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | (provide 'pcmpl-linux) | 30 | (provide 'pcmpl-linux) |
| 31 | 31 | ||
| 32 | (require 'pcomplete) | 32 | (require 'pcomplete) |
| 33 | (eval-when-compile (require 'rx)) | ||
| 33 | 34 | ||
| 34 | ;; Functions: | 35 | ;; Functions: |
| 35 | 36 | ||
| @@ -111,4 +112,71 @@ Test is done using `equal'." | |||
| 111 | (pcomplete-uniquify-list points) | 112 | (pcomplete-uniquify-list points) |
| 112 | (cons "swap" (pcmpl-linux-mounted-directories)))))) | 113 | (cons "swap" (pcmpl-linux-mounted-directories)))))) |
| 113 | 114 | ||
| 115 | ;;; systemd | ||
| 116 | |||
| 117 | (defun pcmpl-linux--systemd-units (&rest args) | ||
| 118 | "Run `systemd list-units ARGS' and return the output as a list." | ||
| 119 | (with-temp-buffer | ||
| 120 | (apply #'call-process | ||
| 121 | "systemctl" nil '(t nil) nil | ||
| 122 | "list-units" "--full" "--legend=no" "--plain" args) | ||
| 123 | (goto-char (point-min)) | ||
| 124 | (let (result) | ||
| 125 | (while (re-search-forward (rx bol (group (+ (not space))) | ||
| 126 | (+ space) (+ (not space)) | ||
| 127 | (+ space) (group (+ (not space))) | ||
| 128 | (+ space) (+ (not space)) | ||
| 129 | (+ space) (group (* nonl))) | ||
| 130 | nil t) | ||
| 131 | (push (match-string 1) result) | ||
| 132 | (put-text-property 0 1 'pcomplete-annotation | ||
| 133 | (concat " " (match-string 2)) | ||
| 134 | (car result)) | ||
| 135 | (put-text-property 0 1 'pcomplete-description | ||
| 136 | (match-string 3) | ||
| 137 | (car result))) | ||
| 138 | (nreverse result)))) | ||
| 139 | |||
| 140 | ;;;###autoload | ||
| 141 | (defun pcomplete/systemctl () | ||
| 142 | "Completion for the `systemctl' command." | ||
| 143 | (let ((subcmds (pcomplete-from-help | ||
| 144 | "systemctl --help" | ||
| 145 | :margin (rx bol " " (group) alpha) | ||
| 146 | :argument (rx (+ (any alpha ?-))) | ||
| 147 | :metavar (rx (group (+ " " (>= 2 (any upper "[]|.")))))))) | ||
| 148 | (while (not (member (pcomplete-arg 1) subcmds)) | ||
| 149 | (if (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 150 | (pcomplete-here (pcomplete-from-help "systemctl --help" | ||
| 151 | :metavar "[^ ]+" | ||
| 152 | :separator " \\(\\)-")) | ||
| 153 | (pcomplete-here subcmds))) | ||
| 154 | (let ((subcmd (pcomplete-arg 1)) | ||
| 155 | (context (if (member "--user" pcomplete-args) "--user" "--system"))) | ||
| 156 | (while (pcase subcmd | ||
| 157 | ((guard (string-prefix-p "-" (pcomplete-arg 0))) | ||
| 158 | (pcomplete-here | ||
| 159 | (pcomplete-from-help "systemctl --help"))) | ||
| 160 | ;; TODO: suggest only relevant units to each subcommand | ||
| 161 | ("start" | ||
| 162 | (pcomplete-here | ||
| 163 | (pcmpl-linux--systemd-units context "--state" "inactive,failed"))) | ||
| 164 | ((or "restart" "stop") | ||
| 165 | (pcomplete-here | ||
| 166 | (pcmpl-linux--systemd-units context "--state" "active"))) | ||
| 167 | (_ (pcomplete-here | ||
| 168 | (completion-table-in-turn | ||
| 169 | (pcmpl-linux--systemd-units context "--all") | ||
| 170 | (pcomplete-entries))))))))) | ||
| 171 | |||
| 172 | ;;;###autoload | ||
| 173 | (defun pcomplete/journalctl () | ||
| 174 | "Completion for the `journalctl' command." | ||
| 175 | (while (if (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 176 | (pcomplete-here (pcomplete-from-help "journalctl --help" | ||
| 177 | :metavar "[^ ]+" | ||
| 178 | :separator " \\(\\)-")) | ||
| 179 | (pcomplete-here (mapcar (lambda (s) (concat s "=")) | ||
| 180 | (process-lines "journalctl" "--fields")))))) | ||
| 181 | |||
| 114 | ;;; pcmpl-linux.el ends here | 182 | ;;; pcmpl-linux.el ends here |
diff --git a/lisp/pcmpl-rpm.el b/lisp/pcmpl-rpm.el index f7925d9d9ec..ebb6b72600c 100644 --- a/lisp/pcmpl-rpm.el +++ b/lisp/pcmpl-rpm.el | |||
| @@ -21,7 +21,8 @@ | |||
| 21 | 21 | ||
| 22 | ;;; Commentary: | 22 | ;;; Commentary: |
| 23 | 23 | ||
| 24 | ;; These functions provide completion rules for the `rpm' command. | 24 | ;; These functions provide completion rules for the `rpm' command and |
| 25 | ;; related tools. | ||
| 25 | 26 | ||
| 26 | ;;; Code: | 27 | ;;; Code: |
| 27 | 28 | ||
| @@ -378,6 +379,46 @@ | |||
| 378 | (t | 379 | (t |
| 379 | (error "You must select a mode: -q, -i, -U, --verify, etc")))))) | 380 | (error "You must select a mode: -q, -i, -U, --verify, etc")))))) |
| 380 | 381 | ||
| 382 | ;;; DNF | ||
| 383 | |||
| 384 | (defvar pcmpl-rpm-dnf-cache-file "/var/cache/dnf/packages.db" | ||
| 385 | "Location of the DNF cache.") | ||
| 386 | |||
| 387 | (defun pcmpl-rpm--dnf-packages (status) | ||
| 388 | (when (and (file-exists-p pcmpl-rpm-dnf-cache-file) | ||
| 389 | (executable-find "sqlite3")) | ||
| 390 | (with-temp-message | ||
| 391 | "Getting list of packages..." | ||
| 392 | (process-lines "sqlite3" "-batch" "-init" "/dev/null" | ||
| 393 | pcmpl-rpm-dnf-cache-file | ||
| 394 | (pcase-exhaustive status | ||
| 395 | ('available "select pkg from available") | ||
| 396 | ('installed "select pkg from installed") | ||
| 397 | ('not-installed "\ | ||
| 398 | select pkg from available where pkg not in (select pkg from installed)")))))) | ||
| 399 | |||
| 400 | ;;;###autoload | ||
| 401 | (defun pcomplete/dnf () | ||
| 402 | "Completion for the `dnf' command." | ||
| 403 | (let ((subcmds (pcomplete-from-help "dnf help" | ||
| 404 | :margin "^\\(\\)[a-z-]+ " | ||
| 405 | :argument "[a-z-]+"))) | ||
| 406 | (while (not (member (pcomplete-arg 1) subcmds)) | ||
| 407 | (pcomplete-here (completion-table-merge | ||
| 408 | subcmds | ||
| 409 | (pcomplete-from-help "dnf help")))) | ||
| 410 | (let ((subcmd (pcomplete-arg 1))) | ||
| 411 | (while (pcase subcmd | ||
| 412 | ((guard (pcomplete-match "\\`-" 0)) | ||
| 413 | (pcomplete-here | ||
| 414 | (pcomplete-from-help `("dnf" "help" ,subcmd)))) | ||
| 415 | ((or "downgrade" "reinstall" "remove") | ||
| 416 | (pcomplete-here (pcmpl-rpm--dnf-packages 'installed))) | ||
| 417 | ((or "install" "mark" "reinstall" "upgrade") | ||
| 418 | (pcomplete-here (pcmpl-rpm--dnf-packages 'not-installed))) | ||
| 419 | ((or "builddep" "changelog" "info" "list" "repoquery" "updateinfo") | ||
| 420 | (pcomplete-here (pcmpl-rpm--dnf-packages 'available)))))))) | ||
| 421 | |||
| 381 | (provide 'pcmpl-rpm) | 422 | (provide 'pcmpl-rpm) |
| 382 | 423 | ||
| 383 | ;;; pcmpl-rpm.el ends here | 424 | ;;; pcmpl-rpm.el ends here |
diff --git a/lisp/pcmpl-unix.el b/lisp/pcmpl-unix.el index 8774f091c83..0c32f814d0e 100644 --- a/lisp/pcmpl-unix.el +++ b/lisp/pcmpl-unix.el | |||
| @@ -25,7 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | (require 'pcomplete) | 26 | (require 'pcomplete) |
| 27 | 27 | ||
| 28 | ;; User Variables: | 28 | ;;; User Variables |
| 29 | 29 | ||
| 30 | (defcustom pcmpl-unix-group-file "/etc/group" | 30 | (defcustom pcmpl-unix-group-file "/etc/group" |
| 31 | "If non-nil, a string naming the group file on your system." | 31 | "If non-nil, a string naming the group file on your system." |
| @@ -56,7 +56,7 @@ being via `pcmpl-ssh-known-hosts-file'." | |||
| 56 | :group 'pcmpl-unix | 56 | :group 'pcmpl-unix |
| 57 | :version "24.1") | 57 | :version "24.1") |
| 58 | 58 | ||
| 59 | ;; Functions: | 59 | ;;; Shell builtins and core utilities |
| 60 | 60 | ||
| 61 | ;;;###autoload | 61 | ;;;###autoload |
| 62 | (defun pcomplete/cd () | 62 | (defun pcomplete/cd () |
| @@ -69,34 +69,38 @@ being via `pcmpl-ssh-known-hosts-file'." | |||
| 69 | ;;;###autoload | 69 | ;;;###autoload |
| 70 | (defun pcomplete/rmdir () | 70 | (defun pcomplete/rmdir () |
| 71 | "Completion for `rmdir'." | 71 | "Completion for `rmdir'." |
| 72 | (while (pcomplete-here (pcomplete-dirs)))) | 72 | (while (if (string-prefix-p "-" (pcomplete-arg)) |
| 73 | (pcomplete-here (pcomplete-from-help "rmdir --help")) | ||
| 74 | (pcomplete-here (pcomplete-dirs))))) | ||
| 73 | 75 | ||
| 74 | ;;;###autoload | 76 | ;;;###autoload |
| 75 | (defun pcomplete/rm () | 77 | (defun pcomplete/rm () |
| 76 | "Completion for `rm'." | 78 | "Completion for the `rm' command." |
| 77 | (let ((pcomplete-help "(fileutils)rm invocation")) | 79 | (pcomplete-here-using-help "rm --help")) |
| 78 | (pcomplete-opt "dfirRv") | ||
| 79 | (while (pcomplete-here (pcomplete-all-entries) nil | ||
| 80 | #'expand-file-name)))) | ||
| 81 | 80 | ||
| 82 | ;;;###autoload | 81 | ;;;###autoload |
| 83 | (defun pcomplete/xargs () | 82 | (defun pcomplete/xargs () |
| 84 | "Completion for `xargs'." | 83 | "Completion for `xargs'." |
| 85 | (while (string-prefix-p "-" (pcomplete-arg 0)) | 84 | (while (string-prefix-p "-" (pcomplete-arg 0)) |
| 86 | (pcomplete-here (funcall pcomplete-default-completion-function))) | 85 | (pcomplete-here (pcomplete-from-help "xargs --help")) |
| 86 | (when (pcomplete-match "\\`-[adEIiLnPs]\\'") (pcomplete-here))) | ||
| 87 | (funcall pcomplete-command-completion-function) | 87 | (funcall pcomplete-command-completion-function) |
| 88 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | 88 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) |
| 89 | pcomplete-default-completion-function))) | 89 | pcomplete-default-completion-function))) |
| 90 | 90 | ||
| 91 | ;; FIXME: Add completion of sudo-specific arguments. | ||
| 92 | (defalias 'pcomplete/sudo #'pcomplete/xargs) | ||
| 93 | |||
| 94 | ;;;###autoload | 91 | ;;;###autoload |
| 95 | (defalias 'pcomplete/time 'pcomplete/xargs) | 92 | (defun pcomplete/time () |
| 93 | "Completion for the `time' command." | ||
| 94 | (pcomplete-opt "p") | ||
| 95 | (funcall pcomplete-command-completion-function) | ||
| 96 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 97 | pcomplete-default-completion-function))) | ||
| 96 | 98 | ||
| 97 | ;;;###autoload | 99 | ;;;###autoload |
| 98 | (defun pcomplete/which () | 100 | (defun pcomplete/which () |
| 99 | "Completion for `which'." | 101 | "Completion for `which'." |
| 102 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 103 | (pcomplete-here (pcomplete-from-help "which --help"))) | ||
| 100 | (while (pcomplete-here (funcall pcomplete-command-completion-function)))) | 104 | (while (pcomplete-here (funcall pcomplete-command-completion-function)))) |
| 101 | 105 | ||
| 102 | (defun pcmpl-unix-read-passwd-file (file) | 106 | (defun pcmpl-unix-read-passwd-file (file) |
| @@ -129,24 +133,454 @@ documentation), this function returns nil." | |||
| 129 | (pcmpl-unix-read-passwd-file pcmpl-unix-passwd-file))) | 133 | (pcmpl-unix-read-passwd-file pcmpl-unix-passwd-file))) |
| 130 | 134 | ||
| 131 | ;;;###autoload | 135 | ;;;###autoload |
| 136 | (defun pcomplete/cat () | ||
| 137 | "Completion for the `cat' command." | ||
| 138 | (pcomplete-here-using-help "cat --help")) | ||
| 139 | |||
| 140 | ;;;###autoload | ||
| 141 | (defun pcomplete/tac () | ||
| 142 | "Completion for the `tac' command." | ||
| 143 | (pcomplete-here-using-help "tac --help")) | ||
| 144 | |||
| 145 | ;;;###autoload | ||
| 146 | (defun pcomplete/nl () | ||
| 147 | "Completion for the `nl' command." | ||
| 148 | (pcomplete-here-using-help "nl --help")) | ||
| 149 | |||
| 150 | ;;;###autoload | ||
| 151 | (defun pcomplete/od () | ||
| 152 | "Completion for the `od' command." | ||
| 153 | (pcomplete-here-using-help "od --help")) | ||
| 154 | |||
| 155 | ;;;###autoload | ||
| 156 | (defun pcomplete/base32 () | ||
| 157 | "Completion for the `base32' and `base64' commands." | ||
| 158 | (pcomplete-here-using-help "base32 --help")) | ||
| 159 | ;;;###autoload | ||
| 160 | (defalias 'pcomplete/base64 'pcomplete/base32) | ||
| 161 | |||
| 162 | ;;;###autoload | ||
| 163 | (defun pcomplete/basenc () | ||
| 164 | "Completion for the `basenc' command." | ||
| 165 | (pcomplete-here-using-help "basenc --help")) | ||
| 166 | |||
| 167 | ;;;###autoload | ||
| 168 | (defun pcomplete/fmt () | ||
| 169 | "Completion for the `fmt' command." | ||
| 170 | (pcomplete-here-using-help "fmt --help")) | ||
| 171 | |||
| 172 | ;;;###autoload | ||
| 173 | (defun pcomplete/pr () | ||
| 174 | "Completion for the `pr' command." | ||
| 175 | (pcomplete-here-using-help "pr --help")) | ||
| 176 | |||
| 177 | ;;;###autoload | ||
| 178 | (defun pcomplete/fold () | ||
| 179 | "Completion for the `fold' command." | ||
| 180 | (pcomplete-here-using-help "fold --help")) | ||
| 181 | |||
| 182 | ;;;###autoload | ||
| 183 | (defun pcomplete/head () | ||
| 184 | "Completion for the `head' command." | ||
| 185 | (pcomplete-here-using-help "head --help")) | ||
| 186 | |||
| 187 | ;;;###autoload | ||
| 188 | (defun pcomplete/tail () | ||
| 189 | "Completion for the `tail' command." | ||
| 190 | (pcomplete-here-using-help "tail --help")) | ||
| 191 | |||
| 192 | ;;;###autoload | ||
| 193 | (defun pcomplete/split () | ||
| 194 | "Completion for the `split' command." | ||
| 195 | (pcomplete-here-using-help "split --help")) | ||
| 196 | |||
| 197 | ;;;###autoload | ||
| 198 | (defun pcomplete/csplit () | ||
| 199 | "Completion for the `csplit' command." | ||
| 200 | (pcomplete-here-using-help "csplit --help")) | ||
| 201 | |||
| 202 | ;;;###autoload | ||
| 203 | (defun pcomplete/wc () | ||
| 204 | "Completion for the `wc' command." | ||
| 205 | (pcomplete-here-using-help "wc --help")) | ||
| 206 | |||
| 207 | ;;;###autoload | ||
| 208 | (defun pcomplete/sum () | ||
| 209 | "Completion for the `sum' command." | ||
| 210 | (pcomplete-here-using-help "sum --help")) | ||
| 211 | |||
| 212 | ;;;###autoload | ||
| 213 | (defun pcomplete/cksum () | ||
| 214 | "Completion for the `cksum' command." | ||
| 215 | (pcomplete-here-using-help "cksum --help")) | ||
| 216 | |||
| 217 | ;;;###autoload | ||
| 218 | (defun pcomplete/b2sum () | ||
| 219 | "Completion for the `b2sum' command." | ||
| 220 | (pcomplete-here-using-help "b2sum --help")) | ||
| 221 | |||
| 222 | ;;;###autoload | ||
| 223 | (defun pcomplete/md5sum () | ||
| 224 | "Completion for checksum commands." | ||
| 225 | (pcomplete-here-using-help "md5sum --help")) | ||
| 226 | ;;;###autoload(defalias 'pcomplete/sha1sum 'pcomplete/md5sum) | ||
| 227 | ;;;###autoload(defalias 'pcomplete/sha224sum 'pcomplete/md5sum) | ||
| 228 | ;;;###autoload(defalias 'pcomplete/sha256sum 'pcomplete/md5sum) | ||
| 229 | ;;;###autoload(defalias 'pcomplete/sha384sum 'pcomplete/md5sum) | ||
| 230 | ;;;###autoload(defalias 'pcomplete/sha521sum 'pcomplete/md5sum) | ||
| 231 | |||
| 232 | ;;;###autoload | ||
| 233 | (defun pcomplete/sort () | ||
| 234 | "Completion for the `sort' command." | ||
| 235 | (pcomplete-here-using-help "sort --help")) | ||
| 236 | |||
| 237 | ;;;###autoload | ||
| 238 | (defun pcomplete/shuf () | ||
| 239 | "Completion for the `shuf' command." | ||
| 240 | (pcomplete-here-using-help "shuf --help")) | ||
| 241 | |||
| 242 | ;;;###autoload | ||
| 243 | (defun pcomplete/uniq () | ||
| 244 | "Completion for the `uniq' command." | ||
| 245 | (pcomplete-here-using-help "uniq --help")) | ||
| 246 | |||
| 247 | ;;;###autoload | ||
| 248 | (defun pcomplete/comm () | ||
| 249 | "Completion for the `comm' command." | ||
| 250 | (pcomplete-here-using-help "comm --help")) | ||
| 251 | |||
| 252 | ;;;###autoload | ||
| 253 | (defun pcomplete/ptx () | ||
| 254 | "Completion for the `ptx' command." | ||
| 255 | (pcomplete-here-using-help "ptx --help")) | ||
| 256 | |||
| 257 | ;;;###autoload | ||
| 258 | (defun pcomplete/tsort () | ||
| 259 | "Completion for the `tsort' command." | ||
| 260 | (pcomplete-here-using-help "tsort --help")) | ||
| 261 | |||
| 262 | ;;;###autoload | ||
| 263 | (defun pcomplete/cut () | ||
| 264 | "Completion for the `cut' command." | ||
| 265 | (pcomplete-here-using-help "cut --help")) | ||
| 266 | |||
| 267 | ;;;###autoload | ||
| 268 | (defun pcomplete/paste () | ||
| 269 | "Completion for the `paste' command." | ||
| 270 | (pcomplete-here-using-help "paste --help")) | ||
| 271 | |||
| 272 | ;;;###autoload | ||
| 273 | (defun pcomplete/join () | ||
| 274 | "Completion for the `join' command." | ||
| 275 | (pcomplete-here-using-help "join --help")) | ||
| 276 | |||
| 277 | ;;;###autoload | ||
| 278 | (defun pcomplete/tr () | ||
| 279 | "Completion for the `tr' command." | ||
| 280 | (pcomplete-here-using-help "tr --help")) | ||
| 281 | |||
| 282 | ;;;###autoload | ||
| 283 | (defun pcomplete/expand () | ||
| 284 | "Completion for the `expand' command." | ||
| 285 | (pcomplete-here-using-help "expand --help")) | ||
| 286 | |||
| 287 | ;;;###autoload | ||
| 288 | (defun pcomplete/unexpand () | ||
| 289 | "Completion for the `unexpand' command." | ||
| 290 | (pcomplete-here-using-help "unexpand --help")) | ||
| 291 | |||
| 292 | ;;;###autoload | ||
| 293 | (defun pcomplete/ls () | ||
| 294 | "Completion for the `ls' command." | ||
| 295 | (pcomplete-here-using-help "ls --help")) | ||
| 296 | ;;;###autoload(defalias 'pcomplete/dir 'pcomplete/ls) | ||
| 297 | ;;;###autoload(defalias 'pcomplete/vdir 'pcomplete/ls) | ||
| 298 | |||
| 299 | ;;;###autoload | ||
| 300 | (defun pcomplete/cp () | ||
| 301 | "Completion for the `cp' command." | ||
| 302 | (pcomplete-here-using-help "cp --help")) | ||
| 303 | |||
| 304 | ;;;###autoload | ||
| 305 | (defun pcomplete/dd () | ||
| 306 | "Completion for the `dd' command." | ||
| 307 | (let ((operands (pcomplete-from-help "dd --help" | ||
| 308 | :argument "[a-z]+=" | ||
| 309 | :narrow-start "\n\n" | ||
| 310 | :narrow-end "\n\n"))) | ||
| 311 | (while | ||
| 312 | (cond ((pcomplete-match "\\`[io]f=\\(.*\\)" 0) | ||
| 313 | (pcomplete-here (pcomplete-entries) | ||
| 314 | (pcomplete-match-string 1 0))) | ||
| 315 | (t (pcomplete-here operands)))))) | ||
| 316 | |||
| 317 | ;;;###autoload | ||
| 318 | (defun pcomplete/install () | ||
| 319 | "Completion for the `install' command." | ||
| 320 | (pcomplete-here-using-help "install --help")) | ||
| 321 | |||
| 322 | ;;;###autoload | ||
| 323 | (defun pcomplete/mv () | ||
| 324 | "Completion for the `mv' command." | ||
| 325 | (pcomplete-here-using-help "mv --help")) | ||
| 326 | |||
| 327 | ;;;###autoload | ||
| 328 | (defun pcomplete/shred () | ||
| 329 | "Completion for the `shred' command." | ||
| 330 | (pcomplete-here-using-help "shred --help")) | ||
| 331 | |||
| 332 | ;;;###autoload | ||
| 333 | (defun pcomplete/ln () | ||
| 334 | "Completion for the `ln' command." | ||
| 335 | (pcomplete-here-using-help "ln --help")) | ||
| 336 | |||
| 337 | ;;;###autoload | ||
| 338 | (defun pcomplete/mkdir () | ||
| 339 | "Completion for the `mkdir' command." | ||
| 340 | (pcomplete-here-using-help "mkdir --help")) | ||
| 341 | |||
| 342 | ;;;###autoload | ||
| 343 | (defun pcomplete/mkfifo () | ||
| 344 | "Completion for the `mkfifo' command." | ||
| 345 | (pcomplete-here-using-help "mkfifo --help")) | ||
| 346 | |||
| 347 | ;;;###autoload | ||
| 348 | (defun pcomplete/mknod () | ||
| 349 | "Completion for the `mknod' command." | ||
| 350 | (pcomplete-here-using-help "mknod --help")) | ||
| 351 | |||
| 352 | ;;;###autoload | ||
| 353 | (defun pcomplete/readlink () | ||
| 354 | "Completion for the `readlink' command." | ||
| 355 | (pcomplete-here-using-help "readlink --help")) | ||
| 356 | |||
| 357 | ;;;###autoload | ||
| 132 | (defun pcomplete/chown () | 358 | (defun pcomplete/chown () |
| 133 | "Completion for the `chown' command." | 359 | "Completion for the `chown' command." |
| 134 | (unless (pcomplete-match "\\`-") | 360 | (while (pcomplete-match "\\`-" 0) |
| 135 | (if (pcomplete-match "\\`[^.]*\\'" 0) | 361 | (pcomplete-here (pcomplete-from-help "chown --help"))) |
| 136 | (pcomplete-here* (pcmpl-unix-user-names)) | 362 | (if (pcomplete-match "\\`[^.]*\\'" 0) |
| 137 | (if (pcomplete-match "\\.\\([^.]*\\)\\'" 0) | 363 | (pcomplete-here* (pcmpl-unix-user-names)) |
| 138 | (pcomplete-here* (pcmpl-unix-group-names) | 364 | (if (pcomplete-match "\\.\\([^.]*\\)\\'" 0) |
| 139 | (pcomplete-match-string 1 0)) | 365 | (pcomplete-here* (pcmpl-unix-group-names) |
| 140 | (pcomplete-here*)))) | 366 | (pcomplete-match-string 1 0)) |
| 367 | (pcomplete-here*))) | ||
| 141 | (while (pcomplete-here (pcomplete-entries)))) | 368 | (while (pcomplete-here (pcomplete-entries)))) |
| 142 | 369 | ||
| 143 | ;;;###autoload | 370 | ;;;###autoload |
| 144 | (defun pcomplete/chgrp () | 371 | (defun pcomplete/chgrp () |
| 145 | "Completion for the `chgrp' command." | 372 | "Completion for the `chgrp' command." |
| 146 | (unless (pcomplete-match "\\`-") | 373 | (while (pcomplete-match "\\`-" 0) |
| 147 | (pcomplete-here* (pcmpl-unix-group-names))) | 374 | (pcomplete-here (pcomplete-from-help "chgrp --help"))) |
| 375 | (pcomplete-here* (pcmpl-unix-group-names)) | ||
| 148 | (while (pcomplete-here (pcomplete-entries)))) | 376 | (while (pcomplete-here (pcomplete-entries)))) |
| 149 | 377 | ||
| 378 | ;;;###autoload | ||
| 379 | (defun pcomplete/chmod () | ||
| 380 | "Completion for the `chmod' command." | ||
| 381 | (pcomplete-here-using-help "chmod --help")) | ||
| 382 | |||
| 383 | ;;;###autoload | ||
| 384 | (defun pcomplete/touch () | ||
| 385 | "Completion for the `touch' command." | ||
| 386 | (pcomplete-here-using-help "touch --help")) | ||
| 387 | |||
| 388 | ;;;###autoload | ||
| 389 | (defun pcomplete/df () | ||
| 390 | "Completion for the `df' command." | ||
| 391 | (pcomplete-here-using-help "df --help")) | ||
| 392 | |||
| 393 | ;;;###autoload | ||
| 394 | (defun pcomplete/du () | ||
| 395 | "Completion for the `du' command." | ||
| 396 | (pcomplete-here-using-help "du --help")) | ||
| 397 | |||
| 398 | ;;;###autoload | ||
| 399 | (defun pcomplete/stat () | ||
| 400 | "Completion for the `stat' command." | ||
| 401 | (pcomplete-here-using-help "stat --help")) | ||
| 402 | |||
| 403 | ;;;###autoload | ||
| 404 | (defun pcomplete/sync () | ||
| 405 | "Completion for the `sync' command." | ||
| 406 | (pcomplete-here-using-help "sync --help")) | ||
| 407 | |||
| 408 | ;;;###autoload | ||
| 409 | (defun pcomplete/truncate () | ||
| 410 | "Completion for the `truncate' command." | ||
| 411 | (pcomplete-here-using-help "truncate --help")) | ||
| 412 | |||
| 413 | ;;;###autoload | ||
| 414 | (defun pcomplete/echo () | ||
| 415 | "Completion for the `echo' command." | ||
| 416 | (pcomplete-here-using-help '("echo" "--help"))) | ||
| 417 | |||
| 418 | ;;;###autoload | ||
| 419 | (defun pcomplete/test () | ||
| 420 | "Completion for the `test' command." | ||
| 421 | (pcomplete-here-using-help '("[" "--help") | ||
| 422 | :margin "^ +\\([A-Z]+1 \\)?")) | ||
| 423 | ;;;###autoload(defalias (intern "pcomplete/[") 'pcomplete/test) | ||
| 424 | |||
| 425 | ;;;###autoload | ||
| 426 | (defun pcomplete/tee () | ||
| 427 | "Completion for the `tee' command." | ||
| 428 | (pcomplete-here-using-help "tee --help")) | ||
| 429 | |||
| 430 | ;;;###autoload | ||
| 431 | (defun pcomplete/basename () | ||
| 432 | "Completion for the `basename' command." | ||
| 433 | (pcomplete-here-using-help "basename --help")) | ||
| 434 | |||
| 435 | ;;;###autoload | ||
| 436 | (defun pcomplete/dirname () | ||
| 437 | "Completion for the `dirname' command." | ||
| 438 | (pcomplete-here-using-help "dirname --help")) | ||
| 439 | |||
| 440 | ;;;###autoload | ||
| 441 | (defun pcomplete/pathchk () | ||
| 442 | "Completion for the `pathchk' command." | ||
| 443 | (pcomplete-here-using-help "pathchk --help")) | ||
| 444 | |||
| 445 | ;;;###autoload | ||
| 446 | (defun pcomplete/mktemp () | ||
| 447 | "Completion for the `mktemp' command." | ||
| 448 | (pcomplete-here-using-help "mktemp --help")) | ||
| 449 | |||
| 450 | ;;;###autoload | ||
| 451 | (defun pcomplete/realpath () | ||
| 452 | "Completion for the `realpath' command." | ||
| 453 | (pcomplete-here-using-help "realpath --help")) | ||
| 454 | |||
| 455 | ;;;###autoload | ||
| 456 | (defun pcomplete/id () | ||
| 457 | "Completion for the `id' command." | ||
| 458 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 459 | (pcomplete-here (pcomplete-from-help "id --help"))) | ||
| 460 | (while (pcomplete-here (pcmpl-unix-user-names)))) | ||
| 461 | |||
| 462 | ;;;###autoload | ||
| 463 | (defun pcomplete/groups () | ||
| 464 | "Completion for the `groups' command." | ||
| 465 | (while (pcomplete-here (pcmpl-unix-user-names)))) | ||
| 466 | |||
| 467 | ;;;###autoload | ||
| 468 | (defun pcomplete/who () | ||
| 469 | "Completion for the `who' command." | ||
| 470 | (pcomplete-here-using-help "who --help")) | ||
| 471 | |||
| 472 | ;;;###autoload | ||
| 473 | (defun pcomplete/date () | ||
| 474 | "Completion for the `date' command." | ||
| 475 | (pcomplete-here-using-help "date --help")) | ||
| 476 | |||
| 477 | ;;;###autoload | ||
| 478 | (defun pcomplete/nproc () | ||
| 479 | "Completion for the `nproc' command." | ||
| 480 | (pcomplete-here-using-help "nproc --help")) | ||
| 481 | |||
| 482 | ;;;###autoload | ||
| 483 | (defun pcomplete/uname () | ||
| 484 | "Completion for the `uname' command." | ||
| 485 | (pcomplete-here-using-help "uname --help")) | ||
| 486 | |||
| 487 | ;;;###autoload | ||
| 488 | (defun pcomplete/hostname () | ||
| 489 | "Completion for the `hostname' command." | ||
| 490 | (pcomplete-here-using-help "hostname --help")) | ||
| 491 | |||
| 492 | ;;;###autoload | ||
| 493 | (defun pcomplete/uptime () | ||
| 494 | "Completion for the `uptime' command." | ||
| 495 | (pcomplete-here-using-help "uptime --help")) | ||
| 496 | |||
| 497 | ;;;###autoload | ||
| 498 | (defun pcomplete/chcon () | ||
| 499 | "Completion for the `chcon' command." | ||
| 500 | (pcomplete-here-using-help "chcon --help")) | ||
| 501 | |||
| 502 | ;;;###autoload | ||
| 503 | (defun pcomplete/runcon () | ||
| 504 | "Completion for the `runcon' command." | ||
| 505 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 506 | (pcomplete-here (pcomplete-from-help "runcon --help")) | ||
| 507 | (when (pcomplete-match "\\`-[turl]\\'" 0) (pcomplete-here))) | ||
| 508 | (funcall pcomplete-command-completion-function) | ||
| 509 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 510 | pcomplete-default-completion-function))) | ||
| 511 | |||
| 512 | ;;;###autoload | ||
| 513 | (defun pcomplete/chroot () | ||
| 514 | "Completion for the `chroot' command." | ||
| 515 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 516 | (pcomplete-here (pcomplete-from-help "chroot --help"))) | ||
| 517 | (pcomplete-here (pcomplete-dirs)) | ||
| 518 | (funcall pcomplete-command-completion-function) | ||
| 519 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 520 | pcomplete-default-completion-function))) | ||
| 521 | |||
| 522 | ;;;###autoload | ||
| 523 | (defun pcomplete/env () | ||
| 524 | "Completion for the `env' command." | ||
| 525 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 526 | (pcomplete-here (pcomplete-from-help "env --help")) | ||
| 527 | (when (pcomplete-match "\\`-[uCS]\\'") (pcomplete-here))) | ||
| 528 | (while (pcomplete-match "=" 0) (pcomplete-here)) ; FIXME: Complete env vars | ||
| 529 | (funcall pcomplete-command-completion-function) | ||
| 530 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 531 | pcomplete-default-completion-function))) | ||
| 532 | |||
| 533 | ;;;###autoload | ||
| 534 | (defun pcomplete/nice () | ||
| 535 | "Completion for the `nice' command." | ||
| 536 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 537 | (pcomplete-here (pcomplete-from-help "nice --help")) | ||
| 538 | (pcomplete-here)) | ||
| 539 | (funcall pcomplete-command-completion-function) | ||
| 540 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 541 | pcomplete-default-completion-function))) | ||
| 542 | |||
| 543 | ;;;###autoload | ||
| 544 | (defun pcomplete/nohup () | ||
| 545 | "Completion for the `nohup' command." | ||
| 546 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 547 | (pcomplete-here (pcomplete-from-help "nohup --help"))) | ||
| 548 | (funcall pcomplete-command-completion-function) | ||
| 549 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 550 | pcomplete-default-completion-function))) | ||
| 551 | |||
| 552 | ;;;###autoload | ||
| 553 | (defun pcomplete/stdbuf () | ||
| 554 | "Completion for the `stdbuf' command." | ||
| 555 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 556 | (pcomplete-here (pcomplete-from-help "stdbuf --help")) | ||
| 557 | (when (pcomplete-match "\\`-[ioe]\\'") (pcomplete-here))) | ||
| 558 | (funcall pcomplete-command-completion-function) | ||
| 559 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 560 | pcomplete-default-completion-function))) | ||
| 561 | |||
| 562 | ;;;###autoload | ||
| 563 | (defun pcomplete/timeout () | ||
| 564 | "Completion for the `timeout' command." | ||
| 565 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 566 | (pcomplete-here (pcomplete-from-help "timeout --help")) | ||
| 567 | (when (pcomplete-match "\\`-[ks]\\'") (pcomplete-here))) | ||
| 568 | (pcomplete-here) ; eat DURATION argument | ||
| 569 | (funcall pcomplete-command-completion-function) | ||
| 570 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 571 | pcomplete-default-completion-function))) | ||
| 572 | |||
| 573 | ;;;###autoload | ||
| 574 | (defun pcomplete/numfmt () | ||
| 575 | "Completion for the `numfmt' command." | ||
| 576 | (pcomplete-here-using-help "numfmt --help")) | ||
| 577 | |||
| 578 | ;;;###autoload | ||
| 579 | (defun pcomplete/seq () | ||
| 580 | "Completion for the `seq' command." | ||
| 581 | (pcomplete-here-using-help "seq --help")) | ||
| 582 | |||
| 583 | ;;; Network commands | ||
| 150 | 584 | ||
| 151 | ;; ssh support by Phil Hagelberg. | 585 | ;; ssh support by Phil Hagelberg. |
| 152 | ;; https://www.emacswiki.org/cgi-bin/wiki/pcmpl-ssh.el | 586 | ;; https://www.emacswiki.org/cgi-bin/wiki/pcmpl-ssh.el |
| @@ -239,6 +673,18 @@ Includes files as well as host names followed by a colon." | |||
| 239 | (pcomplete-opt "xl(pcmpl-unix-user-names)") | 673 | (pcomplete-opt "xl(pcmpl-unix-user-names)") |
| 240 | (pcmpl-unix-complete-hostname)) | 674 | (pcmpl-unix-complete-hostname)) |
| 241 | 675 | ||
| 676 | ;;; Miscellaneous | ||
| 677 | |||
| 678 | ;;;###autoload | ||
| 679 | (defun pcomplete/sudo () | ||
| 680 | "Completion for the `sudo' command." | ||
| 681 | (while (string-prefix-p "-" (pcomplete-arg 0)) | ||
| 682 | (pcomplete-here (pcomplete-from-help "sudo --help")) | ||
| 683 | (when (pcomplete-match "\\`-[CDghpRtTUu]\\'") (pcomplete-here))) | ||
| 684 | (funcall pcomplete-command-completion-function) | ||
| 685 | (funcall (or (pcomplete-find-completion-function (pcomplete-arg 1)) | ||
| 686 | pcomplete-default-completion-function))) | ||
| 687 | |||
| 242 | (provide 'pcmpl-unix) | 688 | (provide 'pcmpl-unix) |
| 243 | 689 | ||
| 244 | ;;; pcmpl-unix.el ends here | 690 | ;;; pcmpl-unix.el ends here |
diff --git a/lisp/pcmpl-x.el b/lisp/pcmpl-x.el index 261a3d4e27b..1ede867c5fb 100644 --- a/lisp/pcmpl-x.el +++ b/lisp/pcmpl-x.el | |||
| @@ -28,6 +28,22 @@ | |||
| 28 | (eval-when-compile (require 'cl-lib)) | 28 | (eval-when-compile (require 'cl-lib)) |
| 29 | (require 'pcomplete) | 29 | (require 'pcomplete) |
| 30 | 30 | ||
| 31 | ;;; TeX | ||
| 32 | |||
| 33 | ;;;###autoload | ||
| 34 | (defun pcomplete/tex () | ||
| 35 | "Completion for the `tex' command." | ||
| 36 | (pcomplete-here-using-help "tex --help" | ||
| 37 | :margin "^\\(?:\\[-no\\]\\)?\\(\\)-")) | ||
| 38 | ;;;###autoload(defalias 'pcomplete/pdftex 'pcomplete/tex) | ||
| 39 | ;;;###autoload(defalias 'pcomplete/latex 'pcomplete/tex) | ||
| 40 | ;;;###autoload(defalias 'pcomplete/pdflatex 'pcomplete/tex) | ||
| 41 | |||
| 42 | ;;;###autoload | ||
| 43 | (defun pcomplete/luatex () | ||
| 44 | "Completion for the `luatex' command." | ||
| 45 | (pcomplete-here-using-help "luatex --help")) | ||
| 46 | ;;;###autoload(defalias 'pcomplete/lualatex 'pcomplete/luatex) | ||
| 31 | 47 | ||
| 32 | ;;;; tlmgr - https://www.tug.org/texlive/tlmgr.html | 48 | ;;;; tlmgr - https://www.tug.org/texlive/tlmgr.html |
| 33 | 49 | ||
| @@ -142,6 +158,12 @@ | |||
| 142 | (unless (pcomplete-match "^--" 0) | 158 | (unless (pcomplete-match "^--" 0) |
| 143 | (pcomplete-here* (pcomplete-dirs-or-entries))))))) | 159 | (pcomplete-here* (pcomplete-dirs-or-entries))))))) |
| 144 | 160 | ||
| 161 | ;;; Grep-like tools | ||
| 162 | |||
| 163 | ;;;###autoload | ||
| 164 | (defun pcomplete/rg () | ||
| 165 | "Completion for the `rg' command." | ||
| 166 | (pcomplete-here-using-help "rg --help")) | ||
| 145 | 167 | ||
| 146 | ;;;; ack - https://betterthangrep.com | 168 | ;;;; ack - https://betterthangrep.com |
| 147 | 169 | ||
| @@ -288,6 +310,8 @@ long options." | |||
| 288 | (pcmpl-x-ag-options)))) | 310 | (pcmpl-x-ag-options)))) |
| 289 | (pcomplete-here* (pcomplete-dirs-or-entries))))) | 311 | (pcomplete-here* (pcomplete-dirs-or-entries))))) |
| 290 | 312 | ||
| 313 | ;;; Borland | ||
| 314 | |||
| 291 | ;;;###autoload | 315 | ;;;###autoload |
| 292 | (defun pcomplete/bcc32 () | 316 | (defun pcomplete/bcc32 () |
| 293 | "Completion function for Borland's C++ compiler." | 317 | "Completion function for Borland's C++ compiler." |
| @@ -321,5 +345,24 @@ long options." | |||
| 321 | ;;;###autoload | 345 | ;;;###autoload |
| 322 | (defalias 'pcomplete/bcc 'pcomplete/bcc32) | 346 | (defalias 'pcomplete/bcc 'pcomplete/bcc32) |
| 323 | 347 | ||
| 348 | ;;; Network tools | ||
| 349 | |||
| 350 | ;;;###autoload | ||
| 351 | (defun pcomplete/rclone () | ||
| 352 | "Completion for the `rclone' command." | ||
| 353 | (let ((subcmds (pcomplete-from-help "rclone help" | ||
| 354 | :margin "^ " | ||
| 355 | :argument "[a-z]+" | ||
| 356 | :narrow-start "\n\n"))) | ||
| 357 | (while (not (member (pcomplete-arg 1) subcmds)) | ||
| 358 | (pcomplete-here (completion-table-merge | ||
| 359 | subcmds | ||
| 360 | (pcomplete-from-help "rclone help flags")))) | ||
| 361 | (let ((subcmd (pcomplete-arg 1))) | ||
| 362 | (while (if (pcomplete-match "\\`-" 0) | ||
| 363 | (pcomplete-here (pcomplete-from-help | ||
| 364 | `("rclone" ,subcmd "--help"))) | ||
| 365 | (pcomplete-here (pcomplete-entries))))))) | ||
| 366 | |||
| 324 | (provide 'pcmpl-x) | 367 | (provide 'pcmpl-x) |
| 325 | ;;; pcmpl-x.el ends here | 368 | ;;; pcmpl-x.el ends here |
diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el index 0e3d1df7814..6fe29d9dcfb 100644 --- a/lisp/pcomplete.el +++ b/lisp/pcomplete.el | |||
| @@ -119,6 +119,9 @@ | |||
| 119 | ;;; Code: | 119 | ;;; Code: |
| 120 | 120 | ||
| 121 | (require 'comint) | 121 | (require 'comint) |
| 122 | (eval-when-compile | ||
| 123 | (require 'cl-lib) | ||
| 124 | (require 'rx)) | ||
| 122 | 125 | ||
| 123 | (defgroup pcomplete nil | 126 | (defgroup pcomplete nil |
| 124 | "Programmable completion." | 127 | "Programmable completion." |
| @@ -481,6 +484,14 @@ Same as `pcomplete' but using the standard completion UI." | |||
| 481 | (when completion-ignore-case | 484 | (when completion-ignore-case |
| 482 | (setq table (completion-table-case-fold table))) | 485 | (setq table (completion-table-case-fold table))) |
| 483 | (list beg (point) table | 486 | (list beg (point) table |
| 487 | :annotation-function | ||
| 488 | (lambda (cand) | ||
| 489 | (when (stringp cand) | ||
| 490 | (get-text-property 0 'pcomplete-annotation cand))) | ||
| 491 | :company-docsig | ||
| 492 | (lambda (cand) | ||
| 493 | (when (stringp cand) | ||
| 494 | (get-text-property 0 'pcomplete-help cand))) | ||
| 484 | :predicate pred | 495 | :predicate pred |
| 485 | :exit-function | 496 | :exit-function |
| 486 | ;; If completion is finished, add a terminating space. | 497 | ;; If completion is finished, add a terminating space. |
| @@ -1325,6 +1336,133 @@ If specific documentation can't be given, be generic." | |||
| 1325 | (pcomplete-read-hosts pcomplete-hosts-file 'pcomplete--host-name-cache | 1336 | (pcomplete-read-hosts pcomplete-hosts-file 'pcomplete--host-name-cache |
| 1326 | 'pcomplete--host-name-cache-timestamp))) | 1337 | 'pcomplete--host-name-cache-timestamp))) |
| 1327 | 1338 | ||
| 1339 | ;;; Parsing help messages | ||
| 1340 | |||
| 1341 | (defvar pcomplete-from-help (make-hash-table :test #'equal) | ||
| 1342 | "Memoization table for function `pcomplete-from-help'.") | ||
| 1343 | |||
| 1344 | (cl-defun pcomplete-from-help (command | ||
| 1345 | &rest args | ||
| 1346 | &key | ||
| 1347 | (margin (rx bol (+ " "))) | ||
| 1348 | (argument (rx "-" (+ (any "-" alnum)) (? "="))) | ||
| 1349 | (metavar (rx (? " ") | ||
| 1350 | (or (+ (any alnum "_-")) | ||
| 1351 | (seq "[" (+? nonl) "]") | ||
| 1352 | (seq "<" (+? nonl) ">") | ||
| 1353 | (seq "{" (+? nonl) "}")))) | ||
| 1354 | (separator (rx ", " symbol-start)) | ||
| 1355 | (description (rx (* nonl) | ||
| 1356 | (* "\n" (>= 9 " ") (* nonl)))) | ||
| 1357 | narrow-start | ||
| 1358 | narrow-end) | ||
| 1359 | "Parse output of COMMAND into a list of completion candidates. | ||
| 1360 | |||
| 1361 | COMMAND can be a string to be executed in a shell or a list of | ||
| 1362 | strings (program name and arguments). It should print a help | ||
| 1363 | message. | ||
| 1364 | |||
| 1365 | A list of arguments is collected after each match of MARGIN. | ||
| 1366 | Each argument should match ARGUMENT, possibly followed by a match | ||
| 1367 | of METAVAR. If a match of SEPARATOR follows, then more | ||
| 1368 | argument-metavar pairs are collected. Finally, a match of | ||
| 1369 | DESCRIPTION is collected. | ||
| 1370 | |||
| 1371 | Keyword ARGS: | ||
| 1372 | |||
| 1373 | MARGIN: regular expression after which argument descriptions are | ||
| 1374 | to be found. Parsing continues at the end of the first match | ||
| 1375 | group or, failing that, the entire match. | ||
| 1376 | |||
| 1377 | ARGUMENT: regular expression matching an argument name. The | ||
| 1378 | first match group (failing that, the entire match) is collected | ||
| 1379 | as the argument name. Parsing continues at the end of the | ||
| 1380 | second matching group (failing that, the first group or entire | ||
| 1381 | match). | ||
| 1382 | |||
| 1383 | METAVAR: regular expression matching an argument parameter name. | ||
| 1384 | The first match group (failing that, the entire match) is | ||
| 1385 | collected as the parameter name and used as completion | ||
| 1386 | annotation. Parsing continues at the end of the second | ||
| 1387 | matching group (failing that, the first group or entire match). | ||
| 1388 | |||
| 1389 | SEPARATOR: regular expression matching the separator between | ||
| 1390 | arguments. Parsing continues at the end of the first match | ||
| 1391 | group (failing that, the entire match). | ||
| 1392 | |||
| 1393 | DESCRIPTION: regular expression matching the description of an | ||
| 1394 | argument. The first match group (failing that, the entire | ||
| 1395 | match) is collected as the parameter name and used as | ||
| 1396 | completion help. Parsing continues at the end of the first | ||
| 1397 | matching group (failing that, the entire match). | ||
| 1398 | |||
| 1399 | NARROW-START, NARROW-END: if non-nil, parsing of the help message | ||
| 1400 | is narrowed to the region between the end of the first match | ||
| 1401 | group (failing that, the entire match) of these regular | ||
| 1402 | expressions." | ||
| 1403 | (with-memoization (gethash (cons command args) pcomplete-from-help) | ||
| 1404 | (with-temp-buffer | ||
| 1405 | (let ((case-fold-search nil) | ||
| 1406 | (default-directory (expand-file-name "~/")) | ||
| 1407 | (command (if (stringp command) | ||
| 1408 | (list shell-file-name | ||
| 1409 | shell-command-switch | ||
| 1410 | command) | ||
| 1411 | command)) | ||
| 1412 | i result) | ||
| 1413 | (apply #'call-process (car command) nil t nil (cdr command)) | ||
| 1414 | (goto-char (point-min)) | ||
| 1415 | (narrow-to-region (or (and narrow-start | ||
| 1416 | (re-search-forward narrow-start nil t) | ||
| 1417 | (or (match-beginning 1) (match-beginning 0))) | ||
| 1418 | (point-min)) | ||
| 1419 | (or (and narrow-end | ||
| 1420 | (re-search-forward narrow-end nil t) | ||
| 1421 | (or (match-beginning 1) (match-beginning 0))) | ||
| 1422 | (point-max))) | ||
| 1423 | (goto-char (point-min)) | ||
| 1424 | (while (re-search-forward margin nil t) | ||
| 1425 | (goto-char (or (match-end 1) (match-end 0))) | ||
| 1426 | (setq i 0) | ||
| 1427 | (while (and (or (zerop i) | ||
| 1428 | (and (looking-at separator) | ||
| 1429 | (goto-char (or (match-end 1) | ||
| 1430 | (match-end 0))))) | ||
| 1431 | (looking-at argument)) | ||
| 1432 | (setq i (1+ i)) | ||
| 1433 | (goto-char (seq-some #'match-end '(2 1 0))) | ||
| 1434 | (push (or (match-string 1) (match-string 0)) result) | ||
| 1435 | (when (looking-at metavar) | ||
| 1436 | (goto-char (seq-some #'match-end '(2 1 0))) | ||
| 1437 | (put-text-property 0 1 | ||
| 1438 | 'pcomplete-annotation | ||
| 1439 | (or (match-string 1) (match-string 0)) | ||
| 1440 | (car result)))) | ||
| 1441 | (when (looking-at description) | ||
| 1442 | (goto-char (seq-some #'match-end '(2 1 0))) | ||
| 1443 | (let ((help (string-clean-whitespace | ||
| 1444 | (or (match-string 1) (match-string 0)))) | ||
| 1445 | (items (take i result))) | ||
| 1446 | (while items | ||
| 1447 | (put-text-property 0 1 'pcomplete-help help | ||
| 1448 | (pop items)))))) | ||
| 1449 | (nreverse result))))) | ||
| 1450 | |||
| 1451 | (defun pcomplete-here-using-help (command &rest args) | ||
| 1452 | "Perform completion for a simple command. | ||
| 1453 | Offer switches and directory entries as completion candidates. | ||
| 1454 | The switches are obtained by calling `pcomplete-from-help' with | ||
| 1455 | COMMAND and ARGS as arguments." | ||
| 1456 | (while (cond | ||
| 1457 | ((string= "--" (pcomplete-arg 1)) | ||
| 1458 | (while (pcomplete-here (pcomplete-entries)))) | ||
| 1459 | ((pcomplete-match "\\`--[^=]+=\\(.*\\)" 0) | ||
| 1460 | (pcomplete-here (pcomplete-entries) | ||
| 1461 | (pcomplete-match-string 1 0))) | ||
| 1462 | ((string-prefix-p "-" (pcomplete-arg 0)) | ||
| 1463 | (pcomplete-here (apply #'pcomplete-from-help command args))) | ||
| 1464 | (t (pcomplete-here (pcomplete-entries)))))) | ||
| 1465 | |||
| 1328 | (provide 'pcomplete) | 1466 | (provide 'pcomplete) |
| 1329 | 1467 | ||
| 1330 | ;;; pcomplete.el ends here | 1468 | ;;; pcomplete.el ends here |
diff --git a/test/lisp/pcomplete-tests.el b/test/lisp/pcomplete-tests.el new file mode 100644 index 00000000000..00a82502f30 --- /dev/null +++ b/test/lisp/pcomplete-tests.el | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | ;;; pcomplete-tests.el --- Tests for pcomplete.el -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2022 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | ;; it under the terms of the GNU General Public License as published by | ||
| 9 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 10 | ;; (at your option) any later version. | ||
| 11 | |||
| 12 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | ;; GNU General Public License for more details. | ||
| 16 | |||
| 17 | ;; You should have received a copy of the GNU General Public License | ||
| 18 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 19 | |||
| 20 | ;;; Commentary: | ||
| 21 | |||
| 22 | ;;; Code: | ||
| 23 | |||
| 24 | (require 'ert) | ||
| 25 | (require 'pcomplete) | ||
| 26 | |||
| 27 | (ert-deftest pcomplete-test-parse-gpg-help () | ||
| 28 | (cl-letf ((pcomplete-from-help (make-hash-table :test #'equal)) | ||
| 29 | ((symbol-function 'call-process) | ||
| 30 | (lambda (&rest _) (insert "\ | ||
| 31 | gpg (GnuPG) 2.3.7 | ||
| 32 | |||
| 33 | Commands: | ||
| 34 | |||
| 35 | -s, --sign make a signature | ||
| 36 | --clear-sign make a clear text signature | ||
| 37 | -b, --detach-sign make a detached signature | ||
| 38 | --tofu-policy VALUE set the TOFU policy for a key | ||
| 39 | |||
| 40 | Options to specify keys: | ||
| 41 | -r, --recipient USER-ID encrypt for USER-ID | ||
| 42 | -u, --local-user USER-ID use USER-ID to sign or decrypt | ||
| 43 | |||
| 44 | (See the man page for a complete listing of all commands and options) | ||
| 45 | |||
| 46 | Examples: | ||
| 47 | |||
| 48 | -se -r Bob [file] sign and encrypt for user Bob | ||
| 49 | --clear-sign [file] make a clear text signature | ||
| 50 | ")))) | ||
| 51 | (should | ||
| 52 | (equal-including-properties | ||
| 53 | (pcomplete-from-help "gpg --help" :narrow-end "^ -se") | ||
| 54 | '(#("-s" 0 1 (pcomplete-help "make a signature")) | ||
| 55 | #("--sign" 0 1 (pcomplete-help "make a signature")) | ||
| 56 | #("--clear-sign" 0 1 (pcomplete-help "make a clear text signature")) | ||
| 57 | #("-b" 0 1 (pcomplete-help "make a detached signature")) | ||
| 58 | #("--detach-sign" 0 1 (pcomplete-help "make a detached signature")) | ||
| 59 | #("--tofu-policy" 0 1 | ||
| 60 | (pcomplete-help "set the TOFU policy for a key" pcomplete-annotation " VALUE")) | ||
| 61 | #("-r" 0 1 (pcomplete-help "encrypt for USER-ID")) | ||
| 62 | #("--recipient" 0 1 | ||
| 63 | (pcomplete-help "encrypt for USER-ID" pcomplete-annotation " USER-ID")) | ||
| 64 | #("-u" 0 1 | ||
| 65 | (pcomplete-help "use USER-ID to sign or decrypt")) | ||
| 66 | #("--local-user" 0 1 | ||
| 67 | (pcomplete-help "use USER-ID to sign or decrypt" pcomplete-annotation " USER-ID"))))))) | ||
| 68 | |||
| 69 | (ert-deftest pcomplete-test-parse-git-help () | ||
| 70 | (cl-letf ((pcomplete-from-help (make-hash-table :test #'equal)) | ||
| 71 | ((symbol-function 'call-process) | ||
| 72 | (lambda (&rest _) (insert "\ | ||
| 73 | usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>] | ||
| 74 | [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] | ||
| 75 | [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare] | ||
| 76 | [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] | ||
| 77 | [--super-prefix=<path>] [--config-env=<name>=<envvar>] | ||
| 78 | <command> [<args>] | ||
| 79 | ")))) | ||
| 80 | (should | ||
| 81 | (equal-including-properties | ||
| 82 | (pcomplete-from-help "git help" | ||
| 83 | :margin "\\(\\[\\)-" | ||
| 84 | :separator " | " | ||
| 85 | :description "\\`") | ||
| 86 | '("-v" "--version" "-h" "--help" | ||
| 87 | #("-C" 0 1 (pcomplete-annotation " <path>")) | ||
| 88 | #("-c" 0 1 (pcomplete-annotation " <name>")) | ||
| 89 | #("--exec-path" 0 1 (pcomplete-annotation "[=<path>]")) | ||
| 90 | "--html-path" "--man-path" "--info-path" | ||
| 91 | "-p" "--paginate" "-P" "--no-pager" | ||
| 92 | "--no-replace-objects" "--bare" | ||
| 93 | #("--git-dir=" 0 1 (pcomplete-annotation "<path>")) | ||
| 94 | #("--work-tree=" 0 1 (pcomplete-annotation "<path>")) | ||
| 95 | #("--namespace=" 0 1 (pcomplete-annotation "<name>")) | ||
| 96 | #("--super-prefix=" 0 1 (pcomplete-annotation "<path>")) | ||
| 97 | #("--config-env=" 0 1 (pcomplete-annotation "<name>"))))))) | ||
| 98 | |||
| 99 | (provide 'pcomplete-tests) | ||
| 100 | ;;; pcomplete-tests.el ends here | ||