Summary edit
Arjen Markus (12 august 2003) I wanted a simple, basic editor for young, inexperienced programmers. The thing is: any editor I know of is too general or too limited or has quirks that I do not fancy. So, what is easier than writing an editor yourself? After asking around a bit, I came up with this script.Note:- It is far from complete
- It contains things that I envisage as being a nice feature but I may be the only one
- I also use this to criticise Tk -- see the new Tk revitalisation project
Code edit
# ypedit.tcl --
# Shell procedures for Young Programmers Project:
# It defines several utility commands:
# ed - edit a file
# vw - view the contents of a file
#
package require Tk
# ypshell --
# Namespace for the commands
#
namespace eval ::ypshell {
namespace export ed vw
variable editfile
set editfile(count) 0
}
# ed --
# Edit a file
#
# Arguments:
# filename Name of the file to edit
#
# Return value:
# None
#
proc ::ypshell::ed { filename } {
::ypshell::EditFile 1 0 $filename
}
# vw --
# View a file
#
# Arguments:
# filename Name of the file to view
#
# Return value:
# None
#
proc ::ypshell::vw { filename } {
::ypshell::EditFile 0 0 $filename
}
# EditFile --
# Edit or view a file (actual procedure)
#
# Arguments:
# editable Select edit mode (1=edit, 0=view)
# newopen Allow new/open menu items (1=yes, 0=no)
# filename Name of the file to edit/view
#
# Return value:
# None
#
proc ::ypshell::EditFile { editable newopen filename } {
variable editfile
incr editfile(count)
set w .edit$editfile(count)
toplevel $w
wm withdraw .
wm title $w "Edit/view: $filename"
set mb $w.menubar
frame $mb
pack $mb -side top -fill x -pady 0
menubutton $mb.file -text File -menu $mb.file.menu -underline 0
menubutton $mb.edit -text Edit -menu $mb.edit.menu -underline 0
menubutton $mb.search -text Search -menu $mb.search.menu -underline 0
menubutton $mb.help -text Help -menu $mb.help.menu -underline 0
menu $mb.file.menu -tearoff false
menu $mb.edit.menu -tearoff false
menu $mb.search.menu -tearoff false
menu $mb.help.menu -tearoff false
pack $mb.file $mb.edit $mb.search -side left
pack $mb.help -side left ;# Platform-dependent!
#
# Set up the "File" menu
#
if { $newopen } {
if { $editable } {
$mb.file.menu add command -label New -underline 0 \
-command [list ::ypshell::NewFile]
}
$mb.file.menu add command -label Open -underline 0 \
-command [list ::ypshell::OpenFile]
$mb.file.menu add separator
}
if { $editable } {
$mb.file.menu add command -label Save -underline 0 \
-command [list ::ypshell::SaveFile $w $filename 0]
if { $newopen } {
$mb.file.menu add command -label "Save as ..." -underline 1 \
-command [list ::ypshell::SaveFile $w $filename 1]
}
$mb.file.menu add separator
}
$mb.file.menu add command -label Exit -underline 1 \
-command [list ::ypshell::ExitEdit $w $newopen $editable $filename]
#
# Set up the "Edit" menu
#
if { $editable } {
$mb.edit.menu add command -label "Undo" -underline 0 \
-command [list ::ypshell::UndoChange]
$mb.edit.menu add command -label "Redo" -underline 0 \
-command [list ::ypshell::RedoChange]
$mb.edit.menu add separator
}
$mb.edit.menu add command -label "Mark line(s)" -underline 0 \
-command [list ::ypshell::MarkLines]
$mb.edit.menu add command -label "Unmark line(s)" -underline 1 \
-command [list ::ypshell::UnmarkLines]
$mb.edit.menu add separator
$mb.edit.menu add command -label "Copy" -underline 0 \
-command [list ::ypshell::CopyBlock]
if { $editable } {
$mb.edit.menu add command -label "Paste" -underline 0 \
-command [list ::ypshell::PasteBlock]
$mb.edit.menu add separator
$mb.edit.menu add command -label "Delete" -underline 0 \
-command [list ::ypshell::DeleteBlock]
}
#
# Set up the "Search" menu
#
$mb.search.menu add command -label "Find" -underline 0 \
-command [list ::ypshell::FindText $w]
if { $editable } {
$mb.search.menu add command -label "Replace" -underline 0 \
-command [list ::ypshell::ChangeText]
}
#
# Set up the "Help" menu
#
$mb.help.menu add command -label "Overview" -underline 1 \
-command [list ::ypshell::HelpOverview]
$mb.help.menu add command -label "About" -underline 0 \
-command [list ::ypshell::AboutEdit]
#
# Create a thin separator
#
set ts $w.separator
frame $ts -height 2 -relief sunken -borderwidth 1
pack $ts -side top -fill x
#
# Create the toolbar
#
set fnt "Courier, 10"
set fnt "systemfixed"
set fixedfont "systemfixed"
set tb $w.toolbar
frame $tb -height 10
button $tb.goto -text "Go to:" -command [list ::ypshell::GotoLine $w ""]
entry $tb.lineno -textvariable ::ypshell::editfile(lineno,$w) \
-width 5 -font $fnt
button $tb.top -text "Top" -command [list ::ypshell::GotoLine $w 1]
button $tb.bottom -text "Bottom" -command [list ::ypshell::GotoLine $w end]
label $tb.empty1 -text " "
label $tb.empty2 -text " "
set ::ypshell::editfile(lineno,$w) 1
pack $tb.goto $tb.lineno $tb.empty1 $tb.top $tb.bottom $tb.empty2 -side left
button $tb.find -text "Find:" -command [list ::ypshell::FindText $w]
entry $tb.string -textvariable ::ypshell::editfile(find,$w) \
-font $fnt
set ypshell::editfile(find,$w) ""
pack $tb.goto $tb.find $tb.string -side left
pack $tb -fill x -side top
#
# Create the text widget and the scroll bars
#
set tf $w.textframe
set tw $tf.text
frame $tf
scrollbar $tf.scrollx -orient horiz -command "$tw xview"
scrollbar $tf.scrolly -command "$tw yview"
text $tw -yscrollcommand "$tf.scrolly set" \
-xscrollcommand "$tf.scrollx set" \
-font $fixedfont
grid $tw $tf.scrolly
grid $tf.scrollx x
grid $tw -sticky news
grid $tf.scrolly -sticky ns
grid $tf.scrollx -sticky ew
grid columnconfigure $tf 0 -weight 1
grid rowconfigure $tf 0 -weight 1
$tw configure -wrap none
pack $tf -fill both -side top -expand 1
set ypshell::editfile(textwidget,$w) $tw
LoadFile $tw $filename
}
# LoadFile --
# Load the file into the text widget
#
# Arguments:
# textw Text widget to use
# filename Name of the file to edit/view
#
# Return value:
# None
#
proc ::ypshell::LoadFile { textw filename } {
set infile [ open "$filename" "r" ]
while { ! [ eof $infile ] } {
gets $infile line
$textw insert end $line
$textw insert end "\n"
}
close $infile
}
# SaveFile --
# Save the file (possibly under a different name)
#
# Arguments:
# w Main widget holding the text
# filename Name of the file to edit/view
# newname Ask for a new name or not
#
# Return value:
# None
#
proc ::ypshell::SaveFile { w filename newname } {
variable editfile
set tw $editfile(textwidget,$w)
# Select a new file name -- TODO
set outfile [ open "$filename" "w" ]
set lineno 1
while { [$tw compare $lineno.0 < end] } {
puts $outfile [$tw get "$lineno.0" "$lineno.0 lineend"]
incr lineno
}
close $outfile
}
# GotoLine --
# Go to a specified line number
#
# Arguments:
# w Main widget containing the text widget
# pos Position
#
# Return value:
# None
#
proc ::ypshell::GotoLine { w pos } {
variable editfile
set tw $editfile(textwidget,$w)
if { $pos == "" } {
set pos $editfile(lineno,$w)
}
if { $pos == "end" } {
$tw mark set current "end linestart"
} else {
$tw mark set current "$pos.0"
}
$tw mark set insert [$tw index current]
$tw see current
focus $tw
}
# FindText --
# Find a text string
#
# Arguments:
# w Main widget containing the text widget
#
# Return value:
# None
#
proc ::ypshell::FindText { w } {
variable editfile
set string $editfile(find,$w)
set tw $editfile(textwidget,$w)
if { $string != "" } {
set newpos [$editfile(textwidget,$w) search -forwards -exact -- $string "insert + 1 chars"]
if { $newpos != "" } {
$tw mark set current $newpos
$tw mark set insert [$tw index current]
$tw see current
focus $tw
}
}
}
# ExitEdit --
# Exit and save the file (if wanted)
#
# Arguments:
# w Widget from which it is called
# editable Select edit mode (1=edit, 0=view)
# newopen Allow new/open menu items (1=yes, 0=no)
# filename Name of the file to edit/view
#
# Return value:
# None
#
proc ::ypshell::ExitEdit { w editable newopen filename } {
if { $editable } {
if { !$newopen } {
SaveFile $w $filename 0
} else {
# Ask whether to save or not
}
}
destroy $w
}
#
# Simple test code
#
namespace import ::ypshell::ed
namespace import ::ypshell::vw
ed [file join [file dirname [info script]] ypedit.tcl]
vw [file join [file dirname [info script]] ypedit.tcl]Comments edit
(2003-08-12): minor change -- made the calls at the end relative to the script location. (Later) added wm withdraw . to get rid of the empty toplevel.AM There is a rather annoying flaw in my way of setting up the menu bar and the menus - this causes most of the grieve (as pointed out by DKF): you better use the menu command, not the frame and menubars that I originally used.Paul Kienzle (2003-10-12): changed -fill x to -fill both so text box resizesSee also A minimal editor for short code that might be educational reading for kids and notebook editor

