# -*- mode: sh; -*- declare -A CMD_HANDLERS CMD_HANDLERS=( ["init"]=_repo_init ["help"]=_repo_help ["abandon"]=_repo_abandon ["branch"]=_repo_branch ["branches"]=_repo_branches ["checkout"]=_repo_checkout ["cherry-pick"]=_repo_cherry_pick ["diff"]=_repo_diff ["download"]=_repo_download ["forall"]=_repo_forall ["grep"]=_repo_grep ["list"]=_repo_list ["prune"]=_repo_prune ["rebase"]=_repo_rebase ["selfupdate"]=_repo_selfupdate ["smartsync"]=_repo_smartsync ["stage"]=_repo_stage ["start"]=_repo_start ["status"]=_repo_status ["sync"]=_repo_sync ["upload"]=_repo_upload ["version"]=_repo_version ) # To be populated by command handlers. declare -a OPTIONS declare -A ARG_OPTIONS declare cur declare prev _init_cur_prev() { cur=$(_get_cword "=") prev=$(_get_cword "=" 1) _split_longopt } _find_repo() { local dir=$(pwd) local found=1 while [ "${dir}" != / ] do if [ -e "${dir}/.repo/repo/main.py" ] then found=0 break fi dir=$(cd "${dir}/.." && pwd) done if [ ${found} -eq 0 ] then echo "${dir}" fi } _is_repo_dir() { local repo_root=$(_find_repo) [ -n "${repo_root}" ] } _gen_comps() { local completions="$1" local suffix="${2:- }" local -i i local -a tmp=( $(compgen -W "${completions}" -- ${cur}) ) for (( i=0; i < ${#tmp[*]}; i++ )) do tmp[$i]="${tmp[$i]}${suffix}" done COMPREPLY=( "${COMPREPLY[@]}" "${tmp[@]}" ) } _strip_colors () { # taken from http://goo.gl/7KlLZ sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" } _no_completion() { true } _command_completion() { local cmds if _is_repo_dir then cmds=("abandon" "branch" "branches" "checkout" "cherry-pick" "diff" "download" "forall" "grep" "help" "init" "list" "prune" "rebase" "selfupdate" "smartsync" "stage" "start" "status" "sync" "upload" "version") else cmds=("help" "init") fi _gen_comps "${cmds[*]}" } _branch_completion() { local raw_branches # separate statement required to be able to access exit code raw_branches=$(repo branches 2>/dev/null) if [ $? -eq 0 ] then local branches=$( echo "${raw_branches}" | _strip_colors | awk 'BEGIN { FS="|" } { print $1 }' | cut -c 3- ) _gen_comps "${branches}" fi } _dir_completion() { _filedir -d } _project_completion() { local repo_root=$(_find_repo) if [ -n "${repo_root}" -a -f "${repo_root}/.repo/project.list" ] then local projects=$(cat "${repo_root}/.repo/project.list") _gen_comps "${projects}" fi } _manifest_completion() { local repo_root=$(_find_repo) if [ -n "${repo_root}" ] then local manifests_dir="${repo_root}/.repo/manifests" local git_dir="${manifests_dir}/.git" local candidates manifests=$( git --git-dir "${git_dir}" ls-files "*.xml" 2>/dev/null) if [ $? -eq 0 ] then _gen_comps "${manifests}" fi fi } _path_cmd_completion() { _gen_comps "$(compgen -c ${cur})" } _is_option() { local opt="$1" [[ "${opt}" == -* ]] } _is_long_option() { local opt="$1" [[ "${opt}" == --* ]] } _expects_arg() { local opt="$1" if [[ ${ARG_OPTIONS[$opt]} ]] then return 0 else return 1 fi } _handle_options() { if _expects_arg "${prev}" then local handler=${ARG_OPTIONS[$prev]} eval ${handler} "${cur}" elif _is_option "${cur}" then _gen_comps "${OPTIONS[*]}" local arg_short local arg_long for opt in "${!ARG_OPTIONS[@]}" do if _is_long_option "${opt}" then arg_long="${arg_long} ${opt}" else arg_short="${arg_short} ${opt}" fi done _gen_comps "${arg_short}" _gen_comps "${arg_long}" "=" else return 1 fi return 0 } _is_known_shortopt() { local needle="$1" for opt in ${OPTIONS[@]} do if [ "${opt}" = "${needle}" ] then return 0 fi done return 1 } _is_known_longopt() { local needle="$1" [[ ${ARG_OPTIONS[$1]} ]] } _arg_index() { local -i i=2 # skip repo and command local -i ix=0 while [ ${i} -lt ${COMP_CWORD} ] do if _is_known_shortopt "${COMP_WORDS[i]}" then i+=1 elif _is_known_longopt "${COMP_WORDS[i]}" then i+=2 elif _is_option "${COMP_WORDS[i]}" then i+=1 else i+=1 ix+=1 fi done eval $1="${ix}" } _when_ix() { local ix="$1" local completion="$2" _arg_index arg_ix if [ ${arg_ix} -eq ${ix} ] then ${completion} return 0 else return 1 fi } _when_first() { _when_ix 0 "$1" } _when_even() { local completion="$1" _arg_index arg_ix if [ $(( ${arg_ix} % 2 )) -eq 0 ] then ${completion} return 0 else return 1 fi } _cmp_opts() { local opt="$1" local word="$2" if _is_option "${opt}" && ! _is_long_option "${opt}" then [ "${word}" == "${opt}" ] else [[ "${word}" == "${opt}"=* || "${word}" == "${opt}" ]] fi } _before() { local completion="$1" local words shift _get_comp_words_by_ref -n = words for word in "${words[@]}" do for needle in "$@" do if _cmp_opts "${needle}" "${word}" then return 1 fi done done ${completion} return 0 } _repo_init() { OPTIONS=( "-h" "--help" "-q" "--quite" "--mirror" "--no-repo-verify" ) ARG_OPTIONS=( ["-u"]=_no_completion ["--manifest-url"]=_no_completion ["-b"]=_no_completion ["--manifest-branch"]=_no_completion ["-m"]=_manifest_completion ["--manifest-name"]=_manifest_completion ["--reference"]=_dir_completion ["--repo-url"]=_no_completion ["--repo-branch"]=_no_completion ) _handle_options } _repo_help() { OPTIONS=( "-a" "--all" "-h" "--help" ) ARG_OPTIONS=() _handle_options || _when_first _command_completion } _repo_abandon() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options || _when_first _branch_completion || _project_completion } _repo_branch() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options } _repo_branches() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options } _repo_checkout() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options || _when_first _branch_completion || _project_completion } _repo_cherry_pick() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options } _repo_diff() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options || _project_completion } _repo_download() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options || _when_even _project_completion } _repo_forall() { OPTIONS=( "-h" "--help" "-p" "-v" "--verbose" ) ARG_OPTIONS=( ["-c"]=_path_cmd_completion ["--command"]=_path_cmd_completion ) _handle_options || _before _project_completion -c --command || _filedir } _repo_grep() { OPTIONS=( "-h" "--help" "--cached" "-r" "--revision" "-i" "--ignore-case" "-a" "--text" "-I" "-w" "--word-regexp" "-v" "--invert-match" "-G" "--basic-regexp" "-E" "--extended-regexp" "-F" "--fixed-strings" "--all-match" "--and" "--or" "--not" "-(" "-)" "-n" "-l" "--name-only" "--files-with-matches" "-L" "--files-without-match" ) ARG_OPTIONS=( ["-e"]=_no_completion ["-C"]=_no_completion ["-B"]=_no_completion ["-A"]=_no_completion ) _handle_options || _project_completion } _repo_list() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options || _project_completion } _repo_prune() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options || _project_completion } _repo_rebase() { OPTIONS=( "-h" "--help" "-i" "--interactive" "-f" "--force-rebase" "--no-ff" "-q" "--quiet" "--autosquash" ) ARG_OPTIONS=( ["--whitespace"]=_no_completion ) _handle_options || _project_completion } _repo_selfupdate() { OPTIONS=( "-h" "--help" "--no-repo-verify" ) ARG_OPTIONS=() _handle_options } _repo_smartsync() { OPTIONS=( "-h" "--help" "-f" "--force-broken" "-l" "--local-only" "-n" "--network-only" "-d" "--detach" "-q" "--quiet" "--no-repo-verify" ) ARG_OPTIONS=( ["-j"]=_no_completion ["--jobs"]=_no_completion ) _handle_options || _project_completion } _repo_stage() { OPTIONS=( "-h" "--help" "-i" "--interactive" ) ARG_OPTIONS=() _handle_options || _project_completion } _repo_start() { OPTIONS=( "-h" "--help" "--all" ) ARG_OPTIONS=() _handle_options || _when_first _branch_completion || _project_completion } _repo_status() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=( ["-j"]=_no_completion ["--jobs"]=_no_completion ) _handle_options || _project_completion } _repo_sync() { OPTIONS=( "-h" "--help" "-f" "--force-broken" "--force-sync" "-l" "--local-only" "-n" "--network-only" "-d" "--detach" "-q" "--quiet" "-s" "--smart-sync" "--no-repo-verify" ) ARG_OPTIONS=( ["-j"]=_no_completion ["--jobs"]=_no_completion ) _handle_options || _project_completion } _repo_upload() { OPTIONS=( "-h" "--help" "-t" "--no-verify" "--verify" ) ARG_OPTIONS=( ["--re"]=_no_completion ["--reviewers"]=_no_completion ["--cc"]=_no_completion ["--br"]=_branch_completion ) _handle_options || _project_completion } _repo_version() { OPTIONS=( "-h" "--help" ) ARG_OPTIONS=() _handle_options } _repo() { COMPREPLY=() _init_cur_prev if [ ${COMP_CWORD} -eq 1 ] then _command_completion else local cmd=${COMP_WORDS[1]} local handler=${CMD_HANDLERS["${cmd}"]} if [ -n ${handler} ] then eval ${handler} fi fi return 0 } complete -o nospace -F _repo repo