xref: /aosp_15_r20/prebuilts/rust/linux-x86/1.81.0.u1/share/zsh/site-functions/_cargo (revision b40554a23088fb75aa6945dfe8e65169c8484da3)
1#compdef cargo
2
3autoload -U regexp-replace
4
5_cargo() {
6    local curcontext="$curcontext" ret=1
7    local -a command_scope_spec common parallel features msgfmt triple target registry
8    local -a state line state_descr # These are set by _arguments
9    typeset -A opt_args
10
11    common=(
12        '(-q --quiet)*'{-v,--verbose}'[use verbose output]'
13        '(-q --quiet -v --verbose)'{-q,--quiet}'[no output printed to stdout]'
14        '-Z+[pass unstable (nightly-only) flags to cargo]: :_cargo_unstable_flags'
15        '--frozen[require that Cargo.lock and cache are up-to-date]'
16        '--locked[require that Cargo.lock is up-to-date]'
17        '--color=[specify colorization option]:coloring:(auto always never)'
18        '(- 1 *)'{-h,--help}'[show help message]'
19    )
20
21    # leading items in parentheses are an exclusion list for the arguments following that arg
22    # See: http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Completion-Functions
23    #   - => exclude all other options
24    #   1 => exclude positional arg 1
25    #   * => exclude all other args
26    #   +blah => exclude +blah
27    _arguments -s -S -C $common \
28        '(- 1 *)--list[list installed commands]' \
29        '(- 1 *)--explain=[provide a detailed explanation of an error message]:error code' \
30        '(- 1 *)'{-V,--version}'[show version information]' \
31        '(+beta +nightly)+stable[use the stable toolchain]' \
32        '(+stable +nightly)+beta[use the beta toolchain]' \
33        '(+stable +beta)+nightly[use the nightly toolchain]' \
34        '1: :_cargo_cmds' \
35        '*:: :->args'
36
37    # These flags are mutually exclusive specifiers for the scope of a command; as
38    # they are used in multiple places without change, they are expanded into the
39    # appropriate command's `_arguments` where appropriate.
40    command_scope_spec=(
41        '(--bin --example --test --lib)--bench=[specify benchmark name]: :_cargo_benchmark_names'
42        '(--bench --bin --test --lib)--example=[specify example name]:example name:_cargo_example_names'
43        '(--bench --example --test --lib)--bin=[specify binary name]:binary name'
44        '(--bench --bin --example --test)--lib=[specify library name]:library name'
45        '(--bench --bin --example --lib)--test=[specify test name]:test name'
46    )
47
48    jobs=(
49        '(-j --jobs)'{-j+,--jobs=}'[specify number of parallel jobs]:jobs [# of CPUs]'
50    )
51
52    parallel=(
53        "${jobs[@]}"
54        '--keep-going[do not abort build on first build error]'
55    )
56
57    features=(
58        '(--all-features)'{-F+,--features=}'[specify features to activate]:feature'
59        '(--features -F)--all-features[activate all available features]'
60        "--no-default-features[don't build the default features]"
61    )
62
63    msgfmt='--message-format=[specify error format]:error format [human]:(human json short)'
64    triple='--target=[specify target triple]:target triple:_cargo_target_triple'
65    target='--target-dir=[specify directory for all generated artifacts]:directory:_directories'
66    manifest='--manifest-path=[specify path to manifest]:path:_directories'
67    registry='--registry=[specify registry to use]:registry'
68
69    case $state in
70        args)
71            curcontext="${curcontext%:*}-${words[1]}:"
72            case ${words[1]} in
73                add)
74                    _arguments -s -A "^--" $common $manifest $registry \
75                        {-F+,--features=}'[specify features to activate]:feature' \
76                        "--default-features[enable the default features]" \
77                        "--no-default-features[don't enable the default features]" \
78                        "--optional[mark the dependency as optional]" \
79                        "--no-optional[mark the dependency as required]" \
80                        "--dev[add as a dev dependency]" \
81                        "--build[add as a build dependency]" \
82                        "--target=[add as a dependency to the given target platform]" \
83                        "--rename=[rename the dependency]" \
84                        "--dry-run[don't actually write the manifest]" \
85                        '--branch=[branch to use when adding from git]:branch' \
86                        '--git=[specify URL from which to add the crate]:url:_urls' \
87                        '--path=[local filesystem path to crate to add]: :_directories' \
88                        '--rev=[specific commit to use when adding from git]:commit' \
89                        '--tag=[tag to use when adding from git]:tag' \
90                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
91                        '1: :_guard "^-*" "crate name"' \
92                        '*:args:_default'
93                        ;;
94                bench)
95                    _arguments -s -A "^--" $common $jobs $features $msgfmt $triple $target $manifest \
96                        "${command_scope_spec[@]}" \
97                        '--all-targets[benchmark all targets]' \
98                        "--no-run[compile but don't run]" \
99                        '(-p --package)'{-p+,--package=}'[specify package to run benchmarks for]:package:_cargo_package_names' \
100                        '--exclude=[exclude packages from the benchmark]:spec' \
101                        '--no-fail-fast[run all benchmarks regardless of failure]' \
102                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
103                        '1: :_guard "^-*" "bench name"' \
104                        '*:args:_default'
105                        ;;
106
107                build | b)
108                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
109                        '--all-targets[equivalent to specifying --lib --bins --tests --benches --examples]' \
110                        "${command_scope_spec[@]}" \
111                        '(-p --package)'{-p+,--package=}'[specify package to build]:package:_cargo_package_names' \
112                        '--release[build in release mode]' \
113                        '--build-plan[output the build plan in JSON]' \
114                        '--ignore-rust-version[Ignore rust-version specification in packages]'
115                        ;;
116
117                check | c)
118                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
119                        '--all-targets[equivalent to specifying --lib --bins --tests --benches --examples]' \
120                        "${command_scope_spec[@]}" \
121                        '(-p --package)'{-p+,--package=}'[specify package to check]:package:_cargo_package_names' \
122                        '--release[check in release mode]' \
123                        '--ignore-rust-version[Ignore rust-version specification in packages]'
124                        ;;
125
126                clean)
127                    _arguments -s -S $common $triple $target $manifest \
128                        '(-p --package)'{-p+,--package=}'[specify package to clean]:package:_cargo_package_names' \
129                        '--release[clean release artifacts]' \
130                        '--doc[clean just the documentation directory]'
131                        ;;
132
133                doc | d)
134                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
135                        '--no-deps[do not build docs for dependencies]' \
136                        '--document-private-items[include non-public items in the documentation]' \
137                        '--open[open docs in browser after the build]' \
138                        '(-p --package)'{-p+,--package=}'[specify package to document]:package:_cargo_package_names' \
139                        '--release[build artifacts in release mode, with optimizations]' \
140                        '--ignore-rust-version[Ignore rust-version specification in packages]'
141                        ;;
142
143                fetch)
144                    _arguments -s -S $common $triple $manifest
145                        ;;
146
147                fix)
148                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
149                        "${command_scope_spec[@]}" \
150                        '--broken-code[fix code even if it already has compiler errors]' \
151                        '--edition[fix in preparation for the next edition]' \
152                        '--edition-idioms[fix warnings to migrate to the idioms of an edition]' \
153                        '--allow-no-vcs[fix code even if a VCS was not detected]' \
154                        '--allow-dirty[fix code even if the working directory is dirty]' \
155                        '--allow-staged[fix code even if the working directory has staged changes]' \
156                        '--ignore-rust-version[Ignore rust-version specification in packages]'
157                ;;
158
159                generate-lockfile)
160                    _arguments -s -S $common $manifest
161                        ;;
162
163                help)
164                    _cargo_cmds
165                        ;;
166
167                init)
168                    _arguments -s -S $common $registry \
169                        '--lib[use library template]' \
170                        '--edition=[specify edition to set for the crate generated]:edition:(2015 2018 2021)' \
171                        '--vcs=[initialize a new repo with a given VCS]:vcs:(git hg pijul fossil none)' \
172                        '--name=[set the resulting package name]:name' \
173                        '1:path:_directories'
174                        ;;
175
176                install)
177                    _arguments -s -S $common $parallel $features $triple $registry \
178                        '(-f --force)'{-f,--force}'[force overwriting of existing crates or binaries]' \
179                        '--bin=[only install the specified binary]:binary' \
180                        '--branch=[branch to use when installing from git]:branch' \
181                        '--debug[Build in debug mode (with the "dev" profile) instead of release mode]' \
182                        '--example=[install the specified example instead of binaries]:example:_cargo_example_names' \
183                        '--git=[specify URL from which to install the crate]:url:_urls' \
184                        '--path=[local filesystem path to crate to install]: :_directories' \
185                        '--rev=[specific commit to use when installing from git]:commit' \
186                        '--root=[directory to install packages into]: :_directories' \
187                        '--tag=[tag to use when installing from git]:tag' \
188                        '--version=[version to install from crates.io]:version' \
189                        '--list[list all installed packages and their versions]' \
190                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
191                        '*: :_guard "^-*" "crate"'
192                        ;;
193
194                locate-project)
195                    _arguments -s -S $common $manifest \
196                        '--message-format=[specify output representation]:output representation [json]:(json plain)' \
197                        '--workspace[locate Cargo.toml of the workspace root]'
198                        ;;
199
200                login)
201                    _arguments -s -S $common $registry \
202                        '*: :_guard "^-*" "token"'
203                        ;;
204
205                metadata)
206                    _arguments -s -S $common $features $manifest \
207                        "--no-deps[output information only about the root package and don't fetch dependencies]" \
208                        '--format-version=[specify format version]:version [1]:(1)'
209                        ;;
210
211                new)
212                    _arguments -s -S $common $registry \
213                        '--lib[use library template]' \
214                        '--vcs:initialize a new repo with a given VCS:(git hg none)' \
215                        '--name=[set the resulting package name]'
216                        ;;
217
218                owner)
219                    _arguments -s -S $common $registry \
220                        '(-a --add)'{-a,--add}'[specify name of a user or team to invite as an owner]:name' \
221                        '--index=[specify registry index]:index' \
222                        '(-l --list)'{-l,--list}'[list owners of a crate]' \
223                        '(-r --remove)'{-r,--remove}'[specify name of a user or team to remove as an owner]:name' \
224                        '--token=[specify API token to use when authenticating]:token' \
225                        '*: :_guard "^-*" "crate"'
226                        ;;
227
228                package)
229                    _arguments -s -S $common $parallel $features $triple $target $manifest \
230                        '(-l --list)'{-l,--list}'[print files included in a package without making one]' \
231                        '--no-metadata[ignore warnings about a lack of human-usable metadata]' \
232                        '--allow-dirty[allow dirty working directories to be packaged]' \
233                        "--no-verify[don't build to verify contents]"
234                        ;;
235
236                pkgid)
237                    _arguments -s -S $common $manifest \
238                        '(-p --package)'{-p+,--package=}'[specify package to get ID specifier for]:package:_cargo_package_names' \
239                        '*: :_guard "^-*" "spec"'
240                        ;;
241
242                publish)
243                    _arguments -s -S $common $parallel $features $triple $target $manifest $registry \
244                        '--index=[specify registry index]:index' \
245                        '--allow-dirty[allow dirty working directories to be packaged]' \
246                        "--no-verify[don't verify the contents by building them]" \
247                        '--token=[specify token to use when uploading]:token' \
248                        '--dry-run[perform all checks without uploading]'
249                        ;;
250
251                read-manifest)
252                    _arguments -s -S $common $manifest
253                        ;;
254
255                remove | rm)
256                    _arguments -s -A "^--" $common $manifest \
257                        "--dev[remove as a dev dependency]" \
258                        "--build[remove as a build dependency]" \
259                        "--target=[remove as a dependency from the given target platform]" \
260                        "--dry-run[don't actually write the manifest]" \
261                        '(-p --package)'{-p+,--package=}'[package to remove from]:package:_cargo_package_names' \
262                        '1: :_guard "^-*" "crate name"' \
263                        '*:args:_default'
264                        ;;
265
266                run | r)
267                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
268                        '--example=[name of the bin target]:name:_cargo_example_names' \
269                        '--bin=[name of the bin target]:name' \
270                        '(-p --package)'{-p+,--package=}'[specify package with the target to run]:package:_cargo_package_names' \
271                        '--release[build in release mode]' \
272                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
273                        '*: :_default'
274                        ;;
275
276                rustc)
277                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
278                        '(-p --package)'{-p+,--package=}'[specify package to build]:package:_cargo_package_names' \
279                        '--profile=[specify profile to build the selected target for]:profile' \
280                        '--release[build artifacts in release mode, with optimizations]' \
281                        "${command_scope_spec[@]}" \
282                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
283                        '*: : _dispatch rustc rustc -default-'
284                        ;;
285
286                rustdoc)
287                    _arguments -s -S $common $parallel $features $msgfmt $triple $target $manifest \
288                        '--document-private-items[include non-public items in the documentation]' \
289                        '--open[open the docs in a browser after the operation]' \
290                        '(-p --package)'{-p+,--package=}'[specify package to document]:package:_cargo_package_names' \
291                        '--release[build artifacts in release mode, with optimizations]' \
292                        "${command_scope_spec[@]}" \
293                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
294                        '*: : _dispatch rustdoc rustdoc -default-'
295                        ;;
296
297                search)
298                    _arguments -s -S $common $registry \
299                        '--index=[specify registry index]:index' \
300                        '--limit=[limit the number of results]:results [10]' \
301                        '*: :_guard "^-*" "query"'
302                        ;;
303
304                test | t)
305                    _arguments -s -S $common $jobs $features $msgfmt $triple $target $manifest \
306                        '--test=[test name]: :_cargo_test_names' \
307                        '--no-fail-fast[run all tests regardless of failure]' \
308                        '--no-run[compile but do not run]' \
309                        '(-p --package)'{-p+,--package=}'[package to run tests for]:package:_cargo_package_names' \
310                        '--all[test all packages in the workspace]' \
311                        '--release[build artifacts in release mode, with optimizations]' \
312                        '1: :_cargo_test_names' \
313                        '(--doc --bin --example --test --bench)--lib[only test library]' \
314                        '(--lib --bin --example --test --bench)--doc[only test documentation]' \
315                        '(--lib --doc --example --test --bench)--bin=[binary name]' \
316                        '(--lib --doc --bin --test --bench)--example=[example name]:_cargo_example_names' \
317                        '(--lib --doc --bin --example --bench)--test=[test name]' \
318                        '(--lib --doc --bin --example --test)--bench=[benchmark name]' \
319                        '--ignore-rust-version[Ignore rust-version specification in packages]' \
320                        '*: :_default'
321                        ;;
322
323                tree)
324                    _arguments -s -S $common $features $triple $manifest \
325                        '(-p --package)'{-p+,--package=}'[package to use as the root]:package:_cargo_package_names' \
326                        '(-i --invert)'{-i+,--invert=}'[invert the tree for the given package]:package:_cargo_package_names' \
327                        '--prefix=[line prefix]:prefix:(depth indent none)' \
328                        '--no-dedupe[repeat shared dependencies]' \
329                        '(-d --duplicates)'{-d,--duplicates}'[packages with multiple versions]' \
330                        '--charset=[utf8 or ascii]:charset:(utf8 ascii)' \
331                        '(-f --format)'{-f,--format=}'[format string]:format' \
332                        '(-e --edges)'{-e,--edges=}'[edge kinds]:kind:(features normal build dev all no-dev no-build no-normal)' \
333                        ;;
334
335                uninstall)
336                    _arguments -s -S $common \
337                        '(-p --package)'{-p+,--package=}'[specify package to uninstall]:package:_cargo_package_names' \
338                        '--bin=[only uninstall the specified binary]:name' \
339                        '--root=[directory to uninstall packages from]: :_files -/' \
340                        '*:crate:_cargo_installed_crates -F line'
341                        ;;
342
343                update)
344                    _arguments -s -S $common $manifest \
345                        '--aggressive=[force dependency update]' \
346                        '--recursive=[force dependency update]' \
347                        "--dry-run[don't actually write the lockfile]" \
348                        '(-p --package)'{-p+,--package=}'[specify package to update]:package:_cargo_package_names' \
349                        '--precise=[update single dependency to precise release]:release' \
350                        '*:package:_cargo_package_names'
351                        ;;
352
353                verify-project)
354                    _arguments -s -S $common $manifest
355                        ;;
356
357                version)
358                    _arguments -s -S $common
359                        ;;
360
361                yank)
362                    _arguments -s -S $common $registry \
363                        '--version=[specify yank version]:version' \
364                        '--undo[undo a yank, putting a version back into the index]' \
365                        '--index=[specify registry index to yank from]:registry index' \
366                        '--token=[specify API token to use when authenticating]:token' \
367                        '*: :_guard "^-*" "crate"'
368                        ;;
369                *)
370                    # allow plugins to define their own functions
371                    if ! _call_function ret _cargo-${words[1]}; then
372                        # fallback on default completion for unknown commands
373                        _default && ret=0
374                    fi
375                    (( ! ret ))
376                ;;
377            esac
378            ;;
379    esac
380}
381
382_cargo_unstable_flags() {
383    local flags
384    flags=( help ${${${(M)${(f)"$(_call_program flags cargo -Z help)"}:#*--*}/ #-- #/:}##*-Z } )
385    _describe -t flags 'unstable flag' flags
386}
387
388_cargo_installed_crates() {
389    local expl
390    _description crates expl 'crate'
391    compadd "$@" "$expl[@]" - ${${${(f)"$(cargo install --list)"}:# *}%% *}
392}
393
394_cargo_cmds() {
395    local -a commands
396    # This uses Parameter Expansion Flags, which are a built-in Zsh feature.
397    # See more: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags
398    # and       http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion
399    #
400    # # How this work?
401    #
402    # First it splits the result of `cargo --list` at newline, then it removes the first line.
403    # Then it removes indentation (4 whitespaces) before each items. (Note the x## pattern [1]).
404    # Then it replaces those spaces between item and description with a `:`
405    #
406    # [1]: https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org#patterns
407    commands=( ${${${(M)"${(f)$(_call_program commands cargo --list)}":#    *}/ ##/}/ ##/:} )
408    _describe -t commands 'command' commands
409}
410
411_cargo_target_triple() {
412    local -a result
413
414    if (( $+commands[rustup] )); then
415        result=( ${(f)"$(rustup target list --installed)"} )
416    else
417        result=( ${(f)"$(rustc --print target-list)"} )
418    fi
419
420    _describe 'target triple' result
421}
422
423#FIXME: Disabled until fixed
424#gets package names from the manifest file
425_cargo_package_names() {
426    _message -e packages package
427}
428
429# Extracts the values of "name" from the array given in $1 and shows them as
430# command line options for completion
431_cargo_names_from_array() {
432    local manifest=$(cargo locate-project --message-format plain)
433    if [[ -z $manifest ]]; then
434        return 0
435    fi
436
437    local last_line
438    local -a names;
439    local in_block=false
440    local block_name=$1
441    names=()
442    while read -r line; do
443        if [[ $last_line == "[[$block_name]]" ]]; then
444            in_block=true
445        else
446            if [[ $last_line =~ '\s*\[\[.*' ]]; then
447                in_block=false
448            fi
449        fi
450
451        if [[ $in_block == true ]]; then
452            if [[ $line =~ '\s*name\s*=' ]]; then
453                regexp-replace line '^\s*name\s*=\s*|"' ''
454                names+=( "$line" )
455            fi
456        fi
457
458        last_line=$line
459    done < "$manifest"
460    _describe "$block_name" names
461
462}
463
464#Gets the test names from the manifest file
465_cargo_test_names() {
466    _cargo_names_from_array "test"
467}
468
469#Gets the bench names from the manifest file
470_cargo_benchmark_names() {
471    _cargo_names_from_array "bench"
472}
473
474_cargo_example_names() {
475    if [[ -d examples ]]; then
476        local -a files=(${(@f)$(echo examples/*.rs(:t:r))})
477        _values 'example' "${files[@]}"
478    fi
479}
480
481_cargo
482