#!/afs/ece/usr/tcl/bin/wish -f
# The next line is executed by most shells, but not Tcl \
wish $0 $*

#
# Script to make Elsbeth text editor from Els, a bare-bones file browser.
#

set All_Tools {focuth commandeth iterath windowth resizeth multh}
set Class_Tools {browseth edith filebrowseth fileth gridth searcheth completh
		 marketh painth scrolleth parenth taggeth}
set Widget_Tools {paragrath tclth cth lispth htmlth}

set Number_Of_Frames 4

set Elsbeth_Help {

The Elsbeth Editor

Elsbeth is a complete text editor based on els, a bare-bones text browser. When
you run elsbeth, it first calls els, which takes the command-line arguments and
sets up a text window for each file specified on the command line. Elsbeth then
adds some bindings provided by the Teacher Hypertools, plus a few extras, like
help and quit. We will first describe the functionality of els (which you can
run alone), and then describe each set of bindings provided by the hypertools.

Els takes any number of command-line arguments. Arguments are divided into two
types, options and configs. For each option, Els opens a new window, the option
signifies what to load into that window. Each config modifies the Els windows
for the options that follow it. For example, typing:
	els alpha -b beta -i gamma &
is equivalent to typing:
	els alpha &
	els -b beta &
	els -b -i gamma &

Each option indicates some material to put in th e text widget of an Els window.
The following are valid options:
	0	Nothing is loaded. Useful if Els is run by another program
	X	The X Selection is copied.
	file	The contents of the file indicated by pathname. If this file
does not exist, the text widget is left blank, but the file is remembered as a
new file, so saves automatically go to that file. The first save will create the
new file.
	-	Standard input. This is useful to put Els at the end of a pipe.
		(Example: ls -l | els -)
	|cmd	Output of exec-ing cmd, just like reading an I/O pipeline.
		(Your shell may require you to place this in quotes.)

Each config indicates some modification to future options. The following are
valid configs:
 	-i 		Causes Els to keep future windows iconified.
	-t Title	Adds the next word to Els's window & icon title.
If more than one -t is specified, all the -t titles are concatenated and put
into the title, before Els's usual stuff.
	-w configs	The configs are passed on to the creation of the text
widget. Thus, for example, one could specify the size of the text widget by:
els -w "-height 4 -width 40" ...
	-c cmd		The cmd is executed as a Tcl command after startup. You 
can thereby load initial modules, such as the paragrath module by:
elsbeth -c "add_elsbeth_module paragrath" ...
	-a 		Causes els to open the new files in a new Wish
interpreter. If this option is not specified, and an els (or elsbeth) program is
already running, the new options are passed to the old elsbeth interpreter, and
the new one exits. If specified, the new interpreter ignores the old one, and
starts up windows on its files.
	-p 		Causes els to open the new files in the main window
instead of using independent toplevel windows. This allows for a 'one window
with everything' approach.
	-H		Causes els to print out a quick help description of its
command-line syntax (similar to what you're reading now). This also happens if
you call els with no command-line arguments.

The startup file checks for the existance of an elsbeth file in the user's
HOME/.th directory, and if it exists, sources it. It also checks for an .elsbeth
file in the current directory and sources it too, if it exists. This enables the
user to customize Elsbeth to his needs. For example, the user may specify when
to load various other modules, such as paragrath. In addition, elsbeth also
sources the file ~/.th/thbind or ./.thbind if they exist. (This is because it
calls thbind).
}


# Repacks all of the non-common widgets of a tool into a lower frame widget.
# Provide a button to show/hide that frame widget.
proc repack {tool i} {
  set f .tool_$i
  set f2 [set f].frame_$tool
  set w [set f2].frame
  set l [set f2].label
  set flag 0

  foreach widget [pack slaves .] {
    if {[lsearch {.buttons .o .bind .aux} $widget] >= 0} {continue}
    if {[string match ".tool_*" $widget]} {continue}

    if {!$flag} {set flag 1
      if {![winfo exists .tool_$i]} {
        frame $f
        pack $f -side top -fill x -expand no
        lower $f
      }
      frame $f2 -relief raised
      pack $f2 -side left -fill both -expand yes -padx 5 -pady 5
      lower $f2
      checkbutton $l -text "[string toupper $tool] Parameters" \
        -variable Visible($tool) -onvalue 1 -offvalue 0 \
        -command "toggle_tool $w $tool"
      pack $l -side top -fill x -expand yes
      frame $w -relief raised
    }

    if {![catch "pack info $widget" info]} {
      set index [lsearch $info "-in"]
      eval pack $widget -in $w [lreplace $info $index [expr $index+1]]
    }
  }
  return $flag
}

proc toggle_tool {w tool} {
  global Visible
  if $Visible($tool) {
    pack $w -side bottom -expand yes -fill both -padx 5 -pady 5
  } else {
    pack forget $w
}}

# Now load all
source "[file dirname [info script]]/../aux/bindings.th/makebeth.tcl"
source "[file dirname [info script]]/../aux/bind.tcl"
set Elsbeth_Bindings $Local_Bindings
set els_help $TH_Bindings_Help
set i 0
set old_help $TH_Bindings_Help
foreach tool [concat $All_Tools $Class_Tools elsbeth $Widget_Tools] {
  if {$tool == "elsbeth"} {
    append Elsbeth_Help "\n" $els_help
  } else {
    source "[file dirname [info script]]/$tool"
    catch {rename widget_bindings "[set tool]_widget_bindings"}
    catch {rename teach_code "[set tool]_teach_code"}
    catch {lappend Elsbeth_Bindings $Local_Bindings}
    if {$old_help != $TH_Bindings_Help} {
      append Elsbeth_Help "\n" $TH_Bindings_Help
    }
    set old_help $TH_Bindings_Help
    if {[repack $tool [expr $i % $Number_Of_Frames]]} {incr i}
}}
set Local_Bindings $Elsbeth_Bindings

set menu .buttons.teach.m
$menu add command -label "Widget Keybindings" -command {teach_codebindings 1 0}
$menu add command -label "Class Keybindings" -command {teach_codebindings 1 1}
$menu add command -label "Menus" -command {teach_codebindings 2 1}
$menu add command -label "Code" -command {teach_codebindings 3 1}
$menu delete "Tags"
clear_output
set Elsbeth_Flag 0 ; set Frame_Flag 0

cd $TH_Dir ; set TH_Dir [pwd]


# Redefine teach_code to teach all the tools' widget code.
proc teach_code {tools} {
  global App Widget Class
  set app $App ; set widget $Widget ; set class $Class
  foreach tool $tools {
    set App $app ; set Widget $widget ; set Class $class
    if {[info procs [set tool]_teach_code] != ""} {
      [set tool]_teach_code
}}}


# Redefine widget_bindings to teach all the tools' widget bindings.
proc widget_bindings {tools} {
  global Frame_Flag App Widget Class Bindings Main_Class TH_Dir
  if {[file exists "$TH_Dir/lib/bind.$Class.tcl"]} {
    set c $Class} else {set c Misc}
  set bindings [regexp_replace $Bindings(Makebeth,All) "%C" $c]

  set app $App ; set widget $Widget ; set class $Class
  foreach tool $tools {
    set App $app ; set Widget $widget ; set Class $class
    if {[info procs [set tool]_widget_bindings] != ""} {
      set bindings [concat $bindings [[set tool]_widget_bindings]]
  }}
  if {![catch "set Bindings(Makebeth,$Class)"]} {
    append bindings $Bindings(Makebeth,$Class)
  }
  return $bindings
}


# The binding library
proc make_library {} {
  global TH_Dir All_Bindings Bindings
  global App Widget Class Menu_Flag All_Tools Class_Tools Widget_Tools
  wm withdraw . 
  toplevel .msg ; pack [label .msg.m]
  wm title .msg "Makebeth Working" ; wm iconname .msg "Makebeth Working"
  set Widget ".makebeth" ; set Class "Button"

  .msg.m configure -text "Starting wish..." ; update
  set App ""   
  exec wish $TH_Dir/aux/makebeth.tcl &
  tkwait variable App
  send $App wm iconify .
  send $App pack \[button $Widget\]
  set bindfile [open "$TH_Dir/lib/bind.Misc.tcl" "w"]

  .msg.m configure -text "Teaching all bindings..." ; update
  set Menu_Flag 0
  if {[set bindings [widget_bindings $All_Tools]] == ""} {continue}
  clear_output
  teach_code $All_Tools
  teach_keybindings all $bindings
  puts $bindfile "# TH bindings (created by makebeth) for $Class widgets"
  puts $bindfile ""
  puts $bindfile [regexp_replace [.output get 4.0 end] $Widget "%W"]
  puts $bindfile ""

  .msg.m configure -text "Teaching all menus..." ; update
  set Menu_Flag 1
  clear_output
  teach_menubindings $bindings
  puts $bindfile "proc th_Misc_menus {w} {"
  puts $bindfile {  global TH
  if {[winfo manager $w] == "pack"} {
    set TH(Menubar,$w) "[set w]_mb"
    pack [frame $TH(Menubar,$w)] -f x -before $w -side top -anchor n
  } else {
    if {[winfo toplevel $w] == "."} {set TH(Menubar,$w) ".mb[th_gensym]"
    } else {set TH(Menubar,$w) "[winfo toplevel $w].mb[th_gensym]"}
    pack [frame $TH(Menubar,$w)] -f x -side top -anchor n -before [lindex [pack slaves [winfo toplevel $TH(Menubar,$w)]] 0]}}

  puts $bindfile "\nset code {"
  puts $bindfile [regexp_replace [.output get 4.0 end] $Widget "%W"]
  puts $bindfile "}\n"
  puts $bindfile {regsub -all "%W_mb" $code $TH(Menubar,$w) new_code
regsub -all %W $new_code $w code
eval $code}

  puts $bindfile "\n}"
  .msg.m configure -text "Cloing $Class file..." ; update
  close $bindfile
  catch {send $App exit}

  .msg.m configure -text "Making auto-index..." ; update
  auto_mkindex $TH_Dir/lib "*.tcl"

  set bindfile [open "$TH_Dir/lib/tk.tcl" "w"]
  global tk_library
  puts $bindfile "# Initialization file for TH bindings\n"
  puts $bindfile "set tk_library \{$tk_library\}"
  puts $bindfile "source \$tk_library/tk.tcl"
  puts $bindfile "set auto_path \"$TH_Dir/lib \$auto_path\""
  puts $bindfile "foreach class {Misc Scale Scrollbar Listbox Entry Canvas Text} {"
  puts $bindfile "  source \[file dirname \[info script\]\]/bind.\$class.tcl"
  puts $bindfile "}"
  puts $bindfile "th_source_local_files thbind"
  puts $bindfile ""
  close $bindfile

  foreach Class {Scrollbar Scale Listbox Canvas Entry Text} {
    .msg.m configure -text "Starting wish..." ; update
    set App ""   
    exec wish $TH_Dir/aux/makebeth.tcl &
    tkwait variable App
    send $App wm iconify .
    send $App pack \[[string tolower $Class] $Widget\]
    send $App "set auto_path \"$TH_Dir/lib \$auto_path\""
    send $App "source $TH_Dir/lib/bind.Misc.tcl"
    send $App "th_Misc_menus $Widget"
    set bindfile [open "$TH_Dir/lib/bind.$Class.tcl" "w"]

    .msg.m configure -text "Teaching $Class bindings..." ; update
    set Menu_Flag 0
    if {[set bindings [widget_bindings $Class_Tools]] == ""} {continue}
    clear_output
    teach_code $Class_Tools
    teach_keybindings $Class $bindings
    puts $bindfile "# TH bindings (created by makebeth) for $Class widgets"
    puts $bindfile ""
    puts $bindfile [regexp_replace [.output get 3.0 end] $Widget "%W"]
    puts $bindfile ""

    .msg.m configure -text "Teaching $Class menus..." ; update
    set Menu_Flag 1
    clear_output
    teach_tag_bindings
    teach_menubindings $bindings
    puts $bindfile "proc th_[set Class]_menus {w} {"
    puts $bindfile "  th_Misc_menus \$w"
    puts $bindfile "set code {"
    puts $bindfile [regexp_replace [.output get 1.0 end] $Widget "%W"]
    puts $bindfile "}\n"
    puts $bindfile {global TH
regsub -all "%W_mb" $code $TH(Menubar,$w) new_code
regsub -all %W $new_code $w code
eval $code}
    puts $bindfile "}\n\n"
    clear_output

    if {$Class == "Text"} {
      foreach tool $Widget_Tools {
        .msg.m configure -text "Copying $tool bindings..." ; update
        puts $bindfile "set TH(Module,Code,$tool) \{"
        [set tool]_teach_code
        do_loadable_bindings $bindfile [[set tool]_widget_bindings]
    }}

    .msg.m configure -text "Cloing $Class file..." ; update
    close $bindfile
    catch {send $App exit}
  }
  .msg.m configure -text "Making auto-index..." ; update
  auto_mkindex $TH_Dir/lib "*.tcl"
  destroy .msg;  wm deiconify .
}


# Teach an app our bindings
proc teach_codebindings {b class_flag} {
  if {![get_widget]} {bell ; return}
  global All_Tools Class_Tools Class Widget
  if $class_flag {set w $Class} else {set w $Widget}
  teach_all_to_widget $b $w [concat $All_Tools $Class_Tools]
}

proc teach_all_to_widget {b w tools} {
  global Menu_Flag Class Widget ; set Menu_Flag $b ; incr Menu_Flag -1
  global Bound_Classes TH_Dir 

  if {[set bindings [widget_bindings $tools]] == ""} {bell ; return}
  clear_output
  if {[file exists "$TH_Dir/lib/bind.$Class.tcl"]} {
    include_files "bind.$Class.tcl th_[set Class]_bind"
  }
  switch $b {
    1 {teach_code $tools
      teach_keybindings $w $bindings
  } 2 {
      if {[file exists "$TH_Dir/lib/bind.$Class.tcl"]} {
        do_cmd "th_[set Class]_menus $Widget\n" 0
      } else {do_cmd "th_Misc_menus $Widget\n" 0}
      teach_code $tools
      teach_tag_bindings
      teach_menubindings $bindings
}}}


# Making Elsbeth

# Creates file 'elsbeth.bindings', which contains Elsbeth's keys and menus.
proc make_elsbeth {} {
  global TH_Dir Elsbeth_Flag Elsbeth_Help All_Bindings Bindings
  global Els App Widget Class All_Tools Class_Tools Widget_Tools

# Start up els
  wm withdraw . 
  toplevel .msg ; label .msg.m ; pack .msg.m ; 
  wm title .msg "Makebeth Working" ; wm iconname .msg "Makebeth Working"
  .msg.m configure -text "Starting els..." ; update
  set send_me [concat send [list [winfo name .]] {set Els [list [winfo name .]]}]
  set Els ""
  exec wish "$TH_Dir/bin/els" -a -i -c $send_me 0 &
# this might have to be changed later!!!
  tkwait variable Els
# Els defines Cancel as Control-g, delete that, so it can be overridden.
  send $Els unset TH(Binding,Cancel)
  set App $Els
  set Elsbeth_Flag 1
  set elsbeth [open "$TH_Dir/aux/elsbeth.bindings.tcl" "w"]
  set toplevel ".syme1"
  set Widget "$toplevel.t"
  set Class Text

# Adjust a few default values
  global Special_Entries Modified_Button Show Paren_Select
  global Search_Select Modified_Button Menu Paren_Show
  set Search_Select 0 ; set Paren_Select 0 ; set Paren_Show 1
  set Modified_Button 1 ; set Show(path) 1 ; set Show(name) 1
  set l [.buttons.completions.m index last]
  for {set i 0} {$i < $l} {incr i} {set Menu(completions,$i) 0}
  completion_source_widget

# Create help file
  .msg.m configure -text "Creating help file..." ; update
  set help [open "$TH_Dir/aux/elsbeth.help" "w"]
  puts $help $Elsbeth_Help
  close $help

# Teach all bindings first, then scrap.
  .msg.m configure -text "Teaching all bindings..." ; update
  puts $elsbeth "# Elsbeth bindings (created by makebeth)\n"
  teach_all_to_widget 1 all $All_Tools
# Copyright & auto-path & basic bindings
  puts $elsbeth [.output get 1.0 2.0]
  clear_output

  do_cmd "source $TH_Dir/lib/tk.tcl\n" 0
  clear_output

# Teach Class bindings (that don't depend on the widget)
  .msg.m configure -text "Teaching Text bindings..." ; update
  teach_all_to_widget 1 Text $Class_Tools
  set mark [.output search -forward -- "bind" 1.0 end]
  puts $elsbeth [regexp_replace [.output get $mark end] $Widget "%W"]
  puts $elsbeth "\nproc elsbeth_Text_instance {w} {set code {"
  puts $elsbeth [regexp_replace [.output get 1.0 $mark] $Widget "%T"]
# Hack to make completion work in text widgets.
  puts $elsbeth "set TH(Completions,%T) {{th_word_replace %T {}}}\nset TH(Completions,Text) {}"
  puts $elsbeth "}\nregsub -all %T \$code \$w new_code"
  puts $elsbeth "uplevel #0 \$new_code\n}\n"

# Teach Instance bindings and menus
  set Modified_Button 0 ; set Show(path) 0 ; set Show(name) 0
  .msg.m configure -text "Teaching menus..." ; update
  teach_all_to_widget 2 $Widget $Class_Tools
  set menu_code [regexp_replace [.output get 2.0 end] $Widget "%M"]

  clear_output
  .msg.m configure -text "Copying Elsbeth bindings..." ; update
  puts $elsbeth "set TH(Module,Code,elsbeth) \{"
  foreach binding {Help Toggle_Menus} {
    teach_binding_code $binding}
  teach_keybindings Text $Bindings(Elsbeth)
  puts $elsbeth [regexp_replace [.output get 1.0 end] "$toplevel.t" "%W"]
  puts $elsbeth "\nth_add_menucode %T \{"
  puts $elsbeth $menu_code
  clear_output
  teach_menubindings $Bindings(Elsbeth)
  puts $elsbeth [regexp_replace [.output get 1.0 end] "$toplevel.t" "%M"]
  puts $elsbeth "\}\}\n"
  clear_output

# Finish file.
  .msg.m configure -text "Completing elsbeth.bindings..." ; update
  close $elsbeth
  set Elsbeth_Flag 0
  destroy .msg
  catch {send $App destroy .}
  wm deiconify .
}

proc do_loadable_bindings {outfile bindings} {
  global Widget
  puts $outfile [regexp_replace [.output get 1.0 end] $Widget "%T"]
  clear_output
  teach_keybindings $Widget $bindings
  puts $outfile [regexp_replace [.output get 1.0 end] $Widget "%T"]
  clear_output
  teach_menubindings $bindings
  puts $outfile "\nth_add_menucode %T \{"
  puts $outfile [regexp_replace [.output get 1.0 end] $Widget "%M"]
  clear_output
  puts $outfile "\}\}"
}


.buttons.source.menu invoke 2
.buttons.teach.m add command -label "Binding Library" -command make_library
.buttons.teach.m add command -label "Make Elsbeth" -command make_elsbeth
pack .buttons.bind_mb -side bottom -before .buttons.teach


set Help "" ; append Help {Makebeth -- Add all available TH keybindings to a widget.

This program serves to add all Elsbeth bindings provided by the Teacher
Hypertools. It runs several available hypertools, whose functions are described
below. Each function here acts as if that function had been executed in every
loaded hypertool.


Functions} $Elsbeth_Help {

Widgets of Elsbeth

Hypertool Checkbuttons

When turned on, the corresponding hypertool parameters are shown, and you can
change them, to alter the behavior of the stuff that hypertool teaches. When
turned off, the hypertool parameters get hidden once more. Only hypertools with
parameter widgets will have hypertool checkbuttons.

  Binding Libraries (off Teach Menu)

When selected, this tool generates several files in elsbeth's library, called
bind.Text.tcl, bind.Entry.tcl, and so on, as well as tk.tcl. These files
serve to assign TH bindings to any application including elsbeth). See the
README file for details on how to use these binding files.

  Make Elsbeth (off Teach menu)

When selected, this tool generates a file called elsbeth.bindings.tcl, using the
parameters and current bindings known to Elsbeth. The Elsbeth program runs els
on whatever command-line arguments are given it, and then adds the bindings and
menus to every text widget opened (as well as any new ones to get created later)
This generation process may take a minute or two. When complete, an empty text
widget with menus for the text widget are shown. You can't close the text
window, but you can play with elsbeth's functions.

} $TH_Frame_Help
