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