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

Freddy Vulto fvulto at gmail.com
Mon Nov 22 22:00:06 UTC 2010


The following commit has been merged in the master branch:
commit 5a38f828d4300af46e8c183c87c19c9001566f42
Author: Freddy Vulto <fvulto at gmail.com>
Date:   Mon Nov 22 22:57:00 2010 +0100

    (testsuite) Split assert_complete() into
    assert_complete_many() and assert_complete_one().
    Fix ssh completion now that match_items() also matches on prompt.

diff --git a/test/lib/completions/cd.exp b/test/lib/completions/cd.exp
index 1361b3c..55bae15 100644
--- a/test/lib/completions/cd.exp
+++ b/test/lib/completions/cd.exp
@@ -40,7 +40,7 @@ set test "Tab should complete CDPATH"
 assert_bash_exec "declare -p CDPATH &>/dev/null && OLDCDPATH=\$CDPATH || :"
 assert_bash_exec "CDPATH=\$PWD";
 assert_complete "$::srcdir/fixtures/shared/default/foo.d/" \
-    "cd $::srcdir/fixtures/shared/default/fo" $test -nospace
+    "cd $::srcdir/fixtures/shared/default/fo" $test -nospace -expect-cmd-minus fo
 sync_after_int
     # Reset CDPATH
 assert_bash_exec "declare -p OLDCDPATH &>/dev/null && CDPATH=\$OLDCDPATH || unset CDPATH && unset OLDCDPATH"
diff --git a/test/lib/completions/mount.exp b/test/lib/completions/mount.exp
index bab720b..c99d605 100644
--- a/test/lib/completions/mount.exp
+++ b/test/lib/completions/mount.exp
@@ -54,7 +54,7 @@ set expected [list /test/path /test/path2 /second/path]
 set cmd "mount mocksrv:/"
 assert_bash_exec {OLDPATH="$PATH"; PATH="$SRCDIRABS/fixtures/mount/bin:$PATH";}
 # This needs an explicit cword param or will output "unresolved".
-assert_complete $expected $cmd $test "/@" 20 "/"
+assert_complete $expected $cmd $test -expect-cmd-minus /
 sync_after_int
 assert_bash_exec {PATH="$OLDPATH"; unset -v OLDPATH}
 
@@ -93,7 +93,7 @@ assert_complete {/mnt/nice\ test\\path} {mnt /mnt/nice\ test\\p}
 sync_after_int
 
 assert_complete {{/mnt/nice\ test\\path} {/mnt/nice\ test-path}} \
-    {mnt /mnt/nice\ } "" /@ 20 {/mnt/nice\ }
+    {mnt /mnt/nice\ } "" -expect-cmd-minus {/mnt/nice\ }
 sync_after_int
 
 assert_complete {/mnt/nice\$test-path} {mnt /mnt/nice\$}
diff --git a/test/lib/completions/ssh.exp b/test/lib/completions/ssh.exp
index 217fa2c..1599dcc 100644
--- a/test/lib/completions/ssh.exp
+++ b/test/lib/completions/ssh.exp
@@ -29,7 +29,6 @@ expect {
     -re /@ { unresolved "$test at prompt" }
     default { unresolved "$test" }
 }
-sync_after_int
 
 
 sync_after_int
@@ -61,15 +60,16 @@ sync_after_int
 
 
 set test "First argument should complete partial hostname"
-assert_complete_partial [get_hosts] ssh "" $test \
-    -filters "ltrim_colon_completions"
+assert_complete_partial [get_hosts] ssh "" $test -ltrim-colon-completions
 
 
 sync_after_int
 
 
 set test "-F should complete filename"
-assert_complete "-Fspaced\\ \\ conf" "ssh -Fsp" "-F should complete filename"
+assert_complete "-Fspaced\\ \\ conf" "ssh -Fsp" $test
+
+
 sync_after_int
 
 
diff --git a/test/lib/library.exp b/test/lib/library.exp
index ace83dc..4ac8800 100644
--- a/test/lib/library.exp
+++ b/test/lib/library.exp
@@ -1,6 +1,6 @@
-    # Source `init.tcl' again to restore the `unknown' procedure
-    # NOTE: DejaGnu has an old `unknown' procedure which unfortunately disables
-    #       tcl auto-loading.
+# Source `init.tcl' again to restore the `unknown' procedure
+# NOTE: DejaGnu has an old `unknown' procedure which unfortunately disables
+#       tcl auto-loading.
 source [file join [info library] init.tcl]
 package require cmdline
 package require textutil::string
@@ -133,133 +133,201 @@ proc assert_bash_list_dir {expected cmd dir test {args {}}} {
 
 
 # Make sure the expected items are returned by TAB-completing the specified
-# command.
+# command.  If the number of expected items is one, expected is:
+#
+#     $cmd<TAB>$expected[<SPACE>]
+#
+# SPACE is not expected if -nospace is specified.
+#
+# If the number of expected items is greater than one, expected is:
+#
+#     $cmd<TAB>\n
+#     $expected\n
+#     $prompt + ($cmd - AUTO) + longest-common-prefix-of-$expected
+#
+# AUTO is calculated like this: If $cmd ends with non-whitespace, and
+# the last argument of $cmd equals the longest-common-prefix of
+# $expected, $cmd minus this argument will be expected.
+#
+# If the algorithm above fails, you can manually specify the CWORD to be
+# subtracted from $cmd specifying `-expect-cmd-minus CWORD'.  Known cases where
+# this is useful are when:
+# - the last whitespace is escaped, e.g. "finger foo\ " or "finger
+#   'foo "
+#
+# If the entire $cmd is expected, specify `-expect-cmd-full'.
+#
 # @param list $expected  Expected completions.
 # @param string $cmd  Command given to generate items
 # @param string $test  Test title
 # @param list $args  Options:
-#     -prompt PROMPT  Bash prompt.  Default is `/@'
+#     -prompt PROMPT   Bash prompt.  Default is `/@'
 #     -chunk-size CHUNK-SIZE   Compare list CHUNK-SIZE items at
 #         a time.  Default is 20.
-#     -cword CWORD  Last argument of $cmd which is an argument-to-complete and
-#         to be replaced with the longest common prefix of $expected.  If empty
-#         string (default), `assert_complete' autodetects if the last argument
-#         is an argument-to-complete by checking if $cmd doesn't end with
-#         whitespace.  Specifying `cword' should only be necessary if this
-#         autodetection fails, e.g.  when the last whitespace is escaped or
-#         quoted, e.g. "finger foo\ " or "finger 'foo "
-#     -nospace  Don't expect space character to be output after completion match.
-#     -filters  List of filters to apply to this function to tweak the expected
-#         completions and argument-to-complete.  Possible values:
-#         - "ltrim_colon_completions"
-#proc assert_complete {expected cmd {test ""} {prompt /@} {size 20} {cword ""} {filters ""}} {
-# @result boolean  True if successful, False if not
+#     -nospace   Don't expect space character to be output after completion match.
+#         Valid only if a single completion is expected.
+#     -ltrim-colon-completions   Left-trim completions with cword containing
+#         colon (:)
+#     -expect-cmd-full   Expect the full $cmd to be echoed.  Expected is:
+#
+#             $cmd<TAB>\n
+#             $expected\n
+#             $prompt + $cmd + longest-common-prefix-of-$expected
+#
+#     -expect-cmd-minus DWORD   Expect $cmd minus DWORD to be echoed.
+#         Expected is:
+#
+#             $cmd<TAB>\n
+#             $expected\n
+#             $prompt + ($cmd - DWORD) + longest-common-prefix-of-$expected
+#
 proc assert_complete {expected cmd {test ""} {args {}}} {
+    set args_orig $args
     array set arg [::cmdline::getoptions args {
         {prompt.arg     "/@" "bash prompt"}
         {chunk-size.arg 20   "compare N list items at a time"}
-        {cword.arg      ""   "word to complete"}
         {nospace             "don't expect space after completion"}
-        {filters.arg    ""   "filters to preprocess expected completions"}
+        {ltrim-colon-completions  "left-trim completions with cword containing :"}
+        {expect-cmd-full          "Expect full cmd after prompt"}
+        {expect-cmd-minus.arg ""  "Expect cmd minus DWORD after prompt"}
     }]
-    set cword $arg(cword)
-    set prompt $arg(prompt)
     if {[llength $expected] == 0} {
         assert_no_complete $cmd $test
+    } elseif {[llength $expected] == 1} {
+        eval assert_complete_one \$expected \$cmd \$test $args_orig
     } else {
-        if {$test == ""} {set test "$cmd should show completions"}
-        send "$cmd\t"
-        if {[llength $expected] == 1} {
-            expect -ex "$cmd"
-
-            if {[lsearch -exact $arg(filters) "ltrim_colon_completions"] == -1} {
-                set cur "";  # Default to empty word to complete on
-                set words [split_words_bash $cmd]
-                if {[llength $words] > 1} {
-                        # Assume last word of `$cmd' is word to complete on.
-                    set index [expr [llength $words] - 1]
-                    set cur [lindex $words $index]
-                }
-                    # Remove second word from beginning of single item $expected
-                if {[string first $cur $expected] == 0} {
-                    set expected [list [string range $expected [string length $cur] end]]
-                }
-            }
-        } else {
-            expect -ex "$cmd\r\n"
-            # Make sure expected items are unique
-            set expected [lsort -unique $expected]
-        }
+        eval assert_complete_many \$expected \$cmd \$test $args_orig
+    }
+}
 
-        if {[lsearch -exact $arg(filters) "ltrim_colon_completions"] != -1} {
-                # If partial contains colon (:), remove partial from begin of items
-                # See also: bash_completion.__ltrim_colon_completions()
-            _ltrim_colon_completions cword expected
-        }
 
-        if {$arg(nospace)} {set endspace ""} else {set endspace "-end-space"}
-        if {[
-            eval match_items \$expected -bash-sort -chunk-size \
-                \$arg(chunk-size) $endspace -prompt \$prompt
-        ]} {
-            if {[llength $expected] == 1} {
-                pass "$test"
-            } else {
-                # Remove optional (partial) last argument-to-complete from `cmd',
-                # E.g. "finger test@" becomes "finger"
-
-                if {[lsearch -exact $arg(filters) "ltrim_colon_completions"] != -1} {
-                    set cmd2 $cmd
-                } else {
-                    set cmd2 [_remove_cword_from_cmd $cmd $cword]
-                }
-
-                # Determine common prefix of completions
-                set common [::textutil::string::longestCommonPrefixList $expected]
-                #if {[string length $common] > 0} {set common " $common"}
-                expect {
-                    -ex "$prompt$cmd2$common" { pass "$test" }
-                    -re $prompt { unresolved "$test at prompt" }
-                    -re eof { unresolved "eof" }
-                }
-            }
-        } else {
-            fail "$test"
+# Make sure the expected multiple items are returned by TAB-completing the
+# specified command.
+# @see assert_complete()
+proc assert_complete_many {expected cmd {test ""} {args {}}} {
+    array set arg [::cmdline::getoptions args {
+        {prompt.arg     "/@" "bash prompt"}
+        {chunk-size.arg 20   "compare N list items at a time"}
+        {nospace             "don't expect space after completion"}
+        {ltrim-colon-completions  "left-trim completions with cword containing :"}
+        {expect-cmd-full          "Expect full cmd after prompt"}
+        {expect-cmd-minus.arg ""  "Expect cmd minus CWORD after prompt"}
+    }]
+    if {$test == ""} {set test "$cmd should show completions"}
+    set prompt $arg(prompt)
+    set dword ""
+    if {$arg(expect-cmd-minus) != ""} {set dword $arg(expect-cmd-minus)}
+
+    send "$cmd\t"
+    expect -ex "$cmd\r\n"
+
+    # Make sure expected items are unique
+    set expected [lsort -unique $expected]
+
+    # Determine common prefix of completions
+    set common [::textutil::string::longestCommonPrefixList $expected]
+
+    if {$arg(ltrim-colon-completions)} {
+        # If partial contains colon (:), remove partial from begin of items
+        _ltrim_colon_completions $cmd expected dword
+    }
+    set cmd2 [_remove_cword_from_cmd $cmd $dword $common]
+
+    set prompt "$prompt$cmd2$common"
+    if {$arg(nospace)} {set endspace ""} else {set endspace "-end-space"}
+    set endprompt "-end-prompt"
+    if {[
+        eval match_items \$expected -bash-sort -chunk-size \
+            \$arg(chunk-size) $endprompt $endspace -prompt \$prompt
+    ]} {
+        pass "$test"
+    } else {
+        fail "$test"
+    }
+}
+
+
+# Make sure the expected single item is returned by TAB-completing the
+# specified command.
+# @see assert_complete()
+proc assert_complete_one {expected cmd {test ""} {args {}}} {
+    array set arg [::cmdline::getoptions args {
+        {prompt.arg     "/@" "bash prompt"}
+        {chunk-size.arg 20   "compare N list items at a time"}
+        {nospace             "don't expect space after completion"}
+        {ltrim_colon_completions  "left-trim completions with cword containing :"}
+        {expect-cmd-full          "Expect full cmd after prompt"}
+        {expect-cmd-minus.arg ""  "Expect cmd minus CWORD after prompt"}
+    }]
+    set prompt $arg(prompt)
+
+    if {$test == ""} {set test "$cmd should show completion"}
+    send "$cmd\t"
+    expect -ex "$cmd"
+    if {$arg(ltrim_colon_completions)} {
+        # If partial contains colon (:), remove partial from begin of items
+        _ltrim_colon_completions cword expected
+    } else {
+        set cur "";  # Default to empty word to complete on
+        set words [split_words_bash $cmd]
+        if {[llength $words] > 1} {
+            # Assume last word of `$cmd' is word to complete on.
+            set index [expr [llength $words] - 1]
+            set cur [lindex $words $index]
         }
+        # Remove second word from beginning of $expected
+        if {[string first $cur $expected] == 0} {
+            set expected [list [string range $expected [string length $cur] end]]
+        }
+    }
+
+    if {$arg(nospace)} {set endspace ""} else {set endspace "-end-space"}
+    if {[
+        eval match_items \$expected -bash-sort -chunk-size \
+            \$arg(chunk-size) $endspace -prompt \$prompt
+    ]} {
+        pass "$test"
+    } else {
+        fail "$test"
     }
 }
 
 
-# @param string $cmd  Command to remove cword from
-# @param string $cword  (optional) Last argument of $cmd which is an
-#     argument-to-complete and to be deleted.  If empty string (default),
-#     `_remove_cword_from_cmd' autodetects if the last argument is an
-#     argument-to-complete by checking if $cmd doesn't end with whitespace.
-#     Specifying `cword' is only necessary if this autodetection fails, e.g.
+# @param string $cmd  Command to remove current-word-to-complete from.
+# @param string $dword  (optional) Manually specify current-word-to-complete,
+#     i.e. word to remove from $cmd.  If empty string (default),
+#     `_remove_cword_from_cmd' autodetects if the last argument is the
+#     current-word-to-complete by checking if $cmd doesn't end with whitespace.
+#     Specifying `dword' is only necessary if this autodetection fails, e.g.
 #     when the last whitespace is escaped or quoted, e.g. "finger foo\ " or
 #     "finger 'foo "
-# @return string  Command with cword removed
-proc _remove_cword_from_cmd {cmd {cword ""}} {
+# @param string $common  (optional) Common prefix of expected completions.
+# @return string  Command with current-word-to-complete removed
+proc _remove_cword_from_cmd {cmd {dword ""} {common ""}} {
     set cmd2 $cmd
-    # Is $cword specified?
-    if {[string length $cword] > 0} {
-        # Remove $cword from end of $cmd
-        if {[string last $cword $cmd] == [string length $cmd] - [string length $cword]} {
-            set cmd2 [string range $cmd 0 [expr [string last $cword $cmd] - 1]]
+    # Is $dword specified?
+    if {[string length $dword] > 0} {
+        # Remove $dword from end of $cmd
+        if {[string last $dword $cmd] == [string length $cmd] - [string length $dword]} {
+            set cmd2 [string range $cmd 0 [expr [string last $dword $cmd] - 1]]
         }
     } else {
-        # No, $cword not specified;
-        # Check if last argument is really an-argument-to-complete, i.e.
+        # No, $dword not specified;
+        # Check if last argument is really a word-to-complete, i.e.
         # doesn't end with whitespace.
         # NOTE: This check fails if trailing whitespace is escaped or quoted,
         #       e.g. "finger foo\ " or "finger 'foo ".  Specify parameter
-        #       $cword in those cases.
+        #       $dword in those cases.
         # Is last char whitespace?
         if {! [string is space [string range $cmd end end]]} {
             # No, last char isn't whitespace;
-            # Remove argument-to-complete from end of $cmd
-            set cmd2 [lrange [split $cmd] 0 end-1]
-            append cmd2 " "
+            set cmds [split $cmd]
+            # Does word-to-complete start with $common?
+            if {[string first $common [lrange $cmds end end]] == 0} {
+                # Remove word-to-complete from end of $cmd
+                set cmd2 [lrange $cmds 0 end-1]
+                append cmd2 " "
+            }
         }
     }
     return $cmd2
@@ -337,37 +405,52 @@ proc assert_complete_partial {expected cmd {partial ""} {test ""} {args {}}} {
         set expected [lsort -unique $expected]
         foreach item $expected {
             if {$partial == ""} {set partial [string range $item 0 0]}
-                # Only append item if starting with $partial
+            # Only append item if starting with $partial
             if {[string range $item 0 [expr [string length $partial] - 1]] == "$partial"} {
                 lappend pick $item
             }
         }
-        assert_complete $pick "$cmd $partial" $test $args
+        # NOTE: The `eval' is necessary to flatten the $args list
+        #       See also: http://wiki.tcl.tk/11787 - {expand}
+        eval assert_complete \$pick \"\$cmd \$partial\" \$test $args; #"
     }
 }
 
 
+# If cword contains colon (:), left-trim completions with cword
+# @param string $cmd  Command to complete 
+# @param list $items  Reference to list of completions to trim
+# @param string $dword   Reference to variable to contain word to remove from
+#                        expected cmd.
 # See also: bash_completion._ltrim_colon_completions
-proc _ltrim_colon_completions {cword items} {
-    upvar 1 $cword cword_out
+proc _ltrim_colon_completions {cmd items dword} {
     upvar 1 $items items_out
+    upvar 1 $dword dword_out
+
+    set cur "";  # Default to empty word to complete on
+    set words [split_words_bash $cmd]
+    if {[llength $words] > 1} {
+        # Assume last word of `$cmd' is word to complete on.
+        set index [expr [llength $words] - 1]
+        set cur [lindex $words $index]
+    }
     # If word-to-complete contains a colon,
     # and bash-version < 4,
     # or bash-version >= 4 and COMP_WORDBREAKS contains a colon
     if {
-        [string first : $cword_out] > -1 && (
+        [string first : $cur] > -1 && (
             [lindex $::BASH_VERSINFO 0] < 4 ||
             ([lindex $::BASH_VERSINFO 0] >= 4 && [string first ":" $::COMP_WORDBREAKS] > -1)
         )
     } {
+        set dword_out $cur
         for {set i 0} {$i < [llength $items_out]} {incr i} {
             set item [lindex $items_out $i]
-            if {[string first $cword_out $item] == 0} {
+            if {[string first $cur $item] == 0} {
                 # Strip colon-prefix
-                lset items_out $i [string range $item [string length $cword_out] end]
+                lset items_out $i [string range $item [string length $cur] end]
             }
         }
-        #set cword_out ""
     }
 }
 
@@ -694,8 +777,15 @@ proc match_items {items {args {}}} {
                 timeout { set result false; break }
             }
         } else {
+            set end ""
+            if {$arg(end-prompt) && $i + $j == [llength $items]} {
+                set end "$prompt"
+                _escape_regexp_chars end
+                # \$ matches real end of expect_out buffer
+                set end "$end\$"
+            }
             expect {
-                -re "^$expected" { set result true }
+                -re "^$expected$end" { set result true }
                 default { set result false; break }
                 timeout { set result false; break }
             }

-- 
bash-completion



More information about the Bash-completion-commits mailing list