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