diff options
| author | Alex Kost <alezost@gmail.com> | 2015-06-06 22:19:51 +0300 |
|---|---|---|
| committer | Alex Kost <alezost@gmail.com> | 2015-06-08 11:46:05 +0300 |
| commit | 00a8dae2a6e74a0d7dd8a0b82c3dc08d3daf2a31 (patch) | |
| tree | 52f2970febcc684a157c723a1ff1024d5ba4499b | |
| parent | 132e74fec99eaf0febb62269ca38bacebeaa0882 (diff) | |
emacs: Add shell completions for "guix" command.
Suggested by Ludovic Courtès <ludo@gnu.org>.
* emacs/guix-pcomplete.el: New file.
* emacs.am (ELFILES): Add it.
* doc/emacs.texi (Emacs Completions): New node.
| -rw-r--r-- | doc/emacs.texi | 32 | ||||
| -rw-r--r-- | emacs.am | 1 | ||||
| -rw-r--r-- | emacs/guix-pcomplete.el | 392 |
3 files changed, 425 insertions, 0 deletions
diff --git a/doc/emacs.texi b/doc/emacs.texi index 6c1b255af08..00cd5c1396f 100644 --- a/doc/emacs.texi +++ b/doc/emacs.texi | |||
| @@ -19,6 +19,7 @@ guix package}). Specifically, ``guix.el'' makes it easy to: | |||
| 19 | * Usage: Emacs Usage. Using the interface. | 19 | * Usage: Emacs Usage. Using the interface. |
| 20 | * Configuration: Emacs Configuration. Configuring the interface. | 20 | * Configuration: Emacs Configuration. Configuring the interface. |
| 21 | * Prettify Mode: Emacs Prettify. Abbreviating @file{/gnu/store/@dots{}} file names. | 21 | * Prettify Mode: Emacs Prettify. Abbreviating @file{/gnu/store/@dots{}} file names. |
| 22 | * Completions: Emacs Completions. Completing @command{guix} shell command. | ||
| 22 | @end menu | 23 | @end menu |
| 23 | 24 | ||
| 24 | @node Emacs Initial Setup | 25 | @node Emacs Initial Setup |
| @@ -489,3 +490,34 @@ mode hooks (@pxref{Hooks,,, emacs, The GNU Emacs Manual}), for example: | |||
| 489 | (add-hook 'shell-mode-hook 'guix-prettify-mode) | 490 | (add-hook 'shell-mode-hook 'guix-prettify-mode) |
| 490 | (add-hook 'dired-mode-hook 'guix-prettify-mode) | 491 | (add-hook 'dired-mode-hook 'guix-prettify-mode) |
| 491 | @end example | 492 | @end example |
| 493 | |||
| 494 | |||
| 495 | @node Emacs Completions | ||
| 496 | @subsection Shell Completions | ||
| 497 | |||
| 498 | Another feature that becomes available after configuring Emacs interface | ||
| 499 | (@pxref{Emacs Initial Setup}) is completing of @command{guix} | ||
| 500 | subcommands, options, packages and other things in @code{shell} | ||
| 501 | (@pxref{Interactive Shell,,, emacs, The GNU Emacs Manual}) and | ||
| 502 | @code{eshell} (@pxref{Top,,, eshell, Eshell: The Emacs Shell}). | ||
| 503 | |||
| 504 | It works the same way as other completions do. Just press @key{TAB} | ||
| 505 | when your intuition tells you. | ||
| 506 | |||
| 507 | And here are some examples, where pressing @key{TAB} may complete | ||
| 508 | something: | ||
| 509 | |||
| 510 | @itemize @w{} | ||
| 511 | |||
| 512 | @item @code{guix pa}@key{TAB} | ||
| 513 | @item @code{guix package -}@key{TAB} | ||
| 514 | @item @code{guix package --}@key{TAB} | ||
| 515 | @item @code{guix package -i gei}@key{TAB} | ||
| 516 | @item @code{guix build -L/tm}@key{TAB} | ||
| 517 | @item @code{guix build --sy}@key{TAB} | ||
| 518 | @item @code{guix build --system=i}@key{TAB} | ||
| 519 | @item @code{guix system rec}@key{TAB} | ||
| 520 | @item @code{guix lint --checkers=sy}@key{TAB} | ||
| 521 | @item @code{guix lint --checkers=synopsis,des}@key{TAB} | ||
| 522 | |||
| 523 | @end itemize | ||
| @@ -26,6 +26,7 @@ ELFILES = \ | |||
| 26 | emacs/guix-info.el \ | 26 | emacs/guix-info.el \ |
| 27 | emacs/guix-list.el \ | 27 | emacs/guix-list.el \ |
| 28 | emacs/guix-messages.el \ | 28 | emacs/guix-messages.el \ |
| 29 | emacs/guix-pcomplete.el \ | ||
| 29 | emacs/guix-prettify.el \ | 30 | emacs/guix-prettify.el \ |
| 30 | emacs/guix-utils.el \ | 31 | emacs/guix-utils.el \ |
| 31 | emacs/guix.el | 32 | emacs/guix.el |
diff --git a/emacs/guix-pcomplete.el b/emacs/guix-pcomplete.el new file mode 100644 index 00000000000..fa71dd5e211 --- /dev/null +++ b/emacs/guix-pcomplete.el | |||
| @@ -0,0 +1,392 @@ | |||
| 1 | ;;; guix-pcomplete.el --- Functions for completing guix commands -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;; Copyright © 2015 Alex Kost <alezost@gmail.com> | ||
| 4 | |||
| 5 | ;; This file is part of GNU Guix. | ||
| 6 | |||
| 7 | ;; GNU Guix 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 Guix 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 this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | |||
| 20 | ;;; Commentary: | ||
| 21 | |||
| 22 | ;; This file provides completions for "guix" command that may be used in | ||
| 23 | ;; `shell', `eshell' and wherever `pcomplete' works. | ||
| 24 | |||
| 25 | ;;; Code: | ||
| 26 | |||
| 27 | (require 'pcomplete) | ||
| 28 | (require 'pcmpl-unix) | ||
| 29 | (require 'cl-lib) | ||
| 30 | (require 'guix-utils) | ||
| 31 | |||
| 32 | |||
| 33 | ;;; Regexps for parsing various "guix ..." outputs | ||
| 34 | |||
| 35 | (defvar guix-pcomplete-parse-package-regexp | ||
| 36 | (rx bol (group (one-or-more (not blank)))) | ||
| 37 | "Regexp used to find names of the packages.") | ||
| 38 | |||
| 39 | (defvar guix-pcomplete-parse-command-regexp | ||
| 40 | (rx bol " " | ||
| 41 | (group wordchar (one-or-more (or wordchar "-")))) | ||
| 42 | "Regexp used to find guix commands. | ||
| 43 | 'Command' means any option not prefixed with '-'. For example, | ||
| 44 | guix subcommand, system action, importer, etc.") | ||
| 45 | |||
| 46 | (defvar guix-pcomplete-parse-long-option-regexp | ||
| 47 | (rx (or " " ", ") | ||
| 48 | (group "--" (one-or-more (or wordchar "-")) | ||
| 49 | (zero-or-one "="))) | ||
| 50 | "Regexp used to find long options.") | ||
| 51 | |||
| 52 | (defvar guix-pcomplete-parse-short-option-regexp | ||
| 53 | (rx bol (one-or-more blank) | ||
| 54 | "-" (group (not (any "- ")))) | ||
| 55 | "Regexp used to find short options.") | ||
| 56 | |||
| 57 | (defvar guix-pcomplete-parse-linter-regexp | ||
| 58 | (rx bol "- " (group (one-or-more (or wordchar "-")))) | ||
| 59 | "Regexp used to find 'lint' checkers.") | ||
| 60 | |||
| 61 | (defvar guix-pcomplete-parse-regexp-group 1 | ||
| 62 | "Parenthesized expression of regexps used to find commands and | ||
| 63 | options.") | ||
| 64 | |||
| 65 | |||
| 66 | ;;; Non-receivable completions | ||
| 67 | |||
| 68 | (defvar guix-pcomplete-systems | ||
| 69 | '("x86_64-linux" "i686-linux" "armhf-linux" "mips64el-linux") | ||
| 70 | "List of supported systems.") | ||
| 71 | |||
| 72 | (defvar guix-pcomplete-hash-formats | ||
| 73 | '("nix-base32" "base32" "base16" "hex" "hexadecimal") | ||
| 74 | "List of supported hash formats.") | ||
| 75 | |||
| 76 | (defvar guix-pcomplete-refresh-subsets | ||
| 77 | '("core" "non-core") | ||
| 78 | "List of supported 'refresh' subsets.") | ||
| 79 | |||
| 80 | (defvar guix-pcomplete-key-policies | ||
| 81 | '("interactive" "always" "never") | ||
| 82 | "List of supported key download policies.") | ||
| 83 | |||
| 84 | |||
| 85 | ;;; Interacting with guix | ||
| 86 | |||
| 87 | (defcustom guix-pcomplete-guix-program (executable-find "guix") | ||
| 88 | "Name of the 'guix' program. | ||
| 89 | It is used to find guix commands, options, packages, etc." | ||
| 90 | :type 'file | ||
| 91 | :group 'pcomplete | ||
| 92 | :group 'guix) | ||
| 93 | |||
| 94 | (defun guix-pcomplete-run-guix (&rest args) | ||
| 95 | "Run `guix-pcomplete-guix-program' with ARGS. | ||
| 96 | Insert the output to the current buffer." | ||
| 97 | (apply #'call-process | ||
| 98 | guix-pcomplete-guix-program nil t nil args)) | ||
| 99 | |||
| 100 | (defun guix-pcomplete-run-guix-and-search (regexp &optional group | ||
| 101 | &rest args) | ||
| 102 | "Run `guix-pcomplete-guix-program' with ARGS and search for matches. | ||
| 103 | Return a list of strings matching REGEXP. | ||
| 104 | GROUP specifies a parenthesized expression used in REGEXP." | ||
| 105 | (with-temp-buffer | ||
| 106 | (apply #'guix-pcomplete-run-guix args) | ||
| 107 | (goto-char (point-min)) | ||
| 108 | (let (result) | ||
| 109 | (while (re-search-forward regexp nil t) | ||
| 110 | (push (match-string-no-properties group) result)) | ||
| 111 | (nreverse result)))) | ||
| 112 | |||
| 113 | (defmacro guix-pcomplete-define-options-finder (name docstring regexp | ||
| 114 | &optional filter) | ||
| 115 | "Define function NAME to receive guix options and commands. | ||
| 116 | |||
| 117 | The defined function takes an optional COMMAND argument. This | ||
| 118 | function will run 'guix COMMAND --help' (or 'guix --help' if | ||
| 119 | COMMAND is nil) using `guix-pcomplete-run-guix-and-search' and | ||
| 120 | return its result. | ||
| 121 | |||
| 122 | If FILTER is specified, it should be a function. The result is | ||
| 123 | passed to this FILTER as argument and the result value of this | ||
| 124 | function call is returned." | ||
| 125 | (declare (doc-string 2) (indent 1)) | ||
| 126 | `(guix-memoized-defun ,name (&optional command) | ||
| 127 | ,docstring | ||
| 128 | (let* ((args '("--help")) | ||
| 129 | (args (if command (cons command args) args)) | ||
| 130 | (res (apply #'guix-pcomplete-run-guix-and-search | ||
| 131 | ,regexp guix-pcomplete-parse-regexp-group args))) | ||
| 132 | ,(if filter | ||
| 133 | `(funcall ,filter res) | ||
| 134 | 'res)))) | ||
| 135 | |||
| 136 | (guix-pcomplete-define-options-finder guix-pcomplete-commands | ||
| 137 | "If COMMAND is nil, return a list of available guix commands. | ||
| 138 | If COMMAND is non-nil (it should be a string), return available | ||
| 139 | subcommands, actions, etc. for this guix COMMAND." | ||
| 140 | guix-pcomplete-parse-command-regexp) | ||
| 141 | |||
| 142 | (guix-pcomplete-define-options-finder guix-pcomplete-long-options | ||
| 143 | "Return a list of available long options for guix COMMAND." | ||
| 144 | guix-pcomplete-parse-long-option-regexp) | ||
| 145 | |||
| 146 | (guix-pcomplete-define-options-finder guix-pcomplete-short-options | ||
| 147 | "Return a string with available short options for guix COMMAND." | ||
| 148 | guix-pcomplete-parse-short-option-regexp | ||
| 149 | (lambda (list) | ||
| 150 | (mapconcat #'identity list ""))) | ||
| 151 | |||
| 152 | (guix-memoized-defun guix-pcomplete-all-packages () | ||
| 153 | "Return a list of all available Guix packages." | ||
| 154 | (guix-pcomplete-run-guix-and-search | ||
| 155 | guix-pcomplete-parse-package-regexp | ||
| 156 | guix-pcomplete-parse-regexp-group | ||
| 157 | "package" "--list-available")) | ||
| 158 | |||
| 159 | (guix-memoized-defun guix-pcomplete-installed-packages (&optional profile) | ||
| 160 | "Return a list of Guix packages installed in PROFILE." | ||
| 161 | (let* ((args (and profile | ||
| 162 | (list (concat "--profile=" profile)))) | ||
| 163 | (args (append '("package" "--list-installed") args))) | ||
| 164 | (apply #'guix-pcomplete-run-guix-and-search | ||
| 165 | guix-pcomplete-parse-package-regexp | ||
| 166 | guix-pcomplete-parse-regexp-group | ||
| 167 | args))) | ||
| 168 | |||
| 169 | (guix-memoized-defun guix-pcomplete-lint-checkers () | ||
| 170 | "Return a list of all available lint checkers." | ||
| 171 | (guix-pcomplete-run-guix-and-search | ||
| 172 | guix-pcomplete-parse-linter-regexp | ||
| 173 | guix-pcomplete-parse-regexp-group | ||
| 174 | "lint" "--list-checkers")) | ||
| 175 | |||
| 176 | |||
| 177 | ;;; Completing | ||
| 178 | |||
| 179 | (defvar guix-pcomplete-option-regexp (rx string-start "-") | ||
| 180 | "Regexp to match an option.") | ||
| 181 | |||
| 182 | (defvar guix-pcomplete-long-option-regexp (rx string-start "--") | ||
| 183 | "Regexp to match a long option.") | ||
| 184 | |||
| 185 | (defvar guix-pcomplete-long-option-with-arg-regexp | ||
| 186 | (rx string-start | ||
| 187 | (group "--" (one-or-more any)) "=" | ||
| 188 | (group (zero-or-more any))) | ||
| 189 | "Regexp to match a long option with its argument. | ||
| 190 | The first parenthesized group defines the option and the second | ||
| 191 | group - the argument.") | ||
| 192 | |||
| 193 | (defvar guix-pcomplete-short-option-with-arg-regexp | ||
| 194 | (rx string-start | ||
| 195 | (group "-" (not (any "-"))) | ||
| 196 | (group (zero-or-more any))) | ||
| 197 | "Regexp to match a short option with its argument. | ||
| 198 | The first parenthesized group defines the option and the second | ||
| 199 | group - the argument.") | ||
| 200 | |||
| 201 | (defun guix-pcomplete-match-option () | ||
| 202 | "Return non-nil, if the current argument is an option." | ||
| 203 | (pcomplete-match guix-pcomplete-option-regexp 0)) | ||
| 204 | |||
| 205 | (defun guix-pcomplete-match-long-option () | ||
| 206 | "Return non-nil, if the current argument is a long option." | ||
| 207 | (pcomplete-match guix-pcomplete-long-option-regexp 0)) | ||
| 208 | |||
| 209 | (defun guix-pcomplete-match-long-option-with-arg () | ||
| 210 | "Return non-nil, if the current argument is a long option with value." | ||
| 211 | (pcomplete-match guix-pcomplete-long-option-with-arg-regexp 0)) | ||
| 212 | |||
| 213 | (defun guix-pcomplete-match-short-option-with-arg () | ||
| 214 | "Return non-nil, if the current argument is a short option with value." | ||
| 215 | (pcomplete-match guix-pcomplete-short-option-with-arg-regexp 0)) | ||
| 216 | |||
| 217 | (defun guix-pcomplete-long-option-arg (option args) | ||
| 218 | "Return a long OPTION's argument from a list of arguments ARGS." | ||
| 219 | (let* ((re (concat "\\`" option "=\\(.*\\)")) | ||
| 220 | (args (cl-member-if (lambda (arg) | ||
| 221 | (string-match re arg)) | ||
| 222 | args)) | ||
| 223 | (cur (car args))) | ||
| 224 | (when cur | ||
| 225 | (match-string-no-properties 1 cur)))) | ||
| 226 | |||
| 227 | (defun guix-pcomplete-short-option-arg (option args) | ||
| 228 | "Return a short OPTION's argument from a list of arguments ARGS." | ||
| 229 | (let* ((re (concat "\\`" option "\\(.*\\)")) | ||
| 230 | (args (cl-member-if (lambda (arg) | ||
| 231 | (string-match re arg)) | ||
| 232 | args)) | ||
| 233 | (cur (car args))) | ||
| 234 | (when cur | ||
| 235 | (let ((arg (match-string-no-properties 1 cur))) | ||
| 236 | (if (string= "" arg) | ||
| 237 | (cadr args) ; take the next arg | ||
| 238 | arg))))) | ||
| 239 | |||
| 240 | (defun guix-pcomplete-complete-comma-args (entries) | ||
| 241 | "Complete comma separated arguments using ENTRIES." | ||
| 242 | (let ((index pcomplete-index)) | ||
| 243 | (while (= index pcomplete-index) | ||
| 244 | (let* ((args (if (or (guix-pcomplete-match-long-option-with-arg) | ||
| 245 | (guix-pcomplete-match-short-option-with-arg)) | ||
| 246 | (pcomplete-match-string 2 0) | ||
| 247 | (pcomplete-arg 0))) | ||
| 248 | (input (if (string-match ".*,\\(.*\\)" args) | ||
| 249 | (match-string-no-properties 1 args) | ||
| 250 | args))) | ||
| 251 | (pcomplete-here* entries input))))) | ||
| 252 | |||
| 253 | (defun guix-pcomplete-complete-command-arg (command) | ||
| 254 | "Complete argument for guix COMMAND." | ||
| 255 | (cond | ||
| 256 | ((member command | ||
| 257 | '("archive" "build" "environment" "lint" "refresh")) | ||
| 258 | (while t | ||
| 259 | (pcomplete-here (guix-pcomplete-all-packages)))) | ||
| 260 | (t (pcomplete-here* (pcomplete-entries))))) | ||
| 261 | |||
| 262 | (defun guix-pcomplete-complete-option-arg (command option &optional input) | ||
| 263 | "Complete argument for COMMAND's OPTION. | ||
| 264 | INPUT is the current partially completed string." | ||
| 265 | (cl-flet ((option? (short long) | ||
| 266 | (or (string= option short) | ||
| 267 | (string= option long))) | ||
| 268 | (command? (&rest commands) | ||
| 269 | (member command commands)) | ||
| 270 | (complete (entries) | ||
| 271 | (pcomplete-here entries input nil t)) | ||
| 272 | (complete* (entries) | ||
| 273 | (pcomplete-here* entries input t))) | ||
| 274 | (cond | ||
| 275 | ((option? "-L" "--load-path") | ||
| 276 | (complete* (pcomplete-dirs))) | ||
| 277 | ((string= "--key-download" option) | ||
| 278 | (complete* guix-pcomplete-key-policies)) | ||
| 279 | |||
| 280 | ((command? "package") | ||
| 281 | (cond | ||
| 282 | ;; For '--install[=]' and '--remove[=]', try to complete a package | ||
| 283 | ;; name (INPUT) after the "=" sign, and then the rest packages | ||
| 284 | ;; separated with spaces. | ||
| 285 | ((option? "-i" "--install") | ||
| 286 | (complete (guix-pcomplete-all-packages)) | ||
| 287 | (while (not (guix-pcomplete-match-option)) | ||
| 288 | (pcomplete-here (guix-pcomplete-all-packages)))) | ||
| 289 | ((option? "-r" "--remove") | ||
| 290 | (let* ((profile (or (guix-pcomplete-short-option-arg | ||
| 291 | "-p" pcomplete-args) | ||
| 292 | (guix-pcomplete-long-option-arg | ||
| 293 | "--profile" pcomplete-args))) | ||
| 294 | (profile (and profile (expand-file-name profile)))) | ||
| 295 | (complete (guix-pcomplete-installed-packages profile)) | ||
| 296 | (while (not (guix-pcomplete-match-option)) | ||
| 297 | (pcomplete-here (guix-pcomplete-installed-packages profile))))) | ||
| 298 | ((string= "--show" option) | ||
| 299 | (complete (guix-pcomplete-all-packages))) | ||
| 300 | ((option? "-p" "--profile") | ||
| 301 | (complete* (pcomplete-dirs))) | ||
| 302 | ((option? "-m" "--manifest") | ||
| 303 | (complete* (pcomplete-entries))))) | ||
| 304 | |||
| 305 | ((and (command? "archive" "build") | ||
| 306 | (option? "-s" "--system")) | ||
| 307 | (complete* guix-pcomplete-systems)) | ||
| 308 | |||
| 309 | ((and (command? "build") | ||
| 310 | (option? "-r" "--root")) | ||
| 311 | (complete* (pcomplete-entries))) | ||
| 312 | |||
| 313 | ((and (command? "environment") | ||
| 314 | (option? "-l" "--load")) | ||
| 315 | (complete* (pcomplete-entries))) | ||
| 316 | |||
| 317 | ((and (command? "hash" "download") | ||
| 318 | (option? "-f" "--format")) | ||
| 319 | (complete* guix-pcomplete-hash-formats)) | ||
| 320 | |||
| 321 | ((and (command? "lint") | ||
| 322 | (option? "-c" "--checkers")) | ||
| 323 | (guix-pcomplete-complete-comma-args | ||
| 324 | (guix-pcomplete-lint-checkers))) | ||
| 325 | |||
| 326 | ((and (command? "publish") | ||
| 327 | (option? "-u" "--user")) | ||
| 328 | (complete* (pcmpl-unix-user-names))) | ||
| 329 | |||
| 330 | ((and (command? "refresh") | ||
| 331 | (option? "-s" "--select")) | ||
| 332 | (complete* guix-pcomplete-refresh-subsets))))) | ||
| 333 | |||
| 334 | (defun guix-pcomplete-complete-options (command) | ||
| 335 | "Complete options (with their arguments) for guix COMMAND." | ||
| 336 | (while (guix-pcomplete-match-option) | ||
| 337 | (let ((index pcomplete-index)) | ||
| 338 | (if (guix-pcomplete-match-long-option) | ||
| 339 | |||
| 340 | ;; Long options. | ||
| 341 | (if (guix-pcomplete-match-long-option-with-arg) | ||
| 342 | (let ((option (pcomplete-match-string 1 0)) | ||
| 343 | (arg (pcomplete-match-string 2 0))) | ||
| 344 | (guix-pcomplete-complete-option-arg | ||
| 345 | command option arg)) | ||
| 346 | |||
| 347 | (pcomplete-here* (guix-pcomplete-long-options command)) | ||
| 348 | ;; We support '--opt arg' style (along with '--opt=arg'), | ||
| 349 | ;; because 'guix package --install/--remove' may be used this | ||
| 350 | ;; way. So try to complete an argument after the option has | ||
| 351 | ;; been completed. | ||
| 352 | (unless (guix-pcomplete-match-option) | ||
| 353 | (guix-pcomplete-complete-option-arg | ||
| 354 | command (pcomplete-arg 0 -1)))) | ||
| 355 | |||
| 356 | ;; Short options. | ||
| 357 | (let ((arg (pcomplete-arg 0))) | ||
| 358 | (if (> (length arg) 2) | ||
| 359 | ;; Support specifying an argument after a short option without | ||
| 360 | ;; spaces (for example, '-L/tmp/foo'). | ||
| 361 | (guix-pcomplete-complete-option-arg | ||
| 362 | command | ||
| 363 | (substring-no-properties arg 0 2) | ||
| 364 | (substring-no-properties arg 2)) | ||
| 365 | (pcomplete-opt (guix-pcomplete-short-options command)) | ||
| 366 | (guix-pcomplete-complete-option-arg | ||
| 367 | command (pcomplete-arg 0 -1))))) | ||
| 368 | |||
| 369 | ;; If there were no completions, move to the next argument and get | ||
| 370 | ;; out if the last argument is achieved. | ||
| 371 | (when (= index pcomplete-index) | ||
| 372 | (if (= pcomplete-index pcomplete-last) | ||
| 373 | (throw 'pcompleted nil) | ||
| 374 | (pcomplete-next-arg)))))) | ||
| 375 | |||
| 376 | ;;;###autoload | ||
| 377 | (defun pcomplete/guix () | ||
| 378 | "Completion for `guix'." | ||
| 379 | (let ((commands (guix-pcomplete-commands))) | ||
| 380 | (pcomplete-here* (cons "--help" commands)) | ||
| 381 | (let ((command (pcomplete-arg 'first 1))) | ||
| 382 | (when (member command commands) | ||
| 383 | (guix-pcomplete-complete-options command) | ||
| 384 | (let ((subcommands (guix-pcomplete-commands command))) | ||
| 385 | (when subcommands | ||
| 386 | (pcomplete-here* subcommands))) | ||
| 387 | (guix-pcomplete-complete-options command) | ||
| 388 | (guix-pcomplete-complete-command-arg command))))) | ||
| 389 | |||
| 390 | (provide 'guix-pcomplete) | ||
| 391 | |||
| 392 | ;;; guix-pcomplete.el ends here | ||
