A Minimal Hypertext Help System

D. McC: For those who want super-simple hypertext help with extremely little overhead, here's something that will do the job. It requires:

  • At least Tk 8.4, to use the "-elide" flag for hiding the link markup tags. (With Tk 8.5, you can use the elegant "-all" flag for the text searches; with Tk 8.4, you can use the clunky code I wrote to substitute for the "-all" flag. Thanks to HJG for pointing out that you get an error if you try to use the "-all" flag with Tk 8.4.)
  • A plain-text help file with uniquely named section titles (or other section identifiers), plus minimal markup for links with names that exactly replicate the section titles, like this:
 <link "Run Programs:">Run Programs</link>

 set tko [package require Tk]

 # Here's a proc to create the text box:

 proc userhelp {} {
        toplevel .uhelp
        grid [text .uhelp.tx -width 65 -height 25 -bg white \
                -yscrollcommand ".uhelp.roll set" \
                -font "times 14" -wrap word -cursor top_left_arrow] \
                -row 0 -column 0 -sticky news
        grid [scrollbar .uhelp.roll -width 12 \
                -command ".uhelp.tx yview"] -row 0 -column 1 -sticky news
        grid [button .uhelp.close -text "Close" -borderwidth 6 \
                -command {destroy .uhelp}] -row 1 -column 0 \
                -columnspan 2 -sticky news
        grid rowconfigure    .uhelp 0 -weight 1
        grid columnconfigure .uhelp 0 -weight 1

 # Here's one to find links with Tk 8.4, which doesn't have
 # the "-all" flag for text-widget searches:

 proc findlinks {what} {
        set ::present_place $::place
        catch {set ::place [.uhelp.tx search -regexp \
                -count countum "$what" "$::present_place +1c" end]}
        if {$::place ne ""} {
                lappend ::linklist $::place
                lappend ::countlist $countum
                findlinks $what
        } else {
                return [list $::linklist $::countlist]

 # Here's one to get the text widget to display links and let the user see 
 # the uniquely named sections when the links are clicked 
 # (anybody who can make this one even simpler than it is, please let me know):

 proc getlinks {} {
        # Find beginnings and ends of all links:
        if {$::tko > 8.4} {
                set linkstars [.uhelp.tx search -regexp -all \
                        -count cti "<link .+?>" 1.0 end]
                set linkends [.uhelp.tx search -regexp -all "</link>" 1.0 end]
        } else {
                # Delete this code if you don't need to work with Tk 8.4
                set ::place 1.0
                set ::linklist [list]
                set ::countlist [list]
                set starlog [findlinks "<link .+?>"]
                set linkstars [lindex $starlog 0]
                set cti [lindex $starlog end]
                set ::place 1.0
                set ::linklist [list]
                set ::countlist [list]
                set endlog [findlinks "</link>"]
                set linkends [lindex $endlog 0]
                unset ::linklist ::countlist ::present_place ::place
        # Fix the links up to work:
        for {set i 0} {$i < [llength $linkstars]} {incr i} {
                set star [lindex $linkstars $i] ; # Begin link-start tag
                set starleng [lindex $cti $i] ; # Length of link-start tag
                set starsplit [split $star "."]
                set starline [lindex $starsplit 0] ; # Line number in text
                set starchar [lindex $starsplit end] ; # Position in line
                # End of link-start tag:
                set starend $starline.[expr {$starchar + $starleng}]
                # Content of link-start tag:
                set linkstar [.uhelp.tx get $star $starend]
                set linkname [string trim $linkstar "<>"] ; # Link name
                # Tag to hide link tags:
                .uhelp.tx tag configure hide -elide 1
                .uhelp.tx tag add hide $star $starend
                # Add tag for clickable link between link-start and link-end tags:
                set finis [lindex $linkends $i]
                .uhelp.tx tag add $linkname $starend $finis
                # And one to hide the link-end tag:
                .uhelp.tx tag add hide $finis "$finis +7c"
                # Get clickable tag to look right and do things:
                .uhelp.tx tag configure $linkname -foreground blue -underline 1
                .uhelp.tx tag bind $linkname <ButtonRelease-1> {
                        # See where clicked link is:
                        set clickpos [.uhelp.tx index insert]
                        # Verify that it's really a link:
                        set tagnames [.uhelp.tx tag names $clickpos]
                        set tagplace [lsearch $tagnames "link *"]
                        if {$tagplace > -1} {
                                # If so, strip off everything but its name:
                                set tagname [lindex $tagnames $tagplace]
                                set tagend [lindex [.uhelp.tx tag range "$tagname"] end]
                                set searchname [string map "{link } {} {\"} {}" $tagname]
                                # And find where the name appears in the help-file text:
                                set target [.uhelp.tx search "$searchname" $tagend \
                                if {$target ne ""} {
                                        .uhelp.tx see $target

 # And here's an example of a proc for getting an application to invoke the help system:

 proc comhelp {fn} {
        wm title .uhelp "WISH Command Center - User Help"
        set helpfile [open $fn r]
        set helpcontents [read $helpfile]
        close $helpfile
        .uhelp.tx insert 1.0 $helpcontents

 # Test (obviously, substitute your directory path first!):
 comhelp "/home/david/9.com/wish/suite/comhelp_link.txt"

HJG I don't see how those section titles in the helpfile should marked up.

MG Perhaps you could post the contents of comhelp_link.txt here, too, so we can see exactly what the demo/example at the bottom should look like?

D. McC: Nov 16 2005 - OK, here goes. This is from the forthcoming version 0.5 of WISH Command Center, so you can't actually download it from my web page quite yet, even though it says you can. Remember, you saw it here first. :o)


 WISH Command Center 0.5
 by David McClamrock <[email protected]>

 Available for download at "Pa Penguin's Icebox"

 WISH Command Center is a simple program launcher written in Tcl/Tk. 
 You can run it from the Linux command line by typing "wishcom &" 
 (without the quotes), or create a menu item for it. It comes with a 
 sample list of programs; you can add or delete program names, and you 
 can sort the list alphabetically.

 Here's what WISH Command Center can do:

 <link "Run Programs:">Run Programs</link>
 <link "Configure:">Configure</link> window appearance
 <link "Auto-Select:">Auto-Select</link> programs to run
 <link "Add:">Add</link> program listings
 <link "Edit:">Edit</link> program listings
 <link "Delete Listing(s):">Delete</link> selected program listing(s)
 <link "Sort List:">Sort List</link> of program listings
 <link "KILL:">KILL</link> a program that isn't working right
 <link "Quit:">Quit</link> doing anything for you

 Run Programs:  To run a single program that's on your system and in 
 your "path" (a list of directories that are automatically searched 
 for programs), just double-click a list item with the left mouse 
 button or single-click with the right button. You can also 
 single-click an item and then click the Run button or hit Enter. If 
 WISH Command Center can't find the program and run it, you'll get a 
 friendly error message.

 To run several programs at once, hold down Control and click the 
 names of all the programs to select them; then release Control and 
 click Run or hit Enter.

 Configure:  There's not a lot to configure in WISH Command Center 
 (other than what programs you want to run), but this button will open 
 up a box to let you determine (1) what colors will appear in the 
 program window and (2) whether the time and date will appear on the 

 In the box, you'll see sliders to change the proportions of red, 
 green, and blue, and a button to display the color. The sliders go 
 from 0 (none) to 255 (maximum). There's also a listbox containing 
 color names; you can right-click or double left-click to select a 
 color, and then modify it with the sliders if you wish. The 
 color-display button displays the hexadecimal (base 16) code for the 
 selected color in black letters if the color is light, or white ones 
 if the color is dark. For example, if you select a color with 255 
 parts red, 204 parts green, and 153 parts blue, the hexadecimal code 
 (displayed in black letters) will be "FFCC99" because "FF" in 
 hexadecimal numeration means 255, "CC" means 204, and "99" means 153.

 Below this, you'll see (1) a checkbutton to determine whether the 
 time and date will be displayed, and (2) a series of radiobuttons for 
 selecting colored things like "Window Background," next to little 
 labels that show the selected color with its name or code. If you 
 click the color-display button, its color and name or code will go 
 into whichever little label has been selected. Click "Apply" to try 
 out the selected colors, "Revert Latest" to dump the latest color you 
 selected, "Revert All" to go back to the colors you had when you 
 opened the box, or "OK" to use the selected colors.

 Auto-Select:  To prepare a list of programs to run all at once when 
 you next use WISH Command Center, click the Auto-Select button to 
 open the Auto-Select box. Select the programs you want and click the 
 "Add to List" button in the Auto-Select box; if you decide you don't 
 want one on the list after all, click Unlist. When you're done, click 
 Done; if you decide you want the list you had before, click Cancel. 
 Next time you open WISH Command Center, the names of all the programs 
 on your Auto-Select list will already be selected; then you can run 
 them all at once (or not, if you prefer).

 Add Listing:  To add one or more programs to the full list, you need 
 to know the "official name" of the program (the name you would type 
 to run the program from the command line). Click the "Add Listing" 
 button, and a box will open up where you can enter the "display name" 
 (the name that will appear in the program list, e.g., "Mandriva 
 Control Center") and the "official name" (e.g., 
 "/usr/sbin/drakconf.real"). Don't put an ampersand (&) after the 
 official name; WISH Command Center will take care of that for you. 
 Hit "Enter" or click "Add Listing" to add the listing and keep going; 
 click "Done" when you can't think of any more programs to add to the 

 Edit Listing:  To edit a program listing, select the listing 
 (single-click with the left button) and click the "Edit Listing" 
 button; the same box you added programs with will open up, and the 
 lines for the display name and the official name will be editable. 
 Click "Replace Listing" or hit "Enter" when you've edited the names 
 to your satisfaction. The box will stay open until you click "Done," 
 so you can repeat the procedure to edit more listings.

 Delete Listing(s):  To delete one or more program names from the 
 list, select the listing(s) and click "Delete Listing(s)." (This will 
 *not* delete the program from your computer, in case you might have 

 Sort List:  When you add a program listing, it will start out at the 
 bottom of the list. This is supposed to make it easy for you to find 
 and test the listing to make sure it works. When you're sure it 
 works, you'll probably want it in alphabetical order with the rest of 
 the listings. Click "Sort List" to do this. (The revised list of 
 programs will automatically be saved each time you click "Add 
 Listing," "Edit Listing," "Sort List," or "Delete Listing(s).")

 Deselect All:  Obviously, this will deselect all selected program 
 listings. To deselect all but one, click that one; the rest will 
 automatically be deselected.

 KILL:  This button will invoke the "Xkill" program to bump off a 
 program that isn't working right. Instead of a regular, mild-mannered 
 cursor, you'll get a deadly-looking skull-and-crossbones cursor. Any 
 program window this cursor touches (when you press the left mouse 
 button) will die the death, at once, with no questions asked. Then 
 the cursor will return to normal, and peace and harmony will reign 
 supreme among the programs that are still working right.

 Quit:  If you're a quitter (at least of programs you don't need any 
 more), use this button--or click the "Close" button on the titlebar, 
 if you prefer. Some programs won't shut down right if you click the 
 "Close" button, but WISH Command Center will, because it will already 
 have saved any changes right after you made them, leaving nothing to 
 be done when shutting down.

[ See also: A Hypertext Help System ]