summaryrefslogtreecommitdiffstats
path: root/src/etc/cargo.bashcomp.sh
blob: cb709dccb8b93f4db191c03f9809c33da63c63dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# Required for bash versions < 4.1
# Default bash version is 3.2 on latest macOS. See #6874
shopt -s extglob

command -v cargo >/dev/null 2>&1 &&
_cargo()
{
	local cur prev words cword
	_get_comp_words_by_ref cur prev words cword

	COMPREPLY=()

	# Skip past - and + options to find the command.
	local nwords=${#words[@]}
	local cmd_i cmd dd_i
	for (( cmd_i=1; cmd_i<$nwords; cmd_i++ ));
	do
		if [[ ! "${words[$cmd_i]}" =~ ^[+-] ]]; then
			cmd="${words[$cmd_i]}"
			break
		fi
	done
	# Find the location of the -- separator.
	for (( dd_i=1; dd_i<$nwords-1; dd_i++ ));
	do
		if [[ "${words[$dd_i]}" = "--" ]]; then
			break
		fi
	done

	local vcs='git hg none pijul fossil'
	local color='auto always never'
	local msg_format='human json short'

	local opt_help='-h --help'
	local opt_verbose='-v --verbose'
	local opt_quiet='-q --quiet'
	local opt_color='--color'
	local opt_common="$opt_help $opt_verbose $opt_quiet $opt_color"
	local opt_pkg_spec='-p --package --all --exclude --workspace'
	local opt_pkg='-p --package'
	local opt_feat='-F --features --all-features --no-default-features'
	local opt_mani='--manifest-path'
	local opt_parallel='-j --jobs --keep-going'
	local opt_force='-f --force'
	local opt_sync='-s --sync'
	local opt_lock='--frozen --locked --offline'
	local opt_targets="--lib --bin --bins --example --examples --test --tests --bench --benches --all-targets"

	local opt___nocmd="$opt_common -V --version --list --explain"
	local opt__add="$opt_common -p --package --features --default-features --no-default-features $opt_mani --optional --no-optional --rename --dry-run --path --git --branch --tag --rev --registry --dev --build --target"
	local opt__bench="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --no-run --no-fail-fast --target-dir"
	local opt__build="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --profile --target-dir"
	local opt__b="$opt__build"
	local opt__check="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --profile --target-dir"
	local opt__c="$opt__check"
	local opt__clean="$opt_common $opt_pkg $opt_mani $opt_lock --target --release --doc --target-dir --profile"
	local opt__clippy="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --profile --target-dir --no-deps --fix"
	local opt__doc="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel --message-format --bin --bins --lib --target --open --no-deps --release --document-private-items --target-dir --profile"
	local opt__d="$opt__doc"
	local opt__fetch="$opt_common $opt_mani $opt_lock --target"
	local opt__fix="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_parallel $opt_targets $opt_lock --release --target --message-format --broken-code --edition --edition-idioms --allow-no-vcs --allow-dirty --allow-staged --profile --target-dir"
	local opt__generate_lockfile="$opt_common $opt_mani $opt_lock"
	local opt__help="$opt_help"
	local opt__init="$opt_common $opt_lock --bin --lib --name --vcs --edition --registry"
	local opt__install="$opt_common $opt_feat $opt_parallel $opt_lock $opt_force --bin --bins --branch --debug --example --examples --git --list --path --rev --root --tag --version --registry --target --profile --no-track"
	local opt__locate_project="$opt_common $opt_mani $opt_lock --message-format --workspace"
	local opt__login="$opt_common $opt_lock --registry"
	local opt__metadata="$opt_common $opt_feat $opt_mani $opt_lock --format-version=1 --no-deps --filter-platform"
	local opt__new="$opt_common $opt_lock --vcs --bin --lib --name --edition --registry"
	local opt__owner="$opt_common $opt_lock -a --add -r --remove -l --list --index --token --registry"
	local opt__package="$opt_common $opt_mani $opt_feat $opt_lock $opt_parallel --allow-dirty -l --list --no-verify --no-metadata --target --target-dir"
	local opt__pkgid="$opt_common $opt_mani $opt_lock $opt_pkg"
	local opt__publish="$opt_common $opt_mani $opt_feat $opt_lock $opt_parallel --allow-dirty --dry-run --token --no-verify --index --registry --target --target-dir"
	local opt__read_manifest="$opt_help $opt_quiet $opt_verbose $opt_mani $opt_color $opt_lock --no-deps"
	local opt__remove="$opt_common $opt_pkg $opt_lock $opt_mani --dry-run --dev --build --target"
	local opt__rm="$opt__remove"
	local opt__report="$opt_help $opt_verbose $opt_color future-incompat future-incompatibilities"
	local opt__report__future_incompat="$opt_help $opt_verbose $opt_color $opt_pkg --id"
	local opt__run="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel --message-format --target --bin --example --release --target-dir --profile"
	local opt__r="$opt__run"
	local opt__rustc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets -L --crate-type --extern --message-format --profile --target --release --target-dir"
	local opt__rustdoc="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --target --release --open --target-dir --profile"
	local opt__search="$opt_common $opt_lock --limit --index --registry"
	local opt__test="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_parallel $opt_targets --message-format --doc --target --no-run --release --no-fail-fast --target-dir --profile"
	local opt__t="$opt__test"
	local opt__tree="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock --target -i --invert --prefix --no-dedupe --duplicates -d --charset -f --format -e --edges"
	local opt__uninstall="$opt_common $opt_lock $opt_pkg --bin --root"
	local opt__update="$opt_common $opt_mani $opt_lock $opt_pkg --aggressive --precise --dry-run"
	local opt__vendor="$opt_common $opt_mani $opt_lock $opt_sync --no-delete --respect-source-config --versioned-dirs"
	local opt__verify_project="$opt_common $opt_mani $opt_lock"
	local opt__version="$opt_common $opt_lock"
	local opt__yank="$opt_common $opt_lock --version --undo --index --token --registry"
	local opt__libtest="--help --include-ignored --ignored --test --bench --list --logfile --nocapture --test-threads --skip -q --quiet --exact --color --format"

	if [[ $cword -gt $dd_i ]]; then
		# Completion after -- separator.
		if [[ "${cmd}" = @(test|bench) ]]; then
			COMPREPLY=( $( compgen -W "${opt__libtest}" -- "$cur" ) )
		else
			# Fallback to filename completion, useful with `cargo run`.
			_filedir
		fi
	elif [[ $cword -le $cmd_i ]]; then
		# Completion before or at the command.
		if [[ "$cur" == -* ]]; then
			COMPREPLY=( $( compgen -W "${opt___nocmd}" -- "$cur" ) )
		elif [[ "$cur" == +* ]]; then
			COMPREPLY=( $( compgen -W "$(_toolchains)" -- "$cur" ) )
		else
			_ensure_cargo_commands_cache_filled
			COMPREPLY=( $( compgen -W "$__cargo_commands_cache" -- "$cur" ) )
		fi
	else
		case "${prev}" in
			--vcs)
				COMPREPLY=( $( compgen -W "$vcs" -- "$cur" ) )
				;;
			--color)
				COMPREPLY=( $( compgen -W "$color" -- "$cur" ) )
				;;
			--message-format)
				COMPREPLY=( $( compgen -W "$msg_format" -- "$cur" ) )
				;;
			--manifest-path)
				_filedir toml
				;;
			--bin)
				COMPREPLY=( $( compgen -W "$(_bin_names)" -- "$cur" ) )
				;;
			--test)
				COMPREPLY=( $( compgen -W "$(_test_names)" -- "$cur" ) )
				;;
			--bench)
				COMPREPLY=( $( compgen -W "$(_benchmark_names)" -- "$cur" ) )
				;;
			--example)
				COMPREPLY=( $( compgen -W "$(_get_examples)" -- "$cur" ) )
				;;
			--target)
				COMPREPLY=( $( compgen -W "$(_get_targets)" -- "$cur" ) )
				;;
			--target-dir|--path)
				_filedir -d
				;;
			help)
				_ensure_cargo_commands_cache_filled
				COMPREPLY=( $( compgen -W "$__cargo_commands_cache" -- "$cur" ) )
				;;
			*)
				if [[ "$cmd" == "report" && "$prev" == future-incompat* ]]; then
					local opt_var=opt__${cmd//-/_}__${prev//-/_}
				else
					local opt_var=opt__${cmd//-/_}
				fi
				if [[ -z "${!opt_var}" ]]; then
					# Fallback to filename completion.
					_filedir
				else
					COMPREPLY=( $( compgen -W "${!opt_var}" -- "$cur" ) )
				fi
				;;
		esac
	fi

	# compopt does not work in bash version 3

	return 0
} &&
complete -F _cargo cargo

__cargo_commands_cache=
_ensure_cargo_commands_cache_filled(){
	if [[ -z $__cargo_commands_cache ]]; then
		__cargo_commands_cache="$(cargo --list 2>/dev/null | awk 'NR>1 {print $1}')"
	fi
}

_locate_manifest(){
	cargo locate-project --message-format plain 2>/dev/null
}

# Extracts the values of "name" from the array given in $1 and shows them as
# command line options for completion
_get_names_from_array()
{
	local manifest=$(_locate_manifest)
	if [[ -z $manifest ]]; then
		return 0
	fi

	local last_line
	local -a names
	local in_block=false
	local block_name=$1
	while read line
	do
		if [[ $last_line == "[[$block_name]]" ]]; then
			in_block=true
		else
			if [[ $last_line =~ .*\[\[.* ]]; then
				in_block=false
			fi
		fi

		if [[ $in_block == true ]]; then
			if [[ $line =~ .*name.*\= ]]; then
				line=${line##*=}
				line=${line%%\"}
				line=${line##*\"}
				names+=($line)
			fi
		fi

		last_line=$line
	done < $manifest
	echo "${names[@]}"
}

#Gets the bin names from the manifest file
_bin_names()
{
	_get_names_from_array "bin"
}

#Gets the test names from the manifest file
_test_names()
{
	_get_names_from_array "test"
}

#Gets the bench names from the manifest file
_benchmark_names()
{
	_get_names_from_array "bench"
}

_get_examples(){
	local manifest=$(_locate_manifest)
	[ -z "$manifest" ] && return 0

	local files=("${manifest%/*}"/examples/*.rs)
	local names=("${files[@]##*/}")
	local names=("${names[@]%.*}")
	# "*" means no examples found
	if [[ "${names[@]}" != "*" ]]; then
		echo "${names[@]}"
	fi
}

_get_targets(){
	local result=()
	local targets=$(rustup target list)
	while read line
	do
		if [[ "$line" =~ default|installed ]]; then
			result+=("${line%% *}")
		fi
	done <<< "$targets"
	echo "${result[@]}"
}

_toolchains(){
	local result=()
	local toolchains=$(rustup toolchain list)
	local channels="nightly|beta|stable|[0-9]\.[0-9]{1,2}\.[0-9]"
	local date="[0-9]{4}-[0-9]{2}-[0-9]{2}"
	while read line
	do
		# Strip " (default)"
		line=${line%% *}
		if [[ "$line" =~ ^($channels)(-($date))?(-.*) ]]; then
			if [[ -z ${BASH_REMATCH[3]} ]]; then
				result+=("+${BASH_REMATCH[1]}")
			else
				# channel-date
				result+=("+${BASH_REMATCH[1]}-${BASH_REMATCH[3]}")
			fi
			result+=("+$line")
		else
			result+=("+$line")
		fi
	done <<< "$toolchains"
	echo "${result[@]}"
}

# vim:ft=sh