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