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