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		--domain
755	"
756
757	all_opts="$bool_opts $special_opts $dir_opts $other_opts"
758
759	case "$prev" in
760		--board|-b)
761			__set_comp_west_boards
762			return
763			;;
764		--shield)
765			__set_comp_west_shields
766			return
767			;;
768		--pristine|-p)
769			__set_comp "auto always never"
770			return
771			;;
772		$(__west_to_extglob "$dir_opts") )
773			__set_comp_dirs
774			return
775			;;
776		# We don't know how to autocomplete those
777		$(__west_to_extglob "$other_opts") )
778			return
779			;;
780	esac
781
782	case "$cur" in
783		-*)
784			__set_comp $all_opts
785			;;
786		*)
787			__set_comp_dirs
788			;;
789	esac
790}
791
792__comp_west_sign()
793{
794	local bool_opts="
795		--quiet -q
796		--force -f
797		--bin --no-bin
798		--hex --no-hex
799	"
800
801	local special_opts="
802		--tool -t
803	"
804
805	local dir_opts="
806		--build-dir -d
807		--tool-path -p
808		--tool-data -D
809	"
810
811	local file_opts="
812		--sbin -B
813		--shex -H
814	"
815
816	all_opts="$bool_opts $special_opts $dir_opts $file_opts"
817
818	case "$prev" in
819		$(__west_to_extglob "$dir_opts") )
820			__set_comp_dirs
821			return
822			;;
823		--tool|-t)
824			__set_comp "imgtool rimage"
825			return
826			;;
827		$(__west_to_extglob "$file_opts") )
828			__set_comp_files
829			return
830			;;
831	esac
832
833	case "$cur" in
834		-*)
835			__set_comp $all_opts
836			;;
837	esac
838}
839
840__comp_west_runner_cmd()
841{
842	# Common arguments for runners
843	local bool_opts="
844		--context -H
845		--skip-rebuild
846	"
847
848	local dir_opts="
849		--board-dir
850		--openocd-search
851		--build-dir -d
852	"
853
854	local file_opts="
855		--file -f
856		--file-type -t
857		--elf-file
858		--hex-file
859		--bin-file
860		--gdb
861		--openocd
862	"
863
864	local other_opts="
865		--runner -r
866		--domain
867		--dev-id -i
868	"
869
870	all_opts="$bool_opts $other_opts $dir_opts $file_opts"
871
872	case "$prev" in
873		$(__west_to_extglob "$dir_opts") )
874			__set_comp_dirs
875			return
876			;;
877		$(__west_to_extglob "$file_opts") )
878			__set_comp_files
879			return
880			;;
881	esac
882
883	case "$cur" in
884		-*)
885			__set_comp $all_opts
886			;;
887	esac
888}
889
890__comp_west_flash()
891{
892	__comp_west_runner_cmd
893}
894
895__comp_west_debug()
896{
897	__comp_west_runner_cmd
898}
899
900__comp_west_debugserver()
901{
902	__comp_west_runner_cmd
903}
904
905__comp_west_attach()
906{
907	__comp_west_runner_cmd
908}
909
910__comp_west_spdx()
911{
912	local bool_opts="
913		--init -i
914		--analyze-includes
915		--include-sdk
916	"
917
918	local dir_opts="
919		--build-dir -d
920		--namespace-prefix -n
921		--spdx-dir -s
922	"
923
924	local other_opts="
925		--namespace-prefix -n
926	"
927
928	all_opts="$bool_opts $other_opts $dir_opts"
929
930	case "$prev" in
931		$(__west_to_extglob "$dir_opts") )
932			__set_comp_dirs
933			return
934			;;
935
936		# We don't know how to autocomplete those
937		$(__west_to_extglob "$other_opts") )
938			return
939			;;
940	esac
941
942	case "$cur" in
943		-*)
944			__set_comp $all_opts
945			;;
946	esac
947}
948
949__comp_west_blobs()
950{
951	local other_opts="
952		--format -f
953	"
954
955	case "$prev" in
956		# We don't know how to autocomplete those
957		$(__west_to_extglob "$other_opts") )
958			return
959			;;
960		blobs)
961			__set_comp "list fetch clean"
962			return
963			;;
964	esac
965
966	case "$cur" in
967		-*)
968			__set_comp $other_opts
969			;;
970		*)
971			__set_comp_west_projs
972			;;
973	esac
974}
975
976__comp_west_twister()
977{
978	local bool_opts="
979		--aggressive-no-clean
980		--all -l
981		--all-deltas -D
982		--allow-installed-plugin
983		--build-only -b
984		--clobber-output -c
985		--cmake-only
986		--coverage -C
987		--create-rom-ram-report
988		--detailed-skipped-report
989		--detailed-test-id
990		--device-flash-with-test
991		--device-testing
992		--disable-suite-name-check
993		--disable-unrecognized-section-test
994		--disable-warnings-as-errors -W
995		--dry-run -y
996		--emulation-only
997		--enable-asan
998		--enable-coverage
999		--enable-lsan
1000		--enable-size-report
1001		--enable-slow -S
1002		--enable-slow-only
1003		--enable-ubsan
1004		--enable-valgrind
1005		--flash-before
1006		--footprint-from-buildlog
1007		--force-color
1008		--force-platform -K
1009		--force-toolchain
1010		--ignore-platform-key
1011		--inline-logs -i
1012		--integration -G
1013		--last-metrics -m
1014		--list-tags
1015		--list-tests
1016		--make -k
1017		--ninja -N
1018		--no-clean -n
1019		--no-detailed-test-id
1020		--no-update -u
1021		--only-failed -f
1022		--overflow-as-errors
1023		--persistent-hardware-map
1024		--platform-reports
1025		--prep-artifacts-for-testing
1026		--quarantine-verify
1027		--retry-build-errors
1028		--short-build-path
1029		--show-footprint
1030		--shuffle-tests
1031		--test-only
1032		--test-tree
1033		--timestamps
1034		--verbose -v
1035	"
1036
1037	local dir_opts="
1038		--alt-config-root
1039		--board-root -A
1040		--coverage-basedir
1041		--outdir -O
1042		--report-dir -o
1043		--testsuite-root -T
1044	"
1045
1046	local file_opts="
1047		--compare-report
1048		--device-serial
1049		--device-serial-pty
1050		--gcov-tool
1051		--generate-hardware-map
1052		--hardware-map
1053		--load-tests -F
1054		--log-file
1055		--package-artifacts
1056		--pre-script
1057		--quarantine-list
1058		--save-tests -E
1059		--size -z
1060		--test-config
1061	"
1062
1063	local special_opts="
1064		--coverage-platform
1065		--coverage-tool
1066		--exclude-platform -P
1067		--filter
1068                --log-level
1069		--platform -p
1070		--runtime-artifact-cleanup -M
1071	"
1072
1073	local other_opts="
1074		--arch -a
1075		--coverage-formats
1076		--device-flash-timeout
1077		--device-serial-baud
1078		--exclude-tag -e
1079		--extra-args -x
1080		--fixture -X
1081		--footprint-threshold -H
1082		--jobs -j
1083		--level
1084		--pytest-args
1085		--report-name
1086		--report-suffix
1087		--retry-failed
1088		--retry-interval
1089		--scenario --test -s
1090		--seed
1091		--shuffle-tests-seed
1092		--sub-test
1093		--subset -B
1094		--tag -t
1095		--timeout-multiplier
1096		--vendor
1097		--west-flash
1098		--west-runner
1099	"
1100
1101	all_opts="$bool_opts $dir_opts $file_opts $special_opts $other_opts"
1102
1103	case "$prev" in
1104		--platform|-p|--exclude-platform|-P|--coverage-platform)
1105			__set_comp_west_boards
1106			return
1107		        ;;
1108
1109		--coverage-tool)
1110		        __set_comp "gcovr lcov"
1111			return
1112		        ;;
1113
1114		--filter)
1115		        __set_comp "buildable runnable"
1116			return
1117		        ;;
1118
1119		--log-level)
1120		        __set_comp "CRITICAL DEBUG ERROR INFO NOTSET WARNING"
1121			return
1122		        ;;
1123
1124		--runtime-artifact-cleanup|-M)
1125		        __set_comp "all pass"
1126			return
1127		        ;;
1128
1129		$(__west_to_extglob "$dir_opts") )
1130			__set_comp_dirs
1131			return
1132			;;
1133
1134		$(__west_to_extglob "$file_opts") )
1135			__set_comp_files
1136			return
1137			;;
1138
1139		# We don't know how to autocomplete those
1140		$(__west_to_extglob "$other_opts") )
1141			return
1142			;;
1143	esac
1144
1145	case "$cur" in
1146		-*)
1147			__set_comp $all_opts
1148			;;
1149	esac
1150}
1151
1152__comp_west_sdk()
1153{
1154	local bool_opts="
1155		--interactive -i
1156		--no-toolchains -T
1157		--no-hosttools -H
1158	"
1159
1160	local dir_opts="
1161		--install-dir -d
1162		--install-base -b
1163	"
1164
1165	local other_opts="
1166		--version
1167		--toolchains -t
1168		--personal-access-token
1169		--api-url
1170	"
1171
1172	all_opts="$bool_opts $dir_opts $other_opts"
1173
1174	case "$prev" in
1175		sdk)
1176			__set_comp "list install"
1177			return
1178			;;
1179		list)
1180			return
1181			;;
1182		$(__west_to_extglob "$dir_opts") )
1183			__set_comp_dirs
1184			return
1185			;;
1186		# We don't know how to autocomplete those
1187		$(__west_to_extglob "$other_opts") )
1188			return
1189			;;
1190	esac
1191
1192	case "$cur" in
1193		-*)
1194			__set_comp $all_opts
1195			;;
1196	esac
1197}
1198
1199__comp_west()
1200{
1201	local previous_extglob_setting=$(shopt -p extglob)
1202	shopt -s extglob
1203	# Reset to default, to make sure compgen works properly
1204	local IFS=$' \t\n'
1205
1206	local builtin_cmds=(
1207		init
1208		update
1209		list
1210		manifest
1211		diff
1212		status
1213		forall
1214		config
1215		topdir
1216		help
1217	)
1218
1219	local zephyr_ext_cmds=(
1220		completion
1221		boards
1222		shields
1223		build
1224		sign
1225		flash
1226		debug
1227		debugserver
1228		attach
1229		zephyr-export
1230		spdx
1231		blobs
1232		twister
1233		sdk
1234	)
1235
1236	local cmds=(${builtin_cmds[*]} ${zephyr_ext_cmds[*]})
1237
1238	# Global options for all commands
1239	local global_bool_opts="
1240		--help -h
1241		--verbose -v
1242		--version -V
1243	"
1244	local global_args_opts="
1245		--zephyr-base -z
1246	"
1247
1248	COMPREPLY=()
1249	local cur words cword prev
1250	_get_comp_words_by_ref -n : cur words cword prev
1251
1252	local command='west' command_pos=0
1253	local counter=1
1254	while [ "$counter" -lt "$cword" ]; do
1255		case "${words[$counter]}" in
1256			west)
1257				return 0
1258				;;
1259			$(__west_to_extglob "$global_args_opts") )
1260				(( counter++ ))
1261				;;
1262			-*)
1263				;;
1264			=)
1265				(( counter++ ))
1266				;;
1267			*)
1268				command="${words[$counter]}"
1269				command_pos=$counter
1270				break
1271				;;
1272		esac
1273		(( counter++ ))
1274	done
1275
1276
1277	# Construct the function name to be called
1278	local completions_func=__comp_west_${command//-/_}
1279	#echo "comp_func: ${completions_func}"
1280	declare -F $completions_func >/dev/null && $completions_func
1281
1282	# Restore the user's extglob setting
1283	eval "$previous_extglob_setting"
1284	return 0
1285}
1286
1287eval "$__west_previous_extglob_setting"
1288unset __west_previous_extglob_setting
1289
1290complete -F __comp_west west
1291