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