]> git.tuebingen.mpg.de Git - gsu.git/blobdiff - subcommand
gui: Remember menu position.
[gsu.git] / subcommand
index a07f4145c69adb6fa319dbdaa9c97e3b0a2d5cde..d37481cdbdccb5b62268d3b788de84b61a2ab347 100644 (file)
@@ -96,11 +96,12 @@ gsu_check_arg_count()
 #      [[ -n "$o_c" ]] && echo "The -c option was given with arg $o_c"
 gsu_getopts()
 {
 #      [[ -n "$o_c" ]] && echo "The -c option was given with arg $o_c"
 gsu_getopts()
 {
-       local i c tab=' ' cr='
+       local -i i
+       local c c1 c2 tab='     ' cr='
 '
 
        gsu_check_arg_count $# 1 1
 '
 
        gsu_check_arg_count $# 1 1
-       if (($ret < 0)); then
+       if ((ret < 0)); then
                gsu_err_msg
                exit 1
        fi
                gsu_err_msg
                exit 1
        fi
@@ -126,7 +127,7 @@ gsu_getopts()
        result="local _gsu_getopts_opt"
        for ((i=0; i < ${#1}; i++)); do
                c1=${1:$i:1}
        result="local _gsu_getopts_opt"
        for ((i=0; i < ${#1}; i++)); do
                c1=${1:$i:1}
-               c2=${1:$(($i + 1)):1}
+               c2=${1:$((i + 1)):1}
                result+=" o_$c1="
                if [[ "$c2" = ":" ]]; then
                        let i++
                result+=" o_$c1="
                if [[ "$c2" = ":" ]]; then
                        let i++
@@ -141,7 +142,7 @@ gsu_getopts()
 "
        for ((i=0; i < ${#1}; i++)); do
                c1=${1:$i:1}
 "
        for ((i=0; i < ${#1}; i++)); do
                c1=${1:$i:1}
-               c2=${1:$(($i + 1)):1}
+               c2=${1:$((i + 1)):1}
                result+="$tab$tab$c1) o_$c1="
                if [[ "$c2" = ":" ]]; then
                        result+="\"\$OPTARG\""
                result+="$tab$tab$c1) o_$c1="
                if [[ "$c2" = ":" ]]; then
                        result+="\"\$OPTARG\""
@@ -167,26 +168,33 @@ gsu_getopts()
 _gsu_print_available_commands()
 {
        local cmd cmds
 _gsu_print_available_commands()
 {
        local cmd cmds
-       local -i count=0
+       local -i maxlen=0 cols width=80 count=0
 
 
+       result=$(stty size 2>/dev/null)
+       if (($? == 0)); then
+               gsu_is_a_number "${result#* }"
+               ((ret >= 0)) && ((result > 0)) && width=$result
+       fi
        _gsu_available_commands
        _gsu_available_commands
-       cmds="$result"
-       printf 'Available commands:\n'
+       cmds=$result
+       for cmd in $cmds; do
+               ((${#cmd} > maxlen)) && maxlen=${#cmd}
+       done
+       let maxlen++
+       ((width < maxlen)) && cols=1 || cols=$((width / maxlen))
+       printf 'Available commands:'
        for cmd in $cmds; do
        for cmd in $cmds; do
-               printf '%s' "$cmd"
+               ((count % cols == 0)) && printf '\n'
+               printf '%-*s' $maxlen $cmd
                let ++count
                let ++count
-               if (($count % 4)); then
-                       printf '\t'
-                       ((${#cmd} < 8)) && printf '\t'
-               else
-                       printf '\n'
-               fi
        done
        printf '\n'
 }
 
 # Print all options of the given optstring to stdout if the word in the current
 # command line begins with a hyphen character.
        done
        printf '\n'
 }
 
 # Print all options of the given optstring to stdout if the word in the current
 # command line begins with a hyphen character.
+#
+# Returns 0 if the current word does not start with a hyphen, one otherwise.
 gsu_complete_options()
 {
        local opts="$1" cword="$2" cur opt
 gsu_complete_options()
 {
        local opts="$1" cword="$2" cur opt
@@ -198,18 +206,18 @@ gsu_complete_options()
        ret=0
        [[ ! "$cur" == -* ]] && return
 
        ret=0
        [[ ! "$cur" == -* ]] && return
 
-       ret=0
        for ((i=0; i < ${#opts}; i++)); do
                opt="${opts:$i:1}"
                [[ "$opt" == ":" ]] && continue
                printf "%s" "-$opt "
        for ((i=0; i < ${#opts}; i++)); do
                opt="${opts:$i:1}"
                [[ "$opt" == ":" ]] && continue
                printf "%s" "-$opt "
-               let ret++
        done
        done
+       ret=1
 }
 
 }
 
+declare -A _gsu_help_text=() # indexed by autocmd
 com_prefs_options='e'
 
 com_prefs_options='e'
 
-_gsu_prefs_txt="
+_gsu_help_text['prefs']='
 Print the current preferences.
 
 Usage: prefs [-e]
 Print the current preferences.
 
 Usage: prefs [-e]
@@ -217,7 +225,7 @@ Usage: prefs [-e]
 If -e is given, the config file is opened with the default editor.
 Without options, the command prints out a list of all config variables,
 together with their current value and the default value.
 If -e is given, the config file is opened with the default editor.
 Without options, the command prints out a list of all config variables,
 together with their current value and the default value.
-"
+'
 
 com_prefs()
 {
 
 com_prefs()
 {
@@ -225,9 +233,9 @@ com_prefs()
 
        gsu_getopts "$com_prefs_options"
        eval "$result"
 
        gsu_getopts "$com_prefs_options"
        eval "$result"
-       (($ret < 0)) && return
+       ((ret < 0)) && return
        gsu_check_arg_count $# 0 0
        gsu_check_arg_count $# 0 0
-       (($ret < 0)) && return
+       ((ret < 0)) && return
 
        if [[ "$o_e" == "true" ]]; then
                ret=-$E_GSU_MKDIR
 
        if [[ "$o_e" == "true" ]]; then
                ret=-$E_GSU_MKDIR
@@ -236,7 +244,7 @@ com_prefs()
                (($? != 0)) && return
                ret=-$E_GSU_EDITOR
                result="${EDITOR:-vi}"
                (($? != 0)) && return
                ret=-$E_GSU_EDITOR
                result="${EDITOR:-vi}"
-               "$result" "$conf"
+               "$result" $conf
                (($? != 0)) && return
                ret=$GSU_SUCCESS
                return
                (($? != 0)) && return
                ret=$GSU_SUCCESS
                return
@@ -255,7 +263,7 @@ com_prefs()
                        printf "# optional"
                        ;;
                esac
                        printf "# optional"
                        ;;
                esac
-               printf "%s: %s" "$option_type" "$description"
+               printf " %s: %s" "$option_type" "$description"
                if [[ "$required" != "yes" && "$required" != "true" ]]; then
                        printf " [%s]" "$default_value"
                fi
                if [[ "$required" != "yes" && "$required" != "true" ]]; then
                        printf " [%s]" "$default_value"
                fi
@@ -288,12 +296,12 @@ complete_man()
        [[ "$result" == 'm' ]] && printf 'roff\ntext\nhtml\n'
 }
 
        [[ "$result" == 'm' ]] && printf 'roff\ntext\nhtml\n'
 }
 
-_gsu_man_txt='
+_gsu_help_text['man']='
 Print the manual.
 
 Usage: man [-m <mode>] [-b <browser>]
 
 Print the manual.
 
 Usage: man [-m <mode>] [-b <browser>]
 
--m: Set output format (text, roff or html). Default: text.
+-m: Set output format (text, roff or html). Default: roff.
 -b: Use the specified browser. Implies html mode.
 
 If stdout is not associated with a terminal device, the command
 -b: Use the specified browser. Implies html mode.
 
 If stdout is not associated with a terminal device, the command
@@ -309,9 +317,6 @@ file is displayed as a page in the web browser. If -b is not given,
 the command stored in the $BROWSER environment variable is executed
 with the path to the temporary file as an argument. If $BROWSER is
 unset, elinks(1) is assumed.
 the command stored in the $BROWSER environment variable is executed
 with the path to the temporary file as an argument. If $BROWSER is
 unset, elinks(1) is assumed.
-
-It is recommended to specify the output format with -m as the default
-mode might change in future versions of gsu.
 '
 
 _gsu_read_line()
 '
 
 _gsu_read_line()
@@ -376,7 +381,7 @@ _gsu_roffify_maindoc()
                fi
                if [[ "${line:0:1}" == "$TAB" ]]; then # example
                        _gsu_change_roffify_state 'state' 'example'
                fi
                if [[ "${line:0:1}" == "$TAB" ]]; then # example
                        _gsu_change_roffify_state 'state' 'example'
-                       printf '%s\n' "$line"
+                       _gsu_print_protected_roff_line "$line"
                        line="$next_line"
                        continue
                fi
                        line="$next_line"
                        continue
                fi
@@ -453,14 +458,17 @@ _gsu_roffify_cmds()
        done
 }
 
        done
 }
 
-_gsu_roffify_autocmd()
+_gsu_roffify_autocmds()
 {
 {
-       local cmd="$1" help_txt="$2"
+       local cmd help_txt
 
 
-       {
-               printf 'com_%s()\n' "$cmd"
-               sed -e 's/^/## /g' <<< "$help_txt"
-       } | _gsu_roffify_cmds
+       for cmd in "${!_gsu_help_text[@]}"; do
+               help_txt="${_gsu_help_text["$cmd"]}"
+               {
+                       printf 'com_%s()\n' "$cmd"
+                       sed -e 's/^/## /g' <<< "$help_txt"
+               } | _gsu_roffify_cmds
+       done
 }
 
 _gsu_roff_man()
 }
 
 _gsu_roff_man()
@@ -482,10 +490,7 @@ EOF
 
        printf '\n.SH "GENERIC SUBCOMMANDS"\n'
        printf 'The following commands are automatically created by gsu\n'
 
        printf '\n.SH "GENERIC SUBCOMMANDS"\n'
        printf 'The following commands are automatically created by gsu\n'
-       _gsu_roffify_autocmd "help" "$_gsu_help_txt"
-       _gsu_roffify_autocmd "man" "$_gsu_man_txt"
-       _gsu_roffify_autocmd "prefs" "$_gsu_prefs_txt"
-       _gsu_roffify_autocmd "complete" "$_gsu_complete_txt"
+       _gsu_roffify_autocmds
 
        printf '\n.SH "LIST OF SUBCOMMANDS"\n'
        printf 'Each command has its own set of options as described below.\n'
 
        printf '\n.SH "LIST OF SUBCOMMANDS"\n'
        printf 'Each command has its own set of options as described below.\n'
@@ -522,7 +527,7 @@ com_man()
                o_m='html'
                browser="$o_b"
        elif [[ -z "$o_m" ]]; then
                o_m='html'
                browser="$o_b"
        elif [[ -z "$o_m" ]]; then
-               o_m='text'
+               o_m='roff'
        fi
 
        _gsu_isatty && isatty='true' || isatty='false'
        fi
 
        _gsu_isatty && isatty='true' || isatty='false'
@@ -597,7 +602,7 @@ com_man()
        _gsu_available_commands
        for com in $result; do
                num=${#com}
        _gsu_available_commands
        for com in $result; do
                num=${#com}
-               (($num < 4)) && num=4
+               ((num < 4)) && num=4
                echo "${minus_signs:0:$num}"
                echo "$com"
                echo "${minus_signs:0:$num}"
                echo "${minus_signs:0:$num}"
                echo "$com"
                echo "${minus_signs:0:$num}"
@@ -608,15 +613,18 @@ com_man()
        ret=$GSU_SUCCESS
 }
 
        ret=$GSU_SUCCESS
 }
 
-_gsu_help_txt="
+_gsu_help_text['help']='
 Print online help.
 
 Print online help.
 
-Usage: help [command]
+Usage: help [-a] [command]
 
 Without arguments, print the list of available commands. Otherwise,
 
 Without arguments, print the list of available commands. Otherwise,
-print the help text for the given command."
+print the help text for the given command.
+
+-a: Also show the help of automatic commands. Ignored if a command
+is given.'
 
 
-_gsu_complete_txt="
+_gsu_help_text['complete']='
 Command line completion.
 
 Usage: complete [<cword> <word>...]
 Command line completion.
 
 Usage: complete [<cword> <word>...]
@@ -628,11 +636,16 @@ 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.
 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_options='a'
 com_help()
 {
 com_help()
 {
-       local ere tab=' '
+       local ere tab=' ' txt
+
+       gsu_getopts "$com_help_options"
+       eval "$result"
+       ((ret < 0)) && return
 
        _gsu_get_command_regex
        ere="$result"
 
        _gsu_get_command_regex
        ere="$result"
@@ -641,10 +654,15 @@ com_help()
                gsu_short_msg "### $gsu_name -- $gsu_banner_txt ###"
                _gsu_usage 2>&1
                {
                gsu_short_msg "### $gsu_name -- $gsu_banner_txt ###"
                _gsu_usage 2>&1
                {
-                       printf "com_help()\n%s" "$_gsu_help_txt" | head -n 4; echo "--"
-                       printf "com_man()\n%s" "$_gsu_man_txt" | head -n 4; echo "--"
-                       printf "com_prefs()\n%s" "$_gsu_prefs_txt" | head -n 4; echo "--"
-                       printf "com_complete()\n%s" "$_gsu_complete_txt" | head -n 4; echo "--"
+                       if [[ "$o_a" == 'true' ]]; then
+                               _gsu_mfcb() { printf '%s\n' "$2"; }
+                               for cmd in "${!_gsu_help_text[@]}"; do
+                                       printf "com_%s()" "$cmd"
+                                       txt="${_gsu_help_text["$cmd"]}"
+                                       mapfile -n 3 -c 1 -C _gsu_mfcb <<< "$txt"
+                               printf -- '--\n'
+                               done
+                       fi
                        grep -EA 2 "$ere" "$0"
                } | grep -v -- '--' \
                        | sed -En "/$ere/"'!d
                        grep -EA 2 "$ere" "$0"
                } | grep -v -- '--' \
                        | sed -En "/$ere/"'!d
@@ -666,33 +684,33 @@ com_help()
                                y/\n/'"$tab"'/
 
                                # and print the sucker
                                y/\n/'"$tab"'/
 
                                # and print the sucker
-                               p'
-               echo
-               echo "# Try $gsu_name help <command> for info on <command>."
-               ret=$GSU_SUCCESS
-               return
-       fi
-       if test "$1" = "help"; then
-               echo "$_gsu_help_txt"
-               ret=$GSU_SUCCESS
-               return
-       fi
-       if test "$1" = "man"; then
-               echo "$_gsu_man_txt"
+                               p
+                       ' | {
+                               local -a cmds=() descs=()
+                               local -i i maxlen=1
+                               local cmd desc
+                               while read cmd desc; do
+                                       ((maxlen < ${#cmd})) && maxlen=${#cmd}
+                                       cmds[${#cmds[@]}]=$cmd
+                                       descs[${#descs[@]}]=$desc
+                               done
+                               for ((i = 0; i < ${#cmds[@]}; i++)); do
+                                       printf '%-*s %s\n' $maxlen ${cmds[$i]} \
+                                               "${descs[$i]}"
+                               done
+                       }
+               printf "\n# Try %s help <command> for info on <command>, or %s help -a to see\n" \
+                       "$gsu_name" "$gsu_name"
+               printf '# also the subcommands which are automatically generated by gsu.\n'
                ret=$GSU_SUCCESS
                return
        fi
                ret=$GSU_SUCCESS
                return
        fi
-       if test "$1" = "prefs"; then
-               echo "$_gsu_prefs_txt"
+       for cmd in "${!_gsu_help_text[@]}"; do
+               [[ "$1" != "$cmd" ]] && continue
+               printf '%s\n' "${_gsu_help_text["$cmd"]}"
                ret=$GSU_SUCCESS
                return
                ret=$GSU_SUCCESS
                return
-       fi
-       if test "$1" = "complete"; then
-               echo "$_gsu_complete_txt"
-               ret=$GSU_SUCCESS
-               return
-       fi
-       ret=$GSU_SUCCESS
+       done
        _gsu_get_command_regex "$1"
        ere="$result"
        if ! grep -Eq "$ere" "$0"; then
        _gsu_get_command_regex "$1"
        ere="$result"
        if ! grep -Eq "$ere" "$0"; then
@@ -719,6 +737,7 @@ com_help()
                        p
                }
        ' "$0"
                        p
                }
        ' "$0"
+       ret=$GSU_SUCCESS
 }
 
 complete_help()
 }
 
 complete_help()
@@ -738,7 +757,12 @@ com_complete()
                local -a candidates;
 
                candidates=(\$($0 complete "\$COMP_CWORD" "\${COMP_WORDS[@]}"));
                local -a candidates;
 
                candidates=(\$($0 complete "\$COMP_CWORD" "\${COMP_WORDS[@]}"));
-               COMPREPLY=(\$(compgen -W "\${candidates[*]}" -- "\$cur"));
+               if ((\$? == 0)); then
+                       COMPREPLY=(\$(compgen -W "\${candidates[*]}" -- "\$cur"));
+               else
+                       compopt -o filenames;
+                       COMPREPLY=(\$(compgen -fd -- "\$cur"));
+               fi
 EOF
                ret=$GSU_SUCCESS
                return
 EOF
                ret=$GSU_SUCCESS
                return
@@ -746,8 +770,8 @@ EOF
 
        cword="$1"
        gsu_is_a_number "$cword"
 
        cword="$1"
        gsu_is_a_number "$cword"
-       (($ret < 0)) && return
-       if (($cword <= 1)); then
+       ((ret < 0)) && return
+       if ((cword <= 1)); then
                _gsu_available_commands
                echo "${result}"
                ret=$GSU_SUCCESS
                _gsu_available_commands
                echo "${result}"
                ret=$GSU_SUCCESS
@@ -756,8 +780,9 @@ EOF
        shift
        words=("$@")
        cmd="${words[1]}"
        shift
        words=("$@")
        cmd="${words[1]}"
-       ret=$GSU_SUCCESS # It's not an error if no completer was defined
-       [[ "$(type -t "complete_$cmd")" != "function" ]] && return
+       # if no completer is defined for this subcommand we exit unsuccessfully
+       # to let the generic completer above fall back to file name completion.
+       [[ "$(type -t "complete_$cmd")" != "function" ]] && exit 1
        "complete_$cmd" "$cword" "${words[@]}"
        # ignore errors, they would only clutter the completion output
        ret=$GSU_SUCCESS
        "complete_$cmd" "$cword" "${words[@]}"
        # ignore errors, they would only clutter the completion output
        ret=$GSU_SUCCESS
@@ -779,18 +804,18 @@ gsu_cword_is_option_parameter()
        local -a words
 
        result=
        local -a words
 
        result=
-       (($cword == 0)) && return
+       ((cword == 0)) && return
        ((${#opts} < 2)) && return
 
        shift 2
        words=("$@")
        ((${#opts} < 2)) && return
 
        shift 2
        words=("$@")
-       prev="${words[$(($cword - 1))]}"
+       prev="${words[$((cword - 1))]}"
        [[ ! "$prev" == -* ]] && return
 
        n=$((${#opts} - 1))
        for ((i=0; i <= $n; i++)); do
                opt="${opts:$i:1}"
        [[ ! "$prev" == -* ]] && return
 
        n=$((${#opts} - 1))
        for ((i=0; i <= $n; i++)); do
                opt="${opts:$i:1}"
-               [[ "${opts:$(($i + 1)):1}" != ":" ]] && continue
+               [[ "${opts:$((i + 1)):1}" != ":" ]] && continue
                let i++
                [[ ! "$prev" =~ ^-.*$opt$ ]] && continue
                result="$opt"
                let i++
                [[ ! "$prev" =~ ^-.*$opt$ ]] && continue
                result="$opt"
@@ -821,13 +846,13 @@ gsu_get_unnamed_arg_num()
        shift 2
        words=("$@")
        cur="${words[$cword]}"
        shift 2
        words=("$@")
        cur="${words[$cword]}"
-       prev="${words[$(($cword - 1))]}"
+       prev="${words[$((cword - 1))]}"
        result=-1
        [[ "$cur" == -* ]] && return
        [[ "$prev" == -* ]] && [[ "$opts" == *${prev#-}:* ]] && return
 
        for ((i=1; i <= $cword; i++)); do
        result=-1
        [[ "$cur" == -* ]] && return
        [[ "$prev" == -* ]] && [[ "$opts" == *${prev#-}:* ]] && return
 
        for ((i=1; i <= $cword; i++)); do
-               prev="${words[$(($i - 1))]}"
+               prev="${words[$((i - 1))]}"
                cur="${words[$i]}"
                [[ "$cur" == -* ]] && continue
                if [[ "$prev" == -* ]]; then
                cur="${words[$i]}"
                [[ "$cur" == -* ]] && continue
                if [[ "$prev" == -* ]]; then
@@ -837,7 +862,7 @@ gsu_get_unnamed_arg_num()
                fi
                let n++
        done
                fi
                let n++
        done
-       result="$(($n - 1))"
+       result="$((n - 1))"
 }
 
 # Entry point for all gsu-based scripts.
 }
 
 # Entry point for all gsu-based scripts.
@@ -868,7 +893,7 @@ gsu()
        shift
        if [[ "$(type -t "com_$arg")" == 'function' ]]; then
                "com_$arg" "$@"
        shift
        if [[ "$(type -t "com_$arg")" == 'function' ]]; then
                "com_$arg" "$@"
-               if (("$ret" < 0)); then
+               if ((ret < 0)); then
                        gsu_err_msg
                        exit 1
                fi
                        gsu_err_msg
                        exit 1
                fi
@@ -877,6 +902,6 @@ gsu()
        ret=-$E_GSU_BAD_COMMAND
        result="$arg"
        gsu_err_msg
        ret=-$E_GSU_BAD_COMMAND
        result="$arg"
        gsu_err_msg
-       _gsu_print_available_commands
+       _gsu_print_available_commands 1>&2
        exit 1
 }
        exit 1
 }