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