Since TclTutor is a Tk based program, using a menu to select lessons is an obvious choice. In the course of developing TclTutor, I've used several techniques for building that menu.
The first, most obvious technique for building a menu is simply to hard-code a set of menu objects. This leads to almost immediate disaster in a package that is constantly being extended with new lessons. I never bothered trying this.
The next obvious technique is to keep the list of lessons and the text to display in each menu item in a table, either within the program, or in a separate file. I've used this technique with success in other projects where the menus changed less frequently, but the idea of constantly modifying the table to keep it in sync with the constantly changing lessons made this a very unattractive option for TclTutor.
This lead me to the idea of examining each lesson file, and extracting the necessary data from each file to build a menu.
The TclTutor lesson format includes a string near the beginning of each lesson with a description of the lesson. This string resembles:
:TITLE: Introducing a title line
Since I wanted to display the TITLE description as the text in each menu item the obvious solution was to extract this line from each lesson file.
Tom Phelps [Phelps95] pointed out that specific purpose programs tend to run more quickly than interpreted programs like Tcl. So, the first construct I used to build the menus resembled this:
for {set i 0} {[file exists Tcl$i.lsn]} {incr i} {
set file Tcl$i.lsn
set title [exec grep ":TITLE:" $file]
$menu add -label [string range 7 end]
}
The problem with this technique is that it got exceedingly slow once there were more than 10 lessons.
At this point, I revisited the idea of table driven menus with the following code to automatically generate the table:
exec grep ":TITLE:" [glob Tcl*.lsn] >Tcl.table
Once the table file existed, it could be read and filtered through some tcl code to sort the resulting list, parse the title string and file name, and add the items to the menu.
This construct stood me in good stead for several iterations of the TclTutor package, until Tcl 7.5 became available and I ported TclTutor to MS Windows. At this point the reliance on grep became somewhat of a liability.
The need to run without grep caused me to re-examine the option of extracting the :TITLE: information from each of the lesson files using a Tcl proc. I realized that Tom Phelp's observation was that it's faster to use a special purpose compiled program than a Tcl scripts when iterating through an entire file. However, the TclTutor lessons have the :TITLE: line very close to the beginning, which allows the loop to terminate long before the entire file is read.
The code to get the list of strings to place in the lesson selection menu currently resembles this:
;;#######################################################################
;;# proc makeLessonIndex
;;# Replaces the grep/sort combo in a platform independent manner.
;;#
proc makeLessonIndex {} {
global tutorGlobalList; eval "global $tutorGlobalList";
set filelist [glob "$tutorGlobals(lessonDir)/$tutorGlobals(courseName)*.lsn"]
foreach file $filelist {
set infl [open $file "r"];
set gottitle 0;
while {![eof $infl]} {
set len [gets $infl line]
if {[string first TITLE $line] > 0} {
lappend titlelist "$file:$line"
break;
}
}
close $infl;
}
return $titlelist;
}
This code performs slightly more slowly than reading a configuration file, but is quite adequate. It is much faster than invoking separate copies of grep to examine the each file.