[wdb] For certain uses I need a very minimalistic shell window where Tk is not yet loaded. Below my `shell.tcl`. Purpose: (1) play around with commands, (2) with my OS (Linux) send commands to the shell. The app name is like filename: `shell.tcl`. Example: to write letter `a` to console window I use the command `send shell.tcl [list evalExpr "puts a"]`. Key sets cursor to previous command line. Key on previous command line copies line to end. License (as always) [OLL]. Have fun! ====== #!/usr/bin/wish # file: shell.tcl package require Tk tk appname shell.tcl bind [winfo class .] exit # create console window destroy .shell pack [frame .shell] -expand yes -fill both grid [text .shell.t\ -wrap none\ -font "Monospace 10"\ -yscrollcommand {.shell.v set}\ -xscrollcommand {.shell.h set}]\ [scrollbar .shell.v -orient vertical -command {.shell.t yview}]\ -sticky news grid [scrollbar .shell.h\ -orient horizontal\ -command {.shell.t xview}]\ -sticky news grid rowconfigure .shell 0 -weight 1 grid columnconfigure .shell 0 -weight 1 event add <> bind .shell.t <> { if {[.shell.t cget -wrap] eq "none"} then { .shell.t configure -wrap char grid forget .shell.h } else { .shell.t configure -wrap none grid .shell.h -sticky news } after idle [list .shell.t see insert] break } after idle "event generate .shell.t <>" .shell.t tag configure prompt -foreground blue .shell.t tag configure result -foreground green .shell.t tag configure error -foreground red bind .shell.t { apply {win {lassign [$win cget -font] font size $win configure -font [list $font [incr size 2]]}} %W } bind .shell.t { apply {win {lassign [$win cget -font] font size if {$size >= 8} then { $win configure -font [list $font [incr size -2]]}}} %W } bind .shell.t { if {[%W tag ranges sel] ne ""} then continue if {([%W get insert-1chars] eq " " && "prompt" in [%W tag names insert-2chars]) || "prompt" in [%W tag names insert-1chars]} then break } bind .shell.t { if {[apply { win { if {[$win tag ranges sel] ne ""} then { $win mark set insert sel.first $win tag remove sel 1.0 end return true } elseif { "prompt" in [$win tag names insert-1chars] || "prompt" in [$win tag names insert-2chars] } then { lassign [$win tag prevrange prompt insert+1chars 1.0] start if {[$win compare $start != 1.0]} then { $win mark set insert $start-1chars } return true } return false } } %W]} then { %W see insert break } } bind .shell.t continue bind .shell.t continue bind .shell.t { if {[%W tag ranges sel] ne ""} then continue if {"prompt" in [%W tag names insert] || ("prompt" in [%W tag names insert-1chars] && [%W get insert] eq " ") } then break } bind .shell.t { if {[%W tag ranges sel] ne ""} then { %W mark set insert sel.last %W tag remove sel 1.0 end break } elseif {"prompt" in [%W tag names insert+1chars]} then { %W mark set insert [lindex [%W tag nextrange prompt insert] end]+1chars break } } bind .shell.t continue bind .shell.t continue bind .shell.t {if {[cursorHome %W]} then break} bind .shell.t { if {[processReturnKey %W]} then break } bind .shell.t { apply { win { lassign\ [$win tag prevrange prompt "insert linestart - 1chars"] - idx if {$idx eq ""} then { set idx 1.0 } elseif {[$win get $idx] eq " "} then { append idx +1chars } $win mark set insert $idx } } %W break } proc evalInputIfComplete {{win .shell.t}} { set src [inputText $win] if {[$win compare insert+1chars == end] && [info complete $src]} then { if {[catch {set result [shell eval $src]} err]} then { message $err error } else { message $result } return true } else { return false } } proc processReturnKey {{win .shell.t}} { if {![copyCurrentLine $win]} then { $win insert insert \n "" $win see insert evalInputIfComplete $win } return true } proc message {msg {tag result} {win .shell.t}} { $win mark set insert end if {$msg ne ""} then { $win insert insert $msg $tag } prompt $win $win see insert } proc cursorHome {{win .shell.t}} { set range\ [$win tag prevrange prompt "insert lineend" "insert linestart"] if {$range eq ""} then { return false } else { lassign $range - start if {[$win get $start] eq " "} then { $win mark set insert $start+1chars } else { $win mark set insert $start } return true } } proc prompt {{win .shell.t}} { $win mark set insert end if {[$win compare "insert linestart" < "insert lineend"]} then { $win insert insert \n "" } $win insert insert "%" prompt " " $win see insert } prompt .shell.t delete 1.0 proc inputText {{win .shell.t}} { # content of last input line set promptRange [$win tag prevrange prompt end 1.0] lassign "$promptRange 0 1.0" - start if {[$win get $start] eq " "} then { set start $start+1chars } $win get $start end-1chars } proc copyCurrentLine {{win .shell.t}} { # copy current line to end of .shell.t set prev [$win tag prevrange prompt insert 1.0] if {$prev eq ""} then { set start 1.0 } else { lassign $prev - start if {[$win get $start] eq " "} then { set start $start+1chars } } set next [$win tag nextrange prompt $start end] if {$next eq ""} then { # at end of text window, so do nothing return false } else { lassign $next end0 set end $end0 set nextResultRange [$win tag nextrange result $start end] if {$nextResultRange ne ""} then { lassign $nextResultRange end1 if {[$win compare $end1 < $end]} then { set end $end1 } } set nextErrorRange [$win tag nextrange error $start end] if {$nextErrorRange ne ""} then { lassign $nextErrorRange end2 if {[$win compare $end2 < $end]} then { set end $end2 } } set line [string trim [$win get $start $end] \n] $win mark set insert end $win insert insert $line $win see insert return true } } proc shellPuts args { set t .shell.t # $t insert insert \n "" switch -exact -- [llength $args] { 1 { lassign $args arg $t insert end $arg\n result $t see insert } 2 { lassign $args how text switch -exact -- $how { -nonewline { $t insert end $text result } stdout { $t insert end $text\n result } stderr { $t insert end $text\n error } default { shell eval __puts__ $args } } } default { shell eval __puts__ $args } } } interp create shell shell eval rename puts __puts__ shell alias puts shellPuts shell eval { proc echo args {puts $args} proc aloud args {putsFlat $args; uplevel $args} proc putsFlat str {puts [regsub -all {\n\s*} $str _]} proc putsVars args { puts [concat {*}[lmap var $args {list $var [uplevel set $var]}]] } proc sourceCode proc { # return source code of procedure $proc set proc [uplevel [list namespace origin $proc]] set arglist [list ] foreach arg [info args $proc] { if {[info default $proc $arg defaultvalue]} then { lappend arglist [list [list $arg] $defaultvalue] } else { lappend arglist [list $arg] } } list proc [namespace origin $proc] $arglist [info body $proc] } proc cat file { set chan [open $file r] set result [read $chan] close $chan set result } } proc evalExpr expr { if {[catch {shell eval $expr} result]} then { message $result error } else { message $result } } # main if {$argv ne ""} then { evalExpr [lindex $argv 0] } else { .shell.t delete 1.0 end catch {.shell.t insert end [exec fortune]\n\n result} .shell.t insert end\ "Hint: Key sequence Escape, Space toggles text wrap!\n" prompt prompt } ====== <>Enter Category Here