[Bash-completion-commits] [SCM] bash-completion branch, master, updated. 884c3f5af68e11825c7044092f7fe62975d03459

Freddy Vulto fvulto at gmail.com
Sat Oct 31 08:58:45 UTC 2009


The following commit has been merged in the master branch:
commit 545750eb2c9b21013ef0dce777e790ee3cb27d32
Author: Freddy Vulto <fvulto at gmail.com>
Date:   Sat Oct 31 09:24:20 2009 +0100

    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."

diff --git a/CHANGES b/CHANGES
index d01f378..d9e3ae9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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 at gmail.com>  Sun, 11 Oct 2009 11:11:57 +0200
 
 bash-completion (1.1)
diff --git a/bash_completion b/bash_completion
index 99ce63a..f648113 100644
--- a/bash_completion
+++ b/bash_completion
@@ -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
+    local cur="${COMP_LINE:0:$COMP_POINT}"
+    local tmp="$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
-        # The WORDBREAK character is escaped;
-        # Recalculate $word_start
-        tmp=${COMP_LINE:0:$(( $word_start - 2 ))}
-        word_start=`expr "$tmp" : '.*['"$WORDBREAKS"']'`
-    done
+    }
+    # 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
+    }
 
-    cur=${cur:$word_start}
-    printf "%s" "$cur"
+    # 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()
 
 

-- 
bash-completion



More information about the Bash-completion-commits mailing list