home *** CD-ROM | disk | FTP | other *** search
/ PCNET 2006 September - Disc 1 / PCNET_CD_2006_09.iso / linux / puppy-barebones-2.01r2.iso / pup_201.sfs / usr / lib / tk8.5 / console.tcl < prev    next >
Encoding:
Text File  |  2006-06-17  |  26.6 KB  |  1,015 lines

  1. # console.tcl --
  2. #
  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
  5. # for shells.
  6. #
  7. # RCS: @(#) $Id: console.tcl,v 1.31 2006/01/25 18:22:04 dgp Exp $
  8. #
  9. # Copyright (c) 1995-1997 Sun Microsystems, Inc.
  10. # Copyright (c) 1998-2000 Ajuba Solutions.
  11. #
  12. # See the file "license.terms" for information on usage and redistribution
  13. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14. #
  15.  
  16. # TODO: history - remember partially written command
  17.  
  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
  24.  
  25.     variable inPlugin [info exists embed_args]
  26.     variable defaultPrompt   ; # default prompt if tcl_prompt1 isn't used
  27.  
  28.  
  29.     if {$inPlugin} {
  30.     set defaultPrompt {subst {[history nextid] % }}
  31.     } else {
  32.     set defaultPrompt {subst {([file tail [pwd]]) [history nextid] % }}
  33.     }
  34. }
  35.  
  36. # simple compat function for tkcon code added for this console
  37. interp alias {} EvalAttached {} consoleinterp eval
  38.  
  39. # ::tk::ConsoleInit --
  40. # This procedure constructs and configures the console windows.
  41. #
  42. # Arguments:
  43. #     None.
  44.  
  45. proc ::tk::ConsoleInit {} {
  46.     global tcl_platform
  47.  
  48.     if {![consoleinterp eval {set tcl_interactive}]} {
  49.     wm withdraw .
  50.     }
  51.  
  52.     if {[tk windowingsystem] eq "aqua"} {
  53.     set mod "Cmd"
  54.     } else {
  55.     set mod "Ctrl"
  56.     }
  57.  
  58.     if {[catch {menu .menubar} err]} {
  59.     bgerror "INIT: $err"
  60.     }
  61.     AmpMenuArgs .menubar add cascade -label [mc &File] -menu .menubar.file
  62.     AmpMenuArgs .menubar add cascade -label [mc &Edit] -menu .menubar.edit
  63.  
  64.     menu .menubar.file -tearoff 0
  65.     AmpMenuArgs .menubar.file add command -label [mc "&Source..."] \
  66.         -command {tk::ConsoleSource}
  67.     AmpMenuArgs .menubar.file add command -label [mc "&Hide Console"] \
  68.         -command {wm withdraw .}
  69.     AmpMenuArgs .menubar.file add command -label [mc "&Clear Console"] \
  70.         -command {.console delete 1.0 "promptEnd linestart"}
  71.     if {[tk windowingsystem] eq "aqua"} {
  72.     AmpMenuArgs .menubar.file add command \
  73.         -label [mc &Quit] -command {exit} -accel "Cmd-Q"
  74.     } else {
  75.     AmpMenuArgs .menubar.file add command -label [mc E&xit] -command {exit}
  76.     }
  77.  
  78.     menu .menubar.edit -tearoff 0
  79.     AmpMenuArgs    .menubar.edit add command -label [mc Cu&t]   -accel "$mod+X"\
  80.         -command {event generate .console <<Cut>>}
  81.     AmpMenuArgs    .menubar.edit add command -label [mc &Copy]  -accel "$mod+C"\
  82.         -command {event generate .console <<Copy>>}
  83.     AmpMenuArgs    .menubar.edit add command -label [mc P&aste] -accel "$mod+V"\
  84.         -command {event generate .console <<Paste>>}
  85.  
  86.     if {$tcl_platform(platform) ne "windows"} {
  87.     AmpMenuArgs .menubar.edit add command -label [mc Cl&ear] \
  88.         -command {event generate .console <<Clear>>}
  89.     } else {
  90.     AmpMenuArgs .menubar.edit add command -label [mc &Delete] \
  91.         -command {event generate .console <<Clear>>} -accel "Del"
  92.  
  93.     AmpMenuArgs .menubar add cascade -label [mc &Help] -menu .menubar.help
  94.     menu .menubar.help -tearoff 0
  95.     AmpMenuArgs .menubar.help add command -label [mc &About...] \
  96.         -command tk::ConsoleAbout
  97.     }
  98.  
  99.     . configure -menu .menubar
  100.  
  101.     set con [text .console -yscrollcommand [list .sb set] -setgrid true]
  102.     scrollbar .sb -command [list $con yview]
  103.     pack .sb -side right -fill both
  104.     pack $con -fill both -expand 1 -side left
  105.     switch -exact $tcl_platform(platform) {
  106.     "windows" {
  107.         $con configure -font systemfixed
  108.     }
  109.     "unix" {
  110.         if {[tk windowingsystem] eq "aqua"} {
  111.         $con configure -font {Monaco 9 normal} -highlightthickness 0
  112.         }
  113.     }
  114.     }
  115.  
  116.     ConsoleBind $con
  117.  
  118.     $con tag configure stderr    -foreground red
  119.     $con tag configure stdin    -foreground blue
  120.     $con tag configure prompt    -foreground \#8F4433
  121.     $con tag configure proc    -foreground \#008800
  122.     $con tag configure var    -background \#FFC0D0
  123.     $con tag raise sel
  124.     $con tag configure blink    -background \#FFFF00
  125.     $con tag configure find    -background \#FFFF00
  126.  
  127.     focus $con
  128.  
  129.     # Avoid listing this console in [winfo interps]
  130.     if {[info command ::send] eq "::send"} {rename ::send {}}
  131.  
  132.     wm protocol . WM_DELETE_WINDOW { wm withdraw . }
  133.     wm title . [mc "Console"]
  134.     flush stdout
  135.     $con mark set output [$con index "end - 1 char"]
  136.     tk::TextSetCursor $con end
  137.     $con mark set promptEnd insert
  138.     $con mark gravity promptEnd left
  139.  
  140.     # A variant of ConsolePrompt to avoid a 'puts' call
  141.     set w $con
  142.     set temp [$w index "end - 1 char"]
  143.     $w mark set output end
  144.     if {![consoleinterp eval "info exists tcl_prompt1"]} {
  145.     set string [EvalAttached $::tk::console::defaultPrompt]
  146.     $w insert output $string stdout
  147.     }
  148.     $w mark set output $temp
  149.     ::tk::TextSetCursor $w end
  150.     $w mark set promptEnd insert
  151.     $w mark gravity promptEnd left
  152.  
  153.     if {$tcl_platform(platform) eq "windows"} {
  154.     # Subtle work-around to erase the '% ' that tclMain.c prints out
  155.     after idle [subst -nocommand {
  156.         if {[$con get 1.0 output] eq "% "} { $con delete 1.0 output }
  157.     }]
  158.     }
  159. }
  160.  
  161. # ::tk::ConsoleSource --
  162. #
  163. # Prompts the user for a file to source in the main interpreter.
  164. #
  165. # Arguments:
  166. # None.
  167.  
  168. proc ::tk::ConsoleSource {} {
  169.     set filename [tk_getOpenFile -defaultextension .tcl -parent . \
  170.         -title [mc "Select a file to source"] \
  171.         -filetypes [list \
  172.         [list [mc "Tcl Scripts"] .tcl] \
  173.         [list [mc "All Files"] *]]]
  174.     if {$filename ne ""} {
  175.         set cmd [list source $filename]
  176.     if {[catch {consoleinterp eval $cmd} result]} {
  177.         ConsoleOutput stderr "$result\n"
  178.     }
  179.     }
  180. }
  181.  
  182. # ::tk::ConsoleInvoke --
  183. # Processes the command line input.  If the command is complete it
  184. # is evaled in the main interpreter.  Otherwise, the continuation
  185. # prompt is added and more input may be added.
  186. #
  187. # Arguments:
  188. # None.
  189.  
  190. proc ::tk::ConsoleInvoke {args} {
  191.     set ranges [.console tag ranges input]
  192.     set cmd ""
  193.     if {[llength $ranges]} {
  194.     set pos 0
  195.     while {[lindex $ranges $pos] ne ""} {
  196.         set start [lindex $ranges $pos]
  197.         set end [lindex $ranges [incr pos]]
  198.         append cmd [.console get $start $end]
  199.         incr pos
  200.     }
  201.     }
  202.     if {$cmd eq ""} {
  203.     ConsolePrompt
  204.     } elseif {[info complete $cmd]} {
  205.     .console mark set output end
  206.     .console tag delete input
  207.     set result [consoleinterp record $cmd]
  208.     if {$result ne ""} {
  209.         puts $result
  210.     }
  211.     ConsoleHistory reset
  212.     ConsolePrompt
  213.     } else {
  214.     ConsolePrompt partial
  215.     }
  216.     .console yview -pickplace insert
  217. }
  218.  
  219. # ::tk::ConsoleHistory --
  220. # This procedure implements command line history for the
  221. # console.  In general is evals the history command in the
  222. # main interpreter to obtain the history.  The variable
  223. # ::tk::HistNum is used to store the current location in the history.
  224. #
  225. # Arguments:
  226. # cmd -    Which action to take: prev, next, reset.
  227.  
  228. set ::tk::HistNum 1
  229. proc ::tk::ConsoleHistory {cmd} {
  230.     variable HistNum
  231.  
  232.     switch $cmd {
  233.         prev {
  234.         incr HistNum -1
  235.         if {$HistNum == 0} {
  236.         set cmd {history event [expr {[history nextid] -1}]}
  237.         } else {
  238.         set cmd "history event $HistNum"
  239.         }
  240.             if {[catch {consoleinterp eval $cmd} cmd]} {
  241.                 incr HistNum
  242.                 return
  243.             }
  244.         .console delete promptEnd end
  245.             .console insert promptEnd $cmd {input stdin}
  246.         }
  247.         next {
  248.         incr HistNum
  249.         if {$HistNum == 0} {
  250.         set cmd {history event [expr {[history nextid] -1}]}
  251.         } elseif {$HistNum > 0} {
  252.         set cmd ""
  253.         set HistNum 1
  254.         } else {
  255.         set cmd "history event $HistNum"
  256.         }
  257.         if {$cmd ne ""} {
  258.         catch {consoleinterp eval $cmd} cmd
  259.         }
  260.         .console delete promptEnd end
  261.         .console insert promptEnd $cmd {input stdin}
  262.         }
  263.         reset {
  264.             set HistNum 1
  265.         }
  266.     }
  267. }
  268.  
  269. # ::tk::ConsolePrompt --
  270. # This procedure draws the prompt.  If tcl_prompt1 or tcl_prompt2
  271. # exists in the main interpreter it will be called to generate the 
  272. # prompt.  Otherwise, a hard coded default prompt is printed.
  273. #
  274. # Arguments:
  275. # partial -    Flag to specify which prompt to print.
  276.  
  277. proc ::tk::ConsolePrompt {{partial normal}} {
  278.     set w .console
  279.     if {$partial eq "normal"} {
  280.     set temp [$w index "end - 1 char"]
  281.     $w mark set output end
  282.         if {[consoleinterp eval "info exists tcl_prompt1"]} {
  283.             consoleinterp eval "eval \[set tcl_prompt1\]"
  284.         } else {
  285.             puts -nonewline [EvalAttached $::tk::console::defaultPrompt]
  286.         }
  287.     } else {
  288.     set temp [$w index output]
  289.     $w mark set output end
  290.         if {[consoleinterp eval "info exists tcl_prompt2"]} {
  291.             consoleinterp eval "eval \[set tcl_prompt2\]"
  292.         } else {
  293.         puts -nonewline "> "
  294.         }
  295.     }
  296.     flush stdout
  297.     $w mark set output $temp
  298.     ::tk::TextSetCursor $w end
  299.     $w mark set promptEnd insert
  300.     $w mark gravity promptEnd left
  301.     ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
  302.     $w see end
  303. }
  304.  
  305. # ::tk::ConsoleBind --
  306. # This procedure first ensures that the default bindings for the Text
  307. # class have been defined.  Then certain bindings are overridden for
  308. # the class.
  309. #
  310. # Arguments:
  311. # None.
  312.  
  313. proc ::tk::ConsoleBind {w} {
  314.     bindtags $w [list $w Console PostConsole [winfo toplevel $w] all]
  315.  
  316.     ## Get all Text bindings into Console
  317.     foreach ev [bind Text] {
  318.     bind Console $ev [bind Text $ev]
  319.     }
  320.     ## We really didn't want the newline insertion...
  321.     bind Console <Control-Key-o> {}
  322.     ## ...or any Control-v binding (would block <<Paste>>)
  323.     bind Console <Control-Key-v> {}
  324.  
  325.     # For the moment, transpose isn't enabled until the console
  326.     # gets and overhaul of how it handles input -- hobbs
  327.     bind Console <Control-Key-t> {}
  328.  
  329.     # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
  330.     # Otherwise, if a widget binding for one of these is defined, the
  331.  
  332.     bind Console <Alt-KeyPress> {# nothing }
  333.     bind Console <Meta-KeyPress> {# nothing}
  334.     bind Console <Control-KeyPress> {# nothing}
  335.  
  336.     foreach {ev key} {
  337.     <<Console_Prev>>        <Key-Up>
  338.     <<Console_Next>>        <Key-Down>
  339.     <<Console_NextImmediate>>    <Control-Key-n>
  340.     <<Console_PrevImmediate>>    <Control-Key-p>
  341.     <<Console_PrevSearch>>        <Control-Key-r>
  342.     <<Console_NextSearch>>        <Control-Key-s>
  343.  
  344.     <<Console_Expand>>        <Key-Tab>
  345.     <<Console_Expand>>        <Key-Escape>
  346.     <<Console_ExpandFile>>        <Control-Shift-Key-F>
  347.     <<Console_ExpandProc>>        <Control-Shift-Key-P>
  348.     <<Console_ExpandVar>>        <Control-Shift-Key-V>
  349.     <<Console_Tab>>            <Control-Key-i>
  350.     <<Console_Tab>>            <Meta-Key-i>
  351.     <<Console_Eval>>        <Key-Return>
  352.     <<Console_Eval>>        <Key-KP_Enter>
  353.  
  354.     <<Console_Clear>>        <Control-Key-l>
  355.     <<Console_KillLine>>        <Control-Key-k>
  356.     <<Console_Transpose>>        <Control-Key-t>
  357.     <<Console_ClearLine>>        <Control-Key-u>
  358.     <<Console_SaveCommand>>        <Control-Key-z>
  359.     } {
  360.     event add $ev $key
  361.     bind Console $key {}
  362.     }
  363.  
  364.     bind Console <<Console_Expand>> {
  365.     if {[%W compare insert > promptEnd]} {
  366.         ::tk::console::Expand %W
  367.     }
  368.     }
  369.     bind Console <<Console_ExpandFile>> {
  370.     if {[%W compare insert > promptEnd]} {
  371.         ::tk::console::Expand %W path
  372.     }
  373.     }
  374.     bind Console <<Console_ExpandProc>> {
  375.     if {[%W compare insert > promptEnd]} {
  376.         ::tk::console::Expand %W proc
  377.     }
  378.     }
  379.     bind Console <<Console_ExpandVar>> {
  380.     if {[%W compare insert > promptEnd]} {
  381.         ::tk::console::Expand %W var
  382.     }
  383.     }
  384.     bind Console <<Console_Eval>> {
  385.     %W mark set insert {end - 1c}
  386.     tk::ConsoleInsert %W "\n"
  387.     tk::ConsoleInvoke
  388.     break
  389.     }
  390.     bind Console <Delete> {
  391.     if {{} ne [%W tag nextrange sel 1.0 end] \
  392.         && [%W compare sel.first >= promptEnd]} {
  393.         %W delete sel.first sel.last
  394.     } elseif {[%W compare insert >= promptEnd]} {
  395.         %W delete insert
  396.         %W see insert
  397.     }
  398.     }
  399.     bind Console <BackSpace> {
  400.     if {{} ne [%W tag nextrange sel 1.0 end] \
  401.         && [%W compare sel.first >= promptEnd]} {
  402.         %W delete sel.first sel.last
  403.     } elseif {[%W compare insert != 1.0] && \
  404.         [%W compare insert > promptEnd]} {
  405.         %W delete insert-1c
  406.         %W see insert
  407.     }
  408.     }
  409.     bind Console <Control-h> [bind Console <BackSpace>]
  410.  
  411.     bind Console <Home> {
  412.     if {[%W compare insert < promptEnd]} {
  413.         tk::TextSetCursor %W {insert linestart}
  414.     } else {
  415.         tk::TextSetCursor %W promptEnd
  416.     }
  417.     }
  418.     bind Console <Control-a> [bind Console <Home>]
  419.     bind Console <End> {
  420.     tk::TextSetCursor %W {insert lineend}
  421.     }
  422.     bind Console <Control-e> [bind Console <End>]
  423.     bind Console <Control-d> {
  424.     if {[%W compare insert < promptEnd]} {
  425.         break
  426.     }
  427.     %W delete insert
  428.     }
  429.     bind Console <<Console_KillLine>> {
  430.     if {[%W compare insert < promptEnd]} {
  431.         break
  432.     }
  433.     if {[%W compare insert == {insert lineend}]} {
  434.         %W delete insert
  435.     } else {
  436.         %W delete insert {insert lineend}
  437.     }
  438.     }
  439.     bind Console <<Console_Clear>> {
  440.     ## Clear console display
  441.     %W delete 1.0 "promptEnd linestart"
  442.     }
  443.     bind Console <<Console_ClearLine>> {
  444.     ## Clear command line (Unix shell staple)
  445.     %W delete promptEnd end
  446.     }
  447.     bind Console <Meta-d> {
  448.     if {[%W compare insert >= promptEnd]} {
  449.         %W delete insert {insert wordend}
  450.     }
  451.     }
  452.     bind Console <Meta-BackSpace> {
  453.     if {[%W compare {insert -1c wordstart} >= promptEnd]} {
  454.         %W delete {insert -1c wordstart} insert
  455.     }
  456.     }
  457.     bind Console <Meta-d> {
  458.     if {[%W compare insert >= promptEnd]} {
  459.         %W delete insert {insert wordend}
  460.     }
  461.     }
  462.     bind Console <Meta-BackSpace> {
  463.     if {[%W compare {insert -1c wordstart} >= promptEnd]} {
  464.         %W delete {insert -1c wordstart} insert
  465.     }
  466.     }
  467.     bind Console <Meta-Delete> {
  468.     if {[%W compare insert >= promptEnd]} {
  469.         %W delete insert {insert wordend}
  470.     }
  471.     }
  472.     bind Console <<Console_Prev>> {
  473.     tk::ConsoleHistory prev
  474.     }
  475.     bind Console <<Console_Next>> {
  476.     tk::ConsoleHistory next
  477.     }
  478.     bind Console <Insert> {
  479.     catch {tk::ConsoleInsert %W [::tk::GetSelection %W PRIMARY]}
  480.     }
  481.     bind Console <KeyPress> {
  482.     tk::ConsoleInsert %W %A
  483.     }
  484.     bind Console <F9> {
  485.     eval destroy [winfo child .]
  486.     source [file join $tk_library console.tcl]
  487.     }
  488.     if {[tk windowingsystem] eq "aqua"} {
  489.     bind Console <Command-q> {
  490.         exit
  491.     }
  492.     }
  493.     bind Console <<Cut>> {
  494.         # Same as the copy event
  495.      if {![catch {set data [%W get sel.first sel.last]}]} {
  496.         clipboard clear -displayof %W
  497.         clipboard append -displayof %W $data
  498.     }
  499.     }
  500.     bind Console <<Copy>> {
  501.      if {![catch {set data [%W get sel.first sel.last]}]} {
  502.         clipboard clear -displayof %W
  503.         clipboard append -displayof %W $data
  504.     }
  505.     }
  506.     bind Console <<Paste>> {
  507.     catch {
  508.         set clip [::tk::GetSelection %W CLIPBOARD]
  509.         set list [split $clip \n\r]
  510.         tk::ConsoleInsert %W [lindex $list 0]
  511.         foreach x [lrange $list 1 end] {
  512.         %W mark set insert {end - 1c}
  513.         tk::ConsoleInsert %W "\n"
  514.         tk::ConsoleInvoke
  515.         tk::ConsoleInsert %W $x
  516.         }
  517.     }
  518.     }
  519.  
  520.     ##
  521.     ## Bindings for doing special things based on certain keys
  522.     ##
  523.     bind PostConsole <Key-parenright> {
  524.     if {"\\" ne [%W get insert-2c]} {
  525.         ::tk::console::MatchPair %W \( \) promptEnd
  526.     }
  527.     }
  528.     bind PostConsole <Key-bracketright> {
  529.     if {"\\" ne [%W get insert-2c]} {
  530.         ::tk::console::MatchPair %W \[ \] promptEnd
  531.     }
  532.     }
  533.     bind PostConsole <Key-braceright> {
  534.     if {"\\" ne [%W get insert-2c]} {
  535.         ::tk::console::MatchPair %W \{ \} promptEnd
  536.     }
  537.     }
  538.     bind PostConsole <Key-quotedbl> {
  539.     if {"\\" ne [%W get insert-2c]} {
  540.         ::tk::console::MatchQuote %W promptEnd
  541.     }
  542.     }
  543.  
  544.     bind PostConsole <KeyPress> {
  545.     if {"%A" ne ""} {
  546.         ::tk::console::TagProc %W
  547.     }
  548.     break
  549.     }
  550. }
  551.  
  552. # ::tk::ConsoleInsert --
  553. # Insert a string into a text at the point of the insertion cursor.
  554. # If there is a selection in the text, and it covers the point of the
  555. # insertion cursor, then delete the selection before inserting.  Insertion
  556. # is restricted to the prompt area.
  557. #
  558. # Arguments:
  559. # w -        The text window in which to insert the string
  560. # s -        The string to insert (usually just a single character)
  561.  
  562. proc ::tk::ConsoleInsert {w s} {
  563.     if {$s eq ""} {
  564.     return
  565.     }
  566.     catch {
  567.     if {[$w compare sel.first <= insert] \
  568.         && [$w compare sel.last >= insert]} {
  569.         $w tag remove sel sel.first promptEnd
  570.         $w delete sel.first sel.last
  571.     }
  572.     }
  573.     if {[$w compare insert < promptEnd]} {
  574.     $w mark set insert end
  575.     }
  576.     $w insert insert $s {input stdin}
  577.     $w see insert
  578. }
  579.  
  580. # ::tk::ConsoleOutput --
  581. #
  582. # This routine is called directly by ConsolePutsCmd to cause a string
  583. # to be displayed in the console.
  584. #
  585. # Arguments:
  586. # dest -    The output tag to be used: either "stderr" or "stdout".
  587. # string -    The string to be displayed.
  588.  
  589. proc ::tk::ConsoleOutput {dest string} {
  590.     set w .console
  591.     $w insert output $string $dest
  592.     ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
  593.     $w see insert
  594. }
  595.  
  596. # ::tk::ConsoleExit --
  597. #
  598. # This routine is called by ConsoleEventProc when the main window of
  599. # the application is destroyed.  Don't call exit - that probably already
  600. # happened.  Just delete our window.
  601. #
  602. # Arguments:
  603. # None.
  604.  
  605. proc ::tk::ConsoleExit {} {
  606.     destroy .
  607. }
  608.  
  609. # ::tk::ConsoleAbout --
  610. #
  611. # This routine displays an About box to show Tcl/Tk version info.
  612. #
  613. # Arguments:
  614. # None.
  615.  
  616. proc ::tk::ConsoleAbout {} {
  617.     tk_messageBox -type ok -message "[mc {Tcl for Windows}]
  618.  
  619. Tcl $::tcl_patchLevel
  620. Tk $::tk_patchLevel"
  621. }
  622.  
  623. # ::tk::console::TagProc --
  624. #
  625. # Tags a procedure in the console if it's recognized
  626. # This procedure is not perfect.  However, making it perfect wastes
  627. # too much CPU time...
  628. #
  629. # Arguments:
  630. #    w    - console text widget
  631.  
  632. proc ::tk::console::TagProc w {
  633.     if {!$::tk::console::magicKeys} {
  634.     return
  635.     }
  636.     set exp "\[^\\\\\]\[\[ \t\n\r\;{}\"\$\]"
  637.     set i [$w search -backwards -regexp $exp insert-1c promptEnd-1c]
  638.     if {$i eq ""} {
  639.     set i promptEnd
  640.     } else {
  641.     append i +2c
  642.     }
  643.     regsub -all "\[\[\\\\\\?\\*\]" [$w get $i "insert-1c wordend"] {\\\0} c
  644.     if {[llength [EvalAttached [list info commands $c]]]} {
  645.     $w tag add proc $i "insert-1c wordend"
  646.     } else {
  647.     $w tag remove proc $i "insert-1c wordend"
  648.     }
  649.     if {[llength [EvalAttached [list info vars $c]]]} {
  650.     $w tag add var $i "insert-1c wordend"
  651.     } else {
  652.     $w tag remove var $i "insert-1c wordend"
  653.     }
  654. }
  655.  
  656. # ::tk::console::MatchPair --
  657. #
  658. # Blinks a matching pair of characters
  659. # c2 is assumed to be at the text index 'insert'.
  660. # This proc is really loopy and took me an hour to figure out given
  661. # all possible combinations with escaping except for escaped \'s.
  662. # It doesn't take into account possible commenting... Oh well.  If
  663. # anyone has something better, I'd like to see/use it.  This is really
  664. # only efficient for small contexts.
  665. #
  666. # Arguments:
  667. #    w    - console text widget
  668. #     c1    - first char of pair
  669. #     c2    - second char of pair
  670. #
  671. # Calls:    ::tk::console::Blink
  672.  
  673. proc ::tk::console::MatchPair {w c1 c2 {lim 1.0}} {
  674.     if {!$::tk::console::magicKeys} {
  675.     return
  676.     }
  677.     if {{} ne [set ix [$w search -back $c1 insert $lim]]} {
  678.     while {
  679.         [string match {\\} [$w get $ix-1c]] &&
  680.         [set ix [$w search -back $c1 $ix-1c $lim]] ne {}
  681.     } {}
  682.     set i1 insert-1c
  683.     while {$ix ne {}} {
  684.         set i0 $ix
  685.         set j 0
  686.         while {[set i0 [$w search $c2 $i0 $i1]] ne {}} {
  687.         append i0 +1c
  688.         if {[string match {\\} [$w get $i0-2c]]} {
  689.             continue
  690.         }
  691.         incr j
  692.         }
  693.         if {!$j} {
  694.         break
  695.         }
  696.         set i1 $ix
  697.         while {$j && [set ix [$w search -back $c1 $ix $lim]] ne {}} {
  698.         if {[string match {\\} [$w get $ix-1c]]} {
  699.             continue
  700.         }
  701.         incr j -1
  702.         }
  703.     }
  704.     if {[string match {} $ix]} {
  705.         set ix [$w index $lim]
  706.     }
  707.     } else {
  708.     set ix [$w index $lim]
  709.     }
  710.     if {$::tk::console::blinkRange} {
  711.     Blink $w $ix [$w index insert]
  712.     } else {
  713.     Blink $w $ix $ix+1c [$w index insert-1c] [$w index insert]
  714.     }
  715. }
  716.  
  717. # ::tk::console::MatchQuote --
  718. #
  719. # Blinks between matching quotes.
  720. # Blinks just the quote if it's unmatched, otherwise blinks quoted string
  721. # The quote to match is assumed to be at the text index 'insert'.
  722. #
  723. # Arguments:
  724. #    w    - console text widget
  725. #
  726. # Calls:    ::tk::console::Blink
  727.  
  728. proc ::tk::console::MatchQuote {w {lim 1.0}} {
  729.     if {!$::tk::console::magicKeys} {
  730.     return
  731.     }
  732.     set i insert-1c
  733.     set j 0
  734.     while {[set i [$w search -back \" $i $lim]] ne {}} {
  735.     if {[string match {\\} [$w get $i-1c]]} {
  736.         continue
  737.     }
  738.     if {!$j} {
  739.         set i0 $i
  740.     }
  741.     incr j
  742.     }
  743.     if {$j&1} {
  744.     if {$::tk::console::blinkRange} {
  745.         Blink $w $i0 [$w index insert]
  746.     } else {
  747.         Blink $w $i0 $i0+1c [$w index insert-1c] [$w index insert]
  748.     }
  749.     } else {
  750.     Blink $w [$w index insert-1c] [$w index insert]
  751.     }
  752. }
  753.  
  754. # ::tk::console::Blink --
  755. #
  756. # Blinks between n index pairs for a specified duration.
  757. #
  758. # Arguments:
  759. #    w    - console text widget
  760. #     i1    - start index to blink region
  761. #     i2    - end index of blink region
  762. #     dur    - duration in usecs to blink for
  763. #
  764. # Outputs:
  765. #    blinks selected characters in $w
  766.  
  767. proc ::tk::console::Blink {w args} {
  768.     eval [list $w tag add blink] $args
  769.     after $::tk::console::blinkTime [list $w] tag remove blink $args
  770. }
  771.  
  772. # ::tk::console::ConstrainBuffer --
  773. #
  774. # This limits the amount of data in the text widget
  775. # Called by Prompt and ConsoleOutput
  776. #
  777. # Arguments:
  778. #    w    - console text widget
  779. #    size    - # of lines to constrain to
  780. #
  781. # Outputs:
  782. #    may delete data in console widget
  783.  
  784. proc ::tk::console::ConstrainBuffer {w size} {
  785.     if {[$w index end] > $size} {
  786.     $w delete 1.0 [expr {int([$w index end])-$size}].0
  787.     }
  788. }
  789.  
  790. # ::tk::console::Expand --
  791. #
  792. # Arguments:
  793. # ARGS:    w    - text widget in which to expand str
  794. #     type    - type of expansion (path / proc / variable)
  795. #
  796. # Calls:    ::tk::console::Expand(Pathname|Procname|Variable)
  797. #
  798. # Outputs:    The string to match is expanded to the longest possible match.
  799. #        If ::tk::console::showMatches is non-zero and the longest match
  800. #        equaled the string to expand, then all possible matches are
  801. #        output to stdout.  Triggers bell if no matches are found.
  802. #
  803. # Returns:    number of matches found
  804.  
  805. proc ::tk::console::Expand {w {type ""}} {
  806.     set exp "\[^\\\\\]\[\[ \t\n\r\\\{\"\\\\\$\]"
  807.     set tmp [$w search -backwards -regexp $exp insert-1c promptEnd-1c]
  808.     if {$tmp eq ""} {
  809.     set tmp promptEnd
  810.     } else {
  811.     append tmp +2c
  812.     }
  813.     if {[$w compare $tmp >= insert]} {
  814.     return
  815.     }
  816.     set str [$w get $tmp insert]
  817.     switch -glob $type {
  818.     path* {
  819.         set res [ExpandPathname $str]
  820.     }
  821.     proc* {
  822.         set res [ExpandProcname $str]
  823.     }
  824.     var* {
  825.         set res [ExpandVariable $str]
  826.     }
  827.     default {
  828.         set res {}
  829.         foreach t {Pathname Procname Variable} {
  830.         if {![catch {Expand$t $str} res] && ($res ne "")} {
  831.             break
  832.         }
  833.         }
  834.     }
  835.     }
  836.     set len [llength $res]
  837.     if {$len} {
  838.     set repl [lindex $res 0]
  839.     $w delete $tmp insert
  840.     $w insert $tmp $repl {input stdin}
  841.     if {($len > 1) && ($::tk::console::showMatches) && ($repl eq $str)} {
  842.         puts stdout [lsort [lreplace $res 0 0]]
  843.     }
  844.     } else {
  845.     bell
  846.     }
  847.     return [incr len -1]
  848. }
  849.  
  850. # ::tk::console::ExpandPathname --
  851. #
  852. # Expand a file pathname based on $str
  853. # This is based on UNIX file name conventions
  854. #
  855. # Arguments:
  856. #    str    - partial file pathname to expand
  857. #
  858. # Calls:    ::tk::console::ExpandBestMatch
  859. #
  860. # Returns:    list containing longest unique match followed by all the
  861. #        possible further matches
  862.  
  863. proc ::tk::console::ExpandPathname str {
  864.     set pwd [EvalAttached pwd]
  865.     if {[catch {EvalAttached [list cd [file dirname $str]]} err]} {
  866.     return -code error $err
  867.     }
  868.     set dir [file tail $str]
  869.     ## Check to see if it was known to be a directory and keep the trailing
  870.     ## slash if so (file tail cuts it off)
  871.     if {[string match */ $str]} {
  872.     append dir /
  873.     }
  874.     if {[catch {lsort [EvalAttached [list glob $dir*]]} m]} {
  875.     set match {}
  876.     } else {
  877.     if {[llength $m] > 1} {
  878.         global tcl_platform
  879.         if {[string match windows $tcl_platform(platform)]} {
  880.         ## Windows is screwy because it's case insensitive
  881.         set tmp [ExpandBestMatch [string tolower $m] \
  882.             [string tolower $dir]]
  883.         ## Don't change case if we haven't changed the word
  884.         if {[string length $dir]==[string length $tmp]} {
  885.             set tmp $dir
  886.         }
  887.         } else {
  888.         set tmp [ExpandBestMatch $m $dir]
  889.         }
  890.         if {[string match ?*/* $str]} {
  891.         set tmp [file dirname $str]/$tmp
  892.         } elseif {[string match /* $str]} {
  893.         set tmp /$tmp
  894.         }
  895.         regsub -all { } $tmp {\\ } tmp
  896.         set match [linsert $m 0 $tmp]
  897.     } else {
  898.         ## This may look goofy, but it handles spaces in path names
  899.         eval append match $m
  900.         if {[file isdir $match]} {
  901.         append match /
  902.         }
  903.         if {[string match ?*/* $str]} {
  904.         set match [file dirname $str]/$match
  905.         } elseif {[string match /* $str]} {
  906.         set match /$match
  907.         }
  908.         regsub -all { } $match {\\ } match
  909.         ## Why is this one needed and the ones below aren't!!
  910.         set match [list $match]
  911.     }
  912.     }
  913.     EvalAttached [list cd $pwd]
  914.     return $match
  915. }
  916.  
  917. # ::tk::console::ExpandProcname --
  918. #
  919. # Expand a tcl proc name based on $str
  920. #
  921. # Arguments:
  922. #    str    - partial proc name to expand
  923. #
  924. # Calls:    ::tk::console::ExpandBestMatch
  925. #
  926. # Returns:    list containing longest unique match followed by all the
  927. #        possible further matches
  928.  
  929. proc ::tk::console::ExpandProcname str {
  930.     set match [EvalAttached [list info commands $str*]]
  931.     if {[llength $match] == 0} {
  932.     set ns [EvalAttached \
  933.         "namespace children \[namespace current\] [list $str*]"]
  934.     if {[llength $ns]==1} {
  935.         set match [EvalAttached [list info commands ${ns}::*]]
  936.     } else {
  937.         set match $ns
  938.     }
  939.     }
  940.     if {[llength $match] > 1} {
  941.     regsub -all { } [ExpandBestMatch $match $str] {\\ } str
  942.     set match [linsert $match 0 $str]
  943.     } else {
  944.     regsub -all { } $match {\\ } match
  945.     }
  946.     return $match
  947. }
  948.  
  949. # ::tk::console::ExpandVariable --
  950. #
  951. # Expand a tcl variable name based on $str
  952. #
  953. # Arguments:
  954. #    str    - partial tcl var name to expand
  955. #
  956. # Calls:    ::tk::console::ExpandBestMatch
  957. #
  958. # Returns:    list containing longest unique match followed by all the
  959. #        possible further matches
  960.  
  961. proc ::tk::console::ExpandVariable str {
  962.     if {[regexp {([^\(]*)\((.*)} $str -> ary str]} {
  963.     ## Looks like they're trying to expand an array.
  964.     set match [EvalAttached [list array names $ary $str*]]
  965.     if {[llength $match] > 1} {
  966.         set vars $ary\([ExpandBestMatch $match $str]
  967.         foreach var $match {
  968.         lappend vars $ary\($var\)
  969.         }
  970.         return $vars
  971.     } elseif {[llength $match] == 1} {
  972.         set match $ary\($match\)
  973.     }
  974.     ## Space transformation avoided for array names.
  975.     } else {
  976.     set match [EvalAttached [list info vars $str*]]
  977.     if {[llength $match] > 1} {
  978.         regsub -all { } [ExpandBestMatch $match $str] {\\ } str
  979.         set match [linsert $match 0 $str]
  980.     } else {
  981.         regsub -all { } $match {\\ } match
  982.     }
  983.     }
  984.     return $match
  985. }
  986.  
  987. # ::tk::console::ExpandBestMatch --
  988. #
  989. # Finds the best unique match in a list of names.
  990. # The extra $e in this argument allows us to limit the innermost loop a little
  991. # further.  This improves speed as $l becomes large or $e becomes long.
  992. #
  993. # Arguments:
  994. #    l    - list to find best unique match in
  995. #     e    - currently best known unique match
  996. #
  997. # Returns:    longest unique match in the list
  998.  
  999. proc ::tk::console::ExpandBestMatch {l {e {}}} {
  1000.     set ec [lindex $l 0]
  1001.     if {[llength $l]>1} {
  1002.     set e [expr {[string length $e] - 1}]
  1003.     set ei [expr {[string length $ec] - 1}]
  1004.     foreach l $l {
  1005.         while {$ei>=$e && [string first $ec $l]} {
  1006.         set ec [string range $ec 0 [incr ei -1]]
  1007.         }
  1008.     }
  1009.     }
  1010.     return $ec
  1011. }
  1012.  
  1013. # now initialize the console
  1014. ::tk::ConsoleInit
  1015.