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