1# Bash auto-completion for west subcommands and flags. To initialize, run
2#
3#     source west-completion.bash
4#
5# To make it persistent, add it to e.g. your .bashrc.
6
7__west_previous_extglob_setting=$(shopt -p extglob)
8shopt -s extglob
9
10# The following function is based on code from:
11#
12#   bash_completion - programmable completion functions for bash 3.2+
13#
14#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
15#             © 2009-2010, Bash Completion Maintainers
16#                     <bash-completion-devel@lists.alioth.debian.org>
17#
18#   This program is free software; you can redistribute it and/or modify
19#   it under the terms of the GNU General Public License as published by
20#   the Free Software Foundation; either version 2, or (at your option)
21#   any later version.
22#
23#   This program is distributed in the hope that it will be useful,
24#   but WITHOUT ANY WARRANTY; without even the implied warranty of
25#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26#   GNU General Public License for more details.
27#
28#   You should have received a copy of the GNU General Public License
29#   along with this program; if not, see <http://www.gnu.org/licenses/>.
30#
31#   The latest version of this software can be obtained here:
32#
33#   http://bash-completion.alioth.debian.org/
34#
35#   RELEASE: 2.x
36
37# This function can be used to access a tokenized list of words
38# on the command line:
39#
40#	__git_reassemble_comp_words_by_ref '=:'
41#	if test "${words_[cword_-1]}" = -w
42#	then
43#		...
44#	fi
45#
46# The argument should be a collection of characters from the list of
47# word completion separators (COMP_WORDBREAKS) to treat as ordinary
48# characters.
49#
50# This is roughly equivalent to going back in time and setting
51# COMP_WORDBREAKS to exclude those characters.  The intent is to
52# make option types like --date=<type> and <rev>:<path> easy to
53# recognize by treating each shell word as a single token.
54#
55# It is best not to set COMP_WORDBREAKS directly because the value is
56# shared with other completion scripts.  By the time the completion
57# function gets called, COMP_WORDS has already been populated so local
58# changes to COMP_WORDBREAKS have no effect.
59#
60# Output: words_, cword_, cur_.
61
62__west_reassemble_comp_words_by_ref()
63{
64	local exclude i j first
65	# Which word separators to exclude?
66	exclude="${1//[^$COMP_WORDBREAKS]}"
67	cword_=$COMP_CWORD
68	if [ -z "$exclude" ]; then
69		words_=("${COMP_WORDS[@]}")
70		return
71	fi
72	# List of word completion separators has shrunk;
73	# re-assemble words to complete.
74	for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
75		# Append each nonempty word consisting of just
76		# word separator characters to the current word.
77		first=t
78		while
79			[ $i -gt 0 ] &&
80			[ -n "${COMP_WORDS[$i]}" ] &&
81			# word consists of excluded word separators
82			[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
83		do
84			# Attach to the previous token,
85			# unless the previous token is the command name.
86			if [ $j -ge 2 ] && [ -n "$first" ]; then
87				((j--))
88			fi
89			first=
90			words_[$j]=${words_[j]}${COMP_WORDS[i]}
91			if [ $i = $COMP_CWORD ]; then
92				cword_=$j
93			fi
94			if (($i < ${#COMP_WORDS[@]} - 1)); then
95				((i++))
96			else
97				# Done.
98				return
99			fi
100		done
101		words_[$j]=${words_[j]}${COMP_WORDS[i]}
102		if [ $i = $COMP_CWORD ]; then
103			cword_=$j
104		fi
105	done
106}
107
108if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
109_get_comp_words_by_ref ()
110{
111	local exclude cur_ words_ cword_
112	if [ "$1" = "-n" ]; then
113		exclude=$2
114		shift 2
115	fi
116	__west_reassemble_comp_words_by_ref "$exclude"
117	cur_=${words_[cword_]}
118	while [ $# -gt 0 ]; do
119		case "$1" in
120		cur)
121			cur=$cur_
122			;;
123		prev)
124			prev=${words_[$cword_-1]}
125			;;
126		words)
127			words=("${words_[@]}")
128			;;
129		cword)
130			cword=$cword_
131			;;
132		esac
133		shift
134	done
135}
136fi
137
138if ! type _tilde >/dev/null 2>&1; then
139# Perform tilde (~) completion
140# @return  True (0) if completion needs further processing,
141#          False (> 0) if tilde is followed by a valid username, completions
142#          are put in COMPREPLY and no further processing is necessary.
143_tilde()
144{
145    local result=0
146    if [[ $1 == \~* && $1 != */* ]]; then
147        # Try generate ~username completions
148        COMPREPLY=( $( compgen -P '~' -u -- "${1#\~}" ) )
149        result=${#COMPREPLY[@]}
150        # 2>/dev/null for direct invocation, e.g. in the _tilde unit test
151        [[ $result -gt 0 ]] && compopt -o filenames 2>/dev/null
152    fi
153    return $result
154}
155fi
156
157if ! type _quote_readline_by_ref >/dev/null 2>&1; then
158# This function quotes the argument in a way so that readline dequoting
159# results in the original argument.  This is necessary for at least
160# `compgen' which requires its arguments quoted/escaped:
161#
162#     $ ls "a'b/"
163#     c
164#     $ compgen -f "a'b/"       # Wrong, doesn't return output
165#     $ compgen -f "a\'b/"      # Good
166#     a\'b/c
167#
168# See also:
169# - http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
170# - http://www.mail-archive.com/bash-completion-devel@lists.alioth.\
171#   debian.org/msg01944.html
172# @param $1  Argument to quote
173# @param $2  Name of variable to return result to
174_quote_readline_by_ref()
175{
176    if [ -z "$1" ]; then
177        # avoid quoting if empty
178        printf -v $2 %s "$1"
179    elif [[ $1 == \'* ]]; then
180        # Leave out first character
181        printf -v $2 %s "${1:1}"
182    elif [[ $1 == \~* ]]; then
183        # avoid escaping first ~
184        printf -v $2 \~%q "${1:1}"
185    else
186        printf -v $2 %q "$1"
187    fi
188
189    # Replace double escaping ( \\ ) by single ( \ )
190    # This happens always when argument is already escaped at cmdline,
191    # and passed to this function as e.g.: file\ with\ spaces
192    [[ ${!2} == *\\* ]] && printf -v $2 %s "${1//\\\\/\\}"
193
194    # If result becomes quoted like this: $'string', re-evaluate in order to
195    # drop the additional quoting.  See also: http://www.mail-archive.com/
196    # bash-completion-devel@lists.alioth.debian.org/msg01942.html
197    [[ ${!2} == \$* ]] && eval $2=${!2}
198} # _quote_readline_by_ref()
199fi
200
201# This function turns on "-o filenames" behavior dynamically. It is present
202# for bash < 4 reasons. See http://bugs.debian.org/272660#64 for info about
203# the bash < 4 compgen hack.
204_compopt_o_filenames()
205{
206    # We test for compopt availability first because directly invoking it on
207    # bash < 4 at this point may cause terminal echo to be turned off for some
208    # reason, see https://bugzilla.redhat.com/653669 for more info.
209    type compopt &>/dev/null && compopt -o filenames 2>/dev/null || \
210        compgen -f /non-existing-dir/ >/dev/null
211}
212
213if ! type _filedir >/dev/null 2>&1; then
214# This function performs file and directory completion. It's better than
215# simply using 'compgen -f', because it honours spaces in filenames.
216# @param $1  If `-d', complete only on directories.  Otherwise filter/pick only
217#            completions with `.$1' and the uppercase version of it as file
218#            extension.
219#
220_filedir()
221{
222    local IFS=$'\n'
223
224    _tilde "$cur" || return
225
226    local -a toks
227    local x tmp
228
229    x=$( compgen -d -- "$cur" ) &&
230    while read -r tmp; do
231        toks+=( "$tmp" )
232    done <<< "$x"
233
234    if [[ "$1" != -d ]]; then
235        local quoted
236        _quote_readline_by_ref "$cur" quoted
237
238        # Munge xspec to contain uppercase version too
239        # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306
240        local xspec=${1:+"!*.@($1|${1^^})"}
241        x=$( compgen -f -X "$xspec" -- $quoted ) &&
242        while read -r tmp; do
243            toks+=( "$tmp" )
244        done <<< "$x"
245
246        # Try without filter if it failed to produce anything and configured to
247        [[ -n ${COMP_FILEDIR_FALLBACK:-} && -n "$1" && ${#toks[@]} -lt 1 ]] && \
248            x=$( compgen -f -- $quoted ) &&
249            while read -r tmp; do
250                toks+=( "$tmp" )
251            done <<< "$x"
252    fi
253
254    if [[ ${#toks[@]} -ne 0 ]]; then
255        # 2>/dev/null for direct invocation, e.g. in the _filedir unit test
256        _compopt_o_filenames
257        COMPREPLY+=( "${toks[@]}" )
258    fi
259} # _filedir()
260fi
261
262# Misc helpers taken from Docker:
263# https://github.com/docker/docker-ce/blob/master/components/cli/contrib/completion/bash/docker
264
265# __west_pos_first_nonflag finds the position of the first word that is neither
266# option nor an option's argument. If there are options that require arguments,
267# you should pass a glob describing those options, e.g. "--option1|-o|--option2"
268# Use this function to restrict completions to exact positions after the argument list.
269__west_pos_first_nonflag()
270{
271	local argument_flags=$1
272
273	local counter=$((${subcommand_pos:-${command_pos}} + 1))
274	while [ "$counter" -le "$cword" ]; do
275		if [ -n "$argument_flags" ] && eval "case '${words[$counter]}' in $argument_flags) true ;; *) false ;; esac"; then
276			(( counter++ ))
277			# eat "=" in case of --option=arg syntax
278			[ "${words[$counter]}" = "=" ] && (( counter++ ))
279		else
280			case "${words[$counter]}" in
281				-*)
282					;;
283				*)
284					break
285					;;
286			esac
287		fi
288
289		# Bash splits words at "=", retaining "=" as a word, examples:
290		# "--debug=false" => 3 words, "--log-opt syslog-facility=daemon" => 4 words
291		while [ "${words[$counter + 1]}" = "=" ] ; do
292			counter=$(( counter + 2))
293		done
294
295		(( counter++ ))
296	done
297
298	echo $counter
299}
300
301# __west_map_key_of_current_option returns `key` if we are currently completing the
302# value of a map option (`key=value`) which matches the extglob given as an argument.
303# This function is needed for key-specific completions.
304__west_map_key_of_current_option()
305{
306	local glob="$1"
307
308	local key glob_pos
309	if [ "$cur" = "=" ] ; then        # key= case
310		key="$prev"
311		glob_pos=$((cword - 2))
312	elif [[ $cur == *=* ]] ; then     # key=value case (OSX)
313		key=${cur%=*}
314		glob_pos=$((cword - 1))
315	elif [ "$prev" = "=" ] ; then
316		key=${words[$cword - 2]}  # key=value case
317		glob_pos=$((cword - 3))
318	else
319		return
320	fi
321
322	[ "${words[$glob_pos]}" = "=" ] && ((glob_pos--))  # --option=key=value syntax
323
324	[[ ${words[$glob_pos]} == @($glob) ]] && echo "$key"
325}
326
327# __west_value_of_option returns the value of the first option matching `option_glob`.
328# Valid values for `option_glob` are option names like `--log-level` and globs like
329# `--log-level|-l`
330# Only positions between the command and the current word are considered.
331__west_value_of_option()
332{
333	local option_extglob=$(__west_to_extglob "$1")
334
335	local counter=$((command_pos + 1))
336	while [ "$counter" -lt "$cword" ]; do
337		case ${words[$counter]} in
338			$option_extglob )
339				echo "${words[$counter + 1]}"
340				break
341				;;
342		esac
343		(( counter++ ))
344	done
345}
346
347# __west_to_alternatives transforms a multiline list of strings into a single line
348# string with the words separated by `|`.
349# This is used to prepare arguments to __west_pos_first_nonflag().
350__west_to_alternatives()
351{
352	local parts=( $1 )
353	local IFS='|'
354	echo "${parts[*]}"
355}
356
357# __west_to_extglob transforms a multiline list of options into an extglob pattern
358# suitable for use in case statements.
359__west_to_extglob()
360{
361	local extglob=$( __west_to_alternatives "$1" )
362	echo "@($extglob)"
363}
364
365__set_comp_dirs()
366{
367	_filedir -d
368}
369
370__set_comp_files()
371{
372	_filedir
373}
374
375# Sets completions for $cur, from the possibilities in $1..n
376__set_comp()
377{
378	# "${*:1}" gives a single argument with arguments $1..n
379	COMPREPLY=($(compgen -W "${*:1}" -- "$cur"))
380}
381
382
383__west_x()
384{
385	west 2>/dev/null "$@"
386}
387
388__set_comp_west_projs()
389{
390	__set_comp "$(__west_x list --format={name} "$@")"
391}
392
393__set_comp_west_boards()
394{
395	boards=( $(__west_x boards --format='{name}|{qualifiers}' "$@") )
396	for i in ${!boards[@]}; do
397		name="${boards[$i]%%|*}"
398		transformed_board="${boards[$i]//|//}"
399		boards[$i]="${transformed_board//,/\ ${name}\/}"
400	done
401	__set_comp ${boards[@]}
402}
403
404__set_comp_west_shields()
405{
406	__set_comp "$(__west_x shields "$@")"
407}
408
409__comp_west_west()
410{
411	case "$prev" in
412		--zephyr-base|-z)
413			__set_comp_dirs
414			return
415			;;
416		# We don't know how to autocomplete any others
417		$(__west_to_extglob "$global_args_opts") )
418			return
419			;;
420	esac
421
422	case "$cur" in
423		-*)
424			__set_comp $global_bool_opts $global_args_opts
425			;;
426		*)
427			local counter=$( __west_pos_first_nonflag "$(__west_to_extglob "$global_args_opts")" )
428			if [ "$cword" -eq "$counter" ]; then
429				__set_comp ${cmds[*]}
430			fi
431			;;
432	esac
433}
434
435__comp_west_init()
436{
437	local dir_opts="
438		--manifest -m
439		--local -l
440	"
441
442	local bool_opts="
443		--manifest-rev --mr
444		--manifest-file --mf
445	"
446
447	all_opts="$dir_opts $bool_opts"
448
449	case "$prev" in
450		$(__west_to_extglob "$dir_opts") )
451			__set_comp_dirs
452			return
453			;;
454	esac
455
456	case "$cur" in
457		-*)
458			__set_comp $all_opts
459			;;
460	esac
461}
462
463__comp_west_update()
464{
465	local bool_opts="
466		--stats
467		--narrow -n
468		--keep-descendants -k
469		--rebase -r
470	"
471
472	local dir_opts="
473		--name-cache
474		--path-cache
475	"
476
477	local other_opts="
478		--fetch -f
479		--fetch-opt -o
480	"
481
482	all_opts="$dir_opts $bool_opts $other_opts"
483
484	case "$prev" in
485		# We don't know how to autocomplete those
486		$(__west_to_extglob "$other_opts") )
487			return
488			;;
489
490		$(__west_to_extglob "$dir_opts") )
491			__set_comp_dirs
492			return
493			;;
494	esac
495
496	case "$cur" in
497		-*)
498			__set_comp $all_opts
499			;;
500		*)
501			__set_comp_west_projs
502			;;
503	esac
504}
505
506__comp_west_list()
507{
508	local other_opts="
509		--format -f
510	"
511
512	local bool_opts="
513		--all -a
514	"
515
516	all_opts="$other_opts $bool_opts"
517
518	case "$prev" in
519		# We don't know how to autocomplete those
520		$(__west_to_extglob "$other_opts") )
521			return
522			;;
523	esac
524
525	case "$cur" in
526		-*)
527			__set_comp $all_opts
528			;;
529		*)
530			__set_comp_west_projs
531			;;
532	esac
533}
534
535__comp_west_manifest()
536{
537	local bool_opts="
538		--resolve
539		--freeze
540		--validate
541		--path
542	"
543	local file_opts="
544		--out -o
545	"
546
547	all_opts="$bool_opts $file_opts"
548
549	case "$prev" in
550		$(__west_to_extglob "$file_opts") )
551			__set_comp_files
552			return
553			;;
554	esac
555
556	case "$cur" in
557		-*)
558			__set_comp $all_opts
559			;;
560	esac
561}
562
563__comp_west_diff()
564{
565	local bool_opts="
566		--all -a
567	"
568
569	case "$cur" in
570		-*)
571			__set_comp $bool_opts
572			;;
573		*)
574			__set_comp_west_projs
575			;;
576	esac
577}
578
579__comp_west_status()
580{
581	local bool_opts="
582		--all -a
583	"
584	case "$cur" in
585		-*)
586			__set_comp $bool_opts
587			;;
588		*)
589			__set_comp_west_projs
590			;;
591	esac
592}
593
594__comp_west_forall()
595{
596	local bool_opts="
597		--all -a
598	"
599	local other_opts="
600		-c
601	"
602
603	all_opts="$bool_opts $other_opts"
604	case "$prev" in
605		# We don't know how to autocomplete those
606		$(__west_to_extglob "$other_opts") )
607			return
608			;;
609	esac
610
611	case "$cur" in
612		-*)
613			__set_comp $all_opts
614			;;
615		*)
616			__set_comp_west_projs
617			;;
618	esac
619}
620
621__comp_west_config()
622{
623	local bool_opts="
624		--list -l
625		--delete -d
626		--delete-all -D
627		--global
628		--local
629		--system
630	"
631
632	case "$cur" in
633		-*)
634			__set_comp $bool_opts
635			;;
636	esac
637}
638
639__comp_west_help()
640{
641	case "$cur" in
642		*)
643			local counter=$( __west_pos_first_nonflag "$(__west_to_extglob "$global_args_opts")" )
644			if [ "$cword" -eq "$counter" ]; then
645				__set_comp ${cmds[*]}
646			fi
647			;;
648	esac
649}
650
651# Zephyr extension commands
652__comp_west_completion()
653{
654	case "$cur" in
655		*)
656			local counter=$( __west_pos_first_nonflag "$(__west_to_extglob "$global_args_opts")" )
657			if [ "$cword" -eq "$counter" ]; then
658				__set_comp "bash zsh fish"
659			fi
660			;;
661	esac
662}
663
664__comp_west_boards()
665{
666	local other_opts="
667		--format -f
668		--name -n
669	"
670
671	local dir_opts="
672		--arch-root
673		--board-root
674		--soc-root
675	"
676
677	all_opts="$dir_opts $other_opts"
678
679	case "$prev" in
680		$(__west_to_extglob "$other_opts") )
681			# We don't know how to autocomplete these.
682			return
683			;;
684		$(__west_to_extglob "$dir_opts") )
685			__set_comp_dirs
686			return
687			;;
688	esac
689
690	case "$cur" in
691		-*)
692			__set_comp $all_opts
693			;;
694	esac
695}
696
697__comp_west_shields()
698{
699	local other_opts="
700		--format -f
701		--name -n
702	"
703
704	local dir_opts="
705		--board-root
706	"
707
708	all_opts="$dir_opts $other_opts"
709
710	case "$prev" in
711		$(__west_to_extglob "$other_opts") )
712			# We don't know how to autocomplete these.
713			return
714			;;
715		$(__west_to_extglob "$dir_opts") )
716			__set_comp_dirs
717			return
718			;;
719	esac
720
721	case "$cur" in
722		-*)
723			__set_comp $all_opts
724			;;
725	esac
726}
727
728__comp_west_build()
729{
730	local bool_opts="
731		--cmake -c
732		--cmake-only
733		-n --just-print --dry-run --recon
734		--force -f
735		--sysbuild
736		--no-sysbuild
737	"
738
739	local special_opts="
740		--board -b
741		--snippet -S
742		--shield
743		--pristine -p
744	"
745
746	local dir_opts="
747		--build-dir -d
748	"
749
750	local other_opts="
751		--target -t
752		--test-item -T
753		--build-opt -o
754	"
755
756	all_opts="$bool_opts $special_opts $dir_opts $other_opts"
757
758	case "$prev" in
759		--board|-b)
760			__set_comp_west_boards
761			return
762			;;
763		--shield)
764			__set_comp_west_shields
765			return
766			;;
767		--pristine|-p)
768			__set_comp "auto always never"
769			return
770			;;
771		$(__west_to_extglob "$dir_opts") )
772			__set_comp_dirs
773			return
774			;;
775		# We don't know how to autocomplete those
776		$(__west_to_extglob "$other_opts") )
777			return
778			;;
779	esac
780
781	case "$cur" in
782		-*)
783			__set_comp $all_opts
784			;;
785		*)
786			__set_comp_dirs
787			;;
788	esac
789}
790
791__comp_west_sign()
792{
793	local bool_opts="
794		--quiet -q
795		--force -f
796		--bin --no-bin
797		--hex --no-hex
798	"
799
800	local special_opts="
801		--tool -t
802	"
803
804	local dir_opts="
805		--build-dir -d
806		--tool-path -p
807		--tool-data -D
808	"
809
810	local file_opts="
811		--sbin -B
812		--shex -H
813	"
814
815	all_opts="$bool_opts $special_opts $dir_opts $file_opts"
816
817	case "$prev" in
818		$(__west_to_extglob "$dir_opts") )
819			__set_comp_dirs
820			return
821			;;
822		--tool|-t)
823			__set_comp "imgtool rimage"
824			return
825			;;
826		$(__west_to_extglob "$file_opts") )
827			__set_comp_files
828			return
829			;;
830	esac
831
832	case "$cur" in
833		-*)
834			__set_comp $all_opts
835			;;
836	esac
837}
838
839__comp_west_runner_cmd()
840{
841	# Common arguments for runners
842	local bool_opts="
843		--context -H
844		--skip-rebuild
845	"
846
847	local dir_opts="
848		--board-dir
849		--openocd-search
850		--build-dir -d
851	"
852
853	local file_opts="
854		--file -f
855		--file-type -t
856		--elf-file
857		--hex-file
858		--bin-file
859		--gdb
860		--openocd
861	"
862
863	local other_opts="
864		--runner -r
865		--domain
866		--dev-id -i
867	"
868
869	all_opts="$bool_opts $other_opts $dir_opts $file_opts"
870
871	case "$prev" in
872		$(__west_to_extglob "$dir_opts") )
873			__set_comp_dirs
874			return
875			;;
876		$(__west_to_extglob "$file_opts") )
877			__set_comp_files
878			return
879			;;
880	esac
881
882	case "$cur" in
883		-*)
884			__set_comp $all_opts
885			;;
886	esac
887}
888
889__comp_west_flash()
890{
891	__comp_west_runner_cmd
892}
893
894__comp_west_debug()
895{
896	__comp_west_runner_cmd
897}
898
899__comp_west_debugserver()
900{
901	__comp_west_runner_cmd
902}
903
904__comp_west_attach()
905{
906	__comp_west_runner_cmd
907}
908
909__comp_west_spdx()
910{
911	local bool_opts="
912		--init -i
913		--analyze-includes
914		--include-sdk
915	"
916
917	local dir_opts="
918		--build-dir -d
919		--namespace-prefix -n
920		--spdx-dir -s
921	"
922
923	local other_opts="
924		--namespace-prefix -n
925	"
926
927	all_opts="$bool_opts $other_opts $dir_opts"
928
929	case "$prev" in
930		$(__west_to_extglob "$dir_opts") )
931			__set_comp_dirs
932			return
933			;;
934
935		# We don't know how to autocomplete those
936		$(__west_to_extglob "$other_opts") )
937			return
938			;;
939	esac
940
941	case "$cur" in
942		-*)
943			__set_comp $all_opts
944			;;
945	esac
946}
947
948__comp_west_blobs()
949{
950	local other_opts="
951		--format -f
952	"
953
954	case "$prev" in
955		# We don't know how to autocomplete those
956		$(__west_to_extglob "$other_opts") )
957			return
958			;;
959		blobs)
960			__set_comp "list fetch clean"
961			return
962			;;
963	esac
964
965	case "$cur" in
966		-*)
967			__set_comp $other_opts
968			;;
969		*)
970			__set_comp_west_projs
971			;;
972	esac
973}
974
975__comp_west_twister()
976{
977	local bool_opts="
978		--aggressive-no-clean
979		--all -l
980		--all-deltas -D
981		--allow-installed-plugin
982		--build-only -b
983		--clobber-output -c
984		--cmake-only
985		--coverage -C
986		--create-rom-ram-report
987		--detailed-skipped-report
988		--detailed-test-id
989		--device-flash-with-test
990		--device-testing
991		--disable-suite-name-check
992		--disable-unrecognized-section-test
993		--disable-warnings-as-errors -W
994		--dry-run -y
995		--emulation-only
996		--enable-asan
997		--enable-coverage
998		--enable-lsan
999		--enable-size-report
1000		--enable-slow -S
1001		--enable-slow-only
1002		--enable-ubsan
1003		--enable-valgrind
1004		--flash-before
1005		--footprint-from-buildlog
1006		--force-color
1007		--force-platform -K
1008		--force-toolchain
1009		--ignore-platform-key
1010		--inline-logs -i
1011		--integration -G
1012		--last-metrics -m
1013		--list-tags
1014		--list-tests
1015		--make -k
1016		--ninja -N
1017		--no-clean -n
1018		--no-detailed-test-id
1019		--no-update -u
1020		--only-failed -f
1021		--overflow-as-errors
1022		--persistent-hardware-map
1023		--platform-reports
1024		--prep-artifacts-for-testing
1025		--quarantine-verify
1026		--retry-build-errors
1027		--short-build-path
1028		--show-footprint
1029		--shuffle-tests
1030		--test-only
1031		--test-tree
1032		--timestamps
1033		--verbose -v
1034	"
1035
1036	local dir_opts="
1037		--alt-config-root
1038		--board-root -A
1039		--coverage-basedir
1040		--outdir -O
1041		--report-dir -o
1042		--testsuite-root -T
1043	"
1044
1045	local file_opts="
1046		--compare-report
1047		--device-serial
1048		--device-serial-pty
1049		--gcov-tool
1050		--generate-hardware-map
1051		--hardware-map
1052		--load-tests -F
1053		--log-file
1054		--package-artifacts
1055		--pre-script
1056		--quarantine-list
1057		--save-tests -E
1058		--size -z
1059		--test-config
1060	"
1061
1062	local special_opts="
1063		--coverage-platform
1064		--coverage-tool
1065		--exclude-platform -P
1066		--filter
1067                --log-level
1068		--platform -p
1069		--runtime-artifact-cleanup -M
1070	"
1071
1072	local other_opts="
1073		--arch -a
1074		--coverage-formats
1075		--device-flash-timeout
1076		--device-serial-baud
1077		--exclude-tag -e
1078		--extra-args -x
1079		--fixture -X
1080		--footprint-threshold -H
1081		--jobs -j
1082		--level
1083		--pytest-args
1084		--report-name
1085		--report-suffix
1086		--retry-failed
1087		--retry-interval
1088		--scenario --test -s
1089		--seed
1090		--shuffle-tests-seed
1091		--sub-test
1092		--subset -B
1093		--tag -t
1094		--timeout-multiplier
1095		--vendor
1096		--west-flash
1097		--west-runner
1098	"
1099
1100	all_opts="$bool_opts $dir_opts $file_opts $special_opts $other_opts"
1101
1102	case "$prev" in
1103		--platform|-p|--exclude-platform|-P|--coverage-platform)
1104			__set_comp_west_boards
1105			return
1106		        ;;
1107
1108		--coverage-tool)
1109		        __set_comp "gcovr lcov"
1110			return
1111		        ;;
1112
1113		--filter)
1114		        __set_comp "buildable runnable"
1115			return
1116		        ;;
1117
1118		--log-level)
1119		        __set_comp "CRITICAL DEBUG ERROR INFO NOTSET WARNING"
1120			return
1121		        ;;
1122
1123		--runtime-artifact-cleanup|-M)
1124		        __set_comp "all pass"
1125			return
1126		        ;;
1127
1128		$(__west_to_extglob "$dir_opts") )
1129			__set_comp_dirs
1130			return
1131			;;
1132
1133		$(__west_to_extglob "$file_opts") )
1134			__set_comp_files
1135			return
1136			;;
1137
1138		# We don't know how to autocomplete those
1139		$(__west_to_extglob "$other_opts") )
1140			return
1141			;;
1142	esac
1143
1144	case "$cur" in
1145		-*)
1146			__set_comp $all_opts
1147			;;
1148	esac
1149}
1150
1151__comp_west_sdk()
1152{
1153	local bool_opts="
1154		--interactive -i
1155		--no-toolchains -T
1156		--no-hosttools -H
1157	"
1158
1159	local dir_opts="
1160		--install-dir -d
1161		--install-base -b
1162	"
1163
1164	local other_opts="
1165		--version
1166		--toolchains -t
1167		--personal-access-token
1168		--api-url
1169	"
1170
1171	all_opts="$bool_opts $dir_opts $other_opts"
1172
1173	case "$prev" in
1174		sdk)
1175			__set_comp "list install"
1176			return
1177			;;
1178		list)
1179			return
1180			;;
1181		$(__west_to_extglob "$dir_opts") )
1182			__set_comp_dirs
1183			return
1184			;;
1185		# We don't know how to autocomplete those
1186		$(__west_to_extglob "$other_opts") )
1187			return
1188			;;
1189	esac
1190
1191	case "$cur" in
1192		-*)
1193			__set_comp $all_opts
1194			;;
1195	esac
1196}
1197
1198__comp_west()
1199{
1200	local previous_extglob_setting=$(shopt -p extglob)
1201	shopt -s extglob
1202	# Reset to default, to make sure compgen works properly
1203	local IFS=$' \t\n'
1204
1205	local builtin_cmds=(
1206		init
1207		update
1208		list
1209		manifest
1210		diff
1211		status
1212		forall
1213		config
1214		topdir
1215		help
1216	)
1217
1218	local zephyr_ext_cmds=(
1219		completion
1220		boards
1221		shields
1222		build
1223		sign
1224		flash
1225		debug
1226		debugserver
1227		attach
1228		zephyr-export
1229		spdx
1230		blobs
1231		twister
1232		sdk
1233	)
1234
1235	local cmds=(${builtin_cmds[*]} ${zephyr_ext_cmds[*]})
1236
1237	# Global options for all commands
1238	local global_bool_opts="
1239		--help -h
1240		--verbose -v
1241		--version -V
1242	"
1243	local global_args_opts="
1244		--zephyr-base -z
1245	"
1246
1247	COMPREPLY=()
1248	local cur words cword prev
1249	_get_comp_words_by_ref -n : cur words cword prev
1250
1251	local command='west' command_pos=0
1252	local counter=1
1253	while [ "$counter" -lt "$cword" ]; do
1254		case "${words[$counter]}" in
1255			west)
1256				return 0
1257				;;
1258			$(__west_to_extglob "$global_args_opts") )
1259				(( counter++ ))
1260				;;
1261			-*)
1262				;;
1263			=)
1264				(( counter++ ))
1265				;;
1266			*)
1267				command="${words[$counter]}"
1268				command_pos=$counter
1269				break
1270				;;
1271		esac
1272		(( counter++ ))
1273	done
1274
1275
1276	# Construct the function name to be called
1277	local completions_func=__comp_west_${command//-/_}
1278	#echo "comp_func: ${completions_func}"
1279	declare -F $completions_func >/dev/null && $completions_func
1280
1281	# Restore the user's extglob setting
1282	eval "$previous_extglob_setting"
1283	return 0
1284}
1285
1286eval "$__west_previous_extglob_setting"
1287unset __west_previous_extglob_setting
1288
1289complete -F __comp_west west
1290