# jedit_modes.tcl - mode-handling procedures for jedit, a tk-based editor
#
######################################################################
# Copyright 1992-1995 by Jay Sekora.  This file may be freely        #
# distributed, modified or unmodified, for any purpose, provided     #
# that this copyright notice is retained verbatim in all copies and  #
# no attempt is made to obscure the authorship of this file.  If you #
# distribute any modified versions, I ask, but do not require, that  #
# you clearly mark any changes you make as such and that you provide #
# your users with instructions for getting the original sources.     #
######################################################################

# TO DO
#   ELIMINATE REDUNDANCY!  both in the code and in what's done when a mode
#     is entered (I think prefs are being read more than once on startup).
#   file_modes panel
#   problem with filename getting set when you cancel Save 
#     for the first time on a new unnamed file
######################################################################

######################################################################
# jedit:guess_mode f - guess mode based on filename f
######################################################################

proc jedit:guess_mode { f } {
  j:debug "jedit:guess_mode $f"
  global FILE_MODES LINE_MODES
  
  #
  # first, try matching on name
  #
  foreach i $FILE_MODES {
    if [string match [lindex $i 0] $f] {
      return [lindex $i 1]
    }
  }
  #
  # then, check first line (might be a script)
  #
  if {[file exists $f]} {
    set line1 ""			;# in case file not readable
    catch {
      set file [open $f {r}]
      set line1 [read $file 80]		;# unix sees 32 chars, but be generous
      close $file
    }
    foreach i $LINE_MODES {
      if [string match [lindex $i 0] $line1] {
        return [lindex $i 1]
      }
    }
  }
  #
  # no matches - just use `plain'
  #
  return plain
}

######################################################################
# jedit:read_mode_prefs m - read prefs in $JEDIT_MODEPREFS for mode m
#   Note that the defaults _can't_ be in $jstools_library/jeditmodes .
######################################################################

proc jedit:read_mode_prefs { {m plain} } {
  j:debug "Reading mode prefs for mode $m."
  global JEDIT_MODEPREFS HOME
  j:read_prefs -array JEDIT_MODEPREFS -prefix $m \
    -directory $HOME/.tk/jeditmodes -file ${m}-defaults {
    {textfont default}
    {textwidth 80}
    {textheight 24}
    {textwrap char}
    {sabbrev 0}
    {dabbrev 0}
    {autobreak 0}
    {autoindent 0}
    {parenflash 0}
    {savestate 0}
    {buttonbar 1}
    {buttons {
      jedit:cmd:done
      jedit:cmd:save
      jedit:cmd:load
      jedit:cmd:print
    }}
    {docs {}}
    {menu,editor 1}
    {menu,file 1}
    {menu,edit 1}
    {menu,prefs 0}
    {menu,abbrev 1}
    {menu,filter 1}
    {menu,format 0}
    {menu,mode1 0}
    {menu,mode2 0}
    {menu,user 1}
    {menu,help 1}
  }
}

######################################################################
# jedit:set_default_mode_prefs mode -
#   set defaults for all mode-specific preferences, so that failure
#   of a mode to specify a particular preference doesn't trigger
#   "no such variable" errors.  doesn't actually read a file.
######################################################################

proc jedit:set_default_mode_prefs { mode } {
  global JEDIT_MODEPREFS
  
  j:default JEDIT_MODEPREFS($mode,textfont) default
  j:default JEDIT_MODEPREFS($mode,textwidth) 80
  j:default JEDIT_MODEPREFS($mode,textheight) 24
  j:default JEDIT_MODEPREFS($mode,textwrap) char
  j:default JEDIT_MODEPREFS($mode,sabbrev) 0
  j:default JEDIT_MODEPREFS($mode,dabbrev) 0
  j:default JEDIT_MODEPREFS($mode,autobreak) 0
  j:default JEDIT_MODEPREFS($mode,autoindent) 0
  j:default JEDIT_MODEPREFS($mode,autoindent) 0
  j:default JEDIT_MODEPREFS($mode,parenflash) 0
  j:default JEDIT_MODEPREFS($mode,buttonbar) 1
  j:default JEDIT_MODEPREFS($mode,buttons) {
    jedit:cmd:done
    jedit:cmd:save
    jedit:cmd:load
    jedit:cmd:print
  }
  j:default JEDIT_MODEPREFS($mode,docs) {}
  j:default JEDIT_MODEPREFS($mode,menu,editor) 1
  j:default JEDIT_MODEPREFS($mode,menu,file) 1
  j:default JEDIT_MODEPREFS($mode,menu,edit) 1
  j:default JEDIT_MODEPREFS($mode,menu,prefs) 0
  j:default JEDIT_MODEPREFS($mode,menu,abbrev) 1
  j:default JEDIT_MODEPREFS($mode,menu,filter) 1
  j:default JEDIT_MODEPREFS($mode,menu,format) 0
  j:default JEDIT_MODEPREFS($mode,menu,mode1) 0
  j:default JEDIT_MODEPREFS($mode,menu,mode2) 0
  j:default JEDIT_MODEPREFS($mode,menu,user) 1
  j:default JEDIT_MODEPREFS($mode,menu,help) 1
}

######################################################################
# mode:plain:init - setup for plain mode
#   the presence of this proc guarantees that jedit won't ever need
#   to look for a "plain-mode.tcl" file.  (the same technique could
#   be used by applications that embed jedit and need to modify its
#   behaviour.)
######################################################################

proc mode:plain:init { t } {
  global JEDIT_MODEPREFS
  
  j:read_prefs -array JEDIT_MODEPREFS -prefix plain \
    -directory ~/.tk/jeditmodes -file plain-defaults {
    {textfont default}
    {textwidth 80}
    {textheight 24}
    {textwrap char}
    {sabbrev 0}
    {dabbrev 0}
    {autobreak 0}
    {autoindent 0}
    {parenflash 0}
    {savestate 0}
    {buttonbar 1}
    {buttons {
      jedit:cmd:done
      jedit:cmd:save
      jedit:cmd:load
      jedit:cmd:print
    }}
    {docs {}}
    {menu,editor 1}
    {menu,file 1}
    {menu,edit 1}
    {menu,prefs 0}
    {menu,abbrev 1}
    {menu,filter 1}
    {menu,format 0}
    {menu,mode1 0}
    {menu,mode2 0}
    {menu,user 1}
    {menu,help 1}
  }
}

######################################################################
# jedit:apply_mode -  apply current mode for window (menus, etc.)
# the window can be specified either as a text widget, or as that
# text widget's corresponding toplevel window.
######################################################################

proc jedit:apply_mode { w } {
  j:debug "jedit:apply_mode $w"
  global HOME JEDIT_MODEPREFS tk_library jstools_library
  
  if { [winfo class $w] == "Text" } {
    set window [jedit:text_to_top $w]
    set text $w
  } else {
    set window $w
    set text [jedit:top_to_text $w]
  }
  set mode [jedit:get_mode $window]
  set menubar [jedit:top_to_menubar $window]
  set buttonbar [jedit:top_to_buttonbar $window]
  
  if [winfo exists $buttonbar] {
    destroy $buttonbar
  }
  
  foreach key {0 1 2 3 4 5 6 7 8 9} {
    bind $text <Meta-Key-$key> { }
  }
  
  jedit:set_default_mode_prefs $mode
  
  if {"x[info procs mode:${mode}:init]" == "x"} {
    # we don't already have procs to enter the mode, so
    # look through a list of directories searching for the mode file:
    #
    set file ${mode}-mode.tcl
    foreach directory [list \
      $HOME/.tk/jeditmodes \
      $jstools_library/jeditmodes \
      $jstools_library/jedit/jeditmodes \
    ] {
      if [file isfile $directory/$file] {
        j:debug "Reading $file in $directory."
        j:source_config -directory $directory $file
        break
      }
    }
  }
  catch {mode:${mode}:init $text}
  jedit:mkmenus $menubar $text
  if $JEDIT_MODEPREFS($mode,buttonbar) {
    jedit:mkbuttonbar $buttonbar $text
    pack $buttonbar -after $menubar -fill x
  }
  jedit:configure_text $text
  jedit:set_mode_label $window $mode
}

######################################################################
# set the mode a particular window is in
# the window can be specified either as a text widget, or as that
# text widget's corresponding toplevel window.
######################################################################

proc jedit:set_mode { w newmode } {
  j:debug
  global MODES HOME
  
  if { [winfo class $w] == "Text" } {
    set window [jedit:text_to_top $w]
    set text $w
  } else {
    set window $w
    set text [jedit:top_to_text $w]
  }
  
  # do any cleanup necessary to cancel effect of current mode
  set oldmode plain
  catch {set oldmode $MODES($window)}
  if {[info procs mode:$oldmode:cleanup] != {}} {
    catch {mode:$oldmode:cleanup $text}
  }
  
  set MODES($window) $newmode
}

######################################################################
# return the mode a particular window is in
# the window can be specified either as a text widget, or as that
# text widget's corresponding toplevel window.  if no mode has been
# set for that window, returns "plain".
######################################################################

proc jedit:get_mode { w } {
#  j:debug
  global MODES
  
  if { [winfo class $w] == "Text" } {
    set window [jedit:text_to_top $w]
#    set text $w
  } else {
    set window $w
#    set text [jedit:top_to_text $w]
  }
  
  if [info exists MODES($window)] {
    return $MODES($window)
  } else {
    return {plain}
  }
}




