505
635
0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
506
636
0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
508
button .ctop.top.bar.leftbut -image bm-left -command goback \
509
-state disabled -width 26
510
pack .ctop.top.bar.leftbut -side left -fill y
511
button .ctop.top.bar.rightbut -image bm-right -command goforw \
512
-state disabled -width 26
513
pack .ctop.top.bar.rightbut -side left -fill y
638
button .tf.bar.leftbut -image bm-left -command goback \
639
-state disabled -width 26
640
pack .tf.bar.leftbut -side left -fill y
641
button .tf.bar.rightbut -image bm-right -command goforw \
642
-state disabled -width 26
643
pack .tf.bar.rightbut -side left -fill y
515
button .ctop.top.bar.findbut -text "Find" -command dofind -font $uifont
516
pack .ctop.top.bar.findbut -side left
645
button .tf.bar.findbut -text "Find" -command dofind -font $uifont
646
pack .tf.bar.findbut -side left
517
647
set findstring {}
518
set fstring .ctop.top.bar.findstring
648
set fstring .tf.bar.findstring
519
649
lappend entries $fstring
520
650
entry $fstring -width 30 -font $textfont -textvariable findstring
521
651
trace add variable findstring write find_change
522
pack $fstring -side left -expand 1 -fill x
652
pack $fstring -side left -expand 1 -fill x -in .tf.bar
523
653
set findtype Exact
524
set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
525
findtype Exact IgnCase Regexp]
654
set findtypemenu [tk_optionMenu .tf.bar.findtype \
655
findtype Exact IgnCase Regexp]
526
656
trace add variable findtype write find_change
527
.ctop.top.bar.findtype configure -font $uifont
528
.ctop.top.bar.findtype.menu configure -font $uifont
657
.tf.bar.findtype configure -font $uifont
658
.tf.bar.findtype.menu configure -font $uifont
529
659
set findloc "All fields"
530
tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
660
tk_optionMenu .tf.bar.findloc findloc "All fields" Headline \
531
661
Comments Author Committer
532
662
trace add variable findloc write find_change
533
.ctop.top.bar.findloc configure -font $uifont
534
.ctop.top.bar.findloc.menu configure -font $uifont
535
pack .ctop.top.bar.findloc -side right
536
pack .ctop.top.bar.findtype -side right
663
.tf.bar.findloc configure -font $uifont
664
.tf.bar.findloc.menu configure -font $uifont
665
pack .tf.bar.findloc -side right
666
pack .tf.bar.findtype -side right
538
label .ctop.top.lbar.flabel -text "Highlight: Commits " \
540
pack .ctop.top.lbar.flabel -side left -fill y
668
# build up the bottom bar of upper window
669
label .tf.lbar.flabel -text "Highlight: Commits " \
671
pack .tf.lbar.flabel -side left -fill y
541
672
set gdttype "touching paths:"
542
set gm [tk_optionMenu .ctop.top.lbar.gdttype gdttype "touching paths:" \
543
"adding/removing string:"]
673
set gm [tk_optionMenu .tf.lbar.gdttype gdttype "touching paths:" \
674
"adding/removing string:"]
544
675
trace add variable gdttype write hfiles_change
545
676
$gm conf -font $uifont
546
.ctop.top.lbar.gdttype conf -font $uifont
547
pack .ctop.top.lbar.gdttype -side left -fill y
548
entry .ctop.top.lbar.fent -width 25 -font $textfont \
677
.tf.lbar.gdttype conf -font $uifont
678
pack .tf.lbar.gdttype -side left -fill y
679
entry .tf.lbar.fent -width 25 -font $textfont \
549
680
-textvariable highlight_files
550
681
trace add variable highlight_files write hfiles_change
551
lappend entries .ctop.top.lbar.fent
552
pack .ctop.top.lbar.fent -side left -fill x -expand 1
553
label .ctop.top.lbar.vlabel -text " OR in view" -font $uifont
554
pack .ctop.top.lbar.vlabel -side left -fill y
682
lappend entries .tf.lbar.fent
683
pack .tf.lbar.fent -side left -fill x -expand 1
684
label .tf.lbar.vlabel -text " OR in view" -font $uifont
685
pack .tf.lbar.vlabel -side left -fill y
555
686
global viewhlmenu selectedhlview
556
set viewhlmenu [tk_optionMenu .ctop.top.lbar.vhl selectedhlview None]
557
$viewhlmenu entryconf 0 -command delvhighlight
687
set viewhlmenu [tk_optionMenu .tf.lbar.vhl selectedhlview None]
688
$viewhlmenu entryconf None -command delvhighlight
558
689
$viewhlmenu conf -font $uifont
559
.ctop.top.lbar.vhl conf -font $uifont
560
pack .ctop.top.lbar.vhl -side left -fill y
561
label .ctop.top.lbar.rlabel -text " OR " -font $uifont
562
pack .ctop.top.lbar.rlabel -side left -fill y
690
.tf.lbar.vhl conf -font $uifont
691
pack .tf.lbar.vhl -side left -fill y
692
label .tf.lbar.rlabel -text " OR " -font $uifont
693
pack .tf.lbar.rlabel -side left -fill y
563
694
global highlight_related
564
set m [tk_optionMenu .ctop.top.lbar.relm highlight_related None \
565
"Descendent" "Not descendent" "Ancestor" "Not ancestor"]
695
set m [tk_optionMenu .tf.lbar.relm highlight_related None \
696
"Descendent" "Not descendent" "Ancestor" "Not ancestor"]
566
697
$m conf -font $uifont
567
.ctop.top.lbar.relm conf -font $uifont
698
.tf.lbar.relm conf -font $uifont
568
699
trace add variable highlight_related write vrel_change
569
pack .ctop.top.lbar.relm -side left -fill y
571
panedwindow .ctop.cdet -orient horizontal
573
frame .ctop.cdet.left
574
frame .ctop.cdet.left.bot
575
pack .ctop.cdet.left.bot -side bottom -fill x
576
button .ctop.cdet.left.bot.search -text "Search" -command dosearch \
700
pack .tf.lbar.relm -side left -fill y
702
# Finish putting the upper half of the viewer together
703
pack .tf.lbar -in .tf -side bottom -fill x
704
pack .tf.bar -in .tf -side bottom -fill x
705
pack .tf.histframe -fill both -side top -expand 1
707
.ctop paneconfigure .tf -height $geometry(topheight)
708
.ctop paneconfigure .tf -width $geometry(topwidth)
710
# now build up the bottom
711
panedwindow .pwbottom -orient horizontal
713
# lower left, a text box over search bar, scroll bar to the right
714
# if we know window height, then that will set the lower text height, otherwise
715
# we set lower text height which will drive window height
716
if {[info exists geometry(main)]} {
717
frame .bleft -width $geometry(botwidth)
719
frame .bleft -width $geometry(botwidth) -height $geometry(botheight)
724
button .bleft.top.search -text "Search" -command dosearch \
578
pack .ctop.cdet.left.bot.search -side left -padx 5
579
set sstring .ctop.cdet.left.bot.sstring
726
pack .bleft.top.search -side left -padx 5
727
set sstring .bleft.top.sstring
580
728
entry $sstring -width 20 -font $textfont -textvariable searchstring
581
729
lappend entries $sstring
582
730
trace add variable searchstring write incrsearch
583
731
pack $sstring -side left -expand 1 -fill x
584
set ctext .ctop.cdet.left.ctext
732
radiobutton .bleft.mid.diff -text "Diff" \
733
-command changediffdisp -variable diffelide -value {0 0}
734
radiobutton .bleft.mid.old -text "Old version" \
735
-command changediffdisp -variable diffelide -value {0 1}
736
radiobutton .bleft.mid.new -text "New version" \
737
-command changediffdisp -variable diffelide -value {1 0}
738
label .bleft.mid.labeldiffcontext -text " Lines of context: " \
740
pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
741
spinbox .bleft.mid.diffcontext -width 5 -font $textfont \
742
-from 1 -increment 1 -to 10000000 \
743
-validate all -validatecommand "diffcontextvalidate %P" \
744
-textvariable diffcontextstring
745
.bleft.mid.diffcontext set $diffcontext
746
trace add variable diffcontextstring write diffcontextchange
747
lappend entries .bleft.mid.diffcontext
748
pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left
749
set ctext .bleft.ctext
585
750
text $ctext -background $bgcolor -foreground $fgcolor \
751
-tabs "[expr {$tabstop * $charspc}]" \
586
752
-state disabled -font $textfont \
587
-width $geometry(ctextw) -height $geometry(ctexth) \
588
753
-yscrollcommand scrolltext -wrap none
589
scrollbar .ctop.cdet.left.sb -command "$ctext yview"
590
pack .ctop.cdet.left.sb -side right -fill y
754
scrollbar .bleft.sb -command "$ctext yview"
755
pack .bleft.top -side top -fill x
756
pack .bleft.mid -side top -fill x
757
pack .bleft.sb -side right -fill y
591
758
pack $ctext -side left -fill both -expand 1
592
.ctop.cdet add .ctop.cdet.left
593
759
lappend bglist $ctext
594
760
lappend fglist $ctext
2772
3274
} elseif {[info exists idrowranges($id)]} {
2773
3275
set ranges $idrowranges($id)
2778
proc drawlineseg {id i} {
2779
global rowoffsets rowidlist
2781
global canv colormap linespc
2782
global numcommits commitrow curview
2784
set ranges [rowranges $id]
2786
if {[info exists commitrow($curview,$id)]
2787
&& $commitrow($curview,$id) < $numcommits} {
2788
set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
2792
set startrow [lindex $ranges [expr {2 * $i}]]
2793
set row [lindex $ranges [expr {2 * $i + 1}]]
2794
if {$startrow == $row} return
2797
set col [lsearch -exact [lindex $rowidlist $row] $id]
2799
puts "oops: drawline: id $id not on row $row"
3278
foreach rid $ranges {
3279
lappend linenos $commitrow($curview,$rid)
3281
if {$linenos ne {}} {
3282
lset linenos 0 [expr {[lindex $linenos 0] + 1}]
3287
# work around tk8.4 refusal to draw arrows on diagonal segments
3288
proc adjarrowhigh {coords} {
3291
set x0 [lindex $coords 0]
3292
set x1 [lindex $coords 2]
3294
set y0 [lindex $coords 1]
3295
set y1 [lindex $coords 3]
3296
if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
3297
# we have a nearby vertical segment, just trim off the diag bit
3298
set coords [lrange $coords 2 end]
3300
set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
3301
set xi [expr {$x0 - $slope * $linespc / 2}]
3302
set yi [expr {$y0 - $linespc / 2}]
3303
set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
3309
proc drawlineseg {id row endrow arrowlow} {
3310
global rowidlist displayorder iddrawn linesegs
3311
global canv colormap linespc curview maxlinelen
3313
set cols [list [lsearch -exact [lindex $rowidlist $row] $id]]
3314
set le [expr {$row + 1}]
2805
set o [lindex $rowoffsets $row $col]
2808
# changing direction
2809
set x [xc $row $col]
2811
lappend coords $x $y
2817
set x [xc $row $col]
2819
lappend coords $x $y
2821
# draw the link to the first child as part of this line
2823
set child [lindex $displayorder $row]
2824
set ccol [lsearch -exact [lindex $rowidlist $row] $child]
2826
set x [xc $row $ccol]
2828
if {$ccol < $col - 1} {
2829
lappend coords [xc $row [expr {$col - 1}]] [yc $row]
2830
} elseif {$ccol > $col + 1} {
2831
lappend coords [xc $row [expr {$col + 1}]] [yc $row]
2833
lappend coords $x $y
2836
if {[llength $coords] < 4} return
2838
# This line has an arrow at the lower end: check if the arrow is
2839
# on a diagonal segment, and if so, work around the Tk 8.4
2840
# refusal to draw arrows on diagonal lines.
2841
set x0 [lindex $coords 0]
2842
set x1 [lindex $coords 2]
2844
set y0 [lindex $coords 1]
2845
set y1 [lindex $coords 3]
2846
if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
2847
# we have a nearby vertical segment, just trim off the diag bit
2848
set coords [lrange $coords 2 end]
2850
set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
2851
set xi [expr {$x0 - $slope * $linespc / 2}]
2852
set yi [expr {$y0 - $linespc / 2}]
2853
set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
2857
set arrow [expr {2 * ($i > 0) + $downarrow}]
2858
set arrow [lindex {none first last both} $arrow]
2859
set t [$canv create line $coords -width [linewidth $id] \
2860
-fill $colormap($id) -tags lines.$id -arrow $arrow]
3317
set c [lsearch -exact [lindex $rowidlist $le] $id]
3323
set x [lindex $displayorder $le]
3328
if {[info exists iddrawn($x)] || $le == $endrow} {
3329
set c [lsearch -exact [lindex $rowidlist [expr {$le+1}]] $id]
3345
if {[info exists linesegs($id)]} {
3346
set lines $linesegs($id)
3348
set r0 [lindex $li 0]
3350
if {$r0 == $le && [lindex $li 1] - $row <= $maxlinelen} {
3360
set li [lindex $lines [expr {$i-1}]]
3361
set r1 [lindex $li 1]
3362
if {$r1 == $row && $le - [lindex $li 0] <= $maxlinelen} {
3367
set x [lindex $cols [expr {$le - $row}]]
3368
set xp [lindex $cols [expr {$le - 1 - $row}]]
3369
set dir [expr {$xp - $x}]
3371
set ith [lindex $lines $i 2]
3372
set coords [$canv coords $ith]
3373
set ah [$canv itemcget $ith -arrow]
3374
set arrowhigh [expr {$ah eq "first" || $ah eq "both"}]
3375
set x2 [lindex $cols [expr {$le + 1 - $row}]]
3376
if {$x2 ne {} && $x - $x2 == $dir} {
3377
set coords [lrange $coords 0 end-2]
3380
set coords [list [xc $le $x] [yc $le]]
3383
set itl [lindex $lines [expr {$i-1}] 2]
3384
set al [$canv itemcget $itl -arrow]
3385
set arrowlow [expr {$al eq "last" || $al eq "both"}]
3386
} elseif {$arrowlow &&
3387
[lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0} {
3390
set arrow [lindex {none first last both} [expr {$arrowhigh + 2*$arrowlow}]]
3391
for {set y $le} {[incr y -1] > $row} {} {
3393
set xp [lindex $cols [expr {$y - 1 - $row}]]
3394
set ndir [expr {$xp - $x}]
3395
if {$dir != $ndir || $xp < 0} {
3396
lappend coords [xc $y $x] [yc $y]
3402
# join parent line to first child
3403
set ch [lindex $displayorder $row]
3404
set xc [lsearch -exact [lindex $rowidlist $row] $ch]
3406
puts "oops: drawlineseg: child $ch not on row $row"
3409
lappend coords [xc $row [expr {$x-1}]] [yc $row]
3410
} elseif {$xc > $x + 1} {
3411
lappend coords [xc $row [expr {$x+1}]] [yc $row]
3415
lappend coords [xc $row $x] [yc $row]
3417
set xn [xc $row $xp]
3419
# work around tk8.4 refusal to draw arrows on diagonal segments
3420
if {$arrowlow && $xn != [lindex $coords end-1]} {
3421
if {[llength $coords] < 4 ||
3422
[lindex $coords end-3] != [lindex $coords end-1] ||
3423
[lindex $coords end] - $yn > 2 * $linespc} {
3424
set xn [xc $row [expr {$xp - 0.5 * $dir}]]
3425
set yo [yc [expr {$row + 0.5}]]
3426
lappend coords $xn $yo $xn $yn
3429
lappend coords $xn $yn
3434
set coords [adjarrowhigh $coords]
3437
set t [$canv create line $coords -width [linewidth $id] \
3438
-fill $colormap($id) -tags lines.$id -arrow $arrow]
3441
set lines [linsert $lines $i [list $row $le $t]]
3443
$canv coords $ith $coords
3444
if {$arrow ne $ah} {
3445
$canv itemconf $ith -arrow $arrow
3447
lset lines $i 0 $row
3450
set xo [lsearch -exact [lindex $rowidlist [expr {$row - 1}]] $id]
3451
set ndir [expr {$xo - $xp}]
3452
set clow [$canv coords $itl]
3453
if {$dir == $ndir} {
3454
set clow [lrange $clow 2 end]
3456
set coords [concat $coords $clow]
3458
lset lines [expr {$i-1}] 1 $le
3460
set coords [adjarrowhigh $coords]
3463
# coalesce two pieces
3465
set b [lindex $lines [expr {$i-1}] 0]
3466
set e [lindex $lines $i 1]
3467
set lines [lreplace $lines [expr {$i-1}] $i [list $b $e $itl]]
3469
$canv coords $itl $coords
3470
if {$arrow ne $al} {
3471
$canv itemconf $itl -arrow $arrow
3475
set linesegs($id) $lines
2865
proc drawparentlinks {id row col olds} {
2866
global rowidlist canv colormap
3479
proc drawparentlinks {id row} {
3480
global rowidlist canv colormap curview parentlist
3483
set rowids [lindex $rowidlist $row]
3484
set col [lsearch -exact $rowids $id]
3485
if {$col < 0} return
3486
set olds [lindex $parentlist $row]
2868
3487
set row2 [expr {$row + 1}]
2869
3488
set x [xc $row $col]
2870
3489
set y [yc $row]
5330
6272
error_popup $err
6275
removehead $id $head
5333
6276
removedhead $id $head
5335
6278
notbusy rmbranch
6283
# Display a list of tags and heads
6285
global showrefstop bgcolor fgcolor selectbgcolor mainfont
6286
global bglist fglist uifont reflistfilter reflist maincursor
6289
set showrefstop $top
6290
if {[winfo exists $top]} {
6296
wm title $top "Tags and heads: [file tail [pwd]]"
6297
text $top.list -background $bgcolor -foreground $fgcolor \
6298
-selectbackground $selectbgcolor -font $mainfont \
6299
-xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
6300
-width 30 -height 20 -cursor $maincursor \
6301
-spacing1 1 -spacing3 1 -state disabled
6302
$top.list tag configure highlight -background $selectbgcolor
6303
lappend bglist $top.list
6304
lappend fglist $top.list
6305
scrollbar $top.ysb -command "$top.list yview" -orient vertical
6306
scrollbar $top.xsb -command "$top.list xview" -orient horizontal
6307
grid $top.list $top.ysb -sticky nsew
6308
grid $top.xsb x -sticky ew
6310
label $top.f.l -text "Filter: " -font $uifont
6311
entry $top.f.e -width 20 -textvariable reflistfilter -font $uifont
6312
set reflistfilter "*"
6313
trace add variable reflistfilter write reflistfilter_change
6314
pack $top.f.e -side right -fill x -expand 1
6315
pack $top.f.l -side left
6316
grid $top.f - -sticky ew -pady 2
6317
button $top.close -command [list destroy $top] -text "Close" \
6320
grid columnconfigure $top 0 -weight 1
6321
grid rowconfigure $top 0 -weight 1
6322
bind $top.list <1> {break}
6323
bind $top.list <B1-Motion> {break}
6324
bind $top.list <ButtonRelease-1> {sel_reflist %W %x %y; break}
6329
proc sel_reflist {w x y} {
6330
global showrefstop reflist headids tagids otherrefids
6332
if {![winfo exists $showrefstop]} return
6333
set l [lindex [split [$w index "@$x,$y"] "."] 0]
6334
set ref [lindex $reflist [expr {$l-1}]]
6335
set n [lindex $ref 0]
6336
switch -- [lindex $ref 1] {
6337
"H" {selbyid $headids($n)}
6338
"T" {selbyid $tagids($n)}
6339
"o" {selbyid $otherrefids($n)}
6341
$showrefstop.list tag add highlight $l.0 "$l.0 lineend"
6344
proc unsel_reflist {} {
6347
if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
6348
$showrefstop.list tag remove highlight 0.0 end
6351
proc reflistfilter_change {n1 n2 op} {
6352
global reflistfilter
6354
after cancel refill_reflist
6355
after 200 refill_reflist
6358
proc refill_reflist {} {
6359
global reflist reflistfilter showrefstop headids tagids otherrefids
6360
global commitrow curview commitinterest
6362
if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
6364
foreach n [array names headids] {
6365
if {[string match $reflistfilter $n]} {
6366
if {[info exists commitrow($curview,$headids($n))]} {
6367
lappend refs [list $n H]
6369
set commitinterest($headids($n)) {run refill_reflist}
6373
foreach n [array names tagids] {
6374
if {[string match $reflistfilter $n]} {
6375
if {[info exists commitrow($curview,$tagids($n))]} {
6376
lappend refs [list $n T]
6378
set commitinterest($tagids($n)) {run refill_reflist}
6382
foreach n [array names otherrefids] {
6383
if {[string match $reflistfilter $n]} {
6384
if {[info exists commitrow($curview,$otherrefids($n))]} {
6385
lappend refs [list $n o]
6387
set commitinterest($otherrefids($n)) {run refill_reflist}
6391
set refs [lsort -index 0 $refs]
6392
if {$refs eq $reflist} return
6394
# Update the contents of $showrefstop.list according to the
6395
# differences between $reflist (old) and $refs (new)
6396
$showrefstop.list conf -state normal
6397
$showrefstop.list insert end "\n"
6400
while {$i < [llength $reflist] || $j < [llength $refs]} {
6401
if {$i < [llength $reflist]} {
6402
if {$j < [llength $refs]} {
6403
set cmp [string compare [lindex $reflist $i 0] \
6404
[lindex $refs $j 0]]
6406
set cmp [string compare [lindex $reflist $i 1] \
6407
[lindex $refs $j 1]]
6417
$showrefstop.list delete "[expr {$j+1}].0" "[expr {$j+2}].0"
6425
set l [expr {$j + 1}]
6426
$showrefstop.list image create $l.0 -align baseline \
6427
-image reficon-[lindex $refs $j 1] -padx 2
6428
$showrefstop.list insert $l.1 "[lindex $refs $j 0]\n"
6434
# delete last newline
6435
$showrefstop.list delete end-2c end-1c
6436
$showrefstop.list conf -state disabled
5338
6439
# Stuff for finding nearby tags
5339
6440
proc getallcommits {} {
5340
global allcstart allcommits allcfd allids
5343
set fd [open [concat | git rev-list --all --topo-order --parents] r]
6441
global allcommits allids nbmp nextarc seeds
6443
if {![info exists allcommits]} {
6451
set cmd [concat | git rev-list --all --parents]
6455
set fd [open $cmd r]
5345
6456
fconfigure $fd -blocking 0
5346
set allcommits "reading"
5347
6458
nowbusy allcommits
5351
proc discardallcommits {} {
5352
global allparents allchildren allcommits allcfd
5353
global desc_tags anc_tags alldtags tagisdesc allids desc_heads
5355
if {![info exists allcommits]} return
5356
if {$allcommits eq "reading"} {
5357
catch {close $allcfd}
5359
foreach v {allcommits allchildren allparents allids desc_tags anc_tags
5360
alldtags tagisdesc desc_heads} {
5365
proc restartgetall {fd} {
5368
fileevent $fd readable [list getallclines $fd]
5369
set allcstart [clock clicks -milliseconds]
5372
proc combine_dtags {l1 l2} {
5373
global tagisdesc notfirstd
5375
set res [lsort -unique [concat $l1 $l2]]
5376
for {set i 0} {$i < [llength $res]} {incr i} {
5377
set x [lindex $res $i]
5378
for {set j [expr {$i+1}]} {$j < [llength $res]} {} {
5379
set y [lindex $res $j]
5380
if {[info exists tagisdesc($x,$y)]} {
5381
if {$tagisdesc($x,$y) > 0} {
5382
# x is a descendent of y, exclude x
5383
set res [lreplace $res $i $i]
5387
# y is a descendent of x, exclude y
5388
set res [lreplace $res $j $j]
5391
# no relation, keep going
5399
proc combine_atags {l1 l2} {
5402
set res [lsort -unique [concat $l1 $l2]]
5403
for {set i 0} {$i < [llength $res]} {incr i} {
5404
set x [lindex $res $i]
5405
for {set j [expr {$i+1}]} {$j < [llength $res]} {} {
5406
set y [lindex $res $j]
5407
if {[info exists tagisdesc($x,$y)]} {
5408
if {$tagisdesc($x,$y) < 0} {
5409
# x is an ancestor of y, exclude x
5410
set res [lreplace $res $i $i]
5414
# y is an ancestor of x, exclude y
5415
set res [lreplace $res $j $j]
5418
# no relation, keep going
5426
proc forward_pass {id children} {
5427
global idtags desc_tags idheads desc_heads alldtags tagisdesc
5431
foreach child $children {
5432
if {[info exists idtags($child)]} {
5433
set ctags [list $child]
5435
set ctags $desc_tags($child)
5439
} elseif {$ctags ne $dtags} {
5440
set dtags [combine_dtags $dtags $ctags]
5442
set cheads $desc_heads($child)
5443
if {$dheads eq {}} {
5445
} elseif {$cheads ne $dheads} {
5446
set dheads [lsort -unique [concat $dheads $cheads]]
5449
set desc_tags($id) $dtags
5450
if {[info exists idtags($id)]} {
5452
foreach tag $dtags {
5453
set adt [concat $adt $alldtags($tag)]
5455
set adt [lsort -unique $adt]
5456
set alldtags($id) $adt
5458
set tagisdesc($id,$tag) -1
5459
set tagisdesc($tag,$id) 1
5462
if {[info exists idheads($id)]} {
5463
set dheads [concat $dheads $idheads($id)]
5465
set desc_heads($id) $dheads
6459
filerun $fd [list getallclines $fd]
6462
# Since most commits have 1 parent and 1 child, we group strings of
6463
# such commits into "arcs" joining branch/merge points (BMPs), which
6464
# are commits that either don't have 1 parent or don't have 1 child.
6466
# arcnos(id) - incoming arcs for BMP, arc we're on for other nodes
6467
# arcout(id) - outgoing arcs for BMP
6468
# arcids(a) - list of IDs on arc including end but not start
6469
# arcstart(a) - BMP ID at start of arc
6470
# arcend(a) - BMP ID at end of arc
6471
# growing(a) - arc a is still growing
6472
# arctags(a) - IDs out of arcids (excluding end) that have tags
6473
# archeads(a) - IDs out of arcids (excluding end) that have heads
6474
# The start of an arc is at the descendent end, so "incoming" means
6475
# coming from descendents, and "outgoing" means going towards ancestors.
5468
6477
proc getallclines {fd} {
5469
global allparents allchildren allcommits allcstart
5470
global desc_tags anc_tags idtags tagisdesc allids
5471
global idheads travindex
6478
global allids allparents allchildren idtags idheads nextarc nbmp
6479
global arcnos arcids arctags arcout arcend arcstart archeads growing
6480
global seeds allcommits
5473
while {[gets $fd line] >= 0} {
6483
while {[incr nid] <= 1000 && [gets $fd line] >= 0} {
5474
6484
set id [lindex $line 0]
6485
if {[info exists allparents($id)]} {
5475
6489
lappend allids $id
5476
6490
set olds [lrange $line 1 end]
5477
6491
set allparents($id) $olds
5478
6492
if {![info exists allchildren($id)]} {
5479
6493
set allchildren($id) {}
6498
if {[llength $olds] == 1 && [llength $a] == 1} {
6499
lappend arcids($a) $id
6500
if {[info exists idtags($id)]} {
6501
lappend arctags($a) $id
6503
if {[info exists idheads($id)]} {
6504
lappend archeads($a) $id
6506
if {[info exists allparents($olds)]} {
6507
# seen parent already
6508
if {![info exists arcout($olds)]} {
6511
lappend arcids($a) $olds
6512
set arcend($a) $olds
6515
lappend allchildren($olds) $id
6516
lappend arcnos($olds) $a
6521
foreach a $arcnos($id) {
6522
lappend arcids($a) $id
5481
6528
foreach p $olds {
5482
6529
lappend allchildren($p) $id
5484
# compute nearest tagged descendents as we go
5485
# also compute descendent heads
5486
forward_pass $id $allchildren($id)
5487
if {[clock clicks -milliseconds] - $allcstart >= 50} {
5488
fileevent $fd readable {}
5489
after idle restartgetall $fd
5494
set travindex [llength $allids]
5495
set allcommits "traversing"
5496
after idle restartatags
5497
if {[catch {close $fd} err]} {
5498
error_popup "Error reading full commit graph: $err.\n\
5499
Results may be incomplete."
5504
# walk backward through the tree and compute nearest tagged ancestors
5505
proc restartatags {} {
5506
global allids allparents idtags anc_tags travindex
5508
set t0 [clock clicks -milliseconds]
5510
while {[incr i -1] >= 0} {
5511
set id [lindex $allids $i]
5513
foreach p $allparents($id) {
5514
if {[info exists idtags($p)]} {
6530
set a [incr nextarc]
6531
set arcstart($a) $id
6538
if {[info exists allparents($p)]} {
6539
# seen it already, may need to make a new branch
6540
if {![info exists arcout($p)]} {
6543
lappend arcids($a) $p
6547
lappend arcnos($p) $a
6552
global cached_dheads cached_dtags cached_atags
6553
catch {unset cached_dheads}
6554
catch {unset cached_dtags}
6555
catch {unset cached_atags}
6558
return [expr {$nid >= 1000? 2: 1}]
6561
if {[incr allcommits -1] == 0} {
6568
proc recalcarc {a} {
6569
global arctags archeads arcids idtags idheads
6573
foreach id [lrange $arcids($a) 0 end-1] {
6574
if {[info exists idtags($id)]} {
6577
if {[info exists idheads($id)]} {
6582
set archeads($a) $ah
6586
global arcnos arcids nextarc nbmp arctags archeads idtags idheads
6587
global arcstart arcend arcout allparents growing
6590
if {[llength $a] != 1} {
6591
puts "oops splitarc called but [llength $a] arcs already"
6595
set i [lsearch -exact $arcids($a) $p]
6597
puts "oops splitarc $p not in arc $a"
6600
set na [incr nextarc]
6601
if {[info exists arcend($a)]} {
6602
set arcend($na) $arcend($a)
6604
set l [lindex $allparents([lindex $arcids($a) end]) 0]
6605
set j [lsearch -exact $arcnos($l) $a]
6606
set arcnos($l) [lreplace $arcnos($l) $j $j $na]
6608
set tail [lrange $arcids($a) [expr {$i+1}] end]
6609
set arcids($a) [lrange $arcids($a) 0 $i]
6611
set arcstart($na) $p
6613
set arcids($na) $tail
6614
if {[info exists growing($a)]} {
6621
if {[llength $arcnos($id)] == 1} {
6624
set j [lsearch -exact $arcnos($id) $a]
6625
set arcnos($id) [lreplace $arcnos($id) $j $j $na]
6629
# reconstruct tags and heads lists
6630
if {$arctags($a) ne {} || $archeads($a) ne {}} {
6635
set archeads($na) {}
6639
# Update things for a new commit added that is a child of one
6640
# existing commit. Used when cherry-picking.
6641
proc addnewchild {id p} {
6642
global allids allparents allchildren idtags nextarc nbmp
6643
global arcnos arcids arctags arcout arcend arcstart archeads growing
6644
global seeds allcommits
6646
if {![info exists allcommits]} return
6648
set allparents($id) [list $p]
6649
set allchildren($id) {}
6653
lappend allchildren($p) $id
6654
set a [incr nextarc]
6655
set arcstart($a) $id
6658
set arcids($a) [list $p]
6660
if {![info exists arcout($p)]} {
6663
lappend arcnos($p) $a
6664
set arcout($id) [list $a]
6667
# Returns 1 if a is an ancestor of b, -1 if b is an ancestor of a,
6668
# or 0 if neither is true.
6669
proc anc_or_desc {a b} {
6670
global arcout arcstart arcend arcnos cached_isanc
6672
if {$arcnos($a) eq $arcnos($b)} {
6673
# Both are on the same arc(s); either both are the same BMP,
6674
# or if one is not a BMP, the other is also not a BMP or is
6675
# the BMP at end of the arc (and it only has 1 incoming arc).
6676
# Or both can be BMPs with no incoming arcs.
6677
if {$a eq $b || $arcnos($a) eq {}} {
6680
# assert {[llength $arcnos($a)] == 1}
6681
set arc [lindex $arcnos($a) 0]
6682
set i [lsearch -exact $arcids($arc) $a]
6683
set j [lsearch -exact $arcids($arc) $b]
6684
if {$i < 0 || $i > $j} {
6691
if {![info exists arcout($a)]} {
6692
set arc [lindex $arcnos($a) 0]
6693
if {[info exists arcend($arc)]} {
6694
set aend $arcend($arc)
6698
set a $arcstart($arc)
6702
if {![info exists arcout($b)]} {
6703
set arc [lindex $arcnos($b) 0]
6704
if {[info exists arcend($arc)]} {
6705
set bend $arcend($arc)
6709
set b $arcstart($arc)
6719
if {[info exists cached_isanc($a,$bend)]} {
6720
if {$cached_isanc($a,$bend)} {
6724
if {[info exists cached_isanc($b,$aend)]} {
6725
if {$cached_isanc($b,$aend)} {
6728
if {[info exists cached_isanc($a,$bend)]} {
6733
set todo [list $a $b]
6736
for {set i 0} {$i < [llength $todo]} {incr i} {
6737
set x [lindex $todo $i]
6738
if {$anc($x) eq {}} {
6741
foreach arc $arcnos($x) {
6742
set xd $arcstart($arc)
6744
set cached_isanc($a,$bend) 1
6745
set cached_isanc($b,$aend) 0
6747
} elseif {$xd eq $aend} {
6748
set cached_isanc($b,$aend) 1
6749
set cached_isanc($a,$bend) 0
6752
if {![info exists anc($xd)]} {
6753
set anc($xd) $anc($x)
6755
} elseif {$anc($xd) ne $anc($x)} {
6760
set cached_isanc($a,$bend) 0
6761
set cached_isanc($b,$aend) 0
6765
# This identifies whether $desc has an ancestor that is
6766
# a growing tip of the graph and which is not an ancestor of $anc
6767
# and returns 0 if so and 1 if not.
6768
# If we subsequently discover a tag on such a growing tip, and that
6769
# turns out to be a descendent of $anc (which it could, since we
6770
# don't necessarily see children before parents), then $desc
6771
# isn't a good choice to display as a descendent tag of
6772
# $anc (since it is the descendent of another tag which is
6773
# a descendent of $anc). Similarly, $anc isn't a good choice to
6774
# display as a ancestor tag of $desc.
6776
proc is_certain {desc anc} {
6777
global arcnos arcout arcstart arcend growing problems
6780
if {[llength $arcnos($anc)] == 1} {
6781
# tags on the same arc are certain
6782
if {$arcnos($desc) eq $arcnos($anc)} {
6785
if {![info exists arcout($anc)]} {
6786
# if $anc is partway along an arc, use the start of the arc instead
6787
set a [lindex $arcnos($anc) 0]
6788
set anc $arcstart($a)
6791
if {[llength $arcnos($desc)] > 1 || [info exists arcout($desc)]} {
6794
set a [lindex $arcnos($desc) 0]
6800
set anclist [list $x]
6804
for {set i 0} {$i < [llength $anclist] && ($nnh > 0 || $ngrowanc > 0)} {incr i} {
6805
set x [lindex $anclist $i]
6810
foreach a $arcout($x) {
6811
if {[info exists growing($a)]} {
6812
if {![info exists growanc($x)] && $dl($x)} {
5517
set ptags $anc_tags($p)
5521
} elseif {$ptags ne $atags} {
5522
set atags [combine_atags $atags $ptags]
5525
set anc_tags($id) $atags
5526
if {[clock clicks -milliseconds] - $t0 >= 50} {
5528
after idle restartatags
5532
set allcommits "done"
5538
# update the desc_tags and anc_tags arrays for a new tag just added
6818
if {[info exists dl($y)]} {
6822
if {![info exists done($y)]} {
6825
if {[info exists growanc($x)]} {
6829
for {set k 0} {$k < [llength $xl]} {incr k} {
6830
set z [lindex $xl $k]
6831
foreach c $arcout($z) {
6832
if {[info exists arcend($c)]} {
6834
if {[info exists dl($v)] && $dl($v)} {
6836
if {![info exists done($v)]} {
6839
if {[info exists growanc($v)]} {
6849
} elseif {$y eq $anc || !$dl($x)} {
6860
foreach x [array names growanc] {
6869
proc validate_arctags {a} {
6870
global arctags idtags
6874
foreach id $arctags($a) {
6876
if {![info exists idtags($id)]} {
6877
set na [lreplace $na $i $i]
6884
proc validate_archeads {a} {
6885
global archeads idheads
6888
set na $archeads($a)
6889
foreach id $archeads($a) {
6891
if {![info exists idheads($id)]} {
6892
set na [lreplace $na $i $i]
6896
set archeads($a) $na
6899
# Return the list of IDs that have tags that are descendents of id,
6900
# ignoring IDs that are descendents of IDs already reported.
6901
proc desctags {id} {
6902
global arcnos arcstart arcids arctags idtags allparents
6903
global growing cached_dtags
6905
if {![info exists allparents($id)]} {
6908
set t1 [clock clicks -milliseconds]
6910
if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
6911
# part-way along an arc; check that arc first
6912
set a [lindex $arcnos($id) 0]
6913
if {$arctags($a) ne {}} {
6915
set i [lsearch -exact $arcids($a) $id]
6917
foreach t $arctags($a) {
6918
set j [lsearch -exact $arcids($a) $t]
6926
set id $arcstart($a)
6927
if {[info exists idtags($id)]} {
6931
if {[info exists cached_dtags($id)]} {
6932
return $cached_dtags($id)
6939
for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
6940
set id [lindex $todo $i]
6942
set ta [info exists hastaggedancestor($id)]
6946
# ignore tags on starting node
6947
if {!$ta && $i > 0} {
6948
if {[info exists idtags($id)]} {
6951
} elseif {[info exists cached_dtags($id)]} {
6952
set tagloc($id) $cached_dtags($id)
6956
foreach a $arcnos($id) {
6958
if {!$ta && $arctags($a) ne {}} {
6960
if {$arctags($a) ne {}} {
6961
lappend tagloc($id) [lindex $arctags($a) end]
6964
if {$ta || $arctags($a) ne {}} {
6965
set tomark [list $d]
6966
for {set j 0} {$j < [llength $tomark]} {incr j} {
6967
set dd [lindex $tomark $j]
6968
if {![info exists hastaggedancestor($dd)]} {
6969
if {[info exists done($dd)]} {
6970
foreach b $arcnos($dd) {
6971
lappend tomark $arcstart($b)
6973
if {[info exists tagloc($dd)]} {
6976
} elseif {[info exists queued($dd)]} {
6979
set hastaggedancestor($dd) 1
6983
if {![info exists queued($d)]} {
6986
if {![info exists hastaggedancestor($d)]} {
6993
foreach id [array names tagloc] {
6994
if {![info exists hastaggedancestor($id)]} {
6995
foreach t $tagloc($id) {
6996
if {[lsearch -exact $tags $t] < 0} {
7002
set t2 [clock clicks -milliseconds]
7005
# remove tags that are descendents of other tags
7006
for {set i 0} {$i < [llength $tags]} {incr i} {
7007
set a [lindex $tags $i]
7008
for {set j 0} {$j < $i} {incr j} {
7009
set b [lindex $tags $j]
7010
set r [anc_or_desc $a $b]
7012
set tags [lreplace $tags $j $j]
7015
} elseif {$r == -1} {
7016
set tags [lreplace $tags $i $i]
7023
if {[array names growing] ne {}} {
7024
# graph isn't finished, need to check if any tag could get
7025
# eclipsed by another tag coming later. Simply ignore any
7026
# tags that could later get eclipsed.
7029
if {[is_certain $t $origid]} {
7033
if {$tags eq $ctags} {
7034
set cached_dtags($origid) $tags
7039
set cached_dtags($origid) $tags
7041
set t3 [clock clicks -milliseconds]
7042
if {0 && $t3 - $t1 >= 100} {
7043
puts "iterating descendents ($loopix/[llength $todo] nodes) took\
7044
[expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
7050
global arcnos arcids arcout arcend arctags idtags allparents
7051
global growing cached_atags
7053
if {![info exists allparents($id)]} {
7056
set t1 [clock clicks -milliseconds]
7058
if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
7059
# part-way along an arc; check that arc first
7060
set a [lindex $arcnos($id) 0]
7061
if {$arctags($a) ne {}} {
7063
set i [lsearch -exact $arcids($a) $id]
7064
foreach t $arctags($a) {
7065
set j [lsearch -exact $arcids($a) $t]
7071
if {![info exists arcend($a)]} {
7075
if {[info exists idtags($id)]} {
7079
if {[info exists cached_atags($id)]} {
7080
return $cached_atags($id)
7088
for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
7089
set id [lindex $todo $i]
7091
set td [info exists hastaggeddescendent($id)]
7095
# ignore tags on starting node
7096
if {!$td && $i > 0} {
7097
if {[info exists idtags($id)]} {
7100
} elseif {[info exists cached_atags($id)]} {
7101
set tagloc($id) $cached_atags($id)
7105
foreach a $arcout($id) {
7106
if {!$td && $arctags($a) ne {}} {
7108
if {$arctags($a) ne {}} {
7109
lappend tagloc($id) [lindex $arctags($a) 0]
7112
if {![info exists arcend($a)]} continue
7114
if {$td || $arctags($a) ne {}} {
7115
set tomark [list $d]
7116
for {set j 0} {$j < [llength $tomark]} {incr j} {
7117
set dd [lindex $tomark $j]
7118
if {![info exists hastaggeddescendent($dd)]} {
7119
if {[info exists done($dd)]} {
7120
foreach b $arcout($dd) {
7121
if {[info exists arcend($b)]} {
7122
lappend tomark $arcend($b)
7125
if {[info exists tagloc($dd)]} {
7128
} elseif {[info exists queued($dd)]} {
7131
set hastaggeddescendent($dd) 1
7135
if {![info exists queued($d)]} {
7138
if {![info exists hastaggeddescendent($d)]} {
7144
set t2 [clock clicks -milliseconds]
7147
foreach id [array names tagloc] {
7148
if {![info exists hastaggeddescendent($id)]} {
7149
foreach t $tagloc($id) {
7150
if {[lsearch -exact $tags $t] < 0} {
7157
# remove tags that are ancestors of other tags
7158
for {set i 0} {$i < [llength $tags]} {incr i} {
7159
set a [lindex $tags $i]
7160
for {set j 0} {$j < $i} {incr j} {
7161
set b [lindex $tags $j]
7162
set r [anc_or_desc $a $b]
7164
set tags [lreplace $tags $j $j]
7167
} elseif {$r == 1} {
7168
set tags [lreplace $tags $i $i]
7175
if {[array names growing] ne {}} {
7176
# graph isn't finished, need to check if any tag could get
7177
# eclipsed by another tag coming later. Simply ignore any
7178
# tags that could later get eclipsed.
7181
if {[is_certain $origid $t]} {
7185
if {$tags eq $ctags} {
7186
set cached_atags($origid) $tags
7191
set cached_atags($origid) $tags
7193
set t3 [clock clicks -milliseconds]
7194
if {0 && $t3 - $t1 >= 100} {
7195
puts "iterating ancestors ($loopix/[llength $todo] nodes) took\
7196
[expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
7201
# Return the list of IDs that have heads that are descendents of id,
7202
# including id itself if it has a head.
7203
proc descheads {id} {
7204
global arcnos arcstart arcids archeads idheads cached_dheads
7207
if {![info exists allparents($id)]} {
7211
if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
7212
# part-way along an arc; check it first
7213
set a [lindex $arcnos($id) 0]
7214
if {$archeads($a) ne {}} {
7215
validate_archeads $a
7216
set i [lsearch -exact $arcids($a) $id]
7217
foreach t $archeads($a) {
7218
set j [lsearch -exact $arcids($a) $t]
7223
set id $arcstart($a)
7229
for {set i 0} {$i < [llength $todo]} {incr i} {
7230
set id [lindex $todo $i]
7231
if {[info exists cached_dheads($id)]} {
7232
set ret [concat $ret $cached_dheads($id)]
7234
if {[info exists idheads($id)]} {
7237
foreach a $arcnos($id) {
7238
if {$archeads($a) ne {}} {
7239
validate_archeads $a
7240
if {$archeads($a) ne {}} {
7241
set ret [concat $ret $archeads($a)]
7245
if {![info exists seen($d)]} {
7252
set ret [lsort -unique $ret]
7253
set cached_dheads($origid) $ret
7254
return [concat $ret $aret]
5539
7257
proc addedtag {id} {
5540
global desc_tags anc_tags allparents allchildren allcommits
5541
global idtags tagisdesc alldtags
5543
if {![info exists desc_tags($id)]} return
5544
set adt $desc_tags($id)
5545
foreach t $desc_tags($id) {
5546
set adt [concat $adt $alldtags($t)]
5548
set adt [lsort -unique $adt]
5549
set alldtags($id) $adt
5551
set tagisdesc($id,$t) -1
5552
set tagisdesc($t,$id) 1
5554
if {[info exists anc_tags($id)]} {
5555
set todo $anc_tags($id)
5556
while {$todo ne {}} {
5557
set do [lindex $todo 0]
5558
set todo [lrange $todo 1 end]
5559
if {[info exists tagisdesc($id,$do)]} continue
5560
set tagisdesc($do,$id) -1
5561
set tagisdesc($id,$do) 1
5562
if {[info exists anc_tags($do)]} {
5563
set todo [concat $todo $anc_tags($do)]
5568
set lastold $desc_tags($id)
5569
set lastnew [list $id]
5572
set todo $allparents($id)
5573
while {$todo ne {}} {
5574
set do [lindex $todo 0]
5575
set todo [lrange $todo 1 end]
5576
if {![info exists desc_tags($do)]} continue
5577
if {$desc_tags($do) ne $lastold} {
5578
set lastold $desc_tags($do)
5579
set lastnew [combine_dtags $lastold [list $id]]
5582
if {$lastold eq $lastnew} continue
5583
set desc_tags($do) $lastnew
5585
if {![info exists idtags($do)]} {
5586
set todo [concat $todo $allparents($do)]
5590
if {![info exists anc_tags($id)]} return
5591
set lastold $anc_tags($id)
5592
set lastnew [list $id]
5595
set todo $allchildren($id)
5596
while {$todo ne {}} {
5597
set do [lindex $todo 0]
5598
set todo [lrange $todo 1 end]
5599
if {![info exists anc_tags($do)]} continue
5600
if {$anc_tags($do) ne $lastold} {
5601
set lastold $anc_tags($do)
5602
set lastnew [combine_atags $lastold [list $id]]
5605
if {$lastold eq $lastnew} continue
5606
set anc_tags($do) $lastnew
5608
if {![info exists idtags($do)]} {
5609
set todo [concat $todo $allchildren($do)]
7258
global arcnos arcout cached_dtags cached_atags
7260
if {![info exists arcnos($id)]} return
7261
if {![info exists arcout($id)]} {
7262
recalcarc [lindex $arcnos($id) 0]
7264
catch {unset cached_dtags}
7265
catch {unset cached_atags}
5614
# update the desc_heads array for a new head just added
5615
7268
proc addedhead {hid head} {
5616
global desc_heads allparents headids idheads
5618
set headids($head) $hid
5619
lappend idheads($hid) $head
5621
set todo [list $hid]
5622
while {$todo ne {}} {
5623
set do [lindex $todo 0]
5624
set todo [lrange $todo 1 end]
5625
if {![info exists desc_heads($do)] ||
5626
[lsearch -exact $desc_heads($do) $head] >= 0} continue
5627
set oldheads $desc_heads($do)
5628
lappend desc_heads($do) $head
5629
set heads $desc_heads($do)
5631
set p $allparents($do)
5632
if {[llength $p] != 1 || ![info exists desc_heads($p)] ||
5633
$desc_heads($p) ne $oldheads} break
5635
set desc_heads($do) $heads
5637
set todo [concat $todo $p]
7269
global arcnos arcout cached_dheads
7271
if {![info exists arcnos($hid)]} return
7272
if {![info exists arcout($hid)]} {
7273
recalcarc [lindex $arcnos($hid) 0]
7275
catch {unset cached_dheads}
5641
# update the desc_heads array for a head just removed
5642
7278
proc removedhead {hid head} {
5643
global desc_heads allparents headids idheads
5645
unset headids($head)
5646
if {$idheads($hid) eq $head} {
5649
set i [lsearch -exact $idheads($hid) $head]
5651
set idheads($hid) [lreplace $idheads($hid) $i $i]
5655
set todo [list $hid]
5656
while {$todo ne {}} {
5657
set do [lindex $todo 0]
5658
set todo [lrange $todo 1 end]
5659
if {![info exists desc_heads($do)]} continue
5660
set i [lsearch -exact $desc_heads($do) $head]
5661
if {$i < 0} continue
5662
set oldheads $desc_heads($do)
5663
set heads [lreplace $desc_heads($do) $i $i]
5665
set desc_heads($do) $heads
5666
set p $allparents($do)
5667
if {[llength $p] != 1 || ![info exists desc_heads($p)] ||
5668
$desc_heads($p) ne $oldheads} break
5671
set todo [concat $todo $p]
7279
global cached_dheads
7281
catch {unset cached_dheads}
5675
# update things for a head moved to a child of its previous location
5676
proc movedhead {id name} {
5677
global headids idheads
7284
proc movedhead {hid head} {
7285
global arcnos arcout cached_dheads
5679
set oldid $headids($name)
5680
set headids($name) $id
5681
if {$idheads($oldid) eq $name} {
5682
unset idheads($oldid)
5684
set i [lsearch -exact $idheads($oldid) $name]
5686
set idheads($oldid) [lreplace $idheads($oldid) $i $i]
7287
if {![info exists arcnos($hid)]} return
7288
if {![info exists arcout($hid)]} {
7289
recalcarc [lindex $arcnos($hid) 0]
5689
lappend idheads($id) $name
7291
catch {unset cached_dheads}
5692
7294
proc changedrefs {} {
5693
global desc_heads desc_tags anc_tags allcommits allids
5694
global allchildren allparents idtags travindex
7295
global cached_dheads cached_dtags cached_atags
7296
global arctags archeads arcnos arcout idheads idtags
5696
if {![info exists allcommits]} return
5697
catch {unset desc_heads}
5698
catch {unset desc_tags}
5699
catch {unset anc_tags}
5700
catch {unset alldtags}
5701
catch {unset tagisdesc}
5702
foreach id $allids {
5703
forward_pass $id $allchildren($id)
5705
if {$allcommits ne "reading"} {
5706
set travindex [llength $allids]
5707
if {$allcommits ne "traversing"} {
5708
set allcommits "traversing"
5709
after idle restartatags
7298
foreach id [concat [array names idheads] [array names idtags]] {
7299
if {[info exists arcnos($id)] && ![info exists arcout($id)]} {
7300
set a [lindex $arcnos($id) 0]
7301
if {![info exists donearc($a)]} {
7307
catch {unset cached_dtags}
7308
catch {unset cached_atags}
7309
catch {unset cached_dheads}
5714
7312
proc rereadrefs {} {