@matheusbsbs / matheus-bagliano / commits / f10d5b064a
Fork 0

git-gui: Add a search command to the blame viewer.

One of the largest deficiencies in the blame viewer at the moment is the impossibility to search for a text string. This commit fixes it by adding a Firefox-like search panel to the viewer. The panel can be shown by pressing F7 or clicking a menu entry, and is hidden by pressing Esc. Find Next is available through the F3 key. Implementation is based on the gitk code, but heavily refactored. It now also supports case-insensitive searches, and uses the text box background color to signal success or failure of the search. Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>

Alexander Gavrilov committed Oct 3, 2008 at 11:36 UTC f10d5b064ae5c9bcd6e353211f128f5c4072ed4f
3 files changed +227 -3
git-gui.sh
+3
@@ -591,6 +591,7 @@ bind . <Visibility> {
591
592 if {[is_Windows]} {
593 wm iconbitmap . -default $oguilib/git-gui.ico
594 + set ::tk::AlwaysShowSelection 1
595 }
596
597 ######################################################################
@@ -1067,6 +1068,8 @@ set selected_commit_type new
1068 set nullid "0000000000000000000000000000000000000000"
1069 set nullid2 "0000000000000000000000000000000000000001"
1070
1071 +set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
1072 +
1073 ######################################################################
1074 ##
1075 ## task management
lib/blame.tcl
+34 -3
@@ -21,9 +21,11 @@ field w_amov ; # text column: annotations + move tracking
21 field w_asim ; # text column: annotations (simple computation)
22 field w_file ; # text column: actual file data
23 field w_cviewer ; # pane showing commit message
24 +field finder ; # find mini-dialog frame
25 field status ; # status mega-widget instance
26 field old_height ; # last known height of $w.file_pane
27
28 +
29 # Tk UI colors
30 #
31 variable active_color #c0edc5
@@ -59,7 +61,7 @@ field tooltip_timer {} ; # Current timer event for our tooltip
61 field tooltip_commit {} ; # Commit(s) in tooltip
62
63 constructor new {i_commit i_path i_jump} {
62 - global cursor_ptr
64 + global cursor_ptr M1B M1T have_tk85
65 variable active_color
66 variable group_colors
67
@@ -199,6 +201,11 @@ constructor new {i_commit i_path i_jump} {
201 -width 80 \
202 -xscrollcommand [list $w.file_pane.out.sbx set] \
203 -font font_diff
204 + if {$have_tk85} {
205 + $w_file configure -inactiveselectbackground darkblue
206 + }
207 + $w_file tag conf found \
208 + -background yellow
209
210 set w_columns [list $w_amov $w_asim $w_line $w_file]
211
@@ -219,6 +226,11 @@ constructor new {i_commit i_path i_jump} {
226 -weight 1
227 grid rowconfigure $w.file_pane.out 0 -weight 1
228
229 + set finder [::searchbar::new \
230 + $w.file_pane.out.ff $w_file \
231 + -column [expr {[llength $w_columns] - 1}] \
232 + ]
233 +
234 set w_cviewer $w.file_pane.cm.t
235 text $w_cviewer \
236 -background white \
@@ -259,6 +271,10 @@ constructor new {i_commit i_path i_jump} {
271 -label [mc "Copy Commit"] \
272 -command [cb _copycommit]
273 $w.ctxm add separator
274 + $w.ctxm add command \
275 + -label [mc "Find Text..."] \
276 + -accelerator F7 \
277 + -command [list searchbar::show $finder]
278 menu $w.ctxm.enc
279 build_encoding_menu $w.ctxm.enc [cb _setencoding]
280 $w.ctxm add cascade \
@@ -280,9 +296,15 @@ constructor new {i_commit i_path i_jump} {
296 $i tag conf color$g -background [lindex $group_colors $g]
297 }
298
299 + if {$i eq $w_file} {
300 + $w_file tag raise found
301 + }
302 + $i tag raise sel
303 +
304 $i conf -cursor $cursor_ptr
284 - $i conf -yscrollcommand [list many2scrollbar \
285 - $w_columns yview $w.file_pane.out.sby]
305 + $i conf -yscrollcommand \
306 + "[list ::searchbar::scrolled $finder]
307 + [list many2scrollbar $w_columns yview $w.file_pane.out.sby]"
308 bind $i <Button-1> "
309 [cb _hide_tooltip]
310 [cb _click $i @%x,%y]
@@ -319,6 +341,11 @@ constructor new {i_commit i_path i_jump} {
341 bind $w_cviewer <Tab> "[list focus $w_file];break"
342 bind $w_cviewer <Button-1> [list focus $w_cviewer]
343 bind $w_file <Visibility> [list focus $w_file]
344 + bind $top <F7> [list searchbar::show $finder]
345 + bind $top <Escape> [list searchbar::hide $finder]
346 + bind $top <F3> [list searchbar::find_next $finder]
347 + bind $top <Shift-F3> [list searchbar::find_prev $finder]
348 + catch { bind $top <Shift-Key-XF86_Switch_VT_3> [list searchbar::find_prev $finder] }
349
350 grid configure $w.header -sticky ew
351 grid configure $w.file_pane -sticky nsew
@@ -873,6 +900,10 @@ method _showcommit {cur_w lno} {
900 foreach i $w_columns {
901 $i tag conf g$cmit -background $active_color
902 $i tag raise g$cmit
903 + if {$i eq $w_file} {
904 + $w_file tag raise found
905 + }
906 + $i tag raise sel
907 }
908
909 set author_name {}
lib/search.tcl new
+190
@@ -0,0 +1,190 @@
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 + set w $i_w
18 + set ctext $i_text
19 +
20 + frame $w
21 + label $w.l -text [mc Find:]
22 + button $w.bn -text [mc Next] -command [cb find_next]
23 + button $w.bp -text [mc Prev] -command [cb find_prev]
24 + checkbutton $w.cs -text [mc Case-Sensitive] \
25 + -variable ${__this}::casesensitive -command [cb _incrsearch]
26 + entry $w.ent -textvariable ${__this}::searchstring -background lightgreen
27 + pack $w.l -side left
28 + pack $w.cs -side right
29 + pack $w.bp -side right
30 + pack $w.bn -side right
31 + pack $w.ent -side left -expand 1 -fill x
32 +
33 + eval grid conf $w -sticky we $args
34 + grid remove $w
35 +
36 + trace add variable searchstring write [cb _incrsearch_cb]
37 +
38 + bind $w <Destroy> [cb delete_this]
39 + return $this
40 +}
41 +
42 +method show {} {
43 + if {![winfo ismapped $w]} {
44 + grid $w
45 + }
46 + focus -force $w.ent
47 +}
48 +
49 +method hide {} {
50 + if {[winfo ismapped $w]} {
51 + focus $ctext
52 + grid remove $w
53 + }
54 +}
55 +
56 +method _get_new_anchor {} {
57 + # use start of selection if it is visible,
58 + # or the bounds of the visible area
59 + set top [$ctext index @0,0]
60 + set bottom [$ctext index @0,[winfo height $ctext]]
61 + set sel [$ctext tag ranges sel]
62 + if {$sel ne {}} {
63 + set spos [lindex $sel 0]
64 + if {[lindex $spos 0] >= [lindex $top 0] &&
65 + [lindex $spos 0] <= [lindex $bottom 0]} {
66 + return $spos
67 + }
68 + }
69 + if {$searchdirn eq "-forwards"} {
70 + return $top
71 + } else {
72 + return $bottom
73 + }
74 +}
75 +
76 +method _get_wrap_anchor {dir} {
77 + if {$dir eq "-forwards"} {
78 + return 1.0
79 + } else {
80 + return end
81 + }
82 +}
83 +
84 +method _do_search {start {mlenvar {}} {dir {}} {endbound {}}} {
85 + set cmd [list $ctext search]
86 + if {$mlenvar ne {}} {
87 + upvar $mlenvar mlen
88 + lappend cmd -count mlen
89 + }
90 + if {!$casesensitive} {
91 + lappend cmd -nocase
92 + }
93 + if {$dir eq {}} {
94 + set dir $searchdirn
95 + }
96 + lappend cmd $dir -- $searchstring
97 + if {$endbound ne {}} {
98 + set here [eval $cmd [list $start] [list $endbound]]
99 + } else {
100 + set here [eval $cmd [list $start]]
101 + if {$here eq {}} {
102 + set here [eval $cmd [_get_wrap_anchor $this $dir]]
103 + }
104 + }
105 + return $here
106 +}
107 +
108 +method _incrsearch_cb {name ix op} {
109 + after idle [cb _incrsearch]
110 +}
111 +
112 +method _incrsearch {} {
113 + $ctext tag remove found 1.0 end
114 + if {[catch {$ctext index anchor}]} {
115 + $ctext mark set anchor [_get_new_anchor $this]
116 + }
117 + if {$searchstring ne {}} {
118 + set here [_do_search $this anchor mlen]
119 + if {$here ne {}} {
120 + $ctext see $here
121 + $ctext tag remove sel 1.0 end
122 + $ctext tag add sel $here "$here + $mlen c"
123 + $w.ent configure -background lightgreen
124 + _set_marks $this 1
125 + } else {
126 + $w.ent configure -background lightpink
127 + }
128 + }
129 +}
130 +
131 +method find_prev {} {
132 + find_next $this -backwards
133 +}
134 +
135 +method find_next {{dir -forwards}} {
136 + focus $w.ent
137 + $w.ent icursor end
138 + set searchdirn $dir
139 + $ctext mark unset anchor
140 + if {$searchstring ne {}} {
141 + set start [_get_new_anchor $this]
142 + if {$dir eq "-forwards"} {
143 + set start "$start + 1c"
144 + }
145 + set match [_do_search $this $start mlen]
146 + $ctext tag remove sel 1.0 end
147 + if {$match ne {}} {
148 + $ctext see $match
149 + $ctext tag add sel $match "$match + $mlen c"
150 + }
151 + }
152 +}
153 +
154 +method _mark_range {first last} {
155 + set mend $first.0
156 + while {1} {
157 + set match [_do_search $this $mend mlen -forwards $last.end]
158 + if {$match eq {}} break
159 + set mend "$match + $mlen c"
160 + $ctext tag add found $match $mend
161 + }
162 +}
163 +
164 +method _set_marks {doall} {
165 + set topline [lindex [split [$ctext index @0,0] .] 0]
166 + set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0]
167 + if {$doall || $botline < $smarktop || $topline > $smarkbot} {
168 + # no overlap with previous
169 + _mark_range $this $topline $botline
170 + set smarktop $topline
171 + set smarkbot $botline
172 + } else {
173 + if {$topline < $smarktop} {
174 + _mark_range $this $topline [expr {$smarktop-1}]
175 + set smarktop $topline
176 + }
177 + if {$botline > $smarkbot} {
178 + _mark_range $this [expr {$smarkbot+1}] $botline
179 + set smarkbot $botline
180 + }
181 + }
182 +}
183 +
184 +method scrolled {} {
185 + if {$searchstring ne {}} {
186 + after idle [cb _set_marks 0]
187 + }
188 +}
189 +
190 +}
\ No newline at end of file