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