From bf7347380207d80183ce80ae6547ef08fa579c6a Mon Sep 17 00:00:00 2001 From: Polesznyák Márk Date: Sat, 29 Nov 2025 01:45:07 +0100 Subject: feat: add scripts, TARGET variable for Makefile --- scripts/bash-completor | 734 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 734 insertions(+) create mode 100755 scripts/bash-completor (limited to 'scripts/bash-completor') diff --git a/scripts/bash-completor b/scripts/bash-completor new file mode 100755 index 0000000..b013ec6 --- /dev/null +++ b/scripts/bash-completor @@ -0,0 +1,734 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail +set -o errtrace +(shopt -p inherit_errexit &>/dev/null) && shopt -s inherit_errexit + +readonly VERSION=v0.2.0 +readonly ARGS=$* +readonly SPACES_8=' ' +readonly SPACES_6=' ' +readonly SPACES_4=' ' +readonly SPACES_2=' ' + +declare -r RED="\\e[31m" +declare -r GREEN="\\e[32m" +declare -r YELLOW="\\e[33m" +declare -r CYAN="\\e[36m" +declare -r RESET_ALL="\\e[0m" + +debug() { + printf "%b[Debug] %s%b\n" "$CYAN" "$*" "$RESET_ALL" >/dev/tty +} + +warn() { + printf "%b[Warn] %s%b\n" "$YELLOW" "$*" "$RESET_ALL" >/dev/tty +} + +error() { + printf "%b[Error] %s%b\n" "$RED" "$*" "$RESET_ALL" >/dev/tty +} + +suggest() { + printf "%b[Suggest] %s%b\n" "$GREEN" "$*" "$RESET_ALL" >/dev/tty +} + +# Copy from https://github.com/adoyle-h/lobash/blob/develop/src/modules/is_array.bash +is_array() { + local attrs + # shellcheck disable=2207 + attrs=$(declare -p "$1" 2>/dev/null | sed -E "s/^declare -([-a-zA-Z]+) .+/\\1/" || true) + + # a: array + # A: associate array + if [[ ${attrs} =~ a|A ]]; then return 0; else return 1; fi +} + +is_func() { + declare -F "$1" &>/dev/null +} + +get_varname() { + local name=${1:-} + local encoded=${word_to_varname[$name]:-} + + if [[ -z ${encoded} ]]; then + encoded=${name//[^a-zA-Z_]/_} + fi + + echo "${encoded}" +} + +is_gnu_sed() { + local out + out=$(${1:-sed} --version 2>/dev/null) + [[ $out =~ 'GNU sed' ]] +} + +reply_words() { + local IFS=$'\n' + # shellcheck disable=2207 + COMPREPLY=( $(IFS=', ' compgen -W "$*" -- "${cur#=}") ) +} + +reply_list() { + local IFS=', ' + local array_list="" array_name + # shellcheck disable=2068 + for array_name in "$@"; do + array_list="$array_list \${${array_name}[*]}" + done + array_list="${array_list[*]:1}" + + IFS=$'\n'' ' + eval "COMPREPLY=( \$(compgen -W \"$array_list\" -- \"\$cur\") )" +} + +reply_files() { + local IFS=$'\n' + compopt -o nospace -o filenames + # shellcheck disable=2207 + COMPREPLY=( $(compgen -A file -- "$cur") ) +} + +reply_files_in_pattern() { + compopt -o nospace -o filenames + + local path + while read -r path; do + if [[ $path =~ $1 ]] || [[ -d $path ]]; then + COMPREPLY+=( "$path" ) + fi + done < <(compgen -A file -- "$cur") +} + +reply_dirs() { + local IFS=$'\n' + compopt -o nospace -o filenames + # shellcheck disable=2207 + COMPREPLY=( $(compgen -A directory -- "$cur") ) +} + + +make_get_varnames() { + echo "" + + declare -p word_to_varname | sed -e "s/word_to_varname/_${cmd}_comp_word_to_varname/" + + declare -f get_varname | sed -e "s/get_varname/_${cmd}_comp_util_get_varname/" -e 's/ *$//g' \ + -e "s/word_to_varname/_${cmd}_comp_word_to_varname/" +} + +make_dumped_variables() { + echo "" + local name + for name in $(compgen -A variable var_); do + declare -p "$name" | sed "s/^declare -.* var_/_${cmd}_comp_var_/" + done +} + +make_header() { + cat < 0 )); then + cat < 0 )); then + cat < 0)) && [[ ${func_arg[*]:0:1} != '@' ]]; then + printf -- "_%s_comp_reply_%s '%s'" "$cmd" "$func_name" "$func_arg" + else + printf -- '_%s_comp_reply_%s' "$cmd" "$func_name" + fi + else + error "Invalid '$position': The action '$var' is not defined." + + case $var in + @f*) suggest "Try '@files' instead of '$var'." ;; + @d*) suggest "Try '@dirs' instead of '$var'." ;; + @h*) suggest "Try '@hold' instead of '$var'." ;; + *) suggest "Try '@files', '@dirs', '@hold' or other reply functions. See https://github.com/adoyle-h/bash-completor/docs/syntax.md#reply-functions " ;; + esac + + exit 5 + fi + ;; + esac + else + if [[ -n "$var" ]]; then + printf -- "_%s_comp_reply_words '%s'" "$cmd" "$var" + else + printf ':' + fi + fi +} + +make_reply_action() { + local varname=$1 + local -n var=$varname + local reply + + if [[ -v "$varname" ]]; then + reply=$(parse_action "$var" "$varname=$var") + elif is_array "$varname"; then + reply="_${cmd}_comp_reply_list '${var}'" + else + reply="_${cmd}_comp_reply_files" + fi + + echo "$reply" +} + +make_reply_set() { + cat <> bash-debug.log +EOF + + local reply_args + + if $has_subcmds; then + cat < 1 )); then + # Enter the subcmd completion + local subcmd_varname + subcmd_varname="\$(_${cmd}_comp_util_get_varname "\${COMP_WORDS[1]}")" + if type "_${cmd}_completions_\$subcmd_varname" &>/dev/null; then + "_${cmd}_completions_\$subcmd_varname" + else + # If subcmd completion function not defined, use the fallback + "_${cmd}_completions__fallback" + fi + return 0 + fi +EOF + + reply_args="_${cmd}_comp_reply_list _${cmd}_comp_subcmds" + else + reply_args=$(make_reply_action cmd_args) + fi + + local reply_opts_fallback + if [[ -v cmd_opts_fallback ]]; then + reply_opts_fallback=$(make_reply_action cmd_opts_fallback) + else + reply_opts_fallback=$(make_reply_action cmd_args) + fi + + cat < "$output_path" + printf '%bGenerated file: %s%b\n' "${GREEN}" "$output_path" "$RESET_ALL" +} + +usage() { + cat < To generate Bash completion script based on configuration + -h|--help Print the usage + --version Print the version of bash-completor + +Description: Quickly generate Bash completion script based on configuration. + +Config Syntax: https://github.com/adoyle-h/bash-completor/docs/syntax.md + +Project: https://github.com/adoyle-h/bash-completor + +Version: $VERSION +EOF +} + +check_conf() { + local conf_path=$1 + + if [[ ! -f $conf_path ]]; then + echo "Not found config file at $conf_path" >&2 + exit 3 + fi + + # shellcheck disable=1090 + . "$conf_path" + + # Set default values of config options + cmd_name=$cmd + cmd=$(get_varname "$cmd_name") + cmd_args=${cmd_args:-@files} + subcmd_args__fallback=${subcmd_args__fallback:-@files} + + if (( ${#subcmds[@]} > 0 )); then + has_subcmds=true + fi +} + +main() { + if (( $# == 0 )); then usage; exit 0; fi + + case "$1" in + -c) + do_make "$2" + ;; + + -h|--help) + usage + ;; + + --version) + echo "$VERSION" + ;; + + *) + echo "Invalid option '$1'." >&2 + exit 2 + ;; + esac +} + +main "$@" -- cgit v1.2.3