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