Files

307 lines
10 KiB
Bash

#!/bin/bash
__math_cursor_index_in_current_word() {
local remaining="${COMP_LINE}"
local word
for word in "${COMP_WORDS[@]::COMP_CWORD}"; do
remaining="${remaining##*([[:space:]])"${word}"*([[:space:]])}"
done
local -ir index="$((COMP_POINT - ${#COMP_LINE} + ${#remaining}))"
if [[ "${index}" -le 0 ]]; then
printf 0
else
printf %s "${index}"
fi
}
# positional arguments:
#
# - 1: the current (sub)command's count of positional arguments
#
# required variables:
#
# - repeating_flags: the repeating flags that the current (sub)command can accept
# - non_repeating_flags: the non-repeating flags that the current (sub)command can accept
# - repeating_options: the repeating options that the current (sub)command can accept
# - non_repeating_options: the non-repeating options that the current (sub)command can accept
# - positional_number: value ignored
# - unparsed_words: unparsed words from the current command line
#
# modified variables:
#
# - non_repeating_flags: remove flags for this (sub)command that are already on the command line
# - non_repeating_options: remove options for this (sub)command that are already on the command line
# - positional_number: set to the current positional number
# - unparsed_words: remove all flags, options, and option values for this (sub)command
__math_offer_flags_options() {
local -ir positional_count="${1}"
positional_number=0
local was_flag_option_terminator_seen=false
local is_parsing_option_value=false
local -ar unparsed_word_indices=("${!unparsed_words[@]}")
local -i word_index
for word_index in "${unparsed_word_indices[@]}"; do
if "${is_parsing_option_value}"; then
# This word is an option value:
# Reset marker for next word iff not currently the last word
[[ "${word_index}" -ne "${unparsed_word_indices[${#unparsed_word_indices[@]} - 1]}" ]] && is_parsing_option_value=false
unset "unparsed_words[${word_index}]"
# Do not process this word as a flag or an option
continue
fi
local word="${unparsed_words["${word_index}"]}"
if ! "${was_flag_option_terminator_seen}"; then
case "${word}" in
--)
unset "unparsed_words[${word_index}]"
# by itself -- is a flag/option terminator, but if it is the last word, it is the start of a completion
if [[ "${word_index}" -ne "${unparsed_word_indices[${#unparsed_word_indices[@]} - 1]}" ]]; then
was_flag_option_terminator_seen=true
fi
continue
;;
-*)
# ${word} is a flag or an option
# If ${word} is an option, mark that the next word to be parsed is an option value
local option
for option in "${repeating_options[@]}" "${non_repeating_options[@]}"; do
[[ "${word}" = "${option}" ]] && is_parsing_option_value=true && break
done
# Remove ${word} from ${non_repeating_flags} or ${non_repeating_options} so it isn't offered again
local not_found=true
local -i index
for index in "${!non_repeating_flags[@]}"; do
if [[ "${non_repeating_flags[${index}]}" = "${word}" ]]; then
unset "non_repeating_flags[${index}]"
non_repeating_flags=("${non_repeating_flags[@]}")
not_found=false
break
fi
done
if "${not_found}"; then
for index in "${!non_repeating_flags[@]}"; do
if [[ "${non_repeating_flags[${index}]}" = "${word}" ]]; then
unset "non_repeating_flags[${index}]"
non_repeating_flags=("${non_repeating_flags[@]}")
break
fi
done
fi
unset "unparsed_words[${word_index}]"
continue
;;
esac
fi
# ${word} is neither a flag, nor an option, nor an option value
if [[ "${positional_number}" -lt "${positional_count}" || "${positional_count}" -lt 0 ]]; then
# ${word} is a positional
((positional_number++))
unset "unparsed_words[${word_index}]"
else
if [[ -z "${word}" ]]; then
# Could be completing a flag, option, or subcommand
positional_number=-1
else
# ${word} is a subcommand or invalid, so stop processing this (sub)command
positional_number=-2
fi
break
fi
done
unparsed_words=("${unparsed_words[@]}")
if\
! "${was_flag_option_terminator_seen}"\
&& ! "${is_parsing_option_value}"\
&& [[ ("${cur}" = -* && "${positional_number}" -ge 0) || "${positional_number}" -eq -1 ]]
then
COMPREPLY+=($(compgen -W "${repeating_flags[*]} ${non_repeating_flags[*]} ${repeating_options[*]} ${non_repeating_options[*]}" -- "${cur}"))
fi
}
__math_add_completions() {
local completion
while IFS='' read -r completion; do
COMPREPLY+=("${completion}")
done < <(IFS=$'\n' compgen "${@}" -- "${cur}")
}
__math_custom_complete() {
if [[ -n "${cur}" || -z ${COMP_WORDS[${COMP_CWORD}]} || "${COMP_LINE:${COMP_POINT}:1}" != ' ' ]]; then
local -ar words=("${COMP_WORDS[@]}")
else
local -ar words=("${COMP_WORDS[@]::${COMP_CWORD}}" '' "${COMP_WORDS[@]:${COMP_CWORD}}")
fi
"${COMP_WORDS[0]}" "${@}" "${words[@]}"
}
_math() {
local state
state="$(shopt -p;shopt -po)"
trap "${state//$'\n'/;}" RETURN
shopt -s extglob
set +o history +o posix
local -xr SAP_SHELL=bash
local -x SAP_SHELL_VERSION
SAP_SHELL_VERSION="$(IFS='.';printf %s "${BASH_VERSINFO[*]}")"
local -r SAP_SHELL_VERSION
local -r cur="${2}"
local -r prev="${3}"
local -i positional_number
local -a unparsed_words=("${COMP_WORDS[@]:1:${COMP_CWORD}}")
local -a repeating_flags=()
local -a non_repeating_flags=(--version -h --help)
local -a repeating_options=()
local -a non_repeating_options=()
__math_offer_flags_options 0
# Offer subcommand / subcommand argument completions
local -r subcommand="${unparsed_words[0]}"
unset 'unparsed_words[0]'
unparsed_words=("${unparsed_words[@]}")
case "${subcommand}" in
add|multiply|stats|help)
# Offer subcommand argument completions
"_math_${subcommand}"
;;
*)
# Offer subcommand completions
COMPREPLY+=($(compgen -W 'add multiply stats help' -- "${cur}"))
;;
esac
}
_math_add() {
repeating_flags=()
non_repeating_flags=(--hex-output -x --version -h --help)
repeating_options=()
non_repeating_options=()
__math_offer_flags_options -1
}
_math_multiply() {
repeating_flags=()
non_repeating_flags=(--hex-output -x --version -h --help)
repeating_options=()
non_repeating_options=()
__math_offer_flags_options -1
}
_math_stats() {
repeating_flags=()
non_repeating_flags=(--version -h --help)
repeating_options=()
non_repeating_options=()
__math_offer_flags_options 0
# Offer subcommand / subcommand argument completions
local -r subcommand="${unparsed_words[0]}"
unset 'unparsed_words[0]'
unparsed_words=("${unparsed_words[@]}")
case "${subcommand}" in
average|stdev|quantiles)
# Offer subcommand argument completions
"_math_stats_${subcommand}"
;;
*)
# Offer subcommand completions
COMPREPLY+=($(compgen -W 'average stdev quantiles' -- "${cur}"))
;;
esac
}
_math_stats_average() {
repeating_flags=()
non_repeating_flags=(--version -h --help)
repeating_options=()
non_repeating_options=(--kind)
__math_offer_flags_options -1
# Offer option value completions
case "${prev}" in
'--kind')
__math_add_completions -W 'mean'$'\n''median'$'\n''mode'
return
;;
esac
}
_math_stats_stdev() {
repeating_flags=()
non_repeating_flags=(--version -h --help)
repeating_options=()
non_repeating_options=()
__math_offer_flags_options -1
}
_math_stats_quantiles() {
repeating_flags=()
non_repeating_flags=(--version -h --help)
repeating_options=()
non_repeating_options=(--file --directory --shell --custom --custom-deprecated)
__math_offer_flags_options -1
# Offer option value completions
case "${prev}" in
'--file')
__math_add_completions -o plusdirs -fX '!*.@(txt|md)'
return
;;
'--directory')
__math_add_completions -d
return
;;
'--shell')
__math_add_completions -W "$(eval 'head -100 '\''/usr/share/dict/words'\'' | tail -50')"
return
;;
'--custom')
__math_add_completions -W "$(__math_custom_complete ---completion stats quantiles -- --custom "${COMP_CWORD}" "$(__math_cursor_index_in_current_word)")"
return
;;
'--custom-deprecated')
__math_add_completions -W "$(__math_custom_complete ---completion stats quantiles -- --custom-deprecated)"
return
;;
esac
# Offer positional completions
case "${positional_number}" in
1)
__math_add_completions -W 'alphabet'$'\n''alligator'$'\n''branch'$'\n''braggart'
return
;;
2)
__math_add_completions -W "$(__math_custom_complete ---completion stats quantiles -- positional@1 "${COMP_CWORD}" "$(__math_cursor_index_in_current_word)")"
return
;;
3)
__math_add_completions -W "$(__math_custom_complete ---completion stats quantiles -- positional@2)"
return
;;
esac
}
_math_help() {
repeating_flags=()
non_repeating_flags=(--version)
repeating_options=()
non_repeating_options=()
__math_offer_flags_options -1
}
complete -o filenames -F _math math