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