- 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


