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