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