Improve _get_comp_words_by_ref to return `words' and `cword'

Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]
Available VARNAMES:
    cur         Return cur within varname "cur"
    prev        Return prev within varname "prev"
    words       Return words within varname "words"
    cword       Return cword within varname "cword"

Available 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.
    -c VARNAME  Return cur within specified VARNAME
    -p VARNAME  Return prev within specified VARNAME
    -w VARNAME  Return words within specified VARNAME
    -i VARNAME  Return words within specified VARNAME

Example usage:

   $ _get_comp_words_by_ref -n : cur prev
master
Freddy Vulto 2010-03-14 11:07:13 +01:00
parent f8bafe285e
commit bdca37a7bf
2 changed files with 112 additions and 32 deletions

View File

@ -330,53 +330,83 @@ ___get_cword_at_cursor_by_ref() {
# (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]]
# Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]
# Available VARNAMES:
# cur Return cur within varname "cur"
# prev Return prev within varname "prev"
# words Return words within varname "words"
# cword Return cword within varname "cword"
#
# Available 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.
# -c VARNAME Return cur within specified VARNAME
# -p VARNAME Return prev within specified VARNAME
# -w VARNAME Return words within specified VARNAME
# -i VARNAME Return words within specified VARNAME
#
# 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
# to make collisions with local variable names less likely.
local __words __cword __cur
local __var_cur __var_prev __var_words __var_cword
__get_comp_words_by_ref \
__words __cword __cur \
__var_cur __var_prev __var_words __var_cword "$@"
[[ $__var_cur ]] && eval $__var_cur=\$__cur
[[ $__var_prev ]] && ((__cword)) && eval $__var_prev=\${__words[__cword - 1]}
[[ $__var_words ]] && eval $__var_words=\${__words[@]}
[[ $__var_cword ]] && eval $__var_cword=\$__cword
return 0
}
# @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 $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 var_cur Name of variable to return current word to complete to
# @param $5 var_prev Name of variable to return previous word to complete to
# @param $6 var_words Name of variable to return words to complete to
# @param $7 var_cword Name of variable to return index of words to complete 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
local exclude flag i OPTIND=8 # Skip first seven arguments
local cword words cur
local var_cur var_cword var_prev var_words
while getopts "c:i:n:p:w:" flag "$@"; do
case $flag in
c) var_cur=$OPTARG ;;
i) var_cword=$OPTARG ;;
n) exclude=$OPTARG ;;
p) var_prev=$OPTARG ;;
w) var_words=$OPTARG ;;
esac
done
varnames=( ${!OPTIND} )
let "OPTIND += 1"
while [[ $# -ge $OPTIND ]]; do
varnames+=( ${!OPTIND} )
case ${!OPTIND} in
cur) var_cur=cur ;;
prev) var_prev=prev ;;
cword) var_cword=cword ;;
words) var_words=words ;;
*) echo "error: $FUNCNAME(): unknown argument: ${!OPTIND}"
esac
let "OPTIND += 1"
done
@ -385,7 +415,10 @@ __get_comp_words_by_ref()
eval $1=\( \"\${words[@]}\" \)
eval $2=\$cword
eval $3=\$cur
eval $4=\( \"\${varnames[@]}\" \)
eval $4=\$var_cur
eval $5=\$var_prev
eval $6=\${var_words[@]}
eval $7=\$var_cword
}

View File

@ -5,7 +5,10 @@ proc setup {} {
proc teardown {} {
assert_bash_exec {unset COMP_CWORD COMP_LINE COMP_POINT COMP_WORDS cur prev prev2}
assert_bash_exec { \
unset COMP_CWORD COMP_LINE COMP_POINT COMP_WORDS cur prev words cword \
cur2 prev2 words2 cword2 \
}
# Delete 'COMP_WORDBREAKS' occupying two lines
assert_env_unmodified {
/COMP_WORDBREAKS=/{N
@ -46,8 +49,8 @@ sync_after_int
set test "a b |"; # | = cursor position
set cmd {COMP_WORDS=(a b ''); COMP_CWORD=2; COMP_LINE='a b '; COMP_POINT=4; _get_comp_words_by_ref cur prev prev2; echo "$cur $prev $prev2"}
assert_bash_list {" b a"} $cmd $test
set cmd {COMP_WORDS=(a b ''); COMP_CWORD=2; COMP_LINE='a b '; COMP_POINT=4; _get_comp_words_by_ref cur prev; echo "$cur $prev"}
assert_bash_list {" b"} $cmd $test
sync_after_int
@ -192,8 +195,8 @@ if {[lindex $::BASH_VERSINFO 0] <= 3} {
}; # if
append cmd {; COMP_LINE='a b c:'; COMP_POINT=6}
assert_bash_exec $cmd $test
set cmd {_get_comp_words_by_ref -n : cur prev; echo "$cur $prev $prev2"}
assert_bash_list {"c: b a"} $cmd $test
set cmd {_get_comp_words_by_ref -n : cur prev; echo "$cur $prev"}
assert_bash_list {"c: b"} $cmd $test
sync_after_int
@ -336,4 +339,48 @@ expect {
sync_after_int
set test {unknown argument should raise error}
set cmd {_get_comp_words_by_ref dummy}
assert_bash_list {"error: __get_comp_words_by_ref(): unknown argument: dummy"} $cmd $test
sync_after_int
set test "a b| to all vars"; # | = cursor position
set cmd {COMP_WORDS=(a b); COMP_CWORD=1; COMP_LINE='a b'; COMP_POINT=3}
assert_bash_exec $cmd
set cmd { \
_get_comp_words_by_ref words cword prev cur; echo "${words[@]} $cword $cur $prev" \
}
assert_bash_list {"a b 1 b a"} $cmd $test
sync_after_int
set test "a b| to alternate vars"; # | = cursor position
set cmd {COMP_WORDS=(a b); COMP_CWORD=1; COMP_LINE='a b'; COMP_POINT=3;}
assert_bash_exec $cmd
set cmd {_get_comp_words_by_ref -c cur2 -p prev2 -w words2 -i cword2}
assert_bash_exec $cmd
set cmd {echo "$cur2 $prev2 ${words2[@]} $cword2"}
assert_bash_list {"b a a b 1"} $cmd $test
sync_after_int
set test "a b| to alternate vars"; # | = cursor position
set cmd {COMP_WORDS=(a b); COMP_CWORD=1; COMP_LINE='a b'; COMP_POINT=3;}
assert_bash_exec $cmd
set cmd {_get_comp_words_by_ref -c cur2 -p prev2 -w words2 -i cword2}
assert_bash_exec $cmd
set cmd {echo "$cur2 $prev2 ${words2[@]} $cword2"}
assert_bash_list {"b a a b 1"} $cmd $test
sync_after_int
teardown