1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150 |
- # console.tcl --
- #
- # This code constructs the console window for an application. It
- # can be used by non-unix systems that do not have built-in support
- # for shells.
- #
- # Copyright (c) 1995-1997 Sun Microsystems, Inc.
- # Copyright (c) 1998-2000 Ajuba Solutions.
- # Copyright (c) 2007-2008 Daniel A. Steffen <das@users.sourceforge.net>
- #
- # 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 useFontchooser [llength [info command ::tk::fontchooser]]
- variable inPlugin [info exists embed_args]
- variable defaultPrompt ; # default prompt if tcl_prompt1 isn't used
- if {$inPlugin} {
- set defaultPrompt {subst {[history nextid] % }}
- } else {
- set defaultPrompt {subst {([file tail [pwd]]) [history nextid] % }}
- }
- }
- # simple compat function for tkcon code added for this console
- interp alias {} EvalAttached {} consoleinterp eval
- # ::tk::ConsoleInit --
- # This procedure constructs and configures the console windows.
- #
- # Arguments:
- # None.
- proc ::tk::ConsoleInit {} {
- if {![consoleinterp eval {set tcl_interactive}]} {
- wm withdraw .
- }
- if {[tk windowingsystem] eq "aqua"} {
- set mod "Cmd"
- } else {
- set mod "Ctrl"
- }
- if {[catch {menu .menubar} err]} {
- bgerror "INIT: $err"
- }
- AmpMenuArgs .menubar add cascade -label [mc &File] -menu .menubar.file
- AmpMenuArgs .menubar add cascade -label [mc &Edit] -menu .menubar.edit
- menu .menubar.file -tearoff 0
- AmpMenuArgs .menubar.file add command -label [mc "&Source..."] \
- -command {tk::ConsoleSource}
- AmpMenuArgs .menubar.file add command -label [mc "&Hide Console"] \
- -command {wm withdraw .}
- AmpMenuArgs .menubar.file add command -label [mc "&Clear Console"] \
- -command {.console delete 1.0 "promptEnd linestart"}
- if {[tk windowingsystem] ne "aqua"} {
- AmpMenuArgs .menubar.file add command -label [mc E&xit] -command {exit}
- }
- menu .menubar.edit -tearoff 0
- AmpMenuArgs .menubar.edit add command -label [mc Cu&t] -accel "$mod+X"\
- -command {event generate .console <<Cut>>}
- AmpMenuArgs .menubar.edit add command -label [mc &Copy] -accel "$mod+C"\
- -command {event generate .console <<Copy>>}
- AmpMenuArgs .menubar.edit add command -label [mc P&aste] -accel "$mod+V"\
- -command {event generate .console <<Paste>>}
- if {[tk windowingsystem] ne "win32"} {
- AmpMenuArgs .menubar.edit add command -label [mc Cl&ear] \
- -command {event generate .console <<Clear>>}
- } else {
- AmpMenuArgs .menubar.edit add command -label [mc &Delete] \
- -command {event generate .console <<Clear>>} -accel "Del"
- AmpMenuArgs .menubar add cascade -label [mc &Help] -menu .menubar.help
- menu .menubar.help -tearoff 0
- AmpMenuArgs .menubar.help add command -label [mc &About...] \
- -command tk::ConsoleAbout
- }
- AmpMenuArgs .menubar.edit add separator
- if {$::tk::console::useFontchooser} {
- if {[tk windowingsystem] eq "aqua"} {
- .menubar.edit add command -label tk_choose_font_marker
- set index [.menubar.edit index tk_choose_font_marker]
- .menubar.edit entryconfigure $index \
- -label [mc "Show Fonts"]\
- -accelerator "$mod-T"\
- -command [list ::tk::console::FontchooserToggle]
- bind Console <<TkFontchooserVisibility>> \
- [list ::tk::console::FontchooserVisibility $index]
- ::tk::console::FontchooserVisibility $index
- } else {
- AmpMenuArgs .menubar.edit add command -label [mc "&Font..."] \
- -command [list ::tk::console::FontchooserToggle]
- }
- bind Console <FocusIn> [list ::tk::console::FontchooserFocus %W 1]
- bind Console <FocusOut> [list ::tk::console::FontchooserFocus %W 0]
- }
- AmpMenuArgs .menubar.edit add command -label [mc "&Increase Font Size"] \
- -accel "$mod++" -command {event generate .console <<Console_FontSizeIncr>>}
- AmpMenuArgs .menubar.edit add command -label [mc "&Decrease Font Size"] \
- -accel "$mod+-" -command {event generate .console <<Console_FontSizeDecr>>}
- AmpMenuArgs .menubar.edit add command -label [mc "Fit To Screen Width"] \
- -command {event generate .console <<Console_FitScreenWidth>>}
- if {[tk windowingsystem] eq "aqua"} {
- .menubar add cascade -label [mc Window] -menu [menu .menubar.window]
- .menubar add cascade -label [mc Help] -menu [menu .menubar.help]
- }
- . configure -menu .menubar
- # See if we can find a better font than the TkFixedFont
- catch {font create TkConsoleFont {*}[font configure TkFixedFont]}
- set families [font families]
- switch -exact -- [tk windowingsystem] {
- aqua { set preferred {Monaco 10} }
- win32 { set preferred {ProFontWindows 8 Consolas 8} }
- default { set preferred {} }
- }
- foreach {family size} $preferred {
- if {$family in $families} {
- font configure TkConsoleFont -family $family -size $size
- break
- }
- }
- # Provide the right border for the text widget (platform dependent).
- ::ttk::style layout ConsoleFrame {
- Entry.field -sticky news -border 1 -children {
- ConsoleFrame.padding -sticky news
- }
- }
- ::ttk::frame .consoleframe -style ConsoleFrame
- set con [text .console -yscrollcommand [list .sb set] -setgrid true \
- -borderwidth 0 -highlightthickness 0 -font TkConsoleFont]
- if {[tk windowingsystem] eq "aqua"} {
- scrollbar .sb -command [list $con yview]
- } else {
- ::ttk::scrollbar .sb -command [list $con yview]
- }
- pack .sb -in .consoleframe -fill both -side right -padx 1 -pady 1
- pack $con -in .consoleframe -fill both -expand 1 -side left -padx 1 -pady 1
- pack .consoleframe -fill both -expand 1 -side left
- ConsoleBind $con
- $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 raise sel
- $con tag configure blink -background \#FFFF00
- $con tag configure find -background \#FFFF00
- focus $con
- # Avoid listing this console in [winfo interps]
- if {[info command ::send] eq "::send"} {rename ::send {}}
- wm protocol . WM_DELETE_WINDOW { wm withdraw . }
- wm title . [mc "Console"]
- flush stdout
- $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 w $con
- set temp [$w index "end - 1 char"]
- $w mark set output end
- if {![consoleinterp eval "info exists tcl_prompt1"]} {
- set string [EvalAttached $::tk::console::defaultPrompt]
- $w insert output $string stdout
- }
- $w mark set output $temp
- ::tk::TextSetCursor $w end
- $w mark set promptEnd insert
- $w mark gravity promptEnd left
- if {[tk windowingsystem] ne "aqua"} {
- # Subtle work-around to erase the '% ' that tclMain.c prints out
- after idle [subst -nocommand {
- if {[$con get 1.0 output] eq "% "} { $con delete 1.0 output }
- }]
- }
- }
- # ::tk::ConsoleSource --
- #
- # Prompts the user for a file to source in the main interpreter.
- #
- # Arguments:
- # None.
- proc ::tk::ConsoleSource {} {
- set filename [tk_getOpenFile -defaultextension .tcl -parent . \
- -title [mc "Select a file to source"] \
- -filetypes [list \
- [list [mc "Tcl Scripts"] .tcl] \
- [list [mc "All Files"] *]]]
- if {$filename ne ""} {
- set cmd [list source $filename]
- if {[catch {consoleinterp eval $cmd} result]} {
- ConsoleOutput stderr "$result\n"
- }
- }
- }
- # ::tk::ConsoleInvoke --
- # 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.
- #
- # Arguments:
- # None.
- proc ::tk::ConsoleInvoke {args} {
- set ranges [.console tag ranges input]
- set cmd ""
- if {[llength $ranges]} {
- set pos 0
- while {[lindex $ranges $pos] ne ""} {
- set start [lindex $ranges $pos]
- set end [lindex $ranges [incr pos]]
- append cmd [.console get $start $end]
- incr pos
- }
- }
- if {$cmd eq ""} {
- ConsolePrompt
- } elseif {[info complete $cmd]} {
- .console mark set output end
- .console tag delete input
- set result [consoleinterp record $cmd]
- if {$result ne ""} {
- puts $result
- }
- ConsoleHistory reset
- ConsolePrompt
- } else {
- ConsolePrompt partial
- }
- .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.
- #
- # Arguments:
- # cmd - Which action to take: prev, next, reset.
- set ::tk::HistNum 1
- proc ::tk::ConsoleHistory {cmd} {
- variable HistNum
- switch $cmd {
- prev {
- incr HistNum -1
- if {$HistNum == 0} {
- set cmd {history event [expr {[history nextid] -1}]}
- } else {
- set cmd "history event $HistNum"
- }
- if {[catch {consoleinterp eval $cmd} cmd]} {
- incr HistNum
- return
- }
- .console delete promptEnd end
- .console insert promptEnd $cmd {input stdin}
- .console see end
- }
- next {
- incr HistNum
- if {$HistNum == 0} {
- set cmd {history event [expr {[history nextid] -1}]}
- } elseif {$HistNum > 0} {
- set cmd ""
- set HistNum 1
- } else {
- set cmd "history event $HistNum"
- }
- if {$cmd ne ""} {
- catch {consoleinterp eval $cmd} cmd
- }
- .console delete promptEnd end
- .console insert promptEnd $cmd {input stdin}
- .console see end
- }
- reset {
- set HistNum 1
- }
- }
- }
- # ::tk::ConsolePrompt --
- # 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.
- #
- # Arguments:
- # partial - Flag to specify which prompt to print.
- proc ::tk::ConsolePrompt {{partial normal}} {
- set w .console
- if {$partial eq "normal"} {
- set temp [$w index "end - 1 char"]
- $w mark set output end
- if {[consoleinterp eval "info exists tcl_prompt1"]} {
- consoleinterp eval "eval \[set tcl_prompt1\]"
- } else {
- puts -nonewline [EvalAttached $::tk::console::defaultPrompt]
- }
- } else {
- set temp [$w index output]
- $w mark set output end
- if {[consoleinterp eval "info exists tcl_prompt2"]} {
- consoleinterp eval "eval \[set tcl_prompt2\]"
- } else {
- puts -nonewline "> "
- }
- }
- flush stdout
- $w mark set output $temp
- ::tk::TextSetCursor $w end
- $w mark set promptEnd insert
- $w mark gravity promptEnd left
- ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
- $w see end
- }
- # Copy selected text from the console
- proc ::tk::console::Copy {w} {
- if {![catch {set data [$w get sel.first sel.last]}]} {
- clipboard clear -displayof $w
- clipboard append -displayof $w $data
- }
- }
- # Copies selected text. If the selection is within the current active edit
- # region then it will be cut, if not it is only copied.
- proc ::tk::console::Cut {w} {
- if {![catch {set data [$w get sel.first sel.last]}]} {
- clipboard clear -displayof $w
- clipboard append -displayof $w $data
- if {[$w compare sel.first >= output]} {
- $w delete sel.first sel.last
- }
- }
- }
- # Paste text from the clipboard
- proc ::tk::console::Paste {w} {
- catch {
- 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"
- tk::ConsoleInvoke
- tk::ConsoleInsert $w $x
- }
- }
- }
- # Fit TkConsoleFont to window width
- proc ::tk::console::FitScreenWidth {w} {
- set width [winfo screenwidth $w]
- set cwidth [$w cget -width]
- set s -50
- set fit 0
- array set fi [font configure TkConsoleFont]
- while {$s < 0} {
- set fi(-size) $s
- set f [font create {*}[array get fi]]
- set c [font measure $f "eM"]
- font delete $f
- if {$c * $cwidth < 1.667 * $width} {
- font configure TkConsoleFont -size $s
- break
- }
- incr s 2
- }
- }
- # ::tk::ConsoleBind --
- # This procedure first ensures that the default bindings for the Text
- # class have been defined. Then certain bindings are overridden for
- # the class.
- #
- # Arguments:
- # None.
- 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
- # <Keypress> class binding will also fire and insert the character
- # which is wrong.
- bind Console <Alt-KeyPress> {# nothing }
- bind Console <Meta-KeyPress> {# nothing}
- bind Console <Control-KeyPress> {# nothing}
- foreach {ev key} {
- <<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>
- <<Console_FontSizeIncr>> <Control-Key-plus>
- <<Console_FontSizeDecr>> <Control-Key-minus>
- } {
- event add $ev $key
- bind Console $key {}
- }
- if {[tk windowingsystem] eq "aqua"} {
- foreach {ev key} {
- <<Console_FontSizeIncr>> <Command-Key-plus>
- <<Console_FontSizeDecr>> <Command-Key-minus>
- } {
- event add $ev $key
- bind Console $key {}
- }
- if {$::tk::console::useFontchooser} {
- bind Console <Command-Key-t> [list ::tk::console::FontchooserToggle]
- }
- }
- 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"
- tk::ConsoleInvoke
- break
- }
- bind Console <Delete> {
- if {{} ne [%W tag nextrange sel 1.0 end] \
- && [%W compare sel.first >= promptEnd]} {
- %W delete sel.first sel.last
- } elseif {[%W compare insert >= promptEnd]} {
- %W delete insert
- %W see insert
- }
- }
- bind Console <BackSpace> {
- if {{} ne [%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]} {
- %W delete insert-1c
- %W see insert
- }
- }
- bind Console <Control-h> [bind Console <BackSpace>]
- bind Console <<LineStart>> {
- if {[%W compare insert < promptEnd]} {
- tk::TextSetCursor %W {insert linestart}
- } else {
- tk::TextSetCursor %W promptEnd
- }
- }
- bind Console <<LineEnd>> {
- tk::TextSetCursor %W {insert lineend}
- }
- bind Console <Control-d> {
- if {[%W compare insert < promptEnd]} {
- break
- }
- %W delete insert
- }
- bind Console <<Console_KillLine>> {
- if {[%W compare insert < promptEnd]} {
- break
- }
- if {[%W compare insert == {insert lineend}]} {
- %W delete insert
- } else {
- %W delete insert {insert lineend}
- }
- }
- bind Console <<Console_Clear>> {
- ## Clear console display
- %W delete 1.0 "promptEnd linestart"
- }
- bind Console <<Console_ClearLine>> {
- ## Clear command line (Unix shell staple)
- %W delete promptEnd end
- }
- bind Console <Meta-d> {
- 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-d> {
- 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 <<PrevLine>> {
- tk::ConsoleHistory prev
- }
- bind Console <<NextLine>> {
- tk::ConsoleHistory next
- }
- bind Console <Insert> {
- catch {tk::ConsoleInsert %W [::tk::GetSelection %W PRIMARY]}
- }
- bind Console <KeyPress> {
- tk::ConsoleInsert %W %A
- }
- bind Console <F9> {
- eval destroy [winfo child .]
- source -encoding utf-8 [file join $tk_library console.tcl]
- }
- if {[tk windowingsystem] eq "aqua"} {
- bind Console <Command-q> {
- exit
- }
- }
- bind Console <<Cut>> { ::tk::console::Cut %W }
- bind Console <<Copy>> { ::tk::console::Copy %W }
- bind Console <<Paste>> { ::tk::console::Paste %W }
- bind Console <<Console_FontSizeIncr>> {
- set size [font configure TkConsoleFont -size]
- if {$size < 0} {set sign -1} else {set sign 1}
- set size [expr {(abs($size) + 1) * $sign}]
- font configure TkConsoleFont -size $size
- if {$::tk::console::useFontchooser} {
- tk fontchooser configure -font TkConsoleFont
- }
- }
- bind Console <<Console_FontSizeDecr>> {
- set size [font configure TkConsoleFont -size]
- if {abs($size) < 2} { return }
- if {$size < 0} {set sign -1} else {set sign 1}
- set size [expr {(abs($size) - 1) * $sign}]
- font configure TkConsoleFont -size $size
- if {$::tk::console::useFontchooser} {
- tk fontchooser configure -font TkConsoleFont
- }
- }
- bind Console <<Console_FitScreenWidth>> {
- ::tk::console::FitScreenWidth %W
- }
- ##
- ## Bindings for doing special things based on certain keys
- ##
- bind PostConsole <Key-parenright> {
- if {"\\" ne [%W get insert-2c]} {
- ::tk::console::MatchPair %W \( \) promptEnd
- }
- }
- bind PostConsole <Key-bracketright> {
- if {"\\" ne [%W get insert-2c]} {
- ::tk::console::MatchPair %W \[ \] promptEnd
- }
- }
- bind PostConsole <Key-braceright> {
- if {"\\" ne [%W get insert-2c]} {
- ::tk::console::MatchPair %W \{ \} promptEnd
- }
- }
- bind PostConsole <Key-quotedbl> {
- if {"\\" ne [%W get insert-2c]} {
- ::tk::console::MatchQuote %W promptEnd
- }
- }
- bind PostConsole <KeyPress> {
- if {"%A" ne ""} {
- ::tk::console::TagProc %W
- }
- }
- }
- # ::tk::ConsoleInsert --
- # 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.
- #
- # Arguments:
- # 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 {$s eq ""} {
- return
- }
- catch {
- 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 mark set insert end
- }
- $w insert insert $s {input stdin}
- $w see insert
- }
- # ::tk::ConsoleOutput --
- #
- # This routine is called directly by ConsolePutsCmd to cause a string
- # to be displayed in the console.
- #
- # Arguments:
- # dest - The output tag to be used: either "stderr" or "stdout".
- # string - The string to be displayed.
- proc ::tk::ConsoleOutput {dest string} {
- set w .console
- $w insert output $string $dest
- ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
- $w see insert
- }
- # ::tk::ConsoleExit --
- #
- # 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.
- #
- # Arguments:
- # None.
- proc ::tk::ConsoleExit {} {
- destroy .
- }
- # ::tk::ConsoleAbout --
- #
- # This routine displays an About box to show Tcl/Tk version info.
- #
- # Arguments:
- # None.
- proc ::tk::ConsoleAbout {} {
- tk_messageBox -type ok -message "[mc {Tcl for Windows}]
- Tcl $::tcl_patchLevel
- Tk $::tk_patchLevel"
- }
- # ::tk::console::Fontchooser* --
- # Let the user select the console font (TIP 324).
- proc ::tk::console::FontchooserToggle {} {
- if {[tk fontchooser configure -visible]} {
- tk fontchooser hide
- } else {
- tk fontchooser show
- }
- }
- proc ::tk::console::FontchooserVisibility {index} {
- if {[tk fontchooser configure -visible]} {
- .menubar.edit entryconfigure $index -label [::tk::msgcat::mc "Hide Fonts"]
- } else {
- .menubar.edit entryconfigure $index -label [::tk::msgcat::mc "Show Fonts"]
- }
- }
- proc ::tk::console::FontchooserFocus {w isFocusIn} {
- if {$isFocusIn} {
- tk fontchooser configure -parent $w -font TkConsoleFont \
- -command [namespace code [list FontchooserApply]]
- } else {
- tk fontchooser configure -parent $w -font {} -command {}
- }
- }
- proc ::tk::console::FontchooserApply {font args} {
- catch {font configure TkConsoleFont {*}[font actual $font]}
- }
- # ::tk::console::TagProc --
- #
- # Tags a procedure in the console if it's recognized
- # This procedure is not perfect. However, making it perfect wastes
- # too much CPU time...
- #
- # Arguments:
- # 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 eq ""} {
- 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"
- } else {
- $w tag remove proc $i "insert-1c wordend"
- }
- if {[llength [EvalAttached [list info vars $c]]]} {
- $w tag add var $i "insert-1c wordend"
- } else {
- $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.
- #
- # Arguments:
- # 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 {{} ne [set ix [$w search -back $c1 insert $lim]]} {
- while {
- [string match {\\} [$w get $ix-1c]] &&
- [set ix [$w search -back $c1 $ix-1c $lim]] ne {}
- } {}
- set i1 insert-1c
- while {$ix ne {}} {
- set i0 $ix
- set j 0
- while {[set i0 [$w search $c2 $i0 $i1]] ne {}} {
- append i0 +1c
- if {[string match {\\} [$w get $i0-2c]]} {
- continue
- }
- incr j
- }
- if {!$j} {
- break
- }
- set i1 $ix
- while {$j && [set ix [$w search -back $c1 $ix $lim]] ne {}} {
- if {[string match {\\} [$w get $ix-1c]]} {
- continue
- }
- incr j -1
- }
- }
- 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]
- } else {
- 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'.
- #
- # Arguments:
- # w - console text widget
- #
- # Calls: ::tk::console::Blink
- proc ::tk::console::MatchQuote {w {lim 1.0}} {
- if {!$::tk::console::magicKeys} {
- return
- }
- set i insert-1c
- set j 0
- while {[set i [$w search -back \" $i $lim]] ne {}} {
- if {[string match {\\} [$w get $i-1c]]} {
- continue
- }
- if {!$j} {
- set i0 $i
- }
- incr j
- }
- if {$j&1} {
- if {$::tk::console::blinkRange} {
- Blink $w $i0 [$w index insert]
- } else {
- Blink $w $i0 $i0+1c [$w index insert-1c] [$w index insert]
- }
- } else {
- Blink $w [$w index insert-1c] [$w index insert]
- }
- }
- # ::tk::console::Blink --
- #
- # Blinks between n index pairs for a specified duration.
- #
- # Arguments:
- # w - console text widget
- # i1 - start index to blink region
- # i2 - end index of blink region
- # dur - duration in usecs to blink for
- #
- # Outputs:
- # 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
- #
- # Arguments:
- # w - console text widget
- # size - # of lines to constrain to
- #
- # Outputs:
- # 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 --
- #
- # Arguments:
- # 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 eq ""} {
- set tmp promptEnd
- } else {
- append tmp +2c
- }
- if {[$w compare $tmp >= insert]} {
- return
- }
- set str [$w get $tmp insert]
- switch -glob $type {
- path* {
- set res [ExpandPathname $str]
- }
- proc* {
- set res [ExpandProcname $str]
- }
- var* {
- set res [ExpandVariable $str]
- }
- default {
- set res {}
- foreach t {Pathname Procname Variable} {
- if {![catch {Expand$t $str} res] && ($res ne "")} {
- break
- }
- }
- }
- }
- set len [llength $res]
- if {$len} {
- set repl [lindex $res 0]
- $w delete $tmp insert
- $w insert $tmp $repl {input stdin}
- if {($len > 1) && ($::tk::console::showMatches) && ($repl eq $str)} {
- puts stdout [lsort [lreplace $res 0 0]]
- }
- } else {
- bell
- }
- return [incr len -1]
- }
- # ::tk::console::ExpandPathname --
- #
- # Expand a file pathname based on $str
- # This is based on UNIX file name conventions
- #
- # Arguments:
- # 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 opt]} {
- return -options $opt $err
- }
- set dir [file tail $str]
- ## 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]} {
- set match {}
- } else {
- if {[llength $m] > 1} {
- if { $::tcl_platform(platform) eq "windows" } {
- ## Windows is screwy because it's case insensitive
- set tmp [ExpandBestMatch [string tolower $m] \
- [string tolower $dir]]
- ## Don't change case if we haven't changed the word
- if {[string length $dir]==[string length $tmp]} {
- set tmp $dir
- }
- } else {
- set tmp [ExpandBestMatch $m $dir]
- }
- if {[string match ?*/* $str]} {
- set tmp [file dirname $str]/$tmp
- } elseif {[string match /* $str]} {
- set tmp /$tmp
- }
- regsub -all { } $tmp {\\ } tmp
- set match [linsert $m 0 $tmp]
- } else {
- ## This may look goofy, but it handles spaces in path names
- eval append match $m
- if {[file isdir $match]} {
- append match /
- }
- if {[string match ?*/* $str]} {
- set match [file dirname $str]/$match
- } elseif {[string match /* $str]} {
- set match /$match
- }
- regsub -all { } $match {\\ } match
- ## Why is this one needed and the ones below aren't!!
- set match [list $match]
- }
- }
- EvalAttached [list cd $pwd]
- return $match
- }
- # ::tk::console::ExpandProcname --
- #
- # Expand a tcl proc name based on $str
- #
- # Arguments:
- # 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} {
- set ns [EvalAttached \
- "namespace children \[namespace current\] [list $str*]"]
- if {[llength $ns]==1} {
- set match [EvalAttached [list info commands ${ns}::*]]
- } else {
- set match $ns
- }
- }
- if {[llength $match] > 1} {
- regsub -all { } [ExpandBestMatch $match $str] {\\ } str
- set match [linsert $match 0 $str]
- } else {
- regsub -all { } $match {\\ } match
- }
- return $match
- }
- # ::tk::console::ExpandVariable --
- #
- # Expand a tcl variable name based on $str
- #
- # Arguments:
- # 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 -> 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\)
- }
- return $vars
- } elseif {[llength $match] == 1} {
- set match $ary\($match\)
- }
- ## Space transformation avoided for array names.
- } else {
- set match [EvalAttached [list info vars $str*]]
- if {[llength $match] > 1} {
- regsub -all { } [ExpandBestMatch $match $str] {\\ } str
- set match [linsert $match 0 $str]
- } else {
- regsub -all { } $match {\\ } match
- }
- }
- return $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.
- #
- # Arguments:
- # 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 ec [lindex $l 0]
- if {[llength $l]>1} {
- set e [expr {[string length $e] - 1}]
- set ei [expr {[string length $ec] - 1}]
- foreach l $l {
- while {$ei>=$e && [string first $ec $l]} {
- set ec [string range $ec 0 [incr ei -1]]
- }
- }
- }
- return $ec
- }
- # now initialize the console
- ::tk::ConsoleInit
|