#
# This file contains general stuff used by the text, C, and other 'modes'.
#


# Returns a list of all the regions in w, given functions for finding them.
# (returns them in reverse order, so changes won't affect subsequent entries)
proc th_Text_regions {w begin_fn end_fn next_fn {start 1.0} {end end}} {
  set list ""
  if {[set s [$begin_fn $w $start]] == ""} {
    set s [$next_fn $w $start]
  }
  while {($s != "") && [$w compare $s < $end]} {
    if {[set e [$end_fn $w $s]] != ""} {
      lappend list [$w index $s] [$w index $e]
    }
    set s [$next_fn $w $s]
  }
  return $list
}

# graces each region (with fns given here) with a tag so it can be indexed.
proc th_Text_tag_regions {w tag begin_fn end_fn next_fn {start 1.0} {end end}} {
  set regions [th_Text_regions $w $begin_fn $end_fn $next_fn $start $end]
  set l [llength $regions]
  for {set i 0} {$i < $l} {incr i 2} {
    $w tag add $tag [lindex $regions $i] [lindex $regions [expr $i + 1]]
}}

# Selects a group of text defined by begin_fn and end_fn.
proc th_Text_select_group {w begin_fn end_fn} {
  set s [$begin_fn $w insert]
  if {($s == "")} {bell ; return}
  set e [$end_fn $w $s]
  if {($e == "")} {bell ; return}
  th_Text_select_range $w $s $e
}


# Splits line if it is longer than length. Returns number of extra lines
# produced (0 if line was unchanged). Index is on line to break, length is
# desired length, string is (optional) contents of line. Returns the number of
# breaks added.
proc th_Text_split {w start end {length ""} {undo 1}} {
  scan [$w index $start] "%d.%d" s dummy
  scan [$w index $end] "%d.%d" e dummy
  $w mark set th_split_end "$end lineend"
  set chars [$w get "$s.0" th_split_end]
  set val 0
  for {set i $e} {$i >= $s} {incr i -1} {
    incr val [th_Text_split_aux $w "$i.0" $length]
  }
  set e [$w index th_split_end] ; $w mark unset th_split_end
  if $undo {th_Text_undoable_replace $w "$s.0" $e $chars "Split"}
  return $val
}

proc th_Text_split_aux {w {index insert} {length ""}} {
  set string [$w get "$index linestart" "$index lineend"]
  if {($length == "")} {set length [$w cget -width]}
  if {($length == [$w cget -width])} {set use_window 1} else {set use_window 0}

  if $use_window {
    $w see $index
    if {[set dlineinfo [$w dlineinfo $index]] == ""} {return 0}
    set eol_index [$w index "@[winfo width $w],[lindex $dlineinfo 1]"]
    if {[$w compare $eol_index == "$index lineend"]} {return 0}
    scan $eol_index "%d.%d" dummy eol
  } else {
    if {([string length $string] < $length)} {return 0}
    set eol [expr $length - 1]}
  set offset [string last " " [string range $string 0 $eol]]
  if {($offset < 0)} {return 0}
  set break [$w index "$index linestart +$offset chars"]
  $w delete $break
  while {[$w get $break] == " "} {$w delete $break}
  $w insert $break \n
  set breaks [th_Text_split_aux $w "$break +1 chars" $length]
  return [incr breaks]
}

# Removes newlines from range of text.
proc th_Text_join {w start end {undo 1}} {
  if {[catch {$w index $start} s]} {bell ; return}
  if {[catch {$w index $end} e]} {bell ; return}
  if {[$w compare $e == end]} {set e "end-1c"}
  set chars [$w get $s $e]
  set trace $s ; $w mark set endtrace $e
  while {([set offset [string first \n [$w get $trace endtrace]]] >= 0)} {
    set trace [$w index "$trace +$offset chars"]
    if {([$w get "$trace +1c"] != "\n") && ([$w get "$trace - 1c"] != "\n")} {
      $w delete $trace ;  $w insert $trace " "
    } else {set trace "$trace +1c"}
  }
  set e [$w index endtrace] ; $w mark unset endtrace
  if $undo {th_Text_undoable_replace $w $s $e $chars "Join"}
}

# Does a join, then a split of a paragraph
proc th_Text_format {w start end {length ""} {undo 1}} {
  if {[catch {$w index $start} s]} {bell ; return}
  if {[catch {$w index $end} e]} {bell ; return}
  set chars [$w get $s $e]
  $w mark set th_format_end $e
  th_Text_join $w $s th_format_end 0
  th_Text_split $w $s th_format_end $length 0
  set e [$w index th_format_end] ; $w mark unset th_format_end
  if $undo {th_Text_undoable_replace $w $s $e $chars "Reformat"}
}
