# This code constructs the console window for an application. It
# can be used by non-unix systems that do not have built-in support
# RCS: @(#) $Id: console.tcl,v 1.22.2.3 2005/05/31 04:58:00 hobbs Exp $
# Copyright (c) 1995-1997 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 Ajuba Solutions.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# TODO: history - remember partially written command
namespace eval ::tk::console {
variable blinkTime
500 ; # msecs to blink braced range for
variable blinkRange
1 ; # enable blinking of the entire braced range
variable magicKeys
1 ; # enable brace matching and proc/var recognition
variable maxLines
600 ; # maximum # of lines buffered in console
variable showMatches
1 ; # show multiple expand matches
variable inPlugin
[info exists embed_args
]
variable defaultPrompt
; # default prompt if tcl_prompt1 isn't used
set defaultPrompt
{subst {[history nextid
] % }}
set defaultPrompt
{subst {([file tail
[pwd]]) [history nextid
] % }}
# simple compat function for tkcon code added for this console
interp alias
{} EvalAttached
{} consoleinterp
eval
# This procedure constructs and configures the console windows.
proc ::tk::ConsoleInit {} {
if {![consoleinterp
eval {set tcl_interactive
}]} {
if {[string equal
$tcl_platform(platform
) "macintosh"]
||
[string equal
[tk windowingsystem
] "aqua"]} {
if {[catch {menu .menubar
} err
]} { bgerror "INIT: $err" }
.menubar add cascade
-label File
-menu .menubar.
file -underline 0
.menubar add cascade
-label Edit
-menu .menubar.edit
-underline 0
menu .menubar.
file -tearoff 0
.menubar.
file add command
-label [mc
"Source..."] \
-underline 0 -command tk::ConsoleSource
.menubar.
file add command
-label [mc
"Hide Console"] \
-underline 0 -command {wm withdraw .
}
.menubar.
file add command
-label [mc
"Clear Console"] \
-underline 0 -command {.
console delete
1.0 "promptEnd linestart"}
if {[string equal
$tcl_platform(platform
) "macintosh"]
||
[string equal
[tk windowingsystem
] "aqua"]} {
.menubar.
file add command
-label [mc
"Quit"] \
-command exit -accel Cmd-Q
.menubar.
file add command
-label [mc
"Exit"] \
-underline 1 -command exit
menu .menubar.edit
-tearoff 0
.menubar.edit add command
-label [mc
"Cut"] -underline 2 \
-command { event generate .
console <<Cut
>> } -accel "$mod+X"
.menubar.edit add command
-label [mc
"Copy"] -underline 0 \
-command { event generate .
console <<Copy
>> } -accel "$mod+C"
.menubar.edit add command
-label [mc
"Paste"] -underline 1 \
-command { event generate .
console <<Paste
>> } -accel "$mod+V"
if {[string compare
$tcl_platform(platform
) "windows"]} {
.menubar.edit add command
-label [mc
"Clear"] -underline 2 \
-command { event generate .
console <<Clear
>> }
.menubar.edit add command
-label [mc
"Delete"] -underline 0 \
-command { event generate .
console <<Clear
>> } -accel "Del"
.menubar add cascade
-label Help
-menu .menubar.help
-underline 0
menu .menubar.help
-tearoff 0
.menubar.help add command
-label [mc
"About..."] \
-underline 0 -command tk::ConsoleAbout
. configure
-menu .menubar
set con
[text .
console -yscrollcommand [list .sb
set] -setgrid true
]
scrollbar .sb
-command [list $con yview
]
pack .sb
-side right
-fill both
pack $con -fill both
-expand 1 -side left
switch -exact $tcl_platform(platform
) {
$con configure
-font {Monaco
9 normal
} -highlightthickness 0
$con configure
-font systemfixed
if {[string equal
[tk windowingsystem
] "aqua"]} {
$con configure
-font {Monaco
9 normal
} -highlightthickness 0
$con tag configure stderr
-foreground red
$con tag configure stdin
-foreground blue
$con tag configure prompt
-foreground \#8F4433
$con tag configure
proc -foreground \#008800
$con tag configure var
-background \#FFC0D0
$con tag configure blink
-background \#FFFF00
$con tag configure find
-background \#FFFF00
wm protocol . WM_DELETE_WINDOW
{ wm withdraw .
}
wm title .
[mc
"Console"]
$con mark
set output
[$con index
"end - 1 char"]
tk::TextSetCursor $con end
$con mark
set promptEnd insert
$con mark gravity promptEnd left
# A variant of ConsolePrompt to avoid a 'puts' call
set temp
[$w index
"end - 1 char"]
if {![consoleinterp
eval "info exists tcl_prompt1"]} {
set string [EvalAttached
$::tk::console::defaultPrompt]
$w insert output
$string stdout
::tk::TextSetCursor $w end
$w mark
set promptEnd insert
$w mark gravity promptEnd left
if {$tcl_platform(platform
) eq
"windows"} {
# Subtle work-around to erase the '% ' that tclMain.c prints out
after idle
[list $con delete
1.0 output
]
# Prompts the user for a file to source in the main interpreter.
proc ::tk::ConsoleSource {} {
set filename [tk_getOpenFile -defaultextension .tcl
-parent .
\
-title [mc
"Select a file to source"] \
[list [mc
"Tcl Scripts"] .tcl
] \
[list [mc
"All Files"] *]]]
if {[string compare
$filename ""]} {
set cmd
[list source $filename]
if {[catch {consoleinterp
eval $cmd} result
]} {
ConsoleOutput stderr
"$result\n"
# Processes the command line input. If the command is complete it
# is evaled in the main interpreter. Otherwise, the continuation
# prompt is added and more input may be added.
proc ::tk::ConsoleInvoke {args
} {
set ranges
[.
console tag ranges input
]
while {[string compare
[lindex $ranges $pos] ""]} {
set start
[lindex $ranges $pos]
set end
[lindex $ranges [incr pos
]]
append cmd
[.
console get
$start $end]
if {[string equal
$cmd ""]} {
} elseif
{[info complete
$cmd]} {
.
console mark
set output end
.
console tag delete input
set result
[consoleinterp record
$cmd]
if {[string compare
$result ""]} {
.
console yview
-pickplace insert
# ::tk::ConsoleHistory --
# This procedure implements command line history for the
# console. In general is evals the history command in the
# main interpreter to obtain the history. The variable
# ::tk::HistNum is used to store the current location in the history.
# cmd - Which action to take: prev, next, reset.
proc ::tk::ConsoleHistory {cmd
} {
set cmd
{history event [expr {[history nextid
] -1}]}
set cmd
"history event $HistNum"
if {[catch {consoleinterp
eval $cmd} cmd
]} {
.
console delete promptEnd end
.
console insert promptEnd
$cmd {input stdin
}
set cmd
{history event [expr {[history nextid
] -1}]}
} elseif
{$HistNum > 0} {
set cmd
"history event $HistNum"
if {[string compare
$cmd ""]} {
catch {consoleinterp
eval $cmd} cmd
.
console delete promptEnd end
.
console insert promptEnd
$cmd {input stdin
}
# This procedure draws the prompt. If tcl_prompt1 or tcl_prompt2
# exists in the main interpreter it will be called to generate the
# prompt. Otherwise, a hard coded default prompt is printed.
# partial - Flag to specify which prompt to print.
proc ::tk::ConsolePrompt {{partial normal
}} {
if {[string equal
$partial "normal"]} {
set temp
[$w index
"end - 1 char"]
if {[consoleinterp
eval "info exists tcl_prompt1"]} {
consoleinterp
eval "eval \[set tcl_prompt1\]"
puts -nonewline [EvalAttached
$::tk::console::defaultPrompt]
set temp
[$w index output
]
if {[consoleinterp
eval "info exists tcl_prompt2"]} {
consoleinterp
eval "eval \[set tcl_prompt2\]"
::tk::TextSetCursor $w end
$w mark
set promptEnd insert
$w mark gravity promptEnd left
::tk::console::ConstrainBuffer $w $::tk::console::maxLines
# This procedure first ensures that the default bindings for the Text
# class have been defined. Then certain bindings are overridden for
proc ::tk::ConsoleBind {w
} {
bindtags $w [list $w Console PostConsole
[winfo toplevel $w] all
]
## Get all Text bindings into Console
foreach ev
[bind Text
] { bind Console
$ev [bind Text
$ev] }
## We really didn't want the newline insertion...
bind Console
<Control-Key-o
> {}
## ...or any Control-v binding (would block <<Paste>>)
bind Console
<Control-Key-v
> {}
# For the moment, transpose isn't enabled until the console
# gets and overhaul of how it handles input -- hobbs
bind Console
<Control-Key-t
> {}
# Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
# Otherwise, if a widget binding for one of these is defined, the
bind Console
<Alt-KeyPress
> {# nothing }
bind Console
<Meta-KeyPress
> {# nothing}
bind Console
<Control-KeyPress
> {# nothing}
<<Console_Prev
>> <Key-Up
>
<<Console_Next
>> <Key-Down
>
<<Console_NextImmediate
>> <Control-Key-n
>
<<Console_PrevImmediate
>> <Control-Key-p
>
<<Console_PrevSearch
>> <Control-Key-r
>
<<Console_NextSearch
>> <Control-Key-s
>
<<Console_Expand
>> <Key-Tab
>
<<Console_Expand
>> <Key-Escape
>
<<Console_ExpandFile
>> <Control-Shift-Key-F
>
<<Console_ExpandProc
>> <Control-Shift-Key-P
>
<<Console_ExpandVar
>> <Control-Shift-Key-V
>
<<Console_Tab
>> <Control-Key-i
>
<<Console_Tab
>> <Meta-Key-i
>
<<Console_Eval
>> <Key-Return
>
<<Console_Eval
>> <Key-KP_Enter
>
<<Console_Clear
>> <Control-Key-l
>
<<Console_KillLine
>> <Control-Key-k
>
<<Console_Transpose
>> <Control-Key-t
>
<<Console_ClearLine
>> <Control-Key-u
>
<<Console_SaveCommand
>> <Control-Key-z
>
bind Console
<<Console_Expand
>> {
if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W
}
bind Console
<<Console_ExpandFile
>> {
if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W path
}
bind Console
<<Console_ExpandProc
>> {
if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W
proc}
bind Console
<<Console_ExpandVar
>> {
if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W var
}
bind Console
<<Console_Eval
>> {
%W mark
set insert
{end
- 1c
}
tk::ConsoleInsert %W
"\n"
if {[string compare
{} [%W tag nextrange sel
1.0 end
]] \
&& [%W compare sel.first
>= promptEnd
]} {
%W delete sel.first sel.last
} elseif
{[%W compare insert
>= promptEnd
]} {
bind Console
<BackSpace
> {
if {[string compare
{} [%W tag nextrange sel
1.0 end
]] \
&& [%W compare sel.first
>= promptEnd
]} {
%W delete sel.first sel.last
} elseif
{[%W compare insert
!= 1.0] && \
[%W compare insert
> promptEnd
]} {
bind Console
<Control-h
> [bind Console
<BackSpace
>]
if {[%W compare insert
< promptEnd
]} {
tk::TextSetCursor %W
{insert linestart
}
tk::TextSetCursor %W promptEnd
bind Console
<Control-a
> [bind Console
<Home
>]
tk::TextSetCursor %W
{insert lineend
}
bind Console
<Control-e
> [bind Console
<End
>]
bind Console
<Control-d
> {
if {[%W compare insert
< promptEnd
]} break
bind Console
<<Console_KillLine
>> {
if {[%W compare insert
< promptEnd
]} break
if {[%W compare insert
== {insert lineend
}]} {
%W delete insert
{insert lineend
}
bind Console
<<Console_Clear
>> {
%W delete
1.0 "promptEnd linestart"
bind Console
<<Console_ClearLine
>> {
## Clear command line (Unix shell staple)
if {[%W compare insert
>= promptEnd
]} {
%W delete insert
{insert wordend
}
bind Console
<Meta-BackSpace
> {
if {[%W compare
{insert
-1c wordstart
} >= promptEnd
]} {
%W delete
{insert
-1c wordstart
} insert
if {[%W compare insert
>= promptEnd
]} {
%W delete insert
{insert wordend
}
bind Console
<Meta-BackSpace
> {
if {[%W compare
{insert
-1c wordstart
} >= promptEnd
]} {
%W delete
{insert
-1c wordstart
} insert
bind Console
<Meta-Delete
> {
if {[%W compare insert
>= promptEnd
]} {
%W delete insert
{insert wordend
}
bind Console
<<Console_Prev
>> {
bind Console
<<Console_Next
>> {
catch {tk::ConsoleInsert %W
[::tk::GetSelection %W PRIMARY
]}
bind Console
<KeyPress
> {
eval destroy [winfo child .
]
if {[string equal
$tcl_platform(platform
) "macintosh"]} {
if {[catch {source [file join $tk_library console.tcl
]}]} {source -rsrc console}
source [file join $tk_library console.tcl
]
if {[string equal
$::tcl_platform(platform
) "macintosh"]
||
[string equal
[tk windowingsystem
] "aqua"]} {
bind Console
<Command-q
> {
if {![catch {set data
[%W get sel.first sel.last
]}]} {
clipboard clear
-displayof %W
clipboard append -displayof %W
$data
if {![catch {set data
[%W get sel.first sel.last
]}]} {
clipboard clear
-displayof %W
clipboard append -displayof %W
$data
set clip
[::tk::GetSelection %W CLIPBOARD
]
set list [split $clip \n\r]
tk::ConsoleInsert %W
[lindex $list 0]
foreach x
[lrange $list 1 end
] {
%W mark
set insert
{end
- 1c
}
tk::ConsoleInsert %W
"\n"
## Bindings for doing special things based on certain keys
bind PostConsole
<Key-parenright
> {
if {[string compare
\\ [%W get insert-2c
]]} {
::tk::console::MatchPair %W
\( \) promptEnd
bind PostConsole
<Key-bracketright
> {
if {[string compare
\\ [%W get insert-2c
]]} {
::tk::console::MatchPair %W
\[ \] promptEnd
bind PostConsole
<Key-braceright
> {
if {[string compare
\\ [%W get insert-2c
]]} {
::tk::console::MatchPair %W
\{ \} promptEnd
bind PostConsole
<Key-quotedbl
> {
if {[string compare
\\ [%W get insert-2c
]]} {
::tk::console::MatchQuote %W promptEnd
bind PostConsole
<KeyPress
> {
::tk::console::TagProc %W
# Insert a string into a text at the point of the insertion cursor.
# If there is a selection in the text, and it covers the point of the
# insertion cursor, then delete the selection before inserting. Insertion
# is restricted to the prompt area.
# w - The text window in which to insert the string
# s - The string to insert (usually just a single character)
proc ::tk::ConsoleInsert {w s
} {
if {[string equal
$s ""]} {
if {[$w compare sel.first
<= insert
]
&& [$w compare sel.last
>= insert
]} {
$w tag remove sel sel.first promptEnd
$w delete sel.first sel.last
if {[$w compare insert
< promptEnd
]} {
$w insert insert
$s {input stdin
}
# This routine is called directly by ConsolePutsCmd to cause a string
# to be displayed in the console.
# dest - The output tag to be used: either "stderr" or "stdout".
# string - The string to be displayed.
proc ::tk::ConsoleOutput {dest
string} {
$w insert output
$string $dest
::tk::console::ConstrainBuffer $w $::tk::console::maxLines
# This routine is called by ConsoleEventProc when the main window of
# the application is destroyed. Don't call exit - that probably already
# happened. Just delete our window.
proc ::tk::ConsoleExit {} {
# This routine displays an About box to show Tcl/Tk version info.
proc ::tk::ConsoleAbout {} {
tk_messageBox -type ok
-message "[mc {Tcl for Windows}]
# ::tk::console::TagProc --
# Tags a procedure in the console if it's recognized
# This procedure is not perfect. However, making it perfect wastes
# w - console text widget
proc ::tk::console::TagProc w
{
if {!$::tk::console::magicKeys} { return }
set exp
"\[^\\\\\]\[\[ \t\n\r\;{}\"\$\]"
set i
[$w search
-backwards -regexp $exp insert-1c promptEnd-1c
]
if {$i == ""} {set i promptEnd
} else {append i
+2c
}
regsub -all "\[\[\\\\\\?\\*\]" [$w get
$i "insert-1c wordend"] {\\\0} c
if {[llength [EvalAttached
[list info commands
$c]]]} {
$w tag add
proc $i "insert-1c wordend"
$w tag remove
proc $i "insert-1c wordend"
if {[llength [EvalAttached
[list info vars
$c]]]} {
$w tag add var
$i "insert-1c wordend"
$w tag remove var
$i "insert-1c wordend"
# ::tk::console::MatchPair --
# Blinks a matching pair of characters
# c2 is assumed to be at the text index 'insert'.
# This proc is really loopy and took me an hour to figure out given
# all possible combinations with escaping except for escaped \'s.
# It doesn't take into account possible commenting... Oh well. If
# anyone has something better, I'd like to see/use it. This is really
# only efficient for small contexts.
# w - console text widget
# c1 - first char of pair
# c2 - second char of pair
# Calls: ::tk::console::Blink
proc ::tk::console::MatchPair {w c1 c2
{lim
1.0}} {
if {!$::tk::console::magicKeys} { return }
if {[string compare
{} [set ix
[$w search
-back $c1 insert
$lim]]]} {
[string match
{\\} [$w get
$ix-1c
]] &&
[string compare
{} [set ix
[$w search
-back $c1 $ix-1c
$lim]]]
while {[string compare
{} $ix]} {
while {[string compare
{} [set i0
[$w search
$c2 $i0 $i1]]]} {
if {[string match
{\\} [$w get
$i0-2c
]]} continue
while {$j && [string compare
{} \
[set ix
[$w search
-back $c1 $ix $lim]]]} {
if {[string match
{\\} [$w get
$ix-1c
]]} continue
if {[string match
{} $ix]} { set ix
[$w index
$lim] }
} else { set ix
[$w index
$lim] }
if {$::tk::console::blinkRange} {
Blink
$w $ix [$w index insert
]
Blink
$w $ix $ix+1c
[$w index insert-1c
] [$w index insert
]
# ::tk::console::MatchQuote --
# Blinks between matching quotes.
# Blinks just the quote if it's unmatched, otherwise blinks quoted string
# The quote to match is assumed to be at the text index 'insert'.
# w - console text widget
# Calls: ::tk::console::Blink
proc ::tk::console::MatchQuote {w
{lim
1.0}} {
if {!$::tk::console::magicKeys} { return }
while {[string compare
[set i
[$w search
-back \" $i $lim]] {}]} {
if {[string match
{\\} [$w get
$i-1c
]]} continue
if {$::tk::console::blinkRange} {
Blink
$w $i0 [$w index insert
]
Blink
$w $i0 $i0+1c
[$w index insert-1c
] [$w index insert
]
Blink
$w [$w index insert-1c
] [$w index insert
]
# ::tk::console::Blink --
# Blinks between n index pairs for a specified duration.
# w - console text widget
# i1 - start index to blink region
# i2 - end index of blink region
# dur - duration in usecs to blink for
# blinks selected characters in $w
proc ::tk::console::Blink {w args
} {
eval [list $w tag add blink
] $args
after $::tk::console::blinkTime [list $w] tag remove blink
$args
# ::tk::console::ConstrainBuffer --
# This limits the amount of data in the text widget
# Called by Prompt and ConsoleOutput
# w - console text widget
# size - # of lines to constrain to
# may delete data in console widget
proc ::tk::console::ConstrainBuffer {w size
} {
if {[$w index end
] > $size} {
$w delete
1.0 [expr {int
([$w index end
])-$size}].0
# ::tk::console::Expand --
# ARGS: w - text widget in which to expand str
# type - type of expansion (path / proc / variable)
# Calls: ::tk::console::Expand(Pathname|Procname|Variable)
# Outputs: The string to match is expanded to the longest possible match.
# If ::tk::console::showMatches is non-zero and the longest match
# equaled the string to expand, then all possible matches are
# output to stdout. Triggers bell if no matches are found.
# Returns: number of matches found
proc ::tk::console::Expand {w
{type
""}} {
set exp
"\[^\\\\\]\[\[ \t\n\r\\\{\"\\\\\$\]"
set tmp
[$w search
-backwards -regexp $exp insert-1c promptEnd-1c
]
if {$tmp == ""} {set tmp promptEnd
} else {append tmp
+2c
}
if {[$w compare
$tmp >= insert
]} { return }
set str
[$w get
$tmp insert
]
path
* { set res
[ExpandPathname
$str] }
proc* { set res
[ExpandProcname
$str] }
var
* { set res
[ExpandVariable
$str] }
foreach t
{Pathname Procname Variable
} {
if {![catch {Expand
$t $str} res
] && ($res != "")} { break }
$w insert
$tmp $repl {input stdin
}
if {($len > 1) && $::tk::console::showMatches \
&& [string equal
$repl $str]} {
puts stdout
[lsort [lreplace $res 0 0]]
# ::tk::console::ExpandPathname --
# Expand a file pathname based on $str
# This is based on UNIX file name conventions
# str - partial file pathname to expand
# Calls: ::tk::console::ExpandBestMatch
# Returns: list containing longest unique match followed by all the
# possible further matches
proc ::tk::console::ExpandPathname str
{
set pwd [EvalAttached
pwd]
if {[catch {EvalAttached
[list cd [file dirname
$str]]} err
]} {
## Check to see if it was known to be a directory and keep the trailing
## slash if so (file tail cuts it off)
if {[string match
*/ $str]} { append dir
/ }
if {[catch {lsort [EvalAttached
[list glob $dir*]]} m
]} {
if {[string match windows
$tcl_platform(platform
)]} {
## Windows is screwy because it's case insensitive
set tmp
[ExpandBestMatch
[string tolower
$m] \
## Don't change case if we haven't changed the word
if {[string length
$dir]==[string length
$tmp]} {
set tmp
[ExpandBestMatch
$m $dir]
if {[string match ?
*/* $str]} {
set tmp
[file dirname
$str]/$tmp
} elseif
{[string match
/* $str]} {
regsub -all { } $tmp {\\ } tmp
set match
[linsert $m 0 $tmp]
## This may look goofy, but it handles spaces in path names
if {[file isdir
$match]} {append match
/}
if {[string match ?
*/* $str]} {
set match
[file dirname
$str]/$match
} elseif
{[string match
/* $str]} {
regsub -all { } $match {\\ } match
## Why is this one needed and the ones below aren't!!
EvalAttached
[list cd $pwd]
# ::tk::console::ExpandProcname --
# Expand a tcl proc name based on $str
# str - partial proc name to expand
# Calls: ::tk::console::ExpandBestMatch
# Returns: list containing longest unique match followed by all the
# possible further matches
proc ::tk::console::ExpandProcname str
{
set match
[EvalAttached
[list info commands
$str*]]
if {[llength $match] == 0} {
"namespace children \[namespace current\] [list $str*]"]
set match
[EvalAttached
[list info commands
${ns
}::*]]
if {[llength $match] > 1} {
regsub -all { } [ExpandBestMatch
$match $str] {\\ } str
set match
[linsert $match 0 $str]
regsub -all { } $match {\\ } match
# ::tk::console::ExpandVariable --
# Expand a tcl variable name based on $str
# str - partial tcl var name to expand
# Calls: ::tk::console::ExpandBestMatch
# Returns: list containing longest unique match followed by all the
# possible further matches
proc ::tk::console::ExpandVariable str
{
if {[regexp {([^
\(]*)\((.
*)} $str junk ary str
]} {
## Looks like they're trying to expand an array.
set match
[EvalAttached
[list array names
$ary $str*]]
if {[llength $match] > 1} {
set vars
$ary\([ExpandBestMatch
$match $str]
foreach var
$match {lappend vars
$ary\($var\)}
} elseif
{[llength $match] == 1} {
## Space transformation avoided for array names.
set match
[EvalAttached
[list info vars
$str*]]
if {[llength $match] > 1} {
regsub -all { } [ExpandBestMatch
$match $str] {\\ } str
set match
[linsert $match 0 $str]
regsub -all { } $match {\\ } match
# ::tk::console::ExpandBestMatch --
# Finds the best unique match in a list of names.
# The extra $e in this argument allows us to limit the innermost loop a little
# further. This improves speed as $l becomes large or $e becomes long.
# l - list to find best unique match in
# e - currently best known unique match
# Returns: longest unique match in the list
proc ::tk::console::ExpandBestMatch {l
{e
{}}} {
set e
[string length
$e]; incr e
-1
set ei
[string length
$ec]; incr ei
-1
while {$ei>=$e && [string first
$ec $l]} {
set ec
[string range
$ec 0 [incr ei
-1]]
# now initialize the console