#
# Module for marking text in Text widgets
#


# Adds a mark to the selected region in $w.
proc th_mark_region {w} {
  if {![catch "$w index sel.last"]} {$w tag add mark sel.first sel.last
  } elseif {![catch {set m [$w index mark]}]} {
    if {[$w compare $m <= insert]} {
      $w tag add mark $m insert
    } else {$w tag add mark $w insert $m}
  } else {bell}
  global TH
  eval $w tag configure mark $TH(Mark,Tag)
}

# Removes mark from the selected region in w.
proc th_unmark_region {w} {
  if {![catch "$w index sel.last"]} {$w tag remove mark sel.first sel.last
  } elseif {![catch {set m [$w index mark]}]} {
    if {[$w compare $m <= insert]} {
      $w tag remove mark $m insert
    } else {$w tag remove mark $w insert $m}
  } else {bell}
}

# Goes to the beginning of the next mark.
proc th_mark_forward {w} {
  if {[set index [lindex [$w tag nextrange mark insert+1c] 0]] == ""} {bell ; return}
  th_Text_goto $w $index
}

# Goes to the beginning of the previous mark.
proc th_mark_backward {w} {
  if {[set index [lindex [th_tag_prevrange $w mark insert-1c] 0]] == ""} {bell ; return}
  th_Text_goto $w $index
}


# Used by th_mark_backward

# Line $w tag nextrange, but returns the range whose start is previous to index
proc th_tag_prevrange {w tag index} {
  set ranges [$w tag ranges $tag]
  set nextrange [$w tag nextrange $tag "$index +1c"]
  if {$nextrange == ""} {set i [llength $ranges]
  } else {set i [th_Text_list_bisearch $w [lindex $nextrange 0] $ranges]}
  return [lrange $ranges [expr $i - 2] [expr $i - 1]]
}

# Searches ranges for index. More efficient than list search, since ranges
# is ordered.
proc th_Text_list_bisearch {w index ranges} {
  set l [llength $ranges]
  if {[$w compare $index == [lindex $ranges 0]]} {return 0}
  if {[$w compare $index == [lindex $ranges [expr $l - 1]]]} {return [expr $l - 1]}
  
  set l [expr $l / 2]
  set i $l
  set r [lindex $ranges $i]
  while {[$w compare $index != $r]} {
    if {$l != 1} {set l [expr $l / 2]}
    if {[$w compare $index < $r]} {	incr i -$l
    } else {			incr i $l}
    set r [lindex $ranges $i]
  }
  return $i
}
