You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
4.0 KiB
190 lines
4.0 KiB
# incremental search panel |
|
# based on code from gitk, Copyright (C) Paul Mackerras |
|
|
|
class searchbar { |
|
|
|
field w |
|
field ctext |
|
|
|
field searchstring {} |
|
field casesensitive 1 |
|
field searchdirn -forwards |
|
|
|
field smarktop |
|
field smarkbot |
|
|
|
constructor new {i_w i_text args} { |
|
set w $i_w |
|
set ctext $i_text |
|
|
|
frame $w |
|
label $w.l -text [mc Find:] |
|
button $w.bn -text [mc Next] -command [cb find_next] |
|
button $w.bp -text [mc Prev] -command [cb find_prev] |
|
checkbutton $w.cs -text [mc Case-Sensitive] \ |
|
-variable ${__this}::casesensitive -command [cb _incrsearch] |
|
entry $w.ent -textvariable ${__this}::searchstring -background lightgreen |
|
pack $w.l -side left |
|
pack $w.cs -side right |
|
pack $w.bp -side right |
|
pack $w.bn -side right |
|
pack $w.ent -side left -expand 1 -fill x |
|
|
|
eval grid conf $w -sticky we $args |
|
grid remove $w |
|
|
|
trace add variable searchstring write [cb _incrsearch_cb] |
|
|
|
bind $w <Destroy> [cb delete_this] |
|
return $this |
|
} |
|
|
|
method show {} { |
|
if {![winfo ismapped $w]} { |
|
grid $w |
|
} |
|
focus -force $w.ent |
|
} |
|
|
|
method hide {} { |
|
if {[winfo ismapped $w]} { |
|
focus $ctext |
|
grid remove $w |
|
} |
|
} |
|
|
|
method _get_new_anchor {} { |
|
# use start of selection if it is visible, |
|
# or the bounds of the visible area |
|
set top [$ctext index @0,0] |
|
set bottom [$ctext index @0,[winfo height $ctext]] |
|
set sel [$ctext tag ranges sel] |
|
if {$sel ne {}} { |
|
set spos [lindex $sel 0] |
|
if {[lindex $spos 0] >= [lindex $top 0] && |
|
[lindex $spos 0] <= [lindex $bottom 0]} { |
|
return $spos |
|
} |
|
} |
|
if {$searchdirn eq "-forwards"} { |
|
return $top |
|
} else { |
|
return $bottom |
|
} |
|
} |
|
|
|
method _get_wrap_anchor {dir} { |
|
if {$dir eq "-forwards"} { |
|
return 1.0 |
|
} else { |
|
return end |
|
} |
|
} |
|
|
|
method _do_search {start {mlenvar {}} {dir {}} {endbound {}}} { |
|
set cmd [list $ctext search] |
|
if {$mlenvar ne {}} { |
|
upvar $mlenvar mlen |
|
lappend cmd -count mlen |
|
} |
|
if {!$casesensitive} { |
|
lappend cmd -nocase |
|
} |
|
if {$dir eq {}} { |
|
set dir $searchdirn |
|
} |
|
lappend cmd $dir -- $searchstring |
|
if {$endbound ne {}} { |
|
set here [eval $cmd [list $start] [list $endbound]] |
|
} else { |
|
set here [eval $cmd [list $start]] |
|
if {$here eq {}} { |
|
set here [eval $cmd [_get_wrap_anchor $this $dir]] |
|
} |
|
} |
|
return $here |
|
} |
|
|
|
method _incrsearch_cb {name ix op} { |
|
after idle [cb _incrsearch] |
|
} |
|
|
|
method _incrsearch {} { |
|
$ctext tag remove found 1.0 end |
|
if {[catch {$ctext index anchor}]} { |
|
$ctext mark set anchor [_get_new_anchor $this] |
|
} |
|
if {$searchstring ne {}} { |
|
set here [_do_search $this anchor mlen] |
|
if {$here ne {}} { |
|
$ctext see $here |
|
$ctext tag remove sel 1.0 end |
|
$ctext tag add sel $here "$here + $mlen c" |
|
$w.ent configure -background lightgreen |
|
_set_marks $this 1 |
|
} else { |
|
$w.ent configure -background lightpink |
|
} |
|
} |
|
} |
|
|
|
method find_prev {} { |
|
find_next $this -backwards |
|
} |
|
|
|
method find_next {{dir -forwards}} { |
|
focus $w.ent |
|
$w.ent icursor end |
|
set searchdirn $dir |
|
$ctext mark unset anchor |
|
if {$searchstring ne {}} { |
|
set start [_get_new_anchor $this] |
|
if {$dir eq "-forwards"} { |
|
set start "$start + 1c" |
|
} |
|
set match [_do_search $this $start mlen] |
|
$ctext tag remove sel 1.0 end |
|
if {$match ne {}} { |
|
$ctext see $match |
|
$ctext tag add sel $match "$match + $mlen c" |
|
} |
|
} |
|
} |
|
|
|
method _mark_range {first last} { |
|
set mend $first.0 |
|
while {1} { |
|
set match [_do_search $this $mend mlen -forwards $last.end] |
|
if {$match eq {}} break |
|
set mend "$match + $mlen c" |
|
$ctext tag add found $match $mend |
|
} |
|
} |
|
|
|
method _set_marks {doall} { |
|
set topline [lindex [split [$ctext index @0,0] .] 0] |
|
set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0] |
|
if {$doall || $botline < $smarktop || $topline > $smarkbot} { |
|
# no overlap with previous |
|
_mark_range $this $topline $botline |
|
set smarktop $topline |
|
set smarkbot $botline |
|
} else { |
|
if {$topline < $smarktop} { |
|
_mark_range $this $topline [expr {$smarktop-1}] |
|
set smarktop $topline |
|
} |
|
if {$botline > $smarkbot} { |
|
_mark_range $this [expr {$smarkbot+1}] $botline |
|
set smarkbot $botline |
|
} |
|
} |
|
} |
|
|
|
method scrolled {} { |
|
if {$searchstring ne {}} { |
|
after idle [cb _set_marks 0] |
|
} |
|
} |
|
|
|
} |