X-Git-Url: http://git.tuebingen.mpg.de/?p=gsu.git;a=blobdiff_plain;f=misc%2Fgsu%2Fsubcommand;h=3a1bc6db6697c7a0676a45ae940b930d18ee8901;hp=332e5a0d43273f352e133f4a31507b061b4bb018;hb=844b7a202a39530d00aa191bae9e3d4189b89049;hpb=d84fb61667757b1e62b915781357e10693ce8a9e diff --git a/misc/gsu/subcommand b/misc/gsu/subcommand index 332e5a0..3a1bc6d 100644 --- a/misc/gsu/subcommand +++ b/misc/gsu/subcommand @@ -10,24 +10,39 @@ _gsu_usage() { gsu_short_msg "# Usage: $_gsu_self command [options]" } -export -f _gsu_usage -# Each line matching this is recognized as a subcommand. The name -# of the subcommand is the first subexpression. -export gsu_command_regex='^com_\([-a-zA-Z_0-9]\+\)()' +# Each line matching this is recognized as a subcommand. The name of the may be +# given as $1. In any case the subcommand is the first subexpression. +_gsu_get_command_regex() +{ + local cmd="${1:-[-a-zA-Z_0-9]+}" + result="^com_($cmd)\(\)" +} _gsu_available_commands() { + local ere + + _gsu_get_command_regex + ere="$result" result="$({ - printf "help\nman\nprefs\n" - sed -ne "s/$gsu_command_regex/\1/g;T;p" $0 - } | sort | tr '\n' ' ')" + printf "help\nman\nprefs\ncomplete\n" + sed -Ee ' + # if line matches, isolate command name + s/'"$ere"'/\1/g + + # if there is a match, (print it and) start next cycle + t + + # otherwise delete it + d + ' $0 + } | sort | tr '\n' ' ')" } -export -f _gsu_available_commands _gsu_print_available_commands() {( - local i count + local i count=0 gsu_short_msg "Available commands:" for i in $gsu_cmds; do printf "$i" @@ -44,7 +59,26 @@ _gsu_print_available_commands() echo ) 2>&1 } -export -f _gsu_print_available_commands + +gsu_complete_options() +{ + local opts="$1" cword="$2" cur opt + local -a words + + shift 2 + words=("$@") + cur="${words[$cword]}" + ret=0 + [[ ! "$cur" == -* ]] && return + + ret=0 + for ((i=0; i < ${#opts}; i++)); do + opt="${opts:$i:1}" + [[ "$opt" == ":" ]] && continue + printf "%s" "-$opt " + let ret++ + done +} export gsu_prefs_txt=" Print the current preferences. @@ -58,7 +92,13 @@ _com_prefs() { local i conf="${gsu_config_file:=$HOME/.$gsu_name.rc}" - if [[ "$1" = "-e" ]]; then + gsu_getopts "e" + eval "$result" + (($ret < 0)) && return + gsu_check_arg_count $# 0 0 + (($ret < 0)) && return + + if [[ "$o_e" == "true" ]]; then ret=-$E_GSU_MKDIR result="${conf%/*}" mkdir -p "$result" @@ -75,7 +115,7 @@ _com_prefs() local name= option_type= default_value= required= local description= help_text= eval "${gsu_options[$i]}" - eval val='"$'${gsu_config_var_prefix}_$name'"' + eval val='"${'${gsu_config_var_prefix}_$name:-'}"' case "$required" in true|yes) printf "# required" @@ -95,7 +135,11 @@ _com_prefs() echo done } -export -f _com_prefs + +complete_prefs() +{ + gsu_complete_options "e" "$@" +} export gsu_man_txt=" Print the manual. @@ -139,19 +183,11 @@ _com_man() done ret=$GSU_SUCCESS } -export -f _com_man _gsu_banner_msg() { - local txt="### $_gsu_self --" - if test -z "$gsu_banner_txt"; then - txt="$txt set \$gsu_banner_txt to customize this message" - else - txt="$txt $gsu_banner_txt" - fi - gsu_short_msg "$txt ###" + gsu_short_msg "### $_gsu_self -- ###" } -export -f _gsu_banner_msg export gsu_help_txt=" Print online help. @@ -161,31 +197,57 @@ Usage: help [command] Without arguments, print the list of available commands. Otherwise, print the help text for the given command." +export gsu_complete_txt=" +Command line completion. + +Usage: complete [ ...] + +When executed without argument the command writes bash code to +stdout. This code is suitable to be evaled from .bashrc to enable +completion. + +If at least one argument is given, all possible completions are +written to stdout. This can be used from the completion function of +the subcommand. +" + _com_help() { - local a b - if test -z "$1"; then + local a b ere tab=' ' + + _gsu_get_command_regex + ere="$result" + + if (($# == 0)); then _gsu_banner_msg 2>&1 _gsu_usage 2>&1 { printf "com_help()\n$gsu_help_txt" | head -n 4; echo "--" printf "com_man()\n$gsu_man_txt" | head -n 4; echo "--" printf "com_prefs()\n$gsu_prefs_txt" | head -n 4; echo "--" - grep -A 2 "$gsu_command_regex" $0 + printf "com_complete()\n$gsu_complete_txt" | head -n 4; echo "--" + grep -EA 2 "$ere" $0 } | grep -v -- '--' \ - | sed -e "/$gsu_command_regex/bs" \ - -e 'H;$!d;x;s/\n//g;b' \ - -e :s \ - -e 'x;s/\n//g;${p;x;}' \ - | sed -e "s/${gsu_command_regex}#*/\1\t/" \ - | sort \ - | while read a b; do - printf "$a\t" - if test ${#a} -lt 8; then - printf "\t" - fi - echo "$b" - done + | sed -En "/$ere/"'!d + # remove everything but the command name + s/^com_(.*)\(\).*/\1/ + + # append tab after short commands (less than 8 chars) + s/^(.{1,7})$/\1'"$tab"'/g + + # remove next line (should contain only ## anyway) + N + s/#.*// + + # append next line, removing leading ## + N + s/#+ *//g + + # replace newline by tab + y/\n/'"$tab"'/ + + # and print the sucker + p' echo echo "# Try $_gsu_self help for info on ." ret=$GSU_SUCCESS @@ -206,32 +268,60 @@ _com_help() ret=$GSU_SUCCESS return fi + if test "$1" = "complete"; then + echo "$gsu_complete_txt" + ret=$GSU_SUCCESS + return + fi ret=$GSU_SUCCESS - if grep -q "^com_$1()" $0; then - sed -e "1,/^com_$1()$/d" -e '/^{/,$d' -e 's/^## *//' $0 + _gsu_get_command_regex "$1" + ere="$result" + if ! grep -Eq "$ere" $0; then + _gsu_print_available_commands + result="$1" + ret=-$E_GSU_BAD_COMMAND return fi - _gsu_print_available_commands - result="$1" - ret=-$E_GSU_BAD_COMMAND + sed -nEe ' + # only consider lines in the comment of the function + /'"$ere"'/,/^[^#]/ { + + # remove leading ## + s/^## *// + + # if it did start with ##, jump to label p and print it + tp + + # otherwise, move on to next line + d + + # print it + :p + p + } + ' $0 } -export -f _com_help -# Wrapper for bash's getopts. +complete_help() +{ + _gsu_available_commands + echo "$result" +} + +# Wrapper for the bash getopts builtin. # # Aborts on programming errors such as missing or invalid option string. On # success $result contains shell code that can be eval'ed. For each defined # option x, the local variable o_x will be created when calling eval "$result". -# o_x contains true/false for options without an argument or the emtpy string/the -# given argument, depending on whether this option was contained in the "$@" -# array. +# o_x contains true/false for options without argument and either the emtpy +# string or the given argument for options that take an argument. # # Example: # gsu_getopts abc:x:y # eval "$result" -# [[ $ret -lt 0 ]] && return +# (($ret < 0)) && return # -# [[ "$o_a" = "true ]] && echo "The -a flag was given" +# [[ "$o_a" = 'true' ]] && echo 'The -a flag was given' # [[ -n "$o_c" ]] && echo "The -c option was given with arg $o_c" gsu_getopts() { @@ -262,21 +352,21 @@ gsu_getopts() exit 1 esac done - result="local opt" + result="local _gsu_getopts_opt" for ((i=0; i < ${#1}; i++)); do c1=${1:$i:1} c2=${1:$(($i + 1)):1} - result+=" o_$c1" + result+=" o_$c1=" if [[ "$c2" = ":" ]]; then let i++ else - result+="=false" + result+="false" fi done result+=" OPTIND=1 - while getopts $1 opt \"\$@\"; do - case \"\$opt\" in + while getopts $1 _gsu_getopts_opt \"\$@\"; do + case \"\$_gsu_getopts_opt\" in " for ((i=0; i < ${#1}; i++)); do c1=${1:$i:1} @@ -302,7 +392,118 @@ gsu_getopts() " ret=$GSU_SUCCESS } -export -f gsu_getopts + +_com_complete() +{ + local cmd n cword + local -a words + + if (($# == 0)); then + cat <