# ts_edit.tcl
# ts internal editor
#
# string handling

proc TedNextWordOrChar {str start} {
  set str [string range $str $start end]
  regsub -all -- {\\} $str # str
  if [regexp -indices {.[a-zA-Z0-9]*[ \n\t]*[^ \t\n]} $str result] {
    return [expr [lindex $result 1] + $start]
  }
}

proc TedReadFile {w} {
  global ted params

  if {$ted($w,file) == "" || [file isdir $ted($w,file)]} {
    append ted($w,file) "##noname##"
    wm title $w "$ted($w,title) [cutdir $ted($w,file)]"
  }
  if [file exists $ted($w,file)] {
    $w.text delete 1.0 end
    set id [open $ted($w,file) r]
    $w.text insert end [read -nonewline $id]
#    while {[gets $id s]!=-1} {
#      $w.text insert end $s\n
#    }
    close $id
    if [info exists gparams(bak)] {
      if {$gparams(bak)} {
        TedSave $w [file rootname $ted($w,file)].bak
      }
    }
  }
  for {set i 1} {[$w.text compare $i.0 < end]} {incr i} {
    TedHandleTags $w [$w.text index $i.0]
  }
}

proc TedNew {w} {
  global ted

  $w.text delete 0.1 end
  set ted($w,file) ""
  TedReadFile $w
}

proc TedSave {w filename} {
  global ted

  if {$filename != ""} {
    set color [lindex [$w.save configure -foreground] 4]
    $w.save configure -foreground Red
    update idletasks
    debug "TedSave: $filename :"
    set id [open $filename w]
    for {set i 1} {[$w.text compare $i.0 < end]} {incr i} {
      set s [$w.text get $i.0 "$i.0 lineend"]
      puts $id $s
    }
    close $id
    set ted($w,stsave) 0
    $w.save configure -foreground $color
  }
}

proc TedSaveAs {w question} {
  global ted params 

  if {$question || [file tail $ted($w,file)] == "##noname##"} {
    set x [winfo rootx $w]
    set y [winfo rooty $w]
    if {![FileDialog +$x+$y "Save File" $ted($w,ext) ted($w,file)]} {
      return
    }
    debug "TedSaveAs: $ted($w,file)"
    wm title $w "$ted($w,title) [cutdir $ted($w,file)]"
    # In cause of changing filename of active edit file: correct
    set params(Edit_file) $ted($w,file)
  }
  TedSave $w $ted($w,file)
}

proc TedAskSave {w} {
  global ted  

  if $ted($w,stsave) {
    set x [winfo rootx $w]
    set y [winfo rooty $w]
    switch [Dialog .dlg +$x+$y Save \
      "Edit file $ted($w,file) has been changed. Save?" \
      warning 0 2 {Yes <Any-y>} {No <Any-n>} {Cancel}] {
      0 {TedSaveAs $w 0}
      1 {}
      2 {return 0}
    }
  }
  return 1
}

proc TedAutoSave {w} {
  global ted

  if {![winfo exists $w]} {return}
  if {$ted($w,autosave)} {
    debug "AutoSave"
    if {$ted($w,stsave)} {
      TedSaveAs $w 0
      exec sync
    }
    after $ted($w,autos_interval) [list TedAutoSave $w]
  }
}
    
proc TedExit {w} {
  global ted  

  if {![TedAskSave $w]} {return 0}
  unset ted($w,file)
  unset ted($w,ext)
  xfocus .
  catch {destroy .hint}
  destroy $w
  return 1
}

proc TedCut {w} {
  global ted

  clipboard clear
  set idx [$w.text index sel.first]
  catch {
    clipboard append [$w.text get sel.first sel.last]
    set s [$w.text get sel.first sel.last]
    set ted($w,undobuf) $s
    set ted($w,undo) \
      "$w.text insert [$w.text index sel.first] \$ted($w,undobuf)"
    $w.text delete sel.first sel.last
  }
  TedHandleTags $w $idx
  TedHandleTags $w [$w.text index insert]
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

proc TedCopy {w} {
  global ted

  clipboard clear
  catch {
    clipboard append [$w.text get sel.first sel.last]
    $w.text tag remove sel sel.first sel.last
  }
}

proc TedPaste {w} {
  global ted ted_buf 

  set idx [$w.text index insert]
  catch {
    $w.text insert insert [selection get -selection CLIPBOARD]
  }
  for {} {[$w.text compare $idx <= insert]} {set idx [$w.text index $idx+1l]} {
    TedHandleTags $w $idx
  }
  set ted($w,pos) [$w.text index insert]  
  $w.text see insert
  set ted($w,stsave) 1
}

proc TedDelMark {w} {
  global  ted

  set l [$w.text tag ranges sel]
  if {[llength $l] != 2} {return} 
  eval $w.text delete $l
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text yview -pickplace insert
}

proc TedInsSel {w} {
  global ted

  set s [selection get STRING]
  $w.text insert insert $s
  $w.text yview -pickplace insert
}

proc TedSearchDlg {w geom replace} {
  global ted_sdlg

  toplevel $w
  wm geometry $w $geom
  wm transient $w . 

  if $replace {
    set title "Search and Replace expression"
  } else {
    set title "Search expression"
  }
  wm title $w $title
   
  label $w.title -text $title
  pack $w.title -fill x

  frame $w.s
  pack $w.s -fill x
  label $w.s.l -text "Text to find" -underline 0 -width 15 -anchor w
  entry $w.s.e -textvariable ted_sdlg(search) -width 15 \
    -relief sunken -bd 1
  pack $w.s.l -side left -fill x
  pack $w.s.e -side left -fill x -expand true -padx 5
  
  frame $w.r
  if $replace {pack $w.r -fill x}
  label $w.r.l -text "New text" -underline 0 -width 15 -anchor w
  entry $w.r.e -textvariable ted_sdlg(replace) -width 15 \
    -relief sunken -bd 1
  pack $w.r.l -side left -fill x
  pack $w.r.e -side left -fill x -expand true -padx 5

  frame $w.b
  pack $w.b -side bottom -fill x

  frame $w.ex1 -bd 1 
  pack $w.ex1 -side left -fill both -expand true -pady 5

  checkbutton $w.ex1.c -text "Case sensitive" -underline 0 -anchor w \
    -variable ted_sdlg(case)
  pack $w.ex1.c -fill x -expand true
  if $replace {
    checkbutton $w.ex1.a -text "Replace all" -underline 0 -anchor w \
      -variable ted_sdlg(all)
    checkbutton $w.ex1.q -text "Prompt on replace"  -underline 0 -anchor w \
      -variable ted_sdlg(prompt)
    pack $w.ex1.a $w.ex1.q -fill x
  }

  frame $w.b.r -height 2 -bd 1 -relief sunken
  pack $w.b.r -side top -fill x -pady 2
  button $w.b.ok -text OK -command {set ted_sdlg(ok) 1} -default active
  button $w.b.cancel -text Cancel -command {set ted_sdlg(ok) 0}
  pack $w.b.ok -padx 5 -pady 2 -side left
  pack $w.b.cancel -padx 5 -pady 2 -side left

  if $replace {
    set el [list $w.s.e $w.r.e]
    bind $w.s.e <Return> "focus $w.r.e"
    bind $w.s.e <Any-Tab> "focus $w.r.e"
    bind $w.r.e <Return> "focus $w.s.e"
    bind $w.r.e <Any-Tab> "focus $w.s.e"
  } else {
    set el [list $w.s.e]
    bind $w.s.e <Return> { }
    bind $w.s.e <Tab> { }
  }
  foreach e $el {
    bind $e <Control-Return> {set ted_sdlg(ok) 1}
    bind $e <Escape> {set ted_sdlg(ok) 0}
    bind $e <Alt-Any-c> {
      set ted_sdlg(case) [expr ! $ted_sdlg(case)]
    }
    bind $e <Alt-Any-r> {
      set ted_sdlg(all) [expr ! $ted_sdlg(all)]
    }
    bind $e <Alt-Any-p> {
      set ted_sdlg(prompt) [expr ! $ted_sdlg(prompt)]
    }
    bind $e <Left> {
      set i [%W index insert]
      if {$i > 0} {incr i -1}
      %W icursor $i
    }
    bind $e <Right> {
      set i [%W index insert]
      set l [string length [%W get]]
      if {$i < $l} {incr i}
      %W icursor $i
    }
  }
  set old_focus [focus]
  focus $w.s.e
  grab $w
  tkwait variable ted_sdlg(ok)
  grab release $w
  focus $old_focus
  destroy $w
  return $ted_sdlg(ok)
} 

proc TedSearch {w} {
  global ted ted_sdlg

  set ted_sdlg(search) ""
  set ted_sdlg(case) 0
  catch {
    set ted_sdlg(search) $ted($w,s_search)
    set ted_sdlg(case) $ted($w,s_case)
  }
  set x [winfo rootx $w.text]
  set y [winfo rooty $w.text]
  if [TedSearchDlg .tedsd +$x+$y 0] {
    set ted($w,s_case)  $ted_sdlg(case)
    if $ted($w,s_case) {
      set ted($w,s_search) $ted_sdlg(search)
    } else {
      set ted($w,s_search) [string tolower $ted_sdlg(search)]
    }
    set ted($w,replace) 0
    TedReplaceNext $w
  }
}

  
proc TedReplace {w} {
  global ted ted_sdlg

  set ted_sdlg(search) ""
  set ted_sdlg(case) 0
  set ted_sdlg(prompt) 1
  set ted_sdlg(all) 0
  catch {
    set ted_sdlg(search) $ted($w,r_search)
    set ted_sdlg(replace) $ted($w,r_replace)
    set ted_sdlg(case) $ted($w,r_case)
    set ted_sdlg(prompt) $ted($w,r_prompt)
    set ted_sdlg(all) $ted($w,r_all)
  }
  set x [winfo rootx $w.text]
  set y [winfo rooty $w.text]
  if [TedSearchDlg .tedsd +$x+$y 1] {
    set ted($w,r_case)  $ted_sdlg(case)
    if $ted($w,r_case) {
      set ted($w,r_search) $ted_sdlg(search)
    } else {
      set ted($w,r_search) [string tolower $ted_sdlg(search)]
    }
    set ted($w,r_replace) $ted_sdlg(replace)
    set ted($w,r_prompt) $ted_sdlg(prompt)
    set ted($w,r_all) $ted_sdlg(all)
    set ted($w,replace) 1
    if $ted($w,r_all) {
      $w.text mark set insert 1.0
      while {[TedReplaceNext $w]} { }
    } else {
      TedReplaceNext $w
    }
  }
}

proc TedReplaceNext {w} {
  global ted

  if ![info exists ted($w,replace)] return
  if $ted($w,replace) {
    # Replace part
    if {$ted($w,r_search) == ""} return
    set search $ted($w,r_search)
    if $ted($w,r_case) {
      set case 1
    } else {
      set case 0
    }
    $w.text mark set pos [$w.text index insert]
    scan [$w.text index insert] %d i
    scan [$w.text index end] %d numLines
    while {$i < $numLines} {
      set s [$w.text get pos "pos lineend"]
      if {! $case} {
        set s [string tolower $s]
      }
      set res [string first $ted($w,r_search) $s]
      if {$res >= 0} {
        set l [string length $ted($w,r_search)]
        $w.text tag add repl "pos + $res c" \
          "pos + $res c + $l c"
        set repl 0
        if $ted($w,r_prompt) { 
	   $w.text see repl.first
           $w.question configure -text "Replace this occurance (y/n/esc)?" \
	     -fg red
	   bind $w.question <Any-y> "set ted($w,dlg_ok) 0"
	   bind $w.question <Any-n> "set ted($w,dlg_ok) 1"
	   bind $w.question <Escape> "set ted($w,dlg_ok) 2"
	   set old_focus [focus]
	   focus $w.question
	   update idletasks
	   grab $w.question
	   tkwait variable ted($w,dlg_ok)
	   grab release $w.question
	   focus $old_focus
           $w.question configure -text ""
	   bind $w.question <Any-y> {# none}
	   bind $w.question <Any-n> {# none}
	   bind $w.question <Escape> {# none}
	   set repl $ted($w,dlg_ok)
        }
        $w.text tag remove repl "pos + $res c" \
          "pos + $res c + $l c"
        if {$repl == 2} {return 0} ; # Interrupt search
        $w.text mark set insert \
          "pos + $res c + $l c"
        if {$repl == 0} {
          $w.text delete "pos + $res c" \
            "pos + $res c + $l c"
          $w.text insert "pos + $res c" $ted($w,r_replace)
          $w.text see insert
          set ted($w,stsave) 1
        } 
        return 1
      }
      incr i
      $w.text mark set pos $i.0
    }
    return 0
  } else {
    # Search part
    if {$ted($w,s_search) == ""} return
    set search $ted($w,s_search)
    if $ted($w,s_case) {
      set case 1
    } else {
      set case 0
    }
    $w.text mark set pos [$w.text index insert]
    scan [$w.text index insert] %d i
    scan [$w.text index end] %d numLines
    while {$i < $numLines} {
      set s [$w.text get pos "pos lineend"]
      if {! $case} {
        set s [string tolower $s]
      }
      set res [string first $ted($w,s_search) $s]
      if {$res >= 0} {
        $w.text mark set insert \
          "pos + $res c + [string length $ted($w,s_search)] c"
        $w.text yview -pickplace insert
        return 1
      }
      incr i
      $w.text mark set pos $i.0
    }
    return 0
  }
}

proc TedGoto {w} {
  global ted

  set r(goto) ""
  set x [winfo rootx $w.text]
  set y [winfo rooty $w.text]
  if [InpDlg r .dlg "Goto Line" +$x+$y "Goto Line" {
    {"Line:" int 4 goto}
    } r] {
    $w.text mark set insert $r(goto).0
    $w.text yview -pickplace insert
    set ted($w,pos) [$w.text index insert]
  }
}

proc TedContextHelp {w} {
  global ted hlp
  
  set s [$w.text get "insert wordstart" "insert wordend"]
  puts $s
###  set i [lsearch $hlp(idx_list) $s*]
#  if {$i < 0} {return}
#  set j $i
#  incr j
#  while {[string match "$s*" [lindex $hlp(idx_list) $j]]} {incr j}
#  incr j -1
#  if {$i < $j} {
#    set l {}
#    for {set k $i} {$k <= $j} {incr k} {
#      lappend l [lindex [split [lindex $hlp(idx_list) $k] \xff] 0]
#    }
#    if {[set k \
#      [ListDlg .hlpdia $hlp(dlg_geom) "Select Item" $l] \
#      ] > -1 } {
#      set i [expr $i + $k]
#    } else {
#      return
#    }
#  }
#  help [lindex [split [lindex $hlp(idx_list) $i] \xff] 1]
}
 
# Tag operations

proc TedChkComment {w} {
  global ted

}

proc TedHasTag {w idx tag} {
  debug "TedHasTag $idx $tag"
  set range [$w.text tag prevrange $tag $idx]
  set end [lindex $range 1]
  debug "prevrange: $range"
  if {[llength $range] == 0 || [$w.text compare $end < $idx]} {
    set range [$w.text tag nextrange $tag $idx]
    if {[llength $range] == 0 || [$w.text compare $idx < [lindex $range 0]]} {
      return 0
    }
  }
  return 1
}

# Handle Tags
# Comment: %...\n
# Environment: \begin{...} or \end{...}

proc TedHandleTags {w idx} {
  global ted

  $w.text tag remove comment "$idx linestart" "$idx lineend"
  set s [$w.text get "$idx linestart" "$idx lineend"]
  # Handle comments
  if [regexp -indices {(\\*)(%)} $s x bs pos] {
    if {([lindex $bs 1]-[lindex $bs 0]) % 2 != 0} {
      set i [lindex $pos 0]
      $w.text tag add comment "$idx linestart + $i c" "$idx lineend"
      set s [string range $s 0 [expr $i - 1]]
    }
  }
  set offset 0
  while {$s != {}} {
    # Handle commands
    if [regexp -indices \
      {\\(begin|end)\{([^\}]*)\}((\{[^\}]*\})|(\[[^]]*\])|(\([\)]*\)))*} \
      $s pos x env] {
      set i0 [expr [lindex $pos 0]+$offset]
      set i1 [expr [lindex $pos 1]+$offset+1]
      $w.text tag add env "$idx linestart + $i0 c" \
        "$idx linestart + $i1 c"
      set s [string range $s $i1 end]
      incr offset $i1
    } else {
      set s {}
    }
  }
}
  
# Insert operations

proc TedNewLine {w pos} {
  global ted

  set l [$w.text get "$pos linestart" "$pos lineend"]
  $w.text insert $pos \n
  if {$ted($w,autoind)} {
    regexp {^ *} $l spaces
    $w.text insert $pos $spaces
    while {[$w.text get $pos] == " "} {$w.text delete $pos}
  }
}

proc TedHandleWrap {w {del ""}} {
  global ted

  if {!$ted($w,wrap)} return
  set line [$w.text get "insert linestart" "insert lineend"]
  debug $line
  set width [$w.text cget -width]
  set l [string length $line]
  if {$l < $width} return 
#    set l1 [string length [$w.text get "insert + 1 l linestart" \
#                           "insert + 1 l lineend"]]
#    debug $l1
  set spc [$w.text search " " insert "insert lineend"]
  if {$spc != ""} {
    foreach {row col} [split $spc "."] { break }
  } else {
    set col $width
  }
  if {$col >= $width} {
    set spc [$w.text search -backwards " " insert "insert linestart"]
    if {$spc == ""} return
    foreach {row col} [split $spc "."] { break }
  }
  regexp -indices {^ *} $l start
  set pos [lindex $start 1]
  if {$col <= $pos} return
  $w.text mark set ml "$spc+1c"
  TedNewLine $w ml
  $w.text delete $spc
  TedHandleTags $w [$w.text index ml]
  TedHandleTags $w [$w.text index ml-1l]
}

proc TedInsert {w c} {
  global ted

  switch -- $c {
    \r {TedNewLine $w insert}
    \b {$w.text delete "insert - 1 c"}
    \t {
      $w.text insert insert " "
      foreach {row col} [split [$w.text index insert] "."] { break }
      while {$col % $ted($w,tabstop) != 0} {
        $w.text insert insert " "
        incr col
      }
    }
    default {
      if {$c < " "} {
        set ted($w,pos) [$w.text index insert]
        return
      }
      $w.text insert insert $c
    }
  }
  set line [$w.text get "insert linestart" "insert lineend"]
  # Handle tags
  switch -- $c {
    \r {
      TedHandleTags $w [$w.text index "insert - 1 l"]
      TedHandleTags $w [$w.text index insert]
    }
    \} {
      # Add \end{..} if possible
      set hastag [TedHasTag $w [$w.text index insert-1c] env]
      TedHandleTags $w [$w.text index insert]
      if {$ted($w,autoext) && [string compare $c \}] == 0 && \
        [$w.text compare insert == "insert lineend"]} {
        if {[regexp {\\begin(\[[^]]*\])?\{([^\}]*)\}$} $line pos opt env] \
	  && !$hastag} {
          regexp {^ *} $line spaces
          set pos [$w.text index insert]
          $w.text insert insert "\n$spaces\\end\{$env\}"
          $w.text yview -pickplace insert
	  TedHandleTags $w [$w.text index insert]
          $w.text mark set insert $pos
	}
      }
    }
    default {
      TedHandleTags $w [$w.text index insert]
    }
  }
  TedHandleWrap $w
  if {$c != "\000"} {
    set ted($w,stsave) 1
  }
  TedHandleTags $w [$w.text index insert]
  set ted($w,pos) [$w.text index insert]
  $w.text yview -pickplace insert
}

# Delete operations

proc TedBackSpace {w} {
  global ted

  if {[$w.text tag nextrange sel 1.0 end] != ""} {
    set s [$w.text get sel.first sel.last]
    set ted($w,undobuf) $s
    set ted($w,undo) \
      "$w.text insert [$w.text index sel.first] \$ted($w,undobuf)"
    set idx [$w.text index sel.first]
    $w.text delete sel.first sel.last
    TedHandleWrap $w del
    TedHandleTags $w $idx
  } else {
    set s [$w.text get insert-1c]
    set ted($w,undobuf) $s
    set ted($w,undo) "$w.text insert [$w.text index insert] \$ted($w,undobuf)"
    $w.text delete insert-1c
    TedHandleWrap $w del
    TedHandleTags $w [$w.text index insert]
  }
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

proc TedDelete {w} {
  global ted

  if {[$w.text tag nextrange sel 1.0 end] != ""} {
    set s [$w.text get sel.first sel.last]
    set ted($w,undobuf) $s
    set ted($w,undo) \
      "$w.text insert [$w.text index sel.first] \$ted($w,undobuf)"
    set idx [$w.text index sel.first]
    $w.text delete sel.first sel.last
    TedHandleWrap $w del
    TedHandleTags $w $idx
  } else {
    set s [$w.text get insert]
    set ted($w,undobuf) $s
    set ted($w,undo) "$w.text insert [$w.text index insert] \$ted($w,undobuf)"
    $w.text delete insert
    TedHandleWrap $w del
    TedHandleTags $w [$w.text index insert]
  }
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

proc TedDelLineEnd {w} {
  global ted

  set s [$w.text get insert {insert lineend}]
  set ted($w,undobuf) $s
  set ted($w,undo) "$w.text insert [$w.text index insert] \$ted($w,undobuf)"
  $w.text delete insert {insert lineend}
  TedHandleTags $w [$w.text index insert]
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

proc TedDelLine {w} {
  global ted

  set s [$w.text get {insert linestart} {insert linestart+1l}]
  set ted($w,undobuf) $s
  set ted($w,undo) \
    "$w.text insert [$w.text index "insert linestart"] \$ted($w,undobuf)"
  $w.text delete {insert linestart} {insert linestart+1l}
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

proc TedDelWord {w} {
  global ted

  set pos [tkTextNextPos $w.text insert TedNextWordOrChar]
  puts $pos
  set s [$w.text get insert $pos]
  set ted($w,undobuf) $s
  set ted($w,undo) "$w.text insert [$w.text index insert] \$ted($w,undobuf)"
  $w.text delete insert $pos
  TedHandleTags $w [$w.text index insert]
  set ted($w,stsave) 1
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

proc TedUndo {w} {
  global ted

  set idx [lindex $ted($w,undo) 2]
  eval $ted($w,undo)
  set ted($w,undo) {}
  TedHandleTags $w $idx
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}
  
# Cursor position

proc TedUpDownLine {w n} {
  global ted

  set i [$w.text index insert]
  scan $i "%d.%d" line char
  if {[string compare $ted($w,prevPos) $i] != 0} {
    set ted($w,charPos) $char
  }
  set new [$w.text index [expr $line + $n].$ted($w,charPos)]
  if {[$w.text compare $new == end] || 
      [$w.text compare $new == "insert linestart"]} {
    set new $i
  }
  set ted($w,prevPos) $new
  return $new
}


proc TedSetCursor {w pos} {
  global ted

  if [$w.text compare $pos == end] {
    set pos {end - 1 chars}
  }
  $w.text mark set insert $pos
  $w.text tag remove sel 1.0 end
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
}

# Mouse

proc TedButton1 {w x y} {
  global ted

  set ted($w,selectMode) char
  tkTextButton1 $w.text $x $y
  set ted($w,pos) [$w.text index insert]
}

# Selection

proc TedKeySelect {w new} {
  global ted

  if {[$w.text tag nextrange sel 1.0 end] == ""} {
    if [$w.text compare $new < insert] {
      $w.text tag add sel $new insert
    } else {
      $w.text tag add sel insert $new
    }
    $w.text mark set anchor insert
  } else {
    if [$w.text compare $new < anchor] {
      set first $new
      set last anchor
    } else {
      set first anchor
      set last $new
    }
    $w.text tag remove sel 1.0 $first
    $w.text tag add sel $first $last
    $w.text tag remove sel $last end
  }
  $w.text mark set insert $new
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
  update idletasks
}
				
proc TedMouseSelect {w x y} {
  global ted

  set ted($w,x) %x
  set ted($w,y) %y
  set ted($w,selectMode) char
  TedSelectTo $w $x $y
}

proc TedSelectTo {w x y} {
  global ted tkPriv

  set cur [tkTextClosestGap $w.text $x $y]
  if [catch {$w.text index anchor}] {
    $w.text mark set anchor $cur
  }
  set anchor [$w.text index anchor]
  if {[$w.text compare $cur != $anchor] || (abs($tkPriv(pressX) - $x) >= 3)} {
    set tkPriv(mouseMoved) 1
  }
  switch $ted($w,selectMode) {
    char {
      if [$w.text compare $cur < anchor] {
        set first $cur
	set last anchor
      } else {
	set first anchor
	set last $cur
      }
    }
    word {
      if [$w.text compare $cur < anchor] {
	set first [tkTextPrevPos $w.text "$cur + 1c" tcl_wordBreakBefore]
	set last [tkTextNextPos $w.text "anchor" tcl_wordBreakAfter]
      } else {
	set first [tkTextPrevPos $w.text anchor tcl_wordBreakBefore]
	set last [tkTextNextPos $w.text "$cur - 1c" tcl_wordBreakAfter]
      }
    }
    line {
      if [$w.text compare $cur < anchor] {
	set first [$w.text index "$cur linestart"]
	set last [$w.text index "anchor - 1c lineend + 1c"]
      } else {
	set first [$w.text index "anchor linestart"]
	set last [$w.text index "$cur lineend + 1c"]
      }
    }
  }
  if {$tkPriv(mouseMoved) || ($ted($w,selectMode) != "char")} {
    $w.text mark set insert $last
    $w.text tag remove sel 0.0 $first
    $w.text tag add sel $first $last
    $w.text tag remove sel $last end
    update idletasks
  }
  set ted($w,pos) [$w.text index insert]
}

# Spellchecker

proc SpellOpt {w} {
  global ted gparams

  set sp(splang) $gparams(splang)
  set sp(spenc) $gparams(spenc)
  set x [winfo rootx $w.text]
  set y [winfo rooty $w.text]
  if [InpDlg sp .dlg "Spell options" +$x+$y "ISpell options" {
    {"Language (-d):" char 10 splang}
    {"Encoding (-T):" char 10 spenc}
    } sp] {
    set gparams(splang) $sp(splang)
    set gparams(spenc) $sp(spenc)
  }
}

proc SpellCheck {w} {
  global ted spell params
  
  TedSaveAs $w 0
  SpellFile $ted($w,file)
  TedReadFile $w
  $w.text mark set insert 1.0
  $w.text see insert
}

# Bindings

proc TextBind {w} {
  global B

  bind $w.text <1> "TedButton1 $w %x %y"
  bind $w.text <B1-Motion> "TedMouseSelect $w %x %y"
  bind $w.text <Up>   "TedSetCursor $w \[TedUpDownLine $w -1\]"
  bind $w.text <Down> "TedSetCursor $w \[TedUpDownLine $w 1\]"
  bind $w.text <Left> "TedSetCursor $w insert-1c"
  bind $w.text <Right> "TedSetCursor $w insert+1c"
  bind $w.text <Prior> "TedSetCursor $w \[tkTextScrollPages $w.text -1\]"
  bind $w.text <Next> "TedSetCursor $w \[tkTextScrollPages $w.text 1\]"
  bind $w.text <Home> "TedSetCursor $w {insert linestart}"
  bind $w.text <End> "TedSetCursor $w {insert lineend}"
  bind $w.text <Control-Home> "TedSetCursor $w 1.0"
  bind $w.text <Control-End> "TedSetCursor $w end-1c"
 
  bind $w.text <Shift-Left> "TedKeySelect $w \[$w.text index insert-1c\]"
  bind $w.text <Shift-Right> "TedKeySelect $w \[$w.text index insert+1c\]"
  bind $w.text <Shift-Up> "TedKeySelect $w \[TedUpDownLine $w -1]"
  bind $w.text <Shift-Down> "TedKeySelect $w \[TedUpDownLine $w 1]"
  bind $w.text <Shift-Prior> "TedKeySelect $w \[tkTextScrollPages $w.text -1]"
  bind $w.text <Shift-Next> "TedKeySelect $w \[tkTextScrollPages $w.text 1]"
  bind $w.text <Shift-Home> "TedKeySelect $w {insert linestart}"
  bind $w.text <Shift-End> "TedKeySelect $w {insert lineend}"
  bind $w.text <Control-Left> \
    "TedSetCursor $w \[tkTextPrevPos $w.text insert tcl_startOfPreviousWord\]"
  bind $w.text <Control-Right> \
    "TedSetCursor $w \[tkTextNextPos $w.text insert TedNextWordOrChar\]"
  bind $w.text <Control-Up> \
    "TedSetCursor $w \[tkTextPrevPara $w.text insert\]"
  bind $w.text <Control-Down> \
    "TedSetCursor $w \[tkTextNextPara $w.text insert\]"
  bind $w.text $B(del) "TedDelete $w"
  bind $w.text $B(bs)  "TedBackSpace $w"
  bind $w.text $B(dlinend) "TedDelLineEnd $w"
  bind $w.text $B(dword) "TedDelWord $w"
  bind $w.text $B(dline) "TedDelLine $w"
  bind $w.text $B(undo) "TedUndo $w"
  bind $w.text <<Cut>> "TedCut $w"
  bind $w.text <<Copy>> "TedCopy $w"
  bind $w.text <<Paste>> "TedPaste $w"
  bind $w.text $B(save) "TedSaveAs $w 0"
  bind $w.text $B(saveas) "TedSaveAs $w 1"
  bind $w.text $B(close) "TedExit $w"
  bind $w.text $B(replace) "TedReplace $w"
  bind $w.text $B(find) "TedSearch $w"
  bind $w.text $B(go) "TedGoto $w"
  bind $w.text $B(rpnext) "TedReplaceNext $w"
  bind $w.text $B(autoext) "set ted($w,autoext) \[expr !\$ted($w,autoext)\]"
  bind $w.text $B(wrap) "set ted($w,wrap) \[expr !\$ted($w,wrap)\]"
  bind $w.text $B(autoind) "set ted($w,autoind) \[expr !\$ted($w,autoind)\]"
  bind $w.text <Any-Key> "TedInsert $w %A"
  bind $w.text <Alt-KeyPress> {# nothing}
  bind $w.text <Meta-KeyPress> {# nothing}
  bind $w.text <Control-KeyPress> {# nothing}
  bind $w.text <Escape> {# nothing}
  bindtags $w.text [list $w.text .]
  bind $w.text <Alt-Key> [bind all <Alt-Key>]
  bind $w.text <Key-F10> [bind all <Key-F10>]
}

# Edit Widget

proc tedit {w geometry title {filename ""} {line 1}} {
  global params ted ted_buf gparams SK
 
  debug "line: $line"
  toplevel $w
  wm group . $w
  set ted($w,file) $filename
  set ted($w,ext) .tex
  set ted($w,stsave) 0
  set ted($w,wrap) 0
  set ted($w,font) fixed
  set ted($w,autosave) 0
  set ted($w,autoext) 0
  set ted($w,autoind) 0
  set ted($w,tabstop) 8
  set ted($w,autos_interval) 60000
  if [info exists gparams(save)] {
    set ted($w,autosave) $gparams(save)
  }
  if [info exists gparams(interval)] {
    set ted($w,autos_interval) [expr $gparams(interval)*1000]
  }
  if [info exists gparams(wrap)] {
    set ted($w,wrap) $gparams(wrap)
  }
  if [info exists gparams(font)] {
    set ted($w,font) $gparams(font)
  }
  if [info exists gparams(autoind)] {
    set ted($w,autoind) $gparams(autoind)
  }
  if [info exists gparams(autoext)] {
    set ted($w,autoext) $gparams(autoext)
  }
  if [info exists gparams(tabstop)] {
    set ted($w,tabstop) $gparams(tabstop)
  }
    
  set ted($w,prevPos) {}
  set ted($w,block) 0
  set ted($w,title) $title
  wm geometry $w $geometry
  wm title $w "$title [cutdir $filename]"
  wm resizable $w 0 0
  # Menu
  menu $w.menubar
  $w config -menu $w.menubar
  foreach m {File Edit Options} {
    set $m [menu $w.menubar.m$m -tearoff 0]
    $w.menubar add cascade -label $m -underline 0 -menu $w.menubar.m$m
  }
  menu $w.menubar.help -tearoff 0
  $w.menubar add cascade -label Help -underline 0 -menu $w.menubar.help

  $File add command -label "New" -underline 0 -command "TedNew $w"
  $File add command -label "Save" -accelerator $SK(save) \
    -command "TedSaveAs $w 0"
  $File add command -label "Save as..." -accelerator $SK(saveas) \
    -command "TedSaveAs $w 1"
  $File add separator
  $File add command -label "Close" -underline 1 -accelerator $SK(close) \
    -command "TedExit $w"

  $Edit add command -label "Undo" -accelerator $SK(undo) \
    -command "TedPaste $w"
  $Edit add command -label "Cut" -accelerator ^X \
    -command "TedCut $w"
  $Edit add command -label "Copy" -accelerator ^C \
    -command "TedCopy $w"
  $Edit add command -label "Paste" -accelerator ^V \
    -command "TedPaste $w"
  $Edit add separator
  $Edit add command -label "Go to..." -accelerator $SK(go) \
    -command "TedGoto $w"
  $Edit add command -label "Find..." -accelerator $SK(find) \
    -command "TedSearch $w"
  $Edit add command -label "Replace..." -accelerator $SK(replace) \
    -command "TedReplace $w"
  $Edit add command -label "Next occurance" -accelerator $SK(rpnext) \
    -command "TedReplaceNext $w"
  $Edit add separator
  $Edit add command -label "Spell checker" -accelerator "" \
    -command "SpellCheck $w"

  $Options add checkbutton -label "Wrap" -accelerator $SK(wrap) \
    -variable ted($w,wrap)
  $Options add checkbutton -label "Autosave" \
    -variable ted($w,autosave) -command "TedAutoSave $w"
  $Options add checkbutton -label "Auto \\end" -accelerator $SK(autoext) \
    -variable ted($w,autoext)
  $Options add checkbutton -label "AutoIndent" -accelerator $SK(autoind) \
    -variable ted($w,autoind)
  $Options add separator
  $Options add command -label "Settings..." \
    -command EditOptions

  frame $w.buttons
  HintButton $w.bnew new.ico "TedNew $w" "New Document"
  HintButton $w.bopen edit1.ico "Edit" "New Editor"
  HintButton $w.bsave save2.ico "TedSaveAs $w 0" "Save"
  HintButton $w.bfind find.ico "TedSearch $w" Search
  HintButton $w.bclose door1.ico "TedExit $w" Close
  pack $w.bnew $w.bopen $w.bsave $w.bfind -in $w.buttons -side left
  pack $w.bclose -in $w.buttons -side right

  text $w.text -yscrollcommand "$w.textsb set" -wrap char -insertwidth 3 \
    -font [list $gparams(font) $gparams(fontsize) $gparams(fontstyle)] \
    -width $gparams(editwidth) -height $gparams(editheight)
  if [info exists gparams(bgnormal)] {
    $w.text config -bg $gparams(bgnormal)
  }
  if [info exists gparams(fgnormal)] {
    $w.text config -insertbackground $gparams(fgnormal)
    $w.text config -fg $gparams(fgnormal)
  }
  if [info exists gparams(fgcomment)] {
    $w.text tag configure comment -foreground $gparams(fgcomment)
  }
  if {[info exists gparams(fgsearch)] && [info exists gparams(bgsearch)]} {
    $w.text tag configure repl -background $gparams(bgsearch) \
      -foreground $gparams(fgsearch)
  } else {
    $w.text tag configure repl -background [$w.text cget -foreground] \
      -foreground [$w.text cget -background]
  }
  # Mistake tag
    $w.text tag configure err -foreground red
  if {[info exists gparams(fgenv)]} {
    $w.text tag configure env  -foreground $gparams(fgenv)
  }
  scrollbar $w.textsb -command "$w.text yview"
  label $w.pos -textvariable ted($w,pos) -relief sunken -bd 1 -width 7 \
    -anchor e -font fixed
  checkbutton $w.save -text "Changed ($SK(save))" -variable ted($w,stsave) \
    -relief sunken -bd 1 -font fixed
  checkbutton $w.wrap -text "Wrap ($SK(wrap))" -variable ted($w,wrap) \
    -relief sunken -bd 1 -font fixed
  checkbutton $w.autoext -text "Auto \\end ($SK(autoext))" \
    -variable ted($w,autoext) -relief sunken -bd 1 -font fixed
  checkbutton $w.autoind -text "Auto indent ($SK(autoind))" \
    -variable ted($w,autoind) -relief sunken -bd 1 -font fixed
  label $w.question -text " " -relief sunken -bd 1 -takefocus 1
  grid configure $w.buttons -row 0 -column 0 -columnspan 7 -sticky ew
  grid configure $w.text -row 1 -column 0 -columnspan 6 -sticky nsew
  grid configure $w.textsb -row 1 -column 6 -sticky ns
  grid configure $w.pos -row 2 -column 0
  grid configure $w.save -row 2 -column 1
  grid configure $w.wrap -row 2 -column 2
  grid configure $w.autoext -row 2 -column 3
  grid configure $w.autoind -row 2 -column 4
  grid configure $w.question -row 2 -column 5 -columnspan 2 -sticky ew
  grid rowconfigure $w 1 -weight 1
  grid columnconfigure $w 5 -weight 1

  # Text widget bindings
  TextBind $w

  update idletasks
  foreach l $ted(global_params) {
    set flag [lindex $l 0]
    set value [lindex $l 1]
    set ted($w,$flag) $value
  }
  TedReadFile $w
  debug "line: $line"
  $w.text mark set insert $line.0
  set ted($w,pos) [$w.text index insert]
  $w.text see insert
  TedAutoSave $w
  xfocus $w.text
}
