3 # This code constructs the console window for an application. It
4 # can be used by non-unix systems that do not have built-in support
7 # RCS: @(#) $Id: console.tcl,v 1.22.2.5 2006/01/25 18:21:41 dgp Exp $
9 # Copyright (c) 1995-1997 Sun Microsystems, Inc.
10 # Copyright (c) 1998-2000 Ajuba Solutions.
12 # See the file "license.terms" for information on usage and redistribution
13 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 # TODO: history - remember partially written command
18 namespace eval ::tk::console {
19 variable blinkTime
500 ; # msecs to blink braced range for
20 variable blinkRange
1 ; # enable blinking of the entire braced range
21 variable magicKeys
1 ; # enable brace matching and proc/var recognition
22 variable maxLines
600 ; # maximum # of lines buffered in console
23 variable showMatches
1 ; # show multiple expand matches
25 variable inPlugin
[info exists embed_args
]
26 variable defaultPrompt
; # default prompt if tcl_prompt1 isn't used
30 set defaultPrompt
{subst {[history nextid
] % }}
32 set defaultPrompt
{subst {([file tail
[pwd]]) [history nextid
] % }}
36 # simple compat function for tkcon code added for this console
37 interp alias
{} EvalAttached
{} consoleinterp
eval
39 # ::tk::ConsoleInit --
40 # This procedure constructs and configures the console windows.
45 proc ::tk::ConsoleInit {} {
48 if {![consoleinterp
eval {set tcl_interactive
}]} {
52 if {$tcl_platform(platform
) eq
"macintosh"
53 ||
[tk windowingsystem
] eq
"aqua"} {
59 if {[catch {menu .menubar
} err
]} { bgerror "INIT: $err" }
60 .menubar add cascade
-label File
-menu .menubar.
file -underline 0
61 .menubar add cascade
-label Edit
-menu .menubar.edit
-underline 0
63 menu .menubar.
file -tearoff 0
64 .menubar.
file add command
-label [mc
"Source..."] \
65 -underline 0 -command tk::ConsoleSource
66 .menubar.
file add command
-label [mc
"Hide Console"] \
67 -underline 0 -command {wm withdraw .
}
68 .menubar.
file add command
-label [mc
"Clear Console"] \
69 -underline 0 -command {.
console delete
1.0 "promptEnd linestart"}
70 if {$tcl_platform(platform
) eq
"macintosh"
71 ||
[tk windowingsystem
] eq
"aqua"} {
72 .menubar.
file add command
-label [mc
"Quit"] \
73 -command exit -accel Cmd-Q
75 .menubar.
file add command
-label [mc
"Exit"] \
76 -underline 1 -command exit
79 menu .menubar.edit
-tearoff 0
80 .menubar.edit add command
-label [mc
"Cut"] -underline 2 \
81 -command { event generate .
console <<Cut
>> } -accel "$mod+X"
82 .menubar.edit add command
-label [mc
"Copy"] -underline 0 \
83 -command { event generate .
console <<Copy
>> } -accel "$mod+C"
84 .menubar.edit add command
-label [mc
"Paste"] -underline 1 \
85 -command { event generate .
console <<Paste
>> } -accel "$mod+V"
87 if {$tcl_platform(platform
) ne
"windows"} {
88 .menubar.edit add command
-label [mc
"Clear"] -underline 2 \
89 -command { event generate .
console <<Clear
>> }
91 .menubar.edit add command
-label [mc
"Delete"] -underline 0 \
92 -command { event generate .
console <<Clear
>> } -accel "Del"
94 .menubar add cascade
-label Help
-menu .menubar.help
-underline 0
95 menu .menubar.help
-tearoff 0
96 .menubar.help add command
-label [mc
"About..."] \
97 -underline 0 -command tk::ConsoleAbout
100 . configure
-menu .menubar
102 set con
[text .
console -yscrollcommand [list .sb
set] -setgrid true
]
103 scrollbar .sb
-command [list $con yview
]
104 pack .sb
-side right
-fill both
105 pack $con -fill both
-expand 1 -side left
106 switch -exact $tcl_platform(platform
) {
108 $con configure
-font {Monaco
9 normal
} -highlightthickness 0
111 $con configure
-font systemfixed
114 if {[tk windowingsystem
] eq
"aqua"} {
115 $con configure
-font {Monaco
9 normal
} -highlightthickness 0
122 $con tag configure stderr
-foreground red
123 $con tag configure stdin
-foreground blue
124 $con tag configure prompt
-foreground \#8F4433
125 $con tag configure
proc -foreground \#008800
126 $con tag configure var
-background \#FFC0D0
128 $con tag configure blink
-background \#FFFF00
129 $con tag configure find
-background \#FFFF00
133 wm protocol . WM_DELETE_WINDOW
{ wm withdraw .
}
134 wm title .
[mc
"Console"]
136 $con mark
set output
[$con index
"end - 1 char"]
137 tk::TextSetCursor $con end
138 $con mark
set promptEnd insert
139 $con mark gravity promptEnd left
141 # A variant of ConsolePrompt to avoid a 'puts' call
143 set temp
[$w index
"end - 1 char"]
144 $w mark
set output end
145 if {![consoleinterp
eval "info exists tcl_prompt1"]} {
146 set string [EvalAttached
$::tk::console::defaultPrompt]
147 $w insert output
$string stdout
149 $w mark
set output
$temp
150 ::tk::TextSetCursor $w end
151 $w mark
set promptEnd insert
152 $w mark gravity promptEnd left
154 if {$tcl_platform(platform
) eq
"windows"} {
155 # Subtle work-around to erase the '% ' that tclMain.c prints out
156 after idle
[subst -nocommand {
157 if {[$con get
1.0 output
] eq
"% "} { $con delete
1.0 output
}
162 # ::tk::ConsoleSource --
164 # Prompts the user for a file to source in the main interpreter.
169 proc ::tk::ConsoleSource {} {
170 set filename [tk_getOpenFile -defaultextension .tcl
-parent .
\
171 -title [mc
"Select a file to source"] \
173 [list [mc
"Tcl Scripts"] .tcl
] \
174 [list [mc
"All Files"] *]]]
175 if {$filename ne
""} {
176 set cmd
[list source $filename]
177 if {[catch {consoleinterp
eval $cmd} result
]} {
178 ConsoleOutput stderr
"$result\n"
183 # ::tk::ConsoleInvoke --
184 # Processes the command line input. If the command is complete it
185 # is evaled in the main interpreter. Otherwise, the continuation
186 # prompt is added and more input may be added.
191 proc ::tk::ConsoleInvoke {args
} {
192 set ranges
[.
console tag ranges input
]
194 if {[llength $ranges]} {
196 while {[lindex $ranges $pos] ne
""} {
197 set start
[lindex $ranges $pos]
198 set end
[lindex $ranges [incr pos
]]
199 append cmd
[.
console get
$start $end]
205 } elseif
{[info complete
$cmd]} {
206 .
console mark
set output end
207 .
console tag delete input
208 set result
[consoleinterp record
$cmd]
215 ConsolePrompt partial
217 .
console yview
-pickplace insert
220 # ::tk::ConsoleHistory --
221 # This procedure implements command line history for the
222 # console. In general is evals the history command in the
223 # main interpreter to obtain the history. The variable
224 # ::tk::HistNum is used to store the current location in the history.
227 # cmd - Which action to take: prev, next, reset.
230 proc ::tk::ConsoleHistory {cmd
} {
237 set cmd
{history event [expr {[history nextid
] -1}]}
239 set cmd
"history event $HistNum"
241 if {[catch {consoleinterp
eval $cmd} cmd
]} {
245 .
console delete promptEnd end
246 .
console insert promptEnd
$cmd {input stdin
}
251 set cmd
{history event [expr {[history nextid
] -1}]}
252 } elseif
{$HistNum > 0} {
256 set cmd
"history event $HistNum"
259 catch {consoleinterp
eval $cmd} cmd
261 .
console delete promptEnd end
262 .
console insert promptEnd
$cmd {input stdin
}
270 # ::tk::ConsolePrompt --
271 # This procedure draws the prompt. If tcl_prompt1 or tcl_prompt2
272 # exists in the main interpreter it will be called to generate the
273 # prompt. Otherwise, a hard coded default prompt is printed.
276 # partial - Flag to specify which prompt to print.
278 proc ::tk::ConsolePrompt {{partial normal
}} {
280 if {$partial eq
"normal"} {
281 set temp
[$w index
"end - 1 char"]
282 $w mark
set output end
283 if {[consoleinterp
eval "info exists tcl_prompt1"]} {
284 consoleinterp
eval "eval \[set tcl_prompt1\]"
286 puts -nonewline [EvalAttached
$::tk::console::defaultPrompt]
289 set temp
[$w index output
]
290 $w mark
set output end
291 if {[consoleinterp
eval "info exists tcl_prompt2"]} {
292 consoleinterp
eval "eval \[set tcl_prompt2\]"
298 $w mark
set output
$temp
299 ::tk::TextSetCursor $w end
300 $w mark
set promptEnd insert
301 $w mark gravity promptEnd left
302 ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
306 # ::tk::ConsoleBind --
307 # This procedure first ensures that the default bindings for the Text
308 # class have been defined. Then certain bindings are overridden for
314 proc ::tk::ConsoleBind {w
} {
315 bindtags $w [list $w Console PostConsole
[winfo toplevel $w] all
]
317 ## Get all Text bindings into Console
318 foreach ev
[bind Text
] { bind Console
$ev [bind Text
$ev] }
319 ## We really didn't want the newline insertion...
320 bind Console
<Control-Key-o
> {}
321 ## ...or any Control-v binding (would block <<Paste>>)
322 bind Console
<Control-Key-v
> {}
324 # For the moment, transpose isn't enabled until the console
325 # gets and overhaul of how it handles input -- hobbs
326 bind Console
<Control-Key-t
> {}
328 # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
329 # Otherwise, if a widget binding for one of these is defined, the
331 bind Console
<Alt-KeyPress
> {# nothing }
332 bind Console
<Meta-KeyPress
> {# nothing}
333 bind Console
<Control-KeyPress
> {# nothing}
336 <<Console_Prev
>> <Key-Up
>
337 <<Console_Next
>> <Key-Down
>
338 <<Console_NextImmediate
>> <Control-Key-n
>
339 <<Console_PrevImmediate
>> <Control-Key-p
>
340 <<Console_PrevSearch
>> <Control-Key-r
>
341 <<Console_NextSearch
>> <Control-Key-s
>
343 <<Console_Expand
>> <Key-Tab
>
344 <<Console_Expand
>> <Key-Escape
>
345 <<Console_ExpandFile
>> <Control-Shift-Key-F
>
346 <<Console_ExpandProc
>> <Control-Shift-Key-P
>
347 <<Console_ExpandVar
>> <Control-Shift-Key-V
>
348 <<Console_Tab
>> <Control-Key-i
>
349 <<Console_Tab
>> <Meta-Key-i
>
350 <<Console_Eval
>> <Key-Return
>
351 <<Console_Eval
>> <Key-KP_Enter
>
353 <<Console_Clear
>> <Control-Key-l
>
354 <<Console_KillLine
>> <Control-Key-k
>
355 <<Console_Transpose
>> <Control-Key-t
>
356 <<Console_ClearLine
>> <Control-Key-u
>
357 <<Console_SaveCommand
>> <Control-Key-z
>
363 bind Console
<<Console_Expand
>> {
364 if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W
}
366 bind Console
<<Console_ExpandFile
>> {
367 if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W path
}
369 bind Console
<<Console_ExpandProc
>> {
370 if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W
proc}
372 bind Console
<<Console_ExpandVar
>> {
373 if {[%W compare insert
> promptEnd
]} {::tk::console::Expand %W var
}
375 bind Console
<<Console_Eval
>> {
376 %W mark
set insert
{end
- 1c
}
377 tk::ConsoleInsert %W
"\n"
381 bind Console
<Delete
> {
382 if {[%W tag nextrange sel
1.0 end
] ne
"" && [%W compare sel.first
>= promptEnd
]} {
383 %W delete sel.first sel.last
384 } elseif
{[%W compare insert
>= promptEnd
]} {
389 bind Console
<BackSpace
> {
390 if {[%W tag nextrange sel
1.0 end
] ne
"" && [%W compare sel.first
>= promptEnd
]} {
391 %W delete sel.first sel.last
392 } elseif
{[%W compare insert
!= 1.0] && \
393 [%W compare insert
> promptEnd
]} {
398 bind Console
<Control-h
> [bind Console
<BackSpace
>]
400 bind Console
<Home
> {
401 if {[%W compare insert
< promptEnd
]} {
402 tk::TextSetCursor %W
{insert linestart
}
404 tk::TextSetCursor %W promptEnd
407 bind Console
<Control-a
> [bind Console
<Home
>]
409 tk::TextSetCursor %W
{insert lineend
}
411 bind Console
<Control-e
> [bind Console
<End
>]
412 bind Console
<Control-d
> {
413 if {[%W compare insert
< promptEnd
]} break
416 bind Console
<<Console_KillLine
>> {
417 if {[%W compare insert
< promptEnd
]} break
418 if {[%W compare insert
== {insert lineend
}]} {
421 %W delete insert
{insert lineend
}
424 bind Console
<<Console_Clear
>> {
425 ## Clear console display
426 %W delete
1.0 "promptEnd linestart"
428 bind Console
<<Console_ClearLine
>> {
429 ## Clear command line (Unix shell staple)
430 %W delete promptEnd end
432 bind Console
<Meta-d
> {
433 if {[%W compare insert
>= promptEnd
]} {
434 %W delete insert
{insert wordend
}
437 bind Console
<Meta-BackSpace
> {
438 if {[%W compare
{insert
-1c wordstart
} >= promptEnd
]} {
439 %W delete
{insert
-1c wordstart
} insert
442 bind Console
<Meta-d
> {
443 if {[%W compare insert
>= promptEnd
]} {
444 %W delete insert
{insert wordend
}
447 bind Console
<Meta-BackSpace
> {
448 if {[%W compare
{insert
-1c wordstart
} >= promptEnd
]} {
449 %W delete
{insert
-1c wordstart
} insert
452 bind Console
<Meta-Delete
> {
453 if {[%W compare insert
>= promptEnd
]} {
454 %W delete insert
{insert wordend
}
457 bind Console
<<Console_Prev
>> {
458 tk::ConsoleHistory prev
460 bind Console
<<Console_Next
>> {
461 tk::ConsoleHistory next
463 bind Console
<Insert
> {
464 catch {tk::ConsoleInsert %W
[::tk::GetSelection %W PRIMARY
]}
466 bind Console
<KeyPress
> {
467 tk::ConsoleInsert %W
%A
470 eval destroy [winfo child .
]
471 if {$tcl_platform(platform
) eq
"macintosh"} {
472 if {[catch {source [file join $tk_library console.tcl
]}]} {source -rsrc console}
474 source [file join $tk_library console.tcl
]
477 if {$::tcl_platform(platform
) eq
"macintosh" ||
[tk windowingsystem
] eq
"aqua"} {
478 bind Console
<Command-q
> {
482 bind Console
<<Cut
>> {
483 # Same as the copy event
484 if {![catch {set data
[%W get sel.first sel.last
]}]} {
485 clipboard clear
-displayof %W
486 clipboard append -displayof %W
$data
489 bind Console
<<Copy
>> {
490 if {![catch {set data
[%W get sel.first sel.last
]}]} {
491 clipboard clear
-displayof %W
492 clipboard append -displayof %W
$data
495 bind Console
<<Paste
>> {
497 set clip
[::tk::GetSelection %W CLIPBOARD
]
498 set list [split $clip \n\r]
499 tk::ConsoleInsert %W
[lindex $list 0]
500 foreach x
[lrange $list 1 end
] {
501 %W mark
set insert
{end
- 1c
}
502 tk::ConsoleInsert %W
"\n"
504 tk::ConsoleInsert %W
$x
510 ## Bindings for doing special things based on certain keys
512 bind PostConsole
<Key-parenright
> {
513 if {"\\" ne
[%W get insert-2c
]} {
514 ::tk::console::MatchPair %W
\( \) promptEnd
517 bind PostConsole
<Key-bracketright
> {
518 if {"\\" ne
[%W get insert-2c
]} {
519 ::tk::console::MatchPair %W
\[ \] promptEnd
522 bind PostConsole
<Key-braceright
> {
523 if {"\\" ne
[%W get insert-2c
]} {
524 ::tk::console::MatchPair %W
\{ \} promptEnd
527 bind PostConsole
<Key-quotedbl
> {
528 if {"\\" ne
[%W get insert-2c
]} {
529 ::tk::console::MatchQuote %W promptEnd
533 bind PostConsole
<KeyPress
> {
535 ::tk::console::TagProc %W
541 # ::tk::ConsoleInsert --
542 # Insert a string into a text at the point of the insertion cursor.
543 # If there is a selection in the text, and it covers the point of the
544 # insertion cursor, then delete the selection before inserting. Insertion
545 # is restricted to the prompt area.
548 # w - The text window in which to insert the string
549 # s - The string to insert (usually just a single character)
551 proc ::tk::ConsoleInsert {w s
} {
556 if {[$w compare sel.first
<= insert
]
557 && [$w compare sel.last
>= insert
]} {
558 $w tag remove sel sel.first promptEnd
559 $w delete sel.first sel.last
562 if {[$w compare insert
< promptEnd
]} {
563 $w mark
set insert end
565 $w insert insert
$s {input stdin
}
569 # ::tk::ConsoleOutput --
571 # This routine is called directly by ConsolePutsCmd to cause a string
572 # to be displayed in the console.
575 # dest - The output tag to be used: either "stderr" or "stdout".
576 # string - The string to be displayed.
578 proc ::tk::ConsoleOutput {dest
string} {
580 $w insert output
$string $dest
581 ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
585 # ::tk::ConsoleExit --
587 # This routine is called by ConsoleEventProc when the main window of
588 # the application is destroyed. Don't call exit - that probably already
589 # happened. Just delete our window.
594 proc ::tk::ConsoleExit {} {
598 # ::tk::ConsoleAbout --
600 # This routine displays an About box to show Tcl/Tk version info.
605 proc ::tk::ConsoleAbout {} {
606 tk_messageBox -type ok
-message "[mc {Tcl for Windows}]
608 Tcl $::tcl_patchLevel
612 # ::tk::console::TagProc --
614 # Tags a procedure in the console if it's recognized
615 # This procedure is not perfect. However, making it perfect wastes
616 # too much CPU time...
619 # w - console text widget
621 proc ::tk::console::TagProc w
{
622 if {!$::tk::console::magicKeys} { return }
623 set exp
"\[^\\\\\]\[\[ \t\n\r\;{}\"\$\]"
624 set i
[$w search
-backwards -regexp $exp insert-1c promptEnd-1c
]
625 if {$i eq
""} {set i promptEnd
} else {append i
+2c
}
626 regsub -all "\[\[\\\\\\?\\*\]" [$w get
$i "insert-1c wordend"] {\\\0} c
627 if {[llength [EvalAttached
[list info commands
$c]]]} {
628 $w tag add
proc $i "insert-1c wordend"
630 $w tag remove
proc $i "insert-1c wordend"
632 if {[llength [EvalAttached
[list info vars
$c]]]} {
633 $w tag add var
$i "insert-1c wordend"
635 $w tag remove var
$i "insert-1c wordend"
639 # ::tk::console::MatchPair --
641 # Blinks a matching pair of characters
642 # c2 is assumed to be at the text index 'insert'.
643 # This proc is really loopy and took me an hour to figure out given
644 # all possible combinations with escaping except for escaped \'s.
645 # It doesn't take into account possible commenting... Oh well. If
646 # anyone has something better, I'd like to see/use it. This is really
647 # only efficient for small contexts.
650 # w - console text widget
651 # c1 - first char of pair
652 # c2 - second char of pair
654 # Calls: ::tk::console::Blink
656 proc ::tk::console::MatchPair {w c1 c2
{lim
1.0}} {
657 if {!$::tk::console::magicKeys} { return }
658 if {[set ix
[$w search
-back $c1 insert
$lim]] ne
""} {
660 [string match
{\\} [$w get
$ix-1c
]] &&
661 [set ix
[$w search
-back $c1 $ix-1c
$lim]] ne
""
667 while {[set i0
[$w search
$c2 $i0 $i1]] ne
""} {
669 if {[string match
{\\} [$w get
$i0-2c
]]} continue
674 while {$j && [set ix
[$w search
-back $c1 $ix $lim]] ne
""} {
675 if {[string match
{\\} [$w get
$ix-1c
]]} continue
679 if {[string match
{} $ix]} { set ix
[$w index
$lim] }
680 } else { set ix
[$w index
$lim] }
681 if {$::tk::console::blinkRange} {
682 Blink
$w $ix [$w index insert
]
684 Blink
$w $ix $ix+1c
[$w index insert-1c
] [$w index insert
]
688 # ::tk::console::MatchQuote --
690 # Blinks between matching quotes.
691 # Blinks just the quote if it's unmatched, otherwise blinks quoted string
692 # The quote to match is assumed to be at the text index 'insert'.
695 # w - console text widget
697 # Calls: ::tk::console::Blink
699 proc ::tk::console::MatchQuote {w
{lim
1.0}} {
700 if {!$::tk::console::magicKeys} { return }
703 while {[set i
[$w search
-back \" $i $lim]] ne
""} {
704 if {[string match
{\\} [$w get
$i-1c
]]} continue
709 if {$::tk::console::blinkRange} {
710 Blink
$w $i0 [$w index insert
]
712 Blink
$w $i0 $i0+1c
[$w index insert-1c
] [$w index insert
]
715 Blink
$w [$w index insert-1c
] [$w index insert
]
719 # ::tk::console::Blink --
721 # Blinks between n index pairs for a specified duration.
724 # w - console text widget
725 # i1 - start index to blink region
726 # i2 - end index of blink region
727 # dur - duration in usecs to blink for
730 # blinks selected characters in $w
732 proc ::tk::console::Blink {w args
} {
733 eval [list $w tag add blink
] $args
734 after $::tk::console::blinkTime [list $w] tag remove blink
$args
737 # ::tk::console::ConstrainBuffer --
739 # This limits the amount of data in the text widget
740 # Called by Prompt and ConsoleOutput
743 # w - console text widget
744 # size - # of lines to constrain to
747 # may delete data in console widget
749 proc ::tk::console::ConstrainBuffer {w size
} {
750 if {[$w index end
] > $size} {
751 $w delete
1.0 [expr {int
([$w index end
])-$size}].0
755 # ::tk::console::Expand --
758 # ARGS: w - text widget in which to expand str
759 # type - type of expansion (path / proc / variable)
761 # Calls: ::tk::console::Expand(Pathname|Procname|Variable)
763 # Outputs: The string to match is expanded to the longest possible match.
764 # If ::tk::console::showMatches is non-zero and the longest match
765 # equaled the string to expand, then all possible matches are
766 # output to stdout. Triggers bell if no matches are found.
768 # Returns: number of matches found
770 proc ::tk::console::Expand {w
{type
""}} {
771 set exp
"\[^\\\\\]\[\[ \t\n\r\\\{\"\\\\\$\]"
772 set tmp
[$w search
-backwards -regexp $exp insert-1c promptEnd-1c
]
773 if {$tmp eq
""} {set tmp promptEnd
} else {append tmp
+2c
}
774 if {[$w compare
$tmp >= insert
]} { return }
775 set str
[$w get
$tmp insert
]
777 path
* { set res
[ExpandPathname
$str] }
778 proc* { set res
[ExpandProcname
$str] }
779 var
* { set res
[ExpandVariable
$str] }
782 foreach t
{Pathname Procname Variable
} {
783 if {![catch {Expand
$t $str} res
] && ($res ne
"")} { break }
787 set len
[llength $res]
789 set repl
[lindex $res 0]
790 $w delete
$tmp insert
791 $w insert
$tmp $repl {input stdin
}
792 if {($len > 1) && $::tk::console::showMatches && $repl eq
$str} {
793 puts stdout
[lsort [lreplace $res 0 0]]
799 # ::tk::console::ExpandPathname --
801 # Expand a file pathname based on $str
802 # This is based on UNIX file name conventions
805 # str - partial file pathname to expand
807 # Calls: ::tk::console::ExpandBestMatch
809 # Returns: list containing longest unique match followed by all the
810 # possible further matches
812 proc ::tk::console::ExpandPathname str
{
813 set pwd [EvalAttached
pwd]
814 if {[catch {EvalAttached
[list cd [file dirname
$str]]} err
]} {
815 return -code error $err
817 set dir
[file tail
$str]
818 ## Check to see if it was known to be a directory and keep the trailing
819 ## slash if so (file tail cuts it off)
820 if {[string match
*/ $str]} { append dir
/ }
821 if {[catch {lsort [EvalAttached
[list glob $dir*]]} m
]} {
824 if {[llength $m] > 1} {
826 if {[string match windows
$tcl_platform(platform
)]} {
827 ## Windows is screwy because it's case insensitive
828 set tmp
[ExpandBestMatch
[string tolower
$m] \
829 [string tolower
$dir]]
830 ## Don't change case if we haven't changed the word
831 if {[string length
$dir]==[string length
$tmp]} {
835 set tmp
[ExpandBestMatch
$m $dir]
837 if {[string match ?
*/* $str]} {
838 set tmp
[file dirname
$str]/$tmp
839 } elseif
{[string match
/* $str]} {
842 regsub -all { } $tmp {\\ } tmp
843 set match
[linsert $m 0 $tmp]
845 ## This may look goofy, but it handles spaces in path names
847 if {[file isdir
$match]} {append match
/}
848 if {[string match ?
*/* $str]} {
849 set match
[file dirname
$str]/$match
850 } elseif
{[string match
/* $str]} {
853 regsub -all { } $match {\\ } match
854 ## Why is this one needed and the ones below aren't!!
855 set match
[list $match]
858 EvalAttached
[list cd $pwd]
862 # ::tk::console::ExpandProcname --
864 # Expand a tcl proc name based on $str
867 # str - partial proc name to expand
869 # Calls: ::tk::console::ExpandBestMatch
871 # Returns: list containing longest unique match followed by all the
872 # possible further matches
874 proc ::tk::console::ExpandProcname str
{
875 set match
[EvalAttached
[list info commands
$str*]]
876 if {[llength $match] == 0} {
877 set ns
[EvalAttached
\
878 "namespace children \[namespace current\] [list $str*]"]
879 if {[llength $ns]==1} {
880 set match
[EvalAttached
[list info commands
${ns
}::*]]
885 if {[llength $match] > 1} {
886 regsub -all { } [ExpandBestMatch
$match $str] {\\ } str
887 set match
[linsert $match 0 $str]
889 regsub -all { } $match {\\ } match
894 # ::tk::console::ExpandVariable --
896 # Expand a tcl variable name based on $str
899 # str - partial tcl var name to expand
901 # Calls: ::tk::console::ExpandBestMatch
903 # Returns: list containing longest unique match followed by all the
904 # possible further matches
906 proc ::tk::console::ExpandVariable str
{
907 if {[regexp {([^
\(]*)\((.
*)} $str junk ary str
]} {
908 ## Looks like they're trying to expand an array.
909 set match
[EvalAttached
[list array names
$ary $str*]]
910 if {[llength $match] > 1} {
911 set vars
$ary\([ExpandBestMatch
$match $str]
912 foreach var
$match {lappend vars
$ary\($var\)}
914 } elseif
{[llength $match] == 1} {
915 set match
$ary\($match\)
917 ## Space transformation avoided for array names.
919 set match
[EvalAttached
[list info vars
$str*]]
920 if {[llength $match] > 1} {
921 regsub -all { } [ExpandBestMatch
$match $str] {\\ } str
922 set match
[linsert $match 0 $str]
924 regsub -all { } $match {\\ } match
930 # ::tk::console::ExpandBestMatch --
932 # Finds the best unique match in a list of names.
933 # The extra $e in this argument allows us to limit the innermost loop a little
934 # further. This improves speed as $l becomes large or $e becomes long.
937 # l - list to find best unique match in
938 # e - currently best known unique match
940 # Returns: longest unique match in the list
942 proc ::tk::console::ExpandBestMatch {l
{e
{}}} {
944 if {[llength $l]>1} {
945 set e
[string length
$e]; incr e
-1
946 set ei
[string length
$ec]; incr ei
-1
948 while {$ei>=$e && [string first
$ec $l]} {
949 set ec
[string range
$ec 0 [incr ei
-1]]
956 # now initialize the console