#By George Peter Staplin
namespace eval ctext {}

proc ctext {win args} { 
	if {[expr {[llength $args] & 1}] != 0} {
		return -code error "Invalid number of arguments given to ctext\
(uneven number): $args"                          
	}
	
	frame $win

	text .__ctextTemp
	set cmdArgs(-bg) [.__ctextTemp cget -background] 
	set cmdArgs(-fg) [.__ctextTemp cget -foreground]
	set cmdArgs(-font) [.__ctextTemp cget -font]
	set cmdArgs(-relief) [.__ctextTemp cget -relief]
	destroy .__ctextTemp
	set cmdArgs(-yscrollcommand) ""
	set cmdArgs(-linemap) 1

	array set cmdArgs $args
	
	foreach flag {foreground background} short {fg bg} {
		if {[info exists cmdArgs(-$flag)] == 1} {
			set cmdArgs(-$short) $cmdArgs(-$flag)
			unset cmdArgs(-$flag)
		}
	}
	
	#Now remove flags that will confuse text and those that need modification:
	foreach arg {yscrollcommand linemap} {
		set loc [lsearch $args -$arg]
		if {$loc != -1} {
			set firstArgs [lrange $args 0 [expr {$loc - 1}]]
			set endArgs [lrange $args [expr {$loc + 2}] end]
			set args "$firstArgs $endArgs"
		}
	}

	if {$cmdArgs(-linemap) == 1} {
		pack [text $win.l -font $cmdArgs(-font) -width 2 -relief $cmdArgs(-relief) \
			-bg $cmdArgs(-bg)  -fg $cmdArgs(-fg)] -side left -fill y
		bindtags $win.l "$win.l . all"
		
		if {$cmdArgs(-yscrollcommand) != ""} {
			append args " -yscrollcommand {ctext::linemapUpdate $win; \
				$cmdArgs(-yscrollcommand)}"
		} else {
			append args " -yscrollcommand {ctext::linemapUpdate $win}"
		}

		pack [eval text $win.t $args] -side right -fill both -expand 1
		bind $win.t <Configure> "ctext::linemapUpdate $win"
		bind $win.l <ButtonPress-1> "ctext::linemapToggleMark $win %y"
	} else {
		if {$cmdArgs(-yscrollcommand) != ""} {
			append args " -yscrollcommand {$cmdArgs(-yscrollcommand)}"
		}
		pack [eval text $win.t $args] -side right -fill both -expand 1
	}

	bind $win.t <KeyRelease-Return> "after 1 {ctext::linemapUpdate $win}"
	rename $win _ctextJunk$win
	rename $win.t $win._t

# modified to correctly unset the appropriate arrays in the ctext namespace
	bind $win <Destroy> " rename $win {};
		foreach var {highlight highlightSpecialChars \
			highlightRegexp highlightCharStart toggled blinkOptions} {
			variable ctext::\$var$win
			catch {array unset ctext::\$var$win}
		}
	"
# start of initialization for electric braces options and modified toggle
	variable ctext::blinkOptions$win
	foreach {key default} {color \#ffff00 range 1 time 500} {
		if {![info exists ctext::blinkOptions${win}($key)]} {
			set ctext::blinkOptions${win}($key) $default
		}
	}

	if {[package vcompare [info tclversion] 8.4] < 0} {
		variable ctext::toggled$win
		set ctext::toggled${win}(modified) 0
		trace variable ctext::toggled${win}(modified) w ctext::modifiedEvent
	}
# end of initialization for electric braces options and modified toggle

	proc $win {cmd args} "eval ctext::instanceCmd $win \$cmd \$args"

	uplevel "interp alias {} $win.t {} $win"
	
	upvar #0 _ctextComments$win ar
	set ar(haveCommentStart) 0
	set ar(startIndex) ""
	set ar(quote) 0
	set ar(afterToWaitFor) ""
	set ar(color) khaki
	ctext::comments $win 1.0

	return $win
}

proc ctext::instanceCmd {self cmd args} {
	variable ::ctext::toggled${self}
	switch -glob -- $cmd {
		append {
			if {[catch {set data [$self._t get sel.first sel.last]}] == 0} {
				clipboard append -displayof $self $data
			}
		}

		cget {
			if {[string trim $args] == "-linemap"} {
				update idletasks
				return [winfo viewable $self.l]
			} else {
				return [$self._t cget [lindex $args 0]]
			}
		}

		conf* {
			for {set a 0} {$a < [llength $args]} {incr a 2} {
				set cmdArgs([lindex $args $a]) [lindex $args [expr {$a + 1}]]
			}

			foreach flag {foreground background} short {fg bg} {
				if {[info exists cmdArgs(-$flag)] == 1} {
					set cmdArgs(-$short) $cmdArgs(-$flag)
				}
			}

			#Now remove flags that will confuse text or mess up ctext's linemap callback from -yscrollcommand:
			foreach arg {yscrollcommand linemap} {
				set loc [lsearch $args -$arg] 
				if {$loc != -1} {
					set firstArgs [lrange $args 0 [expr {$loc - 1}]] 
					set endArgs [lrange $args [expr {$loc + 2}] end]
					set args "$firstArgs $endArgs" 
				}
			}

			if {[info exists cmdArgs(-linemap)] == 1 && $cmdArgs(-linemap) == 1} {
				if {[winfo exists $self.l] != 1} {
					pack [text $self.l -font [$self._t cget -font] -width 2 \
						-relief [$self._t cget -relief] -bg [$self._t cget -bg] \
							-fg [$self._t cget -fg]] -side left -fill y
					bindtags $self.l "$self.l . all"	
				} else {
					pack $self.l -side left -fill y
				}

				if {[$self._t cget -yscrollcommand] !=  ""} { 
					$self._t configure -yscrollcommand "ctext::linemapUpdate $self; \
						[$self._t cget -yscrollcommand]"
				} else {
					$self._t configure -yscrollcommand "ctext::linemapUpdate $self"
				}

				bind $self._t <Configure> "ctext::linemapUpdate $self"
				bind $self.l <ButtonPress-1> "ctext::linemapToggleMark $self %y"
			}

			if {[info exists cmdArgs(-linemap)] == 1 && $cmdArgs(-linemap) == 0} {
				if {[winfo exists $self.l] == 1} {
					pack forget $self.l
				} else {
					return -code error "Hmm... You tried to destroy window\
$self.l, which doesn't exist."
				}
			}

			if {[info exists cmdArgs(-yscrollcommand)] == 1} {
				if {$cmdArgs(-yscrollcommand) != ""} {
					append args " -yscrollcommand {ctext::linemapUpdate $self; \
						$cmdArgs(-yscrollcommand)}"
				} else {
					if {[$self._t cget -yscrollcommand] != ""} {
						append args " -yscrollcommand {ctext::linemapUpdate $self}"
					}
				}
			}
			if {$args != {}} {
				eval $self._t configure $args
# added self modification of line number widget to make foreground, background, and font consistent
				$self.l configure -fg [$self._t cget -fg] -bg [$self._t cget -bg] -font [$self._t cget -font]
			}
		}

		copy {
			tk_textCopy $self
		} 

		cut {
		
			if {[catch {set data [$self.t get sel.first sel.last]}] == 0} {
				clipboard clear -displayof $self.t
				clipboard append -displayof $self.t $data
				$self delete [$self.t index sel.first] [$self.t index sel.last]
# start new text modified code
				if {[info exists ctext::toggled${self}(modified)]} {
					set ctext::toggled${self}(modified) 1
				}
# end new text modified code
			}
		}

		delete {
			#delete n.n ?n.n
			
			#first deal with delete n.n
			set argsLength [llength $args]
			
			if {$argsLength == 1} {
				set deletePos [lindex $args 0]
				set prevChar [$self._t get $deletePos]
				
				$self._t delete $deletePos
				set char [$self._t get $deletePos]
				
				set prevSpace [ctext::findPreviousSpace $self._t $deletePos]
				set nextSpace [ctext::findNextSpace $self._t $deletePos]
				
				set lineStart [$self._t index "$deletePos linestart"]
				set lineEnd [$self._t index "$deletePos + 1 chars lineend"]
				
				if {[string equal $prevChar "#"] || [string equal $char "#"]} {
					set removeStart $lineStart
					set removeEnd $lineEnd
				} else {
					set removeStart $prevSpace
					set removeEnd $nextSpace
				}
				
				foreach tag [$self._t tag names] {
					if {[string equal $tag "_cComment"] != 1} {
						$self._t tag remove $tag $removeStart $removeEnd
					}
				}
				
				if {[regexp {/|\*} $prevChar] || [regexp {/|\*} $char]} {
					ctext::comments $self 1.0
				}
# start new text modified code
				if {[info exists ctext::toggled${self}(modified)]} {
					set ctext::toggled${self}(modified) 1
				}
# end new text modified code
				after 1 "ctext::highlight $self $lineStart $lineEnd"
			} elseif {$argsLength == 2} {
				#now deal with delete n.n n.n
				set deleteStartPos [lindex $args 0]
				set deleteEndPos [lindex $args 1]
				
				set data [$self._t get $deleteStartPos $deleteEndPos]
				
				set lineStart [$self._t index "$deleteStartPos linestart"]
				set lineEnd [$self._t index "$deleteEndPos + 1 chars lineend"]
				eval $self._t delete $args
				
				foreach tag [$self._t tag names] {
					if {[string equal $tag "_cComment"] != 1} {
						$self._t tag remove $tag $lineStart $lineEnd
					}
				}
				
				if {[regexp {/|\*} $data]} {
					ctext::comments $self 1.0
				}
				unset data
# start new text modified code
				if {[info exists ctext::toggled${self}(modified)]} {
					set ctext::toggled${self}(modified) 1
				}
# end new text modified code
				after 1 "ctext::highlight $self $lineStart $lineEnd"
			} else {
				return -code error "invalid argument(s) sent to $self delete: $args"
			}
		}

		fastdelete {
			eval $self._t delete $args
# start new text modified code
			if {[info exists ctext::toggled${self}(modified)]} {
				set ctext::toggled${self}(modified) 1
			}
# end new text modified code
		}
		
		fastinsert {
			eval $self._t insert $args
# start new text modified code
			if {[info exists ctext::toggled${self}(modified)]} {
				set ctext::toggled${self}(modified) 1
			}
# end new text modified code
		}
		
		highlight {
			ctext::highlight $self [lindex $args 0] [lindex $args 1]
			ctext::comments $self 1.0
		}

		insert {
			if {[llength $args] < 2} {
				return -code error "please use at least 2 arguments to $self insert"
			}
			set insertPos [lindex $args 0]  
			set lineStart [$self._t index "$insertPos linestart"]
			set prevSpace [ctext::findPreviousSpace $self._t ${insertPos}-1c]
			set data [lindex $args 1]   
			eval $self._t insert $args 

			set nextSpace [ctext::findNextSpace $self._t insert]
			set lineEnd [$self._t index "insert lineend"] 
			 
			if {[$self._t compare $prevSpace < $lineStart]} {
				set prevSpace $lineStart
			}

			if {[$self._t compare $nextSpace > $lineEnd]} {
				set nextSpace $lineEnd
			}
				
			foreach tag [$self._t tag names] { 
				if {[string equal $tag "_cComment"] != 1} {
					$self._t tag remove $tag $prevSpace $nextSpace 
				}
			} 

			if {[regexp {/|\*} $data]} {
				ctext::comments $self 1.0
			}
# start new text modified code
			if {[info exists ctext::toggled${self}(modified)]} {
				set ctext::toggled${self}(modified) 1
			}
# end new text modified code
			after 1 "ctext::highlight $self $lineStart $lineEnd"
# start new parens matching code
			switch -- $data {
				"\}" {MatchPair $self "\{" "\}"}
				"\]" {MatchPair $self "\[" "\]"}
				"\)" {MatchPair $self "\(" "\)"}
                                "\"" {MatchQuote $self}
			}
# end new parens matching code
		}
		edit {
# start new text edit modified code
			if {[info exists ctext::toggled${self}(modified)]} {
				if {[lindex $args 0] != {modified}} {
					return -code error "invalid operation on $self: [lindex $args 0]"
				}
				set args [lrange $args 1 end]
				switch -regexp -- $args {
					0 -
					1 {
						set ctext::toggled${self}(modified) $args
						return
					}
					{^$} {
					  return [set ctext::toggled${self}(modified)]
					}
					default {
						return -code error "invalid argument(s) sent to $self edit modified: $args"
					}
				}
			} else {
				return [uplevel 2 $self._t modified $args]
			}
# end new text edit modified code
		}
		paste {
			tk_textPaste $self 
			if {[info exists ctext::toggled${self}(modified)]} {
				set ctext::toggled${self}(modified) 1
			}
		}

		default { 
			return [uplevel 2 $self._t $cmd $args]
		}
	}
}


proc ctext::comments {win index} {
	upvar #0 _ctextComments$win ar
	
	
	if {$ar(afterToWaitFor) != "" && \
		[catch {after info $ar(afterToWaitFor)} res] == 0} {
		#There is an existing after already running.
		if {$index != "1.0"} {
			return			
		}
	}

	set startIndex $index
	#puts $startIndex
	set index [$win index "$index + 1 chars lineend"]
	set line [$win get $startIndex $index]	
	$win tag remove _cComment $startIndex $index
	set lastChar ""
	for {set i 0} {$i < [string length $line]} {incr i} {
		set chr [string index $line $i]
					
		if {$chr == "\"" && $lastChar != "\\"} {
			if {$ar(quote) == 1} {
				set ar(quote) 0
			} else {
				set ar(quote) 1
			}
		}
		
		if {$ar(quote) == 0} {
			if {$chr == "*" && $lastChar == "/"} {
				set ar(haveCommentStart) 1	
				set ar(startIndex) [$win index "$startIndex + $i chars - 1 chars"]
			
			} elseif {$chr == "/" && $lastChar == "*"} {
				if {$ar(haveCommentStart) == 1} {
					set endIndex [$win index "$startIndex + $i chars + 1 chars"]
					$win tag add _cComment $ar(startIndex) $endIndex
					$win tag configure _cComment -foreground $ar(color)
					$win tag raise _cComment
					set ar(haveCommentStart) 0
				}
			}
		}
		set lastChar $chr		
	}
	
	set res [$win compare $index >= end]
	if {$res == 1} {
		set ar(quote) 0
		set ar(haveCommentStart) 0
		return
	}

	set ar(afterToWaitFor) [after 1 ctext::comments $win $index]		
}
	


proc ctext::addHighlightClass {win class color keywords} { 
	variable highlight$win
	foreach word $keywords {
		set highlight${win}($word) "$class $color"
	}
}

#For [ ] { } # etc.
proc ctext::addHighlightClassForSpecialChars {win class color chars} {  
	variable highlightSpecialChars$win
	for {set i 0} {$i < [string length $chars]} {incr i} {
		set char [string index $chars $i]
		set highlightSpecialChars${win}($char) "$class $color"
	}			
}

proc ctext::addHighlightClassForRegexp {win class color re} {  
	variable highlightRegexp$win
	set highlightRegexp${win}($class) "$color $re"
}
			
#For things like $blah 
proc ctext::addHighlightClassWithOnlyCharStart {win class color char} { 
	variable highlightCharStart$win
	set highlightCharStart${win}($char) "$class $color"
}


proc ctext::findNextChar {win index char} {
	set i [$win index "$index + 1 chars"]
	set lineend [$win index "$i lineend"]
	while {1} {
		set ch [$win get $i]
		if {[$win compare $i >= $lineend]} {
			return ""
		}
		if {$ch == $char} {
			return $i
		}
		set i [$win index "$i + 1 chars"]
	}
}


proc ctext::findNextSpace {win index} {
	set i [$win index $index]
	set lineStart [$win index "$i linestart"]
	set lineEnd [$win index "$i lineend"]
	#Sometimes the lineend fails (I don't know why), so add 1 and try again.
	if {[$win compare $lineEnd == $lineStart]} {
		set lineEnd [$win index "$i + 1 chars lineend"]
	}

	while {1} {
		set ch [$win get $i]

		if {[$win compare $i >= $lineEnd]} {
			set i $lineEnd
			break
		}

		if {[string is space $ch]} { 
			break
		}
		set i [$win index "$i + 1 chars"]
	}
	return $i
}


proc ctext::findPreviousSpace {win index} {
	set i [$win index $index]
	set lineStart [$win index "$i linestart"]
	while {1} {
		set ch [$win get $i]

		if {[$win compare $i <= $lineStart]} {
			set i $lineStart
			break
		}

		if {[string is space $ch]} {
			break
		}
		
		set i [$win index "$i - 1 chars"]
	}
	return $i
}

proc ctext::clearHighlightClasses {win} {
	variable highlight$win
	variable highlightCharStart$win
	variable highlightSpecialChars$win
	variable highlightRegexp$win

	array unset highlight$win	
	array unset highlightCharStart$win	
	array unset highlightSpecialChars$win	
	array unset highlightRegexp$win	
}

#This is a proc designed to be overwritten by the user.
#It can be used to update a cursor or animation while
#the text is being highlighted.
proc ctext::update {} {

}


proc ctext::highlight {win start end} {
	variable highlight$win
	variable highlightCharStart$win
	variable highlightSpecialChars$win
	variable highlightRegexp$win
	set si $start
		
	set twin "$win._t"
	
	#The number of times the loop has run.
	set numTimes 0
	set numUntilUpdate 600

	while {1} {
		set res [$twin search -count length -regexp -- {([^\s\(\{\[\}\]\)\.\t\n\r;\"'\|,]+)} $si $end]
		if {$res == ""} { 
			break 
		} 
		
		set wordEnd [$twin index "$res + $length chars"]
		set word [$twin get $res $wordEnd] 
		set firstOfWord [string index $word 0]

		if {[info exists highlight${win}($word)] == 1} {
			set wordAttributes [set highlight${win}($word)]
			foreach {tagClass color} $wordAttributes {}
			
			$twin tag add $tagClass $res $wordEnd
			$twin tag configure $tagClass -foreground $color

		} elseif {[info exists highlightCharStart${win}($firstOfWord)] == 1} {
			set wordAttributes [set highlightCharStart${win}($firstOfWord)]
			foreach {tagClass color} $wordAttributes {}
			
			$twin tag add $tagClass $res $wordEnd 
			$twin tag configure $tagClass -foreground $color
		}
		set si $wordEnd

		incr numTimes
		if {$numTimes >= $numUntilUpdate} {
			ctext::update
			set numTimes 0
		}
	}
			
	
	foreach {ichar tagInfo} [array get highlightSpecialChars$win] {
		set si $start
				
		foreach {tagClass color} $tagInfo {}

		while {1} {
			set res [$twin search -- $ichar $si $end] 
			if {$res == ""} { 
				break 
			} 
			set wordEnd [$twin index "$res + 1 chars"]
	
			$twin tag add $tagClass $res $wordEnd
			$twin tag configure $tagClass -foreground $color
			set si $wordEnd

			incr numTimes
			if {$numTimes >= $numUntilUpdate} {
				ctext::update
				set numTimes 0
			}
		}
	}
	
	foreach {tagClass tagInfo} [array get highlightRegexp$win] {
		set si $start
		
		foreach {color re} $tagInfo {}
						
		while {1} {
			set res [$twin search -count length -regexp -- $re $si $end] 
			if {$res == ""} { 
				break 
			} 
		
			set wordEnd [$twin index "$res + $length chars"]
			$twin tag add $tagClass $res $wordEnd
			$twin tag configure $tagClass -foreground $color
			set si $wordEnd
			
			incr numTimes
			if {$numTimes >= $numUntilUpdate} {
				ctext::update
				set numTimes 0
			}
		}
	}
}


proc ctext::linemapToggleMark {win y} {
	#The list of existing marks:
	variable toggled$win
	
	set markChar [$win.l index @0,$y] 
	set lineSelected [lindex [split $markChar .] 0]
	set line [$win.l get $lineSelected.0 $lineSelected.end]

	if {$line == ""} {
		return
	}
	
	if {[info exists toggled${win}($line)] == 1} { 
		#It's already marked, so unmark it.
		array unset toggled$win $line
		ctext::linemapUpdate $win
	} else {
		#This means that the line isn't toggled, so toggle it.
		array set toggled$win "$line {}"
		$win.l tag add lmark $markChar [$win.l index "$markChar lineend"] 
		$win.l tag configure lmark -background yellow -foreground black
	}
}


#args is here because -yscrollcommand may call it
proc ctext::linemapUpdate {win args} {
	
	if {[winfo exists $win.l] != 1} { 
		#-linemap 0 is set, or -linemap 1 isn't set
		return
	}

	set pixel 0
	set lastLine {}
	set lineList [list]
	
	variable toggled$win
	
	set fontMetrics [font metrics [$win._t cget -font]]
	set incrBy [expr {1 + ([lindex $fontMetrics 5] / 2)}]

	while {$pixel < [winfo height $win.l]} {
		set idx [$win._t index @0,$pixel]

		if {$idx != $lastLine} {
			set line [lindex [split $idx .] 0]
			set lastLine $idx
			$win.l config -width [string length $line]
			lappend lineList $line
		}	
		incr pixel $incrBy 
	} 

	$win.l delete 1.0 end	
	set lastLine {}
	foreach line $lineList {
		if {$line == $lastLine} {
			$win.l insert end "\n" 
		} else {
			if {[info exists toggled${win}($line)] == 1} { 
				$win.l insert end "$line\n" lmark
			} else {
				$win.l insert end "$line\n"
			}
		}
		set lastLine $line
	}
}

# Start of procs to support matching of parens, brackets, braces, and quotes
# Adapted from Jeff Hobbs' TkCon 2.3
## ::ctext::MatchPair - blinks a matching pair of characters
## c2 is assumed to be at the text index 'insert'.
## This proc is really loopy and took Jeff an hour to figure out given
## all possible combinations with escaping except for escaped \'s.
## It doesn't take into account possible commenting... Oh well.  If
## anyone has something better, he'd like to see/use it.  This is really
## only efficient for small contexts.
# ARGS:	w	- console text widget
# 	c1	- first char of pair
# 	c2	- second char of pair
# Calls:	::ctext::Blink
## 
proc ctext::MatchPair {w c1 c2 {lim 1.0}} {
	variable blinkOptions$w

	if {[string compare {} [set ix [$w._t search -back $c1 insert $lim]]]} {
		while {[string match {\\} [$w._t get $ix-1c]] && [string compare {} [set ix [$w._t search -back $c1 $ix-1c $lim]]]} {}
		set i1 insert-1c
		while {[string compare {} $ix]} {
			set i0 $ix
			set j 0
			while {[string compare {} [set i0 [$w._t search $c2 $i0 $i1]]]} {
				append i0 +1c
				if {[string match {\\} [$w._t get $i0-2c]]} continue
				incr j
			}
			if {!$j} break
			set i1 $ix
			while {$j && [string compare {} [set ix [$w._t search -back $c1 $ix $lim]]]} {
				if {[string match {\\} [$w._t get $ix-1c]]} continue
				incr j -1
			}
		}
		if {[string match {} $ix]} {
			set ix [$w._t index $lim]
		}
	} else {
		set ix [$w._t index $lim]
	}
	if {[set blinkOptions${w}(range)]} {
		Blink $w $ix [$w._t index insert]
	} else {
		Blink $w $ix $ix+1c [$w._t index insert-1c] [$w._t index insert]
	}
}

## ::ctext::MatchQuote - blinks between matching quotes.
## Blinks just the quote if it's unmatched, otherwise blinks quoted string
## The quote to match is assumed to be at the text index 'insert'.
# ARGS:	w	- console text widget
# Calls:	::ctext::Blink
## 
proc ctext::MatchQuote {w {lim 1.0}} {
	variable blinkOptions$w

	set i insert-1c
	set j 0
	while {[string compare [set i [$w._t search -back \" $i $lim]] {}]} {
		if {[string match {\\} [$w._t get $i-1c]]} continue
		if {!$j} {set i0 $i}
		incr j
	}
	if {$j&1} {
		if {[set blinkOptions${w}(range)]} {
			Blink $w $i0 [$w._t index insert]
		} else {
			Blink $w $i0 $i0+1c [$w._t index insert-1c] [$w._t index insert]
		}
	} else {
		Blink $w [$w._t index insert-1c] [$w._t index insert]
	}
}

## ::ctext::Blink - blinks between n index pairs for a specified duration.
# ARGS:	w	- console text widget
# 	i1	- start index to blink region
# 	i2	- end index of blink region
# 	dur	- duration in usecs to blink for
# Outputs:	blinks selected characters in $w
## 
proc ctext::Blink {w args} {
	variable blinkOptions$w

	eval [list $w._t tag add blink] $args
	$w._t tag configure blink -background [set blinkOptions${w}(color)]
	after [set blinkOptions${w}(time)] [list $w._t] tag remove blink $args
	return
}

# Added proc to support changing of the blink options
## ::ctext::setBlinkOptions - set options related to blinking for the ctext widget.
# ARGS:	w	- console text widget
# 	color	- color of the blink region
# 	range	- 1: blink entire region, 0: blink only the matching characters
# 	time	- time in msecs to for blinking
# Outputs:	blink options are set
## 
proc ctext::setBlinkOptions {w color range time} { 
	variable blinkOptions$w
	
	set blinkOptions${w}(color) $color
	set blinkOptions${w}(range) $range
	set blinkOptions${w}(time) $time
}

proc ctext::modifiedEvent {n1 n2 op} {
  if {![regexp {ctext::toggled([.].+)$} $n1 junk w]} {return}
  if {$n2 != {modified}} { return }
  if {$op != {w}} {return}
  event generate $w <<Modified>>
  return
}
