gitk: Fix more bugs resulting in Tcl "no such element in array" errors
[gitweb.git] / gitk
diff --git a/gitk b/gitk
index ea04a09a0c917bc3300f1ba4877846904d0263b8..9c5de3f45dd2559fb3381ef1fef28f9bec7588c3 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -106,7 +106,7 @@ proc start_rev_list {view} {
     set vnextroot($view) 0
     varcinit $view
 
-    set commits [exec git rev-parse --default HEAD --revs-only \
+    set commits [eval exec git rev-parse --default HEAD --revs-only \
                     $viewargs($view)]
     set viewincl($view) {}
     foreach c $commits {
@@ -268,7 +268,7 @@ proc strrep {n} {
 
 proc varcinit {view} {
     global vseeds varcstart vupptr vdownptr vleftptr varctok varcrow
-    global vtokmod varcmod varcix uat
+    global vtokmod varcmod vrowmod varcix uat
 
     set vseeds($view) {}
     set varcstart($view) {{}}
@@ -279,6 +279,7 @@ proc varcinit {view} {
     set varcrow($view) {{}}
     set vtokmod($view) {}
     set varcmod($view) 0
+    set vrowmod($view) 0
     set varcix($view) {{}}
     set uat 0
 }
@@ -301,15 +302,13 @@ proc resetvarcs {view} {
     foreach vd [array names vseedcount $view,*] {
        unset vseedcount($vd)
     }
-    foreach vid [array names ordertok $view,*] {
-       unset ordertok($vid)
-    }
+    catch {unset ordertok}
 }
 
 proc newvarc {view id} {
     global varcid varctok parents children vseeds
     global vupptr vdownptr vleftptr varcrow varcix varcstart
-    global commitdata commitinfo vseedcount
+    global commitdata commitinfo vseedcount varccommits
 
     set a [llength $varctok($view)]
     set vid $view,$id
@@ -379,6 +378,7 @@ proc newvarc {view id} {
     lappend vdownptr($view) 0
     lappend varcrow($view) {}
     lappend varcix($view) {}
+    set varccommits($view,$a) {}
     return $a
 }
 
@@ -413,7 +413,7 @@ proc splitvarc {p v} {
 
 proc renumbervarc {a v} {
     global parents children varctok varcstart varccommits
-    global vupptr vdownptr vleftptr varcid vtokmod varcmod
+    global vupptr vdownptr vleftptr varcid vtokmod
 
     set t1 [clock clicks -milliseconds]
     set todo {}
@@ -463,6 +463,12 @@ proc renumbervarc {a v} {
        }
        set b [lindex $vupptr($v) $a]
        if {$b != $ka} {
+           if {[string compare [lindex $varctok($v) $ka] $vtokmod($v)] < 0} {
+               modify_arc $v $ka
+           }
+           if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+               modify_arc $v $b
+           }
            set c [lindex $vdownptr($v) $b]
            if {$c == $a} {
                lset vdownptr($v) $b [lindex $vleftptr($v) $a]
@@ -525,8 +531,8 @@ proc fix_reversal {p a v} {
 }
 
 proc insertrow {id p v} {
-    global varcid varccommits parents children cmitlisted ordertok
-    global commitidx varctok vtokmod varcmod
+    global varcid varccommits parents children cmitlisted
+    global commitidx varctok vtokmod
 
     set a $varcid($v,$p)
     set i [lsearch -exact $varccommits($v,$a) $p]
@@ -537,26 +543,20 @@ proc insertrow {id p v} {
     set children($v,$id) {}
     set parents($v,$id) [list $p]
     set varcid($v,$id) $a
-    if {[llength [lappend children($v,$p) $id]] > 1 &&
-       [vtokcmp $v [lindex $children($v,$p) end-1] $id] > 0} {
-       set children($v,$p) [lsort -command [list vtokcmp $v] $children($v,$p)]
-    }
+    lappend children($v,$p) $id
     set cmitlisted($v,$id) 1
     incr commitidx($v)
-    set ordertok($v,$id) $ordertok($v,$p)
     # note we deliberately don't update varcstart($v) even if $i == 0
     set varccommits($v,$a) [linsert $varccommits($v,$a) $i $id]
-    set tok [lindex $varctok($v) $a]
-    if {[string compare $tok $vtokmod($v)] < 0} {
-       set vtokmod($v) $tok
-       set varcmod($v) $a
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
+       modify_arc $v $a $i
     }
-    update_arcrows $v
+    drawvisible
 }
 
 proc removerow {id v} {
-    global varcid varccommits parents children commitidx ordertok
-    global varctok vtokmod varcmod
+    global varcid varccommits parents children commitidx
+    global varctok vtokmod
 
     if {[llength $parents($v,$id)] != 1} {
        puts "oops: removerow [shortids $id] has [llength $parents($v,$id)] parents"
@@ -574,18 +574,16 @@ proc removerow {id v} {
     unset parents($v,$id)
     unset children($v,$id)
     unset cmitlisted($v,$id)
-    unset ordertok($v,$id)
     incr commitidx($v) -1
     set j [lsearch -exact $children($v,$p) $id]
     if {$j >= 0} {
        set children($v,$p) [lreplace $children($v,$p) $j $j]
     }
     set tok [lindex $varctok($v) $a]
-    if {[string compare $tok $vtokmod($v)] < 0} {
-       set vtokmod($v) $tok
-       set varcmod($v) $a
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] < 0} {
+       modify_arc $v $a $i
     }
-    update_arcrows $v
+    drawvisible
 }
 
 proc vtokcmp {v a b} {
@@ -595,8 +593,30 @@ proc vtokcmp {v a b} {
                [lindex $varctok($v) $varcid($v,$b)]]
 }
 
+proc modify_arc {v a {lim {}}} {
+    global varctok vtokmod varcmod varcrow vupptr curview vrowmod varccommits
+
+    set vtokmod($v) [lindex $varctok($v) $a]
+    set varcmod($v) $a
+    if {$v == $curview} {
+       while {$a != 0 && [lindex $varcrow($v) $a] eq {}} {
+           set a [lindex $vupptr($v) $a]
+           set lim {}
+       }
+       set r 0
+       if {$a != 0} {
+           if {$lim eq {}} {
+               set lim [llength $varccommits($v,$a)]
+           }
+           set r [expr {[lindex $varcrow($v) $a] + $lim}]
+       }
+       set vrowmod($v) $r
+       undolayout $r
+    }
+}
+
 proc update_arcrows {v} {
-    global vtokmod varcmod varcrow commitidx currentid selectedline
+    global vtokmod varcmod vrowmod varcrow commitidx currentid selectedline
     global varcid vseeds vrownum varcorder varcix varccommits
     global vupptr vdownptr vleftptr varctok
     global uat displayorder parentlist curview cached_commitrow
@@ -630,14 +650,13 @@ proc update_arcrows {v} {
        }
        set row [lindex $varcrow($v) $a]
     }
-    if {[llength $displayorder] > $row} {
-       set displayorder [lrange $displayorder 0 [expr {$row - 1}]]
-       set parentlist [lrange $parentlist 0 [expr {$row - 1}]]
-    }
     if {$v == $curview} {
+       if {[llength $displayorder] > $vrowmod($v)} {
+           set displayorder [lrange $displayorder 0 [expr {$vrowmod($v) - 1}]]
+           set parentlist [lrange $parentlist 0 [expr {$vrowmod($v) - 1}]]
+       }
        catch {unset cached_commitrow}
     }
-    set startrow $row
     while {1} {
        set p $a
        incr row [llength $varccommits($v,$a)]
@@ -659,18 +678,12 @@ proc update_arcrows {v} {
        lset varcix($v) $a $arcn
        lset varcrow($v) $a $row
     }
+    set vtokmod($v) [lindex $varctok($v) $p]
+    set varcmod($v) $p
+    set vrowmod($v) $row
     if {[info exists currentid]} {
        set selectedline [rowofcommit $currentid]
     }
-    undolayout $startrow
-    if {$row != $commitidx($v)} {
-       puts "oops update_arcrows got to row $row out of $commitidx($v)"
-       set vtokmod($v) {}
-       set varcmod($v) 0
-    } else {
-       set vtokmod($v) [lindex $varctok($v) $p]
-       set varcmod($v) $p
-    }
     set t2 [clock clicks -milliseconds]
     incr uat [expr {$t2-$t1}]
 }
@@ -685,6 +698,7 @@ proc commitinview {id v} {
 # Return the row number for commit $id in the current view
 proc rowofcommit {id} {
     global varcid varccommits varcrow curview cached_commitrow
+    global varctok vtokmod
 
     if {[info exists cached_commitrow($id)]} {
        return $cached_commitrow($id)
@@ -695,6 +709,9 @@ proc rowofcommit {id} {
        return {}
     }
     set a $varcid($v,$id)
+    if {[string compare [lindex $varctok($v) $a] $vtokmod($v)] > 0} {
+       update_arcrows $v
+    }
     set i [lsearch -exact $varccommits($v,$a) $id]
     if {$i < 0} {
        puts "oops didn't find commit [shortids $id] in arc $a"
@@ -728,9 +745,12 @@ proc bsearch {l elt} {
 # Make sure rows $start..$end-1 are valid in displayorder and parentlist
 proc make_disporder {start end} {
     global vrownum curview commitidx displayorder parentlist
-    global varccommits varcorder parents
+    global varccommits varcorder parents vrowmod varcrow
     global d_valid_start d_valid_end
 
+    if {$end > $vrowmod($curview)} {
+       update_arcrows $curview
+    }
     set ai [bsearch $vrownum($curview) $start]
     set start [lindex $vrownum($curview) $ai]
     set narc [llength $vrownum($curview)]
@@ -776,7 +796,7 @@ proc commitonrow {row} {
 
 proc closevarcs {v} {
     global varctok varccommits varcid parents children
-    global cmitlisted commitidx commitinterest vtokmod varcmod
+    global cmitlisted commitidx commitinterest vtokmod
 
     set missing_parents 0
     set scripts {}
@@ -796,12 +816,10 @@ proc closevarcs {v} {
                set b [newvarc $v $p]
            }
            set varcid($v,$p) $b
-           lappend varccommits($v,$b) $p
-           set tok [lindex $varctok($v) $b]
-           if {[string compare $tok $vtokmod($v)] < 0} {
-               set vtokmod($v) $tok
-               set varcmod($v) $b
+           if {[string compare [lindex $varctok($v) $b] $vtokmod($v)] < 0} {
+               modify_arc $v $b
            }
+           lappend varccommits($v,$b) $p
            incr commitidx($v)
            if {[info exists commitinterest($p)]} {
                foreach script $commitinterest($p) {
@@ -812,7 +830,6 @@ proc closevarcs {v} {
        }
     }
     if {$missing_parents > 0} {
-       update_arcrows $v
        foreach s $scripts {
            eval $s
        }
@@ -823,8 +840,8 @@ proc getcommitlines {fd inst view}  {
     global cmitlisted commitinterest leftover getdbg
     global commitidx commitdata
     global parents children curview hlview
-    global ordertok vnextroot idpending
-    global varccommits varcid varctok vtokmod varcmod
+    global vnextroot idpending ordertok
+    global varccommits varcid varctok vtokmod
 
     set stuff [read $fd 500000]
     # git log doesn't terminate the last commit with a null...
@@ -925,29 +942,8 @@ proc getcommitlines {fd inst view}  {
        set id [lindex $ids 0]
        set vid $view,$id
        if {!$listed && [info exists parents($vid)]} continue
-       if {![info exists ordertok($vid)]} {
-           set otok "o[strrep $vnextroot($view)]"
-           incr vnextroot($view)
-           set ordertok($vid) $otok
-       } else {
-           set otok $ordertok($vid)
-       }
        if {$listed} {
            set olds [lrange $ids 1 end]
-           if {[llength $olds] == 1} {
-               set p [lindex $olds 0]
-               if {![info exists ordertok($view,$p)]} {
-                   set ordertok($view,$p) $ordertok($vid)
-               }
-           } else {
-               set i 0
-               foreach p $olds {
-                   if {![info exists ordertok($view,$p)]} {
-                       set ordertok($view,$p) "$otok[strrep $i]]"
-                   }
-                   incr i
-               }
-           }
        } else {
            set olds {}
        }
@@ -970,8 +966,11 @@ proc getcommitlines {fd inst view}  {
            set a [newvarc $view $id]
        }
        set varcid($vid) $a
+       if {[string compare [lindex $varctok($view) $a] $vtokmod($view)] < 0} {
+           modify_arc $view $a
+       }
        lappend varccommits($view,$a) $id
-       set tok [lindex $varctok($view) $a]
+
        set i 0
        foreach p $olds {
            if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
@@ -980,6 +979,7 @@ proc getcommitlines {fd inst view}  {
                    [vtokcmp $view [lindex $children($vp) end-1] $id] > 0} {
                    set children($vp) [lsort -command [list vtokcmp $view] \
                                           $children($vp)]
+                   catch {unset ordertok}
                }
            }
            if {[info exists varcid($view,$p)]} {
@@ -987,10 +987,6 @@ proc getcommitlines {fd inst view}  {
            }
            incr i
        }
-       if {[string compare $tok $vtokmod($view)] < 0} {
-           set vtokmod($view) $tok
-           set varcmod($view) $a
-       }
 
        incr commitidx($view)
        if {[info exists commitinterest($id)]} {
@@ -1002,7 +998,6 @@ proc getcommitlines {fd inst view}  {
        set gotsome 1
     }
     if {$gotsome} {
-       update_arcrows $view
        run chewcommits $view
        foreach s $scripts {
            eval $s
@@ -1939,7 +1934,7 @@ proc about {} {
     message $w.m -text {
 Gitk - a commit viewer for git
 
-Copyright © 2005-2006 Paul Mackerras
+Copyright © 2005-2007 Paul Mackerras
 
 Use and redistribute under the terms of the GNU General Public License} \
            -justify center -aspect 400 -border 2 -bg white -relief groove
@@ -2674,7 +2669,7 @@ proc addviewmenu {n} {
 }
 
 proc showview {n} {
-    global curview viewfiles cached_commitrow
+    global curview viewfiles cached_commitrow ordertok
     global displayorder parentlist rowidlist rowisopt rowfinal
     global colormap rowtextx nextcolor canvxmax
     global numcommits viewcomplete
@@ -2712,6 +2707,7 @@ proc showview {n} {
     }
     catch {unset commitinterest}
     catch {unset cached_commitrow}
+    catch {unset ordertok}
 
     set curview $n
     set selectedview $n
@@ -3303,24 +3299,73 @@ proc ntimes {n o} {
     return $ret
 }
 
+proc ordertoken {id} {
+    global ordertok curview varcid varcstart varctok curview parents children
+    global nullid nullid2
+
+    if {[info exists ordertok($id)]} {
+       return $ordertok($id)
+    }
+    set origid $id
+    set todo {}
+    while {1} {
+       if {[info exists varcid($curview,$id)]} {
+           set a $varcid($curview,$id)
+           set p [lindex $varcstart($curview) $a]
+       } else {
+           set p [lindex $children($curview,$id) 0]
+       }
+       if {[info exists ordertok($p)]} {
+           set tok $ordertok($p)
+           break
+       }
+       if {[llength $children($curview,$p)] == 0} {
+           # it's a root
+           set tok [lindex $varctok($curview) $a]
+           break
+       }
+       set id [lindex $children($curview,$p) 0]
+       if {$id eq $nullid || $id eq $nullid2} {
+           # XXX treat it as a root
+           set tok [lindex $varctok($curview) $a]
+           break
+       }
+       if {[llength $parents($curview,$id)] == 1} {
+           lappend todo [list $p {}]
+       } else {
+           set j [lsearch -exact $parents($curview,$id) $p]
+           if {$j < 0} {
+               puts "oops didn't find [shortids $p] in parents of [shortids $id]"
+           }
+           lappend todo [list $p [strrep $j]]
+       }
+    }
+    for {set i [llength $todo]} {[incr i -1] >= 0} {} {
+       set p [lindex $todo $i 0]
+       append tok [lindex $todo $i 1]
+       set ordertok($p) $tok
+    }
+    set ordertok($origid) $tok
+    return $tok
+}
+
 # Work out where id should go in idlist so that order-token
 # values increase from left to right
 proc idcol {idlist id {i 0}} {
-    global ordertok curview
-
-    set t $ordertok($curview,$id)
-    if {$i >= [llength $idlist] ||
-       $t < $ordertok($curview,[lindex $idlist $i])} {
+    set t [ordertoken $id]
+    if {$i < 0} {
+       set i 0
+    }
+    if {$i >= [llength $idlist] || $t < [ordertoken [lindex $idlist $i]]} {
        if {$i > [llength $idlist]} {
            set i [llength $idlist]
        }
-       while {[incr i -1] >= 0 &&
-              $t < $ordertok($curview,[lindex $idlist $i])} {}
+       while {[incr i -1] >= 0 && $t < [ordertoken [lindex $idlist $i]]} {}
        incr i
     } else {
-       if {$t > $ordertok($curview,[lindex $idlist $i])} {
+       if {$t > [ordertoken [lindex $idlist $i]]} {
            while {[incr i] < [llength $idlist] &&
-                  $t >= $ordertok($curview,[lindex $idlist $i])} {}
+                  $t >= [ordertoken [lindex $idlist $i]]} {}
        }
     }
     return $i
@@ -3375,30 +3420,20 @@ proc visiblerows {} {
 }
 
 proc layoutmore {} {
-    global commitidx viewcomplete numcommits
-    global uparrowlen downarrowlen mingaplen curview
-
-    set show $commitidx($curview)
-    if {$show > $numcommits || $viewcomplete($curview)} {
-       showstuff $show $viewcomplete($curview)
-    }
-}
-
-proc showstuff {canshow last} {
+    global commitidx viewcomplete curview
     global numcommits pending_select selectedline curview
-    global selectfirst
-    global lastscrollset commitinterest
+    global selectfirst lastscrollset commitinterest
 
+    set canshow $commitidx($curview)
+    if {$canshow <= $numcommits && !$viewcomplete($curview)} return
     if {$numcommits == 0} {
-       global phase
-       set phase "incrdraw"
        allcanvs delete all
     }
     set r0 $numcommits
     set prev $numcommits
     set numcommits $canshow
     set t [clock clicks -milliseconds]
-    if {$prev < 100 || $last || $t - $lastscrollset > 500} {
+    if {$prev < 100 || $viewcomplete($curview) || $t - $lastscrollset > 500} {
        set lastscrollset $t
        setcanvscroll
     }
@@ -3426,12 +3461,12 @@ proc showstuff {canshow last} {
 }
 
 proc doshowlocalchanges {} {
-    global curview mainheadid phase
+    global curview mainheadid
 
     if {[commitinview $mainheadid $curview]} {
        dodiffindex
-    } elseif {$phase ne {}} {
-       lappend commitinterest($mainheadid) {}
+    } else {
+       lappend commitinterest($mainheadid) {dodiffindex}
     }
 }
 
@@ -3553,7 +3588,7 @@ proc prevuse {id row} {
 
 proc make_idlist {row} {
     global displayorder parentlist uparrowlen downarrowlen mingaplen
-    global commitidx curview ordertok children
+    global commitidx curview children
 
     set r [expr {$row - $mingaplen - $downarrowlen - 1}]
     if {$r < 0} {
@@ -3576,7 +3611,7 @@ proc make_idlist {row} {
            set rn [nextuse $p $r]
            if {$rn >= $row &&
                $rn <= $r + $downarrowlen + $mingaplen + $uparrowlen} {
-               lappend ids [list $ordertok($curview,$p) $p]
+               lappend ids [list [ordertoken $p] $p]
            }
        }
     }
@@ -3586,17 +3621,17 @@ proc make_idlist {row} {
            if {$p eq $nextid} continue
            set rn [nextuse $p $r]
            if {$rn < 0 || $rn >= $row} {
-               lappend ids [list $ordertok($curview,$p) $p]
+               lappend ids [list [ordertoken $p] $p]
            }
        }
     }
     set id [lindex $displayorder $row]
-    lappend ids [list $ordertok($curview,$id) $id]
+    lappend ids [list [ordertoken $id] $id]
     while {$r < $rb} {
        foreach p [lindex $parentlist $r] {
            set firstkid [lindex $children($curview,$p) 0]
            if {[rowofcommit $firstkid] < $row} {
-               lappend ids [list $ordertok($curview,$p) $p]
+               lappend ids [list [ordertoken $p] $p]
            }
        }
        incr r
@@ -3604,7 +3639,7 @@ proc make_idlist {row} {
        if {$id ne {}} {
            set firstkid [lindex $children($curview,$id) 0]
            if {$firstkid ne {} && [rowofcommit $firstkid] < $row} {
-               lappend ids [list $ordertok($curview,$id) $id]
+               lappend ids [list [ordertoken $id] $id]
            }
        }
     }