]> git.ipfire.org Git - thirdparty/git.git/blob - git-gui/lib/search.tcl
Merge git://repo.or.cz/git-gui into pt/git-gui
[thirdparty/git.git] / git-gui / lib / search.tcl
1 # incremental search panel
2 # based on code from gitk, Copyright (C) Paul Mackerras
3
4 class searchbar {
5
6 field w
7 field ctext
8
9 field searchstring {}
10 field casesensitive 1
11 field searchdirn -forwards
12
13 field smarktop
14 field smarkbot
15
16 constructor new {i_w i_text args} {
17 global use_ttk NS
18 set w $i_w
19 set ctext $i_text
20
21 ${NS}::frame $w
22 ${NS}::label $w.l -text [mc Find:]
23 entry $w.ent -textvariable ${__this}::searchstring -background lightgreen
24 ${NS}::button $w.bn -text [mc Next] -command [cb find_next]
25 ${NS}::button $w.bp -text [mc Prev] -command [cb find_prev]
26 ${NS}::checkbutton $w.cs -text [mc Case-Sensitive] \
27 -variable ${__this}::casesensitive -command [cb _incrsearch]
28 pack $w.l -side left
29 pack $w.cs -side right
30 pack $w.bp -side right
31 pack $w.bn -side right
32 pack $w.ent -side left -expand 1 -fill x
33
34 eval grid conf $w -sticky we $args
35 grid remove $w
36
37 trace add variable searchstring write [cb _incrsearch_cb]
38
39 bind $w <Destroy> [list delete_this $this]
40 return $this
41 }
42
43 method show {} {
44 if {![visible $this]} {
45 grid $w
46 }
47 focus -force $w.ent
48 }
49
50 method hide {} {
51 if {[visible $this]} {
52 focus $ctext
53 grid remove $w
54 }
55 }
56
57 method visible {} {
58 return [winfo ismapped $w]
59 }
60
61 method editor {} {
62 return $w.ent
63 }
64
65 method _get_new_anchor {} {
66 # use start of selection if it is visible,
67 # or the bounds of the visible area
68 set top [$ctext index @0,0]
69 set bottom [$ctext index @0,[winfo height $ctext]]
70 set sel [$ctext tag ranges sel]
71 if {$sel ne {}} {
72 set spos [lindex $sel 0]
73 if {[lindex $spos 0] >= [lindex $top 0] &&
74 [lindex $spos 0] <= [lindex $bottom 0]} {
75 return $spos
76 }
77 }
78 if {$searchdirn eq "-forwards"} {
79 return $top
80 } else {
81 return $bottom
82 }
83 }
84
85 method _get_wrap_anchor {dir} {
86 if {$dir eq "-forwards"} {
87 return 1.0
88 } else {
89 return end
90 }
91 }
92
93 method _do_search {start {mlenvar {}} {dir {}} {endbound {}}} {
94 set cmd [list $ctext search]
95 if {$mlenvar ne {}} {
96 upvar $mlenvar mlen
97 lappend cmd -count mlen
98 }
99 if {!$casesensitive} {
100 lappend cmd -nocase
101 }
102 if {$dir eq {}} {
103 set dir $searchdirn
104 }
105 lappend cmd $dir -- $searchstring
106 if {$endbound ne {}} {
107 set here [eval $cmd [list $start] [list $endbound]]
108 } else {
109 set here [eval $cmd [list $start]]
110 if {$here eq {}} {
111 set here [eval $cmd [_get_wrap_anchor $this $dir]]
112 }
113 }
114 return $here
115 }
116
117 method _incrsearch_cb {name ix op} {
118 after idle [cb _incrsearch]
119 }
120
121 method _incrsearch {} {
122 $ctext tag remove found 1.0 end
123 if {[catch {$ctext index anchor}]} {
124 $ctext mark set anchor [_get_new_anchor $this]
125 }
126 if {$searchstring ne {}} {
127 set here [_do_search $this anchor mlen]
128 if {$here ne {}} {
129 $ctext see $here
130 $ctext tag remove sel 1.0 end
131 $ctext tag add sel $here "$here + $mlen c"
132 $w.ent configure -background lightgreen
133 _set_marks $this 1
134 } else {
135 $w.ent configure -background lightpink
136 }
137 }
138 }
139
140 method find_prev {} {
141 find_next $this -backwards
142 }
143
144 method find_next {{dir -forwards}} {
145 focus $w.ent
146 $w.ent icursor end
147 set searchdirn $dir
148 $ctext mark unset anchor
149 if {$searchstring ne {}} {
150 set start [_get_new_anchor $this]
151 if {$dir eq "-forwards"} {
152 set start "$start + 1c"
153 }
154 set match [_do_search $this $start mlen]
155 $ctext tag remove sel 1.0 end
156 if {$match ne {}} {
157 $ctext see $match
158 $ctext tag add sel $match "$match + $mlen c"
159 }
160 }
161 }
162
163 method _mark_range {first last} {
164 set mend $first.0
165 while {1} {
166 set match [_do_search $this $mend mlen -forwards $last.end]
167 if {$match eq {}} break
168 set mend "$match + $mlen c"
169 $ctext tag add found $match $mend
170 }
171 }
172
173 method _set_marks {doall} {
174 set topline [lindex [split [$ctext index @0,0] .] 0]
175 set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0]
176 if {$doall || $botline < $smarktop || $topline > $smarkbot} {
177 # no overlap with previous
178 _mark_range $this $topline $botline
179 set smarktop $topline
180 set smarkbot $botline
181 } else {
182 if {$topline < $smarktop} {
183 _mark_range $this $topline [expr {$smarktop-1}]
184 set smarktop $topline
185 }
186 if {$botline > $smarkbot} {
187 _mark_range $this [expr {$smarkbot+1}] $botline
188 set smarkbot $botline
189 }
190 }
191 }
192
193 method scrolled {} {
194 if {$searchstring ne {}} {
195 after idle [cb _set_marks 0]
196 }
197 }
198
199 }