Added _get_pword() helper function.

Thanks to Sung Pae (Alioth #312030):
"This patch extends both __get_cword3() and __get_cword4() to accept an
additional integer argument that specifies how many places previous to
the current word the desired word resides, respecting any user
exceptions to COMP_WORDBREAKS."
This commit is contained in:
Freddy Vulto 2009-10-31 09:24:20 +01:00
parent a55d311ae2
commit 545750eb2c
2 changed files with 63 additions and 27 deletions

View File

@ -28,6 +28,9 @@ bash-completion (2.x)
* Drop support for bash < 3.
* Fix sed error in qdbus completions containing slashes (Debian: 552631).
[ Freddy Vulto ]
* Added _get_pword() helper function, thanks to Sung Pae (Alioth: #312030)
-- David Paleino <d.paleino@gmail.com> Sun, 11 Oct 2009 11:11:57 +0200
bash-completion (1.1)

View File

@ -243,10 +243,17 @@ _get_cword()
if [ ${BASH_VERSINFO[0]} -ge 4 ] ; then
__get_cword4 "$@"
else
__get_cword3
__get_cword3 "$2"
fi
} # _get_cword()
# Get word previous to the current word;
# Accepts the same arguments as _get_cword()
#
# This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4
# will properly return the previous word with respect to any given exclusions to
# COMP_WORDBREAKS.
_get_pword() { _get_cword "${@:-}" 1; }
# Get the word to complete on bash-3, where words are not broken by
# COMP_WORDBREAKS characters and the COMP_CWORD variables look like this, for
@ -265,7 +272,10 @@ _get_cword()
[ ${BASH_VERSINFO[0]} -lt 4 ] &&
__get_cword3()
{
if [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then
# return previous word offset by $1
if [[ ${1//[^0-9]/} ]]; then
printf "%s" "${COMP_WORDS[COMP_CWORD-$1]}"
elif [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then
printf "%s" "${COMP_WORDS[COMP_CWORD]}"
else
local i
@ -317,10 +327,14 @@ __get_cword3()
# 2: :
# 3: c
#
# @oaram $1 string
# @param $1 string
# $1 string (optional) 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.
# @param $2 integer
# $2 integer (optional) Return word according to $COMP_WORDBREAKS, negatively
# offset by the value. For example, `__get_cword4 "=:" -1' returns the word
# left of the current word, respecting the exclusions given at $1
# See also:
# _get_cword, main routine
# __get_cword3, bash-3 variant
@ -328,9 +342,10 @@ __get_cword3()
[ ${BASH_VERSINFO[0]} -ge 4 ] &&
__get_cword4()
{
local exclude="$1" n_idx="${2:-0}"
local i
local LC_CTYPE=C
local WORDBREAKS=$COMP_WORDBREAKS
local WORDBREAKS="$COMP_WORDBREAKS"
# Strip single quote (') and double quote (") from WORDBREAKS to
# workaround a bug in bash-4.0, where quoted words are split
# unintended, see:
@ -338,32 +353,50 @@ __get_cword4()
# This fixes simple quoting (e.g. $ a "b<TAB> returns "b instead of b)
# but still fails quoted spaces (e.g. $ a "b c<TAB> returns c instead
# of "b c).
WORDBREAKS=${WORDBREAKS//\"/}
WORDBREAKS=${WORDBREAKS//\'/}
if [ -n "$1" ]; then
for (( i=0; i<${#1}; ++i )); do
local char=${1:$i:1}
WORDBREAKS=${WORDBREAKS//$char/}
WORDBREAKS="${WORDBREAKS//[\"\']/}"
if [[ $exclude ]]; then
for (( i=0; i<${#exclude}; ++i )); do
local char="${exclude:$i:1}"
WORDBREAKS="${WORDBREAKS//$char/}"
done
fi
local cur=${COMP_LINE:0:$COMP_POINT}
local tmp=$cur
local word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'`
while [ "$word_start" -ge 2 ]; do
# Get character before $word_start
local char=${cur:$(( $word_start - 2 )):1}
# If the WORDBREAK character isn't escaped, exit loop
if [ "$char" != "\\" ]; then
break
fi
# The WORDBREAK character is escaped;
# Recalculate $word_start
tmp=${COMP_LINE:0:$(( $word_start - 2 ))}
word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'`
done
local cur="${COMP_LINE:0:$COMP_POINT}"
local tmp="$cur"
cur=${cur:$word_start}
printf "%s" "$cur"
local break_index word_start
# return index of first occuring break character in $1; return 0 if none
break_index() {
if [[ $1 == *[$WORDBREAKS]* ]]; then
local w="${1%[$WORDBREAKS]*}"
echo $((${#w}+1))
else
echo 0
fi
}
# return the index of the start of the last word in $@
word_start() {
local buf="$@"
local start="$(break_index "$buf")"
while [[ $start -ge 2 ]]; do
# Get character before $start
local char="${cur:$(( start - 2 )):1}"
# If the WORDBREAK character isn't escaped, exit loop
[[ $char != \\ ]] && break
# The WORDBREAK character is escaped; recalculate $start
buf="${COMP_LINE:0:$(( start - 2 ))}"
start=$(break_index "$buf")
done
echo $start
}
# calculate current word, negatively offset by n_idx
cur="${tmp:$(word_start "$tmp")}"
while [[ $n_idx -gt 0 ]]; do
local tmp="${tmp%[$WORDBREAKS]$cur}" # truncate passed string
local cur="${tmp:$(word_start "$tmp")}" # then recalculate
((--n_idx))
done
echo -n "$cur"
} # __get_cword4()