diff options
-rw-r--r-- | commands/root.go | 8 | ||||
-rw-r--r-- | misc/bash_completion/git-bug | 1618 | ||||
-rw-r--r-- | misc/gen_completion.go | 36 |
3 files changed, 189 insertions, 1473 deletions
diff --git a/commands/root.go b/commands/root.go index e7848363..e012bd83 100644 --- a/commands/root.go +++ b/commands/root.go @@ -50,14 +50,6 @@ the same git remote you are already using to collaborate with other people. SilenceUsage: true, DisableAutoGenTag: true, - - // Custom bash code to connect the git completion for "git bug" to the - // git-bug completion for "git-bug" - BashCompletionFunction: ` -_git_bug() { - __start_git-bug "$@" -} -`, } cmd.AddCommand(newAddCommand()) diff --git a/misc/bash_completion/git-bug b/misc/bash_completion/git-bug index ab023c71..dec15576 100644 --- a/misc/bash_completion/git-bug +++ b/misc/bash_completion/git-bug @@ -1,4 +1,4 @@ -# bash completion for git-bug -*- shell-script -*- +#TODO: completion code to map "git bug" to "git-bug"# bash completion V2 for git-bug -*- shell-script -*- __git-bug_debug() { @@ -7,64 +7,43 @@ __git-bug_debug() fi } -# Homebrew on Macs have version 1.3 of bash-completion which doesn't include -# _init_completion. This is a very minimal version of that function. +# Macs have bash3 for which the bash-completion package doesn't include +# _init_completion. This is a minimal version of that function. __git-bug_init_completion() { COMPREPLY=() _get_comp_words_by_ref "$@" cur prev words cword } -__git-bug_index_of_word() -{ - local w word=$1 - shift - index=0 - for w in "$@"; do - [[ $w = "$word" ]] && return - index=$((index+1)) - done - index=-1 -} - -__git-bug_contains_word() -{ - local w word=$1; shift - for w in "$@"; do - [[ $w = "$word" ]] && return - done - return 1 -} - -__git-bug_handle_go_custom_completion() -{ - __git-bug_debug "${FUNCNAME[0]}: cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}" - - local shellCompDirectiveError=1 - local shellCompDirectiveNoSpace=2 - local shellCompDirectiveNoFileComp=4 - local shellCompDirectiveFilterFileExt=8 - local shellCompDirectiveFilterDirs=16 - - local out requestComp lastParam lastChar comp directive args +# This function calls the git-bug program to obtain the completion +# results and the directive. It fills the 'out' and 'directive' vars. +__git-bug_get_completion_results() { + local requestComp lastParam lastChar args # Prepare the command to request completions for the program. # Calling ${words[0]} instead of directly git-bug allows to handle aliases args=("${words[@]:1}") - requestComp="${words[0]} __completeNoDesc ${args[*]}" + requestComp="${words[0]} __complete ${args[*]}" lastParam=${words[$((${#words[@]}-1))]} lastChar=${lastParam:$((${#lastParam}-1)):1} - __git-bug_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}" + __git-bug_debug "lastParam ${lastParam}, lastChar ${lastChar}" if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. - __git-bug_debug "${FUNCNAME[0]}: Adding extra empty parameter" - requestComp="${requestComp} \"\"" + __git-bug_debug "Adding extra empty parameter" + requestComp="${requestComp} ''" fi - __git-bug_debug "${FUNCNAME[0]}: calling ${requestComp}" + # When completing a flag with an = (e.g., git-bug -n=<TAB>) + # bash focuses on the part after the =, so we need to remove + # the flag part from $cur + if [[ "${cur}" == -*=* ]]; then + cur="${cur#*=}" + fi + + __git-bug_debug "Calling ${requestComp}" # Use eval to handle any environment variables and such out=$(eval "${requestComp}" 2>/dev/null) @@ -76,24 +55,36 @@ __git-bug_handle_go_custom_completion() # There is not directive specified directive=0 fi - __git-bug_debug "${FUNCNAME[0]}: the completion directive is: ${directive}" - __git-bug_debug "${FUNCNAME[0]}: the completions are: ${out[*]}" + __git-bug_debug "The completion directive is: ${directive}" + __git-bug_debug "The completions are: ${out[*]}" +} + +__git-bug_process_completion_results() { + local shellCompDirectiveError=1 + local shellCompDirectiveNoSpace=2 + local shellCompDirectiveNoFileComp=4 + local shellCompDirectiveFilterFileExt=8 + local shellCompDirectiveFilterDirs=16 if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then # Error code. No completion. - __git-bug_debug "${FUNCNAME[0]}: received error from custom completion go code" + __git-bug_debug "Received error from custom completion go code" return else if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then - __git-bug_debug "${FUNCNAME[0]}: activating no space" + __git-bug_debug "Activating no space" compopt -o nospace + else + __git-bug_debug "No space directive not supported in this version of bash" fi fi if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then if [[ $(type -t compopt) = "builtin" ]]; then - __git-bug_debug "${FUNCNAME[0]}: activating no file completion" + __git-bug_debug "Activating no file completion" compopt +o default + else + __git-bug_debug "No file completion directive not supported in this version of bash" fi fi fi @@ -101,6 +92,7 @@ __git-bug_handle_go_custom_completion() if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local fullFilter filter filteringCmd + # Do not use quotes around the $out variable or else newline # characters will be kept. for filter in ${out[*]}; do @@ -112,1471 +104,179 @@ __git-bug_handle_go_custom_completion() $filteringCmd elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then # File completion for directories only - local subdir + # Use printf to strip any trailing newline + local subdir subdir=$(printf "%s" "${out[0]}") if [ -n "$subdir" ]; then __git-bug_debug "Listing directories in $subdir" - __git-bug_handle_subdirs_in_dir_flag "$subdir" + pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return else __git-bug_debug "Listing directories in ." _filedir -d fi else - while IFS='' read -r comp; do - COMPREPLY+=("$comp") - done < <(compgen -W "${out[*]}" -- "$cur") + __git-bug_handle_completion_types fi + + __git-bug_handle_special_char "$cur" : + __git-bug_handle_special_char "$cur" = } -__git-bug_handle_reply() -{ - __git-bug_debug "${FUNCNAME[0]}" - local comp - case $cur in - -*) - if [[ $(type -t compopt) = "builtin" ]]; then - compopt -o nospace - fi - local allflags - if [ ${#must_have_one_flag[@]} -ne 0 ]; then - allflags=("${must_have_one_flag[@]}") - else - allflags=("${flags[*]} ${two_word_flags[*]}") - fi - while IFS='' read -r comp; do +__git-bug_handle_completion_types() { + __git-bug_debug "__git-bug_handle_completion_types: COMP_TYPE is $COMP_TYPE" + + case $COMP_TYPE in + 37|42) + # Type: menu-complete/menu-complete-backward and insert-completions + # If the user requested inserting one completion at a time, or all + # completions at once on the command-line we must remove the descriptions. + # https://github.com/spf13/cobra/issues/1508 + local tab comp + tab=$(printf '\t') + while IFS='' read -r comp; do + # Strip any description + comp=${comp%%$tab*} + # Only consider the completions that match + comp=$(compgen -W "$comp" -- "$cur") + if [ -n "$comp" ]; then COMPREPLY+=("$comp") - done < <(compgen -W "${allflags[*]}" -- "$cur") - if [[ $(type -t compopt) = "builtin" ]]; then - [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace fi + done < <(printf "%s\n" "${out[@]}") + ;; - # complete after --flag=abc - if [[ $cur == *=* ]]; then - if [[ $(type -t compopt) = "builtin" ]]; then - compopt +o nospace - fi + *) + # Type: complete (normal completion) + __git-bug_handle_standard_completion_case + ;; + esac +} - local index flag - flag="${cur%=*}" - __git-bug_index_of_word "${flag}" "${flags_with_completion[@]}" - COMPREPLY=() - if [[ ${index} -ge 0 ]]; then - PREFIX="" - cur="${cur#*=}" - ${flags_completion[${index}]} - if [ -n "${ZSH_VERSION:-}" ]; then - # zsh completion needs --flag= prefix - eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" - fi - fi - fi +__git-bug_handle_standard_completion_case() { + local tab comp + tab=$(printf '\t') - if [[ -z "${flag_parsing_disabled}" ]]; then - # If flag parsing is enabled, we have completed the flags and can return. - # If flag parsing is disabled, we may not know all (or any) of the flags, so we fallthrough - # to possibly call handle_go_custom_completion. - return 0; - fi - ;; - esac + local longest=0 + # Look for the longest completion so that we can format things nicely + while IFS='' read -r comp; do + # Strip any description before checking the length + comp=${comp%%$tab*} + # Only consider the completions that match + comp=$(compgen -W "$comp" -- "$cur") + if ((${#comp}>longest)); then + longest=${#comp} + fi + done < <(printf "%s\n" "${out[@]}") - # check if we are handling a flag with special work handling - local index - __git-bug_index_of_word "${prev}" "${flags_with_completion[@]}" - if [[ ${index} -ge 0 ]]; then - ${flags_completion[${index}]} - return - fi + local completions=() + while IFS='' read -r comp; do + if [ -z "$comp" ]; then + continue + fi - # we are parsing a flag and don't have a special handler, no completion - if [[ ${cur} != "${words[cword]}" ]]; then - return - fi + __git-bug_debug "Original comp: $comp" + comp="$(__git-bug_format_comp_descriptions "$comp" "$longest")" + __git-bug_debug "Final comp: $comp" + completions+=("$comp") + done < <(printf "%s\n" "${out[@]}") - local completions - completions=("${commands[@]}") - if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then - completions+=("${must_have_one_noun[@]}") - elif [[ -n "${has_completion_function}" ]]; then - # if a go completion function is provided, defer to that function - __git-bug_handle_go_custom_completion - fi - if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then - completions+=("${must_have_one_flag[@]}") - fi while IFS='' read -r comp; do COMPREPLY+=("$comp") done < <(compgen -W "${completions[*]}" -- "$cur") - if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then - while IFS='' read -r comp; do - COMPREPLY+=("$comp") - done < <(compgen -W "${noun_aliases[*]}" -- "$cur") - fi - - if [[ ${#COMPREPLY[@]} -eq 0 ]]; then - if declare -F __git-bug_custom_func >/dev/null; then - # try command name qualified custom func - __git-bug_custom_func - else - # otherwise fall back to unqualified for compatibility - declare -F __custom_func >/dev/null && __custom_func - fi - fi - - # available in bash-completion >= 2, not always present on macOS - if declare -F __ltrim_colon_completions >/dev/null; then - __ltrim_colon_completions "$cur" - fi - - # If there is only 1 completion and it is a flag with an = it will be completed - # but we don't want a space after the = - if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then - compopt -o nospace + # If there is a single completion left, remove the description text + if [ ${#COMPREPLY[*]} -eq 1 ]; then + __git-bug_debug "COMPREPLY[0]: ${COMPREPLY[0]}" + comp="${COMPREPLY[0]%% *}" + __git-bug_debug "Removed description from single completion, which is now: ${comp}" + COMPREPLY=() + COMPREPLY+=("$comp") fi } -# The arguments should be in the form "ext1|ext2|extn" -__git-bug_handle_filename_extension_flag() -{ - local ext="$1" - _filedir "@(${ext})" -} - -__git-bug_handle_subdirs_in_dir_flag() +__git-bug_handle_special_char() { - local dir="$1" - pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return -} - -__git-bug_handle_flag() -{ - __git-bug_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - # if a command required a flag, and we found it, unset must_have_one_flag() - local flagname=${words[c]} - local flagvalue="" - # if the word contained an = - if [[ ${words[c]} == *"="* ]]; then - flagvalue=${flagname#*=} # take in as flagvalue after the = - flagname=${flagname%=*} # strip everything after the = - flagname="${flagname}=" # but put the = back - fi - __git-bug_debug "${FUNCNAME[0]}: looking for ${flagname}" - if __git-bug_contains_word "${flagname}" "${must_have_one_flag[@]}"; then - must_have_one_flag=() - fi - - # if you set a flag which only applies to this command, don't show subcommands - if __git-bug_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then - commands=() - fi - - # keep flag value with flagname as flaghash - # flaghash variable is an associative array which is only supported in bash > 3. - if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then - if [ -n "${flagvalue}" ] ; then - flaghash[${flagname}]=${flagvalue} - elif [ -n "${words[ $((c+1)) ]}" ] ; then - flaghash[${flagname}]=${words[ $((c+1)) ]} - else - flaghash[${flagname}]="true" # pad "true" for bool flag - fi - fi - - # skip the argument to a two word flag - if [[ ${words[c]} != *"="* ]] && __git-bug_contains_word "${words[c]}" "${two_word_flags[@]}"; then - __git-bug_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" - c=$((c+1)) - # if we are looking for a flags value, don't show commands - if [[ $c -eq $cword ]]; then - commands=() - fi + local comp="$1" + local char=$2 + if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then + local word=${comp%"${comp##*${char}}"} + local idx=${#COMPREPLY[*]} + while [[ $((--idx)) -ge 0 ]]; do + COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + done fi - - c=$((c+1)) - } -__git-bug_handle_noun() +__git-bug_format_comp_descriptions() { - __git-bug_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + local tab + tab=$(printf '\t') + local comp="$1" + local longest=$2 - if __git-bug_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then - must_have_one_noun=() - elif __git-bug_contains_word "${words[c]}" "${noun_aliases[@]}"; then - must_have_one_noun=() - fi + # Properly format the description string which follows a tab character if there is one + if [[ "$comp" == *$tab* ]]; then + desc=${comp#*$tab} + comp=${comp%%$tab*} - nouns+=("${words[c]}") - c=$((c+1)) -} - -__git-bug_handle_command() -{ - __git-bug_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + # $COLUMNS stores the current shell width. + # Remove an extra 4 because we add 2 spaces and 2 parentheses. + maxdesclength=$(( COLUMNS - longest - 4 )) - local next_command - if [[ -n ${last_command} ]]; then - next_command="_${last_command}_${words[c]//:/__}" - else - if [[ $c -eq 0 ]]; then - next_command="_git-bug_root_command" + # Make sure we can fit a description of at least 8 characters + # if we are to align the descriptions. + if [[ $maxdesclength -gt 8 ]]; then + # Add the proper number of spaces to align the descriptions + for ((i = ${#comp} ; i < longest ; i++)); do + comp+=" " + done else - next_command="_${words[c]//:/__}" + # Don't pad the descriptions so we can fit more text after the completion + maxdesclength=$(( COLUMNS - ${#comp} - 4 )) fi - fi - c=$((c+1)) - __git-bug_debug "${FUNCNAME[0]}: looking for ${next_command}" - declare -F "$next_command" >/dev/null && $next_command -} -__git-bug_handle_word() -{ - if [[ $c -ge $cword ]]; then - __git-bug_handle_reply - return - fi - __git-bug_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - if [[ "${words[c]}" == -* ]]; then - __git-bug_handle_flag - elif __git-bug_contains_word "${words[c]}" "${commands[@]}"; then - __git-bug_handle_command - elif [[ $c -eq 0 ]]; then - __git-bug_handle_command - elif __git-bug_contains_word "${words[c]}" "${command_aliases[@]}"; then - # aliashash variable is an associative array which is only supported in bash > 3. - if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then - words[c]=${aliashash[${words[c]}]} - __git-bug_handle_command - else - __git-bug_handle_noun + # If there is enough space for any description text, + # truncate the descriptions that are too long for the shell width + if [ $maxdesclength -gt 0 ]; then + if [ ${#desc} -gt $maxdesclength ]; then + desc=${desc:0:$(( maxdesclength - 1 ))} + desc+="…" + fi + comp+=" ($desc)" fi - else - __git-bug_handle_noun fi - __git-bug_handle_word -} - -_git_bug() { - __start_git-bug "$@" -} - -_git-bug_add() -{ - last_command="git-bug_add" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--title=") - two_word_flags+=("--title") - two_word_flags+=("-t") - local_nonpersistent_flags+=("--title") - local_nonpersistent_flags+=("--title=") - local_nonpersistent_flags+=("-t") - flags+=("--message=") - two_word_flags+=("--message") - two_word_flags+=("-m") - local_nonpersistent_flags+=("--message") - local_nonpersistent_flags+=("--message=") - local_nonpersistent_flags+=("-m") - flags+=("--file=") - two_word_flags+=("--file") - two_word_flags+=("-F") - local_nonpersistent_flags+=("--file") - local_nonpersistent_flags+=("--file=") - local_nonpersistent_flags+=("-F") - flags+=("--non-interactive") - local_nonpersistent_flags+=("--non-interactive") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_bridge_auth_add-token() -{ - last_command="git-bug_bridge_auth_add-token" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--target=") - two_word_flags+=("--target") - flags_with_completion+=("--target") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-t") - flags_with_completion+=("-t") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--target") - local_nonpersistent_flags+=("--target=") - local_nonpersistent_flags+=("-t") - flags+=("--login=") - two_word_flags+=("--login") - two_word_flags+=("-l") - local_nonpersistent_flags+=("--login") - local_nonpersistent_flags+=("--login=") - local_nonpersistent_flags+=("-l") - flags+=("--user=") - two_word_flags+=("--user") - flags_with_completion+=("--user") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-u") - flags_with_completion+=("-u") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--user") - local_nonpersistent_flags+=("--user=") - local_nonpersistent_flags+=("-u") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_bridge_auth_rm() -{ - last_command="git-bug_bridge_auth_rm" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_bridge_auth_show() -{ - last_command="git-bug_bridge_auth_show" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_bridge_auth() -{ - last_command="git-bug_bridge_auth" - - command_aliases=() - - commands=() - commands+=("add-token") - commands+=("rm") - commands+=("show") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_bridge_configure() -{ - last_command="git-bug_bridge_configure" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--name=") - two_word_flags+=("--name") - two_word_flags+=("-n") - local_nonpersistent_flags+=("--name") - local_nonpersistent_flags+=("--name=") - local_nonpersistent_flags+=("-n") - flags+=("--target=") - two_word_flags+=("--target") - flags_with_completion+=("--target") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-t") - flags_with_completion+=("-t") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--target") - local_nonpersistent_flags+=("--target=") - local_nonpersistent_flags+=("-t") - flags+=("--url=") - two_word_flags+=("--url") - two_word_flags+=("-u") - local_nonpersistent_flags+=("--url") - local_nonpersistent_flags+=("--url=") - local_nonpersistent_flags+=("-u") - flags+=("--base-url=") - two_word_flags+=("--base-url") - two_word_flags+=("-b") - local_nonpersistent_flags+=("--base-url") - local_nonpersistent_flags+=("--base-url=") - local_nonpersistent_flags+=("-b") - flags+=("--login=") - two_word_flags+=("--login") - two_word_flags+=("-l") - local_nonpersistent_flags+=("--login") - local_nonpersistent_flags+=("--login=") - local_nonpersistent_flags+=("-l") - flags+=("--credential=") - two_word_flags+=("--credential") - two_word_flags+=("-c") - local_nonpersistent_flags+=("--credential") - local_nonpersistent_flags+=("--credential=") - local_nonpersistent_flags+=("-c") - flags+=("--token=") - two_word_flags+=("--token") - local_nonpersistent_flags+=("--token") - local_nonpersistent_flags+=("--token=") - flags+=("--token-stdin") - local_nonpersistent_flags+=("--token-stdin") - flags+=("--owner=") - two_word_flags+=("--owner") - two_word_flags+=("-o") - local_nonpersistent_flags+=("--owner") - local_nonpersistent_flags+=("--owner=") - local_nonpersistent_flags+=("-o") - flags+=("--project=") - two_word_flags+=("--project") - two_word_flags+=("-p") - local_nonpersistent_flags+=("--project") - local_nonpersistent_flags+=("--project=") - local_nonpersistent_flags+=("-p") - flags+=("--non-interactive") - local_nonpersistent_flags+=("--non-interactive") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_bridge_pull() -{ - last_command="git-bug_bridge_pull" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--no-resume") - flags+=("-n") - local_nonpersistent_flags+=("--no-resume") - local_nonpersistent_flags+=("-n") - flags+=("--since=") - two_word_flags+=("--since") - two_word_flags+=("-s") - local_nonpersistent_flags+=("--since") - local_nonpersistent_flags+=("--since=") - local_nonpersistent_flags+=("-s") - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_bridge_push() -{ - last_command="git-bug_bridge_push" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_bridge_rm() -{ - last_command="git-bug_bridge_rm" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_bridge() -{ - last_command="git-bug_bridge" - - command_aliases=() - - commands=() - commands+=("auth") - commands+=("configure") - commands+=("pull") - commands+=("push") - commands+=("rm") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_commands() -{ - last_command="git-bug_commands" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--pretty") - flags+=("-p") - local_nonpersistent_flags+=("--pretty") - local_nonpersistent_flags+=("-p") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_comment_add() -{ - last_command="git-bug_comment_add" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--file=") - two_word_flags+=("--file") - two_word_flags+=("-F") - local_nonpersistent_flags+=("--file") - local_nonpersistent_flags+=("--file=") - local_nonpersistent_flags+=("-F") - flags+=("--message=") - two_word_flags+=("--message") - two_word_flags+=("-m") - local_nonpersistent_flags+=("--message") - local_nonpersistent_flags+=("--message=") - local_nonpersistent_flags+=("-m") - flags+=("--non-interactive") - local_nonpersistent_flags+=("--non-interactive") - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_comment_edit() -{ - last_command="git-bug_comment_edit" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--file=") - two_word_flags+=("--file") - two_word_flags+=("-F") - local_nonpersistent_flags+=("--file") - local_nonpersistent_flags+=("--file=") - local_nonpersistent_flags+=("-F") - flags+=("--message=") - two_word_flags+=("--message") - two_word_flags+=("-m") - local_nonpersistent_flags+=("--message") - local_nonpersistent_flags+=("--message=") - local_nonpersistent_flags+=("-m") - flags+=("--non-interactive") - local_nonpersistent_flags+=("--non-interactive") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_comment() -{ - last_command="git-bug_comment" - - command_aliases=() - - commands=() - commands+=("add") - commands+=("edit") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_deselect() -{ - last_command="git-bug_deselect" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_label_add() -{ - last_command="git-bug_label_add" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_label_rm() -{ - last_command="git-bug_label_rm" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_label() -{ - last_command="git-bug_label" - - command_aliases=() - - commands=() - commands+=("add") - commands+=("rm") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_ls() -{ - last_command="git-bug_ls" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--status=") - two_word_flags+=("--status") - flags_with_completion+=("--status") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-s") - flags_with_completion+=("-s") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--status") - local_nonpersistent_flags+=("--status=") - local_nonpersistent_flags+=("-s") - flags+=("--author=") - two_word_flags+=("--author") - flags_with_completion+=("--author") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-a") - flags_with_completion+=("-a") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--author") - local_nonpersistent_flags+=("--author=") - local_nonpersistent_flags+=("-a") - flags+=("--metadata=") - two_word_flags+=("--metadata") - two_word_flags+=("-m") - local_nonpersistent_flags+=("--metadata") - local_nonpersistent_flags+=("--metadata=") - local_nonpersistent_flags+=("-m") - flags+=("--participant=") - two_word_flags+=("--participant") - flags_with_completion+=("--participant") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-p") - flags_with_completion+=("-p") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--participant") - local_nonpersistent_flags+=("--participant=") - local_nonpersistent_flags+=("-p") - flags+=("--actor=") - two_word_flags+=("--actor") - flags_with_completion+=("--actor") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-A") - flags_with_completion+=("-A") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--actor") - local_nonpersistent_flags+=("--actor=") - local_nonpersistent_flags+=("-A") - flags+=("--label=") - two_word_flags+=("--label") - flags_with_completion+=("--label") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-l") - flags_with_completion+=("-l") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--label") - local_nonpersistent_flags+=("--label=") - local_nonpersistent_flags+=("-l") - flags+=("--title=") - two_word_flags+=("--title") - two_word_flags+=("-t") - local_nonpersistent_flags+=("--title") - local_nonpersistent_flags+=("--title=") - local_nonpersistent_flags+=("-t") - flags+=("--no=") - two_word_flags+=("--no") - flags_with_completion+=("--no") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-n") - flags_with_completion+=("-n") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--no") - local_nonpersistent_flags+=("--no=") - local_nonpersistent_flags+=("-n") - flags+=("--by=") - two_word_flags+=("--by") - flags_with_completion+=("--by") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-b") - flags_with_completion+=("-b") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--by") - local_nonpersistent_flags+=("--by=") - local_nonpersistent_flags+=("-b") - flags+=("--direction=") - two_word_flags+=("--direction") - flags_with_completion+=("--direction") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-d") - flags_with_completion+=("-d") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--direction") - local_nonpersistent_flags+=("--direction=") - local_nonpersistent_flags+=("-d") - flags+=("--format=") - two_word_flags+=("--format") - flags_with_completion+=("--format") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-f") - flags_with_completion+=("-f") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--format") - local_nonpersistent_flags+=("--format=") - local_nonpersistent_flags+=("-f") - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_ls-id() -{ - last_command="git-bug_ls-id" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_ls-label() -{ - last_command="git-bug_ls-label" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_pull() -{ - last_command="git-bug_pull" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_push() -{ - last_command="git-bug_push" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_rm() -{ - last_command="git-bug_rm" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_select() -{ - last_command="git-bug_select" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_show() -{ - last_command="git-bug_show" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--field=") - two_word_flags+=("--field") - local_nonpersistent_flags+=("--field") - local_nonpersistent_flags+=("--field=") - flags+=("--format=") - two_word_flags+=("--format") - two_word_flags+=("-f") - local_nonpersistent_flags+=("--format") - local_nonpersistent_flags+=("--format=") - local_nonpersistent_flags+=("-f") - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_status_close() -{ - last_command="git-bug_status_close" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_status_open() -{ - last_command="git-bug_status_open" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_status() -{ - last_command="git-bug_status" - - command_aliases=() - - commands=() - commands+=("close") - commands+=("open") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_termui() -{ - last_command="git-bug_termui" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_title_edit() -{ - last_command="git-bug_title_edit" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--title=") - two_word_flags+=("--title") - two_word_flags+=("-t") - local_nonpersistent_flags+=("--title") - local_nonpersistent_flags+=("--title=") - local_nonpersistent_flags+=("-t") - flags+=("--non-interactive") - local_nonpersistent_flags+=("--non-interactive") - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_title() -{ - last_command="git-bug_title" - - command_aliases=() - - commands=() - commands+=("edit") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_user_adopt() -{ - last_command="git-bug_user_adopt" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_user_create() -{ - last_command="git-bug_user_create" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--avatar=") - two_word_flags+=("--avatar") - two_word_flags+=("-a") - local_nonpersistent_flags+=("--avatar") - local_nonpersistent_flags+=("--avatar=") - local_nonpersistent_flags+=("-a") - flags+=("--email=") - two_word_flags+=("--email") - two_word_flags+=("-e") - local_nonpersistent_flags+=("--email") - local_nonpersistent_flags+=("--email=") - local_nonpersistent_flags+=("-e") - flags+=("--name=") - two_word_flags+=("--name") - two_word_flags+=("-n") - local_nonpersistent_flags+=("--name") - local_nonpersistent_flags+=("--name=") - local_nonpersistent_flags+=("-n") - flags+=("--non-interactive") - local_nonpersistent_flags+=("--non-interactive") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_user_ls() -{ - last_command="git-bug_user_ls" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--format=") - two_word_flags+=("--format") - flags_with_completion+=("--format") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-f") - flags_with_completion+=("-f") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--format") - local_nonpersistent_flags+=("--format=") - local_nonpersistent_flags+=("-f") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_user() -{ - last_command="git-bug_user" - - command_aliases=() - - commands=() - commands+=("adopt") - commands+=("create") - commands+=("ls") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--field=") - two_word_flags+=("--field") - flags_with_completion+=("--field") - flags_completion+=("__git-bug_handle_go_custom_completion") - two_word_flags+=("-f") - flags_with_completion+=("-f") - flags_completion+=("__git-bug_handle_go_custom_completion") - local_nonpersistent_flags+=("--field") - local_nonpersistent_flags+=("--field=") - local_nonpersistent_flags+=("-f") - - must_have_one_flag=() - must_have_one_noun=() - has_completion_function=1 - noun_aliases=() -} - -_git-bug_version() -{ - last_command="git-bug_version" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--number") - flags+=("-n") - local_nonpersistent_flags+=("--number") - local_nonpersistent_flags+=("-n") - flags+=("--commit") - flags+=("-c") - local_nonpersistent_flags+=("--commit") - local_nonpersistent_flags+=("-c") - flags+=("--all") - flags+=("-a") - local_nonpersistent_flags+=("--all") - local_nonpersistent_flags+=("-a") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_webui() -{ - last_command="git-bug_webui" - - command_aliases=() - - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--host=") - two_word_flags+=("--host") - local_nonpersistent_flags+=("--host") - local_nonpersistent_flags+=("--host=") - flags+=("--open") - local_nonpersistent_flags+=("--open") - flags+=("--no-open") - local_nonpersistent_flags+=("--no-open") - flags+=("--port=") - two_word_flags+=("--port") - two_word_flags+=("-p") - local_nonpersistent_flags+=("--port") - local_nonpersistent_flags+=("--port=") - local_nonpersistent_flags+=("-p") - flags+=("--read-only") - local_nonpersistent_flags+=("--read-only") - flags+=("--query=") - two_word_flags+=("--query") - two_word_flags+=("-q") - local_nonpersistent_flags+=("--query") - local_nonpersistent_flags+=("--query=") - local_nonpersistent_flags+=("-q") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_git-bug_root_command() -{ - last_command="git-bug" - - command_aliases=() - - commands=() - commands+=("add") - commands+=("bridge") - commands+=("commands") - commands+=("comment") - commands+=("deselect") - commands+=("label") - commands+=("ls") - commands+=("ls-id") - commands+=("ls-label") - commands+=("pull") - commands+=("push") - commands+=("rm") - commands+=("select") - commands+=("show") - commands+=("status") - commands+=("termui") - if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then - command_aliases+=("tui") - aliashash["tui"]="termui" - fi - commands+=("title") - commands+=("user") - commands+=("version") - commands+=("webui") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() + # Must use printf to escape all special characters + printf "%q" "${comp}" } __start_git-bug() { local cur prev words cword split - declare -A flaghash 2>/dev/null || : - declare -A aliashash 2>/dev/null || : + + COMPREPLY=() + + # Call _init_completion from the bash-completion package + # to prepare the arguments properly if declare -F _init_completion >/dev/null 2>&1; then - _init_completion -s || return + _init_completion -n "=:" || return else - __git-bug_init_completion -n "=" || return + __git-bug_init_completion -n "=:" || return fi - local c=0 - local flag_parsing_disabled= - local flags=() - local two_word_flags=() - local local_nonpersistent_flags=() - local flags_with_completion=() - local flags_completion=() - local commands=("git-bug") - local command_aliases=() - local must_have_one_flag=() - local must_have_one_noun=() - local has_completion_function="" - local last_command="" - local nouns=() - local noun_aliases=() + __git-bug_debug + __git-bug_debug "========= starting completion logic ==========" + __git-bug_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $cword location, so we need + # to truncate the command-line ($words) up to the $cword location. + words=("${words[@]:0:$cword+1}") + __git-bug_debug "Truncated words[*]: ${words[*]}," - __git-bug_handle_word + local out directive + __git-bug_get_completion_results + __git-bug_process_completion_results } if [[ $(type -t compopt) = "builtin" ]]; then diff --git a/misc/gen_completion.go b/misc/gen_completion.go index c073e67e..fc0f1f68 100644 --- a/misc/gen_completion.go +++ b/misc/gen_completion.go @@ -40,25 +40,49 @@ func main() { } func genBash(root *cobra.Command) error { - cwd, _ := os.Getwd() - dir := filepath.Join(cwd, "misc", "bash_completion", "git-bug") - return root.GenBashCompletionFile(dir) + cwd, err := os.Getwd() + if err != nil { + return err + } + f, err := os.Create(filepath.Join(cwd, "misc", "bash_completion", "git-bug")) + if err != nil { + return err + } + defer f.Close() + + // Custom bash code to connect the git completion for "git bug" to the + // git-bug completion for "git-bug" + _, err = f.WriteString(`#TODO: completion code to map "git bug" to "git-bug"`) + if err != nil { + return err + } + + return root.GenBashCompletionV2(f, true) } func genFish(root *cobra.Command) error { - cwd, _ := os.Getwd() + cwd, err := os.Getwd() + if err != nil { + return err + } dir := filepath.Join(cwd, "misc", "fish_completion", "git-bug") return root.GenFishCompletionFile(dir, true) } func genPowerShell(root *cobra.Command) error { - cwd, _ := os.Getwd() + cwd, err := os.Getwd() + if err != nil { + return err + } path := filepath.Join(cwd, "misc", "powershell_completion", "git-bug") return root.GenPowerShellCompletionFile(path) } func genZsh(root *cobra.Command) error { - cwd, _ := os.Getwd() + cwd, err := os.Getwd() + if err != nil { + return err + } path := filepath.Join(cwd, "misc", "zsh_completion", "git-bug") return root.GenZshCompletionFile(path) } |