Check-in [ea4e9a080f]
Not logged in
Overview
Comment: tclreadline.c tclreadlineCompleter.tcl
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ea4e9a080fed5d5a1bdb87cacefeb7c931680b5b
User & Date: johannes@zellner.org on 1999-09-13 00:21:47
Other Links: manifest | tags
Context
1999-09-13
16:33
.tclshrc .vimrc Modified Files: Makefile.in configure.in sample.tclshrc tclreadline.c tclreadline.h.in Added Files: config.h.in check-in: 0d1401e9c1 user: johannes@zellner.org tags: trunk
00:21
tclreadline.c tclreadlineCompleter.tcl check-in: ea4e9a080f user: johannes@zellner.org tags: trunk
1999-09-10
19:01
Modified Files: Tag: 2.0 GPL README TODO configure.in pkgIndex.tcl.in sample.tclshrc sources tclreadline.h.in tclreadline.n.in tclreadlineCompleter.tcl tclreadlineSetup.tcl.in aux/config.guess aux/config.sub aux/install-sh aux/mkinstalldirs aux/tcltags aux/vimtags Added Files: Tag: 2.0 Makefile.in tclreadline.c tclreadlineConfig.sh.in tclreadlineInit.tcl.in check-in: e0dfd309af user: johannes@zellner.org tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Modified tclreadline.c from [19dbcdadd7] to [3d6f99eaa5].

     1      1   
     2      2    /* ==================================================================
     3      3   
     4      4       FILE: "/home/joze/src/tclreadline/tclreadline.c"
     5         -    LAST MODIFICATION: "Fri Sep 10 02:57:55 1999 (joze)"
            5  +    LAST MODIFICATION: "Mon Sep 13 02:21:35 1999 (joze)"
     6      6       (C) 1998, 1999 by Johannes Zellner, <johannes@zellner.org>
     7      7       $Id$
     8      8       ---
     9      9   
    10     10       tclreadline -- gnu readline for tcl
    11     11       Copyright (C) 1999  Johannes Zellner
    12     12   
................................................................................
   472    472        * default is " \t\n\"\\'`@$><=;|&{("
   473    473        * removed "(" <-- arrays
   474    474        * removed "{" <-- `${' variables 
   475    475        * removed "<" <-- completion lists with < ... >
   476    476        * added "[]"
   477    477        * added "}"
   478    478        */
   479         -    rl_basic_word_break_characters = " \t\n\"\\@$}>=;|&[]";
          479  +    /* 11.Sep rl_basic_word_break_characters = " \t\n\"\\@$}=;|&[]"; */
          480  +    /* besser (11. Sept) 2. (removed \") */
          481  +    /* rl_basic_word_break_characters = " \t\n\\@$}=;|&[]"; */
          482  +    /* besser (11. Sept) 3. (removed }) */
          483  +    rl_basic_word_break_characters = " \t\n\\@$=;|&[]";
   480    484       // rl_basic_quote_characters = "\"{"; // XXX ??? XXX
   481    485       // rl_completer_quote_characters = "\"";
   482    486       /*
   483    487       rl_filename_quote_characters
   484    488       = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
   485    489   
   486    490       rl_filename_quoting_function
................................................................................
   522    526   
   523    527   char**
   524    528   TclReadlineCompletion(char* text, int start, int end)
   525    529   {
   526    530       char** matches = (char**) NULL;
   527    531       int status;
   528    532       // rl_attempted_completion_over = 0;
          533  +    rl_completion_append_character = ' '; /* reset, just in case ... */
   529    534   
   530    535   #if 0
   531    536       fprintf(stderr, "DEBUG> TclReadlineCompletion: text=|%s|\n", text);
   532    537       fprintf(stderr, "DEBUG> TclReadlineCompletion: start=|%d|\n", start);
   533    538       fprintf(stderr, "DEBUG> TclReadlineCompletion: end=|%d|\n", end);
   534    539   #endif
   535    540   
................................................................................
   624    629                       return (char**) NULL;
   625    630                   }
   626    631                   /*
   627    632                   fprintf (stderr, "(TclReadlineCompletion) len[%s]=%d\n",
   628    633                       matches[i], strlen(matches[i]));
   629    634                   */
   630    635               }
          636  +
          637  +            /**
          638  +             * this is a special one:
          639  +             * if the script returns exactly two arguments
          640  +             * and the second argument is the empty string,
          641  +             * the rl_completion_append_character is set
          642  +             * temporaryly to NULL.
          643  +             */
          644  +            if (2 == objc && !strlen(matches[1])) {
          645  +                i--;
          646  +                FREE(matches[1]);
          647  +                rl_completion_append_character = '\0';
          648  +            }
          649  +
   631    650               matches[i] = (char*) NULL; /* terminate */
   632    651           }
   633    652           Tcl_ResetResult(tclrl_interp); /* clear result space */
   634    653       }
   635    654   
   636    655       if (!matches && tclrl_use_builtin_completer) {
   637    656           matches = completion_matches(text, TclReadline0generator);

Modified tclreadlineCompleter.tcl from [d03579b986] to [6becbaf62d].

     1      1   #!/usr/locanl/bin/tclsh
     2      2   # FILE: "/home/joze/src/tclreadline/tclreadlineCompleter.tcl"
     3         -# LAST MODIFICATION: "Fri Sep 10 03:06:31 1999 (joze)"
            3  +# LAST MODIFICATION: "Mon Sep 13 02:21:21 1999 (joze)"
     4      4   # (C) 1998, 1999 by Johannes Zellner, <johannes@zellner.org>
     5      5   # $Id$
     6      6   # ---
     7      7   #
     8      8   # tclreadline -- gnu readline for tcl
     9      9   # Copyright (C) 1999  Johannes Zellner
    10     10   #
................................................................................
    23     23   # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    24     24   #
    25     25   # johannes@zellner.org
    26     26   # http://www.zellner.org/tclreadline/
    27     27   #
    28     28   # ================================================================== 
    29     29   
    30         -# done:
    31         -#
    32         -# - after
    33         -# - append
    34         -# - array
    35         -# - bgerror
    36         -# - binary
    37         -# - break
    38         -# - catch
    39         -# - cd
    40         -# - clock
    41         -# - close
    42         -# - concat
    43         -# - continue
    44         -# - (ddd is only on M$)
    45         -# - encoding
    46         -# - eof
    47         -# - error
    48         -# - eval
    49         -# - exec
    50         -# - exit
    51         -# - expr
    52         -# - fblocked
    53         -# - fconfigure
    54         -# - fcopy
    55         -# - file
    56         -# - fileevent
    57         -# - flush
    58         -# - for # TODO
    59         -# - foreach # TODO
    60         -# - format # TODO
    61         -# - gets
    62         -# - glob
    63         -# - global
    64         -# - if # TODO
    65         -# - incr
    66         -# - index
    67         -# - info
    68         -# - interp
    69         -# - join
    70         -# - lappend
    71         -# - llength
    72         -# - linsert
    73         -# - list
    74         -# - load
    75         -# - lrange
    76         -# - lreplace
    77         -# - lsearch
    78         -# - lsort
    79         -# - history
    80         -# - load
    81         -# - namespace
    82         -# - open
    83         -# - package
    84         -# - pkg_mkIndex
    85         -# - proc
    86         -# - puts
    87         -# - pwd
    88         -# - pid
    89         -# - read
    90         -# - regexp
    91         -# - (registry is only on M$)
    92         -# - regsub
    93         -# - rename
    94         -# - (resource is on mac only)
    95         -# - return
    96         -# - scan # TODO
    97         -# - seek
    98         -# - socket
    99         -# - source
   100         -# - split # TODO
   101         -# - string
   102         -# - subst
   103         -# - switch
   104         -# - tell
   105         -# - time # TODO ??
   106         -# - trace
   107         -# - set
   108         -# - unknown
   109         -# - unset
   110         -# - update
   111         -# - uplevel
   112         -# - upvar
   113         -# - variable
   114         -# - vwait
   115         -# - while # TODO
   116         -# 
           30  +
           31  +# TODO:
           32  +#
           33  +#     - tcltest is missing
           34  +#
           35  +#     - last try: as for widgets
           36  +#
           37  +
   117     38   
   118     39   
   119     40   namespace eval tclreadline {
   120     41   
           42  +namespace export \
           43  +TryFromList CompleteFromList DisplayHints Rehash \
           44  +PreviousWord CommandCompletion RemoveUsedOptions \
           45  +HostList ChannelId InChannelId OutChannelId \
           46  +Lindex Llength CompleteBoolean
           47  +
           48  +#**
   121     49   # TryFromList will return an empty string, if
   122     50   # the text typed so far does not match any of the
   123     51   # elements in list. This might be used to allow
   124     52   # subsequent filename completion by the builtin
   125     53   # completer.
   126     54   #
   127         -proc TryFromList {text lst} {
           55  +proc TryFromList {text lst {allow ""}} {
   128     56   
   129     57       # puts stderr "(CompleteFromList) \ntext=|$text|"
   130     58       # puts stderr "(CompleteFromList) lst=|$lst|"
   131     59       set pre [GetQuotedPrefix ${text}]
   132         -    set matches [MatchesFromList $text $lst]
           60  +    set matches [MatchesFromList $text $lst $allow]
   133     61   
   134     62       # puts stderr "(CompleteFromList) matches=|$matches|"
   135     63       if {1 == [llength $matches]} { ; # unique match
   136     64           # puts stderr \nunique=$matches\n
   137     65           # puts stderr "\n|${pre}${matches}[Right ${pre}]|\n"
   138         -        return [string trim ${pre}${matches}[Right ${pre}]]
           66  +        set null [string index $matches 0]
           67  +        if {"<" == $null || "?" == $null} {
           68  +            return [string trim "[list $text] $lst"]
           69  +        } else {
           70  +            return [string trim ${pre}${matches}[Right ${pre}]]
           71  +        }
   139     72       } elseif {"" != ${matches}} {
   140     73           # puts stderr \nmore=$matches\n
   141     74           set longest [CompleteLongest ${matches}]
   142     75           # puts stderr longest=|$longest|
   143     76           if {"" == $longest} {
   144     77               return [string trim "[list $text] ${matches}"]
   145     78           } else {
................................................................................
   146     79               return [string trim "${pre}${longest} ${matches}"]
   147     80           }
   148     81       } else {
   149     82           return ""; # nothing to complete
   150     83       }
   151     84   }
   152     85   
           86  +#**
   153     87   # CompleteFromList will never return an empty string.
   154     88   # completes, if a completion can be done, or ring
   155     89   # the bell if not.
   156     90   #
   157     91   proc CompleteFromList {text lst} {
   158     92       set result [TryFromList ${text} ${lst}]
   159     93       if {![llength ${result}]} {
   160     94           Alert
   161     95           # return [string trim [list ${text}] ${lst}"]
   162         -        return [string trim "${text} ${lst}"]
           96  +        if {[llength ${lst}]} {
           97  +            return [string trim "${text} ${lst}"]
           98  +        } else {
           99  +            return [string trim [list ${text} {}]]
          100  +        }
   163    101       } else {
   164    102           return ${result}
   165    103       }
   166    104   }
   167    105   
   168         -proc MenuFromList {text lst} {
   169         -    return [CompleteFromList $text $lst]
          106  +#**
          107  +# CompleteBoolean does a CompleteFromList
          108  +# with a list of all valid boolean values.
          109  +#
          110  +proc CompleteBoolean {text} {
          111  +    return [CompleteFromList $text {yes no true false 1 0}]
   170    112   }
   171         -# ???????
          113  +
          114  +#**
          115  +# build a list of all executables which can be
          116  +# found in $env(PATH). This is (naturally) a bit
          117  +# slow, and should not called frequently. Instead
          118  +# it is a good idea to check if the variable
          119  +# `executables' exists and then just use it's
          120  +# content instead of calling Rehash.
          121  +# (see complete(exec)).
   172    122   # 
   173         -# proc MenuFromList {text lst} {
   174         -#     if {![llength ${text}]} {
   175         -#         return [string trim "{} ${lst}"]
   176         -#     } else {
   177         -#         return [TryFromList ${text} ${lst}]
   178         -#     }
   179         -# }
          123  +proc Rehash {} {
          124  +
          125  +    global env
          126  +    variable executables
          127  +
          128  +    if {![info exists env] || ![array exists env]} {
          129  +        return
          130  +    }
          131  +    if {![info exists env(PATH)]} {
          132  +        return
          133  +    }
          134  +
          135  +    set executables 0
          136  +    foreach dir [split $env(PATH) :] {
          137  +        if {[catch [list set files [glob -nocomplain ${dir}/*]]]} { continue }
          138  +        foreach file $files {
          139  +            if {[file executable $file]} {
          140  +                lappend executables [file tail $file]
          141  +            }
          142  +        }
          143  +    }
          144  +}
          145  +
          146  +#**
          147  +# build a list hosts from the /etc/hosts file.
          148  +# this is only done once. This is sort of a
          149  +# dirty hack, /etc/hosts is hardcoded ...
   180    150   # 
   181         -
          151  +proc HostList {} {
          152  +    # read the host table only once.
          153  +    #
          154  +    variable hosts
          155  +    if {![info exists hosts]} {
          156  +        catch {
          157  +            set id [open /etc/hosts r]
          158  +            set hosts ""
          159  +            if {0 != ${id}} {
          160  +                while {-1 != [gets ${id} line]} {
          161  +                    regsub {#.*} ${line} {} line
          162  +                    if {[llength ${line}] >= 2} {
          163  +                        lappend hosts [lindex ${line} 1]
          164  +                    }
          165  +                }
          166  +                close $id
          167  +            } 
          168  +        }
          169  +    }
          170  +    return $hosts
          171  +}
   182    172   
   183    173   #**
   184    174   # never return an empty string, never complete.
   185    175   # This is useful for showing options lists for example.
   186    176   #
   187    177   proc DisplayHints {lst} {
   188    178       return [string trim "{} ${lst}"]
   189    179   }
   190    180   
   191    181   #**
   192         -# find (partial) matches for `text' in `lst'.
   193         -# Ring the bell and return the whole list, if
   194         -# the user tries to complete ?..? options or
   195         -# <..> hints.
          182  +# find (partial) matches for `text' in `lst'. Ring
          183  +# the bell and return the whole list, if the user
          184  +# tries to complete ?..? options or <..> hints.
   196    185   #
   197         -proc MatchesFromList {text lst} {
          186  +# MatchesFromList returns a list which is not suitable
          187  +# for passing to the readline completer. Thus,
          188  +# MatchesFromList should not be called directly but
          189  +# from formatting routines as TryFromList.
          190  +#
          191  +proc MatchesFromList {text lst {allow ""}} {
   198    192       set result ""
   199    193       set text [StripPrefix $text]
   200    194       set null [string index $text 0]
   201         -    if {"<" == $null || "?" == $null} {
   202         -        Alert
   203         -        return $lst
          195  +    foreach char {< ?} {
          196  +        if {$char == $null && -1 == [string first $char $allow]} {
          197  +            Alert
          198  +            return $lst
          199  +        }
   204    200       }
   205    201       # puts stderr "(MatchesFromList) text=$text"
   206    202       # puts stderr "(MatchesFromList) lst=$lst"
   207    203       foreach word $lst {
   208    204           if {[string match ${text}* ${word}]} {
   209    205               lappend result ${word}
   210    206           }
................................................................................
   224    220       return ${expr_pos}
   225    221   }
   226    222   
   227    223   proc RemoveUsedOptions {line opts {terminate {}}} {
   228    224       if {[llength ${terminate}]} {
   229    225           if {[regexp -- ${terminate} ${line}]} {
   230    226               return ""
          227  +            # return ${terminate}
   231    228           }
   232    229       }
   233    230       set new ""
   234    231       foreach word ${opts} {
   235         -        if {![regexp -- ${word} ${line}]} {
          232  +        if {-1 == [string first ${word} ${line}]} {
   236    233               lappend new ${word}
   237    234           }
   238    235       }
   239    236       return [string trim ${new}]
   240    237   }
   241    238   
   242    239   proc Alert {} {
   243    240       puts -nonewline \a
   244    241       flush stdout
   245    242   }
   246    243   
   247         -
          244  +#**
   248    245   # get the longest common completion
   249    246   # e.g. str == {tcl_version tclreadline_version tclreadline_library}
   250    247   # --> [CompleteLongest ${str}] == "tcl"
   251    248   #
   252    249   proc CompleteLongest {str} {
   253    250       # puts stderr str=$str
   254    251       set match0 [lindex ${str} 0]
................................................................................
   320    317       if {1 < [llength $value] && "" == $right} {
   321    318           return [list \"${value}\"]
   322    319       } else {
   323    320           return [list ${left}${value}${right}]
   324    321       }
   325    322   }
   326    323   
   327         -proc InChannelId {text} {
   328         -    # return [ChannelId ${text} inChannel {stdin}]
   329         -    return [ChannelId ${text} inChannel]
          324  +# the following two channel proc's make use of
          325  +# the brandnew (Sep 99) `file channels' command
          326  +# but have some fallback behaviour for older
          327  +# tcl version.
          328  +#
          329  +proc InChannelId {text {switches ""}} {
          330  +    if [catch {set chs [file channels]}] {
          331  +        set chs {stdin}
          332  +    }
          333  +    set result ""
          334  +    foreach ch $chs {
          335  +        if {![catch {fileevent $ch readable}]} {
          336  +            lappend result $ch
          337  +        }
          338  +    }
          339  +    return [ChannelId ${text} <inChannel> $result $switches]
   330    340   }
   331    341   
   332         -proc OutChannelId {text} {
   333         -    # return [ChannelId ${text} outChannel {stdout stderr}]
   334         -    return [ChannelId ${text} outChannel]
          342  +proc OutChannelId {text {switches ""}} {
          343  +    if [catch {set chs [file channels]}] {
          344  +        set chs {stdout stderr}
          345  +    }
          346  +    set result ""
          347  +    foreach ch $chs {
          348  +        if {![catch {fileevent $ch writable}]} {
          349  +            lappend result $ch
          350  +        }
          351  +    }
          352  +    return [ChannelId ${text} <outChannel> $result $switches]
   335    353   }
   336    354   
   337         -proc ChannelId {text {descript channelId} {chs ""}} {
          355  +proc ChannelId {text {descript <channelId>} {chs ""} {switches ""}} {
   338    356       if {"" == ${chs}} {
   339    357           # the `file channels' command is present
   340    358           # only in pretty new versions.
   341    359           #
   342    360           if [catch {set chs [file channels]}] {
   343    361               set chs {stdin stdout stderr}
   344    362           }
   345    363       }
   346         -    if {[llength [set channel [MatchesFromList ${text} ${chs}]]]} {
          364  +    if {[llength [set channel [TryFromList ${text} "${chs} ${switches}"]]]} {
   347    365           return ${channel}
   348    366       } else {
   349         -        return [DisplayHints ${descript}]
          367  +        return [DisplayHints [string trim "${descript} ${switches}"]]
   350    368       }
   351    369   }
   352    370   
   353    371   proc QuoteQuotes {line} {
   354    372       regsub -all -- \" $line {\"} line
   355    373       regsub -all -- \{ $line {\{} line; # \}\} (keep the editor happy)
   356    374       return $line
................................................................................
   400    418   #     return [llength $pre_text]
   401    419   # 
   402    420   }
   403    421   
   404    422   proc Right {left} {
   405    423       # puts left=$left
   406    424       if {"\"" == $left} {
   407         -        return {\"}
          425  +        return "\""
   408    426       } elseif {"\\\"" == $left} {
   409    427           return "\\\""
   410    428       } elseif {"\{" == $left} {
   411    429           return "\}"
   412    430       } elseif {"\\\{" == $left} {
   413    431           return "\\\}"
   414    432       }
................................................................................
   430    448       set pos 0
   431    449       while {-1 != [set pos [string first $char $line $pos]]} {
   432    450           incr pos
   433    451           incr found
   434    452       }
   435    453       return $found
   436    454   }
          455  +
          456  +#**
          457  +# make a proper tcl list from an icomplete
          458  +# string, that is: remove the junk. This is
          459  +# complementary to `IncompleteListRemainder'.
          460  +# e.g.:
          461  +#       for {set i 1} "
          462  +#  -->  for {set i 1}
          463  +#
          464  +proc ProperList {line} {
          465  +    set last [expr [string length $line] - 1]
          466  +    for {set i $last} {$i >= 0} {incr i -1} {
          467  +        if {![catch {llength [string range $line 0 $i]}]} {
          468  +            break
          469  +        }
          470  +    }
          471  +    return [string range $line 0 $i]
          472  +}
          473  +
          474  +#**
          475  +# return the last part of a line which
          476  +# prevents the line from beeing a list.
          477  +# This is complementary to `ProperList'.
          478  +#
          479  +proc IncompleteListRemainder {line} {
          480  +    set last [expr [string length $line] - 1]
          481  +    for {set i $last} {$i >= 0} {incr i -1} {
          482  +        if {![catch {llength [string range $line 0 $i]}]} {
          483  +            break
          484  +        }
          485  +    }
          486  +    incr i
          487  +    return [string range $line $i end]
          488  +}
   437    489   
   438    490   #**
   439    491   # save `lindex'. works also for non-complete lines
   440    492   # with opening parentheses or quotes.
   441    493   # usage as `lindex'.
          494  +# Eventually returns the Rest of an incomplete line,
          495  +# if the index is `end' or == [Llength $line].
   442    496   #
   443    497   proc Lindex {line pos} {
   444    498       if {[catch [list set sub [lindex $line $pos]]]} {
   445         -        set diff [expr [CountChar $line \{] - [CountChar $line \}]]
   446         -        # puts stderr diff=$diff
   447         -        for {set i 0} {$i < $diff} {incr i} { ; # \{ keep the editor happy
   448         -            append line \}
          499  +        if {"end" == $pos || [Llength $line] == $pos} {
          500  +            return [IncompleteListRemainder $line]
   449    501           }
   450         -        # puts stderr line=$line
   451         -        if {!$diff || [catch [list set sub [lindex $line $pos]]]} {
   452         -            if {[expr [CountChar $line \"] % 2]} { append line \" }
   453         -        }
          502  +        set line [ProperList $line]
          503  +        # puts stderr \nproper_line=|$proper_line|
   454    504           if {[catch [list set sub [lindex $line $pos]]]} { return {} }
   455    505       }
   456    506       return $sub
   457    507   }
   458    508   
   459    509   #**
   460    510   # save `llength' (see above).
   461    511   #
   462    512   proc Llength {line} {
   463         -    set diff 0
   464    513       if {[catch [list set len [llength $line]]]} {
   465         -        set diff [expr [CountChar $line \{] - [CountChar $line \}]]
   466         -        # puts stderr diff=$diff
   467         -        for {set i 0} {$i < $diff} {incr i} { ; # \{ keep the editor happy
   468         -            append line \}
   469         -        }
   470         -        if {$diff < 0} {
   471         -            set diff 0
   472         -        }
   473         -        # puts stderr line=$line
   474         -        if {!$diff || [catch [list set len [llength $line]]]} {
   475         -            incr diff
   476         -            if {[expr [CountChar $line \"] % 2]} { append line \" }
   477         -        }
          514  +        set line [ProperList $line]
   478    515           if {[catch [list set len [llength $line]]]} { return {} }
   479    516       }
   480         -    return [expr $len - $diff]
          517  +    # puts stderr \nline=$line
          518  +    return $len
   481    519   }
   482    520   
   483    521   proc StripPrefix {text} {
   484    522       # puts "(StripPrefix) text=|$text|"
   485    523       set null [string index $text 0]
   486    524       if {"\"" == $null || "\{" == $null} {
   487    525           return [string range $text 1 end]
   488    526       } else {
   489    527           return $text
   490    528       }
   491    529   }
   492    530   
   493         -proc ListCompletion {text {level -1}} {
   494         -    # TODO
   495         -    return ""
   496         -    # return [VarCompletion ${text} ${level}]
   497         -}
   498         -
   499    531   proc VarCompletion {text {level -1}} {
   500    532       if {-1 == ${level}} {
   501    533           set level [info level]
   502    534       } else {
   503    535           incr level
   504    536       }
   505    537       set pre [GetQuotedPrefix ${text}]
................................................................................
   533    565           }
   534    566           set namespaces ${new}
   535    567           unset new
   536    568       }
   537    569       set matches \
   538    570       [string trim "[uplevel ${level} info vars ${var}*] ${namespaces}"]
   539    571       if {1 == [llength $matches]} { ; # unique match
          572  +
   540    573           # check if this unique match is an
   541    574           # array name, (whith no "(" yet).
   542    575           #
   543    576           if {[uplevel ${level} array exists $matches]} {
   544    577               return [VarCompletion ${matches}( ${level}]; # recursion
   545    578           } else {
   546    579               return ${pre}${matches}[Right ${pre}]
   547    580           }
   548    581       } elseif {"" != $matches} { ; # more than one match
   549         -        #puts stderr "(VarComletion) matches=|$matches|"
   550         -        #puts stderr "(VarComletion) text=|$text|"
   551         -# 
   552         -#         set common [CompleteLongest ${matches}]
   553         -#         if {"" == ${common}} {
   554         -#             return [Format ${matches} ${text}]
   555         -#         } else {
   556         -#             return [string trim "${pre}${common} ${matches}"]
   557         -#         }
   558         -# 
   559    582             return [CompleteFromList ${text} ${matches}]
   560    583       } else {
   561    584           return ""; # nothing to complete
   562    585       }
   563    586   }
          587  +
          588  +proc CompleteControlStatement {text start end line pos mod pre new_line} {
          589  +    set pre [GetQuotedPrefix ${pre}]
          590  +    set cmd [Lindex $new_line 0]
          591  +    set diff [expr \
          592  +    [string length $line] - [string length $new_line]]
          593  +    if {$diff == [expr $start + 1]} {
          594  +        set mod1 $mod
          595  +    } else {
          596  +        set mod1 $text
          597  +        set pre ""
          598  +    }
          599  +    set new_end [expr $end - $diff]
          600  +    set new_start [expr $new_end - [string length $mod1]]
          601  +    # puts ""
          602  +    # puts new_start=$new_start
          603  +    # puts new_end=$new_end
          604  +    # puts new_line=$new_line
          605  +    # puts mod1=$mod1
          606  +    if {$new_start < 0} {
          607  +        return ""; # when does this occur?
          608  +    }
          609  +    # puts stderr ""
          610  +    # puts stderr start=|$start|
          611  +    # puts stderr end=|$end|
          612  +    # puts stderr mod=|$mod|
          613  +    # puts stderr new_start=|$new_start|
          614  +    # puts stderr new_end=|$new_end|
          615  +    # puts stderr new_line=|$new_line|
          616  +    # puts stderr ""
          617  +    set res [ScriptCompleter $mod1 $new_start $new_end $new_line]
          618  +    # puts stderr \n\${pre}\${res}=|${pre}${res}|
          619  +    if {[string length [Lindex ${res} 0]]} {
          620  +        return ${pre}${res}
          621  +    } else {
          622  +        return ${res}
          623  +    }
          624  +    return ""
          625  +}
          626  +
          627  +proc BraceOrControlStatement {text start end line pos mod} {
          628  +    if {![string length [Lindex $line $pos]]} {
          629  +        return [list \{ {}]; # \}
          630  +    } else {
          631  +        set new_line [string trim [IncompleteListRemainder $line]]
          632  +        if {![regexp {^([\{\"])(.*)$} $new_line all pre new_line]} {
          633  +            set pre ""
          634  +        }
          635  +        return [CompleteControlStatement $text \
          636  +        $start $end $line $pos $mod $pre $new_line]
          637  +    }
          638  +}
   564    639   
   565    640   proc FullQualifiedMatches {qualifier matchlist} {
   566    641       set new ""
          642  +    if {"" != $qualifier && ![regexp ::$ $qualifier]} {
          643  +        append qualifier ::
          644  +    }
   567    645       foreach entry ${matchlist} {
   568         -        set full ${qualifier}::${entry}
          646  +        set full ${qualifier}${entry}
   569    647           if {"" != [namespace which ${full}]} {
   570    648               lappend new ${full}
   571    649           }
   572    650       }
   573    651       return ${new}
   574    652   }
   575    653   
................................................................................
   577    655       return [CommandCompletion ${cmd} procs]
   578    656   }
   579    657   
   580    658   proc CommandsOnlyCompletion {cmd} {
   581    659       return [CommandCompletion ${cmd} commands]
   582    660   }
   583    661   
   584         -proc CommandCompletion {cmd {action both} {spc ::}} {
          662  +proc CommandCompletion {cmd {action both} {spc ::} {pre UNDEFINED}} {
   585    663       # puts stderr "(CommandCompletion) cmd=|$cmd|"
   586    664       # puts stderr "(CommandCompletion) action=|$action|"
   587    665       # puts stderr "(CommandCompletion) spc=|$spc|"
          666  +
          667  +    # get the leading colons in `cmd'.
          668  +    if {"UNDEFINED" == $pre} {
          669  +        regexp {^:*} ${cmd} pre
          670  +    }
          671  +    # puts stderr \npre=|$pre|
          672  +
          673  +    set cmd [StripPrefix ${cmd}]
   588    674       set quali [namespace qualifiers ${cmd}]
   589         -    if {[llength ${quali}]} {
   590         -        set rec [CommandCompletion [namespace tail ${cmd}] ${action} ${quali}]
   591         -        return [FullQualifiedMatches ${quali} ${rec}]
          675  +    if {[string length ${quali}]} {
          676  +        # puts stderr \nquali=|$quali|
          677  +        set matches [CommandCompletion \
          678  +        [namespace tail ${cmd}] ${action} ${spc}${quali} ${pre}]
          679  +        # puts stderr \nmatches1=|$matches|
          680  +        return $matches
   592    681       }
   593         -    # puts stderr \ncmd=|$cmd|\n
   594    682       set cmd [string trim ${cmd}]*
          683  +    # puts stderr \ncmd=|$cmd|\n
   595    684       if {"procs" != ${action}} {
   596         -        set commands [namespace eval $spc "info commands [QuoteQuotes ${cmd}]"]
   597         -        # puts stderr commands=|$commands|
          685  +        set all_commands [namespace eval $spc [list info commands ${cmd}]]
          686  +        # puts stderr all_commands=|$all_commands|
          687  +        set commands ""
          688  +        foreach command $all_commands {
          689  +            if {[namespace eval $spc [list namespace origin $command]] == \
          690  +                [namespace eval $spc [list namespace which $command]]} {
          691  +                lappend commands $command
          692  +            }
          693  +        }
   598    694       } else {
   599    695           set commands ""
   600    696       }
   601    697       if {"commands" != ${action}} {
   602         -        set procs [namespace eval $spc "info procs [QuoteQuotes ${cmd}]"]
          698  +        set all_procs [namespace eval $spc [list info procs ${cmd}]]
   603    699           # puts stderr procs=|$procs|
          700  +        set procs ""
          701  +        foreach proc $all_procs {
          702  +            if {[namespace eval $spc [list namespace origin $command]] == \
          703  +                [namespace eval $spc [list namespace which $command]]} {
          704  +                lappend procs $command
          705  +            }
          706  +        }
   604    707       } else {
   605    708           set procs ""
   606    709       }
   607    710       set matches [namespace eval $spc concat ${commands} ${procs}]
   608         -# 
   609         -#     foreach match ${matches} {
   610         -#         set full ${spc}::${match}
   611         -#         if {"" != [namespace which ${full}]} {
   612         -#             lappend new bla::${full}
   613         -#         }
   614         -#     }
   615         -# 
   616    711       set namespaces [namespace children $spc ${cmd}]
          712  +
   617    713       if {![llength ${matches}] && 1 == [llength ${namespaces}]} {
   618         -        set namespaces [string trim ${namespaces}]
   619         -        regsub {^([^:])} $namespaces {::\1} namespaces
   620         -    #    set matches [namespace eval ${namespaces} \
   621         -    #    {concat [info commands] [info procs]}]
   622         -        if {"procs" != ${action}} {
   623         -            set n_commands [namespace eval ${namespaces} "info commands"]
   624         -        } else {
   625         -            set n_commands ""
   626         -        }
   627         -        if {"commands" != ${action}} {
   628         -            set n_procs [namespace eval ${namespaces} "info procs"]
   629         -        } else {
   630         -            set n_procs ""
   631         -        }
   632         -        set matches [string trim "${n_commands} ${n_procs}"]
   633         -        if {[llength ${matches}]} {
   634         -# 
   635         -#             foreach match ${matches} {
   636         -#                 set full ${namespaces}::${match}
   637         -#                 if {"" != [namespace which ${full}]} {
   638         -#                     lappend new ${namespaces}::${match}
   639         -#                 }
   640         -#             }
   641         -# 
   642         -#             set matches ${new}
   643         -#             unset new
   644         -# 
   645         -            set matches [FullQualifiedMatches ${namespaces} ${matches}]
   646         -            set namespaces ""
   647         -        }
   648         -        return [string trim "${matches} ${namespaces}"]
   649         -    } else {
   650         -        return [string trim "${matches} ${namespaces}"]
   651         -    }
          714  +        set matches [CommandCompletion {} ${action} ${namespaces} ${pre}]
          715  +        # puts stderr \nmatches=|$matches|
          716  +        return $matches
          717  +    }
          718  +
          719  +    # make `namespaces' having exactly
          720  +    # the same number of colons as `cmd'.
          721  +    #
          722  +    regsub -all {^:*} $spc $pre spc
          723  +
          724  +    set matches [FullQualifiedMatches ${spc} ${matches}]
          725  +    # puts stderr \nmatches3=|$matches|
          726  +    return [string trim "${matches} ${namespaces}"]
   652    727   }
   653    728   
   654    729   #**
   655    730   # check, if the first argument starts with a '['
   656    731   # and must be evaluated before continuing.
   657         -# NOTE: eventually modifies all arguments.
          732  +# NOTE: trims the `line'.
          733  +#       eventually modifies all arguments.
   658    734   # DATE: Sep-06-1999
   659    735   #
   660    736   proc EventuallyEvaluateFirst {partT startT endT lineT} {
   661    737       # return; # disabled
   662    738       upvar $partT part $startT start $endT end $lineT line
          739  +
          740  +    set oldlen [string length ${line}]
   663    741       set line [string trim ${line}]
          742  +    set diff [expr [string length $line] - $oldlen]
          743  +    incr start $diff
          744  +    incr end $diff
   664    745   
   665    746       set char [string index ${line} 0]
   666    747       if {{[} != ${char} && {$} != ${char}} {return}
   667    748   
   668    749       set pos 0
   669    750       while {-1 != [set idx [string first {]} ${line} ${pos}]]} {
   670    751           set cmd [string range ${line} 0 ${idx}]
................................................................................
   691    772   # % puts $b<TAB>
   692    773   # part  == $b
   693    774   # start == 5
   694    775   # end   == 7
   695    776   # line  == "$puts $b"
   696    777   #
   697    778   proc ScriptCompleter {part start end line} {
          779  +
   698    780       # puts stderr "(ScriptCompleter) |$part| $start $end |$line|"
   699         -    variable known_cmds
          781  +
          782  +    # if the character before the cursor is a terminating
          783  +    # quote and the user wants completion, we insert a white
          784  +    # space here.
          785  +    #
          786  +    set char [string index $line [expr $end - 1]]
          787  +    if {"\}" == $char} {
          788  +        append $part " "
          789  +        return [list $part]
          790  +    }
          791  +
   700    792       if {{$} == [string index $part 0]} {
          793  +
   701    794           # check for a !$ history event
   702    795           #
   703    796           if {$start > 0} {
   704    797               if {{!} == [string index $line [expr $start - 1]]} {
   705    798                   return ""
   706    799               }
   707    800           }
   708    801           # variable completion. Check first, if the
   709    802           # variable starts with a plain `$' or should
   710    803           # be enclosed in braces.
   711    804           #
   712    805           set var [string range $part 1 end]
   713         -# 
   714         -#         if {"\{" == [string index $part 1]} {
   715         -#             set var [string range $part 2 end]
   716         -#             set left "\{"
   717         -#         } else {
   718         -#             set left ""
   719         -#             set var [string range $part 1 end]
   720         -#         }
   721         -# 
          806  +
   722    807           # check if $var is an array name, which
   723    808           # already has already a "(" somewhere inside.
   724    809           #
   725    810           if {"" != [set vc [VarCompletion $var]]} {
   726    811               if {"" == [lindex $vc 0]} {
   727    812                   return "\$ [lrange ${vc} 1 end]"
   728    813               } else {
   729    814                   return \$${vc}
   730    815               }
   731    816               # puts stderr vc=|$vc|
   732    817           } else {
   733    818               return ""
   734    819           }
          820  +
   735    821       # SCENARIO:
   736    822       #
   737    823       # % puts bla; put<TAB> $b
   738    824       # part  == put
   739    825       # start == 10
   740    826       # end   == 13
   741    827       # line  == "puts bla; put $b"
................................................................................
   749    835           set new_start [lindex $sub 0]
   750    836           set new_end [expr $end - ($start - $new_start)]
   751    837           set new_line [lindex $sub 1]
   752    838           # puts stderr "(SplitLine) $new_start $new_end $new_line"
   753    839           return [ScriptCompleter $part $new_start $new_end $new_line]
   754    840       } elseif {0 == [set pos [PartPosition part start end line]]} {
   755    841           # puts stderr "(PartPosition) $part $start $end $line"
   756         -        # set matches [array names known_cmds "[string trim ${part}]*"]
   757    842           set all [CommandCompletion ${part}]
   758    843           # puts stderr "(ScriptCompleter) all=$all"
   759    844           #puts \nmatches=$matches\n
   760    845           # return [Format $all $part]
   761    846           return [TryFromList $part $all]
   762    847       } else {
          848  +
   763    849           # try to use $pos further ...
   764    850           # puts stderr |$line|
          851  +        #
   765    852           if {"." == [string index [string trim ${line}] 0]} {
   766    853               set alias WIDGET
   767    854           } else {
   768         -            set alias [lindex [QuoteQuotes ${line}] 0]
          855  +
          856  +            # the double `lindex' strips {} or quotes.
          857  +            # the subst enables variables containing
          858  +            # command names.
          859  +            #
          860  +            set alias [uplevel [info level] \
          861  +            subst [lindex [lindex [QuoteQuotes ${line}] 0] 0]]
          862  +
          863  +            # make `alias' a fully qualified name.
          864  +            # this can raise an error, if alias is
          865  +            # no valid command.
          866  +            #
          867  +            if {[catch [list set alias [namespace origin $alias]]]} {
          868  +                return ""
          869  +            }
          870  +
          871  +            # strip leading ::'s.
          872  +            #
          873  +            regsub -all {^::} $alias {} alias
          874  +            set namespc [namespace qualifiers $alias]
          875  +            set alias [namespace tail $alias]
   769    876           }
          877  +
   770    878           foreach cmd [list ${alias} tclreadline_complete_unknown] {
   771         -            if {"" != [namespace eval ::tclreadline \
          879  +            # puts stderr ${namespc}complete(${cmd})
          880  +            if {"" != [namespace eval ::tclreadline::${namespc} \
   772    881                   [list info procs complete(${cmd})]]
   773    882               } {
          883  +                # puts found=|complete($cmd)|
   774    884                   # to be more error-proof, we check here,
   775    885                   # if complete($cmd) takes exactly 5 arguments.
   776    886                   #
   777    887                   if {6 != [set arguments [llength \
   778         -                    [namespace eval ::tclreadline \
   779         -                    [list info args complete(${cmd})]]]]
          888  +                    [namespace eval ::tclreadline::${namespc} \
          889  +                    [list info args complete($cmd)]]]]
   780    890                   } {
   781    891                       error [list complete(${cmd}) takes ${arguments} \
   782    892                       arguments, but should take exactly 6.]
   783    893                   }
   784    894   
   785    895                   # remove leading quotes
   786    896                   #
   787    897                   set mod [StripPrefix $part]
   788    898                   # puts stderr mod=$mod
   789    899   
   790    900                   if {[catch [list set script_result \
   791         -                    [complete(${cmd}) $part \
   792         -                    $start $end $line $pos $mod]] ::tclreadline::errorMsg]
          901  +                    [namespace eval ::tclreadline::${namespc} \
          902  +                    [list complete(${cmd}) $part $start $end $line $pos $mod]]]\
          903  +                    ::tclreadline::errorMsg]
   793    904                   } {
   794         -                    error "error during evaluation of `complete(${cmd})'"
          905  +                    error [list error during evaluation of `complete(${cmd})']
   795    906                   }
   796    907                   # puts stderr \nscript_result=|${script_result}|
   797    908                   return ${script_result}
   798    909               }
          910  +            # set namespc ""; # no qualifiers for tclreadline_complete_unknown
   799    911           }
   800    912           # no specific command completer found.
   801         -        if {"" != [array names known_cmds $cmd]} {
   802         -            set current [lindex $known_cmds($cmd) $pos]
   803         -            if {"" != $current && "" == [string trim $part]} {
   804         -                return $current
   805         -            } else {
   806         -                return ""
   807         -            }
   808         -        } else {
   809         -            return ""
   810         -        }
          913  +        return ""
   811    914       }
   812    915       error "{NOTREACHED (this is probably an error)}"
   813    916   }
   814    917   
   815    918   
   816    919   # explicit command completers
   817    920   #
................................................................................
   826    929       switch -- $pos {
   827    930           1 {
   828    931               return [CompleteFromList ${text} {<ms> cancel idle info}]
   829    932           }
   830    933           2 {
   831    934               switch -- $sub {
   832    935                   cancel {
   833         -                    set after_info [after info]
   834         -                    if {![llength $after_info]} {
   835         -                        return [DisplayHints <script>]
   836         -                    } else {
   837         -                        return [CompleteFromList $mod "<script> [after info]"]
   838         -                    }
          936  +                    return [CompleteFromList $text "<script> [after info]"]
   839    937                   }
   840    938                   idle {
   841    939                       return [DisplayHints <script>]
   842    940                   }
   843    941                   info {
   844         -                    return [CompleteFromList $mod [after info]]
          942  +                    return [CompleteFromList $text [after info]]
   845    943                   }
   846    944                   default { return [DisplayHints ?script?] }
   847    945               }
   848    946           }
   849    947           default {
   850    948               switch -- $sub {
   851    949                   info { return [DisplayHints {}] }
................................................................................
   871    969                   anymore donesearch exists get names
   872    970                   nextelement set size startsearch
   873    971               }
   874    972               return [CompleteFromList $text $cmds]
   875    973           }
   876    974           2 {
   877    975               set matches ""
   878         -            set vars [uplevel [info level] info vars ${mod}*]
          976  +            # set vars [uplevel [info level] info vars ${mod}*]
          977  +            #
          978  +            # better: this displays a list of array names if the
          979  +            # user inters with something which cannot be matched.
          980  +            # The matching against `text' is done by CompleteFromList.
          981  +            #
          982  +            set vars [uplevel [info level] info vars]
   879    983               foreach var ${vars} {
   880    984                   if {[uplevel [info level] array exists ${var}]} {
   881    985                       lappend matches ${var}
   882    986                   }
   883    987               }
   884    988               return [CompleteFromList ${text} ${matches}]
   885    989           }
   886         -        default {
          990  +        3 {
   887    991               set cmd [Lindex $line 1]
   888    992               set array_name [Lindex $line 2]
   889    993               switch -- $cmd {
   890    994                   get -
   891    995                   names {
   892    996                       set pattern [Lindex $line 3]
   893    997                       set matches [uplevel [info level] \
   894    998                       array names ${array_name} ${pattern}*]
   895    999                       if {![llength $matches]} {
   896         -                        return [Menu ?pattern?]
         1000  +                        return [DisplayHints ?pattern?]
   897   1001                       } else {
   898   1002                           return [CompleteFromList ${text} ${matches}]
   899   1003                       }
   900   1004                   }
   901   1005                   anymore -
   902   1006                   donesearch -
   903         -                nextid { return [Menu <searchId>] }
         1007  +                nextelement { return [DisplayHints <searchId>] }
   904   1008               }
   905   1009           }
   906   1010       }
   907   1011       return ""
   908   1012   }
   909   1013   
   910   1014   # proc complete(bgerror) {text start end line pos mod} {
................................................................................
   948   1052       }
   949   1053       return ""
   950   1054   }
   951   1055   
   952   1056   # proc complete(cd) {text start end line pos mod} {
   953   1057   # }
   954   1058   
   955         -proc complete(if) {text start end line pos mod} {
   956         -    # TODO: this is not good yet.
   957         -    switch -- $pos {
   958         -        1 { return [CompleteFromList $mod {\{}] }
   959         -        2 { return [TryFromList $mod {then}] }
   960         -        default {
   961         -            set prev [PreviousWord ${start} ${line}]
   962         -            switch $prev {
   963         -                then -
   964         -                else -
   965         -                elseif { return [CompleteFromList $mod {\{}] }
   966         -                default { return [TryFromList $text {then else elseif}] }
   967         -            }
   968         -        }
   969         -    }
   970         -    return ""
   971         -}
   972         -
   973         -proc complete(incr) {text start end line pos mod} {
   974         -    if {1 == $pos} {
   975         -        set matches [uplevel 2 info vars "${mod}*"]
   976         -        set final ""
   977         -        # check for integers
   978         -        #
   979         -        foreach match $matches {
   980         -            if {[uplevel 2 array exists $match]} {
   981         -                continue
   982         -            }
   983         -            if {[regexp {^[0-9]+$} [uplevel 2 set $match]]} {
   984         -                lappend final $match
   985         -            }
   986         -        }
   987         -        return [Format ${final} $text]
   988         -    }
   989         -}
   990         -
   991   1059   proc complete(clock) {text start end line pos mod} {
   992         -    set cmd [lindex $line 1]
         1060  +    set cmd [Lindex $line 1]
   993   1061       switch -- $pos {
   994   1062           1 {
   995         -            return [TryFromList $text {clicks format scan seconds}]
         1063  +            return [CompleteFromList $text {clicks format scan seconds}]
   996   1064           }
   997   1065           2 {
   998   1066               switch -- $cmd {
   999         -                format  { return [DisplayHints clockValue] }
  1000         -                scan    { return [DisplayHints dateString] }
         1067  +                format  { return [DisplayHints <clockValue>] }
         1068  +                scan    { return [DisplayHints <dateString>] }
         1069  +                clicks  -
         1070  +                seconds {}
         1071  +            }
         1072  +        }
         1073  +        3 -
         1074  +        5 {
         1075  +            switch -- $cmd {
         1076  +                format {
         1077  +                    set subcmds [RemoveUsedOptions $line {-format -gmt}]
         1078  +                    return [TryFromList $text $subcmds]
         1079  +                }
         1080  +                scan {
         1081  +                    set subcmds [RemoveUsedOptions $line {-base -gmt}]
         1082  +                    return [TryFromList $text $subcmds]
         1083  +                }
  1001   1084                   clicks  -
  1002   1085                   seconds {}
  1003   1086               }
  1004   1087           }
  1005         -        3 {
         1088  +        4 -
         1089  +        6 {
         1090  +            set sub [Lindex $line [expr $pos - 1]]
  1006   1091               switch -- $cmd {
  1007   1092                   format {
  1008         -                    set sub [lindex $line 3]
  1009         -                    set subcmds {-fmt -gmt}
  1010         -                    return [TryFromList $text $subcmds]
         1093  +                    switch -- $sub {
         1094  +                        -format { return [DisplayHints <string>] }
         1095  +                        -gmt    { return [DisplayHints <boolean>] }
         1096  +                    }
  1011   1097                   }
  1012   1098                   scan {
  1013         -                    set sub [lindex $line 3]
  1014         -                    set subcmds {-base -gmt}
  1015         -                    return [TryFromList $text $subcmds]
         1099  +                    switch -- $sub {
         1100  +                        -base { return [DisplayHints <clockVal>] }
         1101  +                        -gmt  { return [DisplayHints <boolean>] }
         1102  +                    }
  1016   1103                   }
  1017   1104                   clicks  -
  1018   1105                   seconds {}
  1019   1106               }
  1020   1107           }
  1021   1108       }
  1022   1109       return ""
  1023   1110   }
         1111  +
         1112  +proc complete(close) {text start end line pos mod} {
         1113  +    switch -- $pos {
         1114  +        1 { return [ChannelId $text] }
         1115  +    }
         1116  +    return ""
         1117  +}
         1118  +
         1119  +proc complete(concat) {text start end line pos mod} {
         1120  +    return [DisplayHints ?arg?]
         1121  +}
         1122  +
         1123  +# proc complete(continue) {text start end line pos mod} {
         1124  +# }
         1125  +
         1126  +# proc complete(dde) {text start end line pos mod} {
         1127  +#     We're not on windoze here ...
         1128  +# }
  1024   1129   
  1025   1130   proc complete(encoding) {text start end line pos mod} {
  1026         -    set cmd [lindex $line 1]
         1131  +    set cmd [Lindex $line 1]
  1027   1132       switch -- $pos {
  1028   1133           1 {
  1029         -            return [TryFromList $text {convertfrom convertto names system}]
         1134  +            return [CompleteFromList $text {convertfrom convertto names system}]
  1030   1135           }
  1031   1136           2 {
  1032   1137               switch -- $cmd {
  1033         -                names {}
  1034   1138                   convertfrom -
  1035   1139                   convertto -
  1036   1140                   system {
  1037         -                    return [TryFromList ${text} [encoding names]]
         1141  +                    return [CompleteFromList ${text} [encoding names]]
  1038   1142                   }
  1039   1143               }
  1040   1144           }
         1145  +        3 {
         1146  +            switch -- $cmd {
         1147  +                convertfrom { return [DisplayHints <data>] }
         1148  +                convertto { return [DisplayHints <string>] }
         1149  +            }
         1150  +        }
         1151  +    }
         1152  +    return ""
         1153  +}
         1154  +
         1155  +proc complete(eof) {text start end line pos mod} {
         1156  +    switch -- $pos {
         1157  +        1 { return [InChannelId $text] }
         1158  +    }
         1159  +    return ""
         1160  +}
         1161  +
         1162  +proc complete(error) {text start end line pos mod} {
         1163  +    switch -- $pos {
         1164  +        1 { return [DisplayHints <message>] }
         1165  +        2 { return [DisplayHints ?info?] }
         1166  +        3 { return [DisplayHints ?code?] }
         1167  +    }
         1168  +    return ""
         1169  +}
         1170  +
         1171  +proc complete(eval) {text start end line pos mod} {
         1172  +    switch -- $pos {
         1173  +        1 { return [DisplayHints <arg>] }
         1174  +        default { return [DisplayHints ?arg?] }
         1175  +    }
         1176  +    return ""
         1177  +}
         1178  +
         1179  +proc complete(exec) {text start end line pos mod} {
         1180  +    set redir [list | |& < <@ << > 2> >& >> 2>> >>& >@ 2>@ >&@]
         1181  +    variable executables
         1182  +    if {![info exists executables]} {
         1183  +        Rehash
         1184  +    }
         1185  +    switch -- $pos {
         1186  +        1 {
         1187  +            return [TryFromList $text "-keepnewline -- $executables"]
         1188  +        }
         1189  +        default {
         1190  +            set prev [PreviousWord ${start} ${line}]
         1191  +            if {"-keepnewline" == $prev && 2 == $pos} {
         1192  +                return [TryFromList $text "-- $executables"]
         1193  +            }
         1194  +            switch -exact -- $prev {
         1195  +                | -
         1196  +                |& { return [TryFromList $text $executables] }
         1197  +                < -
         1198  +                > -
         1199  +                2> -
         1200  +                >& -
         1201  +                >> -
         1202  +                2>> -
         1203  +                >>& { return "" }
         1204  +                <@ -
         1205  +                >@ -
         1206  +                2>@ -
         1207  +                >&@ { return [ChannelId $text] }
         1208  +                << { return [DisplayHints <value>] }
         1209  +                default { return [TryFromList $text $redir "<>"] }
         1210  +            }
         1211  +        }
         1212  +    }
         1213  +    return ""
         1214  +}
         1215  +
         1216  +proc complete(exit) {text start end line pos mod} {
         1217  +    switch -- $pos {
         1218  +        1 { return [DisplayHints ?returnCode?] }
  1041   1219       }
  1042   1220       return ""
  1043   1221   }
  1044   1222   
  1045   1223   proc complete(expr) {text start end line pos mod} {
         1224  +    set left $text
         1225  +    set right ""
         1226  +    set substitution [regexp -- {(.*)(\(.*)} $text all left right]; #-)
         1227  +
  1046   1228       set cmds {
         1229  +        - + ~ !  * / % + - << >> < > <= >= == != & ^ | && || <x?y:z>
  1047   1230           acos    cos     hypot   sinh 
  1048   1231           asin    cosh    log     sqrt 
  1049   1232           atan    exp     log10   tan 
  1050   1233           atan2   floor   pow     tanh 
  1051   1234           ceil    fmod    sin     abs 
  1052   1235           double  int     rand    round 
  1053   1236           srand 
  1054   1237       }
  1055         -    return [TryFromList $text $cmds]
         1238  +
         1239  +    if {")" == [string index $text end] && -1 != [lsearch $cmds $left]} {
         1240  +        return "$text "; # append a space after a closing ')'
         1241  +    }
         1242  +
         1243  +    switch -- $left {
         1244  +        rand { return "rand() " }
         1245  +
         1246  +        abs  -
         1247  +        acos -
         1248  +        asin -
         1249  +        atan -
         1250  +        ceil  -
         1251  +        cos -
         1252  +        cosh -
         1253  +        double -
         1254  +        exp -
         1255  +        floor -
         1256  +        int -
         1257  +        log -
         1258  +        log10 -
         1259  +        round  -
         1260  +        sin  -
         1261  +        sinh  -
         1262  +        sqrt  -
         1263  +        srand  -
         1264  +        tan  -
         1265  +        tanh { return [DisplayHints <value>] }
         1266  +
         1267  +
         1268  +        atan2 -
         1269  +        fmod -
         1270  +        hypot -
         1271  +        pow { return [DisplayHints <value>,<value>] }
         1272  +    }
         1273  +
         1274  +    set completions [TryFromList $left $cmds <>]
         1275  +    if {1 == [llength $completions]} {
         1276  +        if {!$substitution} {
         1277  +            if {"rand" == $completions} {
         1278  +                return "rand() "; # rand() takes no arguments
         1279  +            }
         1280  +            append completions (; #-)
         1281  +            return [list $completions {}]
         1282  +        }
         1283  +    } else {
         1284  +        return $completions
         1285  +    }
         1286  +    return ""
         1287  +}
         1288  +
         1289  +proc complete(fblocked) {text start end line pos mod} {
         1290  +    switch -- $pos {
         1291  +        1 { return [InChannelId $text] }
         1292  +    }
         1293  +    return ""
  1056   1294   }
  1057   1295   
  1058   1296   proc complete(fconfigure) {text start end line pos mod} {
  1059         -    set cmd [lindex $line 1]
         1297  +    set cmd [Lindex $line 1]
  1060   1298       switch -- $pos {
  1061   1299           1 {
  1062         -            return [ChannelId ${mod}]
         1300  +            return [ChannelId ${text}]
  1063   1301           }
  1064   1302           default {
  1065   1303               set option [PreviousWord ${start} ${line}]
  1066   1304               switch -- $option {
  1067   1305                   -blocking {
  1068         -                    return [TryFromList ${text} {yes no}]
         1306  +                    return [CompleteBoolean ${text}]
  1069   1307                   }
  1070   1308                   -buffering {
  1071         -                    return [TryFromList ${text} {full line none}]
         1309  +                    return [CompleteFromList ${text} {full line none}]
  1072   1310                   }
  1073   1311                   -buffersize {
  1074   1312                       if {![llength ${text}]} {
  1075         -                        return [DisplayHints newSize]
         1313  +                        return [DisplayHints <newSize>]
  1076   1314                       }
  1077   1315                   }
  1078   1316                   -encoding {
  1079         -                    return [TryFromList ${text} [encoding names]]
         1317  +                    return [CompleteFromList ${text} [encoding names]]
  1080   1318                   }
  1081   1319                   -eofchar {
  1082         -                    return [DisplayHints {\{inChar\ outChar\}}]
         1320  +                    return [DisplayHints {\{<inChar>\ <outChar>\}}]
  1083   1321                   }
  1084   1322                   -translation {
  1085         -                    return [TryFromList ${text} {auto binary cr crlf lf}]
         1323  +                    return [CompleteFromList ${text} {auto binary cr crlf lf}]
  1086   1324                   }
  1087         -                default {return [TryFromList $text {
         1325  +                default {return [CompleteFromList $text \
         1326  +                    [RemoveUsedOptions $line {
  1088   1327                       -blocking -buffering -buffersize
  1089         -                    -encoding -eofchar -translation}]
         1328  +                    -encoding -eofchar -translation}]]
  1090   1329                   }
  1091   1330               }
  1092   1331           }
  1093   1332       }
  1094   1333       return ""
  1095   1334   }
  1096   1335   
  1097   1336   proc complete(fcopy) {text start end line pos mod} {
  1098   1337       switch -- $pos {
  1099   1338           1 {
  1100         -            return [InChannelId ${mod}]
         1339  +            return [InChannelId ${text}]
  1101   1340           }
  1102   1341           2 {
  1103         -            return [OutChannelId ${mod}]
         1342  +            return [OutChannelId ${text}]
  1104   1343           }
  1105   1344           default {
  1106   1345               set option [PreviousWord ${start} ${line}]
  1107   1346               switch -- $option {
  1108         -                -size    { return [DisplayHints size] }
  1109         -                -command { return [DisplayHints callback] }
  1110         -                default  { return [TryFromList $text {-size -command}] }
         1347  +                -size    { return [DisplayHints <size>] }
         1348  +                -command { return [DisplayHints <callback>] }
         1349  +                default  { return [CompleteFromList $text \
         1350  +                    [RemoveUsedOptions $line {-size -command}]]
         1351  +                }
  1111   1352               }
  1112   1353           }
  1113   1354       }
  1114   1355       return ""
  1115   1356   }
  1116   1357   
  1117   1358   proc complete(file) {text start end line pos mod} {
  1118   1359       switch -- $pos {
  1119   1360           1 {
  1120   1361               set cmds {
  1121   1362                   atime attributes copy delete dirname executable exists
  1122         -                extension isdirectory isfile join lstat mtime mkdir
         1363  +                extension isdirectory isfile join lstat mkdir mtime
  1123   1364                   nativename owned pathtype readable readlink rename
  1124   1365                   rootname size split stat tail type volumes writable
  1125   1366               }
  1126   1367               return [TryFromList $text $cmds]
  1127   1368           }
  1128   1369           2 {
  1129         -            set cmd [lindex $line 1]
         1370  +            set cmd [Lindex $line 1]
  1130   1371               switch -- $cmd {
  1131   1372                   atime -
  1132   1373                   attributes -
  1133   1374                   dirname -
  1134   1375                   executable -
  1135   1376                   exists -
  1136   1377                   extension -
................................................................................
  1155   1396                   writable {
  1156   1397                       return ""
  1157   1398                   }
  1158   1399   
  1159   1400                   copy -
  1160   1401                   delete -
  1161   1402                   rename {
  1162         -                #    set match [MenuFromList ${mod} {-force}]
         1403  +                    # return [TryFromList $text "-force [glob *]"]
         1404  +                    # this is not perfect. The  `-force' and `--'
         1405  +                    # options will not be displayed.
  1163   1406                       return ""
  1164   1407                   }
  1165   1408               }
  1166   1409           }
  1167   1410       }
  1168   1411       return ""
  1169   1412   }
  1170   1413   
  1171   1414   proc complete(fileevent) {text start end line pos mod} {
  1172   1415       switch -- $pos {
  1173   1416           1 {
  1174         -            return [ChannelId ${mod}]
         1417  +            return [ChannelId ${text}]
  1175   1418           }
  1176   1419           2 {
  1177         -            return [MenuFromList ${mod} {readable writable}]
         1420  +            return [CompleteFromList ${text} {readable writable}]
         1421  +        }
         1422  +        3 {
         1423  +            return [DisplayHints ?script?]
  1178   1424           }
  1179   1425       }
  1180   1426       return ""
  1181   1427   }
  1182   1428   
  1183   1429   proc complete(flush) {text start end line pos mod} {
  1184   1430       switch -- $pos {
  1185         -        1 { return [ChannelId ${mod}] }
         1431  +        1 { return [OutChannelId ${text}] }
         1432  +    }
         1433  +    return ""
         1434  +}
         1435  +
         1436  +proc complete(for) {text start end line pos mod} {
         1437  +    switch -- $pos {
         1438  +        1 -
         1439  +        2 -
         1440  +        3 -
         1441  +        4 {
         1442  +            return [BraceOrControlStatement $text $start $end $line $pos $mod]
         1443  +        }
         1444  +    }
         1445  +    return ""
         1446  +}
         1447  +
         1448  +proc complete(foreach) {text start end line pos mod} {
         1449  +    switch -- $pos {
         1450  +        1 { return [DisplayHints <varname>] }
         1451  +        2 { return [DisplayHints <list>] }
         1452  +        default {
         1453  +            if {[expr $pos % 2]} {
         1454  +                return [DisplayHints [list ?varname? <body>]]
         1455  +            } else {
         1456  +                return [DisplayHints ?list?]
         1457  +            }
         1458  +        }
         1459  +    }
         1460  +    return ""
         1461  +}
         1462  +
         1463  +proc complete(format) {text start end line pos mod} {
         1464  +    switch -- $pos {
         1465  +        1 { return [DisplayHints <formatString>] }
         1466  +        default { return [DisplayHints ?arg?] }
  1186   1467       }
  1187   1468       return ""
  1188   1469   }
  1189   1470   
  1190   1471   proc complete(gets) {text start end line pos mod} {
  1191   1472       switch -- $pos {
  1192         -        1 { return [InChannelId ${mod}] }
         1473  +        1 { return [InChannelId ${text}] }
         1474  +        2 { return [VarCompletion ${text}]}
  1193   1475       }
  1194   1476       return ""
  1195   1477   }
  1196   1478   
  1197   1479   proc complete(glob) {text start end line pos mod} {
  1198   1480       switch -- $pos {
  1199   1481           1 {
  1200         -            set matches [TryFromList ${mod} {-nocomplain --}]
  1201         -            if {[llength [string trim ${mod}]] && [llength ${matches}]} {
         1482  +            # This also is not perfect.
         1483  +            # This will not display the options as hints!
         1484  +            set matches [TryFromList ${text} {-nocomplain --}]
         1485  +            if {[llength [string trim ${text}]] && [llength ${matches}]} {
  1202   1486                   return ${matches}
  1203   1487               }
  1204   1488           }
  1205   1489       }
  1206   1490       return ""
  1207   1491   }
  1208   1492   
  1209   1493   proc complete(global) {text start end line pos mod} {
  1210   1494       return [VarCompletion ${text}]
  1211   1495   }
  1212   1496   
  1213         -proc complete(index) {text start end line pos mod} {
  1214         -    if {1 == $pos} {
  1215         -        return [VarCompletion ${text}]
  1216         -    } elseif {2 == $pos && ![llength ${mod}]} {
  1217         -        return <index>
         1497  +proc complete(history) {text start end line pos mod} {
         1498  +    switch -- $pos {
         1499  +        1 {
         1500  +            set cmds {add change clear event info keep nextid redo}
         1501  +            return [TryFromList $text $cmds]
         1502  +        }
         1503  +        2 {
         1504  +            set cmd [Lindex $line 1]
         1505  +            switch -- $cmd {
         1506  +                add { return [DisplayHints <command>] }
         1507  +                change { return [DisplayHints <newValue>] }
         1508  +
         1509  +                info -
         1510  +                keep { return [DisplayHints ?count?] }
         1511  +
         1512  +                event -
         1513  +                redo { return [DisplayHints ?event?] }
         1514  +
         1515  +                clear -
         1516  +                nextid { return "" }
         1517  +            }
         1518  +        }
         1519  +    }
         1520  +    return ""
         1521  +}
         1522  +
         1523  +# --- HTTP PACKAGE ---
         1524  +
         1525  +# create a http namespace inside
         1526  +# tclreadline and import some commands.
         1527  +#
         1528  +namespace eval http {
         1529  +    catch {
         1530  +        namespace import \
         1531  +        ::tclreadline::DisplayHints ::tclreadline::PreviousWord \
         1532  +        ::tclreadline::CompleteFromList ::tclreadline::CommandCompletion \
         1533  +        ::tclreadline::RemoveUsedOptions ::tclreadline::HostList \
         1534  +        ::tclreadline::ChannelId ::tclreadline::Lindex \
         1535  +        ::tclreadline::CompleteBoolean
         1536  +    }
         1537  +}
         1538  +
         1539  +proc http::complete(config) {text start end line pos mod} {
         1540  +    set prev [PreviousWord ${start} ${line}]
         1541  +    switch -- $prev {
         1542  +        -accept { return [DisplayHints <mimetypes>] }
         1543  +        -proxyhost {
         1544  +            return [CompleteFromList $text [HostList]]
         1545  +        }
         1546  +        -proxyport { return [DisplayHints <number>] }
         1547  +        -proxyfilter {
         1548  +            return [CompleteFromList $text [CommandCompletion $text]]
         1549  +        }
         1550  +        -useragent { return [DisplayHints <string>] }
         1551  +        default {
         1552  +            return [CompleteFromList $text [RemoveUsedOptions $line {
         1553  +                -accept -proxyhost -proxyport -proxyfilter -useragent
         1554  +            }]]
         1555  +        }
         1556  +    }
         1557  +    return ""
         1558  +}
         1559  +
         1560  +proc http::complete(geturl) {text start end line pos mod} {
         1561  +    switch -- $pos {
         1562  +        1 { return [DisplayHints <url>] }
         1563  +        default {
         1564  +            set prev [PreviousWord ${start} ${line}]
         1565  +            switch -- $prev {
         1566  +                -blocksize { return [DisplayHints <size>] }
         1567  +                -channel { return [ChannelId ${text}] }
         1568  +                -command -
         1569  +                -handler -
         1570  +                -progress {
         1571  +                    return [CompleteFromList $text [CommandCompletion $text]]
         1572  +                }
         1573  +                -headers { return [DisplayHints <keyvaluelist>] }
         1574  +                -query { return [DisplayHints <query>] }
         1575  +                -timeout { return [DisplayHints <milliseconds>] }
         1576  +                -validate { return [CompleteBoolean $text] }
         1577  +                default {
         1578  +                    return [CompleteFromList $text [RemoveUsedOptions $line {
         1579  +                        -blocksize -channel -command -handler -headers
         1580  +                        -progress -query -timeout -validate
         1581  +                    }]]
         1582  +                }
         1583  +            }
         1584  +        }
         1585  +    }
         1586  +    return ""
         1587  +}
         1588  +
         1589  +proc http::complete(formatQuery) {text start end line pos mod} {
         1590  +    switch -- $pos {
         1591  +        1 { return [DisplayHints <key>] }
         1592  +        2 { return [DisplayHints <value>] }
         1593  +        default {
         1594  +            switch [expr $pos % 2] {
         1595  +                0 { return [DisplayHints ?value?] }
         1596  +                1 { return [DisplayHints ?key?] }
         1597  +            }
         1598  +        }
         1599  +    }
         1600  +    return ""
         1601  +}
         1602  +
         1603  +proc http::complete(reset) {text start end line pos mod} {
         1604  +    switch -- $pos {
         1605  +        1 { return [DisplayHints <token>] }
         1606  +        2 { return [DisplayHints ?why?] }
         1607  +    }
         1608  +    return ""
         1609  +}
         1610  +
         1611  +# the unknown proc handles the rest
         1612  +#
         1613  +proc \
         1614  +http::complete(tclreadline_complete_unknown) {text start end line pos mod} {
         1615  +    set cmd [Lindex $line 0]
         1616  +    regsub -all {^.*::} $cmd "" cmd
         1617  +    switch -- $pos {
         1618  +        1 {
         1619  +            switch -- $cmd {
         1620  +                reset -
         1621  +                wait -
         1622  +                data -
         1623  +                status -
         1624  +                code -
         1625  +                size -
         1626  +                cleanup {
         1627  +                    return [DisplayHints <token>]
         1628  +                }
         1629  +            }
         1630  +        }
         1631  +    }
         1632  +    return ""
         1633  +}
         1634  +
         1635  +# --- END OF HTTP PACKAGE ---
         1636  +
         1637  +proc complete(if) {text start end line pos mod} {
         1638  +    # we don't offer the completion `then':
         1639  +    # it's optional, more difficult to parse
         1640  +    # and who uses it anyway?
         1641  +    #
         1642  +    switch -- $pos {
         1643  +        1 -
         1644  +        2 {
         1645  +            return [BraceOrControlStatement $text $start $end $line $pos $mod]
         1646  +        }
         1647  +        default {
         1648  +            set prev [PreviousWord ${start} ${line}]
         1649  +            switch -- $prev {
         1650  +                then -
         1651  +                else -
         1652  +                elseif {
         1653  +                    return [BraceOrControlStatement \
         1654  +                    $text $start $end $line $pos $mod]
         1655  +                }
         1656  +                default {
         1657  +                    if {-1 == [lsearch [ProperList $line] else]} {
         1658  +                        return [CompleteFromList $text {else elseif}]
         1659  +                    }
         1660  +                }
         1661  +            }
         1662  +        }
         1663  +    }
         1664  +    return ""
         1665  +}
         1666  +
         1667  +proc complete(incr) {text start end line pos mod} {
         1668  +    switch -- $pos {
         1669  +        1 {
         1670  +            set matches [uplevel [info level] info vars ${mod}*]
         1671  +            set integers ""
         1672  +            # check for integers
         1673  +            #
         1674  +            foreach match $matches {
         1675  +                if {[uplevel [info level] array exists $match]} {
         1676  +                    continue
         1677  +                }
         1678  +                if {[regexp {^[0-9]+$} [uplevel [info level] set $match]]} {
         1679  +                    lappend integers $match
         1680  +                }
         1681  +            }
         1682  +            return [CompleteFromList ${text} ${integers}]
         1683  +        }
         1684  +        2 { return [DisplayHints ?increment?] }
  1218   1685       }
  1219   1686       return ""
  1220   1687   }
  1221   1688   
  1222   1689   proc complete(info) {text start end line pos mod} {
  1223         -    if {1 == $pos} {
  1224         -        set cmds {
  1225         -            args body cmdcount commands complete default exists
  1226         -            globals hostname level library loaded locals nameofexecutable
  1227         -            patchlevel procs script sharedlibextension tclversion vars}
  1228         -        return [TryFromList $text $cmds]
  1229         -    } elseif {2 == $pos} {
  1230         -        set cmd [lindex $line 1]
  1231         -        switch -- $cmd {
  1232         -            args -
  1233         -            body -
  1234         -            default -
  1235         -            procs { return [complete(proc) ${text} 0 0 ${line} 1 ${mod}] }
  1236         -            complete { ; # TODO
  1237         -            }
  1238         -            level { ; # TODO
  1239         -            }
  1240         -            loaded { ;# TODO
  1241         -            }
  1242         -            commands -
  1243         -            exists -
  1244         -            globals -
  1245         -            locals -
  1246         -            vars {
  1247         -                if {"exists" == $cmd} {
  1248         -                    set do vars
  1249         -                } else {
  1250         -                    set do $cmd
  1251         -                }
  1252         -                # puts stderr [list complete(info) level = [info level]]
  1253         -                return \
  1254         -                [Format [uplevel 2 info ${do} "${mod}*"] $text]
         1690  +    set cmd [Lindex $line 1]
         1691  +    switch -- $pos {
         1692  +        1 {
         1693  +            set cmds {
         1694  +                args body cmdcount commands complete default exists
         1695  +                globals hostname level library loaded locals nameofexecutable
         1696  +                patchlevel procs script sharedlibextension tclversion vars}
         1697  +            return [CompleteFromList $text $cmds]
         1698  +        }
         1699  +        2 {
         1700  +            switch -- $cmd {
         1701  +                args -
         1702  +                body -
         1703  +                default -
         1704  +                procs { return [complete(proc) ${text} 0 0 ${line} 1 ${mod}] }
         1705  +                complete { return [DisplayHints <command>] }
         1706  +                level { return [DisplayHints ?number?] }
         1707  +                loaded { return [DisplayHints ?interp?] }
         1708  +                commands -
         1709  +                exists -
         1710  +                globals -
         1711  +                locals -
         1712  +                vars {
         1713  +                    if {"exists" == $cmd} {
         1714  +                        set do vars
         1715  +                    } else {
         1716  +                        set do $cmd
         1717  +                    }
         1718  +                    # puts stderr [list complete(info) level = [info level]]
         1719  +                    return \
         1720  +                    [CompleteFromList ${text} [uplevel [info level] info ${do}]]
         1721  +                }
         1722  +            }
         1723  +        }
         1724  +        3 {
         1725  +            switch -- $cmd {
         1726  +                default {
         1727  +                    set proc [Lindex $line 2]
         1728  +                    return [CompleteFromList ${text} \
         1729  +                    [uplevel [info level] info args $proc]]
         1730  +                }
         1731  +                default {}
         1732  +            }
         1733  +        }
         1734  +        4 {
         1735  +            switch -- $cmd {
         1736  +                default {
         1737  +                    return [VarCompletion ${text}]
         1738  +                }
         1739  +                default {}
  1255   1740               }
  1256   1741           }
  1257   1742       }
  1258   1743       return ""
  1259   1744   }
  1260   1745   
  1261   1746   proc complete(interp) {text start end line pos mod} {
  1262         -    set cmd [lindex $line 1]
  1263         -    if {1 == $pos} {
  1264         -        set cmds {
  1265         -            alias aliases create delete eval exists expose hide hidden
  1266         -            issafe invokehidden marktrusted slaves share target transfer}
  1267         -        return [TryFromList $text $cmds]
  1268         -    } elseif {2 == $pos} {
  1269         -        switch -- $cmd {
  1270         -            create {
  1271         -                return [TryFromList $text {-safe -- ?path?}]
  1272         -            }
  1273         -
  1274         -            eval -
  1275         -            exists -
  1276         -            expose -
  1277         -            hide -
  1278         -            hidden -
  1279         -            invokehidden -
  1280         -            marktrusted -
  1281         -            target {if {![llength ${mod}]} { return <path> }}
  1282         -
  1283         -            aliases -
  1284         -            delete -
  1285         -            issafe -
  1286         -            slaves {if {![llength ${mod}]} { return ?path? }}
  1287         -
  1288         -            alias -
  1289         -            share -
  1290         -            transfer {if {![llength ${mod}]} { return <srcPath> }}
  1291         -        }
  1292         -    } elseif {3 == $pos} {
  1293         -        switch -- $cmd {
  1294         -
  1295         -            alias {if {![llength ${mod}]} { return <srcCmd> }}
  1296         -
  1297         -            create {
  1298         -                return [TryFromList $text {-safe -- ?path?}]
  1299         -            }
  1300         -
  1301         -            eval {if {![llength ${mod}]} { return <arg> }}
  1302         -            delete {if {![llength ${mod}]} { return ?path? }}
  1303         -
  1304         -            expose {if {![llength ${mod}]} { return <hiddenName> }}
  1305         -            hide {if {![llength ${mod}]} { return <exposedCmdName> }}
  1306         -
  1307         -            invokehidden {
  1308         -                return \
  1309         -                [TryFromList $text {?-global? <hiddenCmdName}]
  1310         -            }
  1311         -
  1312         -            target {if {![llength ${mod}]} { return <alias> }}
  1313         -
  1314         -            exists {}
  1315         -            hidden {}
  1316         -            marktrusted {}
  1317         -            aliases {}
  1318         -            issafe {}
  1319         -            slaves {}
  1320         -
  1321         -            share -
  1322         -            tranfer {return [ChannelId ${mod}]}
  1323         -        }
  1324         -    } elseif {4 == $pos} {
  1325         -        switch -- $cmd {
  1326         -
  1327         -            alias {if {![llength ${mod}]} { return <targetPath> }}
  1328         -
  1329         -            create {
  1330         -                return [TryFromList $text {-safe -- path}]
  1331         -            }
  1332         -
  1333         -            expose {if {![llength ${mod}]} { return ?exposedCmdName? }}
  1334         -            hide {if {![llength ${mod}]} { return ?hiddenCmdName? }}
  1335         -
  1336         -            share -
  1337         -            tranfer {if {![llength ${mod}]} { return ?destPath? }}
         1747  +    set cmd [Lindex $line 1]
         1748  +    switch -- $pos {
         1749  +        1 {
         1750  +            set cmds {
         1751  +                alias aliases create delete eval exists expose hide hidden
         1752  +                invokehidden issafe marktrusted share slaves target transfer}
         1753  +            return [TryFromList $text $cmds]
         1754  +        }
         1755  +        2 {
         1756  +            switch -- $cmd {
         1757  +
         1758  +                create {
         1759  +                    set cmds [RemoveUsedOptions ${line} {-save --} {--}]
         1760  +                    if {[llength $cmds]} {
         1761  +                        return [CompleteFromList $text "$cmds ?path?"]
         1762  +                    } else {
         1763  +                        return [DisplayHints ?path?]
         1764  +                    }
         1765  +                }
         1766  +
         1767  +                eval -
         1768  +                exists -
         1769  +                expose -
         1770  +                hide -
         1771  +                hidden -
         1772  +                invokehidden -
         1773  +                marktrusted -
         1774  +                target { return [DisplayHints [interp slaves]] }
         1775  +
         1776  +                aliases -
         1777  +                delete -
         1778  +                issafe -
         1779  +                slaves { return [DisplayHints [interp slaves]] }
         1780  +
         1781  +                alias -
         1782  +                share -
         1783  +                transfer { return [DisplayHints <srcPath>] }
         1784  +            }
         1785  +        }
         1786  +        3 {
         1787  +            switch -- $cmd {
         1788  +
         1789  +                alias { return [DisplayHints <srcCmd>] }
         1790  +
         1791  +                create {
         1792  +                    set cmds [RemoveUsedOptions ${line} {-save --} {--}]
         1793  +                    if {[llength $cmds]} {
         1794  +                        return [CompleteFromList $text "$cmds ?path?"]
         1795  +                    } else {
         1796  +                        return [DisplayHints ?path?]
         1797  +                    }
         1798  +                }
         1799  +
         1800  +                eval { return [DisplayHints <arg>] }
         1801  +                delete { return [DisplayHints [interp slaves]] }
         1802  +
         1803  +                expose { return [DisplayHints <hiddenName>] }
         1804  +                hide { return [DisplayHints <exposedCmdName>] }
         1805  +
         1806  +                invokehidden {
         1807  +                    return \
         1808  +                    [CompleteFromList $text {?-global? <hiddenCmdName>}]
         1809  +                }
         1810  +
         1811  +                target { return [DisplayHints <alias>] }
         1812  +
         1813  +                exists {}
         1814  +                hidden {}
         1815  +                marktrusted {}
         1816  +                aliases {}
         1817  +                issafe {}
         1818  +                slaves {}
         1819  +
         1820  +                share -
         1821  +                transfer {return [ChannelId ${text}]}
         1822  +            }
         1823  +        }
         1824  +        4 {
         1825  +            switch -- $cmd {
         1826  +
         1827  +                alias { return [DisplayHints <targetPath>] }
         1828  +                eval { return [DisplayHints ?arg?] }
         1829  +
         1830  +                invokehidden {
         1831  +                    return [CompleteFromList $text {<hiddenCmdName> ?arg?}]
         1832  +                }
         1833  +
         1834  +                create {
         1835  +                    set cmds [RemoveUsedOptions ${line} {-save --} {--}]
         1836  +                    if {[llength $cmds]} {
         1837  +                        return [CompleteFromList $text "$cmds ?path?"]
         1838  +                    } else {
         1839  +                        return [DisplayHints ?path?]
         1840  +                    }
         1841  +                }
         1842  +
         1843  +                expose { return [DisplayHints ?exposedCmdName?] }
         1844  +                hide { return [DisplayHints ?hiddenCmdName?] }
         1845  +
         1846  +                share -
         1847  +                transfer { return [DisplayHints [interp slaves]] }
         1848  +            }
         1849  +        }
         1850  +        5 {
         1851  +            switch -- $cmd {
         1852  +
         1853  +                alias { return [DisplayHints <targetCmd>] }
         1854  +                invokehidden -
         1855  +                eval { return [DisplayHints ?arg?] }
         1856  +
         1857  +                expose { return [DisplayHints ?exposedCmdName?] }
         1858  +                hide { return [DisplayHints ?hiddenCmdName?] }
         1859  +
         1860  +                share -
         1861  +                transfer { return [DisplayHints [interp slaves]] }
         1862  +            }
  1338   1863           }
  1339   1864       }
  1340   1865       return ""
  1341   1866   }
  1342   1867   
  1343   1868   proc complete(join) {text start end line pos mod} {
  1344         -    if {1 == $pos} {
  1345         -        return [VarCompletion ${text}]
         1869  +    switch -- $pos {
         1870  +        1 { return [DisplayHints <list>] }
         1871  +        2 { return [DisplayHints ?joinString?] }
  1346   1872       }
  1347   1873       return ""
  1348   1874   }
  1349   1875   
  1350   1876   proc complete(lappend) {text start end line pos mod} {
  1351         -    if {1 == $pos} {
  1352         -        return [ListCompletion ${text}]
         1877  +    switch -- $pos {
         1878  +        1 { return [VarCompletion ${text}] }
         1879  +        default { return [DisplayHints ?value?] }
         1880  +    }
         1881  +    return ""
         1882  +}
         1883  +
         1884  +# the following routines are described in the
         1885  +# `library' man page.
         1886  +# --- LIBRARY ---
         1887  +
         1888  +proc complete(auto_execok) {text start end line pos mod} {
         1889  +    switch -- $pos {
         1890  +        1 { return [DisplayHints <cmd>] }
         1891  +    }
         1892  +    return ""
         1893  +}
         1894  +
         1895  +proc complete(auto_load) {text start end line pos mod} {
         1896  +    switch -- $pos {
         1897  +        1 { return [DisplayHints <cmd>] }
         1898  +    }
         1899  +    return ""
         1900  +}
         1901  +
         1902  +proc complete(auto_mkindex) {text start end line pos mod} {
         1903  +    switch -- $pos {
         1904  +        1 { return "" }
         1905  +        default { return [DisplayHints ?pattern?] }
         1906  +    }
         1907  +    return ""
         1908  +}
         1909  +
         1910  +# proc complete(auto_reset) {text start end line pos mod} {
         1911  +# }
         1912  +
         1913  +proc complete(tcl_findLibrary) {text start end line pos mod} {
         1914  +    switch -- $pos {
         1915  +        1 { return [DisplayHints <basename>] }
         1916  +        2 { return [DisplayHints <version>] }
         1917  +        3 { return [DisplayHints <patch>] }
         1918  +        4 { return [DisplayHints <initScript>] }
         1919  +        5 { return [DisplayHints <enVarName>] }
         1920  +        6 { return [DisplayHints <varName>] }
         1921  +    }
         1922  +    return ""
         1923  +}
         1924  +
         1925  +proc complete(parray) {text start end line pos mod} {
         1926  +    switch -- $pos {
         1927  +        1 {
         1928  +            set vars [uplevel [info level] info vars]
         1929  +            foreach var ${vars} {
         1930  +                if {[uplevel [info level] array exists ${var}]} {
         1931  +                    lappend matches ${var}
         1932  +                }
         1933  +            }
         1934  +            return [CompleteFromList $text $matches]
         1935  +        }
         1936  +    }
         1937  +    return ""
         1938  +}
         1939  +
         1940  +proc complete(tcl_endOfWord) {text start end line pos mod} {
         1941  +    switch -- $pos {
         1942  +        1 { return [DisplayHints <str>] }
         1943  +        2 { return [DisplayHints <start>] }
         1944  +    }
         1945  +    return ""
         1946  +}
         1947  +
         1948  +proc complete(tcl_startOfNextWord) {text start end line pos mod} {
         1949  +    return [complete(tcl_endOfWord) $text $start $end $line $pos $mod]
         1950  +}
         1951  +
         1952  +proc complete(tcl_startOfPreviousWord) {text start end line pos mod} {
         1953  +    return [complete(tcl_endOfWord) $text $start $end $line $pos $mod]
         1954  +}
         1955  +
         1956  +proc complete(tcl_wordBreakAfter) {text start end line pos mod} {
         1957  +    return [complete(tcl_endOfWord) $text $start $end $line $pos $mod]
         1958  +}
         1959  +
         1960  +proc complete(tcl_wordBreakBefore) {text start end line pos mod} {
         1961  +    return [complete(tcl_endOfWord) $text $start $end $line $pos $mod]
         1962  +}
         1963  +
         1964  +# --- END OF `LIBRARY' ---
         1965  +
         1966  +proc complete(lindex) {text start end line pos mod} {
         1967  +    switch -- $pos {
         1968  +        1 { return [DisplayHints <list>] }
         1969  +        2 { return [DisplayHints <index>] }
  1353   1970       }
  1354   1971       return ""
  1355   1972   }
  1356   1973   
  1357   1974   proc complete(linsert) {text start end line pos mod} {
  1358         -    if {1 == $pos} {
  1359         -        return [ListCompletion ${text}]
         1975  +    switch -- $pos {
         1976  +        1 { return [DisplayHints <list>] }
         1977  +        2 { return [DisplayHints <index>] }
         1978  +        3 { return [DisplayHints <element>] }
         1979  +        default { return [DisplayHints ?element?] }
  1360   1980       }
  1361   1981       return ""
  1362   1982   }
         1983  +
         1984  +proc complete(list) {text start end line pos mod} {
         1985  +    return [DisplayHints ?arg?]
         1986  +}
  1363   1987   
  1364   1988   proc complete(llength) {text start end line pos mod} {
  1365         -    if {1 == $pos} {
  1366         -        return [ListCompletion ${text}]
         1989  +    switch -- $pos {
         1990  +        1 {
         1991  +            return [DisplayHints <list>]
         1992  +        }
  1367   1993       }
  1368   1994       return ""
  1369   1995   }
  1370   1996   
  1371   1997   proc complete(load) {text start end line pos mod} {
  1372         -    if {1 == $pos} {
  1373         -        return ""; # filename
  1374         -    } elseif {2 == $pos && ![llength ${mod}]} {
  1375         -        return "<packageName>"
  1376         -    } elseif {3 == $pos && ![llength ${mod}]} {
  1377         -        return "<interp>"
         1998  +    switch -- $pos {
         1999  +        1 {
         2000  +            return ""; # filename
         2001  +        }
         2002  +        2 {
         2003  +            if {![llength ${mod}]} {
         2004  +                return [DisplayHints ?packageName?]
         2005  +            }
         2006  +        }
         2007  +        3 {
         2008  +            if {![llength ${mod}]} {
         2009  +                return [DisplayHints ?interp?]
         2010  +            }
         2011  +        }
  1378   2012       }
  1379   2013       return ""
  1380   2014   }
  1381   2015   
  1382   2016   proc complete(lrange) {text start end line pos mod} {
  1383         -    if {1 == $pos} {
  1384         -        return [ListCompletion ${text}]
  1385         -    } elseif {2 == $pos && ![llength ${mod}]} {
  1386         -        return "<first>"
  1387         -    } elseif {3 == $pos && ![llength ${mod}]} {
  1388         -        return "<last>"
         2017  +    switch -- $pos {
         2018  +        1 { return [DisplayHints <list>] }
         2019  +        2 { return [DisplayHints <first>] }
         2020  +        3 { return [DisplayHints <last>] }
  1389   2021       }
  1390   2022       return ""
  1391   2023   }
  1392   2024   
  1393   2025   proc complete(lreplace) {text start end line pos mod} {
  1394         -    if {1 == $pos} {
  1395         -        return [ListCompletion ${text}]
  1396         -    } elseif {2 == $pos && ![llength ${mod}]} {
  1397         -        return "<first>"
  1398         -    } elseif {3 == $pos && ![llength ${mod}]} {
  1399         -        return "<last>"
  1400         -    } elseif {![llength ${mod}]} {
  1401         -        return "?element?"
         2026  +    switch -- $pos {
         2027  +        1 { return [DisplayHints <list>] }
         2028  +        2 { return [DisplayHints <first>] }
         2029  +        3 { return [DisplayHints <last>] }
         2030  +        default { return [DisplayHints ?element?] }
  1402   2031       }
  1403   2032       return ""
  1404   2033   }
  1405   2034   
  1406   2035   proc complete(lsearch) {text start end line pos mod} {
  1407         -    if {1 == $pos} {
  1408         -        set options [MenuFromList ${mod} {
  1409         -            -exact -glob -regexp <list>}]
  1410         -        set matches [ListCompletion ${text}]
  1411         -        return [string trim "${matches} ${options}"]
  1412         -    } else {
  1413         -        if {![llength ${mod}]} {
  1414         -            set opt [lindex ${line} 1]
  1415         -            if {[llength [MenuFromList ${opt} {
  1416         -                -exact -glob -regexp }]]} {
         2036  +    set options {-exact -glob -regexp}
         2037  +    switch -- $pos {
         2038  +        1 {
         2039  +            return [CompleteFromList ${text} "$options <list>"]
         2040  +        }
         2041  +        2 -
         2042  +        3 -
         2043  +        4 {
         2044  +            set sub [Lindex $line 1]
         2045  +            if {-1 != [lsearch $options $sub]} {
  1417   2046                   incr pos -1
  1418   2047               }
  1419         -            if {1 == $pos} {
  1420         -                return <list>
  1421         -            } elseif {2 == $pos} {
  1422         -                return <pattern>
         2048  +            switch -- $pos {
         2049  +                1 { return [DisplayHints <list>] }
         2050  +                2 { return [DisplayHints <pattern>] }
  1423   2051               }
  1424   2052           }
  1425   2053       }
  1426   2054       return ""
  1427   2055   }
  1428   2056   
  1429   2057   proc complete(lsort) {text start end line pos mod} {
  1430         -    set options [DisplayHints ${mod} {
         2058  +    set options [RemoveUsedOptions ${line} {
  1431   2059           -ascii -dictionary -integer -real -command
  1432         -        -increasing -decreasing -index
         2060  +        -increasing -decreasing -index <list>
  1433   2061       }]
  1434         -    set matches [ListCompletion ${text}]
  1435         -    return [string trim "${matches} ${options}"]
  1436         -}
  1437         -
  1438         -proc complete(history) {text start end line pos mod} {
  1439         -    if {1 == $pos} {
  1440         -        set cmds {add change clear event info keep nextid redo}
  1441         -        return [TryFromList $text $cmds]
  1442         -    } elseif {2 == ${pos}} {
  1443         -        set cmd [lindex $line 1]
  1444         -        switch -- $cmd {
  1445         -            add { if {![llength ${mod}]} { return <newValue> } }
  1446         -            change { if {![llength ${mod}]} { return <newValue> } }
  1447         -
  1448         -            info -
  1449         -            keep { if {![llength ${mod}]} { return ?count? } }
  1450         -
  1451         -            event -
  1452         -            redo { if {![llength ${mod}]} { return ?event? } }
  1453         -
  1454         -            clear -
  1455         -            nextid { return "" }
  1456         -        }
  1457         -    }
  1458         -    return ""
  1459         -}
  1460         -
  1461         -proc complete(namespace) {text start end line pos mod} {
  1462         -    regsub {^([^:])} ${mod} {::\1} mod
         2062  +    switch -- $pos {
         2063  +        1 { return [CompleteFromList ${text} ${options}] }
         2064  +        default {
         2065  +            switch -- [PreviousWord ${start} ${line}] {
         2066  +                -command {
         2067  +                    return [CompleteFromList $text [CommandCompletion $text]]
         2068  +                }
         2069  +                -index { return [DisplayHints <index>] }
         2070  +                default { return [CompleteFromList ${text} ${options}] }
         2071  +            }
         2072  +        }
         2073  +    }
         2074  +    return ""
         2075  +}
         2076  +
         2077  +# --- MSGCAT PACKAGE ---
         2078  +
         2079  +# create a msgcat namespace inside
         2080  +# tclreadline and import some commands.
         2081  +#
         2082  +namespace eval msgcat {
         2083  +    catch {namespace import ::tclreadline::DisplayHints}
         2084  +}
         2085  +
         2086  +proc msgcat::complete(mc) {text start end line pos mod} {
         2087  +    switch -- $pos {
         2088  +        1 { return [DisplayHints <src-string>] }
         2089  +    }
         2090  +    return ""
         2091  +}
         2092  +
         2093  +proc msgcat::complete(mclocale) {text start end line pos mod} {
         2094  +    switch -- $pos {
         2095  +        1 { return [DisplayHints ?newLocale?] }
         2096  +    }
         2097  +    return ""
         2098  +}
         2099  +
         2100  +# proc msgcat::complete(mcpreferences) {text start end line pos mod} {
         2101  +# }
         2102  +
         2103  +proc msgcat::complete(mcload) {text start end line pos mod} {
         2104  +    switch -- $pos {
         2105  +        1 { return [DisplayHints <dirname>] }
         2106  +    }
         2107  +    return ""
         2108  +}
         2109  +
         2110  +proc msgcat::complete(mcset) {text start end line pos mod} {
         2111  +    switch -- $pos {
         2112  +        1 { return [DisplayHints <locale>] }
         2113  +        2 { return [DisplayHints <src-string>] }
         2114  +        3 { return [DisplayHints ?translate-string?] }
         2115  +    }
         2116  +    return ""
         2117  +}
         2118  +
         2119  +proc msgcat::complete(mcunknown) {text start end line pos mod} {
         2120  +    switch -- $pos {
         2121  +        1 { return [DisplayHints <locale>] }
         2122  +        2 { return [DisplayHints <src-string>] }
         2123  +    }
         2124  +    return ""
         2125  +}
         2126  +
         2127  +# --- END OF MSGCAT PACKAGE ---
         2128  +
         2129  +# TODO import ! -force
         2130  +proc complete(namespace) {text start end line pos mod} {
  1463   2131       # TODO dosn't work ???
  1464   2132       set space_matches [namespace children :: [string trim ${mod}*]]
  1465   2133       # puts \nspace_matches=|${space_matches}|
  1466         -    set cmd [lindex $line 1]
  1467         -    if {1 == $pos} {
  1468         -        set cmds {
  1469         -            children code current delete eval export forget
  1470         -            import inscope origin parent qualifiers tail which}
  1471         -        return [TryFromList $text $cmds]
  1472         -    } elseif {2 == $pos} {
  1473         -        switch -- $cmd {
  1474         -            children -
  1475         -            delete -
  1476         -            eval -
  1477         -            inscope -
  1478         -            forget -
  1479         -            parent { return [TryFromList ${mod} $space_matches] }
  1480         -            code { return "" }
  1481         -            current {}
  1482         -            export { return [MenuFromList ${mod} {-clear ?pattern?}] }
  1483         -            import {
  1484         -                return [MenuFromList ${mod} {-force $space_matches}]
  1485         -            }
  1486         -            origin { if {![llength ${mod}]} { return <command> } }
  1487         -            qualifiers -
  1488         -            tail { if {![llength ${mod}]} { return <string> } }
  1489         -            which { return [MenuFromList ${mod} {
  1490         -                -command -variable <name>}] }
  1491         -        }
  1492         -     #      forget { if {![llength ${mod}]} { return ?pattern? } }
  1493         -    } elseif {3 == $pos && "inscope" == $cmd} {
  1494         -            if {![llength ${mod}]} { return arg }
  1495         -    } else {
  1496         -        switch -- $cmd {
  1497         -            children { if {![llength ${mod}]} { return ?pattern? } }
  1498         -            delete { return [TryFromList $text $space_matches] }
  1499         -            eval { if {![llength ${mod}]} { return ?arg? } }
  1500         -            inscope { if {![llength ${mod}]} { return ?arg? } }
  1501         -            parent {}
  1502         -            code {}
  1503         -            current {}
  1504         -            export -
  1505         -            forget -
  1506         -            import { return [DisplayHints ?pattern?] }
  1507         -            origin {}
  1508         -            qualifiers {}
  1509         -            tail {}
  1510         -            which { return [MenuFromList $text {
  1511         -                -command -variable <name>}] }
         2134  +    set cmd [Lindex $line 1]
         2135  +    switch -- $pos {
         2136  +        1 {
         2137  +            set cmds {
         2138  +                children code current delete eval export forget
         2139  +                import inscope origin parent qualifiers tail which}
         2140  +            return [TryFromList $text $cmds]
         2141  +        }
         2142  +        2 {
         2143  +            switch -- $cmd {
         2144  +                children -
         2145  +                delete -
         2146  +                eval -
         2147  +                inscope -
         2148  +                forget -
         2149  +                parent -
         2150  +                qualifiers -
         2151  +                tail {
         2152  +                    regsub {^([^:])} ${mod} {::\1} mod; # full qual. name
         2153  +                    return [TryFromList ${mod} $space_matches]
         2154  +                }
         2155  +                code { return [DisplayHints <script> ] }
         2156  +                current {}
         2157  +                export { return [CompleteFromList ${text} {-clear ?pattern?}] }
         2158  +                import {
         2159  +                    if {"-" != [string index ${mod} 0]} {
         2160  +                        regsub {^([^:])} ${mod} {::\1} mod; # full qual. name
         2161  +                    }
         2162  +                    return [CompleteFromList ${mod} "-force $space_matches"]
         2163  +                }
         2164  +                origin { return [DisplayHints <command>] }
         2165  +                # qualifiers -
         2166  +                # tail { return [DisplayHints <string>] }
         2167  +                which { return [CompleteFromList ${mod} {
         2168  +                    -command -variable <name>}] }
         2169  +            }
         2170  +        }
         2171  +        3 {
         2172  +            switch -- $cmd {
         2173  +                children -
         2174  +                export -
         2175  +                forget -
         2176  +                import { return [DisplayHints ?pattern?] }
         2177  +                delete { return [TryFromList ${mod} $space_matches] }
         2178  +                eval -
         2179  +                inscope { return [DisplayHints <arg>] }
         2180  +                which { return [CompleteFromList ${mod} {-variable <name>}] }
         2181  +            }
         2182  +        }
         2183  +        4 {
         2184  +            switch -- $cmd {
         2185  +                export -
         2186  +                forget -
         2187  +                import { return [DisplayHints ?pattern?] }
         2188  +                delete { return [TryFromList ${mod} $space_matches] }
         2189  +                eval -
         2190  +                inscope { return [DisplayHints ?arg?] }
         2191  +                which { return [CompleteFromList ${mod} {<name>}] }
         2192  +            }
  1512   2193           }
  1513   2194       }
  1514   2195       return ""
  1515   2196   }
  1516   2197   
  1517   2198   proc complete(open) {text start end line pos mod} {
  1518         -    if {![llength ${mod}]} {
  1519         -        if {2 == $pos} {
  1520         -            return ?access?
  1521         -        } elseif {3 == $pos} {
  1522         -            return ?permissions?
         2199  +        # 2 { return [DisplayHints ?access?] }
         2200  +    switch -- $pos {
         2201  +        2 {
         2202  +            set access {r r+ w w+ a a+ 
         2203  +                RDONLY WRONLY RDWR APPEND CREAT EXCL NOCTTY NONBLOCK TRUNC}
         2204  +            return [CompleteFromList ${text} $access]
  1523   2205           }
         2206  +        3 { return [DisplayHints ?permissions?] }
  1524   2207       }
  1525   2208       return ""
  1526   2209   }
  1527   2210   
  1528   2211   proc complete(package) {text start end line pos mod} {
  1529         -    set cmd [lindex $line 1]
  1530         -    if {1 == $pos} {
  1531         -        set cmds {
  1532         -            forget ifneeded names present provide require
  1533         -            unknown vcompare versions vsatisfies}
  1534         -        return [TryFromList $text $cmds]
  1535         -    } elseif {2 == $pos} {
  1536         -        switch -- $cmd {
  1537         -            forget -
  1538         -            ifneeded -
  1539         -            provide -
  1540         -            versions { return [MenuFromList ${mod} [package names]] }
  1541         -            present -
  1542         -            require {
  1543         -                return [MenuFromList ${mod} "-exact [package names]"] }
  1544         -            names {}
  1545         -            unknown { if {![llength ${mod}]} { return ?command? } }
  1546         -            vcompare -
  1547         -            vsatisfies { if {![llength ${mod}]} { return <version1> } }
  1548         -        }
  1549         -    } elseif {3 == $pos} {
  1550         -        switch -- $cmd {
  1551         -            forget {}
  1552         -            ifneeded { if {![llength ${mod}]} { return <version> } }
  1553         -            provide { if {![llength ${mod}]} { return ?version? } }
  1554         -            versions {}
  1555         -            present -
  1556         -            require {
  1557         -                set prev [PreviousWord ${start} ${line}]
  1558         -                if {[llength [MenuFromList ${prev} -exact]]} {
  1559         -                    return [MenuFromList ${mod} [package names]]
  1560         -                } elseif {![llength ${mod}]} {
  1561         -                    return ?version?
  1562         -                }
  1563         -            }
  1564         -            names {}
  1565         -            unknown {}
  1566         -            vcompare -
  1567         -            vsatisfies { if {![llength ${mod}]} { return <version2> } }
  1568         -        }
  1569         -    } 
  1570         -    return ""
         2212  +    set cmd [Lindex $line 1]
         2213  +    switch -- $pos {
         2214  +        1 {
         2215  +            set cmds {
         2216  +                forget ifneeded names present provide require
         2217  +                unknown vcompare versions vsatisfies}
         2218  +            return [TryFromList $text $cmds]
         2219  +        }
         2220  +        2 {
         2221  +            switch -- $cmd {
         2222  +                forget -
         2223  +                ifneeded -
         2224  +                provide -
         2225  +                versions { return [CompleteFromList ${mod} [package names]] }
         2226  +                present -
         2227  +                require {
         2228  +                    return [CompleteFromList ${mod} "-exact [package names]"] }
         2229  +                names {}
         2230  +                unknown { return [DisplayHints ?command?] }
         2231  +                vcompare -
         2232  +                vsatisfies { return [DisplayHints <version1>] }
         2233  +            }
         2234  +        }
         2235  +        3 {
         2236  +            switch -- $cmd {
         2237  +                forget {}
         2238  +                ifneeded { return [DisplayHints <version>] }
         2239  +                provide { return [DisplayHints ?version?] }
         2240  +                versions {}
         2241  +                present -
         2242  +                require {
         2243  +                    if {"-exact" == [PreviousWord ${start} ${line}]} {
         2244  +                        return [CompleteFromList ${mod} [package names]]
         2245  +                    } else {
         2246  +                        return [DisplayHints ?version?]
         2247  +                    }
         2248  +                }
         2249  +                names {}
         2250  +                unknown {}
         2251  +                vcompare -
         2252  +                vsatisfies { return [DisplayHints <version2>] }
         2253  +            }
         2254  +        }
         2255  +    }
         2256  +    return ""
         2257  +}
         2258  +
         2259  +proc complete(pid) {text start end line pos mod} {
         2260  +    switch -- $pos {
         2261  +        1 { return [ChannelId ${text}] }
         2262  +    }
  1571   2263   }
  1572   2264   
  1573   2265   proc complete(pkg_mkIndex) {text start end line pos mod} {
  1574   2266       set cmds [RemoveUsedOptions ${line} {-direct -load -verbose -- <dir>} {--}]
  1575         -    set res [string trim [MenuFromList $text $cmds]]
  1576         -    if {[regexp -- [PreviousWord ${start} ${line}] -load] \
  1577         -        && ![llength ${mod}]} {
  1578         -            return <pkgPat>
         2267  +    set res [string trim [TryFromList $text $cmds]]
         2268  +    set prev [PreviousWord ${start} ${line}]
         2269  +    if {"-load" == $prev} {
         2270  +        return [DisplayHints <pkgPat>]
         2271  +    } elseif {"--" == $prev} {
         2272  +        return [TryFromList ${text} <dir>]
  1579   2273       }
  1580         -    if {![llength [join ${res}]]} {
  1581         -        return ""
  1582         -    } else {
  1583         -        return ${res}
  1584         -    }
  1585         -    return ""
         2274  +    return ${res}
  1586   2275   }
  1587   2276   
  1588   2277   proc complete(proc) {text start end line pos mod} {
  1589         -    # puts known_procs=|${known_procs}|
  1590         -    if {1 == $pos} {
  1591         -        set known_procs [ProcsOnlyCompletion ${mod}]
  1592         -        set common [CompleteLongest ${known_procs}]
  1593         -        if {"" == ${common}} {
  1594         -            return [Format ${known_procs} ${text}]
  1595         -        } else {
  1596         -            return [string trim "${common} ${known_procs}"]
         2278  +    switch -- $pos {
         2279  +        1 {
         2280  +            set known_procs [ProcsOnlyCompletion ${text}]
         2281  +            return [CompleteFromList ${text} ${known_procs}]
  1597   2282           }
  1598         -    } elseif {2 == $pos} {
  1599         -        set proc [lindex $line 1]
  1600         -        if {[catch {set args [uplevel 2 info args ${proc}]}]} {
  1601         -            return ""
  1602         -        } else {
  1603         -            return [list "\{${args}\} \{"]
         2283  +        2 {
         2284  +            set proc [Lindex $line 1]
         2285  +            if {[catch {set args [uplevel [info level] info args ${proc}]}]} {
         2286  +                return [DisplayHints <args>]
         2287  +            } else {
         2288  +                return [list "\{${args}\}"]
         2289  +            }
         2290  +        }
         2291  +        3 {
         2292  +            if {![string length [Lindex $line $pos]]} {
         2293  +                return [list \{ {}]; # \}
         2294  +            } else {
         2295  +                return [DisplayHints <body>]
         2296  +            }
  1604   2297           }
  1605   2298       }
  1606   2299       return ""
  1607   2300   }
  1608   2301   
  1609   2302   proc complete(puts) {text start end line pos mod} {
  1610         -    if {1 == $pos} {
  1611         -        return [TryFromList ${mod} "-nonewline [OutChannelId ${mod}]"]
  1612         -    } elseif {2 <= $pos} {
  1613         -        if {![llength ${mod}]} {
  1614         -            set opt [lindex ${line} 1]
  1615         -            if {[llength [MenuFromList ${opt} {-nonewline}]]} {
  1616         -                incr pos -1
         2303  +    set cmd [Lindex $line 1]
         2304  +    switch -- $pos {
         2305  +        1 {
         2306  +            return [OutChannelId ${text} "-nonewline"]
         2307  +        }
         2308  +        2 {
         2309  +            switch -- $cmd {
         2310  +                -nonewline { return [OutChannelId ${text}] }
         2311  +                default { return [DisplayHints <string>] }
  1617   2312               }
  1618         -            if {1 == $pos} {
  1619         -                return [OutChannelId ${mod}]
  1620         -            } elseif {2 == $pos} {
  1621         -                return [DisplayHints <string>]
  1622         -                return <string>
         2313  +        }
         2314  +        3 {
         2315  +            switch -- $cmd {
         2316  +                -nonewline { return [DisplayHints <string>] }
  1623   2317               }
  1624   2318           }
  1625   2319       }
  1626   2320       return ""
  1627   2321   }
         2322  +
         2323  +# proc complete(pwd) {text start end line pos mod} {
         2324  +# }
  1628   2325   
  1629   2326   proc complete(read) {text start end line pos mod} {
  1630         -    if {1 == $pos} {
  1631         -        return [MenuFromList ${mod} {-nonewline [InChannelId ${mod}]}]
  1632         -    } elseif {2 == $pos} {
  1633         -        if {![llength ${mod}]} {
  1634         -            set opt [lindex ${line} 1]
  1635         -            if {[llength [MenuFromList ${opt} {-nonewline}]]} {
  1636         -                return [InChannelId ${mod}]
  1637         -            } elseif {![llength ${mod}]} {
  1638         -                return [DisplayHints <numBytes>]
         2327  +    set cmd [Lindex $line 1]
         2328  +    switch -- $pos {
         2329  +        1 {
         2330  +            return [InChannelId ${text} "-nonewline"]
         2331  +        }
         2332  +        2 {
         2333  +            switch -- $cmd {
         2334  +                -nonewline { return [InChannelId ${text}] }
         2335  +                default { return [DisplayHints <numChars>] }
  1639   2336               }
  1640   2337           }
  1641   2338       }
  1642   2339       return ""
  1643   2340   }
  1644   2341   
  1645   2342   proc complete(regexp) {text start end line pos mod} {
  1646   2343       set prev [PreviousWord ${start} ${line}]
  1647         -    if {[llength ${prev}] && ("-" == [string index ${prev} 0] || 1 == $pos)} {
         2344  +    if {[llength ${prev}] && "--" != $prev && \
         2345  +        ("-" == [string index ${prev} 0] || 1 == $pos)} {
  1648   2346           set cmds [RemoveUsedOptions ${line} {
  1649   2347               -nocase -indices -expanded -line 
  1650   2348               -linestop -lineanchor -about <expression> --} {--}]
  1651   2349           if {[llength ${cmds}]} {
  1652         -            return [string trim [MenuFromList $text $cmds]]
         2350  +            return [string trim [CompleteFromList $text $cmds]]
  1653   2351           }
  1654   2352       } else {
  1655   2353           set virtual_pos [expr ${pos} - [FirstNonOption ${line}]]
  1656   2354           switch -- ${virtual_pos} {
  1657         -            1 { if {![llength ${mod}]} { return <string> } }
  1658         -            2 { if {![llength ${mod}]} { return ?matchVar? } }
  1659         -            default { if {![llength ${mod}]} { return ?subMatchVar? } }
         2355  +            0 { return [DisplayHints <string>] }
         2356  +            1 { return [DisplayHints ?matchVar?] }
         2357  +            default { return [DisplayHints ?subMatchVar?] }
  1660   2358           }
  1661   2359       }
  1662   2360       return ""
  1663   2361   }
         2362  +
         2363  +# proc complete(regexp) {text start end line pos mod} {
         2364  +#     We're not on windoze here ...
         2365  +# }
  1664   2366   
  1665   2367   proc complete(regsub) {text start end line pos mod} {
  1666   2368       set prev [PreviousWord ${start} ${line}]
  1667         -    if {[llength ${prev}] && ("-" == [string index ${prev} 0] || 1 == $pos)} {
  1668         -        set cmds [RemoveUsedOptions ${line} {-all -nocase -- <expression>} {--}]
  1669         -        set res [string trim [MenuFromList ${mod} ${cmds}]]
  1670         -        if {[llength ${res}]} {
  1671         -            return ${res}
         2369  +    if {[llength ${prev}] && "--" != $prev && \
         2370  +        ("-" == [string index ${prev} 0] || 1 == $pos)} {
         2371  +        set cmds [RemoveUsedOptions ${line} {
         2372  +            -all -nocase --} {--}]
         2373  +        if {[llength ${cmds}]} {
         2374  +            return [string trim [CompleteFromList $text $cmds]]
  1672   2375           }
  1673   2376       } else {
  1674   2377           set virtual_pos [expr ${pos} - [FirstNonOption ${line}]]
  1675   2378           switch -- ${virtual_pos} {
  1676         -            1 { if {![llength ${mod}]} { return <expression> } }
  1677         -            2 { if {![llength ${mod}]} { return <string> } }
  1678         -            3 { if {![llength ${mod}]} { return <subSpec> } }
  1679         -            4 { if {![llength ${mod}]} { return <varName> } }
         2379  +            0 { return [DisplayHints <expression>] }
         2380  +            1 { return [DisplayHints <string>] }
         2381  +            2 { return [DisplayHints <subSpec>] }
         2382  +            3 { return [DisplayHints <varName>] }
  1680   2383           }
  1681   2384       }
  1682   2385       return ""
  1683   2386   }
  1684   2387   
  1685   2388   proc complete(rename) {text start end line pos mod} {
  1686         -    if {1 == $pos} {
  1687         -        # TODO set all [CommandCompletion ${mod}]
  1688         -        return [Format $all ${mod}]
  1689         -    } elseif {2 == $pos && ![llength ${mod}]} {
  1690         -        return <newName>
         2389  +    switch -- $pos {
         2390  +        1 {
         2391  +            return [CompleteFromList $text [CommandCompletion $text]]
         2392  +        }
         2393  +        2 {
         2394  +            return [DisplayHints <newName>]
         2395  +        }
  1691   2396       }
  1692   2397       return ""
  1693   2398   }
         2399  +
         2400  +# proc complete(resource) {text start end line pos mod} {
         2401  +#     This is not a mac ...
         2402  +# }
  1694   2403   
  1695   2404   proc complete(return) {text start end line pos mod} {
  1696   2405       # TODO this is not perfect yet
  1697         -    set cmds {-code -errorinfo -errorcode <string>}
  1698         -    set res [MenuFromList [PreviousWord ${start} ${line}] ${cmds}]
  1699         -    if {1 == [llength ${res}]} {
  1700         -        switch -- ${res} {
  1701         -            -errorinfo { if {![llength ${mod}]} { return <info> } }
  1702         -            -code -
  1703         -            -errorcode {
  1704         -                set codes {ok error return break continue}
  1705         -                return [TryFromList ${mod} ${codes}]
  1706         -            }
  1707         -        }
  1708         -    }
  1709         -    set cmds [RemoveUsedOptions ${line} ${cmds}]
  1710         -    set res [string trim [MenuFromList ${mod} ${cmds}]]
  1711         -    if {[llength ${res}]} {
  1712         -        return ${res}
         2406  +    set cmds {-code -errorinfo -errorcode ?string?}
         2407  +    set res [PreviousWord ${start} ${line}]
         2408  +    switch -- ${res} {
         2409  +        -errorinfo { return [DisplayHints <info>] }
         2410  +        -code -
         2411  +        -errorcode {
         2412  +            set codes {ok error return break continue}
         2413  +            return [TryFromList ${mod} ${codes}]
         2414  +        }
         2415  +    }
         2416  +    return [CompleteFromList ${text} [RemoveUsedOptions ${line} ${cmds}]]
         2417  +}
         2418  +
         2419  +# --- SAFE PACKAGE ---
         2420  +
         2421  +# create a safe namespace inside
         2422  +# tclreadline and import some commands.
         2423  +#
         2424  +namespace eval safe {
         2425  +    catch {
         2426  +        namespace import \
         2427  +        ::tclreadline::DisplayHints ::tclreadline::PreviousWord \
         2428  +        ::tclreadline::CompleteFromList ::tclreadline::CommandCompletion \
         2429  +        ::tclreadline::RemoveUsedOptions ::tclreadline::HostList \
         2430  +        ::tclreadline::ChannelId ::tclreadline::Lindex \
         2431  +        ::tclreadline::CompleteBoolean
         2432  +    }
         2433  +    variable opts
         2434  +    set opts {
         2435  +        -accessPath -statics -noStatics -nested -nestedLoadOk -deleteHook
         2436  +    }
         2437  +    proc SlaveOrOpts {text start line pos slave} {
         2438  +        set prev [PreviousWord ${start} ${line}]
         2439  +        variable opts
         2440  +        if {$pos > 1} {
         2441  +            set slave ""
         2442  +        }
         2443  +        switch -- $prev {
         2444  +            -accessPath { return [DisplayHints <directoryList>] }
         2445  +            -statics { return [CompleteBoolean $text] }
         2446  +            -nested { return [CompleteBoolean $text] }
         2447  +            -deleteHook { return [DisplayHints <script>] }
         2448  +            default {
         2449  +                return [CompleteFromList ${text} \
         2450  +                [RemoveUsedOptions ${line} "${opts} $slave"]]
         2451  +            }
         2452  +        }
         2453  +    }
         2454  +}
         2455  +
         2456  +proc safe::complete(interpCreate) {text start end line pos mod} {
         2457  +    return [SlaveOrOpts $text $start $line $pos ?slave?]
         2458  +}
         2459  +
         2460  +proc safe::complete(interpInit) {text start end line pos mod} {
         2461  +    return [SlaveOrOpts $text $start $line $pos [interp slaves]]
         2462  +}
         2463  +
         2464  +proc safe::complete(interpConfigure) {text start end line pos mod} {
         2465  +    return [SlaveOrOpts $text $start $line $pos [interp slaves]]
         2466  +}
         2467  +
         2468  +proc safe::complete(interpDelete) {text start end line pos mod} {
         2469  +    return [CompleteFromList $text [interp slaves]]
         2470  +}
         2471  +
         2472  +proc safe::complete(interpAddToAccessPath) {text start end line pos mod} {
         2473  +    switch -- $pos {
         2474  +        1 { return [CompleteFromList $text [interp slaves]] }
         2475  +    }
         2476  +}
         2477  +
         2478  +proc safe::complete(interpFindInAccessPath) {text start end line pos mod} {
         2479  +    switch -- $pos {
         2480  +        1 { return [CompleteFromList $text [interp slaves]] }
         2481  +    }
         2482  +}
         2483  +
         2484  +proc safe::complete(setLogCmd) {text start end line pos mod} {
         2485  +    switch -- $pos {
         2486  +        1 { return [DisplayHints ?cmd?] }
         2487  +        default { return [DisplayHints ?arg?] }
         2488  +    }
         2489  +}
         2490  +
         2491  +# --- END OF SAFE PACKAGE ---
         2492  +
         2493  +proc complete(scan) {text start end line pos mod} {
         2494  +    switch -- $pos {
         2495  +        1 { return [DisplayHints <string>] }
         2496  +        2 { return [DisplayHints <format>] }
         2497  +        default { return [VarCompletion ${text}] }
  1713   2498       }
  1714   2499       return ""
  1715   2500   }
  1716   2501   
  1717   2502   proc complete(seek) {text start end line pos mod} {
  1718         -    if {1 == $pos} {
  1719         -        return [ChannelId ${mod}]
  1720         -    } elseif {2 == $pos} {
  1721         -        return [TryFromList ${mod} {start current end}]
         2503  +    switch -- $pos {
         2504  +        1 { return [ChannelId ${text}] }
         2505  +        2 { return [DisplayHints <offset>] }
         2506  +        3 { return [TryFromList ${text} {start current end}] }
  1722   2507       }
  1723   2508       return ""
  1724   2509   }
  1725   2510   
  1726   2511   proc complete(set) {text start end line pos mod} {
  1727         -    # puts stderr "\ntext=|$text| $start $end\n"
  1728         -    # puts stderr \nline=|$line|\n
  1729         -    # puts stderr \npos=|$pos|\n
  1730         -    # puts stderr \nmod=|$mod|\n
  1731         -    if {1 == $pos} {
  1732         -        return [VarCompletion ${text}]
  1733         -    } elseif {2 == $pos && ($text == "" || $text == "\"" || $text == "\{")} {
  1734         -        set line [QuoteQuotes $line]
  1735         -        if {[catch "set value [list [uplevel [info level] set [lindex $line 1]]]" msg]} {
  1736         -            return ""
  1737         -        } else {
  1738         -            return [Quote $value ${text}]
         2512  +    switch -- $pos {
         2513  +        1 { return [VarCompletion ${text}] }
         2514  +        2 {
         2515  +            if {$text == "" || $text == "\"" || $text == "\{"} {
         2516  +                set line [QuoteQuotes $line]
         2517  +                if {[catch [list set value [list [uplevel [info level] \
         2518  +                    set [Lindex $line 1]]]] msg]
         2519  +                } {
         2520  +                    return ""
         2521  +                } else {
         2522  +                    return [Quote $value ${text}]
         2523  +                }
         2524  +            }
  1739   2525           }
  1740   2526       }
  1741   2527       return ""
  1742   2528   }
  1743   2529   
  1744   2530   proc complete(socket) {text start end line pos mod} {
  1745         -    set cmd [lindex ${line} 1]
         2531  +    set cmd [Lindex ${line} 1]
  1746   2532       set prev [PreviousWord ${start} ${line}]
  1747   2533       if {"-server" == ${cmd}} {
  1748   2534           # server sockets
  1749   2535           #
  1750         -        if {2 == $pos && ![llength ${mod}]} { return <command> }
  1751         -        switch -- ${prev} {
  1752         -            -myaddr { if {![llength ${mod}]} { return <addr> } }
         2536  +        switch -- $pos {
         2537  +            2 { return [DisplayHints <command>] }
         2538  +            default {
         2539  +                if {"-myaddr" == $prev} {
         2540  +                    return [DisplayHints <addr>]
         2541  +                } else {
         2542  +                    return [CompleteFromList ${mod} \
         2543  +                    [RemoveUsedOptions $line {-myaddr -error -sockname <port>}]]
         2544  +                }
         2545  +            }
  1753   2546           }
  1754         -        return [TryFromList ${mod} [concat {-error -sockname -peername}]]
  1755   2547       } else {
  1756   2548           # client sockets
  1757   2549           #
  1758   2550           switch -- ${prev} {
  1759         -            -myaddr { if {![llength ${mod}]} { return <addr> } }
  1760         -            -myport { if {![llength ${mod}]} { return <port> } }
         2551  +            -myaddr { return [DisplayHints <addr>] }
         2552  +            -myport { return [DisplayHints <port>] }
  1761   2553           }
  1762   2554   
  1763         -        # read the host table only once.
  1764         -        #
  1765         -        variable hosts
  1766         -        if {![info exists hosts] && "-server" != ${cmd}} {
  1767         -            set id [open /etc/hosts r]
  1768         -            set hosts ""
  1769         -            if {0 != ${id}} {
  1770         -                while {-1 != [gets ${id} line]} {
  1771         -                    regsub {#.*} ${line} {} line
  1772         -                    if {[llength ${line}] >= 2} {
  1773         -                        lappend hosts [lindex ${line} 1]
  1774         -                    }
  1775         -                }
  1776         -                close $id
  1777         -            } 
  1778         -        }
         2555  +        set hosts [HostList]
  1779   2556           set cmds {-myaddr -myport -async -myaddr -error -sockname -peername}
  1780   2557           if {$pos <= 1} {
  1781   2558               lappend cmds -server
  1782   2559           }
  1783         -        return [TryFromList ${mod} [concat ${cmds} ${hosts}]]
         2560  +        set cmds [RemoveUsedOptions $line $cmds]
         2561  +        if {-1 != [lsearch $hosts $prev]} {
         2562  +            return [DisplayHints <port>]
         2563  +        } else {
         2564  +            return [CompleteFromList ${mod} [concat ${cmds} ${hosts}]]
         2565  +        }
  1784   2566       }
  1785   2567       return ""
  1786   2568   }
  1787   2569   
  1788         -proc complete(source) {text start end line pos mod} {
  1789         -    return ""; # force file name completion
         2570  +# proc complete(source) {text start end line pos mod} {
         2571  +# }
         2572  +
         2573  +proc complete(split) {text start end line pos mod} {
         2574  +    switch -- $pos {
         2575  +        1 { return [DisplayHints <string>] }
         2576  +        2 { return [DisplayHints ?splitChars?] }
         2577  +    }
  1790   2578   }
  1791   2579   
  1792   2580   proc complete(string) {text start end line pos mod} {
  1793         -    set cmd [lindex ${line} 1]
         2581  +    set cmd [Lindex ${line} 1]
         2582  +    set prev [PreviousWord ${start} ${line}]
  1794   2583       set cmds {
  1795         -        compare first index last length match range tolower
  1796         -        totitle toupper trim trimleft trimright wordend wordstart}
  1797         -    if {1 == $pos} {
  1798         -        return [TryFromList ${mod} ${cmds}]
  1799         -    } elseif {2 == $pos} {
  1800         -        switch -- $cmd {
  1801         -            compare -
  1802         -            first -
  1803         -            last { if {![llength ${mod}]} { return <string1> } }
  1804         -
  1805         -            match { if {![llength ${mod}]} { return <pattern> } }
  1806         -
  1807         -            index -
  1808         -            length -
  1809         -            range -
  1810         -            tolower -
  1811         -            totitle -
  1812         -            toupper -
  1813         -            trim -
  1814         -            trimleft -
  1815         -            trimright -
  1816         -            wordend -
  1817         -            wordstart { if {![llength ${mod}]} { return <string> } }
  1818         -        }
  1819         -    } elseif {3 == $pos} {
  1820         -        switch -- $cmd {
  1821         -            compare -
  1822         -            first -
  1823         -            last { if {![llength ${mod}]} { return <string2> } }
  1824         -
  1825         -            index { if {![llength ${mod}]} { return <charIndex> } }
  1826         -            length {}
  1827         -
  1828         -            match { if {![llength ${mod}]} { return <string> } }
  1829         -
  1830         -            range { if {![llength ${mod}]} { return <first> } }
  1831         -
  1832         -            tolower -
  1833         -            totitle -
  1834         -            toupper {}
  1835         -
  1836         -            trim -
  1837         -            trimleft { if {![llength ${mod}]} { return ?chars? } }
  1838         -            trimright -
  1839         -            wordend -
  1840         -            wordstart { if {![llength ${mod}]} { return <index> } }
         2584  +        bytelength compare equal first index is last length map match
         2585  +        range repeat replace tolower toupper totitle trim trimleft
         2586  +        trimright wordend wordstart}
         2587  +    switch -- $pos {
         2588  +        1 {
         2589  +            return [CompleteFromList ${text} ${cmds}]
         2590  +        }
         2591  +        2 {
         2592  +            switch -- $cmd {
         2593  +                compare -
         2594  +                equal {
         2595  +                    return [CompleteFromList ${text} {
         2596  +                        -nocase -length <string> }]
         2597  +                }
         2598  +
         2599  +                first -
         2600  +                last { return [DisplayHints <string1>] }
         2601  +
         2602  +                map { return [CompleteFromList ${text} {-nocase <charMap>]} }
         2603  +                match { return [CompleteFromList ${text} {-nocase <pattern>]} }
         2604  +
         2605  +                is {
         2606  +                    return [CompleteFromList ${text} {
         2607  +                        alnum alpha ascii boolean control digit double 
         2608  +                        false graph integer lower print punct space 
         2609  +                        true upper wordchar xdigit 
         2610  +                    }]
         2611  +                }
         2612  +
         2613  +                bytelength -
         2614  +                index -
         2615  +                length -
         2616  +                range -
         2617  +                repeat -
         2618  +                replace -
         2619  +                tolower -
         2620  +                totitle -
         2621  +                toupper -
         2622  +                trim -
         2623  +                trimleft -
         2624  +                trimright -
         2625  +                wordend -
         2626  +                wordstart { return [DisplayHints <string>] }
         2627  +            }
         2628  +        }
         2629  +        3 {
         2630  +            switch -- $cmd {
         2631  +                compare -
         2632  +                equal {
         2633  +                    if {"-length" == $prev} {
         2634  +                        return [DisplayHints <int>]
         2635  +                    }
         2636  +                    return [CompleteFromList ${text} \
         2637  +                    [RemoveUsedOptions $line {-nocase -length <string>}]]
         2638  +                }
         2639  +
         2640  +                first -
         2641  +                last { return [DisplayHints <string2>] }
         2642  +
         2643  +                map {
         2644  +                    if {"-nocase" == $prev} {
         2645  +                        return [DisplayHints <charMap>]
         2646  +                    } else {
         2647  +                        return [DisplayHints <string>]
         2648  +                    }
         2649  +                }
         2650  +                match {
         2651  +                    if {"-nocase" == $prev} {
         2652  +                        return [DisplayHints <pattern>]
         2653  +                    } else {
         2654  +                        return [DisplayHints <string>]
         2655  +                    }
         2656  +                }
         2657  +
         2658  +                is {
         2659  +                    return [CompleteFromList ${text} \
         2660  +                    [RemoveUsedOptions $line {-strict -failindex <string>}]]
         2661  +                }
         2662  +
         2663  +                bytelength {}
         2664  +                index -
         2665  +                wordend -
         2666  +                wordstart { return [DisplayHints <charIndex>] }
         2667  +                range -
         2668  +                replace { return [DisplayHints <first>] }
         2669  +                repeat { return [DisplayHints <count>] }
         2670  +                tolower -
         2671  +                totitle -
         2672  +                toupper { return [DisplayHints ?first?] }
         2673  +                trim -
         2674  +                trimleft -
         2675  +                trimright { return [DisplayHints ?chars?] }
         2676  +            }
         2677  +        }
         2678  +        4 {
         2679  +            switch -- $cmd {
         2680  +                compare -
         2681  +                equal {
         2682  +                    if {"-length" == $prev} {
         2683  +                        return [DisplayHints <int>]
         2684  +                    }
         2685  +                    return [CompleteFromList ${text} \
         2686  +                    [RemoveUsedOptions $line {-nocase -length <string>}]]
         2687  +                }
         2688  +
         2689  +                first -
         2690  +                last { return [DisplayHints ?startIndex?] }
         2691  +
         2692  +                map -
         2693  +                match { return [DisplayHints <string>] }
         2694  +
         2695  +                is {
         2696  +                    if {"-failindex" == $prev} {
         2697  +                        return [VarCompletion ${text}]
         2698  +                    }
         2699  +                    return [CompleteFromList ${text} \
         2700  +                    [RemoveUsedOptions $line {-strict -failindex <string>}]]
         2701  +                }
         2702  +
         2703  +                bytelength {}
         2704  +                index {}
         2705  +                length {}
         2706  +                range -
         2707  +                replace { return [DisplayHints <last>] }
         2708  +                repeat {}
         2709  +                tolower -
         2710  +                totitle -
         2711  +                toupper { return [DisplayHints ?last?] }
         2712  +                trim -
         2713  +                trimleft -
         2714  +                trimright {}
         2715  +                wordend -
         2716  +                wordstart {}
         2717  +            }
         2718  +        }
         2719  +        default {
         2720  +            switch -- $cmd {
         2721  +                compare -
         2722  +                equal {
         2723  +                    if {"-length" == $prev} {
         2724  +                        return [DisplayHints <int>]
         2725  +                    }
         2726  +                    return [CompleteFromList ${text} \
         2727  +                    [RemoveUsedOptions $line {-nocase -length <string>}]]
         2728  +                }
         2729  +
         2730  +                is {
         2731  +                    if {"-failindex" == $prev} {
         2732  +                        return [VarCompletion ${text}]
         2733  +                    }
         2734  +                    return [CompleteFromList ${text} \
         2735  +                    [RemoveUsedOptions $line {-strict -failindex <string>}]]
         2736  +                }
         2737  +
         2738  +                replace { return [DisplayHints ?newString?] }
         2739  +            }
  1841   2740           }
  1842   2741       }
  1843   2742       return ""
  1844   2743   }
  1845   2744   
  1846   2745   proc complete(subst) {text start end line pos mod} {
  1847         -    set opts {-nobackslashes -nocommands -novariables}
  1848         -    set opts [RemoveUsedOptions ${line} ${opts}]
  1849         -    return [TryFromList ${mod} [concat ${opts} <string>]]
  1850         -    return ""
         2746  +    return [CompleteFromList ${text} [RemoveUsedOptions $line {
         2747  +        -nobackslashes -nocommands -novariables <string>}]]
  1851   2748   }
  1852   2749   
  1853   2750   proc complete(switch) {text start end line pos mod} {
  1854         -    set opts {-exact -glob -regexp --}
  1855         -    set opts [RemoveUsedOptions ${line} ${opts} {--}]
  1856         -    return [TryFromList ${mod} [concat ${opts} <string>]]
         2751  +    set prev [PreviousWord ${start} ${line}]
         2752  +    if {[llength ${prev}] && "--" != $prev && \
         2753  +        ("-" == [string index ${prev} 0] || 1 == $pos)} {
         2754  +        set cmds [RemoveUsedOptions ${line} {
         2755  +            -exact -glob -regexp --} {--}]
         2756  +        if {[llength ${cmds}]} {
         2757  +            return [string trim [CompleteFromList $text $cmds]]
         2758  +        }
         2759  +    } else {
         2760  +        set virtual_pos [expr ${pos} - [FirstNonOption ${line}]]
         2761  +        switch -- ${virtual_pos} {
         2762  +            0 { return [DisplayHints <string>] }
         2763  +            1 { return [DisplayHints <pattern>] }
         2764  +            2 { return [DisplayHints <body>] }
         2765  +            default { 
         2766  +                switch [expr $virtual_pos % 2] {
         2767  +                    0 { return [DisplayHints ?body?] }
         2768  +                    1 { return [DisplayHints ?pattern?] }
         2769  +                }
         2770  +            }
         2771  +        }
         2772  +    }
  1857   2773       return ""
  1858   2774   }
  1859   2775   
  1860   2776   proc complete(tell) {text start end line pos mod} {
  1861         -    if {1 == $pos} {
  1862         -        return [ChannelId ${mod}]
         2777  +    switch -- $pos {
         2778  +        1 { return [ChannelId ${mod}] }
         2779  +    }
         2780  +    return ""
         2781  +}
         2782  +
         2783  +proc complete(time) {text start end line pos mod} {
         2784  +    switch -- $pos {
         2785  +        1 { return [DisplayHints <script>] }
         2786  +        2 { return [DisplayHints ?count?] }
  1863   2787       }
  1864   2788       return ""
  1865   2789   }
  1866   2790   
  1867   2791   proc complete(trace) {text start end line pos mod} {
  1868         -    set cmd [lindex ${line} 1]
  1869         -    if {1 == $pos} {
  1870         -        return [TryFromList ${mod} {variable vdelete vinfo}]
  1871         -    } elseif {2 == $pos} {
  1872         -        return [Format [uplevel 2 info vars "${mod}*"] ${mod}]
  1873         -    } elseif {3 == $pos && "variable" == ${cmd}} {
  1874         -        return [TryFromList ${mod} {r w u}]
         2792  +    set cmd [Lindex ${line} 1]
         2793  +    switch -- $pos {
         2794  +        1 {
         2795  +            return [CompleteFromList ${mod} {variable vdelete vinfo}]
         2796  +        }
         2797  +        2 {
         2798  +            return [CompleteFromList ${text} \
         2799  +            [uplevel [info level] info vars "${mod}*"]]
         2800  +        }
         2801  +        3 {
         2802  +            switch -- $cmd {
         2803  +                variable -
         2804  +                vdelete { return [CompleteFromList ${text} {r w u}] }
         2805  +            }
         2806  +        }
         2807  +        4 {
         2808  +            switch -- $cmd {
         2809  +                variable -
         2810  +                vdelete {
         2811  +                    return [CompleteFromList $text [CommandCompletion $text]]
         2812  +                }
         2813  +            }
         2814  +        }
         2815  +    }
         2816  +    return ""
         2817  +}
         2818  +
         2819  +proc complete(unknown) {text start end line pos mod} {
         2820  +    switch -- $pos {
         2821  +        1 {
         2822  +            return [CompleteFromList $text [CommandCompletion $text]]
         2823  +        }
         2824  +        default { return [DisplayHints ?arg?] }
  1875   2825       }
  1876   2826       return ""
  1877   2827   }
         2828  +
         2829  +proc complete(unset) {text start end line pos mod} {
         2830  +    return [VarCompletion ${text}]
         2831  +}
  1878   2832   
  1879   2833   proc complete(update) {text start end line pos mod} {
  1880         -    if {1 == $pos && ![llength ${mod}]} {
  1881         -        return idletasks
         2834  +    switch -- $pos {
         2835  +        1 { return idletasks }
  1882   2836       }
  1883   2837       return ""
  1884   2838   }
  1885   2839   
  1886   2840   proc complete(uplevel) {text start end line pos mod} {
  1887         -    if {![llength ${mod}]} {
  1888         -        if {1 == $pos} {
  1889         -            return ?level?
  1890         -        } elseif {2 == $pos} {
  1891         -            return <command>
  1892         -        } elseif {3 == $pos} {
  1893         -            return ?arg?
  1894         -        } elseif {4 == $pos} {
  1895         -            return ?...?
         2841  +    set one [Lindex ${line} 1]
         2842  +    switch -- $pos {
         2843  +        1 {
         2844  +            return [CompleteFromList $text "?level? [CommandCompletion $text]"]
  1896   2845           }
         2846  +        2 {
         2847  +            if {"#" == [string index $one 0] || [regexp {^[0-9]*$} $one]} {
         2848  +                return [CompleteFromList $text [CommandCompletion $text]]
         2849  +            } else {
         2850  +                return [DisplayHints ?arg?]
         2851  +            }
         2852  +        }
         2853  +        default { return [DisplayHints ?arg?] }
  1897   2854       }
  1898   2855       return ""
  1899   2856   }
  1900   2857   
  1901   2858   proc complete(upvar) {text start end line pos mod} {
  1902         -    if {![llength ${mod}]} {
  1903         -        if {1 == $pos} {
  1904         -            return ?level?
  1905         -        } elseif {2 == $pos} {
  1906         -            return <otherVar>
  1907         -        } elseif {3 == $pos} {
  1908         -            return <myVar>
  1909         -        } elseif {4 == $pos} {
  1910         -            return ?...?
         2859  +    set one [Lindex ${line} 1]
         2860  +    switch -- $pos {
         2861  +        1 {
         2862  +            return [DisplayHints {?level? <otherVar>}]
         2863  +        }
         2864  +        2 {
         2865  +            if {"#" == [string index $one 0] || [regexp {^[0-9]*$} $one]} {
         2866  +                return [DisplayHints <otherVar>]
         2867  +            } else {
         2868  +                return [DisplayHints <myVar>]
         2869  +            }
         2870  +        }
         2871  +        3 {
         2872  +            if {"#" == [string index $one 0] || [regexp {^[0-9]*$} $one]} {
         2873  +                return [DisplayHints <myVar>]
         2874  +            } else {
         2875  +                return [DisplayHints ?otherVar?]
         2876  +            }
         2877  +        }
         2878  +        default {
         2879  +            set virtual_pos $pos
         2880  +            if {"#" == [string index $one 0] || [regexp {^[0-9]*$} $one]} {
         2881  +                incr virtual_pos
         2882  +            }
         2883  +            switch [expr $virtual_pos % 2] {
         2884  +                0 { return [DisplayHints ?myVar?] }
         2885  +                1 { return [DisplayHints ?otherVar?] }
         2886  +            }
  1911   2887           }
  1912   2888       }
  1913   2889       return ""
  1914   2890   }
  1915   2891   
  1916   2892   proc complete(variable) {text start end line pos mod} {
  1917   2893       set modulo [expr $pos % 2]
  1918         -    if {1 == ${modulo}} {
  1919         -        return [VarCompletion ${mod}]
  1920         -    } elseif {0 == ${modulo} && \
  1921         -        ($text == "" || $text == "\"" || $text == "\{")} {
  1922         -        set line [QuoteQuotes $line]
  1923         -        incr pos -1
  1924         -        if {[catch \
  1925         -            "set value [list [uplevel [info level] set [lindex $line ${pos}]]]"\
  1926         -            msg]} {
  1927         -            return ""
  1928         -        } else {
  1929         -            return [Quote $value ${mod}]
         2894  +    switch -- $modulo {
         2895  +        1 { return [VarCompletion ${text}] }
         2896  +        0 {
         2897  +            if {$text == "" || $text == "\"" || $text == "\{"} {
         2898  +                set line [QuoteQuotes $line]
         2899  +                if {[catch [list set value [list [uplevel [info level] \
         2900  +                    set [PreviousWord $start $line]]]] msg]
         2901  +                } {
         2902  +                    return ""
         2903  +                } else {
         2904  +                    return [Quote $value ${text}]
         2905  +                }
         2906  +            }
  1930   2907           }
  1931   2908       }
  1932   2909       return ""
  1933   2910   }
  1934   2911   
  1935   2912   proc complete(vwait) {text start end line pos mod} {
  1936         -    if {1 == ${pos}} {
  1937         -        return [VarCompletion ${mod}]
         2913  +    switch -- $pos {
         2914  +        1 { return [VarCompletion ${mod}] }
  1938   2915       }
         2916  +    return ""
  1939   2917   }
  1940   2918   
  1941         -proc complete(unset) {text start end line pos mod} {
  1942         -    return [VarCompletion ${text}]
         2919  +proc complete(while) {text start end line pos mod} {
         2920  +    switch -- $pos {
         2921  +        1 -
         2922  +        2 {
         2923  +            return [BraceOrControlStatement $text $start $end $line $pos $mod]
         2924  +        }
         2925  +    }
         2926  +    return ""
  1943   2927   }
  1944   2928   
  1945   2929   # -------------------------------------
  1946   2930   #                  TK
  1947   2931   # -------------------------------------
  1948   2932   
  1949   2933   # generic widget configuration