Matthew Maurer | bd39854 | 2019-09-05 16:25:08 -0700 | [diff] [blame] | 1 | # Required for bash versions < 4.1 |
| 2 | # Default bash version is 3.2 on latest macOS. See #6874 |
| 3 | shopt -s extglob |
| 4 | |
| 5 | command -v cargo >/dev/null 2>&1 && |
| 6 | _cargo() |
| 7 | { |
| 8 | local cur prev words cword |
| 9 | _get_comp_words_by_ref cur prev words cword |
| 10 | |
| 11 | COMPREPLY=() |
| 12 | |
| 13 | # Skip past - and + options to find the command. |
| 14 | local nwords=${#words[@]} |
| 15 | local cmd_i cmd dd_i |
| 16 | for (( cmd_i=1; cmd_i<$nwords; cmd_i++ )); |
| 17 | do |
| 18 | if [[ ! "${words[$cmd_i]}" =~ ^[+-] ]]; then |
| 19 | cmd="${words[$cmd_i]}" |
| 20 | break |
| 21 | fi |
| 22 | done |
| 23 | # Find the location of the -- separator. |
| 24 | for (( dd_i=1; dd_i<$nwords-1; dd_i++ )); |
| 25 | do |
| 26 | if [[ "${words[$dd_i]}" = "--" ]]; then |
| 27 | break |
| 28 | fi |
| 29 | done |
| 30 | |
| 31 | local vcs='git hg none pijul fossil' |
| 32 | local color='auto always never' |
| 33 | local msg_format='human json short' |
| 34 | |
| 35 | local opt_help='-h --help' |
| 36 | local opt_verbose='-v --verbose' |
| 37 | local opt_quiet='-q --quiet' |
| 38 | local opt_color='--color' |
| 39 | local opt_common="$opt_help $opt_verbose $opt_quiet $opt_color" |
| 40 | local opt_pkg_spec='-p --package --all --exclude' |
| 41 | local opt_pkg='-p --package' |
| 42 | local opt_feat='--features --all-features --no-default-features' |
| 43 | local opt_mani='--manifest-path' |
| 44 | local opt_jobs='-j --jobs' |
| 45 | local opt_force='-f --force' |
| 46 | local opt_test='--test --bench' |
| 47 | local opt_lock='--frozen --locked' |
| 48 | local opt_targets="--lib --bin --bins --example --examples --test --tests --bench --benches --all-targets" |
| 49 | |
| 50 | local opt___nocmd="$opt_common -V --version --list --explain" |
| 51 | local opt__bench="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_test $opt_targets --message-format --target --no-run --no-fail-fast --target-dir" |
| 52 | local opt__build="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_test $opt_targets --message-format --target --release --target-dir" |
| 53 | local opt__check="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_test $opt_targets --message-format --target --release --profile --target-dir" |
| 54 | local opt__clean="$opt_common $opt_pkg $opt_mani $opt_lock --target --release --doc --target-dir" |
| 55 | local opt__doc="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs --message-format --bin --bins --lib --target --open --no-deps --release --document-private-items --target-dir" |
| 56 | local opt__fetch="$opt_common $opt_mani $opt_lock" |
| 57 | local opt__fix="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_jobs $opt_targets $opt_lock --release --target --message-format --prepare-for --broken-code --edition --edition-idioms --allow-no-vcs --allow-dirty --allow-staged --profile --target-dir" |
| 58 | local opt__generate_lockfile="${opt__fetch}" |
| 59 | local opt__git_checkout="$opt_common $opt_lock --reference --url" |
| 60 | local opt__help="$opt_help" |
| 61 | local opt__init="$opt_common $opt_lock --bin --lib --name --vcs --edition --registry" |
| 62 | local opt__install="$opt_common $opt_feat $opt_jobs $opt_lock $opt_force --bin --bins --branch --debug --example --examples --git --list --path --rev --root --tag --version --registry --target" |
| 63 | local opt__locate_project="$opt_mani -h --help" |
| 64 | local opt__login="$opt_common $opt_lock --host --registry" |
| 65 | local opt__metadata="$opt_common $opt_feat $opt_mani $opt_lock --format-version=1 --no-deps" |
| 66 | local opt__new="$opt_common $opt_lock --vcs --bin --lib --name --edition --registry" |
| 67 | local opt__owner="$opt_common $opt_lock -a --add -r --remove -l --list --index --token --registry" |
| 68 | local opt__package="$opt_common $opt_mani $opt_feat $opt_lock $opt_jobs --allow-dirty -l --list --no-verify --no-metadata --target --target-dir" |
| 69 | local opt__pkgid="${opt__fetch} $opt_pkg" |
| 70 | local opt__publish="$opt_common $opt_mani $opt_feat $opt_lock $opt_jobs --allow-dirty --dry-run --host --token --no-verify --index --registry --target --target-dir" |
| 71 | local opt__read_manifest="$opt_help $opt_quiet $opt_verbose $opt_mani $opt_color " |
| 72 | local opt__run="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_jobs --message-format --target --bin --example --release --target-dir" |
| 73 | local opt__rustc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_jobs $opt_test $opt_targets --message-format --profile --target --release --target-dir" |
| 74 | local opt__rustdoc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_jobs $opt_test $opt_targets --message-format --target --release --open --target-dir" |
| 75 | local opt__search="$opt_common $opt_lock --host --limit --index --limit --registry" |
| 76 | local opt__test="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_test $opt_targets --message-format --doc --target --no-run --release --no-fail-fast --target-dir" |
| 77 | local opt__uninstall="$opt_common $opt_lock $opt_pkg_spec --bin --root" |
| 78 | local opt__update="$opt_common $opt_pkg_spec $opt_mani $opt_lock --aggressive --precise --dry-run" |
| 79 | local opt__verify_project="${opt__fetch}" |
| 80 | local opt__version="$opt_help $opt_verbose $opt_color" |
| 81 | local opt__yank="$opt_common $opt_lock --vers --undo --index --token --registry" |
| 82 | local opt__libtest="--help --include-ignored --ignored --test --bench --list --logfile --nocapture --test-threads --skip -q --quiet --exact --color --format" |
| 83 | |
| 84 | if [[ $cword -gt $dd_i ]]; then |
| 85 | # Completion after -- separator. |
| 86 | if [[ "${cmd}" = @(test|bench) ]]; then |
| 87 | COMPREPLY=( $( compgen -W "${opt__libtest}" -- "$cur" ) ) |
| 88 | else |
| 89 | # Fallback to filename completion, useful with `cargo run`. |
| 90 | _filedir |
| 91 | fi |
| 92 | elif [[ $cword -le $cmd_i ]]; then |
| 93 | # Completion before or at the command. |
| 94 | if [[ "$cur" == -* ]]; then |
| 95 | COMPREPLY=( $( compgen -W "${opt___nocmd}" -- "$cur" ) ) |
| 96 | elif [[ "$cur" == +* ]]; then |
| 97 | COMPREPLY=( $( compgen -W "$(_toolchains)" -- "$cur" ) ) |
| 98 | else |
| 99 | COMPREPLY=( $( compgen -W "$__cargo_commands" -- "$cur" ) ) |
| 100 | fi |
| 101 | else |
| 102 | case "${prev}" in |
| 103 | --vcs) |
| 104 | COMPREPLY=( $( compgen -W "$vcs" -- "$cur" ) ) |
| 105 | ;; |
| 106 | --color) |
| 107 | COMPREPLY=( $( compgen -W "$color" -- "$cur" ) ) |
| 108 | ;; |
| 109 | --message-format) |
| 110 | COMPREPLY=( $( compgen -W "$msg_format" -- "$cur" ) ) |
| 111 | ;; |
| 112 | --manifest-path) |
| 113 | _filedir toml |
| 114 | ;; |
| 115 | --bin) |
| 116 | COMPREPLY=( $( compgen -W "$(_bin_names)" -- "$cur" ) ) |
| 117 | ;; |
| 118 | --test) |
| 119 | COMPREPLY=( $( compgen -W "$(_test_names)" -- "$cur" ) ) |
| 120 | ;; |
| 121 | --bench) |
| 122 | COMPREPLY=( $( compgen -W "$(_benchmark_names)" -- "$cur" ) ) |
| 123 | ;; |
| 124 | --example) |
| 125 | COMPREPLY=( $( compgen -W "$(_get_examples)" -- "$cur" ) ) |
| 126 | ;; |
| 127 | --target) |
| 128 | COMPREPLY=( $( compgen -W "$(_get_targets)" -- "$cur" ) ) |
| 129 | ;; |
| 130 | --target-dir) |
| 131 | _filedir -d |
| 132 | ;; |
| 133 | help) |
| 134 | COMPREPLY=( $( compgen -W "$__cargo_commands" -- "$cur" ) ) |
| 135 | ;; |
| 136 | *) |
| 137 | local opt_var=opt__${cmd//-/_} |
| 138 | if [[ -z "${!opt_var}" ]]; then |
| 139 | # Fallback to filename completion. |
| 140 | _filedir |
| 141 | else |
| 142 | COMPREPLY=( $( compgen -W "${!opt_var}" -- "$cur" ) ) |
| 143 | fi |
| 144 | ;; |
| 145 | esac |
| 146 | fi |
| 147 | |
| 148 | # compopt does not work in bash version 3 |
| 149 | |
| 150 | return 0 |
| 151 | } && |
| 152 | complete -F _cargo cargo |
| 153 | |
| 154 | __cargo_commands=$(cargo --list 2>/dev/null | awk 'NR>1 {print $1}') |
| 155 | |
| 156 | _locate_manifest(){ |
| 157 | local manifest=`cargo locate-project 2>/dev/null` |
| 158 | # regexp-replace manifest '\{"root":"|"\}' '' |
| 159 | echo ${manifest:9:${#manifest}-11} |
| 160 | } |
| 161 | |
| 162 | # Extracts the values of "name" from the array given in $1 and shows them as |
| 163 | # command line options for completion |
| 164 | _get_names_from_array() |
| 165 | { |
| 166 | local manifest=$(_locate_manifest) |
| 167 | if [[ -z $manifest ]]; then |
| 168 | return 0 |
| 169 | fi |
| 170 | |
| 171 | local last_line |
| 172 | local -a names |
| 173 | local in_block=false |
| 174 | local block_name=$1 |
| 175 | while read line |
| 176 | do |
| 177 | if [[ $last_line == "[[$block_name]]" ]]; then |
| 178 | in_block=true |
| 179 | else |
| 180 | if [[ $last_line =~ .*\[\[.* ]]; then |
| 181 | in_block=false |
| 182 | fi |
| 183 | fi |
| 184 | |
| 185 | if [[ $in_block == true ]]; then |
| 186 | if [[ $line =~ .*name.*\= ]]; then |
| 187 | line=${line##*=} |
| 188 | line=${line%%\"} |
| 189 | line=${line##*\"} |
| 190 | names+=($line) |
| 191 | fi |
| 192 | fi |
| 193 | |
| 194 | last_line=$line |
| 195 | done < $manifest |
| 196 | echo "${names[@]}" |
| 197 | } |
| 198 | |
| 199 | #Gets the bin names from the manifest file |
| 200 | _bin_names() |
| 201 | { |
| 202 | _get_names_from_array "bin" |
| 203 | } |
| 204 | |
| 205 | #Gets the test names from the manifest file |
| 206 | _test_names() |
| 207 | { |
| 208 | _get_names_from_array "test" |
| 209 | } |
| 210 | |
| 211 | #Gets the bench names from the manifest file |
| 212 | _benchmark_names() |
| 213 | { |
| 214 | _get_names_from_array "bench" |
| 215 | } |
| 216 | |
| 217 | _get_examples(){ |
| 218 | local manifest=$(_locate_manifest) |
| 219 | [ -z "$manifest" ] && return 0 |
| 220 | |
| 221 | local files=("${manifest%/*}"/examples/*.rs) |
| 222 | local names=("${files[@]##*/}") |
| 223 | local names=("${names[@]%.*}") |
| 224 | # "*" means no examples found |
| 225 | if [[ "${names[@]}" != "*" ]]; then |
| 226 | echo "${names[@]}" |
| 227 | fi |
| 228 | } |
| 229 | |
| 230 | _get_targets(){ |
| 231 | local result=() |
| 232 | local targets=$(rustup target list) |
| 233 | while read line |
| 234 | do |
| 235 | if [[ "$line" =~ default|installed ]]; then |
| 236 | result+=("${line%% *}") |
| 237 | fi |
| 238 | done <<< "$targets" |
| 239 | echo "${result[@]}" |
| 240 | } |
| 241 | |
| 242 | _toolchains(){ |
| 243 | local result=() |
| 244 | local toolchains=$(rustup toolchain list) |
| 245 | local channels="nightly|beta|stable|[0-9]\.[0-9]{1,2}\.[0-9]" |
| 246 | local date="[0-9]{4}-[0-9]{2}-[0-9]{2}" |
| 247 | while read line |
| 248 | do |
| 249 | # Strip " (default)" |
| 250 | line=${line%% *} |
| 251 | if [[ "$line" =~ ^($channels)(-($date))?(-.*) ]]; then |
| 252 | if [[ -z ${BASH_REMATCH[3]} ]]; then |
| 253 | result+=("+${BASH_REMATCH[1]}") |
| 254 | else |
| 255 | # channel-date |
| 256 | result+=("+${BASH_REMATCH[1]}-${BASH_REMATCH[3]}") |
| 257 | fi |
| 258 | result+=("+$line") |
| 259 | else |
| 260 | result+=("+$line") |
| 261 | fi |
| 262 | done <<< "$toolchains" |
| 263 | echo "${result[@]}" |
| 264 | } |
| 265 | |
| 266 | # vim:ft=sh |