[Bash-completion-commits] [SCM] bash-completion branch, master, updated. 1.3-241-g0a40e98

Ville Skyttä ville.skytta at iki.fi
Mon May 2 12:23:09 UTC 2011


The following commit has been merged in the master branch:
commit 68f6f1c685fd9742b97b42d96739ebb52c1ffb35
Author: Ville Skyttä <ville.skytta at iki.fi>
Date:   Mon May 2 13:34:56 2011 +0300

    _parse_usage, _parse_help: Add _parse_usage, expand [no-] and [dont-?] as well in _parse_help.

diff --git a/bash_completion b/bash_completion
index 70591f1..77e76b3 100644
--- a/bash_completion
+++ b/bash_completion
@@ -747,40 +747,81 @@ _init_completion()
     return 0
 }
 
-# This function tries to parse the help output of the given command.
+# Helper function for _parse_help and _parse_usage.
+__parse_options()
+{
+    local option option2 i IFS=$' \t\n,/|'
+
+    # Take first found long option, or first one (short) if not found.
+    option=
+    for i in $1; do
+        case $i in
+            ---*) break ;;
+            --?*) option=$i ; break ;;
+            -?*)  [[ $option ]] || option=$i ;;
+            *)    break ;;
+        esac
+    done
+    [[ $option ]] || return
+
+    IFS=$' \t\n' # affects parsing of the regexps below...
+
+    # Expand --[no]foo to --foo and --nofoo etc
+    if [[ $option =~ (\[((no|dont)-?)\]). ]]; then
+        option2=${option/"${BASH_REMATCH[1]}"/}
+        option2=${option2%%[<{[]*}
+        printf '%s\n' "${option2/=*/=}"
+        option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"}
+    fi
+
+    option=${option%%[<{[]*}
+    printf '%s\n' "${option/=*/=}"
+}
+
+# Parse GNU style help output of the given command.
 # @param $1  command
 # @param $2  command options (default: --help)
 #
 _parse_help()
 {
     eval local cmd=$1
-    local line i option option2 IFS=$' \t\n,/|'
+    local line
     "$cmd" ${2:---help} 2>&1 | while read line; do
 
         [[ $line == *([ $'\t'])-* ]] || continue
+        __parse_options "$line"
 
-        # Take first found long option, or first one (short) if not found.
-        option=
-        for i in $line; do
-            case $i in
-                ---*) break ;;
-                --?*) option=$i ; break ;;
-                -?*)  [[ $option ]] || option=$i ;;
-                *)    break ;;
+    done
+}
+
+# Parse BSD style usage output (options in brackets) of the given command.
+# @param $1  command
+# @param $2  command options (default: --usage)
+#
+_parse_usage()
+{
+    eval local cmd=$1
+    local line match option i char
+    "$cmd" ${2:---usage} 2>&1 | while read -r line; do
+
+        while [[ $line =~ \[(-[^]]+)\] ]]; do
+            match=${BASH_REMATCH[0]}
+            option=${BASH_REMATCH[1]}
+            case $option in
+                -?(\[)+([a-zA-Z0-9?]))
+                    # Treat as bundled short options
+                    for (( i=1; i < ${#option}; i++ )); do
+                        char=${option:i:1}
+                        [[ $char != '[' ]] && printf '%s\n' -$char
+                    done
+                    ;;
+                *)
+                    __parse_options "$option"
+                    ;;
             esac
+            line=${line#*"$match"}
         done
-        [[ $option ]] || continue
-
-        # Expand --[no]foo to --foo and --nofoo
-        if [[ $option == *\[no\]?* ]]; then
-            option2=${option/\[no\]/}
-            option2=${option2%%[<{[]*}
-            printf '%s\n' "${option2/=*/=}"
-            option=${option/\[no\]/no}
-        fi
 
-        option=${option%%[<{[]*}
-        printf '%s\n' "${option/=*/=}"
     done
 }
 
diff --git a/test/unit/_parse_help.exp b/test/unit/_parse_help.exp
index c746b65..9c38dea 100644
--- a/test/unit/_parse_help.exp
+++ b/test/unit/_parse_help.exp
@@ -93,6 +93,22 @@ set cmd {fn() { printf '%s\n' "--[no]foo"; }; _parse_help fn}
 assert_bash_list "--foo\n--nofoo" $cmd "long with \[no\]"
 sync_after_int
 
+set cmd {fn() { printf '%s\n' "--[no-]bar[=quux]"; }; _parse_help fn}
+assert_bash_list "--bar\n--no-bar" $cmd "long with \[no-\] + optional arg"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "--[no-]bar=quux"; }; _parse_help fn}
+assert_bash_list "--bar=\n--no-bar=" $cmd "long with \[no-\] + required arg"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "--[dont-]foo"; }; _parse_help fn}
+assert_bash_list "--foo\n--dont-foo" $cmd "long with \[dont-\]"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "-[dont]x, --[dont]yy"; }; _parse_help fn}
+assert_bash_list "--yy\n--dontyy" $cmd "short and long with \[dont\]"
+sync_after_int
+
 set cmd {fn() { printf '%s\n' "----\n---foo\n----- bar"; }; _parse_help fn}
 assert_bash_list "" $cmd "more than two dashes"
 sync_after_int
diff --git a/test/unit/_parse_usage.exp b/test/unit/_parse_usage.exp
new file mode 100644
index 0000000..6c7cd66
--- /dev/null
+++ b/test/unit/_parse_usage.exp
@@ -0,0 +1,51 @@
+proc setup {} {
+    save_env
+}
+
+proc teardown {} {
+    assert_env_unmodified {
+        /declare -f fn/d
+    }
+}
+
+setup
+
+
+set cmd {fn() { printf '%s\n' ""; }; _parse_usage fn}
+assert_bash_list "" $cmd "empty"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "no dashes here"; }; _parse_usage fn}
+assert_bash_list "" $cmd "no dashes"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "foo [-f]"; }; _parse_usage fn}
+assert_bash_list "-f" $cmd "simple"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "bar [-aBcD] [-e X]"; }; _parse_usage fn}
+assert_bash_list "-a -B -c -D -e" $cmd "bundled + separate 1 short"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "[-[XyZ]] [--long=arg]"; }; _parse_usage fn}
+assert_bash_list "-X -y -Z --long=" $cmd "bundled in brackets + separate long"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "[-s|--long]"; }; _parse_usage fn}
+assert_bash_list "--long" $cmd "short or long"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "[-s, --long=arg]"; }; _parse_usage fn}
+assert_bash_list "--long=" $cmd "short or long with arg, comma"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "[--long/-s] [-S/--longer]"; }; _parse_usage fn}
+assert_bash_list "--long\n--longer" $cmd "long or short, slash"
+sync_after_int
+
+set cmd {fn() { printf '%s\n' "----\n---foo\n----- bar"; }; _parse_usage fn}
+assert_bash_list "" $cmd "many dashes"
+sync_after_int
+
+
+teardown

-- 
bash-completion



More information about the Bash-completion-commits mailing list