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

Freddy Vulto fvulto at gmail.com
Thu Dec 24 09:02:59 UTC 2009


The following commit has been merged in the master branch:
commit c9c98da36edeb9305e24e7ea2d8ccf8b0934ce70
Author: Freddy Vulto <fvulto at gmail.com>
Date:   Thu Dec 24 10:00:29 2009 +0100

    Fixed `quote_readline'.
    This fixes completing filenames containing single quote (') on bash-4.
    
    Also added emulation of `-o filenames' to _filedir.
    
    Added tests for _filedir.
    
    Fixed array assignment within __reassemble_comp_words_by_ref().

diff --git a/bash_completion b/bash_completion
index 1b103d7..d6374f7 100644
--- a/bash_completion
+++ b/bash_completion
@@ -188,19 +188,14 @@ quote()
     echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
 }
 
-# This function quotes the argument in a way so that readline dequoting
-# results in the original argument
+# @see _quote_readline_by_ref()
 quote_readline()
 {
-    if [ ${BASH_VERSINFO[0]} -ge 4 ]; then
-        # This function isn't really necessary on bash 4
-        # See: http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
-        echo "${1}"
-        return
-    fi
-    local t="${1//\\/\\\\}"
-    echo \'${t//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
-}
+    local quoted
+    _quote_readline_by_ref "$1" ret
+    printf %s "$ret"
+} # quote_readline()
+
 
 # This function shell-dequotes the argument
 dequote()
@@ -224,8 +219,6 @@ __reassemble_comp_words_by_ref() {
     if [[ $1 ]]; then
         # Yes, exclude word separator characters;
         # Exclude only those characters, which were really included
-        # NOTE: On bash-3, `COMP_WORDBREAKS' is empty which is ok; no
-        #       additional word breaking is done on bash-3.
         exclude="${1//[^$COMP_WORDBREAKS]}"
     fi
         
@@ -240,7 +233,7 @@ __reassemble_comp_words_by_ref() {
                 [ $j -ge 2 ] && ((j--))
                 # Append word separator to current word
                 ref="$2[$j]"
-                eval $2[$j]=\""${!ref}${COMP_WORDS[$i]}"\"
+                eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
                 # Indicate new cword
                 [ $i = $COMP_CWORD ] && eval $3=$j
                 # Indicate next word if available, else end *both* while and for loop
@@ -248,7 +241,7 @@ __reassemble_comp_words_by_ref() {
             done
             # Append word to current word
             ref="$2[$j]"
-            eval $2[$j]=\""${!ref}${COMP_WORDS[$i]}"\"
+            eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
             # Indicate new cword
             [ $i = $COMP_CWORD ] && eval $3=$j
         done
@@ -295,7 +288,7 @@ _get_cword()
                 "${#cur}" -ge ${#words[i]} &&
                 # $cur doesn't match cword?
                 "${cur:0:${#words[i]}}" != "${words[i]}"
-                ]]; do
+            ]]; do
                 # Strip first character
                 cur="${cur:1}"
                 # Decrease cursor position
@@ -369,6 +362,46 @@ __ltrim_colon_completions() {
 } # __ltrim_colon_completions()
 
 
+# This function quotes the argument in a way so that readline dequoting
+# results in the original argument.  This is necessary for at least
+# `compgen' which requires its arguments quoted/escaped:
+#
+#     $ ls "a'b/"
+#     c
+#     $ compgen -f "a'b/"       # Wrong, doesn't return output
+#     $ compgen -f "a\'b/"      # Good (bash-4)
+#     a\'b/c
+#     $ compgen -f "a\\\\\'b/"  # Good (bash-3)
+#     a\'b/c
+#
+# See also: http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
+# @param $1  Argument to quote
+# @param $2  Name of variable to return result to
+_quote_readline_by_ref()
+{
+   # If bash <= 3 and argument starts with single quote ('), double-escape
+#   if [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == "'" ]]; then
+#        local t
+#        printf -v t %q "${1:1}"
+#        printf -v $2 %q "$t"
+#   else
+#        printf -v $2 %q "$1"
+#   fi
+    if [[ ${1:0:1} == "'" ]]; then
+        # Quote word, leaving out first character
+        printf -v $2 %q "${1:1}"
+        if [[ ${BASH_VERSINFO[0]} -le 3 ]]; then
+            # Double-quote word on bash-3
+            printf -v $2 %q ${!2}
+        fi
+    elif [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == '"' ]]; then
+        printf -v $2 %q "${1:1}"
+    else
+        printf -v $2 %q "$1"
+    fi
+} # _quote_readline_by_ref()
+
+
 # This function performs file and directory completion. It's better than
 # simply using 'compgen -f', because it honours spaces in filenames.
 # If passed -d, it completes only on directories. If passed anything else,
@@ -376,12 +409,12 @@ __ltrim_colon_completions() {
 #
 _filedir()
 {
-    local IFS=$'\t\n' xspec
+    local i IFS=$'\t\n' xspec
 
-    _expand || return 0
+    __expand_tilde_by_ref cur
 
     local -a toks
-    local tmp
+    local quoted tmp
 
     # TODO: I've removed a "[ -n $tmp ] &&" before `printf '%s\n' $tmp',
     #       and everything works again. If this bug
@@ -393,28 +426,74 @@ _filedir()
     #       because quotes-in-comments-in-a-subshell cause errors on
     #       bash-3.1.  See also:
     #       http://www.mail-archive.com/bug-bash@gnu.org/msg01667.html
+    _quote_readline_by_ref "$cur" quoted
     toks=( ${toks[@]-} $(
-        compgen -d -- "$(quote_readline "$cur")" | {
+        compgen -d -- "$quoted" | {
             while read -r tmp; do
                 printf '%s\n' $tmp
             done
         }
     ))
 
+    # On bash-3, special characters need to be escaped extra.  This is
+    # unless the first character is a single quote (').  If the single
+    # quote appears further down the string, bash default completion also
+    # fails, e.g.:
+    #
+    #     $ ls 'a&b/'
+    #     f
+    #     $ foo 'a&b/<TAB>  # Becomes: foo 'a&b/f'
+    #     $ foo a'&b/<TAB>  # Nothing happens
+    #
     if [[ "$1" != -d ]]; then
         xspec=${1:+"!*.$1"}
-        toks=( ${toks[@]-} $(
-            compgen -f -X "$xspec" -- "$(quote_readline "$cur")" | {
-                while read -r tmp; do
-                    [ -n $tmp ] && printf '%s\n' $tmp
+        if [[ ${cur:0:1} == "'" && ${BASH_VERSINFO[0]} -ge 4 ]]; then
+            toks=( ${toks[@]-} $(
+                eval compgen -f -X \"\$xspec\" -- $quoted
+            ) )
+        else
+            toks=( ${toks[@]-} $(
+                compgen -f -X "$xspec" -- $quoted
+            ) )
+        fi
+        if [ ${#toks[@]} -ne 0 ]; then
+            # If `compopt' is available, set `-o filenames'
+            compopt &>/dev/null && compopt -o filenames ||
+            # No, `compopt' isn't available;
+            # Is `-o filenames' set?
+            [[ "$(complete -p ${COMP_WORDS[0]})" == *"-o filenames"* ]] || {
+                # No, `-o filenames' isn't set;
+                # Emulate `-o filenames'
+                # NOTE: A side-effect of emulating `-o filenames' is that backslash escape
+                #       characters are visible within the list of presented completions, e.g.
+                #       the completions look like:
+                #
+                #           $ foo a<TAB>
+                #           a\ b/  a\$b/
+                #
+                #       whereas with `-o filenames' active the completions look like:
+                #
+                #           $ ls a<TAB>
+                #           a b/  a$b/
+                #
+                for ((i=0; i < ${#toks[@]}; i++)); do
+                    # If directory exists, append slash (/)
+                    if [[ ${cur:0:1} != "'" ]]; then
+                        [[ -d ${toks[i]} ]] && toks[i]="${toks[i]}"/
+                        if [[ ${cur:0:1} == '"' ]]; then
+                            toks[i]=${toks[i]//\\/\\\\}       
+                            toks[i]=${toks[i]//\"/\\\"}
+                            toks[i]=${toks[i]//\$/\\\$}
+                        else
+                            toks[i]=$(printf %q ${toks[i]})       
+                        fi
+                    fi
                 done
             }
-        ))
+        fi
     fi
 
     COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" )
-    [ ${#COMPREPLY[@]} -ne 0 ] && type compopt &>/dev/null && \
-        compopt -o filenames
 } # _filedir()
 
 
diff --git a/test/fixture1/bar b/test/fixtures/_filedir/a b/i
similarity index 100%
copy from test/fixture1/bar
copy to test/fixtures/_filedir/a b/i
diff --git a/test/fixture1/bar "b/test/fixtures/_filedir/a\"b/d"
similarity index 100%
copy from test/fixture1/bar
copy to "test/fixtures/_filedir/a\"b/d"
diff --git a/test/fixture1/bar b/test/fixtures/_filedir/a$b/h
similarity index 100%
copy from test/fixture1/bar
copy to test/fixtures/_filedir/a$b/h
diff --git a/test/fixture1/bar b/test/fixtures/_filedir/a&b/f
similarity index 100%
copy from test/fixture1/bar
copy to test/fixtures/_filedir/a&b/f
diff --git a/test/fixture1/bar b/test/fixtures/_filedir/a'b/c
similarity index 100%
copy from test/fixture1/bar
copy to test/fixtures/_filedir/a'b/c
diff --git a/test/fixture1/bar "b/test/fixtures/_filedir/a\\b/g"
similarity index 100%
copy from test/fixture1/bar
copy to "test/fixtures/_filedir/a\\b/g"
diff --git a/test/fixture1/bar b/test/fixtures/_filedir/ab/e
similarity index 100%
copy from test/fixture1/bar
copy to test/fixtures/_filedir/ab/e
diff --git a/test/fixture1/bar b/test/fixtures/compgen/a'b/c
similarity index 100%
copy from test/fixture1/bar
copy to test/fixtures/compgen/a'b/c
diff --git a/test/fixtures/compgen/t1.txt b/test/fixtures/compgen/t1.txt
new file mode 100644
index 0000000..322a14d
--- /dev/null
+++ b/test/fixtures/compgen/t1.txt
@@ -0,0 +1,121 @@
+BASH=/bin/bash
+BASH_ARGC=()
+BASH_ARGV=()
+BASH_LINENO=()
+BASH_SOURCE=()
+BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release" [5]="i486-pc-linux-gnu")
+BASH_VERSION='3.2.39(1)-release'
+CDPL_DIRS=([0]="/home/freddy/proj")
+CDPM_DIRS=
+CDP_DIRS=([0]="/home/freddy/proj" [1]="")
+COLUMNS=130
+COMP_CACHE=/home/freddy/.bash_completion_lib.d/cache~
+COMP_DIR=/etc/bash_completion_lib
+COMP_PATH=/home/freddy/.bash_completion_lib.d:/etc/bash_completion_lib
+COMP_RESTRICT_BY_EXTENSION=0
+COMP_VERSION=bash_completion_lib-1.3.1
+DIRSTACK=()
+EDITOR=/usr/bin/vim
+EUID=1000
+GPGKEY=10A575C3
+GPG_AGENT_INFO=/tmp/gpg-Pg6JXR/S.gpg-agent:4129:1
+GPG_TTY=/dev/pts/0
+GREP_OPTIONS='--exclude '\''distrib/*'\'' --exclude tags'
+GROUPS=()
+HISTCONTROL=ignoreboth
+HISTFILE=/home/freddy/.bash_history
+HISTFILESIZE=500
+HISTIGNORE=exit
+HISTSIZE=500
+HOME=/home/freddy
+HOSTNAME=blondy
+HOSTTYPE=i486
+IFS=$' \t\n'
+LANG=en_US
+LANGUAGE=en_NL:en_US:en_GB:en
+LINES=49
+LOGNAME=freddy
+MACHTYPE=i486-pc-linux-gnu
+MAIL=/var/mail/freddy
+MAILCHECK=60
+OLDPWD=/home/freddy/.bash_completion_lib.d
+OPTERR=1
+OPTIND=1
+OSTYPE=linux-gnu
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/freddy/proj/rc/bin
+PIPESTATUS=([0]="0")
+PPID=29352
+PS1=$'\\[\E[0;34m\\]\\!\\[\E[0m\\]\\[\E[1;32m\\]$(stoppedjobs)\\[\E[0m\\]:\\u@\\h:\\w> \\[\E[m\\]'
+PS2='> '
+PS4='+ '
+PWD=/home/freddy/proj/bashCompletion/bash-completion.git/test/fixtures/compgen
+SHELL=/bin/bash
+SHELLOPTS=braceexpand:hashall:histexpand:interactive-comments:monitor:vi
+SHLVL=1
+SSH_AUTH_SOCK=/tmp/ssh-xhQbo29352/agent.29352
+SSH_CLIENT='192.168.123.143 37670 4822'
+SSH_CONNECTION='192.168.123.143 37670 192.168.123.8 4822'
+SSH_TTY=/dev/pts/0
+TERM=xterm
+UID=1000
+USER=freddy
+VIM=/home/freddy/.vim
+VIMRUNTIME=/usr/share/vim/vimcurrent
+_=GPG_AGENT_INFO
+bash205='3.2.39(1)-release'
+bash205b='3.2.39(1)-release'
+bash3='3.2.39(1)-release'
+cdots () 
+{ 
+    [ -d "$1$2" ] && cd "$1$2" || eval cd "$1$2"
+}
+comp_load () 
+{ 
+    local cmd=${COMP_WORDS[0]} dir globs OLDIFS=$IFS;
+    IFS=:;
+    local -a aPaths=($COMP_PATH);
+    IFS='
+';
+    globs=($(
+	for dir in "${aPaths[@]}"; do 
+	    echo \"$dir\"/complete\*/\*.$cmd
+	    echo \"$dir\"/complete\*/$cmd\!
+	    echo \"$dir\"/complete\*/$cmd
+	done
+    ));
+    IFS=$OLDIFS;
+    if ! declare -F comp_include >&/dev/null; then
+        for dir in "${aPaths[@]}";
+        do
+            [ -r "$dir/include/comp_include" ] && . "$dir/include/comp_include" && break;
+        done;
+    fi;
+    comp_include comp_load_init;
+    comp_load_init;
+    local script="$(eval find "${globs[@]}" 2> /dev/null | head -1)";
+    local link comp=${script##*/};
+    [[ ${comp: -1:1} == ! ]] || { 
+        link=${comp#*.};
+        comp=${comp%.$link}
+    };
+    local path=${script%/*};
+    [ "$script" -a -r "$path/$comp" ] && . "$path/$comp" && declare -F _$comp >&/dev/null && { 
+        [ ${COMP_INSTALL:-1} -eq 0 ] || _comp_install $comp "$path"
+    } && _$comp $link;
+    comp_load_deinit
+}
+nameTerminal () 
+{ 
+    [ "${TERM:0:5}" = "xterm" ] && local ansiNrTab=0;
+    [ "$TERM" = "rxvt" ] && local ansiNrTab=61;
+    [ "$TERM" = "konsole" ] && local ansiNrTab=30 ansiNrWindow=0;
+    [ $ansiNrTab ] && echo -n ''"]$ansiNrTab;$1"'';
+    [ $ansiNrWindow -a "$2" ] && echo -n ''"]$ansiNrWindow;$2"''
+}
+stoppedjobs () 
+{ 
+    if [ "$(jobs -s)" ]; then
+        echo -n "%";
+        jobs -s | wc -l;
+    fi
+}
diff --git a/test/fixtures/compgen/t2.txt b/test/fixtures/compgen/t2.txt
new file mode 100644
index 0000000..371ab2b
--- /dev/null
+++ b/test/fixtures/compgen/t2.txt
@@ -0,0 +1,121 @@
+BASH=/bin/bash
+BASH_ARGC=()
+BASH_ARGV=()
+BASH_LINENO=()
+BASH_SOURCE=()
+BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release" [5]="i486-pc-linux-gnu")
+BASH_VERSION='3.2.39(1)-release'
+CDPL_DIRS=([0]="/home/freddy/proj")
+CDPM_DIRS=
+CDP_DIRS=([0]="/home/freddy/proj" [1]="")
+COLUMNS=130
+COMP_CACHE=/home/freddy/.bash_completion_lib.d/cache~
+COMP_DIR=/etc/bash_completion_lib
+COMP_PATH=/home/freddy/.bash_completion_lib.d:/etc/bash_completion_lib
+COMP_RESTRICT_BY_EXTENSION=0
+COMP_VERSION=bash_completion_lib-1.3.1
+DIRSTACK=()
+EDITOR=/usr/bin/vim
+EUID=1000
+GPGKEY=10A575C3
+GPG_AGENT_INFO=/tmp/gpg-Pg6JXR/S.gpg-agent:4129:1
+GPG_TTY=/dev/pts/0
+GREP_OPTIONS='--exclude '\''distrib/*'\'' --exclude tags'
+GROUPS=()
+HISTCONTROL=ignoreboth
+HISTFILE=/home/freddy/.bash_history
+HISTFILESIZE=500
+HISTIGNORE=exit
+HISTSIZE=500
+HOME=/home/freddy
+HOSTNAME=blondy
+HOSTTYPE=i486
+IFS=$' \t\n'
+LANG=en_US
+LANGUAGE=en_NL:en_US:en_GB:en
+LINES=49
+LOGNAME=freddy
+MACHTYPE=i486-pc-linux-gnu
+MAIL=/var/mail/freddy
+MAILCHECK=60
+OLDPWD=/home/freddy/.bash_completion_lib.d
+OPTERR=1
+OPTIND=1
+OSTYPE=linux-gnu
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/freddy/proj/rc/bin
+PIPESTATUS=([0]="0")
+PPID=29352
+PS1=$'\\[\E[0;34m\\]\\!\\[\E[0m\\]\\[\E[1;32m\\]$(stoppedjobs)\\[\E[0m\\]:\\u@\\h:\\w> \\[\E[m\\]'
+PS2='> '
+PS4='+ '
+PWD=/home/freddy/proj/bashCompletion/bash-completion.git/test/fixtures/compgen
+SHELL=/bin/bash
+SHELLOPTS=braceexpand:hashall:histexpand:interactive-comments:monitor:vi
+SHLVL=1
+SSH_AUTH_SOCK=/tmp/ssh-xhQbo29352/agent.29352
+SSH_CLIENT='192.168.123.143 37670 4822'
+SSH_CONNECTION='192.168.123.143 37670 192.168.123.8 4822'
+SSH_TTY=/dev/pts/0
+TERM=xterm
+UID=1000
+USER=freddy
+VIM=/home/freddy/.vim
+VIMRUNTIME=/usr/share/vim/vimcurrent
+_='a\\\'\''b/'
+bash205='3.2.39(1)-release'
+bash205b='3.2.39(1)-release'
+bash3='3.2.39(1)-release'
+cdots () 
+{ 
+    [ -d "$1$2" ] && cd "$1$2" || eval cd "$1$2"
+}
+comp_load () 
+{ 
+    local cmd=${COMP_WORDS[0]} dir globs OLDIFS=$IFS;
+    IFS=:;
+    local -a aPaths=($COMP_PATH);
+    IFS='
+';
+    globs=($(
+	for dir in "${aPaths[@]}"; do 
+	    echo \"$dir\"/complete\*/\*.$cmd
+	    echo \"$dir\"/complete\*/$cmd\!
+	    echo \"$dir\"/complete\*/$cmd
+	done
+    ));
+    IFS=$OLDIFS;
+    if ! declare -F comp_include >&/dev/null; then
+        for dir in "${aPaths[@]}";
+        do
+            [ -r "$dir/include/comp_include" ] && . "$dir/include/comp_include" && break;
+        done;
+    fi;
+    comp_include comp_load_init;
+    comp_load_init;
+    local script="$(eval find "${globs[@]}" 2> /dev/null | head -1)";
+    local link comp=${script##*/};
+    [[ ${comp: -1:1} == ! ]] || { 
+        link=${comp#*.};
+        comp=${comp%.$link}
+    };
+    local path=${script%/*};
+    [ "$script" -a -r "$path/$comp" ] && . "$path/$comp" && declare -F _$comp >&/dev/null && { 
+        [ ${COMP_INSTALL:-1} -eq 0 ] || _comp_install $comp "$path"
+    } && _$comp $link;
+    comp_load_deinit
+}
+nameTerminal () 
+{ 
+    [ "${TERM:0:5}" = "xterm" ] && local ansiNrTab=0;
+    [ "$TERM" = "rxvt" ] && local ansiNrTab=61;
+    [ "$TERM" = "konsole" ] && local ansiNrTab=30 ansiNrWindow=0;
+    [ $ansiNrTab ] && echo -n ''"]$ansiNrTab;$1"'';
+    [ $ansiNrWindow -a "$2" ] && echo -n ''"]$ansiNrWindow;$2"''
+}
+stoppedjobs () 
+{ 
+    if [ "$(jobs -s)" ]; then
+        echo -n "%";
+        jobs -s | wc -l;
+    fi
+}
diff --git a/test/fixtures/compgen/t3.txt b/test/fixtures/compgen/t3.txt
new file mode 100644
index 0000000..371ab2b
--- /dev/null
+++ b/test/fixtures/compgen/t3.txt
@@ -0,0 +1,121 @@
+BASH=/bin/bash
+BASH_ARGC=()
+BASH_ARGV=()
+BASH_LINENO=()
+BASH_SOURCE=()
+BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release" [5]="i486-pc-linux-gnu")
+BASH_VERSION='3.2.39(1)-release'
+CDPL_DIRS=([0]="/home/freddy/proj")
+CDPM_DIRS=
+CDP_DIRS=([0]="/home/freddy/proj" [1]="")
+COLUMNS=130
+COMP_CACHE=/home/freddy/.bash_completion_lib.d/cache~
+COMP_DIR=/etc/bash_completion_lib
+COMP_PATH=/home/freddy/.bash_completion_lib.d:/etc/bash_completion_lib
+COMP_RESTRICT_BY_EXTENSION=0
+COMP_VERSION=bash_completion_lib-1.3.1
+DIRSTACK=()
+EDITOR=/usr/bin/vim
+EUID=1000
+GPGKEY=10A575C3
+GPG_AGENT_INFO=/tmp/gpg-Pg6JXR/S.gpg-agent:4129:1
+GPG_TTY=/dev/pts/0
+GREP_OPTIONS='--exclude '\''distrib/*'\'' --exclude tags'
+GROUPS=()
+HISTCONTROL=ignoreboth
+HISTFILE=/home/freddy/.bash_history
+HISTFILESIZE=500
+HISTIGNORE=exit
+HISTSIZE=500
+HOME=/home/freddy
+HOSTNAME=blondy
+HOSTTYPE=i486
+IFS=$' \t\n'
+LANG=en_US
+LANGUAGE=en_NL:en_US:en_GB:en
+LINES=49
+LOGNAME=freddy
+MACHTYPE=i486-pc-linux-gnu
+MAIL=/var/mail/freddy
+MAILCHECK=60
+OLDPWD=/home/freddy/.bash_completion_lib.d
+OPTERR=1
+OPTIND=1
+OSTYPE=linux-gnu
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/freddy/proj/rc/bin
+PIPESTATUS=([0]="0")
+PPID=29352
+PS1=$'\\[\E[0;34m\\]\\!\\[\E[0m\\]\\[\E[1;32m\\]$(stoppedjobs)\\[\E[0m\\]:\\u@\\h:\\w> \\[\E[m\\]'
+PS2='> '
+PS4='+ '
+PWD=/home/freddy/proj/bashCompletion/bash-completion.git/test/fixtures/compgen
+SHELL=/bin/bash
+SHELLOPTS=braceexpand:hashall:histexpand:interactive-comments:monitor:vi
+SHLVL=1
+SSH_AUTH_SOCK=/tmp/ssh-xhQbo29352/agent.29352
+SSH_CLIENT='192.168.123.143 37670 4822'
+SSH_CONNECTION='192.168.123.143 37670 192.168.123.8 4822'
+SSH_TTY=/dev/pts/0
+TERM=xterm
+UID=1000
+USER=freddy
+VIM=/home/freddy/.vim
+VIMRUNTIME=/usr/share/vim/vimcurrent
+_='a\\\'\''b/'
+bash205='3.2.39(1)-release'
+bash205b='3.2.39(1)-release'
+bash3='3.2.39(1)-release'
+cdots () 
+{ 
+    [ -d "$1$2" ] && cd "$1$2" || eval cd "$1$2"
+}
+comp_load () 
+{ 
+    local cmd=${COMP_WORDS[0]} dir globs OLDIFS=$IFS;
+    IFS=:;
+    local -a aPaths=($COMP_PATH);
+    IFS='
+';
+    globs=($(
+	for dir in "${aPaths[@]}"; do 
+	    echo \"$dir\"/complete\*/\*.$cmd
+	    echo \"$dir\"/complete\*/$cmd\!
+	    echo \"$dir\"/complete\*/$cmd
+	done
+    ));
+    IFS=$OLDIFS;
+    if ! declare -F comp_include >&/dev/null; then
+        for dir in "${aPaths[@]}";
+        do
+            [ -r "$dir/include/comp_include" ] && . "$dir/include/comp_include" && break;
+        done;
+    fi;
+    comp_include comp_load_init;
+    comp_load_init;
+    local script="$(eval find "${globs[@]}" 2> /dev/null | head -1)";
+    local link comp=${script##*/};
+    [[ ${comp: -1:1} == ! ]] || { 
+        link=${comp#*.};
+        comp=${comp%.$link}
+    };
+    local path=${script%/*};
+    [ "$script" -a -r "$path/$comp" ] && . "$path/$comp" && declare -F _$comp >&/dev/null && { 
+        [ ${COMP_INSTALL:-1} -eq 0 ] || _comp_install $comp "$path"
+    } && _$comp $link;
+    comp_load_deinit
+}
+nameTerminal () 
+{ 
+    [ "${TERM:0:5}" = "xterm" ] && local ansiNrTab=0;
+    [ "$TERM" = "rxvt" ] && local ansiNrTab=61;
+    [ "$TERM" = "konsole" ] && local ansiNrTab=30 ansiNrWindow=0;
+    [ $ansiNrTab ] && echo -n ''"]$ansiNrTab;$1"'';
+    [ $ansiNrWindow -a "$2" ] && echo -n ''"]$ansiNrWindow;$2"''
+}
+stoppedjobs () 
+{ 
+    if [ "$(jobs -s)" ]; then
+        echo -n "%";
+        jobs -s | wc -l;
+    fi
+}
diff --git a/test/lib/completions/screen.exp b/test/lib/completions/screen.exp
index a9d239e..4bd5ad0 100644
--- a/test/lib/completions/screen.exp
+++ b/test/lib/completions/screen.exp
@@ -33,6 +33,11 @@ expect {
     -re "\r\nbar\\s+bar bar.d\\s+foo\\s+foo.d" { 
         if {[lindex $BASH_VERSINFO 0] < 4} {xfail "$test"} {fail "$test"}
     }
+    -re "\r\nbar\\s+bar\\\\ bar.d/\\s+foo\\s+foo.d/" {
+        # On bash-3, the space in `bar bar.d' is escaped with a backslash
+        # as a side-effect of emulating `-o filenames'.
+        if {[lindex $BASH_VERSINFO 0] <= 3} {pass "$test"} {fail "$test"}
+    }
     -re $prompt { unresolved "$test at prompt" }
     default { unresolved "$test" }
 }; # expect
diff --git a/test/unit/_filedir.exp b/test/unit/_filedir.exp
new file mode 100644
index 0000000..c5dd877
--- /dev/null
+++ b/test/unit/_filedir.exp
@@ -0,0 +1,234 @@
+proc setup {} {
+    assert_bash_exec {unset COMPREPLY cur}
+    assert_bash_exec {unset -f _f}
+    save_env
+    # Declare bash completion function `_f'
+    assert_bash_exec { \
+        _f() { local cur=$(_get_cword); unset COMPREPLY; _filedir; }; \
+        complete -F _f f \
+    }
+    # Declare bash completion function `_f2' with `-o filenames' active.
+    assert_bash_exec { \
+        complete -F _f -o filenames f2 \
+    }
+    # Create directory `a*b'
+    # NOTE: directory `a*b' isn't included in Git, because a directory
+    #       containing an asterisk (*) causes troubles on Cygwin/Windows
+    assert_bash_exec {(cd fixtures/_filedir && [ ! -d a\*b ] && mkdir a\*b && touch a\*b/j || true)}
+}; # setup()
+
+
+proc teardown {} {
+    assert_bash_exec {(cd fixtures/_filedir && rm -- a\*b/j && rmdir a\*b/ || true)}
+    assert_bash_exec {unset COMPREPLY cur}
+    assert_bash_exec {unset -f _f}
+    assert_bash_exec {complete -r f}
+    assert_env_unmodified { /OLDPWD/d }
+}; # teardown()
+
+
+setup
+
+
+set test "_filedir should run without errors"
+assert_bash_exec {_filedir > /dev/null} $test
+
+
+sync_after_int
+
+
+foreach name {f f2} {
+
+    set test "completing $name ab/ should return e"
+    set cmd "$name ab/"
+    assert_complete_dir e $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\\ b/ should return i"
+    set cmd "$name a\\ b/"
+    assert_complete_dir i $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\\\'b/ should return i"
+    set cmd "$name a\\\'b/"
+    assert_complete_dir c $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\\\"b/ should return i"; #"
+    set cmd "$name a\\\"b/"; #"
+    assert_complete_dir d $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\\\$b/ should return h"
+    set cmd "$name a\\\$b/"
+    assert_complete_dir "\b\b\b\b\b$::TESTDIR/fixtures/_filedir/a\\\\\$b/h" $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\\\\b/ should return g"
+    set cmd "$name a\\\\b/"
+    assert_complete_dir g $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\\&b/ should return f"
+    set cmd "$name a\\&b/"
+    assert_complete_dir f $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    set test "completing $name a\$ should return a\\\$b/"
+    set cmd "$name a\$"
+    assert_complete_dir "\b\\\\\$b/" $cmd "fixtures/_filedir"
+
+
+    sync_after_int
+
+
+    # NOTE: Bash versions 4.0.0 up to 4.0.34 contain a bug when completing quoted
+    #       words, so tests within this if aren't executed for these bash versions.
+    if {! (
+        [lindex $::BASH_VERSINFO 0] == 4 && 
+        [lindex $::BASH_VERSINFO 1] == 0 &&
+        [lindex $::BASH_VERSINFO 2] < 35
+    )} {
+        set test "completing $name 'ab/ should return e"
+        set cmd "$name 'ab/"
+        assert_complete_dir {e'} $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name 'a b/ should return i"
+        set cmd "$name 'a b/"
+        assert_complete_dir {i'} $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name 'a\"b/ should return d"; #"
+        set cmd "$name 'a\"b/"; #"
+        assert_complete_dir {d'} $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name 'a\$b/ should return h"
+        set cmd "$name 'a\$b/"
+        if {[lindex $::BASH_VERSINFO 0] == 4} {
+            assert_complete_dir {h'} $cmd "fixtures/_filedir"
+        } else {
+            assert_complete_dir "\b\b\b\b$::TESTDIR/fixtures/_filedir/a\$b/h'" $cmd "fixtures/_filedir"
+        }; # if
+            
+
+
+        sync_after_int
+
+
+        set test "completing $name 'a\\b/ should return g"
+        set cmd "$name 'a\\b/"
+        assert_complete_dir {g'} $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name 'a&b/ should return f"
+        set cmd "$name 'a&b/"
+        assert_complete_dir {f'} $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"ab/ should return e"; #"
+        set cmd "$name \"ab/"; #"
+        assert_complete_dir {e"} $cmd "fixtures/_filedir"; #"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a b/ should return i"; #"
+        set cmd "$name \"a b/"; #"
+        assert_complete_dir {i"} $cmd "fixtures/_filedir"; #"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a'b/ should return c"; #"
+        set cmd "$name \"a'b/"; #"
+        assert_complete_dir {c"} $cmd "fixtures/_filedir"; #"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a\\\"b/ should return d"; #"
+        set cmd "$name \"a\\\"b/"; #"
+        assert_complete_dir {d"} $cmd "fixtures/_filedir"; #"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a\\\$b/ should return h"; #"
+        set cmd "$name \"a\\\$b/"; #"
+        assert_complete_dir "\b\b\b\b\b$::TESTDIR/fixtures/_filedir/a\\\\\$b/h\\\"" $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a\\b/ should return e"; #"
+        set cmd "$name \"a\\b/"; #"
+        assert_complete_dir "\b\b\bb/e\\\"" $cmd "fixtures/_filedir"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a\\\\b/ should return g"; #"
+        set cmd "$name \"a\\\\b/"; #"
+        assert_complete_dir {g"} $cmd "fixtures/_filedir"; #"
+
+
+        sync_after_int
+
+
+        set test "completing $name \"a&b/ should return f"; #"
+        set cmd "$name \"a&b/"; #"
+        assert_complete_dir {f"} $cmd "fixtures/_filedir"; #"
+
+
+        sync_after_int
+
+
+    }; # if
+}; # for
+
+
+teardown
diff --git a/test/unit/_get_cword.exp b/test/unit/_get_cword.exp
index 3481b4a..7e38e9e 100644
--- a/test/unit/_get_cword.exp
+++ b/test/unit/_get_cword.exp
@@ -253,4 +253,32 @@ expect {
 sync_after_int
 
 
+set test {a 'b&c| should return 'b&c};  # | = cursor position
+if {
+    [lindex $::BASH_VERSINFO 0] == 4 && 
+    [lindex $::BASH_VERSINFO 1] == 0 &&
+    [lindex $::BASH_VERSINFO 2] < 35
+} {
+    set cmd {COMP_WORDS=(a "'" b "&" c); COMP_CWORD=4}
+} else {
+    set cmd {COMP_WORDS=(a "'b&c"); COMP_CWORD=1}
+}; # if
+append cmd {; COMP_LINE="a 'b&c"; COMP_POINT=6; _get_cword}
+send "$cmd\r"
+expect -ex "$cmd\r\n"
+expect {
+    -ex "'b&c/@" { pass "$test" }
+    -ex "c/@" { 
+        if {
+            [lindex $::BASH_VERSINFO 0] == 4 &&
+            [lindex $::BASH_VERSINFO 1] == 0 &&
+            [lindex $::BASH_VERSINFO 2] < 35
+        } {xfail "$test"} {fail "$test"}
+    }
+}; # expect
+
+
+sync_after_int
+
+
 teardown
diff --git a/test/unit/compgen.exp b/test/unit/compgen.exp
new file mode 100644
index 0000000..8c33c41
--- /dev/null
+++ b/test/unit/compgen.exp
@@ -0,0 +1,52 @@
+proc setup {} {
+    save_env
+}; # setup()
+
+
+proc teardown {} {
+    assert_env_unmodified {/OLDPWD/d}
+}; # teardown()
+
+
+setup
+
+
+if {[lindex $::BASH_VERSINFO 0] <= 3} {
+    set test {compgen -f a\\\\\\\'b/ on bash-3 should return a\'b/c};
+    set cmd {compgen -f a\\\\\\\'b/}
+} else {
+    set test {compgen -f a\\\'b/ on bash-4 should return a\'b/c};
+    set cmd {compgen -f a\\\'b/}
+}; # if
+set dir fixtures/compgen
+set prompt "/$dir/@"
+assert_bash_exec "cd $dir" "" $prompt
+send "$cmd\r"
+expect -ex "$cmd\r\n"
+expect {
+    -re {a\\\'b/c} {
+        # On bash-3.2, compgen returns inconsequent output
+        if {
+            [lindex $::BASH_VERSINFO 0] >= 4 || (
+                [lindex $::BASH_VERSINFO 0] == 3 &&
+                [lindex $::BASH_VERSINFO 1] == 2
+            )
+        } {pass $test} else {fail $test}
+    }
+    -re {a'b/c} {
+        if {[lindex $::BASH_VERSINFO 0] <= 3 } \
+            {pass $test} else {fail $test}
+    }
+    -re $prompt { pass "$test" }
+    -re eof { unresolved "eof" }
+}; # expect
+sync_after_int $prompt
+assert_bash_exec "cd \$TESTDIR"
+
+#assert_bash_list_dir {a\\\'b/c} $cmd fixtures/compgen
+
+
+sync_after_int
+
+
+teardown

-- 
bash-completion



More information about the Bash-completion-commits mailing list