Skip to content

Commit f10d5b0

Browse files
angavrilovspearce
authored andcommitted
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 <[email protected]> Signed-off-by: Shawn O. Pearce <[email protected]>
1 parent d4d9925 commit f10d5b0

File tree

3 files changed

+227
-3
lines changed

3 files changed

+227
-3
lines changed

git-gui.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ bind . <Visibility> {
591591
592592
if {[is_Windows]} {
593593
wm iconbitmap . -default $oguilib/git-gui.ico
594+
set ::tk::AlwaysShowSelection 1
594595
}
595596
596597
######################################################################
@@ -1067,6 +1068,8 @@ set selected_commit_type new
10671068
set nullid "0000000000000000000000000000000000000000"
10681069
set nullid2 "0000000000000000000000000000000000000001"
10691070
1071+
set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
1072+
10701073
######################################################################
10711074
##
10721075
## task management

lib/blame.tcl

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ field w_amov ; # text column: annotations + move tracking
2121
field w_asim ; # text column: annotations (simple computation)
2222
field w_file ; # text column: actual file data
2323
field w_cviewer ; # pane showing commit message
24+
field finder ; # find mini-dialog frame
2425
field status ; # status mega-widget instance
2526
field old_height ; # last known height of $w.file_pane
2627

28+
2729
# Tk UI colors
2830
#
2931
variable active_color #c0edc5
@@ -59,7 +61,7 @@ field tooltip_timer {} ; # Current timer event for our tooltip
5961
field tooltip_commit {} ; # Commit(s) in tooltip
6062

6163
constructor new {i_commit i_path i_jump} {
62-
global cursor_ptr
64+
global cursor_ptr M1B M1T have_tk85
6365
variable active_color
6466
variable group_colors
6567

@@ -199,6 +201,11 @@ constructor new {i_commit i_path i_jump} {
199201
-width 80 \
200202
-xscrollcommand [list $w.file_pane.out.sbx set] \
201203
-font font_diff
204+
if {$have_tk85} {
205+
$w_file configure -inactiveselectbackground darkblue
206+
}
207+
$w_file tag conf found \
208+
-background yellow
202209

203210
set w_columns [list $w_amov $w_asim $w_line $w_file]
204211

@@ -219,6 +226,11 @@ constructor new {i_commit i_path i_jump} {
219226
-weight 1
220227
grid rowconfigure $w.file_pane.out 0 -weight 1
221228

229+
set finder [::searchbar::new \
230+
$w.file_pane.out.ff $w_file \
231+
-column [expr {[llength $w_columns] - 1}] \
232+
]
233+
222234
set w_cviewer $w.file_pane.cm.t
223235
text $w_cviewer \
224236
-background white \
@@ -259,6 +271,10 @@ constructor new {i_commit i_path i_jump} {
259271
-label [mc "Copy Commit"] \
260272
-command [cb _copycommit]
261273
$w.ctxm add separator
274+
$w.ctxm add command \
275+
-label [mc "Find Text..."] \
276+
-accelerator F7 \
277+
-command [list searchbar::show $finder]
262278
menu $w.ctxm.enc
263279
build_encoding_menu $w.ctxm.enc [cb _setencoding]
264280
$w.ctxm add cascade \
@@ -280,9 +296,15 @@ constructor new {i_commit i_path i_jump} {
280296
$i tag conf color$g -background [lindex $group_colors $g]
281297
}
282298

299+
if {$i eq $w_file} {
300+
$w_file tag raise found
301+
}
302+
$i tag raise sel
303+
283304
$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]"
286308
bind $i <Button-1> "
287309
[cb _hide_tooltip]
288310
[cb _click $i @%x,%y]
@@ -319,6 +341,11 @@ constructor new {i_commit i_path i_jump} {
319341
bind $w_cviewer <Tab> "[list focus $w_file];break"
320342
bind $w_cviewer <Button-1> [list focus $w_cviewer]
321343
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] }
322349

323350
grid configure $w.header -sticky ew
324351
grid configure $w.file_pane -sticky nsew
@@ -873,6 +900,10 @@ method _showcommit {cur_w lno} {
873900
foreach i $w_columns {
874901
$i tag conf g$cmit -background $active_color
875902
$i tag raise g$cmit
903+
if {$i eq $w_file} {
904+
$w_file tag raise found
905+
}
906+
$i tag raise sel
876907
}
877908

878909
set author_name {}

lib/search.tcl

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)