diff options
author | Freddy Vulto <fvulto@gmail.com> | 2009-12-02 22:38:30 +0100 |
---|---|---|
committer | Freddy Vulto <fvulto@gmail.com> | 2009-12-02 22:38:30 +0100 |
commit | eb860b7b9f88f0a42bccfc66ab72133cca7bac9f (patch) | |
tree | aadbc7558c5ca6635123f6d637eeb29a250abb66 | |
parent | 048e27bf283e08be6762fe2090be224fc6c98fc3 (diff) | |
download | bash-completion-eb860b7b9f88f0a42bccfc66ab72133cca7bac9f.tar.gz |
Added helper function __expand_tilde_by_ref()
Expands only tilde (~), if first char, in variable.
This function displays bash's capabilities of passing a variable by
reference (variable indirection) which allows us to avoid using a
subshell. As far as I can see it works surprisingly well?
To run the automated test:
./runUnit __expand_tilde_by_ref.exp
Also fixed some testsuite issues regarding list splitting.
-rw-r--r-- | bash_completion | 44 | ||||
-rw-r--r-- | test/lib/library.exp | 14 | ||||
-rw-r--r-- | test/unit/__expand_tilde_by_ref.exp | 87 | ||||
-rw-r--r-- | test/unit/_get_cword.exp | 6 | ||||
-rw-r--r-- | test/unit/_known_hosts_real.exp | 8 |
5 files changed, 148 insertions, 11 deletions
diff --git a/bash_completion b/bash_completion index 12a4f3fb..97320109 100644 --- a/bash_completion +++ b/bash_completion @@ -557,6 +557,46 @@ _available_interfaces() COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) ) } + +# Expand variable starting with tilde (~) +# Only the first portion of the variable from the tilde up to the first slash +# (~../) is expanded. The remainder of the variable, containing for example +# a dollar sign variable ($) or asterisk (*) is not expanded. +# Example usage: +# +# $ v="~"; __expand_tilde v; echo "$v" +# +# Example output: +# +# v output +# -------- ---------------- +# ~ /home/user +# ~foo/bar /home/foo/bar +# ~foo/$HOME /home/foo/$HOME +# ~foo/a b /home/foo/a b +# ~foo/* /home/foo/* +# +# @param $1 Name of variable (not the value of the variable) to expand +__expand_tilde_by_ref() { + # Does $1 start with tilde (~)? + if [ "${!1:0:1}" = "~" ]; then + # Does $1 contain slash (/)? + if [ "${!1}" != "${!1//\/}" ]; then + # Yes, $1 contains slash; + # 1: Remove * including and after first slash (/), i.e. "~a/b" + # becomes "~a". Double quotes allow eval. + # 2: Remove * before the first slash (/), i.e. "~a/b" + # becomes "b". Single quotes prevent eval. + # +-----1----+ +---2----+ + eval $1="${!1/%\/*}"/'${!1#*/}' + else + # No, $1 doesn't contain slash + eval $1="${!1}" + fi + fi +} # __expand_tilde_by_ref() + + # This function expands tildes in pathnames # _expand() @@ -1270,8 +1310,8 @@ _known_hosts_real() for i in "${tmpkh[@]}"; do # Remove possible quotes i=${i//\"} - # Eval/expand `~' or `~user', only if first char is tilde (~) - [ "${i:0:1}" = "~" ] && i=$( eval echo "$i" ) + # Eval/expand possible `~' or `~user' + __expand_tilde_by_ref i [ -r "$i" ] && kh=( "${kh[@]}" "$i" ) done IFS=$OIFS diff --git a/test/lib/library.exp b/test/lib/library.exp index 7a13b9fa..3fa1f8e5 100644 --- a/test/lib/library.exp +++ b/test/lib/library.exp @@ -458,6 +458,16 @@ 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() + + # Expect items. # Break items into chunks because `expect' seems to have a limited buffer size # @param list $items @@ -466,8 +476,8 @@ proc get_signals {} { proc match_items {items test {size 20}} { # NOTE: `exec sort' is used instead of `lsort' to achieve exactly the # same sort order as in bash -- FVu, Wed Nov 25 22:25:28 CET 2009 - #set items [list [exec sort << [join $items "\n"]]] - set items [exec sort << [join $items "\n"]] + set items [bash_sort $items] + #set items [exec sort << [join $items "\n"]] set result false for {set i 0} {$i < [llength $items]} {set i [expr {$i + $size}]} { set expected "" diff --git a/test/unit/__expand_tilde_by_ref.exp b/test/unit/__expand_tilde_by_ref.exp new file mode 100644 index 00000000..d4a75d11 --- /dev/null +++ b/test/unit/__expand_tilde_by_ref.exp @@ -0,0 +1,87 @@ +# @param string $out Reference to variable to hold value of bash environment +# variable $HOME. +proc setup {home user} { + upvar $home _home + upvar $user _user + save_env + assert_bash_exec {echo "$HOME"} {} /@ _home + set _home [string trim $_home] + assert_bash_exec {echo "$USER"} {} /@ _user + set _user [string trim $_user] +}; # setup() + + +proc teardown {} { + assert_env_unmodified { + /var=/d + } +}; # teardown() + + +setup home user + + +set test "function should run without errors" +assert_bash_exec {__expand_tilde_by_ref > /dev/null} $test + + +sync_after_int + + +set test "function should not pollute environment" +# NOTE: A possible environment pollution is detected by assert_env_modified() in teardown() +assert_bash_exec {foo() { local aa="~"; __expand_tilde_by_ref aa; }; foo; unset foo} $test + + +sync_after_int + + +set test "~user should return /home/user" +set cmd [format {var="~%s"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user] +assert_bash_list "$home" $cmd $test + + +sync_after_int + + +set test "~/foo should return /home/user/foo" +set cmd {var='~/foo'; __expand_tilde_by_ref var; printf "%s" "$var"} +assert_bash_list "$home/foo" $cmd $test + + +sync_after_int + + +set test "~user/bar should return /home/user/bar" +set cmd [format {var="~%s/bar"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user] +assert_bash_list "$home/bar" $cmd $test + + +sync_after_int + + +set test "~user/\$HOME should return /home/user/\$HOME" +set cmd [format {var="~%s/\$HOME"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user] +assert_bash_list "$home/\$HOME" $cmd $test + + +sync_after_int + + +set test "'~user/a b' should return '/home/user/a b'" +set cmd [format {var="~%s/a b"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user] +assert_bash_list [list [format {%s/a b} $home]] $cmd $test + + +sync_after_int + + +set test "~user/* should return /home/user/*" +set cmd [format {var="~%s/*"; __expand_tilde_by_ref var; printf "%%s" "$var"} $user] +assert_bash_list "$home/\*" $cmd $test + + +sync_after_int + + +teardown diff --git a/test/unit/_get_cword.exp b/test/unit/_get_cword.exp index ec29bf17..5d032eb8 100644 --- a/test/unit/_get_cword.exp +++ b/test/unit/_get_cword.exp @@ -57,7 +57,7 @@ sync_after_int set test {a b\ c| should return b\ c}; # | = cursor position set cmd {COMP_WORDS=(a 'b\ c'); COMP_CWORD=1; COMP_LINE='a b\ c'; COMP_POINT=6; _get_cword} -assert_bash_list {{"b\\ c"}} $cmd $test +assert_bash_list {"b\\ c"} $cmd $test sync_after_int @@ -65,7 +65,7 @@ sync_after_int set test {a b\| c should return b\ }; # | = cursor position set cmd {COMP_WORDS=(a 'b\ c'); COMP_CWORD=1; COMP_LINE='a b\ c'; COMP_POINT=4; _get_cword} -assert_bash_list {{"b\\"}} $cmd $test +assert_bash_list {"b\\"} $cmd $test sync_after_int @@ -73,7 +73,7 @@ sync_after_int set test {a "b\| should return "b\ }; # | = cursor position set cmd {COMP_WORDS=(a '"b\'); COMP_CWORD=1; COMP_LINE='a "b\'; COMP_POINT=5; _get_cword} -assert_bash_list {{"\"b\\"}} $cmd $test +assert_bash_list {"\"b\\"} $cmd $test sync_after_int diff --git a/test/unit/_known_hosts_real.exp b/test/unit/_known_hosts_real.exp index 0cdf63ce..152cf885 100644 --- a/test/unit/_known_hosts_real.exp +++ b/test/unit/_known_hosts_real.exp @@ -53,9 +53,9 @@ lappend hosts gee hus two set hosts_config $hosts # Hosts `doo' and `ike' are defined in `./fixtures/_known_hosts_/spaced known_hosts' lappend hosts doo ike -set hosts [join [lsort -ascii $hosts ] "\\s+"] -set hosts_orig [join [lsort -ascii $hosts_orig ] "\\s+"] -set hosts_config [join [lsort -ascii $hosts_config] "\\s+"] +set hosts [join [bash_sort $hosts ] "\\s+"] +set hosts_orig [join [bash_sort $hosts_orig ] "\\s+"] +set hosts_config [join [bash_sort $hosts_config] "\\s+"] # Call _known_hosts set cmd {unset COMPREPLY; _known_hosts_real -aF 'fixtures/_known_hosts_real/spaced conf' ''; echo_array COMPREPLY} send "$cmd\r" @@ -77,7 +77,7 @@ set hosts [get_hosts] # Host `two' is defined in ./fixtures/_known_hosts_real/known_hosts2 # Host `three' is defined in ./fixtures/_known_hosts_real/known_hosts3 lappend hosts two three -set hosts [join [lsort -ascii $hosts] "\\s+"] +set hosts [join [bash_sort $hosts] "\\s+"] # Setup environment set cmd {OLDHOME=$HOME; HOME=$TESTDIR} send "$cmd\r" |