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