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