[Bash-completion-commits] [SCM] bash-completion branch, master, updated. ebdd9cefdc33a80aa51192df66e24616ddb4a9b2
Crestez Dan Leonard
cdleonard at gmail.com
Tue Feb 9 13:57:43 UTC 2010
The following commit has been merged in the master branch:
commit ebdd9cefdc33a80aa51192df66e24616ddb4a9b2
Merge: 6b30acc9ac24a2bf9650499da7d805ad5cf4fea8 aac11de466f9a22312329e91769d0c84ae347407
Author: Crestez Dan Leonard <cdleonard at gmail.com>
Date: Tue Feb 9 15:45:40 2010 +0200
Merge branch 'space-fix': Fix tests when BASH_COMPLETION or TESTDIR contain
spaces.
Conflicts:
CHANGES
diff --combined CHANGES
index 2b0ff4e,c6baded..db5ef76
--- a/CHANGES
+++ b/CHANGES
@@@ -68,7 -68,7 +68,8 @@@ bash-completion (2.x
* Improve ssh -o suboption completion (Alioth: #312122).
* Fix NFS mounts completion (Alioth: #312285).
* Fix completion of usernames (Alioth: #311396, Debian: #511788).
+ * Fix chown test crashing on systems with no root group (Alioth: #312306).
+ * Fixed tests when BASH_COMPLETION or TESTDIR contain spaces.
[ Raphaël Droz ]
* Add xsltproc completion (Alioth: #311843).
diff --combined bash_completion
index 84f9bd0,8467272..904a8be
--- a/bash_completion
+++ b/bash_completion
@@@ -90,7 -90,7 +90,7 @@@ complete -f -X '!*.@(@(?(e)ps|?(E)PS|pd
complete -f -X '!*.@(okular|@(?(e|x)ps|?(E|X)PS|pdf|PDF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb|FB|mobi|MOBI|g3|G3|chm|CHM|fdf|FDF)?(.?(gz|GZ|bz2|BZ2)))' okular
complete -f -X '!*.@(?(e)ps|?(E)PS|pdf|PDF)' ps2pdf ps2pdf12 ps2pdf13 ps2pdf14 ps2pdfwr
complete -f -X '!*.texi*' makeinfo texi2html
-complete -f -X '!*.@(?(la)tex|?(LA)TEX|texi|TEXI|dtx|DTX|ins|INS)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi
+complete -f -X '!*.@(?(la)tex|?(LA)TEX|texi|TEXI|dtx|DTX|ins|INS|ltx|LTX)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi
complete -f -X '!*.@(mp3|MP3)' mpg123 mpg321 madplay
complete -f -X '!*@(.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp[234]|MP[234]|m4[pv]|M4[PV]|mkv|MKV|og[gmv]|OG[GMV]|wav|WAV|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))' xine aaxine fbxine kaffeine dragon
complete -f -X '!*.@(avi|asf|wmv)' aviplay
@@@ -253,142 -253,6 +253,142 @@@ __reassemble_comp_words_by_ref()
} # __reassemble_comp_words_by_ref()
+# @param $1 exclude Characters out of $COMP_WORDBREAKS which should NOT be
+# considered word breaks. This is useful for things like scp where
+# we want to return host:path and not only path, so we would pass the
+# colon (:) as $1 in this case. Bash-3 doesn't do word splitting, so this
+# ensures we get the same word on both bash-3 and bash-4.
+# @param $2 words Name of variable to return words to
+# @param $3 cword Name of variable to return cword to
+# @param $4 cur Name of variable to return current word to complete to
+# @see ___get_cword_at_cursor_by_ref()
+__get_cword_at_cursor_by_ref() {
+ # NOTE: The call to the main function ___get_cword_at_cursor_by_ref() is
+ # wrapped to make collisions with local variable names less likely.
+ local __words __cword __cur
+ ___get_cword_at_cursor_by_ref "$1" __words __cword __cur
+
+ eval $2=\( \"\${__words[@]}\" \)
+ eval $3=\$__cword
+ eval $4=\$__cur
+}
+
+
+# @param $1 exclude
+# @param $2 words Name of variable to return words to
+# @param $3 cword Name of variable to return cword to
+# @param $4 cur Name of variable to return current word to complete to
+# @note Do not call this function directly but call
+# `__get_cword_at_cursor_by_ref()' instead to make variable name collisions
+# less likely
+# @see __get_cword_at_cursor_by_ref()
+___get_cword_at_cursor_by_ref() {
+ local cword words
+ __reassemble_comp_words_by_ref "$1" words cword
+
+ local i
+ local cur="$COMP_LINE"
+ local index="$COMP_POINT"
+ for (( i = 0; i <= cword; ++i )); do
+ while [[
+ # Current word fits in $cur?
+ "${#cur}" -ge ${#words[i]} &&
+ # $cur doesn't match cword?
+ "${cur:0:${#words[i]}}" != "${words[i]}"
+ ]]; do
+ # Strip first character
+ cur="${cur:1}"
+ # Decrease cursor position
+ ((index--))
+ done
+
+ # Does found word matches cword?
+ if [[ "$i" -lt "$cword" ]]; then
+ # No, cword lies further;
+ local old_size="${#cur}"
+ cur="${cur#${words[i]}}"
+ local new_size="${#cur}"
+ index=$(( index - old_size + new_size ))
+ fi
+ done
+
+ if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then
+ # We messed up. At least return the whole word so things keep working
+ eval $4=\"\${words[cword]}\"
+ else
+ eval $4=\"\${cur:0:\$index}\"
+ fi
+
+ eval $2=\( \"\${words[@]}\" \)
+ eval $3=\$cword
+}
+
+
+# Get the word to complete and optional previous words.
+# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases
+# where the user is completing in the middle of a word.
+# (For example, if the line is "ls foobar",
+# and the cursor is here --------> ^
+# Also one is able to cross over possible wordbreak characters.
+# Usage: _get_comp_words_by_ref [OPTIONS] VAR1 [VAR2 [VAR3]]
+# Example usage:
+#
+# $ _get_comp_words_by_ref -n : cur prev
+#
+# Options: -n EXCLUDE Characters out of $COMP_WORDBREAKS which should NOT
+# be considered word breaks. This is useful for things like scp where
+# we want to return host:path and not only path, so we would pass the
+# colon (:) as -n option in this case. Bash-3 doesn't do word splitting,
+# so this ensures we get the same word on both bash-3 and bash-4.
+# @see __get_comp_words_by_ref
+_get_comp_words_by_ref() {
+ # NOTE: The call to the main function __get_comp_words_by_ref() is wrapped
+ # to make collisions with local variable name less likely.
+ local __words __cword __cur __var __vars
+ __get_comp_words_by_ref __words __cword __cur __vars "$@"
+ set -- "${__vars[@]}"
+ eval $1=\$__cur
+ shift
+ for __var; do
+ ((__cword--))
+ [[ ${__words[__cword]} ]] && eval $__var=\${__words[__cword]}
+ done
+}
+
+
+# @param $1 words Name of variable to return words to
+# @param $2 cword Name of variable to return cword to
+# @param $3 cur Name of variable to return current word to complete to
+# @param $4 varnames Name of variable to return array of variable names to
+# @param $@ Arguments to _get_comp_words_by_ref()
+# @note Do not call this function directly but call `_get_comp_words_by_ref()'
+# instead to make variable name collisions less likely
+# @see _get_comp_words_by_ref()
+__get_comp_words_by_ref()
+{
+ local exclude flag i OPTIND=5 # Skip first four arguments
+ local cword words cur varnames=()
+ while getopts "n:" flag "$@"; do
+ case $flag in
+ n) exclude=$OPTARG ;;
+ esac
+ done
+ varnames=( ${!OPTIND} )
+ let "OPTIND += 1"
+ while [[ $# -ge $OPTIND ]]; do
+ varnames+=( ${!OPTIND} )
+ let "OPTIND += 1"
+ done
+
+ __get_cword_at_cursor_by_ref "$exclude" words cword cur
+
+ eval $1=\( \"\${words[@]}\" \)
+ eval $2=\$cword
+ eval $3=\$cur
+ eval $4=\( \"\${varnames[@]}\" \)
+}
+
+
# Get the word to complete.
# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases
# where the user is completing in the middle of a word.
@@@ -1810,7 -1674,7 +1810,7 @@@ _filedir_xspec(
# get first exclusion compspec that matches this command
xspec=$( awk "/^complete[ \t]+.*[ \t]${1##*/}([ \t]|\$)/ { print \$0; exit }" \
- $BASH_COMPLETION )
+ "$BASH_COMPLETION" )
# prune to leave nothing but the -X spec
xspec=${xspec#*-X }
xspec=${xspec%% *}
@@@ -1837,7 -1701,7 +1837,7 @@@
COMPREPLY=( "${toks[@]}" )
}
- list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' $BASH_COMPLETION | \
+ list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' "$BASH_COMPLETION" | \
# read exclusion compspecs
(
while read line
@@@ -1863,19 -1727,19 +1863,19 @@@ unset lis
# source completion directory definitions
if [[ -d $BASH_COMPLETION_COMPAT_DIR && -r $BASH_COMPLETION_COMPAT_DIR && \
-x $BASH_COMPLETION_COMPAT_DIR ]]; then
- for i in $(LC_ALL=C command ls $BASH_COMPLETION_COMPAT_DIR); do
+ for i in $(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR"); do
i=$BASH_COMPLETION_COMPAT_DIR/$i
[[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)) \
- && ( -f $i || -h $i ) && -r $i ]] && . $i
+ && ( -f $i || -h $i ) && -r $i ]] && . "$i"
done
fi
if [[ $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_DIR && \
-d $BASH_COMPLETION_DIR && -r $BASH_COMPLETION_DIR && \
-x $BASH_COMPLETION_DIR ]]; then
- for i in $(LC_ALL=C command ls $BASH_COMPLETION_DIR); do
+ for i in $(LC_ALL=C command ls "$BASH_COMPLETION_DIR"); do
i=$BASH_COMPLETION_DIR/$i
[[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)) \
- && ( -f $i || -h $i ) && -r $i ]] && . $i
+ && ( -f $i || -h $i ) && -r $i ]] && . "$i"
done
fi
unset i
diff --combined test/lib/completions/screen.exp
index 53e94b1,f486b46..62c5736
--- a/test/lib/completions/screen.exp
+++ b/test/lib/completions/screen.exp
@@@ -18,7 -18,7 +18,7 @@@ sync_after_in
set test "-c should complete files/dirs"
-set dir fixture1
+set dir fixtures/shared/default
set prompt "/$dir/@"
assert_bash_exec "cd $dir" "" $prompt
set cmd "screen -c "
@@@ -42,7 -42,7 +42,7 @@@ expect
default { unresolved "$test" }
}; # expect
sync_after_int $prompt
- assert_bash_exec "cd \$TESTDIR"
+ assert_bash_exec {cd "$TESTDIR"}
diff --combined test/lib/completions/ssh.exp
index 2bec70c,8a0d88d..91955c1
--- a/test/lib/completions/ssh.exp
+++ b/test/lib/completions/ssh.exp
@@@ -29,7 -29,7 +29,7 @@@ expect
default { unresolved "$test" }
}; # expect
sync_after_int $prompt
- assert_bash_exec "cd \$TESTDIR"
+ assert_bash_exec {cd "$TESTDIR"}
sync_after_int
@@@ -52,17 -52,30 +52,17 @@@ sync_after_in
set test "First argument shouldn't complete with commands"
-# NOTE: This test assumes the machine running this test has a command "bash"
-# but no host named "bash" ...
+# NOTE: This test assumes there's a command "bash" and no host named "bash"
set cmd "ssh bas"
-send "$cmd\t"
-expect -ex "$cmd"
-expect {
- -timeout 1
- # In case multiple commands `bas*' - besides `bash' - are completed
- -re "^\r\n.*bash.*\r\n/@$cmd$" { fail "$test" }
- # In case the single command `bash' is completed
- -re "h $" { fail "$test" }
- # In case the hostname `bash_completion' is completed.
- # See `scp' tests in `lib/completions/scp.exp'
- -re "h_completion $" { pass "$test" }
- -re ".+" { unresolved "$test" }
- timeout { pass "$test" }
-}; # expect
+assert_complete [get_known_hosts "bas"] $cmd $test
sync_after_int
set test "First argument should complete partial hostname"
-assert_complete_partial [get_hosts] ssh "" $test /@ 20 [list "ltrim_colon_completions"]
+assert_complete_partial [get_hosts] ssh "" $test /@ 20 \
+ [list "ltrim_colon_completions"]
sync_after_int
@@@ -84,7 -97,7 +84,7 @@@ expect
default { unresolved "$test" }
}; # expect
sync_after_int $prompt
- assert_bash_exec "cd \$TESTDIR"
+ assert_bash_exec {cd "$TESTDIR"}
sync_after_int
diff --combined test/lib/library.exp
index 0092f3f,fa554c7..00dd846
--- a/test/lib/library.exp
+++ b/test/lib/library.exp
@@@ -79,22 -79,18 +79,22 @@@ proc assert_bash_type {command}
# @result boolean True if successful, False if not
proc assert_bash_list {expected cmd {test ""} {prompt /@} {size 20}} {
if {$test == ""} {set test "$cmd should show expected output"}
- send "$cmd\r"
- expect -ex "$cmd\r\n"
-
- if {[match_items $expected $test $prompt $size]} {
- expect {
- -re $prompt { pass "$test" }
- -re eof { unresolved "eof" }
- }; # expect
+ if {[llength $expected] == 0} {
+ assert_no_output $cmd $test $prompt
} else {
- fail "$test"
- }; # if
-}; # assert_bash_list()
+ send "$cmd\r"
+ expect -ex "$cmd\r\n"
+
+ if {[match_items $expected $test $prompt $size]} {
+ expect {
+ -re $prompt { pass "$test" }
+ -re eof { unresolved "eof" }
+ }
+ } else {
+ fail "$test"
+ }
+ }
+}
proc assert_bash_list_dir {expected cmd dir {test ""} {prompt /@} {size 20}} {
@@@ -102,7 -98,7 +102,7 @@@
assert_bash_exec "cd $dir" "" $prompt
assert_bash_list $expected $cmd $test $prompt $size
sync_after_int $prompt
- assert_bash_exec "cd \$TESTDIR"
+ assert_bash_exec {cd "$TESTDIR"}
}; # assert_bash_list_dir()
@@@ -272,7 -268,7 +272,7 @@@ proc assert_complete_dir {expected cmd
assert_bash_exec "cd $dir" "" $prompt
assert_complete $expected $cmd $test $prompt $size $cword
sync_after_int $prompt
- assert_bash_exec "cd \$TESTDIR"
+ assert_bash_exec {cd "$TESTDIR"}
}; # assert_complete_dir
@@@ -455,43 -451,6 +455,43 @@@ proc assert_no_complete {{cmd} {test ""
}; # assert_no_complete()
+# Check that no output is generated on a certain command.
+# @param string $cmd The command to attempt to complete.
+# @param string $test Optional parameter with test name.
+# @param string $prompt (optional) Bash prompt. Default is "/@"
+proc assert_no_output {{cmd} {test ""} {prompt /@}} {
+ if {[string length $test] == 0} {
+ set test "$cmd shouldn't generate output"
+ }
+
+ send "$cmd\r"
+ expect -ex "$cmd"
+
+ expect {
+ -re "^\r\n$prompt$" { pass "$test" }
+ default { fail "$test" }
+ timeout { fail "$test" }
+ }
+}
+
+
+# Source/run file with additional tests if completion for the specified command
+# is installed in bash.
+# @param string $command Command to check completion availability for.
+# @param string $file (optional) File to source/run. Default is
+# "lib/completions/$cmd.exp".
+proc assert_source_completions {command {file ""}} {
+ if {[is_bash_completion_installed_for $command]} {
+ if {[string length $file] == 0} {
+ set file "lib/completions/$command.exp"
+ }
+ source $file
+ } else {
+ untested $command
+ }
+}; # assert_source_completions()
+
+
# Sort list.
# `exec sort' is used instead of `lsort' to achieve exactly the
# same sort order as in bash.
@@@ -503,12 -462,10 +503,12 @@@ proc bash_sort {items}
# Get 'known' hostnames. Looks also in ssh's 'known_hosts' files.
+# @param string cword (optional) Word, hosts should start with.
# @return list Hostnames
# @see get_hosts()
-proc get_known_hosts {} {
- assert_bash_exec {_known_hosts_real ''; echo_array COMPREPLY} {} /@ result
+proc get_known_hosts {{cword ''}} {
+ assert_bash_exec "_known_hosts_real '$cword'; echo_array COMPREPLY" \
+ {} /@ result
return $result
}; # get_known_hosts()
@@@ -575,24 -532,6 +575,24 @@@ proc init_tcl_bash_globals {}
}; # init_tcl_bash_globals()
+# Check whether completion is installed for the specified command by executing
+# `complete -p ...' in bash.
+# @param string $command Command to check completion availability for.
+# @return boolean True (1) if completion is installed, False (0) if not.
+proc is_bash_completion_installed_for {command} {
+ set test "$command should have completion installed in bash"
+ set cmd "complete -p $command &> /dev/null && echo -n 0 || echo -n 1"
+ send "$cmd\r"
+ expect "$cmd\r\n"
+ expect {
+ -ex 0 { set result true }
+ -ex 1 { set result false }
+ }
+ expect "/@"
+ return $result
+}; # is_bash_completion_installed_for()
+
+
# Detect if test suite is running under Cygwin/Windows
proc is_cygwin {} {
expr {[string first [string tolower [exec uname -s]] cygwin] >= 0}
@@@ -692,16 -631,16 +692,16 @@@ proc save_env {{file ""}}
# @param string File to save the environment to. Default is "$TESTDIR/tmp/env1~".
# @see assert_env_unmodified()
proc _save_env {{file ""}} {
- assert_bash_exec "{ set; declare -F; shopt -p; } > $file"
+ assert_bash_exec "{ set; declare -F; shopt -p; } > \"$file\""
}; # _save_env()
# Source bash_completion package
proc source_bash_completion {} {
- assert_bash_exec {BASH_COMPLETION_DIR=$(cd $TESTDIR/..; pwd)/contrib}
+ assert_bash_exec {BASH_COMPLETION_DIR=$(cd "$TESTDIR/.."; pwd)/contrib}
assert_bash_exec {BASH_COMPLETION_COMPAT_DIR=$BASH_COMPLETION_DIR}
- assert_bash_exec {BASH_COMPLETION=$(cd $TESTDIR/..; pwd)/bash_completion}
- assert_bash_exec {source $BASH_COMPLETION}
+ assert_bash_exec {BASH_COMPLETION=$(cd "$TESTDIR/.."; pwd)/bash_completion}
+ assert_bash_exec {source "$BASH_COMPLETION"}
}; # source_bash_completion()
@@@ -745,73 -684,6 +745,73 @@@ proc split_words_bash {line}
}; # split_words_bash()
+# Given a list of items this proc finds a (part, full) pair so that when
+# completing from $part $full will be the only option.
+#
+# Arguments:
+# list The list of full completions.
+# partName Output parameter for the partial string.
+# fullName Output parameter for the full string, member of item.
+#
+# Results:
+# 1, or 0 if no suitable result was found.
+proc find_unique_completion_pair {{list} {partName} {fullName}} {
+ upvar $partName part
+ upvar $fullName full
+ set bestscore 0
+ set list [lsort $list]
+ set n [llength $list]
+ for {set i 0} {$i < $n} {incr i} {
+ set cur [lindex $list $i]
+ set curlen [string length $cur]
+
+ set prev [lindex $list [expr {$i - 1}]]
+ set next [lindex $list [expr {$i + 1}]]
+ set diffprev [expr {$prev == ""}]
+ set diffnext [expr {$next == ""}]
+
+ # Analyse each item of the list and look for the minimum length of the
+ # partial prefix which is distinct from both $next and $prev. The list
+ # is sorted so the prefix will be unique in the entire list.
+ #
+ # In the worst case we analyse every character in the list 3 times.
+ # That's actually very fast, sorting could take more.
+ for {set j 0} {$j < $curlen} {incr j} {
+ set curchar [string index $cur $j]
+ if {!$diffprev && [string index $prev $j] != $curchar} {
+ set diffprev 1
+ }
+ if {!$diffnext && [string index $next $j] != $curchar} {
+ set diffnext 1
+ }
+ if {$diffnext && $diffprev} {
+ break
+ }
+ }
+
+ # At the end of the loop $j is the index of last character of
+ # the unique partial prefix. The length is one plus that.
+ set parlen [expr {$j + 1}]
+ if {$parlen >= $curlen} {
+ continue
+ }
+
+ # Try to find the most "readable pair"; look for a long pair where
+ # $part is about half of $full.
+ if {$parlen < $curlen / 2} {
+ set parlen [expr {$curlen / 2}]
+ }
+ set score [expr {$curlen - $parlen}]
+ if {$score > $bestscore} {
+ set bestscore $score
+ set part [string range $cur 0 [expr {$parlen - 1}]]
+ set full $cur
+ }
+ }
+ return [expr {$bestscore != 0}]
+}
+
+
# Start bash running as test environment.
proc start_bash {} {
global TESTDIR TOOL_EXECUTABLE spawn_id
--
bash-completion
More information about the Bash-completion-commits
mailing list