##// END OF EJS Templates
hgk: add context menu visual diff action...
Patrick Mezard -
r5394:0ad0e973 default
parent child Browse files
Show More
@@ -1,3782 +1,3815 b''
1 #!/usr/bin/env wish
1 #!/usr/bin/env wish
2
2
3 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
3 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
4 # This program is free software; it may be used, copied, modified
4 # This program is free software; it may be used, copied, modified
5 # and distributed under the terms of the GNU General Public Licence,
5 # and distributed under the terms of the GNU General Public Licence,
6 # either version 2, or (at your option) any later version.
6 # either version 2, or (at your option) any later version.
7
7
8
8
9 # Modified version of Tip 171:
9 # Modified version of Tip 171:
10 # http://www.tcl.tk/cgi-bin/tct/tip/171.html
10 # http://www.tcl.tk/cgi-bin/tct/tip/171.html
11 #
11 #
12 # The in_mousewheel global was added to fix strange reentrancy issues.
12 # The in_mousewheel global was added to fix strange reentrancy issues.
13 # The whole snipped is activated only under windows, mouse wheel
13 # The whole snipped is activated only under windows, mouse wheel
14 # bindings working already under MacOSX and Linux.
14 # bindings working already under MacOSX and Linux.
15
15
16 if {[tk windowingsystem] eq "win32"} {
16 if {[tk windowingsystem] eq "win32"} {
17
17
18 set mw_classes [list Text Listbox Table TreeCtrl]
18 set mw_classes [list Text Listbox Table TreeCtrl]
19 foreach class $mw_classes { bind $class <MouseWheel> {} }
19 foreach class $mw_classes { bind $class <MouseWheel> {} }
20
20
21 set in_mousewheel 0
21 set in_mousewheel 0
22
22
23 proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
23 proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
24 global in_mousewheel
24 global in_mousewheel
25 if { $in_mousewheel != 0 } { return }
25 if { $in_mousewheel != 0 } { return }
26 # Set event to check based on call
26 # Set event to check based on call
27 set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
27 set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
28 # do not double-fire in case the class already has a binding
28 # do not double-fire in case the class already has a binding
29 if {[bind [winfo class $wFired] $evt] ne ""} { return }
29 if {[bind [winfo class $wFired] $evt] ne ""} { return }
30 # obtain the window the mouse is over
30 # obtain the window the mouse is over
31 set w [winfo containing $X $Y]
31 set w [winfo containing $X $Y]
32 # if we are outside the app, try and scroll the focus widget
32 # if we are outside the app, try and scroll the focus widget
33 if {![winfo exists $w]} { catch {set w [focus]} }
33 if {![winfo exists $w]} { catch {set w [focus]} }
34 if {[winfo exists $w]} {
34 if {[winfo exists $w]} {
35
35
36 if {[bind $w $evt] ne ""} {
36 if {[bind $w $evt] ne ""} {
37 # Awkward ... this widget has a MouseWheel binding, but to
37 # Awkward ... this widget has a MouseWheel binding, but to
38 # trigger successfully in it, we must give it focus.
38 # trigger successfully in it, we must give it focus.
39 catch {focus} old
39 catch {focus} old
40 if {$w ne $old} { focus $w }
40 if {$w ne $old} { focus $w }
41 set in_mousewheel 1
41 set in_mousewheel 1
42 event generate $w $evt -rootx $X -rooty $Y -delta $D
42 event generate $w $evt -rootx $X -rooty $Y -delta $D
43 set in_mousewheel 0
43 set in_mousewheel 0
44 if {$w ne $old} { focus $old }
44 if {$w ne $old} { focus $old }
45 return
45 return
46 }
46 }
47
47
48 # aqua and x11/win32 have different delta handling
48 # aqua and x11/win32 have different delta handling
49 if {[tk windowingsystem] ne "aqua"} {
49 if {[tk windowingsystem] ne "aqua"} {
50 set delta [expr {- ($D / 30)}]
50 set delta [expr {- ($D / 30)}]
51 } else {
51 } else {
52 set delta [expr {- ($D)}]
52 set delta [expr {- ($D)}]
53 }
53 }
54 # scrollbars have different call conventions
54 # scrollbars have different call conventions
55 if {[string match "*Scrollbar" [winfo class $w]]} {
55 if {[string match "*Scrollbar" [winfo class $w]]} {
56 catch {tk::ScrollByUnits $w \
56 catch {tk::ScrollByUnits $w \
57 [string index [$w cget -orient] 0] $delta}
57 [string index [$w cget -orient] 0] $delta}
58 } else {
58 } else {
59 set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
59 set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
60 scroll $delta units]
60 scroll $delta units]
61 # Walking up to find the proper widget (handles cases like
61 # Walking up to find the proper widget (handles cases like
62 # embedded widgets in a canvas)
62 # embedded widgets in a canvas)
63 while {[catch $cmd] && [winfo toplevel $w] ne $w} {
63 while {[catch $cmd] && [winfo toplevel $w] ne $w} {
64 set w [winfo parent $w]
64 set w [winfo parent $w]
65 }
65 }
66 }
66 }
67 }
67 }
68 }
68 }
69
69
70 bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
70 bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
71
71
72 # end of win32 section
72 # end of win32 section
73 }
73 }
74
74
75
75
76 # Unify right mouse button handling.
76 # Unify right mouse button handling.
77 # See "mouse buttons on macintosh" thread on comp.lang.tcl
77 # See "mouse buttons on macintosh" thread on comp.lang.tcl
78 if {[tk windowingsystem] eq "aqua"} {
78 if {[tk windowingsystem] eq "aqua"} {
79 event add <<B3>> <Control-ButtonPress-1>
79 event add <<B3>> <Control-ButtonPress-1>
80 event add <<B3>> <Button-2>
80 event add <<B3>> <Button-2>
81 } else {
81 } else {
82 event add <<B3>> <Button-3>
82 event add <<B3>> <Button-3>
83 }
83 }
84
84
85 proc gitdir {} {
85 proc gitdir {} {
86 global env
86 global env
87 if {[info exists env(GIT_DIR)]} {
87 if {[info exists env(GIT_DIR)]} {
88 return $env(GIT_DIR)
88 return $env(GIT_DIR)
89 } else {
89 } else {
90 return ".hg"
90 return ".hg"
91 }
91 }
92 }
92 }
93
93
94 proc getcommits {rargs} {
94 proc getcommits {rargs} {
95 global commits commfd phase canv mainfont env
95 global commits commfd phase canv mainfont env
96 global startmsecs nextupdate ncmupdate
96 global startmsecs nextupdate ncmupdate
97 global ctext maincursor textcursor leftover
97 global ctext maincursor textcursor leftover
98
98
99 # check that we can find a .git directory somewhere...
99 # check that we can find a .git directory somewhere...
100 set gitdir [gitdir]
100 set gitdir [gitdir]
101 if {![file isdirectory $gitdir]} {
101 if {![file isdirectory $gitdir]} {
102 error_popup "Cannot find the git directory \"$gitdir\"."
102 error_popup "Cannot find the git directory \"$gitdir\"."
103 exit 1
103 exit 1
104 }
104 }
105 set commits {}
105 set commits {}
106 set phase getcommits
106 set phase getcommits
107 set startmsecs [clock clicks -milliseconds]
107 set startmsecs [clock clicks -milliseconds]
108 set nextupdate [expr $startmsecs + 100]
108 set nextupdate [expr $startmsecs + 100]
109 set ncmupdate 1
109 set ncmupdate 1
110 set limit 0
110 set limit 0
111 set revargs {}
111 set revargs {}
112 for {set i 0} {$i < [llength $rargs]} {incr i} {
112 for {set i 0} {$i < [llength $rargs]} {incr i} {
113 set opt [lindex $rargs $i]
113 set opt [lindex $rargs $i]
114 if {$opt == "--limit"} {
114 if {$opt == "--limit"} {
115 incr i
115 incr i
116 set limit [lindex $rargs $i]
116 set limit [lindex $rargs $i]
117 } else {
117 } else {
118 lappend revargs $opt
118 lappend revargs $opt
119 }
119 }
120 }
120 }
121 if [catch {
121 if [catch {
122 set parse_args [concat --default HEAD $revargs]
122 set parse_args [concat --default HEAD $revargs]
123 set parse_temp [eval exec {$env(HG)} --config ui.report_untrusted=false debug-rev-parse $parse_args]
123 set parse_temp [eval exec {$env(HG)} --config ui.report_untrusted=false debug-rev-parse $parse_args]
124 regsub -all "\r\n" $parse_temp "\n" parse_temp
124 regsub -all "\r\n" $parse_temp "\n" parse_temp
125 set parsed_args [split $parse_temp "\n"]
125 set parsed_args [split $parse_temp "\n"]
126 } err] {
126 } err] {
127 # if git-rev-parse failed for some reason...
127 # if git-rev-parse failed for some reason...
128 if {$rargs == {}} {
128 if {$rargs == {}} {
129 set revargs HEAD
129 set revargs HEAD
130 }
130 }
131 set parsed_args $revargs
131 set parsed_args $revargs
132 }
132 }
133 if {$limit > 0} {
133 if {$limit > 0} {
134 set parsed_args [concat -n $limit $parsed_args]
134 set parsed_args [concat -n $limit $parsed_args]
135 }
135 }
136 if [catch {
136 if [catch {
137 set commfd [open "|{$env(HG)} --config ui.report_untrusted=false debug-rev-list --header --topo-order --parents $parsed_args" r]
137 set commfd [open "|{$env(HG)} --config ui.report_untrusted=false debug-rev-list --header --topo-order --parents $parsed_args" r]
138 } err] {
138 } err] {
139 puts stderr "Error executing hg debug-rev-list: $err"
139 puts stderr "Error executing hg debug-rev-list: $err"
140 exit 1
140 exit 1
141 }
141 }
142 set leftover {}
142 set leftover {}
143 fconfigure $commfd -blocking 0 -translation lf
143 fconfigure $commfd -blocking 0 -translation lf
144 fileevent $commfd readable [list getcommitlines $commfd]
144 fileevent $commfd readable [list getcommitlines $commfd]
145 $canv delete all
145 $canv delete all
146 $canv create text 3 3 -anchor nw -text "Reading commits..." \
146 $canv create text 3 3 -anchor nw -text "Reading commits..." \
147 -font $mainfont -tags textitems
147 -font $mainfont -tags textitems
148 . config -cursor watch
148 . config -cursor watch
149 settextcursor watch
149 settextcursor watch
150 }
150 }
151
151
152 proc getcommitlines {commfd} {
152 proc getcommitlines {commfd} {
153 global commits parents cdate children
153 global commits parents cdate children
154 global commitlisted phase commitinfo nextupdate
154 global commitlisted phase commitinfo nextupdate
155 global stopped redisplaying leftover
155 global stopped redisplaying leftover
156
156
157 set stuff [read $commfd]
157 set stuff [read $commfd]
158 if {$stuff == {}} {
158 if {$stuff == {}} {
159 if {![eof $commfd]} return
159 if {![eof $commfd]} return
160 # set it blocking so we wait for the process to terminate
160 # set it blocking so we wait for the process to terminate
161 fconfigure $commfd -blocking 1
161 fconfigure $commfd -blocking 1
162 if {![catch {close $commfd} err]} {
162 if {![catch {close $commfd} err]} {
163 after idle finishcommits
163 after idle finishcommits
164 return
164 return
165 }
165 }
166 if {[string range $err 0 4] == "usage"} {
166 if {[string range $err 0 4] == "usage"} {
167 set err \
167 set err \
168 {Gitk: error reading commits: bad arguments to git-rev-list.
168 {Gitk: error reading commits: bad arguments to git-rev-list.
169 (Note: arguments to gitk are passed to git-rev-list
169 (Note: arguments to gitk are passed to git-rev-list
170 to allow selection of commits to be displayed.)}
170 to allow selection of commits to be displayed.)}
171 } else {
171 } else {
172 set err "Error reading commits: $err"
172 set err "Error reading commits: $err"
173 }
173 }
174 error_popup $err
174 error_popup $err
175 exit 1
175 exit 1
176 }
176 }
177 set start 0
177 set start 0
178 while 1 {
178 while 1 {
179 set i [string first "\0" $stuff $start]
179 set i [string first "\0" $stuff $start]
180 if {$i < 0} {
180 if {$i < 0} {
181 append leftover [string range $stuff $start end]
181 append leftover [string range $stuff $start end]
182 return
182 return
183 }
183 }
184 set cmit [string range $stuff $start [expr {$i - 1}]]
184 set cmit [string range $stuff $start [expr {$i - 1}]]
185 if {$start == 0} {
185 if {$start == 0} {
186 set cmit "$leftover$cmit"
186 set cmit "$leftover$cmit"
187 set leftover {}
187 set leftover {}
188 }
188 }
189 set start [expr {$i + 1}]
189 set start [expr {$i + 1}]
190 regsub -all "\r\n" $cmit "\n" cmit
190 regsub -all "\r\n" $cmit "\n" cmit
191 set j [string first "\n" $cmit]
191 set j [string first "\n" $cmit]
192 set ok 0
192 set ok 0
193 if {$j >= 0} {
193 if {$j >= 0} {
194 set ids [string range $cmit 0 [expr {$j - 1}]]
194 set ids [string range $cmit 0 [expr {$j - 1}]]
195 set ok 1
195 set ok 1
196 foreach id $ids {
196 foreach id $ids {
197 if {![regexp {^[0-9a-f]{12}$} $id]} {
197 if {![regexp {^[0-9a-f]{12}$} $id]} {
198 set ok 0
198 set ok 0
199 break
199 break
200 }
200 }
201 }
201 }
202 }
202 }
203 if {!$ok} {
203 if {!$ok} {
204 set shortcmit $cmit
204 set shortcmit $cmit
205 if {[string length $shortcmit] > 80} {
205 if {[string length $shortcmit] > 80} {
206 set shortcmit "[string range $shortcmit 0 80]..."
206 set shortcmit "[string range $shortcmit 0 80]..."
207 }
207 }
208 error_popup "Can't parse hg debug-rev-list output: {$shortcmit}"
208 error_popup "Can't parse hg debug-rev-list output: {$shortcmit}"
209 exit 1
209 exit 1
210 }
210 }
211 set id [lindex $ids 0]
211 set id [lindex $ids 0]
212 set olds [lrange $ids 1 end]
212 set olds [lrange $ids 1 end]
213 set cmit [string range $cmit [expr {$j + 1}] end]
213 set cmit [string range $cmit [expr {$j + 1}] end]
214 lappend commits $id
214 lappend commits $id
215 set commitlisted($id) 1
215 set commitlisted($id) 1
216 parsecommit $id $cmit 1 [lrange $ids 1 end]
216 parsecommit $id $cmit 1 [lrange $ids 1 end]
217 drawcommit $id
217 drawcommit $id
218 if {[clock clicks -milliseconds] >= $nextupdate} {
218 if {[clock clicks -milliseconds] >= $nextupdate} {
219 doupdate 1
219 doupdate 1
220 }
220 }
221 while {$redisplaying} {
221 while {$redisplaying} {
222 set redisplaying 0
222 set redisplaying 0
223 if {$stopped == 1} {
223 if {$stopped == 1} {
224 set stopped 0
224 set stopped 0
225 set phase "getcommits"
225 set phase "getcommits"
226 foreach id $commits {
226 foreach id $commits {
227 drawcommit $id
227 drawcommit $id
228 if {$stopped} break
228 if {$stopped} break
229 if {[clock clicks -milliseconds] >= $nextupdate} {
229 if {[clock clicks -milliseconds] >= $nextupdate} {
230 doupdate 1
230 doupdate 1
231 }
231 }
232 }
232 }
233 }
233 }
234 }
234 }
235 }
235 }
236 }
236 }
237
237
238 proc doupdate {reading} {
238 proc doupdate {reading} {
239 global commfd nextupdate numcommits ncmupdate
239 global commfd nextupdate numcommits ncmupdate
240
240
241 if {$reading} {
241 if {$reading} {
242 fileevent $commfd readable {}
242 fileevent $commfd readable {}
243 }
243 }
244 update
244 update
245 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
245 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
246 if {$numcommits < 100} {
246 if {$numcommits < 100} {
247 set ncmupdate [expr {$numcommits + 1}]
247 set ncmupdate [expr {$numcommits + 1}]
248 } elseif {$numcommits < 10000} {
248 } elseif {$numcommits < 10000} {
249 set ncmupdate [expr {$numcommits + 10}]
249 set ncmupdate [expr {$numcommits + 10}]
250 } else {
250 } else {
251 set ncmupdate [expr {$numcommits + 100}]
251 set ncmupdate [expr {$numcommits + 100}]
252 }
252 }
253 if {$reading} {
253 if {$reading} {
254 fileevent $commfd readable [list getcommitlines $commfd]
254 fileevent $commfd readable [list getcommitlines $commfd]
255 }
255 }
256 }
256 }
257
257
258 proc readcommit {id} {
258 proc readcommit {id} {
259 global env
259 global env
260 if [catch {set contents [exec $env(HG) --config ui.report_untrusted=false debug-cat-file commit $id]}] return
260 if [catch {set contents [exec $env(HG) --config ui.report_untrusted=false debug-cat-file commit $id]}] return
261 parsecommit $id $contents 0 {}
261 parsecommit $id $contents 0 {}
262 }
262 }
263
263
264 proc parsecommit {id contents listed olds} {
264 proc parsecommit {id contents listed olds} {
265 global commitinfo children nchildren parents nparents cdate ncleft
265 global commitinfo children nchildren parents nparents cdate ncleft
266
266
267 set inhdr 1
267 set inhdr 1
268 set comment {}
268 set comment {}
269 set headline {}
269 set headline {}
270 set auname {}
270 set auname {}
271 set audate {}
271 set audate {}
272 set comname {}
272 set comname {}
273 set comdate {}
273 set comdate {}
274 set rev {}
274 set rev {}
275 if {![info exists nchildren($id)]} {
275 if {![info exists nchildren($id)]} {
276 set children($id) {}
276 set children($id) {}
277 set nchildren($id) 0
277 set nchildren($id) 0
278 set ncleft($id) 0
278 set ncleft($id) 0
279 }
279 }
280 set parents($id) $olds
280 set parents($id) $olds
281 set nparents($id) [llength $olds]
281 set nparents($id) [llength $olds]
282 foreach p $olds {
282 foreach p $olds {
283 if {![info exists nchildren($p)]} {
283 if {![info exists nchildren($p)]} {
284 set children($p) [list $id]
284 set children($p) [list $id]
285 set nchildren($p) 1
285 set nchildren($p) 1
286 set ncleft($p) 1
286 set ncleft($p) 1
287 } elseif {[lsearch -exact $children($p) $id] < 0} {
287 } elseif {[lsearch -exact $children($p) $id] < 0} {
288 lappend children($p) $id
288 lappend children($p) $id
289 incr nchildren($p)
289 incr nchildren($p)
290 incr ncleft($p)
290 incr ncleft($p)
291 }
291 }
292 }
292 }
293 regsub -all "\r\n" $contents "\n" contents
293 regsub -all "\r\n" $contents "\n" contents
294 foreach line [split $contents "\n"] {
294 foreach line [split $contents "\n"] {
295 if {$inhdr} {
295 if {$inhdr} {
296 set line [split $line]
296 set line [split $line]
297 if {$line == {}} {
297 if {$line == {}} {
298 set inhdr 0
298 set inhdr 0
299 } else {
299 } else {
300 set tag [lindex $line 0]
300 set tag [lindex $line 0]
301 if {$tag == "author"} {
301 if {$tag == "author"} {
302 set x [expr {[llength $line] - 2}]
302 set x [expr {[llength $line] - 2}]
303 set audate [lindex $line $x]
303 set audate [lindex $line $x]
304 set auname [join [lrange $line 1 [expr {$x - 1}]]]
304 set auname [join [lrange $line 1 [expr {$x - 1}]]]
305 } elseif {$tag == "committer"} {
305 } elseif {$tag == "committer"} {
306 set x [expr {[llength $line] - 2}]
306 set x [expr {[llength $line] - 2}]
307 set comdate [lindex $line $x]
307 set comdate [lindex $line $x]
308 set comname [join [lrange $line 1 [expr {$x - 1}]]]
308 set comname [join [lrange $line 1 [expr {$x - 1}]]]
309 } elseif {$tag == "revision"} {
309 } elseif {$tag == "revision"} {
310 set rev [lindex $line 1]
310 set rev [lindex $line 1]
311 }
311 }
312 }
312 }
313 } else {
313 } else {
314 if {$comment == {}} {
314 if {$comment == {}} {
315 set headline [string trim $line]
315 set headline [string trim $line]
316 } else {
316 } else {
317 append comment "\n"
317 append comment "\n"
318 }
318 }
319 if {!$listed} {
319 if {!$listed} {
320 # git-rev-list indents the comment by 4 spaces;
320 # git-rev-list indents the comment by 4 spaces;
321 # if we got this via git-cat-file, add the indentation
321 # if we got this via git-cat-file, add the indentation
322 append comment " "
322 append comment " "
323 }
323 }
324 append comment $line
324 append comment $line
325 }
325 }
326 }
326 }
327 if {$audate != {}} {
327 if {$audate != {}} {
328 set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
328 set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
329 }
329 }
330 if {$comdate != {}} {
330 if {$comdate != {}} {
331 set cdate($id) $comdate
331 set cdate($id) $comdate
332 set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
332 set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
333 }
333 }
334 set commitinfo($id) [list $headline $auname $audate \
334 set commitinfo($id) [list $headline $auname $audate \
335 $comname $comdate $comment $rev]
335 $comname $comdate $comment $rev]
336 }
336 }
337
337
338 proc readrefs {} {
338 proc readrefs {} {
339 global tagids idtags headids idheads tagcontents env
339 global tagids idtags headids idheads tagcontents env
340
340
341 set tags [exec $env(HG) --config ui.report_untrusted=false tags]
341 set tags [exec $env(HG) --config ui.report_untrusted=false tags]
342 regsub -all "\r\n" $tags "\n" tags
342 regsub -all "\r\n" $tags "\n" tags
343 set lines [split $tags "\n"]
343 set lines [split $tags "\n"]
344 foreach f $lines {
344 foreach f $lines {
345 regexp {(\S+)$} $f full
345 regexp {(\S+)$} $f full
346 regsub {\s+(\S+)$} $f "" direct
346 regsub {\s+(\S+)$} $f "" direct
347 set sha [split $full ':']
347 set sha [split $full ':']
348 set tag [lindex $sha 1]
348 set tag [lindex $sha 1]
349 lappend tagids($direct) $tag
349 lappend tagids($direct) $tag
350 lappend idtags($tag) $direct
350 lappend idtags($tag) $direct
351 }
351 }
352 }
352 }
353
353
354 proc readotherrefs {base dname excl} {
354 proc readotherrefs {base dname excl} {
355 global otherrefids idotherrefs
355 global otherrefids idotherrefs
356
356
357 set git [gitdir]
357 set git [gitdir]
358 set files [glob -nocomplain -types f [file join $git $base *]]
358 set files [glob -nocomplain -types f [file join $git $base *]]
359 foreach f $files {
359 foreach f $files {
360 catch {
360 catch {
361 set fd [open $f r]
361 set fd [open $f r]
362 set line [read $fd 40]
362 set line [read $fd 40]
363 if {[regexp {^[0-9a-f]{12}} $line id]} {
363 if {[regexp {^[0-9a-f]{12}} $line id]} {
364 set name "$dname[file tail $f]"
364 set name "$dname[file tail $f]"
365 set otherrefids($name) $id
365 set otherrefids($name) $id
366 lappend idotherrefs($id) $name
366 lappend idotherrefs($id) $name
367 }
367 }
368 close $fd
368 close $fd
369 }
369 }
370 }
370 }
371 set dirs [glob -nocomplain -types d [file join $git $base *]]
371 set dirs [glob -nocomplain -types d [file join $git $base *]]
372 foreach d $dirs {
372 foreach d $dirs {
373 set dir [file tail $d]
373 set dir [file tail $d]
374 if {[lsearch -exact $excl $dir] >= 0} continue
374 if {[lsearch -exact $excl $dir] >= 0} continue
375 readotherrefs [file join $base $dir] "$dname$dir/" {}
375 readotherrefs [file join $base $dir] "$dname$dir/" {}
376 }
376 }
377 }
377 }
378
378
379 proc allcansmousewheel {delta} {
379 proc allcansmousewheel {delta} {
380 set delta [expr -5*(int($delta)/abs($delta))]
380 set delta [expr -5*(int($delta)/abs($delta))]
381 allcanvs yview scroll $delta units
381 allcanvs yview scroll $delta units
382 }
382 }
383
383
384 proc error_popup msg {
384 proc error_popup msg {
385 set w .error
385 set w .error
386 toplevel $w
386 toplevel $w
387 wm transient $w .
387 wm transient $w .
388 message $w.m -text $msg -justify center -aspect 400
388 message $w.m -text $msg -justify center -aspect 400
389 pack $w.m -side top -fill x -padx 20 -pady 20
389 pack $w.m -side top -fill x -padx 20 -pady 20
390 button $w.ok -text OK -command "destroy $w"
390 button $w.ok -text OK -command "destroy $w"
391 pack $w.ok -side bottom -fill x
391 pack $w.ok -side bottom -fill x
392 bind $w <Visibility> "grab $w; focus $w"
392 bind $w <Visibility> "grab $w; focus $w"
393 tkwait window $w
393 tkwait window $w
394 }
394 }
395
395
396 proc makewindow {} {
396 proc makewindow {} {
397 global canv canv2 canv3 linespc charspc ctext cflist textfont
397 global canv canv2 canv3 linespc charspc ctext cflist textfont
398 global findtype findtypemenu findloc findstring fstring geometry
398 global findtype findtypemenu findloc findstring fstring geometry
399 global entries sha1entry sha1string sha1but
399 global entries sha1entry sha1string sha1but
400 global maincursor textcursor curtextcursor
400 global maincursor textcursor curtextcursor
401 global rowctxmenu gaudydiff mergemax
401 global rowctxmenu gaudydiff mergemax
402 global hgvdiff
402
403
403 menu .bar
404 menu .bar
404 .bar add cascade -label "File" -menu .bar.file
405 .bar add cascade -label "File" -menu .bar.file
405 menu .bar.file
406 menu .bar.file
406 .bar.file add command -label "Reread references" -command rereadrefs
407 .bar.file add command -label "Reread references" -command rereadrefs
407 .bar.file add command -label "Quit" -command doquit
408 .bar.file add command -label "Quit" -command doquit
408 menu .bar.help
409 menu .bar.help
409 .bar add cascade -label "Help" -menu .bar.help
410 .bar add cascade -label "Help" -menu .bar.help
410 .bar.help add command -label "About gitk" -command about
411 .bar.help add command -label "About gitk" -command about
411 . configure -menu .bar
412 . configure -menu .bar
412
413
413 if {![info exists geometry(canv1)]} {
414 if {![info exists geometry(canv1)]} {
414 set geometry(canv1) [expr 45 * $charspc]
415 set geometry(canv1) [expr 45 * $charspc]
415 set geometry(canv2) [expr 30 * $charspc]
416 set geometry(canv2) [expr 30 * $charspc]
416 set geometry(canv3) [expr 15 * $charspc]
417 set geometry(canv3) [expr 15 * $charspc]
417 set geometry(canvh) [expr 25 * $linespc + 4]
418 set geometry(canvh) [expr 25 * $linespc + 4]
418 set geometry(ctextw) 80
419 set geometry(ctextw) 80
419 set geometry(ctexth) 30
420 set geometry(ctexth) 30
420 set geometry(cflistw) 30
421 set geometry(cflistw) 30
421 }
422 }
422 panedwindow .ctop -orient vertical
423 panedwindow .ctop -orient vertical
423 if {[info exists geometry(width)]} {
424 if {[info exists geometry(width)]} {
424 .ctop conf -width $geometry(width) -height $geometry(height)
425 .ctop conf -width $geometry(width) -height $geometry(height)
425 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
426 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
426 set geometry(ctexth) [expr {($texth - 8) /
427 set geometry(ctexth) [expr {($texth - 8) /
427 [font metrics $textfont -linespace]}]
428 [font metrics $textfont -linespace]}]
428 }
429 }
429 frame .ctop.top
430 frame .ctop.top
430 frame .ctop.top.bar
431 frame .ctop.top.bar
431 pack .ctop.top.bar -side bottom -fill x
432 pack .ctop.top.bar -side bottom -fill x
432 set cscroll .ctop.top.csb
433 set cscroll .ctop.top.csb
433 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
434 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
434 pack $cscroll -side right -fill y
435 pack $cscroll -side right -fill y
435 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
436 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
436 pack .ctop.top.clist -side top -fill both -expand 1
437 pack .ctop.top.clist -side top -fill both -expand 1
437 .ctop add .ctop.top
438 .ctop add .ctop.top
438 set canv .ctop.top.clist.canv
439 set canv .ctop.top.clist.canv
439 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
440 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
440 -bg white -bd 0 \
441 -bg white -bd 0 \
441 -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey
442 -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey
442 .ctop.top.clist add $canv
443 .ctop.top.clist add $canv
443 set canv2 .ctop.top.clist.canv2
444 set canv2 .ctop.top.clist.canv2
444 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
445 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
445 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
446 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
446 .ctop.top.clist add $canv2
447 .ctop.top.clist add $canv2
447 set canv3 .ctop.top.clist.canv3
448 set canv3 .ctop.top.clist.canv3
448 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
449 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
449 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
450 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
450 .ctop.top.clist add $canv3
451 .ctop.top.clist add $canv3
451 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
452 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
452
453
453 set sha1entry .ctop.top.bar.sha1
454 set sha1entry .ctop.top.bar.sha1
454 set entries $sha1entry
455 set entries $sha1entry
455 set sha1but .ctop.top.bar.sha1label
456 set sha1but .ctop.top.bar.sha1label
456 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
457 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
457 -command gotocommit -width 8
458 -command gotocommit -width 8
458 $sha1but conf -disabledforeground [$sha1but cget -foreground]
459 $sha1but conf -disabledforeground [$sha1but cget -foreground]
459 pack .ctop.top.bar.sha1label -side left
460 pack .ctop.top.bar.sha1label -side left
460 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
461 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
461 trace add variable sha1string write sha1change
462 trace add variable sha1string write sha1change
462 pack $sha1entry -side left -pady 2
463 pack $sha1entry -side left -pady 2
463
464
464 image create bitmap bm-left -data {
465 image create bitmap bm-left -data {
465 #define left_width 16
466 #define left_width 16
466 #define left_height 16
467 #define left_height 16
467 static unsigned char left_bits[] = {
468 static unsigned char left_bits[] = {
468 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
469 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
469 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
470 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
470 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
471 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
471 }
472 }
472 image create bitmap bm-right -data {
473 image create bitmap bm-right -data {
473 #define right_width 16
474 #define right_width 16
474 #define right_height 16
475 #define right_height 16
475 static unsigned char right_bits[] = {
476 static unsigned char right_bits[] = {
476 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
477 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
477 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
478 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
478 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
479 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
479 }
480 }
480 button .ctop.top.bar.leftbut -image bm-left -command goback \
481 button .ctop.top.bar.leftbut -image bm-left -command goback \
481 -state disabled -width 26
482 -state disabled -width 26
482 pack .ctop.top.bar.leftbut -side left -fill y
483 pack .ctop.top.bar.leftbut -side left -fill y
483 button .ctop.top.bar.rightbut -image bm-right -command goforw \
484 button .ctop.top.bar.rightbut -image bm-right -command goforw \
484 -state disabled -width 26
485 -state disabled -width 26
485 pack .ctop.top.bar.rightbut -side left -fill y
486 pack .ctop.top.bar.rightbut -side left -fill y
486
487
487 button .ctop.top.bar.findbut -text "Find" -command dofind
488 button .ctop.top.bar.findbut -text "Find" -command dofind
488 pack .ctop.top.bar.findbut -side left
489 pack .ctop.top.bar.findbut -side left
489 set findstring {}
490 set findstring {}
490 set fstring .ctop.top.bar.findstring
491 set fstring .ctop.top.bar.findstring
491 lappend entries $fstring
492 lappend entries $fstring
492 entry $fstring -width 30 -font $textfont -textvariable findstring
493 entry $fstring -width 30 -font $textfont -textvariable findstring
493 pack $fstring -side left -expand 1 -fill x
494 pack $fstring -side left -expand 1 -fill x
494 set findtype Exact
495 set findtype Exact
495 set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
496 set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
496 findtype Exact IgnCase Regexp]
497 findtype Exact IgnCase Regexp]
497 set findloc "All fields"
498 set findloc "All fields"
498 tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
499 tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
499 Comments Author Committer Files Pickaxe
500 Comments Author Committer Files Pickaxe
500 pack .ctop.top.bar.findloc -side right
501 pack .ctop.top.bar.findloc -side right
501 pack .ctop.top.bar.findtype -side right
502 pack .ctop.top.bar.findtype -side right
502 # for making sure type==Exact whenever loc==Pickaxe
503 # for making sure type==Exact whenever loc==Pickaxe
503 trace add variable findloc write findlocchange
504 trace add variable findloc write findlocchange
504
505
505 panedwindow .ctop.cdet -orient horizontal
506 panedwindow .ctop.cdet -orient horizontal
506 .ctop add .ctop.cdet
507 .ctop add .ctop.cdet
507 frame .ctop.cdet.left
508 frame .ctop.cdet.left
508 set ctext .ctop.cdet.left.ctext
509 set ctext .ctop.cdet.left.ctext
509 text $ctext -bg white -state disabled -font $textfont \
510 text $ctext -bg white -state disabled -font $textfont \
510 -width $geometry(ctextw) -height $geometry(ctexth) \
511 -width $geometry(ctextw) -height $geometry(ctexth) \
511 -yscrollcommand ".ctop.cdet.left.sb set" \
512 -yscrollcommand ".ctop.cdet.left.sb set" \
512 -xscrollcommand ".ctop.cdet.left.hb set" -wrap none
513 -xscrollcommand ".ctop.cdet.left.hb set" -wrap none
513 scrollbar .ctop.cdet.left.sb -command "$ctext yview"
514 scrollbar .ctop.cdet.left.sb -command "$ctext yview"
514 scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview"
515 scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview"
515 pack .ctop.cdet.left.sb -side right -fill y
516 pack .ctop.cdet.left.sb -side right -fill y
516 pack .ctop.cdet.left.hb -side bottom -fill x
517 pack .ctop.cdet.left.hb -side bottom -fill x
517 pack $ctext -side left -fill both -expand 1
518 pack $ctext -side left -fill both -expand 1
518 .ctop.cdet add .ctop.cdet.left
519 .ctop.cdet add .ctop.cdet.left
519
520
520 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
521 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
521 if {$gaudydiff} {
522 if {$gaudydiff} {
522 $ctext tag conf hunksep -back blue -fore white
523 $ctext tag conf hunksep -back blue -fore white
523 $ctext tag conf d0 -back "#ff8080"
524 $ctext tag conf d0 -back "#ff8080"
524 $ctext tag conf d1 -back green
525 $ctext tag conf d1 -back green
525 } else {
526 } else {
526 $ctext tag conf hunksep -fore blue
527 $ctext tag conf hunksep -fore blue
527 $ctext tag conf d0 -fore red
528 $ctext tag conf d0 -fore red
528 $ctext tag conf d1 -fore "#00a000"
529 $ctext tag conf d1 -fore "#00a000"
529 $ctext tag conf m0 -fore red
530 $ctext tag conf m0 -fore red
530 $ctext tag conf m1 -fore blue
531 $ctext tag conf m1 -fore blue
531 $ctext tag conf m2 -fore green
532 $ctext tag conf m2 -fore green
532 $ctext tag conf m3 -fore purple
533 $ctext tag conf m3 -fore purple
533 $ctext tag conf m4 -fore brown
534 $ctext tag conf m4 -fore brown
534 $ctext tag conf mmax -fore darkgrey
535 $ctext tag conf mmax -fore darkgrey
535 set mergemax 5
536 set mergemax 5
536 $ctext tag conf mresult -font [concat $textfont bold]
537 $ctext tag conf mresult -font [concat $textfont bold]
537 $ctext tag conf msep -font [concat $textfont bold]
538 $ctext tag conf msep -font [concat $textfont bold]
538 $ctext tag conf found -back yellow
539 $ctext tag conf found -back yellow
539 }
540 }
540
541
541 frame .ctop.cdet.right
542 frame .ctop.cdet.right
542 set cflist .ctop.cdet.right.cfiles
543 set cflist .ctop.cdet.right.cfiles
543 listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
544 listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
544 -yscrollcommand ".ctop.cdet.right.sb set"
545 -yscrollcommand ".ctop.cdet.right.sb set"
545 scrollbar .ctop.cdet.right.sb -command "$cflist yview"
546 scrollbar .ctop.cdet.right.sb -command "$cflist yview"
546 pack .ctop.cdet.right.sb -side right -fill y
547 pack .ctop.cdet.right.sb -side right -fill y
547 pack $cflist -side left -fill both -expand 1
548 pack $cflist -side left -fill both -expand 1
548 .ctop.cdet add .ctop.cdet.right
549 .ctop.cdet add .ctop.cdet.right
549 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
550 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
550
551
551 pack .ctop -side top -fill both -expand 1
552 pack .ctop -side top -fill both -expand 1
552
553
553 bindall <1> {selcanvline %W %x %y}
554 bindall <1> {selcanvline %W %x %y}
554 #bindall <B1-Motion> {selcanvline %W %x %y}
555 #bindall <B1-Motion> {selcanvline %W %x %y}
555 bindall <MouseWheel> "allcansmousewheel %D"
556 bindall <MouseWheel> "allcansmousewheel %D"
556 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
557 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
557 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
558 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
558 bindall <2> "allcanvs scan mark 0 %y"
559 bindall <2> "allcanvs scan mark 0 %y"
559 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
560 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
560 bind . <Key-Up> "selnextline -1"
561 bind . <Key-Up> "selnextline -1"
561 bind . <Key-Down> "selnextline 1"
562 bind . <Key-Down> "selnextline 1"
562 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
563 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
563 bind . <Key-Next> "allcanvs yview scroll 1 pages"
564 bind . <Key-Next> "allcanvs yview scroll 1 pages"
564 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
565 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
565 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
566 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
566 bindkey <Key-space> "$ctext yview scroll 1 pages"
567 bindkey <Key-space> "$ctext yview scroll 1 pages"
567 bindkey p "selnextline -1"
568 bindkey p "selnextline -1"
568 bindkey n "selnextline 1"
569 bindkey n "selnextline 1"
569 bindkey b "$ctext yview scroll -1 pages"
570 bindkey b "$ctext yview scroll -1 pages"
570 bindkey d "$ctext yview scroll 18 units"
571 bindkey d "$ctext yview scroll 18 units"
571 bindkey u "$ctext yview scroll -18 units"
572 bindkey u "$ctext yview scroll -18 units"
572 bindkey / {findnext 1}
573 bindkey / {findnext 1}
573 bindkey <Key-Return> {findnext 0}
574 bindkey <Key-Return> {findnext 0}
574 bindkey ? findprev
575 bindkey ? findprev
575 bindkey f nextfile
576 bindkey f nextfile
576 bind . <Control-q> doquit
577 bind . <Control-q> doquit
577 bind . <Control-w> doquit
578 bind . <Control-w> doquit
578 bind . <Control-f> dofind
579 bind . <Control-f> dofind
579 bind . <Control-g> {findnext 0}
580 bind . <Control-g> {findnext 0}
580 bind . <Control-r> findprev
581 bind . <Control-r> findprev
581 bind . <Control-equal> {incrfont 1}
582 bind . <Control-equal> {incrfont 1}
582 bind . <Control-KP_Add> {incrfont 1}
583 bind . <Control-KP_Add> {incrfont 1}
583 bind . <Control-minus> {incrfont -1}
584 bind . <Control-minus> {incrfont -1}
584 bind . <Control-KP_Subtract> {incrfont -1}
585 bind . <Control-KP_Subtract> {incrfont -1}
585 bind $cflist <<ListboxSelect>> listboxsel
586 bind $cflist <<ListboxSelect>> listboxsel
586 bind . <Destroy> {savestuff %W}
587 bind . <Destroy> {savestuff %W}
587 bind . <Button-1> "click %W"
588 bind . <Button-1> "click %W"
588 bind $fstring <Key-Return> dofind
589 bind $fstring <Key-Return> dofind
589 bind $sha1entry <Key-Return> gotocommit
590 bind $sha1entry <Key-Return> gotocommit
590 bind $sha1entry <<PasteSelection>> clearsha1
591 bind $sha1entry <<PasteSelection>> clearsha1
591
592
592 set maincursor [. cget -cursor]
593 set maincursor [. cget -cursor]
593 set textcursor [$ctext cget -cursor]
594 set textcursor [$ctext cget -cursor]
594 set curtextcursor $textcursor
595 set curtextcursor $textcursor
595
596
596 set rowctxmenu .rowctxmenu
597 set rowctxmenu .rowctxmenu
597 menu $rowctxmenu -tearoff 0
598 menu $rowctxmenu -tearoff 0
598 $rowctxmenu add command -label "Diff this -> selected" \
599 $rowctxmenu add command -label "Diff this -> selected" \
599 -command {diffvssel 0}
600 -command {diffvssel 0}
600 $rowctxmenu add command -label "Diff selected -> this" \
601 $rowctxmenu add command -label "Diff selected -> this" \
601 -command {diffvssel 1}
602 -command {diffvssel 1}
602 $rowctxmenu add command -label "Make patch" -command mkpatch
603 $rowctxmenu add command -label "Make patch" -command mkpatch
603 $rowctxmenu add command -label "Create tag" -command mktag
604 $rowctxmenu add command -label "Create tag" -command mktag
604 $rowctxmenu add command -label "Write commit to file" -command writecommit
605 $rowctxmenu add command -label "Write commit to file" -command writecommit
606 if { $hgvdiff ne "" } {
607 $rowctxmenu add command -label "Visual diff with parent" \
608 -command {vdiff 1}
609 $rowctxmenu add command -label "Visual diff with selected" \
610 -command {vdiff 0}
611 }
605 }
612 }
606
613
607 # when we make a key binding for the toplevel, make sure
614 # when we make a key binding for the toplevel, make sure
608 # it doesn't get triggered when that key is pressed in the
615 # it doesn't get triggered when that key is pressed in the
609 # find string entry widget.
616 # find string entry widget.
610 proc bindkey {ev script} {
617 proc bindkey {ev script} {
611 global entries
618 global entries
612 bind . $ev $script
619 bind . $ev $script
613 set escript [bind Entry $ev]
620 set escript [bind Entry $ev]
614 if {$escript == {}} {
621 if {$escript == {}} {
615 set escript [bind Entry <Key>]
622 set escript [bind Entry <Key>]
616 }
623 }
617 foreach e $entries {
624 foreach e $entries {
618 bind $e $ev "$escript; break"
625 bind $e $ev "$escript; break"
619 }
626 }
620 }
627 }
621
628
622 # set the focus back to the toplevel for any click outside
629 # set the focus back to the toplevel for any click outside
623 # the entry widgets
630 # the entry widgets
624 proc click {w} {
631 proc click {w} {
625 global entries
632 global entries
626 foreach e $entries {
633 foreach e $entries {
627 if {$w == $e} return
634 if {$w == $e} return
628 }
635 }
629 focus .
636 focus .
630 }
637 }
631
638
632 proc savestuff {w} {
639 proc savestuff {w} {
633 global canv canv2 canv3 ctext cflist mainfont textfont
640 global canv canv2 canv3 ctext cflist mainfont textfont
634 global stuffsaved findmergefiles gaudydiff maxgraphpct
641 global stuffsaved findmergefiles gaudydiff maxgraphpct
635 global maxwidth
642 global maxwidth
636
643
637 if {$stuffsaved} return
644 if {$stuffsaved} return
638 if {![winfo viewable .]} return
645 if {![winfo viewable .]} return
639 catch {
646 catch {
640 set f [open "~/.gitk-new" w]
647 set f [open "~/.gitk-new" w]
641 puts $f [list set mainfont $mainfont]
648 puts $f [list set mainfont $mainfont]
642 puts $f [list set textfont $textfont]
649 puts $f [list set textfont $textfont]
643 puts $f [list set findmergefiles $findmergefiles]
650 puts $f [list set findmergefiles $findmergefiles]
644 puts $f [list set gaudydiff $gaudydiff]
651 puts $f [list set gaudydiff $gaudydiff]
645 puts $f [list set maxgraphpct $maxgraphpct]
652 puts $f [list set maxgraphpct $maxgraphpct]
646 puts $f [list set maxwidth $maxwidth]
653 puts $f [list set maxwidth $maxwidth]
647 puts $f "set geometry(width) [winfo width .ctop]"
654 puts $f "set geometry(width) [winfo width .ctop]"
648 puts $f "set geometry(height) [winfo height .ctop]"
655 puts $f "set geometry(height) [winfo height .ctop]"
649 puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
656 puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
650 puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
657 puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
651 puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
658 puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
652 puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
659 puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
653 set wid [expr {([winfo width $ctext] - 8) \
660 set wid [expr {([winfo width $ctext] - 8) \
654 / [font measure $textfont "0"]}]
661 / [font measure $textfont "0"]}]
655 puts $f "set geometry(ctextw) $wid"
662 puts $f "set geometry(ctextw) $wid"
656 set wid [expr {([winfo width $cflist] - 11) \
663 set wid [expr {([winfo width $cflist] - 11) \
657 / [font measure [$cflist cget -font] "0"]}]
664 / [font measure [$cflist cget -font] "0"]}]
658 puts $f "set geometry(cflistw) $wid"
665 puts $f "set geometry(cflistw) $wid"
659 close $f
666 close $f
660 file rename -force "~/.gitk-new" "~/.gitk"
667 file rename -force "~/.gitk-new" "~/.gitk"
661 }
668 }
662 set stuffsaved 1
669 set stuffsaved 1
663 }
670 }
664
671
665 proc resizeclistpanes {win w} {
672 proc resizeclistpanes {win w} {
666 global oldwidth
673 global oldwidth
667 if [info exists oldwidth($win)] {
674 if [info exists oldwidth($win)] {
668 set s0 [$win sash coord 0]
675 set s0 [$win sash coord 0]
669 set s1 [$win sash coord 1]
676 set s1 [$win sash coord 1]
670 if {$w < 60} {
677 if {$w < 60} {
671 set sash0 [expr {int($w/2 - 2)}]
678 set sash0 [expr {int($w/2 - 2)}]
672 set sash1 [expr {int($w*5/6 - 2)}]
679 set sash1 [expr {int($w*5/6 - 2)}]
673 } else {
680 } else {
674 set factor [expr {1.0 * $w / $oldwidth($win)}]
681 set factor [expr {1.0 * $w / $oldwidth($win)}]
675 set sash0 [expr {int($factor * [lindex $s0 0])}]
682 set sash0 [expr {int($factor * [lindex $s0 0])}]
676 set sash1 [expr {int($factor * [lindex $s1 0])}]
683 set sash1 [expr {int($factor * [lindex $s1 0])}]
677 if {$sash0 < 30} {
684 if {$sash0 < 30} {
678 set sash0 30
685 set sash0 30
679 }
686 }
680 if {$sash1 < $sash0 + 20} {
687 if {$sash1 < $sash0 + 20} {
681 set sash1 [expr $sash0 + 20]
688 set sash1 [expr $sash0 + 20]
682 }
689 }
683 if {$sash1 > $w - 10} {
690 if {$sash1 > $w - 10} {
684 set sash1 [expr $w - 10]
691 set sash1 [expr $w - 10]
685 if {$sash0 > $sash1 - 20} {
692 if {$sash0 > $sash1 - 20} {
686 set sash0 [expr $sash1 - 20]
693 set sash0 [expr $sash1 - 20]
687 }
694 }
688 }
695 }
689 }
696 }
690 $win sash place 0 $sash0 [lindex $s0 1]
697 $win sash place 0 $sash0 [lindex $s0 1]
691 $win sash place 1 $sash1 [lindex $s1 1]
698 $win sash place 1 $sash1 [lindex $s1 1]
692 }
699 }
693 set oldwidth($win) $w
700 set oldwidth($win) $w
694 }
701 }
695
702
696 proc resizecdetpanes {win w} {
703 proc resizecdetpanes {win w} {
697 global oldwidth
704 global oldwidth
698 if [info exists oldwidth($win)] {
705 if [info exists oldwidth($win)] {
699 set s0 [$win sash coord 0]
706 set s0 [$win sash coord 0]
700 if {$w < 60} {
707 if {$w < 60} {
701 set sash0 [expr {int($w*3/4 - 2)}]
708 set sash0 [expr {int($w*3/4 - 2)}]
702 } else {
709 } else {
703 set factor [expr {1.0 * $w / $oldwidth($win)}]
710 set factor [expr {1.0 * $w / $oldwidth($win)}]
704 set sash0 [expr {int($factor * [lindex $s0 0])}]
711 set sash0 [expr {int($factor * [lindex $s0 0])}]
705 if {$sash0 < 45} {
712 if {$sash0 < 45} {
706 set sash0 45
713 set sash0 45
707 }
714 }
708 if {$sash0 > $w - 15} {
715 if {$sash0 > $w - 15} {
709 set sash0 [expr $w - 15]
716 set sash0 [expr $w - 15]
710 }
717 }
711 }
718 }
712 $win sash place 0 $sash0 [lindex $s0 1]
719 $win sash place 0 $sash0 [lindex $s0 1]
713 }
720 }
714 set oldwidth($win) $w
721 set oldwidth($win) $w
715 }
722 }
716
723
717 proc allcanvs args {
724 proc allcanvs args {
718 global canv canv2 canv3
725 global canv canv2 canv3
719 eval $canv $args
726 eval $canv $args
720 eval $canv2 $args
727 eval $canv2 $args
721 eval $canv3 $args
728 eval $canv3 $args
722 }
729 }
723
730
724 proc bindall {event action} {
731 proc bindall {event action} {
725 global canv canv2 canv3
732 global canv canv2 canv3
726 bind $canv $event $action
733 bind $canv $event $action
727 bind $canv2 $event $action
734 bind $canv2 $event $action
728 bind $canv3 $event $action
735 bind $canv3 $event $action
729 }
736 }
730
737
731 proc about {} {
738 proc about {} {
732 set w .about
739 set w .about
733 if {[winfo exists $w]} {
740 if {[winfo exists $w]} {
734 raise $w
741 raise $w
735 return
742 return
736 }
743 }
737 toplevel $w
744 toplevel $w
738 wm title $w "About gitk"
745 wm title $w "About gitk"
739 message $w.m -text {
746 message $w.m -text {
740 Gitk version 1.2
747 Gitk version 1.2
741
748
742 Copyright οΏ½ 2005 Paul Mackerras
749 Copyright οΏ½ 2005 Paul Mackerras
743
750
744 Use and redistribute under the terms of the GNU General Public License} \
751 Use and redistribute under the terms of the GNU General Public License} \
745 -justify center -aspect 400
752 -justify center -aspect 400
746 pack $w.m -side top -fill x -padx 20 -pady 20
753 pack $w.m -side top -fill x -padx 20 -pady 20
747 button $w.ok -text Close -command "destroy $w"
754 button $w.ok -text Close -command "destroy $w"
748 pack $w.ok -side bottom
755 pack $w.ok -side bottom
749 }
756 }
750
757
751 proc assigncolor {id} {
758 proc assigncolor {id} {
752 global commitinfo colormap commcolors colors nextcolor
759 global commitinfo colormap commcolors colors nextcolor
753 global parents nparents children nchildren
760 global parents nparents children nchildren
754 global cornercrossings crossings
761 global cornercrossings crossings
755
762
756 if [info exists colormap($id)] return
763 if [info exists colormap($id)] return
757 set ncolors [llength $colors]
764 set ncolors [llength $colors]
758 if {$nparents($id) <= 1 && $nchildren($id) == 1} {
765 if {$nparents($id) <= 1 && $nchildren($id) == 1} {
759 set child [lindex $children($id) 0]
766 set child [lindex $children($id) 0]
760 if {[info exists colormap($child)]
767 if {[info exists colormap($child)]
761 && $nparents($child) == 1} {
768 && $nparents($child) == 1} {
762 set colormap($id) $colormap($child)
769 set colormap($id) $colormap($child)
763 return
770 return
764 }
771 }
765 }
772 }
766 set badcolors {}
773 set badcolors {}
767 if {[info exists cornercrossings($id)]} {
774 if {[info exists cornercrossings($id)]} {
768 foreach x $cornercrossings($id) {
775 foreach x $cornercrossings($id) {
769 if {[info exists colormap($x)]
776 if {[info exists colormap($x)]
770 && [lsearch -exact $badcolors $colormap($x)] < 0} {
777 && [lsearch -exact $badcolors $colormap($x)] < 0} {
771 lappend badcolors $colormap($x)
778 lappend badcolors $colormap($x)
772 }
779 }
773 }
780 }
774 if {[llength $badcolors] >= $ncolors} {
781 if {[llength $badcolors] >= $ncolors} {
775 set badcolors {}
782 set badcolors {}
776 }
783 }
777 }
784 }
778 set origbad $badcolors
785 set origbad $badcolors
779 if {[llength $badcolors] < $ncolors - 1} {
786 if {[llength $badcolors] < $ncolors - 1} {
780 if {[info exists crossings($id)]} {
787 if {[info exists crossings($id)]} {
781 foreach x $crossings($id) {
788 foreach x $crossings($id) {
782 if {[info exists colormap($x)]
789 if {[info exists colormap($x)]
783 && [lsearch -exact $badcolors $colormap($x)] < 0} {
790 && [lsearch -exact $badcolors $colormap($x)] < 0} {
784 lappend badcolors $colormap($x)
791 lappend badcolors $colormap($x)
785 }
792 }
786 }
793 }
787 if {[llength $badcolors] >= $ncolors} {
794 if {[llength $badcolors] >= $ncolors} {
788 set badcolors $origbad
795 set badcolors $origbad
789 }
796 }
790 }
797 }
791 set origbad $badcolors
798 set origbad $badcolors
792 }
799 }
793 if {[llength $badcolors] < $ncolors - 1} {
800 if {[llength $badcolors] < $ncolors - 1} {
794 foreach child $children($id) {
801 foreach child $children($id) {
795 if {[info exists colormap($child)]
802 if {[info exists colormap($child)]
796 && [lsearch -exact $badcolors $colormap($child)] < 0} {
803 && [lsearch -exact $badcolors $colormap($child)] < 0} {
797 lappend badcolors $colormap($child)
804 lappend badcolors $colormap($child)
798 }
805 }
799 if {[info exists parents($child)]} {
806 if {[info exists parents($child)]} {
800 foreach p $parents($child) {
807 foreach p $parents($child) {
801 if {[info exists colormap($p)]
808 if {[info exists colormap($p)]
802 && [lsearch -exact $badcolors $colormap($p)] < 0} {
809 && [lsearch -exact $badcolors $colormap($p)] < 0} {
803 lappend badcolors $colormap($p)
810 lappend badcolors $colormap($p)
804 }
811 }
805 }
812 }
806 }
813 }
807 }
814 }
808 if {[llength $badcolors] >= $ncolors} {
815 if {[llength $badcolors] >= $ncolors} {
809 set badcolors $origbad
816 set badcolors $origbad
810 }
817 }
811 }
818 }
812 for {set i 0} {$i <= $ncolors} {incr i} {
819 for {set i 0} {$i <= $ncolors} {incr i} {
813 set c [lindex $colors $nextcolor]
820 set c [lindex $colors $nextcolor]
814 if {[incr nextcolor] >= $ncolors} {
821 if {[incr nextcolor] >= $ncolors} {
815 set nextcolor 0
822 set nextcolor 0
816 }
823 }
817 if {[lsearch -exact $badcolors $c]} break
824 if {[lsearch -exact $badcolors $c]} break
818 }
825 }
819 set colormap($id) $c
826 set colormap($id) $c
820 }
827 }
821
828
822 proc initgraph {} {
829 proc initgraph {} {
823 global canvy canvy0 lineno numcommits nextcolor linespc
830 global canvy canvy0 lineno numcommits nextcolor linespc
824 global mainline mainlinearrow sidelines
831 global mainline mainlinearrow sidelines
825 global nchildren ncleft
832 global nchildren ncleft
826 global displist nhyperspace
833 global displist nhyperspace
827
834
828 allcanvs delete all
835 allcanvs delete all
829 set nextcolor 0
836 set nextcolor 0
830 set canvy $canvy0
837 set canvy $canvy0
831 set lineno -1
838 set lineno -1
832 set numcommits 0
839 set numcommits 0
833 catch {unset mainline}
840 catch {unset mainline}
834 catch {unset mainlinearrow}
841 catch {unset mainlinearrow}
835 catch {unset sidelines}
842 catch {unset sidelines}
836 foreach id [array names nchildren] {
843 foreach id [array names nchildren] {
837 set ncleft($id) $nchildren($id)
844 set ncleft($id) $nchildren($id)
838 }
845 }
839 set displist {}
846 set displist {}
840 set nhyperspace 0
847 set nhyperspace 0
841 }
848 }
842
849
843 proc bindline {t id} {
850 proc bindline {t id} {
844 global canv
851 global canv
845
852
846 $canv bind $t <Enter> "lineenter %x %y $id"
853 $canv bind $t <Enter> "lineenter %x %y $id"
847 $canv bind $t <Motion> "linemotion %x %y $id"
854 $canv bind $t <Motion> "linemotion %x %y $id"
848 $canv bind $t <Leave> "lineleave $id"
855 $canv bind $t <Leave> "lineleave $id"
849 $canv bind $t <Button-1> "lineclick %x %y $id 1"
856 $canv bind $t <Button-1> "lineclick %x %y $id 1"
850 }
857 }
851
858
852 proc drawlines {id xtra} {
859 proc drawlines {id xtra} {
853 global mainline mainlinearrow sidelines lthickness colormap canv
860 global mainline mainlinearrow sidelines lthickness colormap canv
854
861
855 $canv delete lines.$id
862 $canv delete lines.$id
856 if {[info exists mainline($id)]} {
863 if {[info exists mainline($id)]} {
857 set t [$canv create line $mainline($id) \
864 set t [$canv create line $mainline($id) \
858 -width [expr {($xtra + 1) * $lthickness}] \
865 -width [expr {($xtra + 1) * $lthickness}] \
859 -fill $colormap($id) -tags lines.$id \
866 -fill $colormap($id) -tags lines.$id \
860 -arrow $mainlinearrow($id)]
867 -arrow $mainlinearrow($id)]
861 $canv lower $t
868 $canv lower $t
862 bindline $t $id
869 bindline $t $id
863 }
870 }
864 if {[info exists sidelines($id)]} {
871 if {[info exists sidelines($id)]} {
865 foreach ls $sidelines($id) {
872 foreach ls $sidelines($id) {
866 set coords [lindex $ls 0]
873 set coords [lindex $ls 0]
867 set thick [lindex $ls 1]
874 set thick [lindex $ls 1]
868 set arrow [lindex $ls 2]
875 set arrow [lindex $ls 2]
869 set t [$canv create line $coords -fill $colormap($id) \
876 set t [$canv create line $coords -fill $colormap($id) \
870 -width [expr {($thick + $xtra) * $lthickness}] \
877 -width [expr {($thick + $xtra) * $lthickness}] \
871 -arrow $arrow -tags lines.$id]
878 -arrow $arrow -tags lines.$id]
872 $canv lower $t
879 $canv lower $t
873 bindline $t $id
880 bindline $t $id
874 }
881 }
875 }
882 }
876 }
883 }
877
884
878 # level here is an index in displist
885 # level here is an index in displist
879 proc drawcommitline {level} {
886 proc drawcommitline {level} {
880 global parents children nparents displist
887 global parents children nparents displist
881 global canv canv2 canv3 mainfont namefont canvy linespc
888 global canv canv2 canv3 mainfont namefont canvy linespc
882 global lineid linehtag linentag linedtag commitinfo
889 global lineid linehtag linentag linedtag commitinfo
883 global colormap numcommits currentparents dupparents
890 global colormap numcommits currentparents dupparents
884 global idtags idline idheads idotherrefs
891 global idtags idline idheads idotherrefs
885 global lineno lthickness mainline mainlinearrow sidelines
892 global lineno lthickness mainline mainlinearrow sidelines
886 global commitlisted rowtextx idpos lastuse displist
893 global commitlisted rowtextx idpos lastuse displist
887 global oldnlines olddlevel olddisplist
894 global oldnlines olddlevel olddisplist
888
895
889 incr numcommits
896 incr numcommits
890 incr lineno
897 incr lineno
891 set id [lindex $displist $level]
898 set id [lindex $displist $level]
892 set lastuse($id) $lineno
899 set lastuse($id) $lineno
893 set lineid($lineno) $id
900 set lineid($lineno) $id
894 set idline($id) $lineno
901 set idline($id) $lineno
895 set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
902 set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
896 if {![info exists commitinfo($id)]} {
903 if {![info exists commitinfo($id)]} {
897 readcommit $id
904 readcommit $id
898 if {![info exists commitinfo($id)]} {
905 if {![info exists commitinfo($id)]} {
899 set commitinfo($id) {"No commit information available"}
906 set commitinfo($id) {"No commit information available"}
900 set nparents($id) 0
907 set nparents($id) 0
901 }
908 }
902 }
909 }
903 assigncolor $id
910 assigncolor $id
904 set currentparents {}
911 set currentparents {}
905 set dupparents {}
912 set dupparents {}
906 if {[info exists commitlisted($id)] && [info exists parents($id)]} {
913 if {[info exists commitlisted($id)] && [info exists parents($id)]} {
907 foreach p $parents($id) {
914 foreach p $parents($id) {
908 if {[lsearch -exact $currentparents $p] < 0} {
915 if {[lsearch -exact $currentparents $p] < 0} {
909 lappend currentparents $p
916 lappend currentparents $p
910 } else {
917 } else {
911 # remember that this parent was listed twice
918 # remember that this parent was listed twice
912 lappend dupparents $p
919 lappend dupparents $p
913 }
920 }
914 }
921 }
915 }
922 }
916 set x [xcoord $level $level $lineno]
923 set x [xcoord $level $level $lineno]
917 set y1 $canvy
924 set y1 $canvy
918 set canvy [expr $canvy + $linespc]
925 set canvy [expr $canvy + $linespc]
919 allcanvs conf -scrollregion \
926 allcanvs conf -scrollregion \
920 [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
927 [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
921 if {[info exists mainline($id)]} {
928 if {[info exists mainline($id)]} {
922 lappend mainline($id) $x $y1
929 lappend mainline($id) $x $y1
923 if {$mainlinearrow($id) ne "none"} {
930 if {$mainlinearrow($id) ne "none"} {
924 set mainline($id) [trimdiagstart $mainline($id)]
931 set mainline($id) [trimdiagstart $mainline($id)]
925 }
932 }
926 }
933 }
927 drawlines $id 0
934 drawlines $id 0
928 set orad [expr {$linespc / 3}]
935 set orad [expr {$linespc / 3}]
929 set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
936 set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
930 [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
937 [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
931 -fill $ofill -outline black -width 1]
938 -fill $ofill -outline black -width 1]
932 $canv raise $t
939 $canv raise $t
933 $canv bind $t <1> {selcanvline {} %x %y}
940 $canv bind $t <1> {selcanvline {} %x %y}
934 set xt [xcoord [llength $displist] $level $lineno]
941 set xt [xcoord [llength $displist] $level $lineno]
935 if {[llength $currentparents] > 2} {
942 if {[llength $currentparents] > 2} {
936 set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}]
943 set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}]
937 }
944 }
938 set rowtextx($lineno) $xt
945 set rowtextx($lineno) $xt
939 set idpos($id) [list $x $xt $y1]
946 set idpos($id) [list $x $xt $y1]
940 if {[info exists idtags($id)] || [info exists idheads($id)]
947 if {[info exists idtags($id)] || [info exists idheads($id)]
941 || [info exists idotherrefs($id)]} {
948 || [info exists idotherrefs($id)]} {
942 set xt [drawtags $id $x $xt $y1]
949 set xt [drawtags $id $x $xt $y1]
943 }
950 }
944 set headline [lindex $commitinfo($id) 0]
951 set headline [lindex $commitinfo($id) 0]
945 set name [lindex $commitinfo($id) 1]
952 set name [lindex $commitinfo($id) 1]
946 set date [lindex $commitinfo($id) 2]
953 set date [lindex $commitinfo($id) 2]
947 set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
954 set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
948 -text $headline -font $mainfont ]
955 -text $headline -font $mainfont ]
949 $canv bind $linehtag($lineno) <<B3>> "rowmenu %X %Y $id"
956 $canv bind $linehtag($lineno) <<B3>> "rowmenu %X %Y $id"
950 set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \
957 set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \
951 -text $name -font $namefont]
958 -text $name -font $namefont]
952 set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \
959 set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \
953 -text $date -font $mainfont]
960 -text $date -font $mainfont]
954
961
955 set olddlevel $level
962 set olddlevel $level
956 set olddisplist $displist
963 set olddisplist $displist
957 set oldnlines [llength $displist]
964 set oldnlines [llength $displist]
958 }
965 }
959
966
960 proc drawtags {id x xt y1} {
967 proc drawtags {id x xt y1} {
961 global idtags idheads idotherrefs
968 global idtags idheads idotherrefs
962 global linespc lthickness
969 global linespc lthickness
963 global canv mainfont idline rowtextx
970 global canv mainfont idline rowtextx
964
971
965 set marks {}
972 set marks {}
966 set ntags 0
973 set ntags 0
967 set nheads 0
974 set nheads 0
968 if {[info exists idtags($id)]} {
975 if {[info exists idtags($id)]} {
969 set marks $idtags($id)
976 set marks $idtags($id)
970 set ntags [llength $marks]
977 set ntags [llength $marks]
971 }
978 }
972 if {[info exists idheads($id)]} {
979 if {[info exists idheads($id)]} {
973 set marks [concat $marks $idheads($id)]
980 set marks [concat $marks $idheads($id)]
974 set nheads [llength $idheads($id)]
981 set nheads [llength $idheads($id)]
975 }
982 }
976 if {[info exists idotherrefs($id)]} {
983 if {[info exists idotherrefs($id)]} {
977 set marks [concat $marks $idotherrefs($id)]
984 set marks [concat $marks $idotherrefs($id)]
978 }
985 }
979 if {$marks eq {}} {
986 if {$marks eq {}} {
980 return $xt
987 return $xt
981 }
988 }
982
989
983 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
990 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
984 set yt [expr $y1 - 0.5 * $linespc]
991 set yt [expr $y1 - 0.5 * $linespc]
985 set yb [expr $yt + $linespc - 1]
992 set yb [expr $yt + $linespc - 1]
986 set xvals {}
993 set xvals {}
987 set wvals {}
994 set wvals {}
988 foreach tag $marks {
995 foreach tag $marks {
989 set wid [font measure $mainfont $tag]
996 set wid [font measure $mainfont $tag]
990 lappend xvals $xt
997 lappend xvals $xt
991 lappend wvals $wid
998 lappend wvals $wid
992 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
999 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
993 }
1000 }
994 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
1001 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
995 -width $lthickness -fill black -tags tag.$id]
1002 -width $lthickness -fill black -tags tag.$id]
996 $canv lower $t
1003 $canv lower $t
997 foreach tag $marks x $xvals wid $wvals {
1004 foreach tag $marks x $xvals wid $wvals {
998 set xl [expr $x + $delta]
1005 set xl [expr $x + $delta]
999 set xr [expr $x + $delta + $wid + $lthickness]
1006 set xr [expr $x + $delta + $wid + $lthickness]
1000 if {[incr ntags -1] >= 0} {
1007 if {[incr ntags -1] >= 0} {
1001 # draw a tag
1008 # draw a tag
1002 set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
1009 set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
1003 $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
1010 $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
1004 -width 1 -outline black -fill yellow -tags tag.$id]
1011 -width 1 -outline black -fill yellow -tags tag.$id]
1005 $canv bind $t <1> [list showtag $tag 1]
1012 $canv bind $t <1> [list showtag $tag 1]
1006 set rowtextx($idline($id)) [expr {$xr + $linespc}]
1013 set rowtextx($idline($id)) [expr {$xr + $linespc}]
1007 } else {
1014 } else {
1008 # draw a head or other ref
1015 # draw a head or other ref
1009 if {[incr nheads -1] >= 0} {
1016 if {[incr nheads -1] >= 0} {
1010 set col green
1017 set col green
1011 } else {
1018 } else {
1012 set col "#ddddff"
1019 set col "#ddddff"
1013 }
1020 }
1014 set xl [expr $xl - $delta/2]
1021 set xl [expr $xl - $delta/2]
1015 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
1022 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
1016 -width 1 -outline black -fill $col -tags tag.$id
1023 -width 1 -outline black -fill $col -tags tag.$id
1017 }
1024 }
1018 set t [$canv create text $xl $y1 -anchor w -text $tag \
1025 set t [$canv create text $xl $y1 -anchor w -text $tag \
1019 -font $mainfont -tags tag.$id]
1026 -font $mainfont -tags tag.$id]
1020 if {$ntags >= 0} {
1027 if {$ntags >= 0} {
1021 $canv bind $t <1> [list showtag $tag 1]
1028 $canv bind $t <1> [list showtag $tag 1]
1022 }
1029 }
1023 }
1030 }
1024 return $xt
1031 return $xt
1025 }
1032 }
1026
1033
1027 proc notecrossings {id lo hi corner} {
1034 proc notecrossings {id lo hi corner} {
1028 global olddisplist crossings cornercrossings
1035 global olddisplist crossings cornercrossings
1029
1036
1030 for {set i $lo} {[incr i] < $hi} {} {
1037 for {set i $lo} {[incr i] < $hi} {} {
1031 set p [lindex $olddisplist $i]
1038 set p [lindex $olddisplist $i]
1032 if {$p == {}} continue
1039 if {$p == {}} continue
1033 if {$i == $corner} {
1040 if {$i == $corner} {
1034 if {![info exists cornercrossings($id)]
1041 if {![info exists cornercrossings($id)]
1035 || [lsearch -exact $cornercrossings($id) $p] < 0} {
1042 || [lsearch -exact $cornercrossings($id) $p] < 0} {
1036 lappend cornercrossings($id) $p
1043 lappend cornercrossings($id) $p
1037 }
1044 }
1038 if {![info exists cornercrossings($p)]
1045 if {![info exists cornercrossings($p)]
1039 || [lsearch -exact $cornercrossings($p) $id] < 0} {
1046 || [lsearch -exact $cornercrossings($p) $id] < 0} {
1040 lappend cornercrossings($p) $id
1047 lappend cornercrossings($p) $id
1041 }
1048 }
1042 } else {
1049 } else {
1043 if {![info exists crossings($id)]
1050 if {![info exists crossings($id)]
1044 || [lsearch -exact $crossings($id) $p] < 0} {
1051 || [lsearch -exact $crossings($id) $p] < 0} {
1045 lappend crossings($id) $p
1052 lappend crossings($id) $p
1046 }
1053 }
1047 if {![info exists crossings($p)]
1054 if {![info exists crossings($p)]
1048 || [lsearch -exact $crossings($p) $id] < 0} {
1055 || [lsearch -exact $crossings($p) $id] < 0} {
1049 lappend crossings($p) $id
1056 lappend crossings($p) $id
1050 }
1057 }
1051 }
1058 }
1052 }
1059 }
1053 }
1060 }
1054
1061
1055 proc xcoord {i level ln} {
1062 proc xcoord {i level ln} {
1056 global canvx0 xspc1 xspc2
1063 global canvx0 xspc1 xspc2
1057
1064
1058 set x [expr {$canvx0 + $i * $xspc1($ln)}]
1065 set x [expr {$canvx0 + $i * $xspc1($ln)}]
1059 if {$i > 0 && $i == $level} {
1066 if {$i > 0 && $i == $level} {
1060 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
1067 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
1061 } elseif {$i > $level} {
1068 } elseif {$i > $level} {
1062 set x [expr {$x + $xspc2 - $xspc1($ln)}]
1069 set x [expr {$x + $xspc2 - $xspc1($ln)}]
1063 }
1070 }
1064 return $x
1071 return $x
1065 }
1072 }
1066
1073
1067 # it seems Tk can't draw arrows on the end of diagonal line segments...
1074 # it seems Tk can't draw arrows on the end of diagonal line segments...
1068 proc trimdiagend {line} {
1075 proc trimdiagend {line} {
1069 while {[llength $line] > 4} {
1076 while {[llength $line] > 4} {
1070 set x1 [lindex $line end-3]
1077 set x1 [lindex $line end-3]
1071 set y1 [lindex $line end-2]
1078 set y1 [lindex $line end-2]
1072 set x2 [lindex $line end-1]
1079 set x2 [lindex $line end-1]
1073 set y2 [lindex $line end]
1080 set y2 [lindex $line end]
1074 if {($x1 == $x2) != ($y1 == $y2)} break
1081 if {($x1 == $x2) != ($y1 == $y2)} break
1075 set line [lreplace $line end-1 end]
1082 set line [lreplace $line end-1 end]
1076 }
1083 }
1077 return $line
1084 return $line
1078 }
1085 }
1079
1086
1080 proc trimdiagstart {line} {
1087 proc trimdiagstart {line} {
1081 while {[llength $line] > 4} {
1088 while {[llength $line] > 4} {
1082 set x1 [lindex $line 0]
1089 set x1 [lindex $line 0]
1083 set y1 [lindex $line 1]
1090 set y1 [lindex $line 1]
1084 set x2 [lindex $line 2]
1091 set x2 [lindex $line 2]
1085 set y2 [lindex $line 3]
1092 set y2 [lindex $line 3]
1086 if {($x1 == $x2) != ($y1 == $y2)} break
1093 if {($x1 == $x2) != ($y1 == $y2)} break
1087 set line [lreplace $line 0 1]
1094 set line [lreplace $line 0 1]
1088 }
1095 }
1089 return $line
1096 return $line
1090 }
1097 }
1091
1098
1092 proc drawslants {id needonscreen nohs} {
1099 proc drawslants {id needonscreen nohs} {
1093 global canv mainline mainlinearrow sidelines
1100 global canv mainline mainlinearrow sidelines
1094 global canvx0 canvy xspc1 xspc2 lthickness
1101 global canvx0 canvy xspc1 xspc2 lthickness
1095 global currentparents dupparents
1102 global currentparents dupparents
1096 global lthickness linespc canvy colormap lineno geometry
1103 global lthickness linespc canvy colormap lineno geometry
1097 global maxgraphpct maxwidth
1104 global maxgraphpct maxwidth
1098 global displist onscreen lastuse
1105 global displist onscreen lastuse
1099 global parents commitlisted
1106 global parents commitlisted
1100 global oldnlines olddlevel olddisplist
1107 global oldnlines olddlevel olddisplist
1101 global nhyperspace numcommits nnewparents
1108 global nhyperspace numcommits nnewparents
1102
1109
1103 if {$lineno < 0} {
1110 if {$lineno < 0} {
1104 lappend displist $id
1111 lappend displist $id
1105 set onscreen($id) 1
1112 set onscreen($id) 1
1106 return 0
1113 return 0
1107 }
1114 }
1108
1115
1109 set y1 [expr {$canvy - $linespc}]
1116 set y1 [expr {$canvy - $linespc}]
1110 set y2 $canvy
1117 set y2 $canvy
1111
1118
1112 # work out what we need to get back on screen
1119 # work out what we need to get back on screen
1113 set reins {}
1120 set reins {}
1114 if {$onscreen($id) < 0} {
1121 if {$onscreen($id) < 0} {
1115 # next to do isn't displayed, better get it on screen...
1122 # next to do isn't displayed, better get it on screen...
1116 lappend reins [list $id 0]
1123 lappend reins [list $id 0]
1117 }
1124 }
1118 # make sure all the previous commits's parents are on the screen
1125 # make sure all the previous commits's parents are on the screen
1119 foreach p $currentparents {
1126 foreach p $currentparents {
1120 if {$onscreen($p) < 0} {
1127 if {$onscreen($p) < 0} {
1121 lappend reins [list $p 0]
1128 lappend reins [list $p 0]
1122 }
1129 }
1123 }
1130 }
1124 # bring back anything requested by caller
1131 # bring back anything requested by caller
1125 if {$needonscreen ne {}} {
1132 if {$needonscreen ne {}} {
1126 lappend reins $needonscreen
1133 lappend reins $needonscreen
1127 }
1134 }
1128
1135
1129 # try the shortcut
1136 # try the shortcut
1130 if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} {
1137 if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} {
1131 set dlevel $olddlevel
1138 set dlevel $olddlevel
1132 set x [xcoord $dlevel $dlevel $lineno]
1139 set x [xcoord $dlevel $dlevel $lineno]
1133 set mainline($id) [list $x $y1]
1140 set mainline($id) [list $x $y1]
1134 set mainlinearrow($id) none
1141 set mainlinearrow($id) none
1135 set lastuse($id) $lineno
1142 set lastuse($id) $lineno
1136 set displist [lreplace $displist $dlevel $dlevel $id]
1143 set displist [lreplace $displist $dlevel $dlevel $id]
1137 set onscreen($id) 1
1144 set onscreen($id) 1
1138 set xspc1([expr {$lineno + 1}]) $xspc1($lineno)
1145 set xspc1([expr {$lineno + 1}]) $xspc1($lineno)
1139 return $dlevel
1146 return $dlevel
1140 }
1147 }
1141
1148
1142 # update displist
1149 # update displist
1143 set displist [lreplace $displist $olddlevel $olddlevel]
1150 set displist [lreplace $displist $olddlevel $olddlevel]
1144 set j $olddlevel
1151 set j $olddlevel
1145 foreach p $currentparents {
1152 foreach p $currentparents {
1146 set lastuse($p) $lineno
1153 set lastuse($p) $lineno
1147 if {$onscreen($p) == 0} {
1154 if {$onscreen($p) == 0} {
1148 set displist [linsert $displist $j $p]
1155 set displist [linsert $displist $j $p]
1149 set onscreen($p) 1
1156 set onscreen($p) 1
1150 incr j
1157 incr j
1151 }
1158 }
1152 }
1159 }
1153 if {$onscreen($id) == 0} {
1160 if {$onscreen($id) == 0} {
1154 lappend displist $id
1161 lappend displist $id
1155 set onscreen($id) 1
1162 set onscreen($id) 1
1156 }
1163 }
1157
1164
1158 # remove the null entry if present
1165 # remove the null entry if present
1159 set nullentry [lsearch -exact $displist {}]
1166 set nullentry [lsearch -exact $displist {}]
1160 if {$nullentry >= 0} {
1167 if {$nullentry >= 0} {
1161 set displist [lreplace $displist $nullentry $nullentry]
1168 set displist [lreplace $displist $nullentry $nullentry]
1162 }
1169 }
1163
1170
1164 # bring back the ones we need now (if we did it earlier
1171 # bring back the ones we need now (if we did it earlier
1165 # it would change displist and invalidate olddlevel)
1172 # it would change displist and invalidate olddlevel)
1166 foreach pi $reins {
1173 foreach pi $reins {
1167 # test again in case of duplicates in reins
1174 # test again in case of duplicates in reins
1168 set p [lindex $pi 0]
1175 set p [lindex $pi 0]
1169 if {$onscreen($p) < 0} {
1176 if {$onscreen($p) < 0} {
1170 set onscreen($p) 1
1177 set onscreen($p) 1
1171 set lastuse($p) $lineno
1178 set lastuse($p) $lineno
1172 set displist [linsert $displist [lindex $pi 1] $p]
1179 set displist [linsert $displist [lindex $pi 1] $p]
1173 incr nhyperspace -1
1180 incr nhyperspace -1
1174 }
1181 }
1175 }
1182 }
1176
1183
1177 set lastuse($id) $lineno
1184 set lastuse($id) $lineno
1178
1185
1179 # see if we need to make any lines jump off into hyperspace
1186 # see if we need to make any lines jump off into hyperspace
1180 set displ [llength $displist]
1187 set displ [llength $displist]
1181 if {$displ > $maxwidth} {
1188 if {$displ > $maxwidth} {
1182 set ages {}
1189 set ages {}
1183 foreach x $displist {
1190 foreach x $displist {
1184 lappend ages [list $lastuse($x) $x]
1191 lappend ages [list $lastuse($x) $x]
1185 }
1192 }
1186 set ages [lsort -integer -index 0 $ages]
1193 set ages [lsort -integer -index 0 $ages]
1187 set k 0
1194 set k 0
1188 while {$displ > $maxwidth} {
1195 while {$displ > $maxwidth} {
1189 set use [lindex $ages $k 0]
1196 set use [lindex $ages $k 0]
1190 set victim [lindex $ages $k 1]
1197 set victim [lindex $ages $k 1]
1191 if {$use >= $lineno - 5} break
1198 if {$use >= $lineno - 5} break
1192 incr k
1199 incr k
1193 if {[lsearch -exact $nohs $victim] >= 0} continue
1200 if {[lsearch -exact $nohs $victim] >= 0} continue
1194 set i [lsearch -exact $displist $victim]
1201 set i [lsearch -exact $displist $victim]
1195 set displist [lreplace $displist $i $i]
1202 set displist [lreplace $displist $i $i]
1196 set onscreen($victim) -1
1203 set onscreen($victim) -1
1197 incr nhyperspace
1204 incr nhyperspace
1198 incr displ -1
1205 incr displ -1
1199 if {$i < $nullentry} {
1206 if {$i < $nullentry} {
1200 incr nullentry -1
1207 incr nullentry -1
1201 }
1208 }
1202 set x [lindex $mainline($victim) end-1]
1209 set x [lindex $mainline($victim) end-1]
1203 lappend mainline($victim) $x $y1
1210 lappend mainline($victim) $x $y1
1204 set line [trimdiagend $mainline($victim)]
1211 set line [trimdiagend $mainline($victim)]
1205 set arrow "last"
1212 set arrow "last"
1206 if {$mainlinearrow($victim) ne "none"} {
1213 if {$mainlinearrow($victim) ne "none"} {
1207 set line [trimdiagstart $line]
1214 set line [trimdiagstart $line]
1208 set arrow "both"
1215 set arrow "both"
1209 }
1216 }
1210 lappend sidelines($victim) [list $line 1 $arrow]
1217 lappend sidelines($victim) [list $line 1 $arrow]
1211 unset mainline($victim)
1218 unset mainline($victim)
1212 }
1219 }
1213 }
1220 }
1214
1221
1215 set dlevel [lsearch -exact $displist $id]
1222 set dlevel [lsearch -exact $displist $id]
1216
1223
1217 # If we are reducing, put in a null entry
1224 # If we are reducing, put in a null entry
1218 if {$displ < $oldnlines} {
1225 if {$displ < $oldnlines} {
1219 # does the next line look like a merge?
1226 # does the next line look like a merge?
1220 # i.e. does it have > 1 new parent?
1227 # i.e. does it have > 1 new parent?
1221 if {$nnewparents($id) > 1} {
1228 if {$nnewparents($id) > 1} {
1222 set i [expr {$dlevel + 1}]
1229 set i [expr {$dlevel + 1}]
1223 } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} {
1230 } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} {
1224 set i $olddlevel
1231 set i $olddlevel
1225 if {$nullentry >= 0 && $nullentry < $i} {
1232 if {$nullentry >= 0 && $nullentry < $i} {
1226 incr i -1
1233 incr i -1
1227 }
1234 }
1228 } elseif {$nullentry >= 0} {
1235 } elseif {$nullentry >= 0} {
1229 set i $nullentry
1236 set i $nullentry
1230 while {$i < $displ
1237 while {$i < $displ
1231 && [lindex $olddisplist $i] == [lindex $displist $i]} {
1238 && [lindex $olddisplist $i] == [lindex $displist $i]} {
1232 incr i
1239 incr i
1233 }
1240 }
1234 } else {
1241 } else {
1235 set i $olddlevel
1242 set i $olddlevel
1236 if {$dlevel >= $i} {
1243 if {$dlevel >= $i} {
1237 incr i
1244 incr i
1238 }
1245 }
1239 }
1246 }
1240 if {$i < $displ} {
1247 if {$i < $displ} {
1241 set displist [linsert $displist $i {}]
1248 set displist [linsert $displist $i {}]
1242 incr displ
1249 incr displ
1243 if {$dlevel >= $i} {
1250 if {$dlevel >= $i} {
1244 incr dlevel
1251 incr dlevel
1245 }
1252 }
1246 }
1253 }
1247 }
1254 }
1248
1255
1249 # decide on the line spacing for the next line
1256 # decide on the line spacing for the next line
1250 set lj [expr {$lineno + 1}]
1257 set lj [expr {$lineno + 1}]
1251 set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}]
1258 set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}]
1252 if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} {
1259 if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} {
1253 set xspc1($lj) $xspc2
1260 set xspc1($lj) $xspc2
1254 } else {
1261 } else {
1255 set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}]
1262 set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}]
1256 if {$xspc1($lj) < $lthickness} {
1263 if {$xspc1($lj) < $lthickness} {
1257 set xspc1($lj) $lthickness
1264 set xspc1($lj) $lthickness
1258 }
1265 }
1259 }
1266 }
1260
1267
1261 foreach idi $reins {
1268 foreach idi $reins {
1262 set id [lindex $idi 0]
1269 set id [lindex $idi 0]
1263 set j [lsearch -exact $displist $id]
1270 set j [lsearch -exact $displist $id]
1264 set xj [xcoord $j $dlevel $lj]
1271 set xj [xcoord $j $dlevel $lj]
1265 set mainline($id) [list $xj $y2]
1272 set mainline($id) [list $xj $y2]
1266 set mainlinearrow($id) first
1273 set mainlinearrow($id) first
1267 }
1274 }
1268
1275
1269 set i -1
1276 set i -1
1270 foreach id $olddisplist {
1277 foreach id $olddisplist {
1271 incr i
1278 incr i
1272 if {$id == {}} continue
1279 if {$id == {}} continue
1273 if {$onscreen($id) <= 0} continue
1280 if {$onscreen($id) <= 0} continue
1274 set xi [xcoord $i $olddlevel $lineno]
1281 set xi [xcoord $i $olddlevel $lineno]
1275 if {$i == $olddlevel} {
1282 if {$i == $olddlevel} {
1276 foreach p $currentparents {
1283 foreach p $currentparents {
1277 set j [lsearch -exact $displist $p]
1284 set j [lsearch -exact $displist $p]
1278 set coords [list $xi $y1]
1285 set coords [list $xi $y1]
1279 set xj [xcoord $j $dlevel $lj]
1286 set xj [xcoord $j $dlevel $lj]
1280 if {$xj < $xi - $linespc} {
1287 if {$xj < $xi - $linespc} {
1281 lappend coords [expr {$xj + $linespc}] $y1
1288 lappend coords [expr {$xj + $linespc}] $y1
1282 notecrossings $p $j $i [expr {$j + 1}]
1289 notecrossings $p $j $i [expr {$j + 1}]
1283 } elseif {$xj > $xi + $linespc} {
1290 } elseif {$xj > $xi + $linespc} {
1284 lappend coords [expr {$xj - $linespc}] $y1
1291 lappend coords [expr {$xj - $linespc}] $y1
1285 notecrossings $p $i $j [expr {$j - 1}]
1292 notecrossings $p $i $j [expr {$j - 1}]
1286 }
1293 }
1287 if {[lsearch -exact $dupparents $p] >= 0} {
1294 if {[lsearch -exact $dupparents $p] >= 0} {
1288 # draw a double-width line to indicate the doubled parent
1295 # draw a double-width line to indicate the doubled parent
1289 lappend coords $xj $y2
1296 lappend coords $xj $y2
1290 lappend sidelines($p) [list $coords 2 none]
1297 lappend sidelines($p) [list $coords 2 none]
1291 if {![info exists mainline($p)]} {
1298 if {![info exists mainline($p)]} {
1292 set mainline($p) [list $xj $y2]
1299 set mainline($p) [list $xj $y2]
1293 set mainlinearrow($p) none
1300 set mainlinearrow($p) none
1294 }
1301 }
1295 } else {
1302 } else {
1296 # normal case, no parent duplicated
1303 # normal case, no parent duplicated
1297 set yb $y2
1304 set yb $y2
1298 set dx [expr {abs($xi - $xj)}]
1305 set dx [expr {abs($xi - $xj)}]
1299 if {0 && $dx < $linespc} {
1306 if {0 && $dx < $linespc} {
1300 set yb [expr {$y1 + $dx}]
1307 set yb [expr {$y1 + $dx}]
1301 }
1308 }
1302 if {![info exists mainline($p)]} {
1309 if {![info exists mainline($p)]} {
1303 if {$xi != $xj} {
1310 if {$xi != $xj} {
1304 lappend coords $xj $yb
1311 lappend coords $xj $yb
1305 }
1312 }
1306 set mainline($p) $coords
1313 set mainline($p) $coords
1307 set mainlinearrow($p) none
1314 set mainlinearrow($p) none
1308 } else {
1315 } else {
1309 lappend coords $xj $yb
1316 lappend coords $xj $yb
1310 if {$yb < $y2} {
1317 if {$yb < $y2} {
1311 lappend coords $xj $y2
1318 lappend coords $xj $y2
1312 }
1319 }
1313 lappend sidelines($p) [list $coords 1 none]
1320 lappend sidelines($p) [list $coords 1 none]
1314 }
1321 }
1315 }
1322 }
1316 }
1323 }
1317 } else {
1324 } else {
1318 set j $i
1325 set j $i
1319 if {[lindex $displist $i] != $id} {
1326 if {[lindex $displist $i] != $id} {
1320 set j [lsearch -exact $displist $id]
1327 set j [lsearch -exact $displist $id]
1321 }
1328 }
1322 if {$j != $i || $xspc1($lineno) != $xspc1($lj)
1329 if {$j != $i || $xspc1($lineno) != $xspc1($lj)
1323 || ($olddlevel < $i && $i < $dlevel)
1330 || ($olddlevel < $i && $i < $dlevel)
1324 || ($dlevel < $i && $i < $olddlevel)} {
1331 || ($dlevel < $i && $i < $olddlevel)} {
1325 set xj [xcoord $j $dlevel $lj]
1332 set xj [xcoord $j $dlevel $lj]
1326 lappend mainline($id) $xi $y1 $xj $y2
1333 lappend mainline($id) $xi $y1 $xj $y2
1327 }
1334 }
1328 }
1335 }
1329 }
1336 }
1330 return $dlevel
1337 return $dlevel
1331 }
1338 }
1332
1339
1333 # search for x in a list of lists
1340 # search for x in a list of lists
1334 proc llsearch {llist x} {
1341 proc llsearch {llist x} {
1335 set i 0
1342 set i 0
1336 foreach l $llist {
1343 foreach l $llist {
1337 if {$l == $x || [lsearch -exact $l $x] >= 0} {
1344 if {$l == $x || [lsearch -exact $l $x] >= 0} {
1338 return $i
1345 return $i
1339 }
1346 }
1340 incr i
1347 incr i
1341 }
1348 }
1342 return -1
1349 return -1
1343 }
1350 }
1344
1351
1345 proc drawmore {reading} {
1352 proc drawmore {reading} {
1346 global displayorder numcommits ncmupdate nextupdate
1353 global displayorder numcommits ncmupdate nextupdate
1347 global stopped nhyperspace parents commitlisted
1354 global stopped nhyperspace parents commitlisted
1348 global maxwidth onscreen displist currentparents olddlevel
1355 global maxwidth onscreen displist currentparents olddlevel
1349
1356
1350 set n [llength $displayorder]
1357 set n [llength $displayorder]
1351 while {$numcommits < $n} {
1358 while {$numcommits < $n} {
1352 set id [lindex $displayorder $numcommits]
1359 set id [lindex $displayorder $numcommits]
1353 set ctxend [expr {$numcommits + 10}]
1360 set ctxend [expr {$numcommits + 10}]
1354 if {!$reading && $ctxend > $n} {
1361 if {!$reading && $ctxend > $n} {
1355 set ctxend $n
1362 set ctxend $n
1356 }
1363 }
1357 set dlist {}
1364 set dlist {}
1358 if {$numcommits > 0} {
1365 if {$numcommits > 0} {
1359 set dlist [lreplace $displist $olddlevel $olddlevel]
1366 set dlist [lreplace $displist $olddlevel $olddlevel]
1360 set i $olddlevel
1367 set i $olddlevel
1361 foreach p $currentparents {
1368 foreach p $currentparents {
1362 if {$onscreen($p) == 0} {
1369 if {$onscreen($p) == 0} {
1363 set dlist [linsert $dlist $i $p]
1370 set dlist [linsert $dlist $i $p]
1364 incr i
1371 incr i
1365 }
1372 }
1366 }
1373 }
1367 }
1374 }
1368 set nohs {}
1375 set nohs {}
1369 set reins {}
1376 set reins {}
1370 set isfat [expr {[llength $dlist] > $maxwidth}]
1377 set isfat [expr {[llength $dlist] > $maxwidth}]
1371 if {$nhyperspace > 0 || $isfat} {
1378 if {$nhyperspace > 0 || $isfat} {
1372 if {$ctxend > $n} break
1379 if {$ctxend > $n} break
1373 # work out what to bring back and
1380 # work out what to bring back and
1374 # what we want to don't want to send into hyperspace
1381 # what we want to don't want to send into hyperspace
1375 set room 1
1382 set room 1
1376 for {set k $numcommits} {$k < $ctxend} {incr k} {
1383 for {set k $numcommits} {$k < $ctxend} {incr k} {
1377 set x [lindex $displayorder $k]
1384 set x [lindex $displayorder $k]
1378 set i [llsearch $dlist $x]
1385 set i [llsearch $dlist $x]
1379 if {$i < 0} {
1386 if {$i < 0} {
1380 set i [llength $dlist]
1387 set i [llength $dlist]
1381 lappend dlist $x
1388 lappend dlist $x
1382 }
1389 }
1383 if {[lsearch -exact $nohs $x] < 0} {
1390 if {[lsearch -exact $nohs $x] < 0} {
1384 lappend nohs $x
1391 lappend nohs $x
1385 }
1392 }
1386 if {$reins eq {} && $onscreen($x) < 0 && $room} {
1393 if {$reins eq {} && $onscreen($x) < 0 && $room} {
1387 set reins [list $x $i]
1394 set reins [list $x $i]
1388 }
1395 }
1389 set newp {}
1396 set newp {}
1390 if {[info exists commitlisted($x)]} {
1397 if {[info exists commitlisted($x)]} {
1391 set right 0
1398 set right 0
1392 foreach p $parents($x) {
1399 foreach p $parents($x) {
1393 if {[llsearch $dlist $p] < 0} {
1400 if {[llsearch $dlist $p] < 0} {
1394 lappend newp $p
1401 lappend newp $p
1395 if {[lsearch -exact $nohs $p] < 0} {
1402 if {[lsearch -exact $nohs $p] < 0} {
1396 lappend nohs $p
1403 lappend nohs $p
1397 }
1404 }
1398 if {$reins eq {} && $onscreen($p) < 0 && $room} {
1405 if {$reins eq {} && $onscreen($p) < 0 && $room} {
1399 set reins [list $p [expr {$i + $right}]]
1406 set reins [list $p [expr {$i + $right}]]
1400 }
1407 }
1401 }
1408 }
1402 set right 1
1409 set right 1
1403 }
1410 }
1404 }
1411 }
1405 set l [lindex $dlist $i]
1412 set l [lindex $dlist $i]
1406 if {[llength $l] == 1} {
1413 if {[llength $l] == 1} {
1407 set l $newp
1414 set l $newp
1408 } else {
1415 } else {
1409 set j [lsearch -exact $l $x]
1416 set j [lsearch -exact $l $x]
1410 set l [concat [lreplace $l $j $j] $newp]
1417 set l [concat [lreplace $l $j $j] $newp]
1411 }
1418 }
1412 set dlist [lreplace $dlist $i $i $l]
1419 set dlist [lreplace $dlist $i $i $l]
1413 if {$room && $isfat && [llength $newp] <= 1} {
1420 if {$room && $isfat && [llength $newp] <= 1} {
1414 set room 0
1421 set room 0
1415 }
1422 }
1416 }
1423 }
1417 }
1424 }
1418
1425
1419 set dlevel [drawslants $id $reins $nohs]
1426 set dlevel [drawslants $id $reins $nohs]
1420 drawcommitline $dlevel
1427 drawcommitline $dlevel
1421 if {[clock clicks -milliseconds] >= $nextupdate
1428 if {[clock clicks -milliseconds] >= $nextupdate
1422 && $numcommits >= $ncmupdate} {
1429 && $numcommits >= $ncmupdate} {
1423 doupdate $reading
1430 doupdate $reading
1424 if {$stopped} break
1431 if {$stopped} break
1425 }
1432 }
1426 }
1433 }
1427 }
1434 }
1428
1435
1429 # level here is an index in todo
1436 # level here is an index in todo
1430 proc updatetodo {level noshortcut} {
1437 proc updatetodo {level noshortcut} {
1431 global ncleft todo nnewparents
1438 global ncleft todo nnewparents
1432 global commitlisted parents onscreen
1439 global commitlisted parents onscreen
1433
1440
1434 set id [lindex $todo $level]
1441 set id [lindex $todo $level]
1435 set olds {}
1442 set olds {}
1436 if {[info exists commitlisted($id)]} {
1443 if {[info exists commitlisted($id)]} {
1437 foreach p $parents($id) {
1444 foreach p $parents($id) {
1438 if {[lsearch -exact $olds $p] < 0} {
1445 if {[lsearch -exact $olds $p] < 0} {
1439 lappend olds $p
1446 lappend olds $p
1440 }
1447 }
1441 }
1448 }
1442 }
1449 }
1443 if {!$noshortcut && [llength $olds] == 1} {
1450 if {!$noshortcut && [llength $olds] == 1} {
1444 set p [lindex $olds 0]
1451 set p [lindex $olds 0]
1445 if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} {
1452 if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} {
1446 set ncleft($p) 0
1453 set ncleft($p) 0
1447 set todo [lreplace $todo $level $level $p]
1454 set todo [lreplace $todo $level $level $p]
1448 set onscreen($p) 0
1455 set onscreen($p) 0
1449 set nnewparents($id) 1
1456 set nnewparents($id) 1
1450 return 0
1457 return 0
1451 }
1458 }
1452 }
1459 }
1453
1460
1454 set todo [lreplace $todo $level $level]
1461 set todo [lreplace $todo $level $level]
1455 set i $level
1462 set i $level
1456 set n 0
1463 set n 0
1457 foreach p $olds {
1464 foreach p $olds {
1458 incr ncleft($p) -1
1465 incr ncleft($p) -1
1459 set k [lsearch -exact $todo $p]
1466 set k [lsearch -exact $todo $p]
1460 if {$k < 0} {
1467 if {$k < 0} {
1461 set todo [linsert $todo $i $p]
1468 set todo [linsert $todo $i $p]
1462 set onscreen($p) 0
1469 set onscreen($p) 0
1463 incr i
1470 incr i
1464 incr n
1471 incr n
1465 }
1472 }
1466 }
1473 }
1467 set nnewparents($id) $n
1474 set nnewparents($id) $n
1468
1475
1469 return 1
1476 return 1
1470 }
1477 }
1471
1478
1472 proc decidenext {{noread 0}} {
1479 proc decidenext {{noread 0}} {
1473 global ncleft todo
1480 global ncleft todo
1474 global datemode cdate
1481 global datemode cdate
1475 global commitinfo
1482 global commitinfo
1476
1483
1477 # choose which one to do next time around
1484 # choose which one to do next time around
1478 set todol [llength $todo]
1485 set todol [llength $todo]
1479 set level -1
1486 set level -1
1480 set latest {}
1487 set latest {}
1481 for {set k $todol} {[incr k -1] >= 0} {} {
1488 for {set k $todol} {[incr k -1] >= 0} {} {
1482 set p [lindex $todo $k]
1489 set p [lindex $todo $k]
1483 if {$ncleft($p) == 0} {
1490 if {$ncleft($p) == 0} {
1484 if {$datemode} {
1491 if {$datemode} {
1485 if {![info exists commitinfo($p)]} {
1492 if {![info exists commitinfo($p)]} {
1486 if {$noread} {
1493 if {$noread} {
1487 return {}
1494 return {}
1488 }
1495 }
1489 readcommit $p
1496 readcommit $p
1490 }
1497 }
1491 if {$latest == {} || $cdate($p) > $latest} {
1498 if {$latest == {} || $cdate($p) > $latest} {
1492 set level $k
1499 set level $k
1493 set latest $cdate($p)
1500 set latest $cdate($p)
1494 }
1501 }
1495 } else {
1502 } else {
1496 set level $k
1503 set level $k
1497 break
1504 break
1498 }
1505 }
1499 }
1506 }
1500 }
1507 }
1501 if {$level < 0} {
1508 if {$level < 0} {
1502 if {$todo != {}} {
1509 if {$todo != {}} {
1503 puts "ERROR: none of the pending commits can be done yet:"
1510 puts "ERROR: none of the pending commits can be done yet:"
1504 foreach p $todo {
1511 foreach p $todo {
1505 puts " $p ($ncleft($p))"
1512 puts " $p ($ncleft($p))"
1506 }
1513 }
1507 }
1514 }
1508 return -1
1515 return -1
1509 }
1516 }
1510
1517
1511 return $level
1518 return $level
1512 }
1519 }
1513
1520
1514 proc drawcommit {id} {
1521 proc drawcommit {id} {
1515 global phase todo nchildren datemode nextupdate
1522 global phase todo nchildren datemode nextupdate
1516 global numcommits ncmupdate displayorder todo onscreen
1523 global numcommits ncmupdate displayorder todo onscreen
1517
1524
1518 if {$phase != "incrdraw"} {
1525 if {$phase != "incrdraw"} {
1519 set phase incrdraw
1526 set phase incrdraw
1520 set displayorder {}
1527 set displayorder {}
1521 set todo {}
1528 set todo {}
1522 initgraph
1529 initgraph
1523 }
1530 }
1524 if {$nchildren($id) == 0} {
1531 if {$nchildren($id) == 0} {
1525 lappend todo $id
1532 lappend todo $id
1526 set onscreen($id) 0
1533 set onscreen($id) 0
1527 }
1534 }
1528 set level [decidenext 1]
1535 set level [decidenext 1]
1529 if {$level == {} || $id != [lindex $todo $level]} {
1536 if {$level == {} || $id != [lindex $todo $level]} {
1530 return
1537 return
1531 }
1538 }
1532 while 1 {
1539 while 1 {
1533 lappend displayorder [lindex $todo $level]
1540 lappend displayorder [lindex $todo $level]
1534 if {[updatetodo $level $datemode]} {
1541 if {[updatetodo $level $datemode]} {
1535 set level [decidenext 1]
1542 set level [decidenext 1]
1536 if {$level == {}} break
1543 if {$level == {}} break
1537 }
1544 }
1538 set id [lindex $todo $level]
1545 set id [lindex $todo $level]
1539 if {![info exists commitlisted($id)]} {
1546 if {![info exists commitlisted($id)]} {
1540 break
1547 break
1541 }
1548 }
1542 }
1549 }
1543 drawmore 1
1550 drawmore 1
1544 }
1551 }
1545
1552
1546 proc finishcommits {} {
1553 proc finishcommits {} {
1547 global phase
1554 global phase
1548 global canv mainfont ctext maincursor textcursor
1555 global canv mainfont ctext maincursor textcursor
1549
1556
1550 if {$phase != "incrdraw"} {
1557 if {$phase != "incrdraw"} {
1551 $canv delete all
1558 $canv delete all
1552 $canv create text 3 3 -anchor nw -text "No commits selected" \
1559 $canv create text 3 3 -anchor nw -text "No commits selected" \
1553 -font $mainfont -tags textitems
1560 -font $mainfont -tags textitems
1554 set phase {}
1561 set phase {}
1555 } else {
1562 } else {
1556 drawrest
1563 drawrest
1557 }
1564 }
1558 . config -cursor $maincursor
1565 . config -cursor $maincursor
1559 settextcursor $textcursor
1566 settextcursor $textcursor
1560 }
1567 }
1561
1568
1562 # Don't change the text pane cursor if it is currently the hand cursor,
1569 # Don't change the text pane cursor if it is currently the hand cursor,
1563 # showing that we are over a sha1 ID link.
1570 # showing that we are over a sha1 ID link.
1564 proc settextcursor {c} {
1571 proc settextcursor {c} {
1565 global ctext curtextcursor
1572 global ctext curtextcursor
1566
1573
1567 if {[$ctext cget -cursor] == $curtextcursor} {
1574 if {[$ctext cget -cursor] == $curtextcursor} {
1568 $ctext config -cursor $c
1575 $ctext config -cursor $c
1569 }
1576 }
1570 set curtextcursor $c
1577 set curtextcursor $c
1571 }
1578 }
1572
1579
1573 proc drawgraph {} {
1580 proc drawgraph {} {
1574 global nextupdate startmsecs ncmupdate
1581 global nextupdate startmsecs ncmupdate
1575 global displayorder onscreen
1582 global displayorder onscreen
1576
1583
1577 if {$displayorder == {}} return
1584 if {$displayorder == {}} return
1578 set startmsecs [clock clicks -milliseconds]
1585 set startmsecs [clock clicks -milliseconds]
1579 set nextupdate [expr $startmsecs + 100]
1586 set nextupdate [expr $startmsecs + 100]
1580 set ncmupdate 1
1587 set ncmupdate 1
1581 initgraph
1588 initgraph
1582 foreach id $displayorder {
1589 foreach id $displayorder {
1583 set onscreen($id) 0
1590 set onscreen($id) 0
1584 }
1591 }
1585 drawmore 0
1592 drawmore 0
1586 }
1593 }
1587
1594
1588 proc drawrest {} {
1595 proc drawrest {} {
1589 global phase stopped redisplaying selectedline
1596 global phase stopped redisplaying selectedline
1590 global datemode todo displayorder
1597 global datemode todo displayorder
1591 global numcommits ncmupdate
1598 global numcommits ncmupdate
1592 global nextupdate startmsecs
1599 global nextupdate startmsecs
1593
1600
1594 set level [decidenext]
1601 set level [decidenext]
1595 if {$level >= 0} {
1602 if {$level >= 0} {
1596 set phase drawgraph
1603 set phase drawgraph
1597 while 1 {
1604 while 1 {
1598 lappend displayorder [lindex $todo $level]
1605 lappend displayorder [lindex $todo $level]
1599 set hard [updatetodo $level $datemode]
1606 set hard [updatetodo $level $datemode]
1600 if {$hard} {
1607 if {$hard} {
1601 set level [decidenext]
1608 set level [decidenext]
1602 if {$level < 0} break
1609 if {$level < 0} break
1603 }
1610 }
1604 }
1611 }
1605 drawmore 0
1612 drawmore 0
1606 }
1613 }
1607 set phase {}
1614 set phase {}
1608 set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
1615 set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
1609 #puts "overall $drawmsecs ms for $numcommits commits"
1616 #puts "overall $drawmsecs ms for $numcommits commits"
1610 if {$redisplaying} {
1617 if {$redisplaying} {
1611 if {$stopped == 0 && [info exists selectedline]} {
1618 if {$stopped == 0 && [info exists selectedline]} {
1612 selectline $selectedline 0
1619 selectline $selectedline 0
1613 }
1620 }
1614 if {$stopped == 1} {
1621 if {$stopped == 1} {
1615 set stopped 0
1622 set stopped 0
1616 after idle drawgraph
1623 after idle drawgraph
1617 } else {
1624 } else {
1618 set redisplaying 0
1625 set redisplaying 0
1619 }
1626 }
1620 }
1627 }
1621 }
1628 }
1622
1629
1623 proc findmatches {f} {
1630 proc findmatches {f} {
1624 global findtype foundstring foundstrlen
1631 global findtype foundstring foundstrlen
1625 if {$findtype == "Regexp"} {
1632 if {$findtype == "Regexp"} {
1626 set matches [regexp -indices -all -inline $foundstring $f]
1633 set matches [regexp -indices -all -inline $foundstring $f]
1627 } else {
1634 } else {
1628 if {$findtype == "IgnCase"} {
1635 if {$findtype == "IgnCase"} {
1629 set str [string tolower $f]
1636 set str [string tolower $f]
1630 } else {
1637 } else {
1631 set str $f
1638 set str $f
1632 }
1639 }
1633 set matches {}
1640 set matches {}
1634 set i 0
1641 set i 0
1635 while {[set j [string first $foundstring $str $i]] >= 0} {
1642 while {[set j [string first $foundstring $str $i]] >= 0} {
1636 lappend matches [list $j [expr $j+$foundstrlen-1]]
1643 lappend matches [list $j [expr $j+$foundstrlen-1]]
1637 set i [expr $j + $foundstrlen]
1644 set i [expr $j + $foundstrlen]
1638 }
1645 }
1639 }
1646 }
1640 return $matches
1647 return $matches
1641 }
1648 }
1642
1649
1643 proc dofind {} {
1650 proc dofind {} {
1644 global findtype findloc findstring markedmatches commitinfo
1651 global findtype findloc findstring markedmatches commitinfo
1645 global numcommits lineid linehtag linentag linedtag
1652 global numcommits lineid linehtag linentag linedtag
1646 global mainfont namefont canv canv2 canv3 selectedline
1653 global mainfont namefont canv canv2 canv3 selectedline
1647 global matchinglines foundstring foundstrlen
1654 global matchinglines foundstring foundstrlen
1648
1655
1649 stopfindproc
1656 stopfindproc
1650 unmarkmatches
1657 unmarkmatches
1651 focus .
1658 focus .
1652 set matchinglines {}
1659 set matchinglines {}
1653 if {$findloc == "Pickaxe"} {
1660 if {$findloc == "Pickaxe"} {
1654 findpatches
1661 findpatches
1655 return
1662 return
1656 }
1663 }
1657 if {$findtype == "IgnCase"} {
1664 if {$findtype == "IgnCase"} {
1658 set foundstring [string tolower $findstring]
1665 set foundstring [string tolower $findstring]
1659 } else {
1666 } else {
1660 set foundstring $findstring
1667 set foundstring $findstring
1661 }
1668 }
1662 set foundstrlen [string length $findstring]
1669 set foundstrlen [string length $findstring]
1663 if {$foundstrlen == 0} return
1670 if {$foundstrlen == 0} return
1664 if {$findloc == "Files"} {
1671 if {$findloc == "Files"} {
1665 findfiles
1672 findfiles
1666 return
1673 return
1667 }
1674 }
1668 if {![info exists selectedline]} {
1675 if {![info exists selectedline]} {
1669 set oldsel -1
1676 set oldsel -1
1670 } else {
1677 } else {
1671 set oldsel $selectedline
1678 set oldsel $selectedline
1672 }
1679 }
1673 set didsel 0
1680 set didsel 0
1674 set fldtypes {Headline Author Date Committer CDate Comment}
1681 set fldtypes {Headline Author Date Committer CDate Comment}
1675 for {set l 0} {$l < $numcommits} {incr l} {
1682 for {set l 0} {$l < $numcommits} {incr l} {
1676 set id $lineid($l)
1683 set id $lineid($l)
1677 set info $commitinfo($id)
1684 set info $commitinfo($id)
1678 set doesmatch 0
1685 set doesmatch 0
1679 foreach f $info ty $fldtypes {
1686 foreach f $info ty $fldtypes {
1680 if {$findloc != "All fields" && $findloc != $ty} {
1687 if {$findloc != "All fields" && $findloc != $ty} {
1681 continue
1688 continue
1682 }
1689 }
1683 set matches [findmatches $f]
1690 set matches [findmatches $f]
1684 if {$matches == {}} continue
1691 if {$matches == {}} continue
1685 set doesmatch 1
1692 set doesmatch 1
1686 if {$ty == "Headline"} {
1693 if {$ty == "Headline"} {
1687 markmatches $canv $l $f $linehtag($l) $matches $mainfont
1694 markmatches $canv $l $f $linehtag($l) $matches $mainfont
1688 } elseif {$ty == "Author"} {
1695 } elseif {$ty == "Author"} {
1689 markmatches $canv2 $l $f $linentag($l) $matches $namefont
1696 markmatches $canv2 $l $f $linentag($l) $matches $namefont
1690 } elseif {$ty == "Date"} {
1697 } elseif {$ty == "Date"} {
1691 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
1698 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
1692 }
1699 }
1693 }
1700 }
1694 if {$doesmatch} {
1701 if {$doesmatch} {
1695 lappend matchinglines $l
1702 lappend matchinglines $l
1696 if {!$didsel && $l > $oldsel} {
1703 if {!$didsel && $l > $oldsel} {
1697 findselectline $l
1704 findselectline $l
1698 set didsel 1
1705 set didsel 1
1699 }
1706 }
1700 }
1707 }
1701 }
1708 }
1702 if {$matchinglines == {}} {
1709 if {$matchinglines == {}} {
1703 bell
1710 bell
1704 } elseif {!$didsel} {
1711 } elseif {!$didsel} {
1705 findselectline [lindex $matchinglines 0]
1712 findselectline [lindex $matchinglines 0]
1706 }
1713 }
1707 }
1714 }
1708
1715
1709 proc findselectline {l} {
1716 proc findselectline {l} {
1710 global findloc commentend ctext
1717 global findloc commentend ctext
1711 selectline $l 1
1718 selectline $l 1
1712 if {$findloc == "All fields" || $findloc == "Comments"} {
1719 if {$findloc == "All fields" || $findloc == "Comments"} {
1713 # highlight the matches in the comments
1720 # highlight the matches in the comments
1714 set f [$ctext get 1.0 $commentend]
1721 set f [$ctext get 1.0 $commentend]
1715 set matches [findmatches $f]
1722 set matches [findmatches $f]
1716 foreach match $matches {
1723 foreach match $matches {
1717 set start [lindex $match 0]
1724 set start [lindex $match 0]
1718 set end [expr [lindex $match 1] + 1]
1725 set end [expr [lindex $match 1] + 1]
1719 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
1726 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
1720 }
1727 }
1721 }
1728 }
1722 }
1729 }
1723
1730
1724 proc findnext {restart} {
1731 proc findnext {restart} {
1725 global matchinglines selectedline
1732 global matchinglines selectedline
1726 if {![info exists matchinglines]} {
1733 if {![info exists matchinglines]} {
1727 if {$restart} {
1734 if {$restart} {
1728 dofind
1735 dofind
1729 }
1736 }
1730 return
1737 return
1731 }
1738 }
1732 if {![info exists selectedline]} return
1739 if {![info exists selectedline]} return
1733 foreach l $matchinglines {
1740 foreach l $matchinglines {
1734 if {$l > $selectedline} {
1741 if {$l > $selectedline} {
1735 findselectline $l
1742 findselectline $l
1736 return
1743 return
1737 }
1744 }
1738 }
1745 }
1739 bell
1746 bell
1740 }
1747 }
1741
1748
1742 proc findprev {} {
1749 proc findprev {} {
1743 global matchinglines selectedline
1750 global matchinglines selectedline
1744 if {![info exists matchinglines]} {
1751 if {![info exists matchinglines]} {
1745 dofind
1752 dofind
1746 return
1753 return
1747 }
1754 }
1748 if {![info exists selectedline]} return
1755 if {![info exists selectedline]} return
1749 set prev {}
1756 set prev {}
1750 foreach l $matchinglines {
1757 foreach l $matchinglines {
1751 if {$l >= $selectedline} break
1758 if {$l >= $selectedline} break
1752 set prev $l
1759 set prev $l
1753 }
1760 }
1754 if {$prev != {}} {
1761 if {$prev != {}} {
1755 findselectline $prev
1762 findselectline $prev
1756 } else {
1763 } else {
1757 bell
1764 bell
1758 }
1765 }
1759 }
1766 }
1760
1767
1761 proc findlocchange {name ix op} {
1768 proc findlocchange {name ix op} {
1762 global findloc findtype findtypemenu
1769 global findloc findtype findtypemenu
1763 if {$findloc == "Pickaxe"} {
1770 if {$findloc == "Pickaxe"} {
1764 set findtype Exact
1771 set findtype Exact
1765 set state disabled
1772 set state disabled
1766 } else {
1773 } else {
1767 set state normal
1774 set state normal
1768 }
1775 }
1769 $findtypemenu entryconf 1 -state $state
1776 $findtypemenu entryconf 1 -state $state
1770 $findtypemenu entryconf 2 -state $state
1777 $findtypemenu entryconf 2 -state $state
1771 }
1778 }
1772
1779
1773 proc stopfindproc {{done 0}} {
1780 proc stopfindproc {{done 0}} {
1774 global findprocpid findprocfile findids
1781 global findprocpid findprocfile findids
1775 global ctext findoldcursor phase maincursor textcursor
1782 global ctext findoldcursor phase maincursor textcursor
1776 global findinprogress
1783 global findinprogress
1777
1784
1778 catch {unset findids}
1785 catch {unset findids}
1779 if {[info exists findprocpid]} {
1786 if {[info exists findprocpid]} {
1780 if {!$done} {
1787 if {!$done} {
1781 catch {exec kill $findprocpid}
1788 catch {exec kill $findprocpid}
1782 }
1789 }
1783 catch {close $findprocfile}
1790 catch {close $findprocfile}
1784 unset findprocpid
1791 unset findprocpid
1785 }
1792 }
1786 if {[info exists findinprogress]} {
1793 if {[info exists findinprogress]} {
1787 unset findinprogress
1794 unset findinprogress
1788 if {$phase != "incrdraw"} {
1795 if {$phase != "incrdraw"} {
1789 . config -cursor $maincursor
1796 . config -cursor $maincursor
1790 settextcursor $textcursor
1797 settextcursor $textcursor
1791 }
1798 }
1792 }
1799 }
1793 }
1800 }
1794
1801
1795 proc findpatches {} {
1802 proc findpatches {} {
1796 global findstring selectedline numcommits
1803 global findstring selectedline numcommits
1797 global findprocpid findprocfile
1804 global findprocpid findprocfile
1798 global finddidsel ctext lineid findinprogress
1805 global finddidsel ctext lineid findinprogress
1799 global findinsertpos
1806 global findinsertpos
1800 global env
1807 global env
1801
1808
1802 if {$numcommits == 0} return
1809 if {$numcommits == 0} return
1803
1810
1804 # make a list of all the ids to search, starting at the one
1811 # make a list of all the ids to search, starting at the one
1805 # after the selected line (if any)
1812 # after the selected line (if any)
1806 if {[info exists selectedline]} {
1813 if {[info exists selectedline]} {
1807 set l $selectedline
1814 set l $selectedline
1808 } else {
1815 } else {
1809 set l -1
1816 set l -1
1810 }
1817 }
1811 set inputids {}
1818 set inputids {}
1812 for {set i 0} {$i < $numcommits} {incr i} {
1819 for {set i 0} {$i < $numcommits} {incr i} {
1813 if {[incr l] >= $numcommits} {
1820 if {[incr l] >= $numcommits} {
1814 set l 0
1821 set l 0
1815 }
1822 }
1816 append inputids $lineid($l) "\n"
1823 append inputids $lineid($l) "\n"
1817 }
1824 }
1818
1825
1819 if {[catch {
1826 if {[catch {
1820 set f [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree --stdin -s -r -S$findstring << $inputids] r]
1827 set f [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree --stdin -s -r -S$findstring << $inputids] r]
1821 } err]} {
1828 } err]} {
1822 error_popup "Error starting search process: $err"
1829 error_popup "Error starting search process: $err"
1823 return
1830 return
1824 }
1831 }
1825
1832
1826 set findinsertpos end
1833 set findinsertpos end
1827 set findprocfile $f
1834 set findprocfile $f
1828 set findprocpid [pid $f]
1835 set findprocpid [pid $f]
1829 fconfigure $f -blocking 0
1836 fconfigure $f -blocking 0
1830 fileevent $f readable readfindproc
1837 fileevent $f readable readfindproc
1831 set finddidsel 0
1838 set finddidsel 0
1832 . config -cursor watch
1839 . config -cursor watch
1833 settextcursor watch
1840 settextcursor watch
1834 set findinprogress 1
1841 set findinprogress 1
1835 }
1842 }
1836
1843
1837 proc readfindproc {} {
1844 proc readfindproc {} {
1838 global findprocfile finddidsel
1845 global findprocfile finddidsel
1839 global idline matchinglines findinsertpos
1846 global idline matchinglines findinsertpos
1840
1847
1841 set n [gets $findprocfile line]
1848 set n [gets $findprocfile line]
1842 if {$n < 0} {
1849 if {$n < 0} {
1843 if {[eof $findprocfile]} {
1850 if {[eof $findprocfile]} {
1844 stopfindproc 1
1851 stopfindproc 1
1845 if {!$finddidsel} {
1852 if {!$finddidsel} {
1846 bell
1853 bell
1847 }
1854 }
1848 }
1855 }
1849 return
1856 return
1850 }
1857 }
1851 if {![regexp {^[0-9a-f]{12}} $line id]} {
1858 if {![regexp {^[0-9a-f]{12}} $line id]} {
1852 error_popup "Can't parse git-diff-tree output: $line"
1859 error_popup "Can't parse git-diff-tree output: $line"
1853 stopfindproc
1860 stopfindproc
1854 return
1861 return
1855 }
1862 }
1856 if {![info exists idline($id)]} {
1863 if {![info exists idline($id)]} {
1857 puts stderr "spurious id: $id"
1864 puts stderr "spurious id: $id"
1858 return
1865 return
1859 }
1866 }
1860 set l $idline($id)
1867 set l $idline($id)
1861 insertmatch $l $id
1868 insertmatch $l $id
1862 }
1869 }
1863
1870
1864 proc insertmatch {l id} {
1871 proc insertmatch {l id} {
1865 global matchinglines findinsertpos finddidsel
1872 global matchinglines findinsertpos finddidsel
1866
1873
1867 if {$findinsertpos == "end"} {
1874 if {$findinsertpos == "end"} {
1868 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
1875 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
1869 set matchinglines [linsert $matchinglines 0 $l]
1876 set matchinglines [linsert $matchinglines 0 $l]
1870 set findinsertpos 1
1877 set findinsertpos 1
1871 } else {
1878 } else {
1872 lappend matchinglines $l
1879 lappend matchinglines $l
1873 }
1880 }
1874 } else {
1881 } else {
1875 set matchinglines [linsert $matchinglines $findinsertpos $l]
1882 set matchinglines [linsert $matchinglines $findinsertpos $l]
1876 incr findinsertpos
1883 incr findinsertpos
1877 }
1884 }
1878 markheadline $l $id
1885 markheadline $l $id
1879 if {!$finddidsel} {
1886 if {!$finddidsel} {
1880 findselectline $l
1887 findselectline $l
1881 set finddidsel 1
1888 set finddidsel 1
1882 }
1889 }
1883 }
1890 }
1884
1891
1885 proc findfiles {} {
1892 proc findfiles {} {
1886 global selectedline numcommits lineid ctext
1893 global selectedline numcommits lineid ctext
1887 global ffileline finddidsel parents nparents
1894 global ffileline finddidsel parents nparents
1888 global findinprogress findstartline findinsertpos
1895 global findinprogress findstartline findinsertpos
1889 global treediffs fdiffids fdiffsneeded fdiffpos
1896 global treediffs fdiffids fdiffsneeded fdiffpos
1890 global findmergefiles
1897 global findmergefiles
1891 global env
1898 global env
1892
1899
1893 if {$numcommits == 0} return
1900 if {$numcommits == 0} return
1894
1901
1895 if {[info exists selectedline]} {
1902 if {[info exists selectedline]} {
1896 set l [expr {$selectedline + 1}]
1903 set l [expr {$selectedline + 1}]
1897 } else {
1904 } else {
1898 set l 0
1905 set l 0
1899 }
1906 }
1900 set ffileline $l
1907 set ffileline $l
1901 set findstartline $l
1908 set findstartline $l
1902 set diffsneeded {}
1909 set diffsneeded {}
1903 set fdiffsneeded {}
1910 set fdiffsneeded {}
1904 while 1 {
1911 while 1 {
1905 set id $lineid($l)
1912 set id $lineid($l)
1906 if {$findmergefiles || $nparents($id) == 1} {
1913 if {$findmergefiles || $nparents($id) == 1} {
1907 foreach p $parents($id) {
1914 foreach p $parents($id) {
1908 if {![info exists treediffs([list $id $p])]} {
1915 if {![info exists treediffs([list $id $p])]} {
1909 append diffsneeded "$id $p\n"
1916 append diffsneeded "$id $p\n"
1910 lappend fdiffsneeded [list $id $p]
1917 lappend fdiffsneeded [list $id $p]
1911 }
1918 }
1912 }
1919 }
1913 }
1920 }
1914 if {[incr l] >= $numcommits} {
1921 if {[incr l] >= $numcommits} {
1915 set l 0
1922 set l 0
1916 }
1923 }
1917 if {$l == $findstartline} break
1924 if {$l == $findstartline} break
1918 }
1925 }
1919
1926
1920 # start off a git-diff-tree process if needed
1927 # start off a git-diff-tree process if needed
1921 if {$diffsneeded ne {}} {
1928 if {$diffsneeded ne {}} {
1922 if {[catch {
1929 if {[catch {
1923 set df [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r --stdin << $diffsneeded] r]
1930 set df [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r --stdin << $diffsneeded] r]
1924 } err ]} {
1931 } err ]} {
1925 error_popup "Error starting search process: $err"
1932 error_popup "Error starting search process: $err"
1926 return
1933 return
1927 }
1934 }
1928 catch {unset fdiffids}
1935 catch {unset fdiffids}
1929 set fdiffpos 0
1936 set fdiffpos 0
1930 fconfigure $df -blocking 0
1937 fconfigure $df -blocking 0
1931 fileevent $df readable [list readfilediffs $df]
1938 fileevent $df readable [list readfilediffs $df]
1932 }
1939 }
1933
1940
1934 set finddidsel 0
1941 set finddidsel 0
1935 set findinsertpos end
1942 set findinsertpos end
1936 set id $lineid($l)
1943 set id $lineid($l)
1937 set p [lindex $parents($id) 0]
1944 set p [lindex $parents($id) 0]
1938 . config -cursor watch
1945 . config -cursor watch
1939 settextcursor watch
1946 settextcursor watch
1940 set findinprogress 1
1947 set findinprogress 1
1941 findcont [list $id $p]
1948 findcont [list $id $p]
1942 update
1949 update
1943 }
1950 }
1944
1951
1945 proc readfilediffs {df} {
1952 proc readfilediffs {df} {
1946 global findids fdiffids fdiffs
1953 global findids fdiffids fdiffs
1947
1954
1948 set n [gets $df line]
1955 set n [gets $df line]
1949 if {$n < 0} {
1956 if {$n < 0} {
1950 if {[eof $df]} {
1957 if {[eof $df]} {
1951 donefilediff
1958 donefilediff
1952 if {[catch {close $df} err]} {
1959 if {[catch {close $df} err]} {
1953 stopfindproc
1960 stopfindproc
1954 bell
1961 bell
1955 error_popup "Error in hg debug-diff-tree: $err"
1962 error_popup "Error in hg debug-diff-tree: $err"
1956 } elseif {[info exists findids]} {
1963 } elseif {[info exists findids]} {
1957 set ids $findids
1964 set ids $findids
1958 stopfindproc
1965 stopfindproc
1959 bell
1966 bell
1960 error_popup "Couldn't find diffs for {$ids}"
1967 error_popup "Couldn't find diffs for {$ids}"
1961 }
1968 }
1962 }
1969 }
1963 return
1970 return
1964 }
1971 }
1965 if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} {
1972 if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} {
1966 # start of a new string of diffs
1973 # start of a new string of diffs
1967 donefilediff
1974 donefilediff
1968 set fdiffids [list $id $p]
1975 set fdiffids [list $id $p]
1969 set fdiffs {}
1976 set fdiffs {}
1970 } elseif {[string match ":*" $line]} {
1977 } elseif {[string match ":*" $line]} {
1971 lappend fdiffs [lindex $line 5]
1978 lappend fdiffs [lindex $line 5]
1972 }
1979 }
1973 }
1980 }
1974
1981
1975 proc donefilediff {} {
1982 proc donefilediff {} {
1976 global fdiffids fdiffs treediffs findids
1983 global fdiffids fdiffs treediffs findids
1977 global fdiffsneeded fdiffpos
1984 global fdiffsneeded fdiffpos
1978
1985
1979 if {[info exists fdiffids]} {
1986 if {[info exists fdiffids]} {
1980 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
1987 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
1981 && $fdiffpos < [llength $fdiffsneeded]} {
1988 && $fdiffpos < [llength $fdiffsneeded]} {
1982 # git-diff-tree doesn't output anything for a commit
1989 # git-diff-tree doesn't output anything for a commit
1983 # which doesn't change anything
1990 # which doesn't change anything
1984 set nullids [lindex $fdiffsneeded $fdiffpos]
1991 set nullids [lindex $fdiffsneeded $fdiffpos]
1985 set treediffs($nullids) {}
1992 set treediffs($nullids) {}
1986 if {[info exists findids] && $nullids eq $findids} {
1993 if {[info exists findids] && $nullids eq $findids} {
1987 unset findids
1994 unset findids
1988 findcont $nullids
1995 findcont $nullids
1989 }
1996 }
1990 incr fdiffpos
1997 incr fdiffpos
1991 }
1998 }
1992 incr fdiffpos
1999 incr fdiffpos
1993
2000
1994 if {![info exists treediffs($fdiffids)]} {
2001 if {![info exists treediffs($fdiffids)]} {
1995 set treediffs($fdiffids) $fdiffs
2002 set treediffs($fdiffids) $fdiffs
1996 }
2003 }
1997 if {[info exists findids] && $fdiffids eq $findids} {
2004 if {[info exists findids] && $fdiffids eq $findids} {
1998 unset findids
2005 unset findids
1999 findcont $fdiffids
2006 findcont $fdiffids
2000 }
2007 }
2001 }
2008 }
2002 }
2009 }
2003
2010
2004 proc findcont {ids} {
2011 proc findcont {ids} {
2005 global findids treediffs parents nparents
2012 global findids treediffs parents nparents
2006 global ffileline findstartline finddidsel
2013 global ffileline findstartline finddidsel
2007 global lineid numcommits matchinglines findinprogress
2014 global lineid numcommits matchinglines findinprogress
2008 global findmergefiles
2015 global findmergefiles
2009
2016
2010 set id [lindex $ids 0]
2017 set id [lindex $ids 0]
2011 set p [lindex $ids 1]
2018 set p [lindex $ids 1]
2012 set pi [lsearch -exact $parents($id) $p]
2019 set pi [lsearch -exact $parents($id) $p]
2013 set l $ffileline
2020 set l $ffileline
2014 while 1 {
2021 while 1 {
2015 if {$findmergefiles || $nparents($id) == 1} {
2022 if {$findmergefiles || $nparents($id) == 1} {
2016 if {![info exists treediffs($ids)]} {
2023 if {![info exists treediffs($ids)]} {
2017 set findids $ids
2024 set findids $ids
2018 set ffileline $l
2025 set ffileline $l
2019 return
2026 return
2020 }
2027 }
2021 set doesmatch 0
2028 set doesmatch 0
2022 foreach f $treediffs($ids) {
2029 foreach f $treediffs($ids) {
2023 set x [findmatches $f]
2030 set x [findmatches $f]
2024 if {$x != {}} {
2031 if {$x != {}} {
2025 set doesmatch 1
2032 set doesmatch 1
2026 break
2033 break
2027 }
2034 }
2028 }
2035 }
2029 if {$doesmatch} {
2036 if {$doesmatch} {
2030 insertmatch $l $id
2037 insertmatch $l $id
2031 set pi $nparents($id)
2038 set pi $nparents($id)
2032 }
2039 }
2033 } else {
2040 } else {
2034 set pi $nparents($id)
2041 set pi $nparents($id)
2035 }
2042 }
2036 if {[incr pi] >= $nparents($id)} {
2043 if {[incr pi] >= $nparents($id)} {
2037 set pi 0
2044 set pi 0
2038 if {[incr l] >= $numcommits} {
2045 if {[incr l] >= $numcommits} {
2039 set l 0
2046 set l 0
2040 }
2047 }
2041 if {$l == $findstartline} break
2048 if {$l == $findstartline} break
2042 set id $lineid($l)
2049 set id $lineid($l)
2043 }
2050 }
2044 set p [lindex $parents($id) $pi]
2051 set p [lindex $parents($id) $pi]
2045 set ids [list $id $p]
2052 set ids [list $id $p]
2046 }
2053 }
2047 stopfindproc
2054 stopfindproc
2048 if {!$finddidsel} {
2055 if {!$finddidsel} {
2049 bell
2056 bell
2050 }
2057 }
2051 }
2058 }
2052
2059
2053 # mark a commit as matching by putting a yellow background
2060 # mark a commit as matching by putting a yellow background
2054 # behind the headline
2061 # behind the headline
2055 proc markheadline {l id} {
2062 proc markheadline {l id} {
2056 global canv mainfont linehtag commitinfo
2063 global canv mainfont linehtag commitinfo
2057
2064
2058 set bbox [$canv bbox $linehtag($l)]
2065 set bbox [$canv bbox $linehtag($l)]
2059 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
2066 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
2060 $canv lower $t
2067 $canv lower $t
2061 }
2068 }
2062
2069
2063 # mark the bits of a headline, author or date that match a find string
2070 # mark the bits of a headline, author or date that match a find string
2064 proc markmatches {canv l str tag matches font} {
2071 proc markmatches {canv l str tag matches font} {
2065 set bbox [$canv bbox $tag]
2072 set bbox [$canv bbox $tag]
2066 set x0 [lindex $bbox 0]
2073 set x0 [lindex $bbox 0]
2067 set y0 [lindex $bbox 1]
2074 set y0 [lindex $bbox 1]
2068 set y1 [lindex $bbox 3]
2075 set y1 [lindex $bbox 3]
2069 foreach match $matches {
2076 foreach match $matches {
2070 set start [lindex $match 0]
2077 set start [lindex $match 0]
2071 set end [lindex $match 1]
2078 set end [lindex $match 1]
2072 if {$start > $end} continue
2079 if {$start > $end} continue
2073 set xoff [font measure $font [string range $str 0 [expr $start-1]]]
2080 set xoff [font measure $font [string range $str 0 [expr $start-1]]]
2074 set xlen [font measure $font [string range $str 0 [expr $end]]]
2081 set xlen [font measure $font [string range $str 0 [expr $end]]]
2075 set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
2082 set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
2076 -outline {} -tags matches -fill yellow]
2083 -outline {} -tags matches -fill yellow]
2077 $canv lower $t
2084 $canv lower $t
2078 }
2085 }
2079 }
2086 }
2080
2087
2081 proc unmarkmatches {} {
2088 proc unmarkmatches {} {
2082 global matchinglines findids
2089 global matchinglines findids
2083 allcanvs delete matches
2090 allcanvs delete matches
2084 catch {unset matchinglines}
2091 catch {unset matchinglines}
2085 catch {unset findids}
2092 catch {unset findids}
2086 }
2093 }
2087
2094
2088 proc selcanvline {w x y} {
2095 proc selcanvline {w x y} {
2089 global canv canvy0 ctext linespc
2096 global canv canvy0 ctext linespc
2090 global lineid linehtag linentag linedtag rowtextx
2097 global lineid linehtag linentag linedtag rowtextx
2091 set ymax [lindex [$canv cget -scrollregion] 3]
2098 set ymax [lindex [$canv cget -scrollregion] 3]
2092 if {$ymax == {}} return
2099 if {$ymax == {}} return
2093 set yfrac [lindex [$canv yview] 0]
2100 set yfrac [lindex [$canv yview] 0]
2094 set y [expr {$y + $yfrac * $ymax}]
2101 set y [expr {$y + $yfrac * $ymax}]
2095 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
2102 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
2096 if {$l < 0} {
2103 if {$l < 0} {
2097 set l 0
2104 set l 0
2098 }
2105 }
2099 if {$w eq $canv} {
2106 if {$w eq $canv} {
2100 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
2107 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
2101 }
2108 }
2102 unmarkmatches
2109 unmarkmatches
2103 selectline $l 1
2110 selectline $l 1
2104 }
2111 }
2105
2112
2106 proc commit_descriptor {p} {
2113 proc commit_descriptor {p} {
2107 global commitinfo
2114 global commitinfo
2108 set l "..."
2115 set l "..."
2109 if {[info exists commitinfo($p)]} {
2116 if {[info exists commitinfo($p)]} {
2110 set l [lindex $commitinfo($p) 0]
2117 set l [lindex $commitinfo($p) 0]
2111 set r [lindex $commitinfo($p) 6]
2118 set r [lindex $commitinfo($p) 6]
2112 }
2119 }
2113 return "$r:$p ($l)"
2120 return "$r:$p ($l)"
2114 }
2121 }
2115
2122
2116 # append some text to the ctext widget, and make any SHA1 ID
2123 # append some text to the ctext widget, and make any SHA1 ID
2117 # that we know about be a clickable link.
2124 # that we know about be a clickable link.
2118 proc appendwithlinks {text} {
2125 proc appendwithlinks {text} {
2119 global ctext idline linknum
2126 global ctext idline linknum
2120
2127
2121 set start [$ctext index "end - 1c"]
2128 set start [$ctext index "end - 1c"]
2122 $ctext insert end $text
2129 $ctext insert end $text
2123 $ctext insert end "\n"
2130 $ctext insert end "\n"
2124 set links [regexp -indices -all -inline {[0-9a-f]{12}} $text]
2131 set links [regexp -indices -all -inline {[0-9a-f]{12}} $text]
2125 foreach l $links {
2132 foreach l $links {
2126 set s [lindex $l 0]
2133 set s [lindex $l 0]
2127 set e [lindex $l 1]
2134 set e [lindex $l 1]
2128 set linkid [string range $text $s $e]
2135 set linkid [string range $text $s $e]
2129 if {![info exists idline($linkid)]} continue
2136 if {![info exists idline($linkid)]} continue
2130 incr e
2137 incr e
2131 $ctext tag add link "$start + $s c" "$start + $e c"
2138 $ctext tag add link "$start + $s c" "$start + $e c"
2132 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
2139 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
2133 $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
2140 $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
2134 incr linknum
2141 incr linknum
2135 }
2142 }
2136 $ctext tag conf link -foreground blue -underline 1
2143 $ctext tag conf link -foreground blue -underline 1
2137 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
2144 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
2138 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
2145 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
2139 }
2146 }
2140
2147
2141 proc selectline {l isnew} {
2148 proc selectline {l isnew} {
2142 global canv canv2 canv3 ctext commitinfo selectedline
2149 global canv canv2 canv3 ctext commitinfo selectedline
2143 global lineid linehtag linentag linedtag
2150 global lineid linehtag linentag linedtag
2144 global canvy0 linespc parents nparents children
2151 global canvy0 linespc parents nparents children
2145 global cflist currentid sha1entry
2152 global cflist currentid sha1entry
2146 global commentend idtags idline linknum
2153 global commentend idtags idline linknum
2147
2154
2148 $canv delete hover
2155 $canv delete hover
2149 normalline
2156 normalline
2150 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
2157 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
2151 $canv delete secsel
2158 $canv delete secsel
2152 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
2159 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
2153 -tags secsel -fill [$canv cget -selectbackground]]
2160 -tags secsel -fill [$canv cget -selectbackground]]
2154 $canv lower $t
2161 $canv lower $t
2155 $canv2 delete secsel
2162 $canv2 delete secsel
2156 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
2163 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
2157 -tags secsel -fill [$canv2 cget -selectbackground]]
2164 -tags secsel -fill [$canv2 cget -selectbackground]]
2158 $canv2 lower $t
2165 $canv2 lower $t
2159 $canv3 delete secsel
2166 $canv3 delete secsel
2160 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
2167 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
2161 -tags secsel -fill [$canv3 cget -selectbackground]]
2168 -tags secsel -fill [$canv3 cget -selectbackground]]
2162 $canv3 lower $t
2169 $canv3 lower $t
2163 set y [expr {$canvy0 + $l * $linespc}]
2170 set y [expr {$canvy0 + $l * $linespc}]
2164 set ymax [lindex [$canv cget -scrollregion] 3]
2171 set ymax [lindex [$canv cget -scrollregion] 3]
2165 set ytop [expr {$y - $linespc - 1}]
2172 set ytop [expr {$y - $linespc - 1}]
2166 set ybot [expr {$y + $linespc + 1}]
2173 set ybot [expr {$y + $linespc + 1}]
2167 set wnow [$canv yview]
2174 set wnow [$canv yview]
2168 set wtop [expr [lindex $wnow 0] * $ymax]
2175 set wtop [expr [lindex $wnow 0] * $ymax]
2169 set wbot [expr [lindex $wnow 1] * $ymax]
2176 set wbot [expr [lindex $wnow 1] * $ymax]
2170 set wh [expr {$wbot - $wtop}]
2177 set wh [expr {$wbot - $wtop}]
2171 set newtop $wtop
2178 set newtop $wtop
2172 if {$ytop < $wtop} {
2179 if {$ytop < $wtop} {
2173 if {$ybot < $wtop} {
2180 if {$ybot < $wtop} {
2174 set newtop [expr {$y - $wh / 2.0}]
2181 set newtop [expr {$y - $wh / 2.0}]
2175 } else {
2182 } else {
2176 set newtop $ytop
2183 set newtop $ytop
2177 if {$newtop > $wtop - $linespc} {
2184 if {$newtop > $wtop - $linespc} {
2178 set newtop [expr {$wtop - $linespc}]
2185 set newtop [expr {$wtop - $linespc}]
2179 }
2186 }
2180 }
2187 }
2181 } elseif {$ybot > $wbot} {
2188 } elseif {$ybot > $wbot} {
2182 if {$ytop > $wbot} {
2189 if {$ytop > $wbot} {
2183 set newtop [expr {$y - $wh / 2.0}]
2190 set newtop [expr {$y - $wh / 2.0}]
2184 } else {
2191 } else {
2185 set newtop [expr {$ybot - $wh}]
2192 set newtop [expr {$ybot - $wh}]
2186 if {$newtop < $wtop + $linespc} {
2193 if {$newtop < $wtop + $linespc} {
2187 set newtop [expr {$wtop + $linespc}]
2194 set newtop [expr {$wtop + $linespc}]
2188 }
2195 }
2189 }
2196 }
2190 }
2197 }
2191 if {$newtop != $wtop} {
2198 if {$newtop != $wtop} {
2192 if {$newtop < 0} {
2199 if {$newtop < 0} {
2193 set newtop 0
2200 set newtop 0
2194 }
2201 }
2195 allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
2202 allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
2196 }
2203 }
2197
2204
2198 if {$isnew} {
2205 if {$isnew} {
2199 addtohistory [list selectline $l 0]
2206 addtohistory [list selectline $l 0]
2200 }
2207 }
2201
2208
2202 set selectedline $l
2209 set selectedline $l
2203
2210
2204 set id $lineid($l)
2211 set id $lineid($l)
2205 set currentid $id
2212 set currentid $id
2206 $sha1entry delete 0 end
2213 $sha1entry delete 0 end
2207 $sha1entry insert 0 $id
2214 $sha1entry insert 0 $id
2208 $sha1entry selection from 0
2215 $sha1entry selection from 0
2209 $sha1entry selection to end
2216 $sha1entry selection to end
2210
2217
2211 $ctext conf -state normal
2218 $ctext conf -state normal
2212 $ctext delete 0.0 end
2219 $ctext delete 0.0 end
2213 set linknum 0
2220 set linknum 0
2214 $ctext mark set fmark.0 0.0
2221 $ctext mark set fmark.0 0.0
2215 $ctext mark gravity fmark.0 left
2222 $ctext mark gravity fmark.0 left
2216 set info $commitinfo($id)
2223 set info $commitinfo($id)
2217 $ctext insert end "Revision: [lindex $info 6]\n"
2224 $ctext insert end "Revision: [lindex $info 6]\n"
2218 $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n"
2225 $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n"
2219 $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
2226 $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
2220 if {[info exists idtags($id)]} {
2227 if {[info exists idtags($id)]} {
2221 $ctext insert end "Tags:"
2228 $ctext insert end "Tags:"
2222 foreach tag $idtags($id) {
2229 foreach tag $idtags($id) {
2223 $ctext insert end " $tag"
2230 $ctext insert end " $tag"
2224 }
2231 }
2225 $ctext insert end "\n"
2232 $ctext insert end "\n"
2226 }
2233 }
2227
2234
2228 set comment {}
2235 set comment {}
2229 if {[info exists parents($id)]} {
2236 if {[info exists parents($id)]} {
2230 foreach p $parents($id) {
2237 foreach p $parents($id) {
2231 append comment "Parent: [commit_descriptor $p]\n"
2238 append comment "Parent: [commit_descriptor $p]\n"
2232 }
2239 }
2233 }
2240 }
2234 if {[info exists children($id)]} {
2241 if {[info exists children($id)]} {
2235 foreach c $children($id) {
2242 foreach c $children($id) {
2236 append comment "Child: [commit_descriptor $c]\n"
2243 append comment "Child: [commit_descriptor $c]\n"
2237 }
2244 }
2238 }
2245 }
2239 append comment "\n"
2246 append comment "\n"
2240 append comment [lindex $info 5]
2247 append comment [lindex $info 5]
2241
2248
2242 # make anything that looks like a SHA1 ID be a clickable link
2249 # make anything that looks like a SHA1 ID be a clickable link
2243 appendwithlinks $comment
2250 appendwithlinks $comment
2244
2251
2245 $ctext tag delete Comments
2252 $ctext tag delete Comments
2246 $ctext tag remove found 1.0 end
2253 $ctext tag remove found 1.0 end
2247 $ctext conf -state disabled
2254 $ctext conf -state disabled
2248 set commentend [$ctext index "end - 1c"]
2255 set commentend [$ctext index "end - 1c"]
2249
2256
2250 $cflist delete 0 end
2257 $cflist delete 0 end
2251 $cflist insert end "Comments"
2258 $cflist insert end "Comments"
2252 if {$nparents($id) == 1} {
2259 if {$nparents($id) == 1} {
2253 startdiff [concat $id $parents($id)]
2260 startdiff [concat $id $parents($id)]
2254 } elseif {$nparents($id) > 1} {
2261 } elseif {$nparents($id) > 1} {
2255 mergediff $id
2262 mergediff $id
2256 }
2263 }
2257 }
2264 }
2258
2265
2259 proc selnextline {dir} {
2266 proc selnextline {dir} {
2260 global selectedline
2267 global selectedline
2261 if {![info exists selectedline]} return
2268 if {![info exists selectedline]} return
2262 set l [expr $selectedline + $dir]
2269 set l [expr $selectedline + $dir]
2263 unmarkmatches
2270 unmarkmatches
2264 selectline $l 1
2271 selectline $l 1
2265 }
2272 }
2266
2273
2267 proc unselectline {} {
2274 proc unselectline {} {
2268 global selectedline
2275 global selectedline
2269
2276
2270 catch {unset selectedline}
2277 catch {unset selectedline}
2271 allcanvs delete secsel
2278 allcanvs delete secsel
2272 }
2279 }
2273
2280
2274 proc addtohistory {cmd} {
2281 proc addtohistory {cmd} {
2275 global history historyindex
2282 global history historyindex
2276
2283
2277 if {$historyindex > 0
2284 if {$historyindex > 0
2278 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2285 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2279 return
2286 return
2280 }
2287 }
2281
2288
2282 if {$historyindex < [llength $history]} {
2289 if {$historyindex < [llength $history]} {
2283 set history [lreplace $history $historyindex end $cmd]
2290 set history [lreplace $history $historyindex end $cmd]
2284 } else {
2291 } else {
2285 lappend history $cmd
2292 lappend history $cmd
2286 }
2293 }
2287 incr historyindex
2294 incr historyindex
2288 if {$historyindex > 1} {
2295 if {$historyindex > 1} {
2289 .ctop.top.bar.leftbut conf -state normal
2296 .ctop.top.bar.leftbut conf -state normal
2290 } else {
2297 } else {
2291 .ctop.top.bar.leftbut conf -state disabled
2298 .ctop.top.bar.leftbut conf -state disabled
2292 }
2299 }
2293 .ctop.top.bar.rightbut conf -state disabled
2300 .ctop.top.bar.rightbut conf -state disabled
2294 }
2301 }
2295
2302
2296 proc goback {} {
2303 proc goback {} {
2297 global history historyindex
2304 global history historyindex
2298
2305
2299 if {$historyindex > 1} {
2306 if {$historyindex > 1} {
2300 incr historyindex -1
2307 incr historyindex -1
2301 set cmd [lindex $history [expr {$historyindex - 1}]]
2308 set cmd [lindex $history [expr {$historyindex - 1}]]
2302 eval $cmd
2309 eval $cmd
2303 .ctop.top.bar.rightbut conf -state normal
2310 .ctop.top.bar.rightbut conf -state normal
2304 }
2311 }
2305 if {$historyindex <= 1} {
2312 if {$historyindex <= 1} {
2306 .ctop.top.bar.leftbut conf -state disabled
2313 .ctop.top.bar.leftbut conf -state disabled
2307 }
2314 }
2308 }
2315 }
2309
2316
2310 proc goforw {} {
2317 proc goforw {} {
2311 global history historyindex
2318 global history historyindex
2312
2319
2313 if {$historyindex < [llength $history]} {
2320 if {$historyindex < [llength $history]} {
2314 set cmd [lindex $history $historyindex]
2321 set cmd [lindex $history $historyindex]
2315 incr historyindex
2322 incr historyindex
2316 eval $cmd
2323 eval $cmd
2317 .ctop.top.bar.leftbut conf -state normal
2324 .ctop.top.bar.leftbut conf -state normal
2318 }
2325 }
2319 if {$historyindex >= [llength $history]} {
2326 if {$historyindex >= [llength $history]} {
2320 .ctop.top.bar.rightbut conf -state disabled
2327 .ctop.top.bar.rightbut conf -state disabled
2321 }
2328 }
2322 }
2329 }
2323
2330
2324 proc mergediff {id} {
2331 proc mergediff {id} {
2325 global parents diffmergeid diffmergegca mergefilelist diffpindex
2332 global parents diffmergeid diffmergegca mergefilelist diffpindex
2326
2333
2327 set diffmergeid $id
2334 set diffmergeid $id
2328 set diffpindex -1
2335 set diffpindex -1
2329 set diffmergegca [findgca $parents($id)]
2336 set diffmergegca [findgca $parents($id)]
2330 if {[info exists mergefilelist($id)]} {
2337 if {[info exists mergefilelist($id)]} {
2331 if {$mergefilelist($id) ne {}} {
2338 if {$mergefilelist($id) ne {}} {
2332 showmergediff
2339 showmergediff
2333 }
2340 }
2334 } else {
2341 } else {
2335 contmergediff {}
2342 contmergediff {}
2336 }
2343 }
2337 }
2344 }
2338
2345
2339 proc findgca {ids} {
2346 proc findgca {ids} {
2340 global env
2347 global env
2341 set gca {}
2348 set gca {}
2342 foreach id $ids {
2349 foreach id $ids {
2343 if {$gca eq {}} {
2350 if {$gca eq {}} {
2344 set gca $id
2351 set gca $id
2345 } else {
2352 } else {
2346 if {[catch {
2353 if {[catch {
2347 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2354 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2348 } err]} {
2355 } err]} {
2349 return {}
2356 return {}
2350 }
2357 }
2351 }
2358 }
2352 }
2359 }
2353 return $gca
2360 return $gca
2354 }
2361 }
2355
2362
2356 proc contmergediff {ids} {
2363 proc contmergediff {ids} {
2357 global diffmergeid diffpindex parents nparents diffmergegca
2364 global diffmergeid diffpindex parents nparents diffmergegca
2358 global treediffs mergefilelist diffids treepending
2365 global treediffs mergefilelist diffids treepending
2359
2366
2360 # diff the child against each of the parents, and diff
2367 # diff the child against each of the parents, and diff
2361 # each of the parents against the GCA.
2368 # each of the parents against the GCA.
2362 while 1 {
2369 while 1 {
2363 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2370 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2364 set ids [list [lindex $ids 1] $diffmergegca]
2371 set ids [list [lindex $ids 1] $diffmergegca]
2365 } else {
2372 } else {
2366 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2373 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2367 set p [lindex $parents($diffmergeid) $diffpindex]
2374 set p [lindex $parents($diffmergeid) $diffpindex]
2368 set ids [list $diffmergeid $p]
2375 set ids [list $diffmergeid $p]
2369 }
2376 }
2370 if {![info exists treediffs($ids)]} {
2377 if {![info exists treediffs($ids)]} {
2371 set diffids $ids
2378 set diffids $ids
2372 if {![info exists treepending]} {
2379 if {![info exists treepending]} {
2373 gettreediffs $ids
2380 gettreediffs $ids
2374 }
2381 }
2375 return
2382 return
2376 }
2383 }
2377 }
2384 }
2378
2385
2379 # If a file in some parent is different from the child and also
2386 # If a file in some parent is different from the child and also
2380 # different from the GCA, then it's interesting.
2387 # different from the GCA, then it's interesting.
2381 # If we don't have a GCA, then a file is interesting if it is
2388 # If we don't have a GCA, then a file is interesting if it is
2382 # different from the child in all the parents.
2389 # different from the child in all the parents.
2383 if {$diffmergegca ne {}} {
2390 if {$diffmergegca ne {}} {
2384 set files {}
2391 set files {}
2385 foreach p $parents($diffmergeid) {
2392 foreach p $parents($diffmergeid) {
2386 set gcadiffs $treediffs([list $p $diffmergegca])
2393 set gcadiffs $treediffs([list $p $diffmergegca])
2387 foreach f $treediffs([list $diffmergeid $p]) {
2394 foreach f $treediffs([list $diffmergeid $p]) {
2388 if {[lsearch -exact $files $f] < 0
2395 if {[lsearch -exact $files $f] < 0
2389 && [lsearch -exact $gcadiffs $f] >= 0} {
2396 && [lsearch -exact $gcadiffs $f] >= 0} {
2390 lappend files $f
2397 lappend files $f
2391 }
2398 }
2392 }
2399 }
2393 }
2400 }
2394 set files [lsort $files]
2401 set files [lsort $files]
2395 } else {
2402 } else {
2396 set p [lindex $parents($diffmergeid) 0]
2403 set p [lindex $parents($diffmergeid) 0]
2397 set files $treediffs([list $diffmergeid $p])
2404 set files $treediffs([list $diffmergeid $p])
2398 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2405 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2399 set p [lindex $parents($diffmergeid) $i]
2406 set p [lindex $parents($diffmergeid) $i]
2400 set df $treediffs([list $diffmergeid $p])
2407 set df $treediffs([list $diffmergeid $p])
2401 set nf {}
2408 set nf {}
2402 foreach f $files {
2409 foreach f $files {
2403 if {[lsearch -exact $df $f] >= 0} {
2410 if {[lsearch -exact $df $f] >= 0} {
2404 lappend nf $f
2411 lappend nf $f
2405 }
2412 }
2406 }
2413 }
2407 set files $nf
2414 set files $nf
2408 }
2415 }
2409 }
2416 }
2410
2417
2411 set mergefilelist($diffmergeid) $files
2418 set mergefilelist($diffmergeid) $files
2412 if {$files ne {}} {
2419 if {$files ne {}} {
2413 showmergediff
2420 showmergediff
2414 }
2421 }
2415 }
2422 }
2416
2423
2417 proc showmergediff {} {
2424 proc showmergediff {} {
2418 global cflist diffmergeid mergefilelist parents
2425 global cflist diffmergeid mergefilelist parents
2419 global diffopts diffinhunk currentfile currenthunk filelines
2426 global diffopts diffinhunk currentfile currenthunk filelines
2420 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2427 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2421 global env
2428 global env
2422
2429
2423 set files $mergefilelist($diffmergeid)
2430 set files $mergefilelist($diffmergeid)
2424 foreach f $files {
2431 foreach f $files {
2425 $cflist insert end $f
2432 $cflist insert end $f
2426 }
2433 }
2427 set env(GIT_DIFF_OPTS) $diffopts
2434 set env(GIT_DIFF_OPTS) $diffopts
2428 set flist {}
2435 set flist {}
2429 catch {unset currentfile}
2436 catch {unset currentfile}
2430 catch {unset currenthunk}
2437 catch {unset currenthunk}
2431 catch {unset filelines}
2438 catch {unset filelines}
2432 catch {unset groupfilenum}
2439 catch {unset groupfilenum}
2433 catch {unset grouphunks}
2440 catch {unset grouphunks}
2434 set groupfilelast -1
2441 set groupfilelast -1
2435 foreach p $parents($diffmergeid) {
2442 foreach p $parents($diffmergeid) {
2436 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2443 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2437 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2444 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2438 if {[catch {set f [open $cmd r]} err]} {
2445 if {[catch {set f [open $cmd r]} err]} {
2439 error_popup "Error getting diffs: $err"
2446 error_popup "Error getting diffs: $err"
2440 foreach f $flist {
2447 foreach f $flist {
2441 catch {close $f}
2448 catch {close $f}
2442 }
2449 }
2443 return
2450 return
2444 }
2451 }
2445 lappend flist $f
2452 lappend flist $f
2446 set ids [list $diffmergeid $p]
2453 set ids [list $diffmergeid $p]
2447 set mergefds($ids) $f
2454 set mergefds($ids) $f
2448 set diffinhunk($ids) 0
2455 set diffinhunk($ids) 0
2449 set diffblocked($ids) 0
2456 set diffblocked($ids) 0
2450 fconfigure $f -blocking 0
2457 fconfigure $f -blocking 0
2451 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2458 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2452 }
2459 }
2453 }
2460 }
2454
2461
2455 proc getmergediffline {f ids id} {
2462 proc getmergediffline {f ids id} {
2456 global diffmergeid diffinhunk diffoldlines diffnewlines
2463 global diffmergeid diffinhunk diffoldlines diffnewlines
2457 global currentfile currenthunk
2464 global currentfile currenthunk
2458 global diffoldstart diffnewstart diffoldlno diffnewlno
2465 global diffoldstart diffnewstart diffoldlno diffnewlno
2459 global diffblocked mergefilelist
2466 global diffblocked mergefilelist
2460 global noldlines nnewlines difflcounts filelines
2467 global noldlines nnewlines difflcounts filelines
2461
2468
2462 set n [gets $f line]
2469 set n [gets $f line]
2463 if {$n < 0} {
2470 if {$n < 0} {
2464 if {![eof $f]} return
2471 if {![eof $f]} return
2465 }
2472 }
2466
2473
2467 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2474 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2468 if {$n < 0} {
2475 if {$n < 0} {
2469 close $f
2476 close $f
2470 }
2477 }
2471 return
2478 return
2472 }
2479 }
2473
2480
2474 if {$diffinhunk($ids) != 0} {
2481 if {$diffinhunk($ids) != 0} {
2475 set fi $currentfile($ids)
2482 set fi $currentfile($ids)
2476 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2483 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2477 # continuing an existing hunk
2484 # continuing an existing hunk
2478 set line [string range $line 1 end]
2485 set line [string range $line 1 end]
2479 set p [lindex $ids 1]
2486 set p [lindex $ids 1]
2480 if {$match eq "-" || $match eq " "} {
2487 if {$match eq "-" || $match eq " "} {
2481 set filelines($p,$fi,$diffoldlno($ids)) $line
2488 set filelines($p,$fi,$diffoldlno($ids)) $line
2482 incr diffoldlno($ids)
2489 incr diffoldlno($ids)
2483 }
2490 }
2484 if {$match eq "+" || $match eq " "} {
2491 if {$match eq "+" || $match eq " "} {
2485 set filelines($id,$fi,$diffnewlno($ids)) $line
2492 set filelines($id,$fi,$diffnewlno($ids)) $line
2486 incr diffnewlno($ids)
2493 incr diffnewlno($ids)
2487 }
2494 }
2488 if {$match eq " "} {
2495 if {$match eq " "} {
2489 if {$diffinhunk($ids) == 2} {
2496 if {$diffinhunk($ids) == 2} {
2490 lappend difflcounts($ids) \
2497 lappend difflcounts($ids) \
2491 [list $noldlines($ids) $nnewlines($ids)]
2498 [list $noldlines($ids) $nnewlines($ids)]
2492 set noldlines($ids) 0
2499 set noldlines($ids) 0
2493 set diffinhunk($ids) 1
2500 set diffinhunk($ids) 1
2494 }
2501 }
2495 incr noldlines($ids)
2502 incr noldlines($ids)
2496 } elseif {$match eq "-" || $match eq "+"} {
2503 } elseif {$match eq "-" || $match eq "+"} {
2497 if {$diffinhunk($ids) == 1} {
2504 if {$diffinhunk($ids) == 1} {
2498 lappend difflcounts($ids) [list $noldlines($ids)]
2505 lappend difflcounts($ids) [list $noldlines($ids)]
2499 set noldlines($ids) 0
2506 set noldlines($ids) 0
2500 set nnewlines($ids) 0
2507 set nnewlines($ids) 0
2501 set diffinhunk($ids) 2
2508 set diffinhunk($ids) 2
2502 }
2509 }
2503 if {$match eq "-"} {
2510 if {$match eq "-"} {
2504 incr noldlines($ids)
2511 incr noldlines($ids)
2505 } else {
2512 } else {
2506 incr nnewlines($ids)
2513 incr nnewlines($ids)
2507 }
2514 }
2508 }
2515 }
2509 # and if it's \ No newline at end of line, then what?
2516 # and if it's \ No newline at end of line, then what?
2510 return
2517 return
2511 }
2518 }
2512 # end of a hunk
2519 # end of a hunk
2513 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2520 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2514 lappend difflcounts($ids) [list $noldlines($ids)]
2521 lappend difflcounts($ids) [list $noldlines($ids)]
2515 } elseif {$diffinhunk($ids) == 2
2522 } elseif {$diffinhunk($ids) == 2
2516 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2523 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2517 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2524 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2518 }
2525 }
2519 set currenthunk($ids) [list $currentfile($ids) \
2526 set currenthunk($ids) [list $currentfile($ids) \
2520 $diffoldstart($ids) $diffnewstart($ids) \
2527 $diffoldstart($ids) $diffnewstart($ids) \
2521 $diffoldlno($ids) $diffnewlno($ids) \
2528 $diffoldlno($ids) $diffnewlno($ids) \
2522 $difflcounts($ids)]
2529 $difflcounts($ids)]
2523 set diffinhunk($ids) 0
2530 set diffinhunk($ids) 0
2524 # -1 = need to block, 0 = unblocked, 1 = is blocked
2531 # -1 = need to block, 0 = unblocked, 1 = is blocked
2525 set diffblocked($ids) -1
2532 set diffblocked($ids) -1
2526 processhunks
2533 processhunks
2527 if {$diffblocked($ids) == -1} {
2534 if {$diffblocked($ids) == -1} {
2528 fileevent $f readable {}
2535 fileevent $f readable {}
2529 set diffblocked($ids) 1
2536 set diffblocked($ids) 1
2530 }
2537 }
2531 }
2538 }
2532
2539
2533 if {$n < 0} {
2540 if {$n < 0} {
2534 # eof
2541 # eof
2535 if {!$diffblocked($ids)} {
2542 if {!$diffblocked($ids)} {
2536 close $f
2543 close $f
2537 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2544 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2538 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2545 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2539 processhunks
2546 processhunks
2540 }
2547 }
2541 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2548 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2542 # start of a new file
2549 # start of a new file
2543 set currentfile($ids) \
2550 set currentfile($ids) \
2544 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2551 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2545 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2552 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2546 $line match f1l f1c f2l f2c rest]} {
2553 $line match f1l f1c f2l f2c rest]} {
2547 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2554 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2548 # start of a new hunk
2555 # start of a new hunk
2549 if {$f1l == 0 && $f1c == 0} {
2556 if {$f1l == 0 && $f1c == 0} {
2550 set f1l 1
2557 set f1l 1
2551 }
2558 }
2552 if {$f2l == 0 && $f2c == 0} {
2559 if {$f2l == 0 && $f2c == 0} {
2553 set f2l 1
2560 set f2l 1
2554 }
2561 }
2555 set diffinhunk($ids) 1
2562 set diffinhunk($ids) 1
2556 set diffoldstart($ids) $f1l
2563 set diffoldstart($ids) $f1l
2557 set diffnewstart($ids) $f2l
2564 set diffnewstart($ids) $f2l
2558 set diffoldlno($ids) $f1l
2565 set diffoldlno($ids) $f1l
2559 set diffnewlno($ids) $f2l
2566 set diffnewlno($ids) $f2l
2560 set difflcounts($ids) {}
2567 set difflcounts($ids) {}
2561 set noldlines($ids) 0
2568 set noldlines($ids) 0
2562 set nnewlines($ids) 0
2569 set nnewlines($ids) 0
2563 }
2570 }
2564 }
2571 }
2565 }
2572 }
2566
2573
2567 proc processhunks {} {
2574 proc processhunks {} {
2568 global diffmergeid parents nparents currenthunk
2575 global diffmergeid parents nparents currenthunk
2569 global mergefilelist diffblocked mergefds
2576 global mergefilelist diffblocked mergefds
2570 global grouphunks grouplinestart grouplineend groupfilenum
2577 global grouphunks grouplinestart grouplineend groupfilenum
2571
2578
2572 set nfiles [llength $mergefilelist($diffmergeid)]
2579 set nfiles [llength $mergefilelist($diffmergeid)]
2573 while 1 {
2580 while 1 {
2574 set fi $nfiles
2581 set fi $nfiles
2575 set lno 0
2582 set lno 0
2576 # look for the earliest hunk
2583 # look for the earliest hunk
2577 foreach p $parents($diffmergeid) {
2584 foreach p $parents($diffmergeid) {
2578 set ids [list $diffmergeid $p]
2585 set ids [list $diffmergeid $p]
2579 if {![info exists currenthunk($ids)]} return
2586 if {![info exists currenthunk($ids)]} return
2580 set i [lindex $currenthunk($ids) 0]
2587 set i [lindex $currenthunk($ids) 0]
2581 set l [lindex $currenthunk($ids) 2]
2588 set l [lindex $currenthunk($ids) 2]
2582 if {$i < $fi || ($i == $fi && $l < $lno)} {
2589 if {$i < $fi || ($i == $fi && $l < $lno)} {
2583 set fi $i
2590 set fi $i
2584 set lno $l
2591 set lno $l
2585 set pi $p
2592 set pi $p
2586 }
2593 }
2587 }
2594 }
2588
2595
2589 if {$fi < $nfiles} {
2596 if {$fi < $nfiles} {
2590 set ids [list $diffmergeid $pi]
2597 set ids [list $diffmergeid $pi]
2591 set hunk $currenthunk($ids)
2598 set hunk $currenthunk($ids)
2592 unset currenthunk($ids)
2599 unset currenthunk($ids)
2593 if {$diffblocked($ids) > 0} {
2600 if {$diffblocked($ids) > 0} {
2594 fileevent $mergefds($ids) readable \
2601 fileevent $mergefds($ids) readable \
2595 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2602 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2596 }
2603 }
2597 set diffblocked($ids) 0
2604 set diffblocked($ids) 0
2598
2605
2599 if {[info exists groupfilenum] && $groupfilenum == $fi
2606 if {[info exists groupfilenum] && $groupfilenum == $fi
2600 && $lno <= $grouplineend} {
2607 && $lno <= $grouplineend} {
2601 # add this hunk to the pending group
2608 # add this hunk to the pending group
2602 lappend grouphunks($pi) $hunk
2609 lappend grouphunks($pi) $hunk
2603 set endln [lindex $hunk 4]
2610 set endln [lindex $hunk 4]
2604 if {$endln > $grouplineend} {
2611 if {$endln > $grouplineend} {
2605 set grouplineend $endln
2612 set grouplineend $endln
2606 }
2613 }
2607 continue
2614 continue
2608 }
2615 }
2609 }
2616 }
2610
2617
2611 # succeeding stuff doesn't belong in this group, so
2618 # succeeding stuff doesn't belong in this group, so
2612 # process the group now
2619 # process the group now
2613 if {[info exists groupfilenum]} {
2620 if {[info exists groupfilenum]} {
2614 processgroup
2621 processgroup
2615 unset groupfilenum
2622 unset groupfilenum
2616 unset grouphunks
2623 unset grouphunks
2617 }
2624 }
2618
2625
2619 if {$fi >= $nfiles} break
2626 if {$fi >= $nfiles} break
2620
2627
2621 # start a new group
2628 # start a new group
2622 set groupfilenum $fi
2629 set groupfilenum $fi
2623 set grouphunks($pi) [list $hunk]
2630 set grouphunks($pi) [list $hunk]
2624 set grouplinestart $lno
2631 set grouplinestart $lno
2625 set grouplineend [lindex $hunk 4]
2632 set grouplineend [lindex $hunk 4]
2626 }
2633 }
2627 }
2634 }
2628
2635
2629 proc processgroup {} {
2636 proc processgroup {} {
2630 global groupfilelast groupfilenum difffilestart
2637 global groupfilelast groupfilenum difffilestart
2631 global mergefilelist diffmergeid ctext filelines
2638 global mergefilelist diffmergeid ctext filelines
2632 global parents diffmergeid diffoffset
2639 global parents diffmergeid diffoffset
2633 global grouphunks grouplinestart grouplineend nparents
2640 global grouphunks grouplinestart grouplineend nparents
2634 global mergemax
2641 global mergemax
2635
2642
2636 $ctext conf -state normal
2643 $ctext conf -state normal
2637 set id $diffmergeid
2644 set id $diffmergeid
2638 set f $groupfilenum
2645 set f $groupfilenum
2639 if {$groupfilelast != $f} {
2646 if {$groupfilelast != $f} {
2640 $ctext insert end "\n"
2647 $ctext insert end "\n"
2641 set here [$ctext index "end - 1c"]
2648 set here [$ctext index "end - 1c"]
2642 set difffilestart($f) $here
2649 set difffilestart($f) $here
2643 set mark fmark.[expr {$f + 1}]
2650 set mark fmark.[expr {$f + 1}]
2644 $ctext mark set $mark $here
2651 $ctext mark set $mark $here
2645 $ctext mark gravity $mark left
2652 $ctext mark gravity $mark left
2646 set header [lindex $mergefilelist($id) $f]
2653 set header [lindex $mergefilelist($id) $f]
2647 set l [expr {(78 - [string length $header]) / 2}]
2654 set l [expr {(78 - [string length $header]) / 2}]
2648 set pad [string range "----------------------------------------" 1 $l]
2655 set pad [string range "----------------------------------------" 1 $l]
2649 $ctext insert end "$pad $header $pad\n" filesep
2656 $ctext insert end "$pad $header $pad\n" filesep
2650 set groupfilelast $f
2657 set groupfilelast $f
2651 foreach p $parents($id) {
2658 foreach p $parents($id) {
2652 set diffoffset($p) 0
2659 set diffoffset($p) 0
2653 }
2660 }
2654 }
2661 }
2655
2662
2656 $ctext insert end "@@" msep
2663 $ctext insert end "@@" msep
2657 set nlines [expr {$grouplineend - $grouplinestart}]
2664 set nlines [expr {$grouplineend - $grouplinestart}]
2658 set events {}
2665 set events {}
2659 set pnum 0
2666 set pnum 0
2660 foreach p $parents($id) {
2667 foreach p $parents($id) {
2661 set startline [expr {$grouplinestart + $diffoffset($p)}]
2668 set startline [expr {$grouplinestart + $diffoffset($p)}]
2662 set ol $startline
2669 set ol $startline
2663 set nl $grouplinestart
2670 set nl $grouplinestart
2664 if {[info exists grouphunks($p)]} {
2671 if {[info exists grouphunks($p)]} {
2665 foreach h $grouphunks($p) {
2672 foreach h $grouphunks($p) {
2666 set l [lindex $h 2]
2673 set l [lindex $h 2]
2667 if {$nl < $l} {
2674 if {$nl < $l} {
2668 for {} {$nl < $l} {incr nl} {
2675 for {} {$nl < $l} {incr nl} {
2669 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2676 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2670 incr ol
2677 incr ol
2671 }
2678 }
2672 }
2679 }
2673 foreach chunk [lindex $h 5] {
2680 foreach chunk [lindex $h 5] {
2674 if {[llength $chunk] == 2} {
2681 if {[llength $chunk] == 2} {
2675 set olc [lindex $chunk 0]
2682 set olc [lindex $chunk 0]
2676 set nlc [lindex $chunk 1]
2683 set nlc [lindex $chunk 1]
2677 set nnl [expr {$nl + $nlc}]
2684 set nnl [expr {$nl + $nlc}]
2678 lappend events [list $nl $nnl $pnum $olc $nlc]
2685 lappend events [list $nl $nnl $pnum $olc $nlc]
2679 incr ol $olc
2686 incr ol $olc
2680 set nl $nnl
2687 set nl $nnl
2681 } else {
2688 } else {
2682 incr ol [lindex $chunk 0]
2689 incr ol [lindex $chunk 0]
2683 incr nl [lindex $chunk 0]
2690 incr nl [lindex $chunk 0]
2684 }
2691 }
2685 }
2692 }
2686 }
2693 }
2687 }
2694 }
2688 if {$nl < $grouplineend} {
2695 if {$nl < $grouplineend} {
2689 for {} {$nl < $grouplineend} {incr nl} {
2696 for {} {$nl < $grouplineend} {incr nl} {
2690 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2697 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2691 incr ol
2698 incr ol
2692 }
2699 }
2693 }
2700 }
2694 set nlines [expr {$ol - $startline}]
2701 set nlines [expr {$ol - $startline}]
2695 $ctext insert end " -$startline,$nlines" msep
2702 $ctext insert end " -$startline,$nlines" msep
2696 incr pnum
2703 incr pnum
2697 }
2704 }
2698
2705
2699 set nlines [expr {$grouplineend - $grouplinestart}]
2706 set nlines [expr {$grouplineend - $grouplinestart}]
2700 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2707 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2701
2708
2702 set events [lsort -integer -index 0 $events]
2709 set events [lsort -integer -index 0 $events]
2703 set nevents [llength $events]
2710 set nevents [llength $events]
2704 set nmerge $nparents($diffmergeid)
2711 set nmerge $nparents($diffmergeid)
2705 set l $grouplinestart
2712 set l $grouplinestart
2706 for {set i 0} {$i < $nevents} {set i $j} {
2713 for {set i 0} {$i < $nevents} {set i $j} {
2707 set nl [lindex $events $i 0]
2714 set nl [lindex $events $i 0]
2708 while {$l < $nl} {
2715 while {$l < $nl} {
2709 $ctext insert end " $filelines($id,$f,$l)\n"
2716 $ctext insert end " $filelines($id,$f,$l)\n"
2710 incr l
2717 incr l
2711 }
2718 }
2712 set e [lindex $events $i]
2719 set e [lindex $events $i]
2713 set enl [lindex $e 1]
2720 set enl [lindex $e 1]
2714 set j $i
2721 set j $i
2715 set active {}
2722 set active {}
2716 while 1 {
2723 while 1 {
2717 set pnum [lindex $e 2]
2724 set pnum [lindex $e 2]
2718 set olc [lindex $e 3]
2725 set olc [lindex $e 3]
2719 set nlc [lindex $e 4]
2726 set nlc [lindex $e 4]
2720 if {![info exists delta($pnum)]} {
2727 if {![info exists delta($pnum)]} {
2721 set delta($pnum) [expr {$olc - $nlc}]
2728 set delta($pnum) [expr {$olc - $nlc}]
2722 lappend active $pnum
2729 lappend active $pnum
2723 } else {
2730 } else {
2724 incr delta($pnum) [expr {$olc - $nlc}]
2731 incr delta($pnum) [expr {$olc - $nlc}]
2725 }
2732 }
2726 if {[incr j] >= $nevents} break
2733 if {[incr j] >= $nevents} break
2727 set e [lindex $events $j]
2734 set e [lindex $events $j]
2728 if {[lindex $e 0] >= $enl} break
2735 if {[lindex $e 0] >= $enl} break
2729 if {[lindex $e 1] > $enl} {
2736 if {[lindex $e 1] > $enl} {
2730 set enl [lindex $e 1]
2737 set enl [lindex $e 1]
2731 }
2738 }
2732 }
2739 }
2733 set nlc [expr {$enl - $l}]
2740 set nlc [expr {$enl - $l}]
2734 set ncol mresult
2741 set ncol mresult
2735 set bestpn -1
2742 set bestpn -1
2736 if {[llength $active] == $nmerge - 1} {
2743 if {[llength $active] == $nmerge - 1} {
2737 # no diff for one of the parents, i.e. it's identical
2744 # no diff for one of the parents, i.e. it's identical
2738 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2745 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2739 if {![info exists delta($pnum)]} {
2746 if {![info exists delta($pnum)]} {
2740 if {$pnum < $mergemax} {
2747 if {$pnum < $mergemax} {
2741 lappend ncol m$pnum
2748 lappend ncol m$pnum
2742 } else {
2749 } else {
2743 lappend ncol mmax
2750 lappend ncol mmax
2744 }
2751 }
2745 break
2752 break
2746 }
2753 }
2747 }
2754 }
2748 } elseif {[llength $active] == $nmerge} {
2755 } elseif {[llength $active] == $nmerge} {
2749 # all parents are different, see if one is very similar
2756 # all parents are different, see if one is very similar
2750 set bestsim 30
2757 set bestsim 30
2751 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2758 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2752 set sim [similarity $pnum $l $nlc $f \
2759 set sim [similarity $pnum $l $nlc $f \
2753 [lrange $events $i [expr {$j-1}]]]
2760 [lrange $events $i [expr {$j-1}]]]
2754 if {$sim > $bestsim} {
2761 if {$sim > $bestsim} {
2755 set bestsim $sim
2762 set bestsim $sim
2756 set bestpn $pnum
2763 set bestpn $pnum
2757 }
2764 }
2758 }
2765 }
2759 if {$bestpn >= 0} {
2766 if {$bestpn >= 0} {
2760 lappend ncol m$bestpn
2767 lappend ncol m$bestpn
2761 }
2768 }
2762 }
2769 }
2763 set pnum -1
2770 set pnum -1
2764 foreach p $parents($id) {
2771 foreach p $parents($id) {
2765 incr pnum
2772 incr pnum
2766 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
2773 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
2767 set olc [expr {$nlc + $delta($pnum)}]
2774 set olc [expr {$nlc + $delta($pnum)}]
2768 set ol [expr {$l + $diffoffset($p)}]
2775 set ol [expr {$l + $diffoffset($p)}]
2769 incr diffoffset($p) $delta($pnum)
2776 incr diffoffset($p) $delta($pnum)
2770 unset delta($pnum)
2777 unset delta($pnum)
2771 for {} {$olc > 0} {incr olc -1} {
2778 for {} {$olc > 0} {incr olc -1} {
2772 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
2779 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
2773 incr ol
2780 incr ol
2774 }
2781 }
2775 }
2782 }
2776 set endl [expr {$l + $nlc}]
2783 set endl [expr {$l + $nlc}]
2777 if {$bestpn >= 0} {
2784 if {$bestpn >= 0} {
2778 # show this pretty much as a normal diff
2785 # show this pretty much as a normal diff
2779 set p [lindex $parents($id) $bestpn]
2786 set p [lindex $parents($id) $bestpn]
2780 set ol [expr {$l + $diffoffset($p)}]
2787 set ol [expr {$l + $diffoffset($p)}]
2781 incr diffoffset($p) $delta($bestpn)
2788 incr diffoffset($p) $delta($bestpn)
2782 unset delta($bestpn)
2789 unset delta($bestpn)
2783 for {set k $i} {$k < $j} {incr k} {
2790 for {set k $i} {$k < $j} {incr k} {
2784 set e [lindex $events $k]
2791 set e [lindex $events $k]
2785 if {[lindex $e 2] != $bestpn} continue
2792 if {[lindex $e 2] != $bestpn} continue
2786 set nl [lindex $e 0]
2793 set nl [lindex $e 0]
2787 set ol [expr {$ol + $nl - $l}]
2794 set ol [expr {$ol + $nl - $l}]
2788 for {} {$l < $nl} {incr l} {
2795 for {} {$l < $nl} {incr l} {
2789 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2796 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2790 }
2797 }
2791 set c [lindex $e 3]
2798 set c [lindex $e 3]
2792 for {} {$c > 0} {incr c -1} {
2799 for {} {$c > 0} {incr c -1} {
2793 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
2800 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
2794 incr ol
2801 incr ol
2795 }
2802 }
2796 set nl [lindex $e 1]
2803 set nl [lindex $e 1]
2797 for {} {$l < $nl} {incr l} {
2804 for {} {$l < $nl} {incr l} {
2798 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
2805 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
2799 }
2806 }
2800 }
2807 }
2801 }
2808 }
2802 for {} {$l < $endl} {incr l} {
2809 for {} {$l < $endl} {incr l} {
2803 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2810 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2804 }
2811 }
2805 }
2812 }
2806 while {$l < $grouplineend} {
2813 while {$l < $grouplineend} {
2807 $ctext insert end " $filelines($id,$f,$l)\n"
2814 $ctext insert end " $filelines($id,$f,$l)\n"
2808 incr l
2815 incr l
2809 }
2816 }
2810 $ctext conf -state disabled
2817 $ctext conf -state disabled
2811 }
2818 }
2812
2819
2813 proc similarity {pnum l nlc f events} {
2820 proc similarity {pnum l nlc f events} {
2814 global diffmergeid parents diffoffset filelines
2821 global diffmergeid parents diffoffset filelines
2815
2822
2816 set id $diffmergeid
2823 set id $diffmergeid
2817 set p [lindex $parents($id) $pnum]
2824 set p [lindex $parents($id) $pnum]
2818 set ol [expr {$l + $diffoffset($p)}]
2825 set ol [expr {$l + $diffoffset($p)}]
2819 set endl [expr {$l + $nlc}]
2826 set endl [expr {$l + $nlc}]
2820 set same 0
2827 set same 0
2821 set diff 0
2828 set diff 0
2822 foreach e $events {
2829 foreach e $events {
2823 if {[lindex $e 2] != $pnum} continue
2830 if {[lindex $e 2] != $pnum} continue
2824 set nl [lindex $e 0]
2831 set nl [lindex $e 0]
2825 set ol [expr {$ol + $nl - $l}]
2832 set ol [expr {$ol + $nl - $l}]
2826 for {} {$l < $nl} {incr l} {
2833 for {} {$l < $nl} {incr l} {
2827 incr same [string length $filelines($id,$f,$l)]
2834 incr same [string length $filelines($id,$f,$l)]
2828 incr same
2835 incr same
2829 }
2836 }
2830 set oc [lindex $e 3]
2837 set oc [lindex $e 3]
2831 for {} {$oc > 0} {incr oc -1} {
2838 for {} {$oc > 0} {incr oc -1} {
2832 incr diff [string length $filelines($p,$f,$ol)]
2839 incr diff [string length $filelines($p,$f,$ol)]
2833 incr diff
2840 incr diff
2834 incr ol
2841 incr ol
2835 }
2842 }
2836 set nl [lindex $e 1]
2843 set nl [lindex $e 1]
2837 for {} {$l < $nl} {incr l} {
2844 for {} {$l < $nl} {incr l} {
2838 incr diff [string length $filelines($id,$f,$l)]
2845 incr diff [string length $filelines($id,$f,$l)]
2839 incr diff
2846 incr diff
2840 }
2847 }
2841 }
2848 }
2842 for {} {$l < $endl} {incr l} {
2849 for {} {$l < $endl} {incr l} {
2843 incr same [string length $filelines($id,$f,$l)]
2850 incr same [string length $filelines($id,$f,$l)]
2844 incr same
2851 incr same
2845 }
2852 }
2846 if {$same == 0} {
2853 if {$same == 0} {
2847 return 0
2854 return 0
2848 }
2855 }
2849 return [expr {200 * $same / (2 * $same + $diff)}]
2856 return [expr {200 * $same / (2 * $same + $diff)}]
2850 }
2857 }
2851
2858
2852 proc startdiff {ids} {
2859 proc startdiff {ids} {
2853 global treediffs diffids treepending diffmergeid
2860 global treediffs diffids treepending diffmergeid
2854
2861
2855 set diffids $ids
2862 set diffids $ids
2856 catch {unset diffmergeid}
2863 catch {unset diffmergeid}
2857 if {![info exists treediffs($ids)]} {
2864 if {![info exists treediffs($ids)]} {
2858 if {![info exists treepending]} {
2865 if {![info exists treepending]} {
2859 gettreediffs $ids
2866 gettreediffs $ids
2860 }
2867 }
2861 } else {
2868 } else {
2862 addtocflist $ids
2869 addtocflist $ids
2863 }
2870 }
2864 }
2871 }
2865
2872
2866 proc addtocflist {ids} {
2873 proc addtocflist {ids} {
2867 global treediffs cflist
2874 global treediffs cflist
2868 foreach f $treediffs($ids) {
2875 foreach f $treediffs($ids) {
2869 $cflist insert end $f
2876 $cflist insert end $f
2870 }
2877 }
2871 getblobdiffs $ids
2878 getblobdiffs $ids
2872 }
2879 }
2873
2880
2874 proc gettreediffs {ids} {
2881 proc gettreediffs {ids} {
2875 global treediff parents treepending env
2882 global treediff parents treepending env
2876 set treepending $ids
2883 set treepending $ids
2877 set treediff {}
2884 set treediff {}
2878 set id [lindex $ids 0]
2885 set id [lindex $ids 0]
2879 set p [lindex $ids 1]
2886 set p [lindex $ids 1]
2880 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
2887 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
2881 fconfigure $gdtf -blocking 0
2888 fconfigure $gdtf -blocking 0
2882 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
2889 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
2883 }
2890 }
2884
2891
2885 proc gettreediffline {gdtf ids} {
2892 proc gettreediffline {gdtf ids} {
2886 global treediff treediffs treepending diffids diffmergeid
2893 global treediff treediffs treepending diffids diffmergeid
2887
2894
2888 set n [gets $gdtf line]
2895 set n [gets $gdtf line]
2889 if {$n < 0} {
2896 if {$n < 0} {
2890 if {![eof $gdtf]} return
2897 if {![eof $gdtf]} return
2891 close $gdtf
2898 close $gdtf
2892 set treediffs($ids) $treediff
2899 set treediffs($ids) $treediff
2893 unset treepending
2900 unset treepending
2894 if {$ids != $diffids} {
2901 if {$ids != $diffids} {
2895 gettreediffs $diffids
2902 gettreediffs $diffids
2896 } else {
2903 } else {
2897 if {[info exists diffmergeid]} {
2904 if {[info exists diffmergeid]} {
2898 contmergediff $ids
2905 contmergediff $ids
2899 } else {
2906 } else {
2900 addtocflist $ids
2907 addtocflist $ids
2901 }
2908 }
2902 }
2909 }
2903 return
2910 return
2904 }
2911 }
2905 set tab1 [expr [string first "\t" $line] + 1]
2912 set tab1 [expr [string first "\t" $line] + 1]
2906 set tab2 [expr [string first "\t" $line $tab1] - 1]
2913 set tab2 [expr [string first "\t" $line $tab1] - 1]
2907 set file [string range $line $tab1 $tab2]
2914 set file [string range $line $tab1 $tab2]
2908 lappend treediff $file
2915 lappend treediff $file
2909 }
2916 }
2910
2917
2911 proc getblobdiffs {ids} {
2918 proc getblobdiffs {ids} {
2912 global diffopts blobdifffd diffids env curdifftag curtagstart
2919 global diffopts blobdifffd diffids env curdifftag curtagstart
2913 global difffilestart nextupdate diffinhdr treediffs
2920 global difffilestart nextupdate diffinhdr treediffs
2914
2921
2915 set id [lindex $ids 0]
2922 set id [lindex $ids 0]
2916 set p [lindex $ids 1]
2923 set p [lindex $ids 1]
2917 set env(GIT_DIFF_OPTS) $diffopts
2924 set env(GIT_DIFF_OPTS) $diffopts
2918 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
2925 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
2919 if {[catch {set bdf [open $cmd r]} err]} {
2926 if {[catch {set bdf [open $cmd r]} err]} {
2920 puts "error getting diffs: $err"
2927 puts "error getting diffs: $err"
2921 return
2928 return
2922 }
2929 }
2923 set diffinhdr 0
2930 set diffinhdr 0
2924 fconfigure $bdf -blocking 0
2931 fconfigure $bdf -blocking 0
2925 set blobdifffd($ids) $bdf
2932 set blobdifffd($ids) $bdf
2926 set curdifftag Comments
2933 set curdifftag Comments
2927 set curtagstart 0.0
2934 set curtagstart 0.0
2928 catch {unset difffilestart}
2935 catch {unset difffilestart}
2929 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
2936 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
2930 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
2937 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
2931 }
2938 }
2932
2939
2933 proc getblobdiffline {bdf ids} {
2940 proc getblobdiffline {bdf ids} {
2934 global diffids blobdifffd ctext curdifftag curtagstart
2941 global diffids blobdifffd ctext curdifftag curtagstart
2935 global diffnexthead diffnextnote difffilestart
2942 global diffnexthead diffnextnote difffilestart
2936 global nextupdate diffinhdr treediffs
2943 global nextupdate diffinhdr treediffs
2937 global gaudydiff
2944 global gaudydiff
2938
2945
2939 set n [gets $bdf line]
2946 set n [gets $bdf line]
2940 if {$n < 0} {
2947 if {$n < 0} {
2941 if {[eof $bdf]} {
2948 if {[eof $bdf]} {
2942 close $bdf
2949 close $bdf
2943 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
2950 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
2944 $ctext tag add $curdifftag $curtagstart end
2951 $ctext tag add $curdifftag $curtagstart end
2945 }
2952 }
2946 }
2953 }
2947 return
2954 return
2948 }
2955 }
2949 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
2956 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
2950 return
2957 return
2951 }
2958 }
2952 regsub -all "\r" $line "" line
2959 regsub -all "\r" $line "" line
2953 $ctext conf -state normal
2960 $ctext conf -state normal
2954 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
2961 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
2955 # start of a new file
2962 # start of a new file
2956 $ctext insert end "\n"
2963 $ctext insert end "\n"
2957 $ctext tag add $curdifftag $curtagstart end
2964 $ctext tag add $curdifftag $curtagstart end
2958 set curtagstart [$ctext index "end - 1c"]
2965 set curtagstart [$ctext index "end - 1c"]
2959 set header $newname
2966 set header $newname
2960 set here [$ctext index "end - 1c"]
2967 set here [$ctext index "end - 1c"]
2961 set i [lsearch -exact $treediffs($diffids) $fname]
2968 set i [lsearch -exact $treediffs($diffids) $fname]
2962 if {$i >= 0} {
2969 if {$i >= 0} {
2963 set difffilestart($i) $here
2970 set difffilestart($i) $here
2964 incr i
2971 incr i
2965 $ctext mark set fmark.$i $here
2972 $ctext mark set fmark.$i $here
2966 $ctext mark gravity fmark.$i left
2973 $ctext mark gravity fmark.$i left
2967 }
2974 }
2968 if {$newname != $fname} {
2975 if {$newname != $fname} {
2969 set i [lsearch -exact $treediffs($diffids) $newname]
2976 set i [lsearch -exact $treediffs($diffids) $newname]
2970 if {$i >= 0} {
2977 if {$i >= 0} {
2971 set difffilestart($i) $here
2978 set difffilestart($i) $here
2972 incr i
2979 incr i
2973 $ctext mark set fmark.$i $here
2980 $ctext mark set fmark.$i $here
2974 $ctext mark gravity fmark.$i left
2981 $ctext mark gravity fmark.$i left
2975 }
2982 }
2976 }
2983 }
2977 set curdifftag "f:$fname"
2984 set curdifftag "f:$fname"
2978 $ctext tag delete $curdifftag
2985 $ctext tag delete $curdifftag
2979 set l [expr {(78 - [string length $header]) / 2}]
2986 set l [expr {(78 - [string length $header]) / 2}]
2980 set pad [string range "----------------------------------------" 1 $l]
2987 set pad [string range "----------------------------------------" 1 $l]
2981 $ctext insert end "$pad $header $pad\n" filesep
2988 $ctext insert end "$pad $header $pad\n" filesep
2982 set diffinhdr 1
2989 set diffinhdr 1
2983 } elseif {[regexp {^(---|\+\+\+)} $line]} {
2990 } elseif {[regexp {^(---|\+\+\+)} $line]} {
2984 set diffinhdr 0
2991 set diffinhdr 0
2985 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2992 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2986 $line match f1l f1c f2l f2c rest]} {
2993 $line match f1l f1c f2l f2c rest]} {
2987 if {$gaudydiff} {
2994 if {$gaudydiff} {
2988 $ctext insert end "\t" hunksep
2995 $ctext insert end "\t" hunksep
2989 $ctext insert end " $f1l " d0 " $f2l " d1
2996 $ctext insert end " $f1l " d0 " $f2l " d1
2990 $ctext insert end " $rest \n" hunksep
2997 $ctext insert end " $rest \n" hunksep
2991 } else {
2998 } else {
2992 $ctext insert end "$line\n" hunksep
2999 $ctext insert end "$line\n" hunksep
2993 }
3000 }
2994 set diffinhdr 0
3001 set diffinhdr 0
2995 } else {
3002 } else {
2996 set x [string range $line 0 0]
3003 set x [string range $line 0 0]
2997 if {$x == "-" || $x == "+"} {
3004 if {$x == "-" || $x == "+"} {
2998 set tag [expr {$x == "+"}]
3005 set tag [expr {$x == "+"}]
2999 if {$gaudydiff} {
3006 if {$gaudydiff} {
3000 set line [string range $line 1 end]
3007 set line [string range $line 1 end]
3001 }
3008 }
3002 $ctext insert end "$line\n" d$tag
3009 $ctext insert end "$line\n" d$tag
3003 } elseif {$x == " "} {
3010 } elseif {$x == " "} {
3004 if {$gaudydiff} {
3011 if {$gaudydiff} {
3005 set line [string range $line 1 end]
3012 set line [string range $line 1 end]
3006 }
3013 }
3007 $ctext insert end "$line\n"
3014 $ctext insert end "$line\n"
3008 } elseif {$diffinhdr || $x == "\\"} {
3015 } elseif {$diffinhdr || $x == "\\"} {
3009 # e.g. "\ No newline at end of file"
3016 # e.g. "\ No newline at end of file"
3010 $ctext insert end "$line\n" filesep
3017 $ctext insert end "$line\n" filesep
3011 } elseif {$line != ""} {
3018 } elseif {$line != ""} {
3012 # Something else we don't recognize
3019 # Something else we don't recognize
3013 if {$curdifftag != "Comments"} {
3020 if {$curdifftag != "Comments"} {
3014 $ctext insert end "\n"
3021 $ctext insert end "\n"
3015 $ctext tag add $curdifftag $curtagstart end
3022 $ctext tag add $curdifftag $curtagstart end
3016 set curtagstart [$ctext index "end - 1c"]
3023 set curtagstart [$ctext index "end - 1c"]
3017 set curdifftag Comments
3024 set curdifftag Comments
3018 }
3025 }
3019 $ctext insert end "$line\n" filesep
3026 $ctext insert end "$line\n" filesep
3020 }
3027 }
3021 }
3028 }
3022 $ctext conf -state disabled
3029 $ctext conf -state disabled
3023 if {[clock clicks -milliseconds] >= $nextupdate} {
3030 if {[clock clicks -milliseconds] >= $nextupdate} {
3024 incr nextupdate 100
3031 incr nextupdate 100
3025 fileevent $bdf readable {}
3032 fileevent $bdf readable {}
3026 update
3033 update
3027 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3034 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3028 }
3035 }
3029 }
3036 }
3030
3037
3031 proc nextfile {} {
3038 proc nextfile {} {
3032 global difffilestart ctext
3039 global difffilestart ctext
3033 set here [$ctext index @0,0]
3040 set here [$ctext index @0,0]
3034 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3041 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3035 if {[$ctext compare $difffilestart($i) > $here]} {
3042 if {[$ctext compare $difffilestart($i) > $here]} {
3036 if {![info exists pos]
3043 if {![info exists pos]
3037 || [$ctext compare $difffilestart($i) < $pos]} {
3044 || [$ctext compare $difffilestart($i) < $pos]} {
3038 set pos $difffilestart($i)
3045 set pos $difffilestart($i)
3039 }
3046 }
3040 }
3047 }
3041 }
3048 }
3042 if {[info exists pos]} {
3049 if {[info exists pos]} {
3043 $ctext yview $pos
3050 $ctext yview $pos
3044 }
3051 }
3045 }
3052 }
3046
3053
3047 proc listboxsel {} {
3054 proc listboxsel {} {
3048 global ctext cflist currentid
3055 global ctext cflist currentid
3049 if {![info exists currentid]} return
3056 if {![info exists currentid]} return
3050 set sel [lsort [$cflist curselection]]
3057 set sel [lsort [$cflist curselection]]
3051 if {$sel eq {}} return
3058 if {$sel eq {}} return
3052 set first [lindex $sel 0]
3059 set first [lindex $sel 0]
3053 catch {$ctext yview fmark.$first}
3060 catch {$ctext yview fmark.$first}
3054 }
3061 }
3055
3062
3056 proc setcoords {} {
3063 proc setcoords {} {
3057 global linespc charspc canvx0 canvy0 mainfont
3064 global linespc charspc canvx0 canvy0 mainfont
3058 global xspc1 xspc2 lthickness
3065 global xspc1 xspc2 lthickness
3059
3066
3060 set linespc [font metrics $mainfont -linespace]
3067 set linespc [font metrics $mainfont -linespace]
3061 set charspc [font measure $mainfont "m"]
3068 set charspc [font measure $mainfont "m"]
3062 set canvy0 [expr 3 + 0.5 * $linespc]
3069 set canvy0 [expr 3 + 0.5 * $linespc]
3063 set canvx0 [expr 3 + 0.5 * $linespc]
3070 set canvx0 [expr 3 + 0.5 * $linespc]
3064 set lthickness [expr {int($linespc / 9) + 1}]
3071 set lthickness [expr {int($linespc / 9) + 1}]
3065 set xspc1(0) $linespc
3072 set xspc1(0) $linespc
3066 set xspc2 $linespc
3073 set xspc2 $linespc
3067 }
3074 }
3068
3075
3069 proc redisplay {} {
3076 proc redisplay {} {
3070 global stopped redisplaying phase
3077 global stopped redisplaying phase
3071 if {$stopped > 1} return
3078 if {$stopped > 1} return
3072 if {$phase == "getcommits"} return
3079 if {$phase == "getcommits"} return
3073 set redisplaying 1
3080 set redisplaying 1
3074 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3081 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3075 set stopped 1
3082 set stopped 1
3076 } else {
3083 } else {
3077 drawgraph
3084 drawgraph
3078 }
3085 }
3079 }
3086 }
3080
3087
3081 proc incrfont {inc} {
3088 proc incrfont {inc} {
3082 global mainfont namefont textfont ctext canv phase
3089 global mainfont namefont textfont ctext canv phase
3083 global stopped entries
3090 global stopped entries
3084 unmarkmatches
3091 unmarkmatches
3085 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3092 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3086 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3093 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3087 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3094 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3088 setcoords
3095 setcoords
3089 $ctext conf -font $textfont
3096 $ctext conf -font $textfont
3090 $ctext tag conf filesep -font [concat $textfont bold]
3097 $ctext tag conf filesep -font [concat $textfont bold]
3091 foreach e $entries {
3098 foreach e $entries {
3092 $e conf -font $mainfont
3099 $e conf -font $mainfont
3093 }
3100 }
3094 if {$phase == "getcommits"} {
3101 if {$phase == "getcommits"} {
3095 $canv itemconf textitems -font $mainfont
3102 $canv itemconf textitems -font $mainfont
3096 }
3103 }
3097 redisplay
3104 redisplay
3098 }
3105 }
3099
3106
3100 proc clearsha1 {} {
3107 proc clearsha1 {} {
3101 global sha1entry sha1string
3108 global sha1entry sha1string
3102 if {[string length $sha1string] == 40} {
3109 if {[string length $sha1string] == 40} {
3103 $sha1entry delete 0 end
3110 $sha1entry delete 0 end
3104 }
3111 }
3105 }
3112 }
3106
3113
3107 proc sha1change {n1 n2 op} {
3114 proc sha1change {n1 n2 op} {
3108 global sha1string currentid sha1but
3115 global sha1string currentid sha1but
3109 if {$sha1string == {}
3116 if {$sha1string == {}
3110 || ([info exists currentid] && $sha1string == $currentid)} {
3117 || ([info exists currentid] && $sha1string == $currentid)} {
3111 set state disabled
3118 set state disabled
3112 } else {
3119 } else {
3113 set state normal
3120 set state normal
3114 }
3121 }
3115 if {[$sha1but cget -state] == $state} return
3122 if {[$sha1but cget -state] == $state} return
3116 if {$state == "normal"} {
3123 if {$state == "normal"} {
3117 $sha1but conf -state normal -relief raised -text "Goto: "
3124 $sha1but conf -state normal -relief raised -text "Goto: "
3118 } else {
3125 } else {
3119 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3126 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3120 }
3127 }
3121 }
3128 }
3122
3129
3123 proc gotocommit {} {
3130 proc gotocommit {} {
3124 global sha1string currentid idline tagids
3131 global sha1string currentid idline tagids
3125 global lineid numcommits
3132 global lineid numcommits
3126
3133
3127 if {$sha1string == {}
3134 if {$sha1string == {}
3128 || ([info exists currentid] && $sha1string == $currentid)} return
3135 || ([info exists currentid] && $sha1string == $currentid)} return
3129 if {[info exists tagids($sha1string)]} {
3136 if {[info exists tagids($sha1string)]} {
3130 set id $tagids($sha1string)
3137 set id $tagids($sha1string)
3131 } else {
3138 } else {
3132 set id [string tolower $sha1string]
3139 set id [string tolower $sha1string]
3133 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3140 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3134 set matches {}
3141 set matches {}
3135 for {set l 0} {$l < $numcommits} {incr l} {
3142 for {set l 0} {$l < $numcommits} {incr l} {
3136 if {[string match $id* $lineid($l)]} {
3143 if {[string match $id* $lineid($l)]} {
3137 lappend matches $lineid($l)
3144 lappend matches $lineid($l)
3138 }
3145 }
3139 }
3146 }
3140 if {$matches ne {}} {
3147 if {$matches ne {}} {
3141 if {[llength $matches] > 1} {
3148 if {[llength $matches] > 1} {
3142 error_popup "Short SHA1 id $id is ambiguous"
3149 error_popup "Short SHA1 id $id is ambiguous"
3143 return
3150 return
3144 }
3151 }
3145 set id [lindex $matches 0]
3152 set id [lindex $matches 0]
3146 }
3153 }
3147 }
3154 }
3148 }
3155 }
3149 if {[info exists idline($id)]} {
3156 if {[info exists idline($id)]} {
3150 selectline $idline($id) 1
3157 selectline $idline($id) 1
3151 return
3158 return
3152 }
3159 }
3153 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3160 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3154 set type "SHA1 id"
3161 set type "SHA1 id"
3155 } else {
3162 } else {
3156 set type "Tag"
3163 set type "Tag"
3157 }
3164 }
3158 error_popup "$type $sha1string is not known"
3165 error_popup "$type $sha1string is not known"
3159 }
3166 }
3160
3167
3161 proc lineenter {x y id} {
3168 proc lineenter {x y id} {
3162 global hoverx hovery hoverid hovertimer
3169 global hoverx hovery hoverid hovertimer
3163 global commitinfo canv
3170 global commitinfo canv
3164
3171
3165 if {![info exists commitinfo($id)]} return
3172 if {![info exists commitinfo($id)]} return
3166 set hoverx $x
3173 set hoverx $x
3167 set hovery $y
3174 set hovery $y
3168 set hoverid $id
3175 set hoverid $id
3169 if {[info exists hovertimer]} {
3176 if {[info exists hovertimer]} {
3170 after cancel $hovertimer
3177 after cancel $hovertimer
3171 }
3178 }
3172 set hovertimer [after 500 linehover]
3179 set hovertimer [after 500 linehover]
3173 $canv delete hover
3180 $canv delete hover
3174 }
3181 }
3175
3182
3176 proc linemotion {x y id} {
3183 proc linemotion {x y id} {
3177 global hoverx hovery hoverid hovertimer
3184 global hoverx hovery hoverid hovertimer
3178
3185
3179 if {[info exists hoverid] && $id == $hoverid} {
3186 if {[info exists hoverid] && $id == $hoverid} {
3180 set hoverx $x
3187 set hoverx $x
3181 set hovery $y
3188 set hovery $y
3182 if {[info exists hovertimer]} {
3189 if {[info exists hovertimer]} {
3183 after cancel $hovertimer
3190 after cancel $hovertimer
3184 }
3191 }
3185 set hovertimer [after 500 linehover]
3192 set hovertimer [after 500 linehover]
3186 }
3193 }
3187 }
3194 }
3188
3195
3189 proc lineleave {id} {
3196 proc lineleave {id} {
3190 global hoverid hovertimer canv
3197 global hoverid hovertimer canv
3191
3198
3192 if {[info exists hoverid] && $id == $hoverid} {
3199 if {[info exists hoverid] && $id == $hoverid} {
3193 $canv delete hover
3200 $canv delete hover
3194 if {[info exists hovertimer]} {
3201 if {[info exists hovertimer]} {
3195 after cancel $hovertimer
3202 after cancel $hovertimer
3196 unset hovertimer
3203 unset hovertimer
3197 }
3204 }
3198 unset hoverid
3205 unset hoverid
3199 }
3206 }
3200 }
3207 }
3201
3208
3202 proc linehover {} {
3209 proc linehover {} {
3203 global hoverx hovery hoverid hovertimer
3210 global hoverx hovery hoverid hovertimer
3204 global canv linespc lthickness
3211 global canv linespc lthickness
3205 global commitinfo mainfont
3212 global commitinfo mainfont
3206
3213
3207 set text [lindex $commitinfo($hoverid) 0]
3214 set text [lindex $commitinfo($hoverid) 0]
3208 set ymax [lindex [$canv cget -scrollregion] 3]
3215 set ymax [lindex [$canv cget -scrollregion] 3]
3209 if {$ymax == {}} return
3216 if {$ymax == {}} return
3210 set yfrac [lindex [$canv yview] 0]
3217 set yfrac [lindex [$canv yview] 0]
3211 set x [expr {$hoverx + 2 * $linespc}]
3218 set x [expr {$hoverx + 2 * $linespc}]
3212 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3219 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3213 set x0 [expr {$x - 2 * $lthickness}]
3220 set x0 [expr {$x - 2 * $lthickness}]
3214 set y0 [expr {$y - 2 * $lthickness}]
3221 set y0 [expr {$y - 2 * $lthickness}]
3215 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3222 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3216 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3223 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3217 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3224 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3218 -fill \#ffff80 -outline black -width 1 -tags hover]
3225 -fill \#ffff80 -outline black -width 1 -tags hover]
3219 $canv raise $t
3226 $canv raise $t
3220 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3227 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3221 $canv raise $t
3228 $canv raise $t
3222 }
3229 }
3223
3230
3224 proc clickisonarrow {id y} {
3231 proc clickisonarrow {id y} {
3225 global mainline mainlinearrow sidelines lthickness
3232 global mainline mainlinearrow sidelines lthickness
3226
3233
3227 set thresh [expr {2 * $lthickness + 6}]
3234 set thresh [expr {2 * $lthickness + 6}]
3228 if {[info exists mainline($id)]} {
3235 if {[info exists mainline($id)]} {
3229 if {$mainlinearrow($id) ne "none"} {
3236 if {$mainlinearrow($id) ne "none"} {
3230 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3237 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3231 return "up"
3238 return "up"
3232 }
3239 }
3233 }
3240 }
3234 }
3241 }
3235 if {[info exists sidelines($id)]} {
3242 if {[info exists sidelines($id)]} {
3236 foreach ls $sidelines($id) {
3243 foreach ls $sidelines($id) {
3237 set coords [lindex $ls 0]
3244 set coords [lindex $ls 0]
3238 set arrow [lindex $ls 2]
3245 set arrow [lindex $ls 2]
3239 if {$arrow eq "first" || $arrow eq "both"} {
3246 if {$arrow eq "first" || $arrow eq "both"} {
3240 if {abs([lindex $coords 1] - $y) < $thresh} {
3247 if {abs([lindex $coords 1] - $y) < $thresh} {
3241 return "up"
3248 return "up"
3242 }
3249 }
3243 }
3250 }
3244 if {$arrow eq "last" || $arrow eq "both"} {
3251 if {$arrow eq "last" || $arrow eq "both"} {
3245 if {abs([lindex $coords end] - $y) < $thresh} {
3252 if {abs([lindex $coords end] - $y) < $thresh} {
3246 return "down"
3253 return "down"
3247 }
3254 }
3248 }
3255 }
3249 }
3256 }
3250 }
3257 }
3251 return {}
3258 return {}
3252 }
3259 }
3253
3260
3254 proc arrowjump {id dirn y} {
3261 proc arrowjump {id dirn y} {
3255 global mainline sidelines canv
3262 global mainline sidelines canv
3256
3263
3257 set yt {}
3264 set yt {}
3258 if {$dirn eq "down"} {
3265 if {$dirn eq "down"} {
3259 if {[info exists mainline($id)]} {
3266 if {[info exists mainline($id)]} {
3260 set y1 [lindex $mainline($id) 1]
3267 set y1 [lindex $mainline($id) 1]
3261 if {$y1 > $y} {
3268 if {$y1 > $y} {
3262 set yt $y1
3269 set yt $y1
3263 }
3270 }
3264 }
3271 }
3265 if {[info exists sidelines($id)]} {
3272 if {[info exists sidelines($id)]} {
3266 foreach ls $sidelines($id) {
3273 foreach ls $sidelines($id) {
3267 set y1 [lindex $ls 0 1]
3274 set y1 [lindex $ls 0 1]
3268 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3275 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3269 set yt $y1
3276 set yt $y1
3270 }
3277 }
3271 }
3278 }
3272 }
3279 }
3273 } else {
3280 } else {
3274 if {[info exists sidelines($id)]} {
3281 if {[info exists sidelines($id)]} {
3275 foreach ls $sidelines($id) {
3282 foreach ls $sidelines($id) {
3276 set y1 [lindex $ls 0 end]
3283 set y1 [lindex $ls 0 end]
3277 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3284 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3278 set yt $y1
3285 set yt $y1
3279 }
3286 }
3280 }
3287 }
3281 }
3288 }
3282 }
3289 }
3283 if {$yt eq {}} return
3290 if {$yt eq {}} return
3284 set ymax [lindex [$canv cget -scrollregion] 3]
3291 set ymax [lindex [$canv cget -scrollregion] 3]
3285 if {$ymax eq {} || $ymax <= 0} return
3292 if {$ymax eq {} || $ymax <= 0} return
3286 set view [$canv yview]
3293 set view [$canv yview]
3287 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3294 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3288 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3295 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3289 if {$yfrac < 0} {
3296 if {$yfrac < 0} {
3290 set yfrac 0
3297 set yfrac 0
3291 }
3298 }
3292 $canv yview moveto $yfrac
3299 $canv yview moveto $yfrac
3293 }
3300 }
3294
3301
3295 proc lineclick {x y id isnew} {
3302 proc lineclick {x y id isnew} {
3296 global ctext commitinfo children cflist canv thickerline
3303 global ctext commitinfo children cflist canv thickerline
3297
3304
3298 unmarkmatches
3305 unmarkmatches
3299 unselectline
3306 unselectline
3300 normalline
3307 normalline
3301 $canv delete hover
3308 $canv delete hover
3302 # draw this line thicker than normal
3309 # draw this line thicker than normal
3303 drawlines $id 1
3310 drawlines $id 1
3304 set thickerline $id
3311 set thickerline $id
3305 if {$isnew} {
3312 if {$isnew} {
3306 set ymax [lindex [$canv cget -scrollregion] 3]
3313 set ymax [lindex [$canv cget -scrollregion] 3]
3307 if {$ymax eq {}} return
3314 if {$ymax eq {}} return
3308 set yfrac [lindex [$canv yview] 0]
3315 set yfrac [lindex [$canv yview] 0]
3309 set y [expr {$y + $yfrac * $ymax}]
3316 set y [expr {$y + $yfrac * $ymax}]
3310 }
3317 }
3311 set dirn [clickisonarrow $id $y]
3318 set dirn [clickisonarrow $id $y]
3312 if {$dirn ne {}} {
3319 if {$dirn ne {}} {
3313 arrowjump $id $dirn $y
3320 arrowjump $id $dirn $y
3314 return
3321 return
3315 }
3322 }
3316
3323
3317 if {$isnew} {
3324 if {$isnew} {
3318 addtohistory [list lineclick $x $y $id 0]
3325 addtohistory [list lineclick $x $y $id 0]
3319 }
3326 }
3320 # fill the details pane with info about this line
3327 # fill the details pane with info about this line
3321 $ctext conf -state normal
3328 $ctext conf -state normal
3322 $ctext delete 0.0 end
3329 $ctext delete 0.0 end
3323 $ctext tag conf link -foreground blue -underline 1
3330 $ctext tag conf link -foreground blue -underline 1
3324 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3331 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3325 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3332 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3326 $ctext insert end "Parent:\t"
3333 $ctext insert end "Parent:\t"
3327 $ctext insert end $id [list link link0]
3334 $ctext insert end $id [list link link0]
3328 $ctext tag bind link0 <1> [list selbyid $id]
3335 $ctext tag bind link0 <1> [list selbyid $id]
3329 set info $commitinfo($id)
3336 set info $commitinfo($id)
3330 $ctext insert end "\n\t[lindex $info 0]\n"
3337 $ctext insert end "\n\t[lindex $info 0]\n"
3331 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
3338 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
3332 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3339 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3333 if {[info exists children($id)]} {
3340 if {[info exists children($id)]} {
3334 $ctext insert end "\nChildren:"
3341 $ctext insert end "\nChildren:"
3335 set i 0
3342 set i 0
3336 foreach child $children($id) {
3343 foreach child $children($id) {
3337 incr i
3344 incr i
3338 set info $commitinfo($child)
3345 set info $commitinfo($child)
3339 $ctext insert end "\n\t"
3346 $ctext insert end "\n\t"
3340 $ctext insert end $child [list link link$i]
3347 $ctext insert end $child [list link link$i]
3341 $ctext tag bind link$i <1> [list selbyid $child]
3348 $ctext tag bind link$i <1> [list selbyid $child]
3342 $ctext insert end "\n\t[lindex $info 0]"
3349 $ctext insert end "\n\t[lindex $info 0]"
3343 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
3350 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
3344 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3351 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3345 }
3352 }
3346 }
3353 }
3347 $ctext conf -state disabled
3354 $ctext conf -state disabled
3348
3355
3349 $cflist delete 0 end
3356 $cflist delete 0 end
3350 }
3357 }
3351
3358
3352 proc normalline {} {
3359 proc normalline {} {
3353 global thickerline
3360 global thickerline
3354 if {[info exists thickerline]} {
3361 if {[info exists thickerline]} {
3355 drawlines $thickerline 0
3362 drawlines $thickerline 0
3356 unset thickerline
3363 unset thickerline
3357 }
3364 }
3358 }
3365 }
3359
3366
3360 proc selbyid {id} {
3367 proc selbyid {id} {
3361 global idline
3368 global idline
3362 if {[info exists idline($id)]} {
3369 if {[info exists idline($id)]} {
3363 selectline $idline($id) 1
3370 selectline $idline($id) 1
3364 }
3371 }
3365 }
3372 }
3366
3373
3367 proc mstime {} {
3374 proc mstime {} {
3368 global startmstime
3375 global startmstime
3369 if {![info exists startmstime]} {
3376 if {![info exists startmstime]} {
3370 set startmstime [clock clicks -milliseconds]
3377 set startmstime [clock clicks -milliseconds]
3371 }
3378 }
3372 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3379 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3373 }
3380 }
3374
3381
3375 proc rowmenu {x y id} {
3382 proc rowmenu {x y id} {
3376 global rowctxmenu idline selectedline rowmenuid
3383 global rowctxmenu idline selectedline rowmenuid hgvdiff
3377
3384
3378 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3385 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3379 set state disabled
3386 set state disabled
3380 } else {
3387 } else {
3381 set state normal
3388 set state normal
3382 }
3389 }
3383 $rowctxmenu entryconfigure 0 -state $state
3390 $rowctxmenu entryconfigure 0 -state $state
3384 $rowctxmenu entryconfigure 1 -state $state
3391 $rowctxmenu entryconfigure 1 -state $state
3385 $rowctxmenu entryconfigure 2 -state $state
3392 $rowctxmenu entryconfigure 2 -state $state
3393 if { $hgvdiff ne "" } {
3394 $rowctxmenu entryconfigure 6 -state $state
3395 }
3386 set rowmenuid $id
3396 set rowmenuid $id
3387 tk_popup $rowctxmenu $x $y
3397 tk_popup $rowctxmenu $x $y
3388 }
3398 }
3389
3399
3390 proc diffvssel {dirn} {
3400 proc diffvssel {dirn} {
3391 global rowmenuid selectedline lineid
3401 global rowmenuid selectedline lineid
3392
3402
3393 if {![info exists selectedline]} return
3403 if {![info exists selectedline]} return
3394 if {$dirn} {
3404 if {$dirn} {
3395 set oldid $lineid($selectedline)
3405 set oldid $lineid($selectedline)
3396 set newid $rowmenuid
3406 set newid $rowmenuid
3397 } else {
3407 } else {
3398 set oldid $rowmenuid
3408 set oldid $rowmenuid
3399 set newid $lineid($selectedline)
3409 set newid $lineid($selectedline)
3400 }
3410 }
3401 addtohistory [list doseldiff $oldid $newid]
3411 addtohistory [list doseldiff $oldid $newid]
3402 doseldiff $oldid $newid
3412 doseldiff $oldid $newid
3403 }
3413 }
3404
3414
3405 proc doseldiff {oldid newid} {
3415 proc doseldiff {oldid newid} {
3406 global ctext cflist
3416 global ctext cflist
3407 global commitinfo
3417 global commitinfo
3408
3418
3409 $ctext conf -state normal
3419 $ctext conf -state normal
3410 $ctext delete 0.0 end
3420 $ctext delete 0.0 end
3411 $ctext mark set fmark.0 0.0
3421 $ctext mark set fmark.0 0.0
3412 $ctext mark gravity fmark.0 left
3422 $ctext mark gravity fmark.0 left
3413 $cflist delete 0 end
3423 $cflist delete 0 end
3414 $cflist insert end "Top"
3424 $cflist insert end "Top"
3415 $ctext insert end "From "
3425 $ctext insert end "From "
3416 $ctext tag conf link -foreground blue -underline 1
3426 $ctext tag conf link -foreground blue -underline 1
3417 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3427 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3418 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3428 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3419 $ctext tag bind link0 <1> [list selbyid $oldid]
3429 $ctext tag bind link0 <1> [list selbyid $oldid]
3420 $ctext insert end $oldid [list link link0]
3430 $ctext insert end $oldid [list link link0]
3421 $ctext insert end "\n "
3431 $ctext insert end "\n "
3422 $ctext insert end [lindex $commitinfo($oldid) 0]
3432 $ctext insert end [lindex $commitinfo($oldid) 0]
3423 $ctext insert end "\n\nTo "
3433 $ctext insert end "\n\nTo "
3424 $ctext tag bind link1 <1> [list selbyid $newid]
3434 $ctext tag bind link1 <1> [list selbyid $newid]
3425 $ctext insert end $newid [list link link1]
3435 $ctext insert end $newid [list link link1]
3426 $ctext insert end "\n "
3436 $ctext insert end "\n "
3427 $ctext insert end [lindex $commitinfo($newid) 0]
3437 $ctext insert end [lindex $commitinfo($newid) 0]
3428 $ctext insert end "\n"
3438 $ctext insert end "\n"
3429 $ctext conf -state disabled
3439 $ctext conf -state disabled
3430 $ctext tag delete Comments
3440 $ctext tag delete Comments
3431 $ctext tag remove found 1.0 end
3441 $ctext tag remove found 1.0 end
3432 startdiff [list $newid $oldid]
3442 startdiff [list $newid $oldid]
3433 }
3443 }
3434
3444
3435 proc mkpatch {} {
3445 proc mkpatch {} {
3436 global rowmenuid currentid commitinfo patchtop patchnum
3446 global rowmenuid currentid commitinfo patchtop patchnum
3437
3447
3438 if {![info exists currentid]} return
3448 if {![info exists currentid]} return
3439 set oldid $currentid
3449 set oldid $currentid
3440 set oldhead [lindex $commitinfo($oldid) 0]
3450 set oldhead [lindex $commitinfo($oldid) 0]
3441 set newid $rowmenuid
3451 set newid $rowmenuid
3442 set newhead [lindex $commitinfo($newid) 0]
3452 set newhead [lindex $commitinfo($newid) 0]
3443 set top .patch
3453 set top .patch
3444 set patchtop $top
3454 set patchtop $top
3445 catch {destroy $top}
3455 catch {destroy $top}
3446 toplevel $top
3456 toplevel $top
3447 label $top.title -text "Generate patch"
3457 label $top.title -text "Generate patch"
3448 grid $top.title - -pady 10
3458 grid $top.title - -pady 10
3449 label $top.from -text "From:"
3459 label $top.from -text "From:"
3450 entry $top.fromsha1 -width 40 -relief flat
3460 entry $top.fromsha1 -width 40 -relief flat
3451 $top.fromsha1 insert 0 $oldid
3461 $top.fromsha1 insert 0 $oldid
3452 $top.fromsha1 conf -state readonly
3462 $top.fromsha1 conf -state readonly
3453 grid $top.from $top.fromsha1 -sticky w
3463 grid $top.from $top.fromsha1 -sticky w
3454 entry $top.fromhead -width 60 -relief flat
3464 entry $top.fromhead -width 60 -relief flat
3455 $top.fromhead insert 0 $oldhead
3465 $top.fromhead insert 0 $oldhead
3456 $top.fromhead conf -state readonly
3466 $top.fromhead conf -state readonly
3457 grid x $top.fromhead -sticky w
3467 grid x $top.fromhead -sticky w
3458 label $top.to -text "To:"
3468 label $top.to -text "To:"
3459 entry $top.tosha1 -width 40 -relief flat
3469 entry $top.tosha1 -width 40 -relief flat
3460 $top.tosha1 insert 0 $newid
3470 $top.tosha1 insert 0 $newid
3461 $top.tosha1 conf -state readonly
3471 $top.tosha1 conf -state readonly
3462 grid $top.to $top.tosha1 -sticky w
3472 grid $top.to $top.tosha1 -sticky w
3463 entry $top.tohead -width 60 -relief flat
3473 entry $top.tohead -width 60 -relief flat
3464 $top.tohead insert 0 $newhead
3474 $top.tohead insert 0 $newhead
3465 $top.tohead conf -state readonly
3475 $top.tohead conf -state readonly
3466 grid x $top.tohead -sticky w
3476 grid x $top.tohead -sticky w
3467 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
3477 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
3468 grid $top.rev x -pady 10
3478 grid $top.rev x -pady 10
3469 label $top.flab -text "Output file:"
3479 label $top.flab -text "Output file:"
3470 entry $top.fname -width 60
3480 entry $top.fname -width 60
3471 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3481 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3472 incr patchnum
3482 incr patchnum
3473 grid $top.flab $top.fname -sticky w
3483 grid $top.flab $top.fname -sticky w
3474 frame $top.buts
3484 frame $top.buts
3475 button $top.buts.gen -text "Generate" -command mkpatchgo
3485 button $top.buts.gen -text "Generate" -command mkpatchgo
3476 button $top.buts.can -text "Cancel" -command mkpatchcan
3486 button $top.buts.can -text "Cancel" -command mkpatchcan
3477 grid $top.buts.gen $top.buts.can
3487 grid $top.buts.gen $top.buts.can
3478 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3488 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3479 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3489 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3480 grid $top.buts - -pady 10 -sticky ew
3490 grid $top.buts - -pady 10 -sticky ew
3481 focus $top.fname
3491 focus $top.fname
3482 }
3492 }
3483
3493
3484 proc mkpatchrev {} {
3494 proc mkpatchrev {} {
3485 global patchtop
3495 global patchtop
3486
3496
3487 set oldid [$patchtop.fromsha1 get]
3497 set oldid [$patchtop.fromsha1 get]
3488 set oldhead [$patchtop.fromhead get]
3498 set oldhead [$patchtop.fromhead get]
3489 set newid [$patchtop.tosha1 get]
3499 set newid [$patchtop.tosha1 get]
3490 set newhead [$patchtop.tohead get]
3500 set newhead [$patchtop.tohead get]
3491 foreach e [list fromsha1 fromhead tosha1 tohead] \
3501 foreach e [list fromsha1 fromhead tosha1 tohead] \
3492 v [list $newid $newhead $oldid $oldhead] {
3502 v [list $newid $newhead $oldid $oldhead] {
3493 $patchtop.$e conf -state normal
3503 $patchtop.$e conf -state normal
3494 $patchtop.$e delete 0 end
3504 $patchtop.$e delete 0 end
3495 $patchtop.$e insert 0 $v
3505 $patchtop.$e insert 0 $v
3496 $patchtop.$e conf -state readonly
3506 $patchtop.$e conf -state readonly
3497 }
3507 }
3498 }
3508 }
3499
3509
3500 proc mkpatchgo {} {
3510 proc mkpatchgo {} {
3501 global patchtop env
3511 global patchtop env
3502
3512
3503 set oldid [$patchtop.fromsha1 get]
3513 set oldid [$patchtop.fromsha1 get]
3504 set newid [$patchtop.tosha1 get]
3514 set newid [$patchtop.tosha1 get]
3505 set fname [$patchtop.fname get]
3515 set fname [$patchtop.fname get]
3506 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3516 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3507 error_popup "Error creating patch: $err"
3517 error_popup "Error creating patch: $err"
3508 }
3518 }
3509 catch {destroy $patchtop}
3519 catch {destroy $patchtop}
3510 unset patchtop
3520 unset patchtop
3511 }
3521 }
3512
3522
3513 proc mkpatchcan {} {
3523 proc mkpatchcan {} {
3514 global patchtop
3524 global patchtop
3515
3525
3516 catch {destroy $patchtop}
3526 catch {destroy $patchtop}
3517 unset patchtop
3527 unset patchtop
3518 }
3528 }
3519
3529
3520 proc mktag {} {
3530 proc mktag {} {
3521 global rowmenuid mktagtop commitinfo
3531 global rowmenuid mktagtop commitinfo
3522
3532
3523 set top .maketag
3533 set top .maketag
3524 set mktagtop $top
3534 set mktagtop $top
3525 catch {destroy $top}
3535 catch {destroy $top}
3526 toplevel $top
3536 toplevel $top
3527 label $top.title -text "Create tag"
3537 label $top.title -text "Create tag"
3528 grid $top.title - -pady 10
3538 grid $top.title - -pady 10
3529 label $top.id -text "ID:"
3539 label $top.id -text "ID:"
3530 entry $top.sha1 -width 40 -relief flat
3540 entry $top.sha1 -width 40 -relief flat
3531 $top.sha1 insert 0 $rowmenuid
3541 $top.sha1 insert 0 $rowmenuid
3532 $top.sha1 conf -state readonly
3542 $top.sha1 conf -state readonly
3533 grid $top.id $top.sha1 -sticky w
3543 grid $top.id $top.sha1 -sticky w
3534 entry $top.head -width 60 -relief flat
3544 entry $top.head -width 60 -relief flat
3535 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3545 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3536 $top.head conf -state readonly
3546 $top.head conf -state readonly
3537 grid x $top.head -sticky w
3547 grid x $top.head -sticky w
3538 label $top.tlab -text "Tag name:"
3548 label $top.tlab -text "Tag name:"
3539 entry $top.tag -width 60
3549 entry $top.tag -width 60
3540 grid $top.tlab $top.tag -sticky w
3550 grid $top.tlab $top.tag -sticky w
3541 frame $top.buts
3551 frame $top.buts
3542 button $top.buts.gen -text "Create" -command mktaggo
3552 button $top.buts.gen -text "Create" -command mktaggo
3543 button $top.buts.can -text "Cancel" -command mktagcan
3553 button $top.buts.can -text "Cancel" -command mktagcan
3544 grid $top.buts.gen $top.buts.can
3554 grid $top.buts.gen $top.buts.can
3545 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3555 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3546 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3556 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3547 grid $top.buts - -pady 10 -sticky ew
3557 grid $top.buts - -pady 10 -sticky ew
3548 focus $top.tag
3558 focus $top.tag
3549 }
3559 }
3550
3560
3551 proc domktag {} {
3561 proc domktag {} {
3552 global mktagtop env tagids idtags
3562 global mktagtop env tagids idtags
3553
3563
3554 set id [$mktagtop.sha1 get]
3564 set id [$mktagtop.sha1 get]
3555 set tag [$mktagtop.tag get]
3565 set tag [$mktagtop.tag get]
3556 if {$tag == {}} {
3566 if {$tag == {}} {
3557 error_popup "No tag name specified"
3567 error_popup "No tag name specified"
3558 return
3568 return
3559 }
3569 }
3560 if {[info exists tagids($tag)]} {
3570 if {[info exists tagids($tag)]} {
3561 error_popup "Tag \"$tag\" already exists"
3571 error_popup "Tag \"$tag\" already exists"
3562 return
3572 return
3563 }
3573 }
3564 if {[catch {
3574 if {[catch {
3565 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3575 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3566 } err]} {
3576 } err]} {
3567 error_popup "Error creating tag: $err"
3577 error_popup "Error creating tag: $err"
3568 return
3578 return
3569 }
3579 }
3570
3580
3571 set tagids($tag) $id
3581 set tagids($tag) $id
3572 lappend idtags($id) $tag
3582 lappend idtags($id) $tag
3573 redrawtags $id
3583 redrawtags $id
3574 }
3584 }
3575
3585
3576 proc redrawtags {id} {
3586 proc redrawtags {id} {
3577 global canv linehtag idline idpos selectedline
3587 global canv linehtag idline idpos selectedline
3578
3588
3579 if {![info exists idline($id)]} return
3589 if {![info exists idline($id)]} return
3580 $canv delete tag.$id
3590 $canv delete tag.$id
3581 set xt [eval drawtags $id $idpos($id)]
3591 set xt [eval drawtags $id $idpos($id)]
3582 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3592 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3583 if {[info exists selectedline] && $selectedline == $idline($id)} {
3593 if {[info exists selectedline] && $selectedline == $idline($id)} {
3584 selectline $selectedline 0
3594 selectline $selectedline 0
3585 }
3595 }
3586 }
3596 }
3587
3597
3588 proc mktagcan {} {
3598 proc mktagcan {} {
3589 global mktagtop
3599 global mktagtop
3590
3600
3591 catch {destroy $mktagtop}
3601 catch {destroy $mktagtop}
3592 unset mktagtop
3602 unset mktagtop
3593 }
3603 }
3594
3604
3595 proc mktaggo {} {
3605 proc mktaggo {} {
3596 domktag
3606 domktag
3597 mktagcan
3607 mktagcan
3598 }
3608 }
3599
3609
3600 proc writecommit {} {
3610 proc writecommit {} {
3601 global rowmenuid wrcomtop commitinfo wrcomcmd
3611 global rowmenuid wrcomtop commitinfo wrcomcmd
3602
3612
3603 set top .writecommit
3613 set top .writecommit
3604 set wrcomtop $top
3614 set wrcomtop $top
3605 catch {destroy $top}
3615 catch {destroy $top}
3606 toplevel $top
3616 toplevel $top
3607 label $top.title -text "Write commit to file"
3617 label $top.title -text "Write commit to file"
3608 grid $top.title - -pady 10
3618 grid $top.title - -pady 10
3609 label $top.id -text "ID:"
3619 label $top.id -text "ID:"
3610 entry $top.sha1 -width 40 -relief flat
3620 entry $top.sha1 -width 40 -relief flat
3611 $top.sha1 insert 0 $rowmenuid
3621 $top.sha1 insert 0 $rowmenuid
3612 $top.sha1 conf -state readonly
3622 $top.sha1 conf -state readonly
3613 grid $top.id $top.sha1 -sticky w
3623 grid $top.id $top.sha1 -sticky w
3614 entry $top.head -width 60 -relief flat
3624 entry $top.head -width 60 -relief flat
3615 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3625 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3616 $top.head conf -state readonly
3626 $top.head conf -state readonly
3617 grid x $top.head -sticky w
3627 grid x $top.head -sticky w
3618 label $top.clab -text "Command:"
3628 label $top.clab -text "Command:"
3619 entry $top.cmd -width 60 -textvariable wrcomcmd
3629 entry $top.cmd -width 60 -textvariable wrcomcmd
3620 grid $top.clab $top.cmd -sticky w -pady 10
3630 grid $top.clab $top.cmd -sticky w -pady 10
3621 label $top.flab -text "Output file:"
3631 label $top.flab -text "Output file:"
3622 entry $top.fname -width 60
3632 entry $top.fname -width 60
3623 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3633 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3624 grid $top.flab $top.fname -sticky w
3634 grid $top.flab $top.fname -sticky w
3625 frame $top.buts
3635 frame $top.buts
3626 button $top.buts.gen -text "Write" -command wrcomgo
3636 button $top.buts.gen -text "Write" -command wrcomgo
3627 button $top.buts.can -text "Cancel" -command wrcomcan
3637 button $top.buts.can -text "Cancel" -command wrcomcan
3628 grid $top.buts.gen $top.buts.can
3638 grid $top.buts.gen $top.buts.can
3629 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3639 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3630 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3640 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3631 grid $top.buts - -pady 10 -sticky ew
3641 grid $top.buts - -pady 10 -sticky ew
3632 focus $top.fname
3642 focus $top.fname
3633 }
3643 }
3634
3644
3635 proc wrcomgo {} {
3645 proc wrcomgo {} {
3636 global wrcomtop
3646 global wrcomtop
3637
3647
3638 set id [$wrcomtop.sha1 get]
3648 set id [$wrcomtop.sha1 get]
3639 set cmd "echo $id | [$wrcomtop.cmd get]"
3649 set cmd "echo $id | [$wrcomtop.cmd get]"
3640 set fname [$wrcomtop.fname get]
3650 set fname [$wrcomtop.fname get]
3641 if {[catch {exec sh -c $cmd > $fname &} err]} {
3651 if {[catch {exec sh -c $cmd > $fname &} err]} {
3642 error_popup "Error writing commit: $err"
3652 error_popup "Error writing commit: $err"
3643 }
3653 }
3644 catch {destroy $wrcomtop}
3654 catch {destroy $wrcomtop}
3645 unset wrcomtop
3655 unset wrcomtop
3646 }
3656 }
3647
3657
3648 proc wrcomcan {} {
3658 proc wrcomcan {} {
3649 global wrcomtop
3659 global wrcomtop
3650
3660
3651 catch {destroy $wrcomtop}
3661 catch {destroy $wrcomtop}
3652 unset wrcomtop
3662 unset wrcomtop
3653 }
3663 }
3654
3664
3655 proc listrefs {id} {
3665 proc listrefs {id} {
3656 global idtags idheads idotherrefs
3666 global idtags idheads idotherrefs
3657
3667
3658 set x {}
3668 set x {}
3659 if {[info exists idtags($id)]} {
3669 if {[info exists idtags($id)]} {
3660 set x $idtags($id)
3670 set x $idtags($id)
3661 }
3671 }
3662 set y {}
3672 set y {}
3663 if {[info exists idheads($id)]} {
3673 if {[info exists idheads($id)]} {
3664 set y $idheads($id)
3674 set y $idheads($id)
3665 }
3675 }
3666 set z {}
3676 set z {}
3667 if {[info exists idotherrefs($id)]} {
3677 if {[info exists idotherrefs($id)]} {
3668 set z $idotherrefs($id)
3678 set z $idotherrefs($id)
3669 }
3679 }
3670 return [list $x $y $z]
3680 return [list $x $y $z]
3671 }
3681 }
3672
3682
3673 proc rereadrefs {} {
3683 proc rereadrefs {} {
3674 global idtags idheads idotherrefs
3684 global idtags idheads idotherrefs
3675 global tagids headids otherrefids
3685 global tagids headids otherrefids
3676
3686
3677 set refids [concat [array names idtags] \
3687 set refids [concat [array names idtags] \
3678 [array names idheads] [array names idotherrefs]]
3688 [array names idheads] [array names idotherrefs]]
3679 foreach id $refids {
3689 foreach id $refids {
3680 if {![info exists ref($id)]} {
3690 if {![info exists ref($id)]} {
3681 set ref($id) [listrefs $id]
3691 set ref($id) [listrefs $id]
3682 }
3692 }
3683 }
3693 }
3684 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
3694 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
3685 catch {unset $v}
3695 catch {unset $v}
3686 }
3696 }
3687 readrefs
3697 readrefs
3688 set refids [lsort -unique [concat $refids [array names idtags] \
3698 set refids [lsort -unique [concat $refids [array names idtags] \
3689 [array names idheads] [array names idotherrefs]]]
3699 [array names idheads] [array names idotherrefs]]]
3690 foreach id $refids {
3700 foreach id $refids {
3691 set v [listrefs $id]
3701 set v [listrefs $id]
3692 if {![info exists ref($id)] || $ref($id) != $v} {
3702 if {![info exists ref($id)] || $ref($id) != $v} {
3693 redrawtags $id
3703 redrawtags $id
3694 }
3704 }
3695 }
3705 }
3696 }
3706 }
3697
3707
3708 proc vdiff {withparent} {
3709 global env rowmenuid selectedline lineid
3710
3711 if {![info exists rowmenuid]} return
3712 set curid $rowmenuid
3713
3714 if {$withparent} {
3715 set parents [exec $env(HG) --config ui.report_untrusted=false parents --rev $curid --template "{node}\n"]
3716 set firstparent [lindex [split $parents "\n"] 0]
3717 set otherid $firstparent
3718 } else {
3719 if {![info exists selectedline]} return
3720 set otherid $lineid($selectedline)
3721 }
3722 set range "$otherid:$curid"
3723 if {[catch {exec $env(HG) --config ui.report_untrusted=false vdiff -r $range} err]} {
3724 # Ignore errors, this is just visualization
3725 }
3726 }
3727
3698 proc showtag {tag isnew} {
3728 proc showtag {tag isnew} {
3699 global ctext cflist tagcontents tagids linknum
3729 global ctext cflist tagcontents tagids linknum
3700
3730
3701 if {$isnew} {
3731 if {$isnew} {
3702 addtohistory [list showtag $tag 0]
3732 addtohistory [list showtag $tag 0]
3703 }
3733 }
3704 $ctext conf -state normal
3734 $ctext conf -state normal
3705 $ctext delete 0.0 end
3735 $ctext delete 0.0 end
3706 set linknum 0
3736 set linknum 0
3707 if {[info exists tagcontents($tag)]} {
3737 if {[info exists tagcontents($tag)]} {
3708 set text $tagcontents($tag)
3738 set text $tagcontents($tag)
3709 } else {
3739 } else {
3710 set text "Tag: $tag\nId: $tagids($tag)"
3740 set text "Tag: $tag\nId: $tagids($tag)"
3711 }
3741 }
3712 appendwithlinks $text
3742 appendwithlinks $text
3713 $ctext conf -state disabled
3743 $ctext conf -state disabled
3714 $cflist delete 0 end
3744 $cflist delete 0 end
3715 }
3745 }
3716
3746
3717 proc doquit {} {
3747 proc doquit {} {
3718 global stopped
3748 global stopped
3719 set stopped 100
3749 set stopped 100
3720 destroy .
3750 destroy .
3721 }
3751 }
3722
3752
3723 proc getconfig {} {
3753 proc getconfig {} {
3724 global env
3754 global env
3725
3755
3726 set lines [exec $env(HG) debug-config]
3756 set lines [exec $env(HG) debug-config]
3727 regsub -all "\r\n" $lines "\n" config
3757 regsub -all "\r\n" $lines "\n" config
3728 set config {}
3758 set config {}
3729 foreach line [split $lines "\n"] {
3759 foreach line [split $lines "\n"] {
3730 regsub "^(k|v)=" $line "" line
3760 regsub "^(k|v)=" $line "" line
3731 lappend config $line
3761 lappend config $line
3732 }
3762 }
3733 return $config
3763 return $config
3734 }
3764 }
3735
3765
3736 # defaults...
3766 # defaults...
3737 set datemode 0
3767 set datemode 0
3738 set boldnames 0
3768 set boldnames 0
3739 set diffopts "-U 5 -p"
3769 set diffopts "-U 5 -p"
3740 set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty"
3770 set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty"
3741
3771
3742 set mainfont {Helvetica 9}
3772 set mainfont {Helvetica 9}
3743 set textfont {Courier 9}
3773 set textfont {Courier 9}
3744 set findmergefiles 0
3774 set findmergefiles 0
3745 set gaudydiff 0
3775 set gaudydiff 0
3746 set maxgraphpct 50
3776 set maxgraphpct 50
3747 set maxwidth 16
3777 set maxwidth 16
3748
3778
3749 set colors {green red blue magenta darkgrey brown orange}
3779 set colors {green red blue magenta darkgrey brown orange}
3750
3780
3751 catch {source ~/.gitk}
3781 catch {source ~/.gitk}
3752
3782
3753 set namefont $mainfont
3783 set namefont $mainfont
3754 if {$boldnames} {
3784 if {$boldnames} {
3755 lappend namefont bold
3785 lappend namefont bold
3756 }
3786 }
3757
3787
3758 set revtreeargs {}
3788 set revtreeargs {}
3759 foreach arg $argv {
3789 foreach arg $argv {
3760 switch -regexp -- $arg {
3790 switch -regexp -- $arg {
3761 "^$" { }
3791 "^$" { }
3762 "^-b" { set boldnames 1 }
3792 "^-b" { set boldnames 1 }
3763 "^-d" { set datemode 1 }
3793 "^-d" { set datemode 1 }
3764 default {
3794 default {
3765 lappend revtreeargs $arg
3795 lappend revtreeargs $arg
3766 }
3796 }
3767 }
3797 }
3768 }
3798 }
3769
3799
3770 set history {}
3800 set history {}
3771 set historyindex 0
3801 set historyindex 0
3772
3802
3773 set stopped 0
3803 set stopped 0
3774 set redisplaying 0
3804 set redisplaying 0
3775 set stuffsaved 0
3805 set stuffsaved 0
3776 set patchnum 0
3806 set patchnum 0
3807
3808 array set config [getconfig]
3809 set hgvdiff $config(vdiff)
3777 setcoords
3810 setcoords
3778 makewindow
3811 makewindow
3779 readrefs
3812 readrefs
3780 set hgroot [exec $env(HG) root]
3813 set hgroot [exec $env(HG) root]
3781 wm title . "hgk $hgroot"
3814 wm title . "hgk $hgroot"
3782 getcommits $revtreeargs
3815 getcommits $revtreeargs
General Comments 0
You need to be logged in to leave comments. Login now