- The editor starts automatically on an empty page (controlled by the autostart index in the global array).
- The name of the main window is "obfuscated" to avoid obvious name conflicts.
- The save procedure uses now a reference to the global array. I think that the previous code was broken since it did not modified dynamically the menu when serially editing several files.
package require Tk namespace eval ::pocketeditor { variable g if {![info exists g]} { array set g { autostart on mainwin ".__pe" } } namespace export e } proc ::pocketeditor::e {{name ""}} { variable g if ![winfo exists $g(mainwin)] { toplevel $g(mainwin) text $g(mainwin).t -wrap word -yscr "$g(mainwin).y set" \ -width 37 -bd 2 -undo 1 scrollbar $g(mainwin).y -com "$g(mainwin).t yview" pack $g(mainwin).t $g(mainwin).y -side left -fill y set m [menu $g(mainwin).m] $g(mainwin) config -menu $m m+ $m File Open.. ::pocketeditor::open m+ $m File Save {::pocketeditor::save ::pocketeditor::g(filename)} m+ $m File "Save as.." ::pocketeditor::save m+ $m File --- m+ $m File Eval {eval [$::pocketeditor::g(mainwin).t get 1.0 end]} m+ $m File Clear {$::pocketeditor::g(mainwin).t delete 1.0 end} m+ $m File ok {console eval {raise .; focus -force .console}} foreach i {Cut Copy Paste} { m+ $m Edit $i [list event gen $g(mainwin).t <<$i>>] } m+ $m Edit --- m+ $m Edit Undo {$g(mainwin).t edit undo} m+ $m Edit Redo {$g(mainwin).t edit redo} m+ $m Goto Top {$g(mainwin).t see 1.0} m+ $m Goto Cursor {$g(mainwin).t see insert} m+ $m Goto Bottom {$g(mainwin).t see end} $m add casc -label @ -menu [menu $m.dummy] bind $g(mainwin).t <ButtonRelease-1> {$::pocketeditor::g(mainwin).m entryconf @* -label @[$::pocketeditor::g(mainwin).t index current]; ::pocketeditor::xx} wm geo $g(mainwin) 240x189+0+25 set ::g(dir) [pwd] } if {$name ne ""} { $g(mainwin).t delete 1.0 end $g(mainwin).t insert end [::pocketeditor::get $name] wm title $g(mainwin) [file tail $name] } raise $g(mainwin) focus -force $g(mainwin).t } proc ::pocketeditor::get name { variable g if [file exists $name] { set f [::open $name] set g(filename) $name ::pocketeditor::K [read $f] [close $f] } else {::pocketeditor::corp $name} } proc ::pocketeditor::K {a b} {set a} proc ::pocketeditor::corp name { set argl {} foreach a [info args $name] { if [info default $name $a def] { lappend a $def } lappend argl $a } list proc $name $argl [info body $name] } proc ::pocketeditor::open {} { variable g e [tk_getOpenFile -initialdir $::g(dir)] } proc ::pocketeditor::save {{file_p ""}} { variable g if {$file_p eq ""} { set file [tk_getSaveFile -initialdir $::g(dir)] } else { puts "$file_p" upvar \#0 $file_p file puts "Saving into $file" } if {$file ne ""} { set ::g(dir) [file dir [file join [pwd] $file]] set f [::open $file w] puts $f [$g(mainwin).t get 1.0 "end - 1c"] close $f } } proc ::pocketeditor::m+ {m head label {cmd ""}} { if ![winfo ex $m.m$head] { $m add casc -label $head -menu [menu $m.m$head -tearoff 0] } if {$label ne "---"} { $m.m$head add command -label $label -command $cmd } else {$m.m$head add separator} } proc ::pocketeditor::xx {} { variable g $g(mainwin) config -menu "" $g(mainwin) config -menu $g(mainwin).m } package provide pocketeditor 0.1 if { [string is true $::pocketeditor::g(autostart)] } { ::pocketeditor::e }
JHJL 27/01/06: Can you give me a hint how to install this!
RS: Thanks for your interest, first of all. But consider that I tapped the e code on my cellphone, and still prefer to type
einstead of
package require pocketeditor namespace export pocketeditor::* eto finally get the editor up :^) You're right that namespaces are a good way of packaging software, and sort-of hiding internal details away, and avoiding name conflicts between different modules. But always spelling out fully-qualified names is a bit of an overkill - one design feature of namespaces is that "at home you don't need to say your family name":
namespace eval foo {...} proc foo::bar {...} { grill ... } proc foo::grill {...} { bar }will resolve grill and bar to the version in the own namespace as first choice.And, also consider the usage scope: while pocketeditor::get and pocketeditor::save are specific to this little thing, and hence deserve to live in the same namespace, other functions are not:
- m+ is generic for adding items to owned menus
- xx is just a workaround as long as eTcl can't update menu titles well
- corp is a very generic inverse of proc, can also be used e.g. to transfer procedures between interpreters
- and K finally is the most generic combinator - to draw that into the ::pocketeditor namespace would just lead to code duplication...
- packages are good for comprehensive, engineered libraries of general usability. The ones I use most often are BWidget, Img, tdom
- namespaces are, apart from being used in packages, good for wrapping smaller units not for general use (internal functions and variables), down to single objects in OO
- auto_index provides a gentler way of getting library functions. If you engineeringly start an app with a series of package requires, that code will be sourced even though it may not be used at all. With auto_index, source occurs on demand, and startup is faster.
MB: After RS and EF work, I extended the possibilities of the editor and released it as an open-source sourceforge project :http://tclrep.wiki.sourceforge.net/PocketEditor