diff --git a/CHANGES b/CHANGES index c76677a6..399f4344 100644 --- a/CHANGES +++ b/CHANGES @@ -29,8 +29,8 @@ bash-completion (2.x) mysqladmin, rsync, screen, service, scp, ssh, sshfs, update-alternatives, vncviewer, and general hostname completions. * Add abook and wtf completion, based on work by Raphaƫl Droz. - * Add cvsps, fusermount, jarsigner, k3b, lftpget, pm-utils, pack200 and - unpack200 completions. + * Add cvsps, fusermount, jarsigner, k3b, lftpget, pm-utils, rtcwake, pack200 + and unpack200 completions. * Don't overwrite other host completions when completing from multiple SSH known hosts files. * Speed up installed rpm package completion on SUSE, based on work by diff --git a/Makefile.am b/Makefile.am index 5b1a0616..aa677083 100644 --- a/Makefile.am +++ b/Makefile.am @@ -117,6 +117,7 @@ bashcomp_DATA = contrib/abook \ contrib/rpmcheck \ contrib/rrdtool \ contrib/rsync \ + contrib/rtcwake \ contrib/samba \ contrib/sbcl \ contrib/screen \ diff --git a/bash_completion b/bash_completion index 248bd25a..0747fd66 100644 --- a/bash_completion +++ b/bash_completion @@ -222,14 +222,19 @@ __reassemble_comp_words_by_ref() { exclude="${1//[^$COMP_WORDBREAKS]}" fi + # Default to cword unchanged + eval $3=$COMP_CWORD # Are characters excluded which were former included? if [[ $exclude ]]; then # Yes, list of word completion separators has shrunk; # Re-assemble words to complete for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do - # Is current word not word 0 (the command itself) and is word made up of - # just word separators characters to be excluded? - while [[ $i -gt 0 && ${COMP_WORDS[$i]//[^$exclude]} ]]; do + # Is current word not word 0 (the command itself) and is word not + # empty and is word made up of just word separator characters to be + # excluded? + while [[ $i -gt 0 && ${COMP_WORDS[$i]} && + ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]} + ]]; do [ $j -ge 2 ] && ((j--)) # Append word separator to current word ref="$2[$j]" @@ -243,12 +248,11 @@ __reassemble_comp_words_by_ref() { ref="$2[$j]" eval $2[$j]=\${!ref}\${COMP_WORDS[i]} # Indicate new cword - [ $i = $COMP_CWORD ] && eval $3=$j + [ $i = $COMP_CWORD ] && [[ ${COMP_WORDS[i]} ]] && eval $3=$j done else # No, list of word completions separators hasn't changed; eval $2=\( \"\${COMP_WORDS[@]}\" \) - eval $3=$COMP_CWORD fi } # __reassemble_comp_words_by_ref() diff --git a/contrib/rtcwake b/contrib/rtcwake new file mode 100644 index 00000000..0169fb61 --- /dev/null +++ b/contrib/rtcwake @@ -0,0 +1,39 @@ +# bash completion for rtcwake + +have rtcwake && +_rtcwake() +{ + COMPREPLY=() + local cur=`_get_cword` prev=`_get_pword` split=false + + _split_longopt && split=true + + case "$prev" in + --help|-h|--version|-V|--seconds|-s|--time|-t) + return 0 + ;; + --mode|-m) + COMPREPLY=( $( compgen -W 'standby mem disk on no off' -- "$cur" ) ) + return 0 + ;; + --device|-d) + COMPREPLY=( $( command ls -d /dev/rtc?* 2>/dev/null ) ) + COMPREPLY=( $( compgen -W '${COMPREPLY[@]#/dev/}' -- "$cur" ) ) + return 0 + ;; + esac + + $split && return 0 + + COMPREPLY=( $( compgen -W '--device --local --mode --seconds --time --utc \ + --verbose --version --help' -- "$cur" ) ) +} && +complete -F _rtcwake rtcwake + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh diff --git a/test/completion/rtcwake.exp b/test/completion/rtcwake.exp new file mode 100644 index 00000000..3970a42a --- /dev/null +++ b/test/completion/rtcwake.exp @@ -0,0 +1,3 @@ +if {[assert_bash_type rtcwake]} { + source "lib/completions/rtcwake.exp" +}; # if diff --git "a/test/fixtures/_filedir/a\\b/g" "b/test/fixtures/_filedir/a\\b/g" deleted file mode 100644 index e69de29b..00000000 diff --git a/test/lib/completions/rtcwake.exp b/test/lib/completions/rtcwake.exp new file mode 100644 index 00000000..0b9a974b --- /dev/null +++ b/test/lib/completions/rtcwake.exp @@ -0,0 +1,20 @@ +proc setup {} { + save_env +}; # setup() + + +proc teardown {} { + assert_env_unmodified +}; # teardown() + + +setup + + +assert_complete_any "rtcwake " + + +sync_after_int + + +teardown diff --git a/test/lib/library.exp b/test/lib/library.exp index e5ce9716..0e457c84 100644 --- a/test/lib/library.exp +++ b/test/lib/library.exp @@ -417,6 +417,16 @@ proc assert_exec {cmd {stdout ''} {test ''}} { }; # assert_exec() +# Sort list. +# `exec sort' is used instead of `lsort' to achieve exactly the +# same sort order as in bash. +# @param list $items +# @return list Sort list +proc bash_sort {items} { + return [split [exec sort << [join $items "\n"]] "\n"] +}; # bash_sort() + + # Get hostnames # @return list Hostnames proc get_hosts {} { @@ -467,16 +477,6 @@ proc get_signals {} { }; # get_signals() -# Sort list. -# `exec sort' is used instead of `lsort' to achieve exactly the -# same sort order as in bash. -# @param list $items -# @return list Sort list -proc bash_sort {items} { - return [split [exec sort << [join $items "\n"]] "\n"] -}; # bash_sort() - - # Initialize tcl globals with bash variables proc init_tcl_bash_globals {} { global BASH_VERSINFO BASH_VERSION COMP_WORDBREAKS @@ -488,6 +488,12 @@ proc init_tcl_bash_globals {} { }; # init_tcl_bash_globals() +# Detect if test suite is running under Cygwin/Windows +proc is_cygwin {} { + expr {[string first [string tolower [exec uname -s]] cygwin] >= 0} +}; # is_cygwin() + + # Expect items. # Break items into chunks because `expect' seems to have a limited buffer size # @param list $items diff --git a/test/unit/_filedir.exp b/test/unit/_filedir.exp index c5dd877e..2e4591e8 100644 --- a/test/unit/_filedir.exp +++ b/test/unit/_filedir.exp @@ -11,15 +11,22 @@ proc setup {} { assert_bash_exec { \ complete -F _f -o filenames f2 \ } - # Create directory `a*b' - # NOTE: directory `a*b' isn't included in Git, because a directory - # containing an asterisk (*) causes troubles on Cygwin/Windows - assert_bash_exec {(cd fixtures/_filedir && [ ! -d a\*b ] && mkdir a\*b && touch a\*b/j || true)} + # Create directories `a*b' and `a\b' only when not running on Cygwin/Windows; + # directories containing `*' or `\' aren't allowed on Cygwin/Windows + if {! [is_cygwin]} { + # Create directory `a*b' + assert_bash_exec {(cd fixtures/_filedir && [ ! -d a\*b ] && mkdir a\*b && touch a\*b/j || true)} + # Create directory `a\b' + assert_bash_exec {(cd fixtures/_filedir && [ ! -d a\\b ] && mkdir a\\b && touch a\\b/g || true)} + }; # if }; # setup() proc teardown {} { - assert_bash_exec {(cd fixtures/_filedir && rm -- a\*b/j && rmdir a\*b/ || true)} + if {! [is_cygwin]} { + assert_bash_exec {(cd fixtures/_filedir && rm -- a\\b/g && rmdir a\\b/ || true)} + assert_bash_exec {(cd fixtures/_filedir && rm -- a\*b/j && rmdir a\*b/ || true)} + }; # if assert_bash_exec {unset COMPREPLY cur} assert_bash_exec {unset -f _f} assert_bash_exec {complete -r f} @@ -79,12 +86,17 @@ foreach name {f f2} { sync_after_int - set test "completing $name a\\\\b/ should return g" - set cmd "$name a\\\\b/" - assert_complete_dir g $cmd "fixtures/_filedir" + # Execute these tests only when not running on Cygwin/Windows, because + # directories containing asterisk (*) or backslash (\) aren't allowed on + # Cygwin/Windows + if {! [is_cygwin]} { + set test "completing $name a\\\\b/ should return g" + set cmd "$name a\\\\b/" + assert_complete_dir g $cmd "fixtures/_filedir" - sync_after_int + sync_after_int + }; # if set test "completing $name a\\&b/ should return f" @@ -147,12 +159,16 @@ foreach name {f f2} { sync_after_int - set test "completing $name 'a\\b/ should return g" - set cmd "$name 'a\\b/" - assert_complete_dir {g'} $cmd "fixtures/_filedir" + # Execute these tests only when not running on Cygwin/Windows, because + # directories containing `*' or `\' aren't allowed on Cygwin/Windows + if {! [is_cygwin]} { + set test "completing $name 'a\\b/ should return g" + set cmd "$name 'a\\b/" + assert_complete_dir {g'} $cmd "fixtures/_filedir" - sync_after_int + sync_after_int + }; # if set test "completing $name 'a&b/ should return f" diff --git a/test/unit/_get_cword.exp b/test/unit/_get_cword.exp index 7e38e9ed..25e0e8d5 100644 --- a/test/unit/_get_cword.exp +++ b/test/unit/_get_cword.exp @@ -45,6 +45,24 @@ expect -ex "$cmd\r\n/@" {pass "$test"} sync_after_int +set test "a b | should return nothing"; # | = cursor position +set cmd {COMP_WORDS=(a b ''); COMP_CWORD=2; COMP_LINE='a b '; COMP_POINT=4; _get_cword} +send "$cmd\r" +expect -ex "$cmd\r\n/@" {pass "$test"} + + +sync_after_int + + +set test "a b | with WORDBREAKS -= : should return nothing"; # | = cursor position +set cmd {COMP_WORDS=(a b ''); COMP_CWORD=2; COMP_LINE='a b '; COMP_POINT=4; _get_cword :} +send "$cmd\r" +expect -ex "$cmd\r\n/@" {pass "$test"} + + +sync_after_int + + set test "a b|c should return b"; # | = cursor position set cmd {COMP_WORDS=(a bc); COMP_CWORD=1; COMP_LINE='a bc'; COMP_POINT=3; _get_cword} assert_bash_list b $cmd $test @@ -161,6 +179,19 @@ assert_bash_list b:c $cmd $test sync_after_int +set test {a b c:| with WORDBREAKS -= : should return c:}; # | = cursor position +if {[lindex $::BASH_VERSINFO 0] <= 3} { + set cmd {COMP_WORDS=(a b c:); COMP_CWORD=2} +} else { + set cmd {COMP_WORDS=(a b c :); COMP_CWORD=3} +}; # if +append cmd {; COMP_LINE='a b c:'; COMP_POINT=6; _get_cword :} +assert_bash_list c: $cmd $test + + +sync_after_int + + set test {a :| with WORDBREAKS -= : should return :}; # | = cursor position set cmd {COMP_WORDS=(a :); COMP_CWORD=1; COMP_LINE='a :'; COMP_POINT=3; _get_cword :} assert_bash_list : $cmd $test