• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Required for bash versions < 4.1
2# Default bash version is 3.2 on latest macOS. See #6874
3shopt -s extglob
4
5command -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 --workspace'
41	local opt_pkg='-p --package'
42	local opt_feat='-F --features --all-features --no-default-features'
43	local opt_mani='--manifest-path'
44	local opt_jobs='-j --jobs'
45	local opt_parallel="$opt_jobs --keep-going"
46	local opt_force='-f --force'
47	local opt_sync='-s --sync'
48	local opt_lock='--frozen --locked --offline'
49	local opt_targets="--lib --bin --bins --example --examples --test --tests --bench --benches --all-targets"
50
51	local opt___nocmd="$opt_common -V --version --list --explain"
52	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 --ignore-rust-version"
53	local opt__bench="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_targets --message-format --target --no-run --no-fail-fast --target-dir --ignore-rust-version"
54	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 --ignore-rust-version"
55	local opt__b="$opt__build"
56	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 --ignore-rust-version"
57	local opt__c="$opt__check"
58	local opt__clean="$opt_common $opt_pkg $opt_mani $opt_lock --target --release --doc --target-dir --profile"
59	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"
60	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 --ignore-rust-version"
61	local opt__d="$opt__doc"
62	local opt__fetch="$opt_common $opt_mani $opt_lock --target"
63	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 --ignore-rust-version"
64	local opt__generate_lockfile="$opt_common $opt_mani $opt_lock"
65	local opt__help="$opt_help"
66	local opt__info="$opt_common $opt_lock --registry --index"
67	local opt__init="$opt_common $opt_lock --bin --lib --name --vcs --edition --registry"
68	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 --ignore-rust-version"
69	local opt__locate_project="$opt_common $opt_mani $opt_lock --message-format --workspace"
70	local opt__login="$opt_common $opt_lock --registry"
71	local opt__metadata="$opt_common $opt_feat $opt_mani $opt_lock --format-version=1 --no-deps --filter-platform"
72	local opt__new="$opt_common $opt_lock --vcs --bin --lib --name --edition --registry"
73	local opt__owner="$opt_common $opt_lock -a --add -r --remove -l --list --index --token --registry"
74	local opt__package="$opt_common $opt_mani $opt_feat $opt_lock $opt_parallel --allow-dirty -l --list --no-verify --no-metadata --index --registry --target --target-dir"
75	local opt__pkgid="$opt_common $opt_mani $opt_lock $opt_pkg"
76	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"
77	local opt__read_manifest="$opt_help $opt_quiet $opt_verbose $opt_mani $opt_color $opt_lock --no-deps"
78	local opt__remove="$opt_common $opt_pkg $opt_lock $opt_mani --dry-run --dev --build --target"
79	local opt__rm="$opt__remove"
80	local opt__report="$opt_help $opt_verbose $opt_color future-incompat future-incompatibilities"
81	local opt__report__future_incompat="$opt_help $opt_verbose $opt_color $opt_pkg --id"
82	local opt__run="$opt_common $opt_pkg $opt_feat $opt_mani $opt_lock $opt_parallel --message-format --target --bin --example --release --target-dir --profile --ignore-rust-version"
83	local opt__r="$opt__run"
84	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 --ignore-rust-version"
85	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 --ignore-rust-version"
86	local opt__search="$opt_common $opt_lock --limit --index --registry"
87	local opt__test="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_lock $opt_jobs $opt_targets --message-format --doc --target --no-run --release --no-fail-fast --target-dir --profile --ignore-rust-version"
88	local opt__t="$opt__test"
89	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"
90	local opt__uninstall="$opt_common $opt_lock $opt_pkg --bin --root"
91	local opt__update="$opt_common $opt_mani $opt_lock $opt_pkg --aggressive --recursive --precise --dry-run"
92	local opt__vendor="$opt_common $opt_mani $opt_lock $opt_sync --no-delete --respect-source-config --versioned-dirs"
93	local opt__verify_project="$opt_common $opt_mani $opt_lock"
94	local opt__version="$opt_common $opt_lock"
95	local opt__yank="$opt_common $opt_lock --version --undo --index --token --registry"
96	local opt__libtest="--help --include-ignored --ignored --test --bench --list --logfile --nocapture --test-threads --skip -q --quiet --exact --color --format"
97
98	if [[ $cword -gt $dd_i ]]; then
99		# Completion after -- separator.
100		if [[ "${cmd}" = @(test|bench) ]]; then
101			COMPREPLY=( $( compgen -W "${opt__libtest}" -- "$cur" ) )
102		else
103			# Fallback to filename completion, useful with `cargo run`.
104			_filedir
105		fi
106	elif [[ $cword -le $cmd_i ]]; then
107		# Completion before or at the command.
108		if [[ "$cur" == -* ]]; then
109			COMPREPLY=( $( compgen -W "${opt___nocmd}" -- "$cur" ) )
110		elif [[ "$cur" == +* ]]; then
111			COMPREPLY=( $( compgen -W "$(_toolchains)" -- "$cur" ) )
112		else
113			_ensure_cargo_commands_cache_filled
114			COMPREPLY=( $( compgen -W "$__cargo_commands_cache" -- "$cur" ) )
115		fi
116	else
117		case "${prev}" in
118			--vcs)
119				COMPREPLY=( $( compgen -W "$vcs" -- "$cur" ) )
120				;;
121			--color)
122				COMPREPLY=( $( compgen -W "$color" -- "$cur" ) )
123				;;
124			--message-format)
125				COMPREPLY=( $( compgen -W "$msg_format" -- "$cur" ) )
126				;;
127			--manifest-path)
128				_filedir toml
129				;;
130			--bin)
131				COMPREPLY=( $( compgen -W "$(_bin_names)" -- "$cur" ) )
132				;;
133			--test)
134				COMPREPLY=( $( compgen -W "$(_test_names)" -- "$cur" ) )
135				;;
136			--bench)
137				COMPREPLY=( $( compgen -W "$(_benchmark_names)" -- "$cur" ) )
138				;;
139			--example)
140				COMPREPLY=( $( compgen -W "$(_get_examples)" -- "$cur" ) )
141				;;
142			--target)
143				COMPREPLY=( $( compgen -W "$(_get_targets)" -- "$cur" ) )
144				;;
145			--target-dir|--path)
146				_filedir -d
147				;;
148			help)
149				_ensure_cargo_commands_cache_filled
150				COMPREPLY=( $( compgen -W "$__cargo_commands_cache" -- "$cur" ) )
151				;;
152			*)
153				if [[ "$cmd" == "report" && "$prev" == future-incompat* ]]; then
154					local opt_var=opt__${cmd//-/_}__${prev//-/_}
155				else
156					local opt_var=opt__${cmd//-/_}
157				fi
158				if [[ -z "${!opt_var-}" ]]; then
159					# Fallback to filename completion.
160					_filedir
161				else
162					COMPREPLY=( $( compgen -W "${!opt_var}" -- "$cur" ) )
163				fi
164				;;
165		esac
166	fi
167
168	# compopt does not work in bash version 3
169
170	return 0
171} &&
172complete -F _cargo cargo
173
174__cargo_commands_cache=
175_ensure_cargo_commands_cache_filled(){
176	if [[ -z $__cargo_commands_cache ]]; then
177		__cargo_commands_cache="$(cargo --list 2>/dev/null | awk 'NR>1 {print $1}')"
178	fi
179}
180
181_locate_manifest(){
182	cargo locate-project --message-format plain 2>/dev/null
183}
184
185# Extracts the values of "name" from the array given in $1 and shows them as
186# command line options for completion
187_get_names_from_array()
188{
189	local manifest=$(_locate_manifest)
190	if [[ -z $manifest ]]; then
191		return 0
192	fi
193
194	local last_line
195	local -a names
196	local in_block=false
197	local block_name=$1
198	while read line
199	do
200		if [[ $last_line == "[[$block_name]]" ]]; then
201			in_block=true
202		else
203			if [[ $last_line =~ .*\[\[.* ]]; then
204				in_block=false
205			fi
206		fi
207
208		if [[ $in_block == true ]]; then
209			if [[ $line =~ .*name.*\= ]]; then
210				line=${line##*=}
211				line=${line%%\"}
212				line=${line##*\"}
213				names+=("$line")
214			fi
215		fi
216
217		last_line=$line
218	done < "$manifest"
219	echo "${names[@]}"
220}
221
222#Gets the bin names from the manifest file
223_bin_names()
224{
225	_get_names_from_array "bin"
226}
227
228#Gets the test names from the manifest file
229_test_names()
230{
231	_get_names_from_array "test"
232}
233
234#Gets the bench names from the manifest file
235_benchmark_names()
236{
237	_get_names_from_array "bench"
238}
239
240_get_examples(){
241	local manifest=$(_locate_manifest)
242	[ -z "$manifest" ] && return 0
243
244	local files=("${manifest%/*}"/examples/*.rs)
245	local names=("${files[@]##*/}")
246	local names=("${names[@]%.*}")
247	# "*" means no examples found
248	if [[ "${names[@]}" != "*" ]]; then
249		echo "${names[@]}"
250	fi
251}
252
253_get_targets(){
254	if command -v rustup >/dev/null 2>/dev/null; then
255	  rustup target list --installed
256	else
257	  rustc --print target-list
258	fi
259}
260
261_toolchains(){
262	local result=()
263	local toolchains=$(rustup toolchain list)
264	local channels="nightly|beta|stable|[0-9]\.[0-9]{1,2}\.[0-9]"
265	local date="[0-9]{4}-[0-9]{2}-[0-9]{2}"
266	while read line
267	do
268		# Strip " (default)"
269		line=${line%% *}
270		if [[ "$line" =~ ^($channels)(-($date))?(-.*) ]]; then
271			if [[ -z ${BASH_REMATCH[3]} ]]; then
272				result+=("+${BASH_REMATCH[1]}")
273			else
274				# channel-date
275				result+=("+${BASH_REMATCH[1]}-${BASH_REMATCH[3]}")
276			fi
277			result+=("+$line")
278		else
279			result+=("+$line")
280		fi
281	done <<< "$toolchains"
282	echo "${result[@]}"
283}
284
285# vim:ft=sh
286