From: Paul Mackerras Date: Sun, 2 Dec 2007 23:33:01 +0000 (+1100) Subject: gitk: Use git log without --topo-order and reorganize the commits ourselves X-Git-Tag: v1.5.6-rc0~20^2~45 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=7fcc92bff4f75b69d61d8d32a5326395c20ff587;p=git.git gitk: Use git log without --topo-order and reorganize the commits ourselves This very large patch implements code to organize the commits from git log into "arcs" (sequences of commits where each pair of adjacent commits are the only parent and child of each other), and orders the arcs so as to get a topological ordering of the commits. This means we can use git log without --topo-order and display the commits as we get them, incrementally, which makes the cold-cache start up time much faster, particularly on unpacked repos. One beneficial effect of this is that the File->Update menu item now just adds any new commits to the existing graph instead of rereading the whole thing from scratch, which is much faster. (If you do want to reread the whole graph from scratch you can use File->Reload.) At an implementation level, this means that the displayorder and parentlist lists are no longer fully valid at all times, and the commitrow array has gone. New procedures commitinview and commitonrow replace the commitrow array, and make_disporder ensures that displayorder and parentlist are valid for a range of rows. The overall time to load the kernel repository has gone up a bit, from ~9 seconds to ~11 seconds on my G5, but I think that is worth it given that the time to get a window up with commits displayed in it has gone from ~3 seconds to under 1 second. Signed-off-by: Paul Mackerras --- diff --git a/gitk b/gitk index 1da0b0af1..ea04a09a0 100755 --- a/gitk +++ b/gitk @@ -47,12 +47,24 @@ proc filereadable {fd script} { lappend runq [list $fd $script] } +proc nukefile {fd} { + global runq + + for {set i 0} {$i < [llength $runq]} {} { + if {[lindex $runq $i 0] eq $fd} { + set runq [lreplace $runq $i $i] + } else { + incr i + } + } +} + proc dorunq {} { global isonrunq runq set tstart [clock clicks -milliseconds] set t0 $tstart - while {$runq ne {}} { + while {[llength $runq] > 0} { set fd [lindex $runq 0 0] set script [lindex $runq 0 1] set repeat [eval $script] @@ -85,24 +97,34 @@ proc start_rev_list {view} { global viewargs viewfiles commitidx viewcomplete vnextroot global showlocalchanges commitinterest mainheadid global progressdirn progresscoords proglastnc curview + global viewincl viewactive loginstance viewinstances set startmsecs [clock clicks -milliseconds] set commitidx($view) 0 set viewcomplete($view) 0 + set viewactive($view) 1 set vnextroot($view) 0 - set order "--topo-order" - if {$datemode} { - set order "--date-order" + varcinit $view + + set commits [exec git rev-parse --default HEAD --revs-only \ + $viewargs($view)] + set viewincl($view) {} + foreach c $commits { + if {![string match "^*" $c]} { + lappend viewincl($view) $c + } } if {[catch { - set fd [open [concat | git log --no-color -z --pretty=raw $order --parents \ - --boundary $viewargs($view) "--" $viewfiles($view)] r] + set fd [open [concat | git log --no-color -z --pretty=raw --parents \ + --boundary $commits "--" $viewfiles($view)] r] } err]} { - error_popup "Error executing git rev-list: $err" + error_popup "Error executing git log: $err" exit 1 } - set commfd($view) $fd - set leftover($view) {} + set i [incr loginstance] + set viewinstances($view) [list $i] + set commfd($i) $fd + set leftover($i) {} if {$showlocalchanges} { lappend commitinterest($mainheadid) {dodiffindex} } @@ -110,7 +132,7 @@ proc start_rev_list {view} { if {$tclencoding != {}} { fconfigure $fd -encoding $tclencoding } - filerun $fd [list getcommitlines $fd $view] + filerun $fd [list getcommitlines $fd $i $view] nowbusy $view "Reading" if {$view == $curview} { set progressdirn 1 @@ -119,28 +141,115 @@ proc start_rev_list {view} { } } -proc stop_rev_list {} { - global commfd curview +proc stop_rev_list {view} { + global commfd viewinstances leftover - if {![info exists commfd($curview)]} return - set fd $commfd($curview) - catch { - set pid [pid $fd] - exec kill $pid + foreach inst $viewinstances($view) { + set fd $commfd($inst) + catch { + set pid [pid $fd] + exec kill $pid + } + catch {close $fd} + nukefile $fd + unset commfd($inst) + unset leftover($inst) } - catch {close $fd} - unset commfd($curview) + set viewinstances($view) {} } proc getcommits {} { - global phase canv curview + global canv curview - set phase getcommits initlayout start_rev_list $curview show_status "Reading commits..." } +proc updatecommits {} { + global curview viewargs viewfiles viewincl viewinstances + global viewactive viewcomplete loginstance tclencoding + global varcid startmsecs commfd getdbg showneartags leftover + + set getdbg 1 + set view $curview + set commits [exec git rev-parse --default HEAD --revs-only \ + $viewargs($view)] + set pos {} + set neg {} + foreach c $commits { + if {[string match "^*" $c]} { + lappend neg $c + } else { + if {!([info exists varcid($view,$c)] || + [lsearch -exact $viewincl($view) $c] >= 0)} { + lappend pos $c + } + } + } + if {$pos eq {}} { + return + } + foreach id $viewincl($view) { + lappend neg "^$id" + } + set viewincl($view) [concat $viewincl($view) $pos] + if {[catch { + set fd [open [concat | git log --no-color -z --pretty=raw --parents \ + --boundary $pos $neg "--" $viewfiles($view)] r] + } err]} { + error_popup "Error executing git log: $err" + exit 1 + } + if {$viewactive($view) == 0} { + set startmsecs [clock clicks -milliseconds] + } + set i [incr loginstance] + lappend viewinstances($view) $i + set commfd($i) $fd + set leftover($i) {} + fconfigure $fd -blocking 0 -translation lf -eofchar {} + if {$tclencoding != {}} { + fconfigure $fd -encoding $tclencoding + } + filerun $fd [list getcommitlines $fd $i $view] + incr viewactive($view) + set viewcomplete($view) 0 + nowbusy $view "Reading" + readrefs + changedrefs + if {$showneartags} { + getallcommits + } +} + +proc reloadcommits {} { + global curview viewcomplete selectedline currentid thickerline + global showneartags treediffs commitinterest cached_commitrow + global progresscoords + + if {!$viewcomplete($curview)} { + stop_rev_list $curview + set progresscoords {0 0} + adjustprogress + } + resetvarcs $curview + catch {unset selectedline} + catch {unset currentid} + catch {unset thickerline} + catch {unset treediffs} + readrefs + changedrefs + if {$showneartags} { + getallcommits + } + clear_display + catch {unset commitinterest} + catch {unset cached_commitrow} + setcanvscroll + getcommits +} + # This makes a string representation of a positive integer which # sorts as a string in numerical order proc strrep {n} { @@ -154,46 +263,585 @@ proc strrep {n} { return [format "z%.8x" $n] } -proc getcommitlines {fd view} { - global commitlisted commitinterest - global leftover commfd - global displayorder commitidx viewcomplete commitrow commitdata - global parentlist children curview hlview - global vparentlist vdisporder vcmitlisted +# Procedures used in reordering commits from git log (without +# --topo-order) into the order for display. + +proc varcinit {view} { + global vseeds varcstart vupptr vdownptr vleftptr varctok varcrow + global vtokmod varcmod varcix uat + + set vseeds($view) {} + set varcstart($view) {{}} + set vupptr($view) {0} + set vdownptr($view) {0} + set vleftptr($view) {0} + set varctok($view) {{}} + set varcrow($view) {{}} + set vtokmod($view) {} + set varcmod($view) 0 + set varcix($view) {{}} + set uat 0 +} + +proc resetvarcs {view} { + global varcid varccommits parents children vseedcount ordertok + + foreach vid [array names varcid $view,*] { + unset varcid($vid) + unset children($vid) + unset parents($vid) + } + # some commits might have children but haven't been seen yet + foreach vid [array names children $view,*] { + unset children($vid) + } + foreach va [array names varccommits $view,*] { + unset varccommits($va) + } + foreach vd [array names vseedcount $view,*] { + unset vseedcount($vd) + } + foreach vid [array names ordertok $view,*] { + unset ordertok($vid) + } +} + +proc newvarc {view id} { + global varcid varctok parents children vseeds + global vupptr vdownptr vleftptr varcrow varcix varcstart + global commitdata commitinfo vseedcount + + set a [llength $varctok($view)] + set vid $view,$id + if {[llength $children($vid)] == 0} { + if {![info exists commitinfo($id)]} { + parsecommit $id $commitdata($id) 1 + } + set cdate [lindex $commitinfo($id) 4] + if {![string is integer -strict $cdate]} { + set cdate 0 + } + if {![info exists vseedcount($view,$cdate)]} { + set vseedcount($view,$cdate) -1 + } + set c [incr vseedcount($view,$cdate)] + set cdate [expr {$cdate ^ 0xffffffff}] + set tok "s[strrep $cdate][strrep $c]" + lappend vseeds($view) $id + lappend vupptr($view) 0 + set ka [lindex $vdownptr($view) 0] + if {$ka == 0 || + [string compare $tok [lindex $varctok($view) $ka]] < 0} { + lset vdownptr($view) 0 $a + lappend vleftptr($view) $ka + } else { + while {[set b [lindex $vleftptr($view) $ka]] != 0 && + [string compare $tok [lindex $varctok($view) $b]] >= 0} { + set ka $b + } + lset vleftptr($view) $ka $a + lappend vleftptr($view) $b + } + } else { + set tok {} + foreach k $children($vid) { + set ka $varcid($view,$k) + if {[string compare [lindex $varctok($view) $ka] $tok] > 0} { + set ki $k + set tok [lindex $varctok($view) $ka] + } + } + set ka $varcid($view,$ki) + lappend vupptr($view) $ka + set i [lsearch -exact $parents($view,$ki) $id] + set j [expr {[llength $parents($view,$ki)] - 1 - $i}] + set rsib 0 + while {[incr i] < [llength $parents($view,$ki)]} { + set bi [lindex $parents($view,$ki) $i] + if {[info exists varcid($view,$bi)]} { + set b $varcid($view,$bi) + if {[lindex $vupptr($view) $b] == $ka} { + set rsib $b + lappend vleftptr($view) [lindex $vleftptr($view) $b] + lset vleftptr($view) $b $a + break + } + } + } + if {$rsib == 0} { + lappend vleftptr($view) [lindex $vdownptr($view) $ka] + lset vdownptr($view) $ka $a + } + append tok [strrep $j] + } + lappend varctok($view) $tok + lappend varcstart($view) $id + lappend vdownptr($view) 0 + lappend varcrow($view) {} + lappend varcix($view) {} + return $a +} + +proc splitvarc {p v} { + global varcid varcstart varccommits varctok + global vupptr vdownptr vleftptr varcix varcrow + + set oa $varcid($v,$p) + set ac $varccommits($v,$oa) + set i [lsearch -exact $varccommits($v,$oa) $p] + if {$i <= 0} return + set na [llength $varctok($v)] + # "%" sorts before "0"... + set tok "[lindex $varctok($v) $oa]%[strrep $i]" + lappend varctok($v) $tok + lappend varcrow($v) {} + lappend varcix($v) {} + set varccommits($v,$oa) [lrange $ac 0 [expr {$i - 1}]] + set varccommits($v,$na) [lrange $ac $i end] + lappend varcstart($v) $p + foreach id $varccommits($v,$na) { + set varcid($v,$id) $na + } + lappend vdownptr($v) [lindex $vdownptr($v) $oa] + lset vdownptr($v) $oa $na + lappend vupptr($v) $oa + lappend vleftptr($v) 0 + for {set b [lindex $vdownptr($v) $na]} {$b != 0} {set b [lindex $vleftptr($v) $b]} { + lset vupptr($v) $b $na + } +} + +proc renumbervarc {a v} { + global parents children varctok varcstart varccommits + global vupptr vdownptr vleftptr varcid vtokmod varcmod + + set t1 [clock clicks -milliseconds] + set todo {} + set isrelated($a) 1 + set ntot 0 + while {$a != 0} { + if {[info exists isrelated($a)]} { + lappend todo $a + set id [lindex $varccommits($v,$a) end] + foreach p $parents($v,$id) { + if {[info exists varcid($v,$p)]} { + set isrelated($varcid($v,$p)) 1 + } + } + } + incr ntot + set b [lindex $vdownptr($v) $a] + if {$b == 0} { + while {$a != 0} { + set b [lindex $vleftptr($v) $a] + if {$b != 0} break + set a [lindex $vupptr($v) $a] + } + } + set a $b + } + foreach a $todo { + set id [lindex $varcstart($v) $a] + set tok {} + foreach k $children($v,$id) { + set ka $varcid($v,$k) + if {[string compare [lindex $varctok($v) $ka] $tok] > 0} { + set ki $k + set tok [lindex $varctok($v) $ka] + } + } + if {$tok ne {}} { + set ka $varcid($v,$ki) + set i [lsearch -exact $parents($v,$ki) $id] + set j [expr {[llength $parents($v,$ki)] - 1 - $i}] + append tok [strrep $j] + set oldtok [lindex $varctok($v) $a] + if {$tok eq $oldtok} continue + lset varctok($v) $a $tok + } else { + set ka 0 + } + set b [lindex $vupptr($v) $a] + if {$b != $ka} { + set c [lindex $vdownptr($v) $b] + if {$c == $a} { + lset vdownptr($v) $b [lindex $vleftptr($v) $a] + } else { + set b $c + while {$b != 0 && [lindex $vleftptr($v) $b] != $a} { + set b [lindex $vleftptr($v) $b] + } + if {$b != 0} { + lset vleftptr($v) $b [lindex $vleftptr($v) $a] + } else { + puts "oops couldn't find $a in chain for [lindex $vupptr($v) $a]" + } + } + lset vupptr($v) $a $ka + set rsib 0 + while {[incr i] < [llength $parents($v,$ki)]} { + set bi [lindex $parents($v,$ki) $i] + if {[info exists varcid($v,$bi)]} { + set b $varcid($v,$bi) + if {[lindex $vupptr($v) $b] == $ka} { + set rsib $b + lset vleftptr($v) $a [lindex $vleftptr($v) $b] + lset vleftptr($v) $b $a + break + } + } + } + if {$rsib == 0} { + lset vleftptr($v) $a [lindex $vdownptr($v) $ka] + lset vdownptr($v) $ka $a + } + } + } + set t2 [clock clicks -milliseconds] + #puts "renumbervarc did [llength $todo] of $ntot arcs in [expr {$t2-$t1}]ms" +} + +proc fix_reversal {p a v} { + global varcid varcstart varctok vupptr vseeds + + set pa $varcid($v,$p) + if {$p ne [lindex $varcstart($v) $pa]} { + splitvarc $p $v + set pa $varcid($v,$p) + } + # seeds always need to be renumbered (and taken out of the seeds list) + if {[lindex $vupptr($v) $pa] == 0} { + set i [lsearch -exact $vseeds($v) $p] + if {$i >= 0} { + set vseeds($v) [lreplace $vseeds($v) $i $i] + } else { + puts "oops couldn't find [shortids $p] in seeds" + } + renumbervarc $pa $v + } elseif {[string compare [lindex $varctok($v) $a] \ + [lindex $varctok($v) $pa]] > 0} { + renumbervarc $pa $v + } +} + +proc insertrow {id p v} { + global varcid varccommits parents children cmitlisted ordertok + global commitidx varctok vtokmod varcmod + + set a $varcid($v,$p) + set i [lsearch -exact $varccommits($v,$a) $p] + if {$i < 0} { + puts "oops: insertrow can't find [shortids $p] on arc $a" + return + } + 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)] + } + 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 + } + update_arcrows $v +} + +proc removerow {id v} { + global varcid varccommits parents children commitidx ordertok + global varctok vtokmod varcmod + + if {[llength $parents($v,$id)] != 1} { + puts "oops: removerow [shortids $id] has [llength $parents($v,$id)] parents" + return + } + set p [lindex $parents($v,$id) 0] + set a $varcid($v,$id) + set i [lsearch -exact $varccommits($v,$a) $id] + if {$i < 0} { + puts "oops: removerow can't find [shortids $id] on arc $a" + return + } + unset varcid($v,$id) + set varccommits($v,$a) [lreplace $varccommits($v,$a) $i $i] + 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 + } + update_arcrows $v +} + +proc vtokcmp {v a b} { + global varctok varcid + + return [string compare [lindex $varctok($v) $varcid($v,$a)] \ + [lindex $varctok($v) $varcid($v,$b)]] +} + +proc update_arcrows {v} { + global vtokmod varcmod varcrow commitidx currentid selectedline + global varcid vseeds vrownum varcorder varcix varccommits + global vupptr vdownptr vleftptr varctok + global uat displayorder parentlist curview cached_commitrow + + set t1 [clock clicks -milliseconds] + set narctot [expr {[llength $varctok($v)] - 1}] + set a $varcmod($v) + while {$a != 0 && [lindex $varcix($v) $a] eq {}} { + # go up the tree until we find something that has a row number, + # or we get to a seed + set a [lindex $vupptr($v) $a] + } + if {$a == 0} { + set a [lindex $vdownptr($v) 0] + if {$a == 0} return + set vrownum($v) {0} + set varcorder($v) [list $a] + lset varcix($v) $a 0 + lset varcrow($v) $a 0 + set arcn 0 + set row 0 + } else { + set arcn [lindex $varcix($v) $a] + # see if a is the last arc; if so, nothing to do + if {$arcn == $narctot - 1} { + return + } + if {[llength $vrownum($v)] > $arcn + 1} { + set vrownum($v) [lrange $vrownum($v) 0 $arcn] + set varcorder($v) [lrange $varcorder($v) 0 $arcn] + } + 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} { + catch {unset cached_commitrow} + } + set startrow $row + while {1} { + set p $a + incr row [llength $varccommits($v,$a)] + # go down if possible + set b [lindex $vdownptr($v) $a] + if {$b == 0} { + # if not, go left, or go up until we can go left + while {$a != 0} { + set b [lindex $vleftptr($v) $a] + if {$b != 0} break + set a [lindex $vupptr($v) $a] + } + if {$a == 0} break + } + set a $b + incr arcn + lappend vrownum($v) $row + lappend varcorder($v) $a + lset varcix($v) $a $arcn + lset varcrow($v) $a $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}] +} + +# Test whether view $v contains commit $id +proc commitinview {id v} { + global varcid + + return [info exists varcid($v,$id)] +} + +# Return the row number for commit $id in the current view +proc rowofcommit {id} { + global varcid varccommits varcrow curview cached_commitrow + + if {[info exists cached_commitrow($id)]} { + return $cached_commitrow($id) + } + set v $curview + if {![info exists varcid($v,$id)]} { + puts "oops rowofcommit no arc for [shortids $id]" + return {} + } + set a $varcid($v,$id) + set i [lsearch -exact $varccommits($v,$a) $id] + if {$i < 0} { + puts "oops didn't find commit [shortids $id] in arc $a" + return {} + } + incr i [lindex $varcrow($v) $a] + set cached_commitrow($id) $i + return $i +} + +proc bsearch {l elt} { + if {[llength $l] == 0 || $elt <= [lindex $l 0]} { + return 0 + } + set lo 0 + set hi [llength $l] + while {$hi - $lo > 1} { + set mid [expr {int(($lo + $hi) / 2)}] + set t [lindex $l $mid] + if {$elt < $t} { + set hi $mid + } elseif {$elt > $t} { + set lo $mid + } else { + return $mid + } + } + return $lo +} + +# 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 d_valid_start d_valid_end + + set ai [bsearch $vrownum($curview) $start] + set start [lindex $vrownum($curview) $ai] + set narc [llength $vrownum($curview)] + for {set r $start} {$ai < $narc && $r < $end} {incr ai} { + set a [lindex $varcorder($curview) $ai] + set l [llength $displayorder] + set al [llength $varccommits($curview,$a)] + if {$l < $r + $al} { + if {$l < $r} { + set pad [ntimes [expr {$r - $l}] {}] + set displayorder [concat $displayorder $pad] + set parentlist [concat $parentlist $pad] + } elseif {$l > $r} { + set displayorder [lrange $displayorder 0 [expr {$r - 1}]] + set parentlist [lrange $parentlist 0 [expr {$r - 1}]] + } + foreach id $varccommits($curview,$a) { + lappend displayorder $id + lappend parentlist $parents($curview,$id) + } + } elseif {[lindex $displayorder $r] eq {}} { + set i $r + foreach id $varccommits($curview,$a) { + lset displayorder $i $id + lset parentlist $i $parents($curview,$id) + incr i + } + } + incr r $al + } +} + +proc commitonrow {row} { + global displayorder + + set id [lindex $displayorder $row] + if {$id eq {}} { + make_disporder $row [expr {$row + 1}] + set id [lindex $displayorder $row] + } + return $id +} + +proc closevarcs {v} { + global varctok varccommits varcid parents children + global cmitlisted commitidx commitinterest vtokmod varcmod + + set missing_parents 0 + set scripts {} + set narcs [llength $varctok($v)] + for {set a 1} {$a < $narcs} {incr a} { + set id [lindex $varccommits($v,$a) end] + foreach p $parents($v,$id) { + if {[info exists varcid($v,$p)]} continue + # add p as a new commit + incr missing_parents + set cmitlisted($v,$p) 0 + set parents($v,$p) {} + if {[llength $children($v,$p)] == 1 && + [llength $parents($v,$id)] == 1} { + set b $a + } else { + 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 + } + incr commitidx($v) + if {[info exists commitinterest($p)]} { + foreach script $commitinterest($p) { + lappend scripts [string map [list "%I" $p] $script] + } + unset commitinterest($id) + } + } + } + if {$missing_parents > 0} { + update_arcrows $v + foreach s $scripts { + eval $s + } + } +} + +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 set stuff [read $fd 500000] # git log doesn't terminate the last commit with a null... - if {$stuff == {} && $leftover($view) ne {} && [eof $fd]} { + if {$stuff == {} && $leftover($inst) ne {} && [eof $fd]} { set stuff "\0" } if {$stuff == {}} { if {![eof $fd]} { return 1 } - # Check if we have seen any ids listed as parents that haven't - # appeared in the list - foreach vid [array names idpending "$view,*"] { - # should only get here if git log is buggy - set id [lindex [split $vid ","] 1] - set commitrow($vid) $commitidx($view) - incr commitidx($view) - if {$view == $curview} { - lappend parentlist {} - lappend displayorder $id - lappend commitlisted 0 - } else { - lappend vparentlist($view) {} - lappend vdisporder($view) $id - lappend vcmitlisted($view) 0 - } + global commfd viewcomplete viewactive viewname progresscoords + global viewinstances + unset commfd($inst) + set i [lsearch -exact $viewinstances($view) $inst] + if {$i >= 0} { + set viewinstances($view) [lreplace $viewinstances($view) $i $i] } - set viewcomplete($view) 1 - global viewname progresscoords - unset commfd($view) - notbusy $view - set progresscoords {0 0} - adjustprogress # set it blocking so we wait for the process to terminate fconfigure $fd -blocking 1 if {[catch {close $fd} err]} { @@ -214,6 +862,15 @@ proc getcommitlines {fd view} { } error_popup $err } + if {[incr viewactive($view) -1] <= 0} { + set viewcomplete($view) 1 + # Check if we have seen any ids listed as parents that haven't + # appeared in the list + closevarcs $view + notbusy $view + set progresscoords {0 0} + adjustprogress + } if {$view == $curview} { run chewcommits $view } @@ -221,16 +878,17 @@ proc getcommitlines {fd view} { } set start 0 set gotsome 0 + set scripts {} while 1 { set i [string first "\0" $stuff $start] if {$i < 0} { - append leftover($view) [string range $stuff $start end] + append leftover($inst) [string range $stuff $start end] break } if {$start == 0} { - set cmit $leftover($view) + set cmit $leftover($inst) append cmit [string range $stuff 0 [expr {$i - 1}]] - set leftover($view) {} + set leftover($inst) {} } else { set cmit [string range $stuff $start [expr {$i - 1}]] } @@ -265,32 +923,27 @@ proc getcommitlines {fd view} { exit 1 } set id [lindex $ids 0] - if {![info exists ordertok($view,$id)]} { + 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($view,$id) $otok + set ordertok($vid) $otok } else { - set otok $ordertok($view,$id) - unset idpending($view,$id) + set otok $ordertok($vid) } if {$listed} { set olds [lrange $ids 1 end] if {[llength $olds] == 1} { set p [lindex $olds 0] - lappend children($view,$p) $id if {![info exists ordertok($view,$p)]} { - set ordertok($view,$p) $ordertok($view,$id) - set idpending($view,$p) 1 + set ordertok($view,$p) $ordertok($vid) } } else { set i 0 foreach p $olds { - if {$i == 0 || [lsearch -exact $olds $p] >= $i} { - lappend children($view,$p) $id - } if {![info exists ordertok($view,$p)]} { set ordertok($view,$p) "$otok[strrep $i]]" - set idpending($view,$p) 1 } incr i } @@ -298,31 +951,62 @@ proc getcommitlines {fd view} { } else { set olds {} } - if {![info exists children($view,$id)]} { - set children($view,$id) {} - } set commitdata($id) [string range $cmit [expr {$j + 1}] end] - set commitrow($view,$id) $commitidx($view) - incr commitidx($view) - if {$view == $curview} { - lappend parentlist $olds - lappend displayorder $id - lappend commitlisted $listed + set cmitlisted($vid) $listed + set parents($vid) $olds + set a 0 + if {![info exists children($vid)]} { + set children($vid) {} } else { - lappend vparentlist($view) $olds - lappend vdisporder($view) $id - lappend vcmitlisted($view) $listed + if {[llength $children($vid)] == 1} { + set k [lindex $children($vid) 0] + if {[llength $parents($view,$k)] == 1} { + set a $varcid($view,$k) + } + } } + if {$a == 0} { + # new arc + set a [newvarc $view $id] + } + set varcid($vid) $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} { + set vp $view,$p + if {[llength [lappend children($vp) $id]] > 1 && + [vtokcmp $view [lindex $children($vp) end-1] $id] > 0} { + set children($vp) [lsort -command [list vtokcmp $view] \ + $children($vp)] + } + } + if {[info exists varcid($view,$p)]} { + fix_reversal $p $a $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)]} { foreach script $commitinterest($id) { - eval [string map [list "%I" $id] $script] + lappend scripts [string map [list "%I" $id] $script] } unset commitinterest($id) } set gotsome 1 } if {$gotsome} { + update_arcrows $view run chewcommits $view + foreach s $scripts { + eval $s + } if {$view == $curview} { # update progress bar global progressdirn progresscoords proglastnc @@ -356,13 +1040,14 @@ proc getcommitlines {fd view} { proc chewcommits {view} { global curview hlview viewcomplete - global selectedline pending_select + global pending_select if {$view == $curview} { layoutmore if {$viewcomplete($view)} { - global displayorder commitidx phase + global commitidx global numcommits startmsecs + global mainheadid commitinfo nullid if {[info exists pending_select]} { set row [first_real_row] @@ -371,11 +1056,12 @@ proc chewcommits {view} { if {$commitidx($curview) > 0} { #set ms [expr {[clock clicks -milliseconds] - $startmsecs}] #puts "overall $ms ms for $numcommits commits" + #global uat + #puts "${uat}ms in update_arcrows" } else { show_status "No commits selected" } notbusy layout - set phase {} } } if {[info exists hlview] && $view == $hlview} { @@ -389,35 +1075,6 @@ proc readcommit {id} { parsecommit $id $contents 0 } -proc updatecommits {} { - global viewdata curview phase displayorder ordertok idpending - global children commitrow selectedline thickerline showneartags - - if {$phase ne {}} { - stop_rev_list - set phase {} - } - set n $curview - foreach id $displayorder { - catch {unset children($n,$id)} - catch {unset commitrow($n,$id)} - catch {unset ordertok($n,$id)} - } - foreach vid [array names idpending "$n,*"] { - unset idpending($vid) - } - set curview -1 - catch {unset selectedline} - catch {unset thickerline} - catch {unset viewdata($n)} - readrefs - changedrefs - if {$showneartags} { - getallcommits - } - showview $n -} - proc parsecommit {id contents listed} { global commitinfo cdate @@ -544,10 +1201,10 @@ proc readrefs {} { # skip over fake commits proc first_real_row {} { - global nullid nullid2 displayorder numcommits + global nullid nullid2 numcommits for {set row 0} {$row < $numcommits} {incr row} { - set id [lindex $displayorder $row] + set id [commitonrow $row] if {$id ne $nullid && $id ne $nullid2} { break } @@ -634,6 +1291,7 @@ proc makewindow {} { .bar configure -font uifont menu .bar.file .bar.file add command -label "Update" -command updatecommits + .bar.file add command -label "Reload" -command reloadcommits .bar.file add command -label "Reread references" -command rereadrefs .bar.file add command -label "List references" -command showrefs .bar.file add command -label "Quit" -command doquit @@ -1643,7 +2301,7 @@ image create bitmap reficon-o -background black -foreground "#ddddff" \ -data $rectdata -maskdata $rectmask proc init_flist {first} { - global cflist cflist_top selectedline difffilestart + global cflist cflist_top difffilestart $cflist conf -state normal $cflist delete 0.0 end @@ -1986,7 +2644,7 @@ proc newviewok {top n} { set viewfiles($n) $files set viewargs($n) $newargs if {$curview == $n} { - run updatecommits + run reloadcommits } } } @@ -1994,7 +2652,7 @@ proc newviewok {top n} { } proc delview {} { - global curview viewdata viewperm hlview selectedhlview + global curview viewperm hlview selectedhlview if {$curview == 0} return if {[info exists hlview] && $hlview == $curview} { @@ -2002,7 +2660,6 @@ proc delview {} { unset hlview } allviewmenus $curview delete - set viewdata($curview) {} set viewperm($curview) 0 showview 0 } @@ -2016,52 +2673,30 @@ proc addviewmenu {n} { # -command [list addvhighlight $n] -variable selectedhlview } -proc flatten {var} { - global $var - - set ret {} - foreach i [array names $var] { - lappend ret $i [set $var\($i\)] - } - return $ret -} - -proc unflatten {var l} { - global $var - - catch {unset $var} - foreach {i v} $l { - set $var\($i\) $v - } -} - proc showview {n} { - global curview viewdata viewfiles + global curview viewfiles cached_commitrow global displayorder parentlist rowidlist rowisopt rowfinal - global colormap rowtextx commitrow nextcolor canvxmax - global numcommits commitlisted + global colormap rowtextx nextcolor canvxmax + global numcommits viewcomplete global selectedline currentid canv canvy0 global treediffs - global pending_select phase + global pending_select global commitidx - global commfd global selectedview selectfirst - global vparentlist vdisporder vcmitlisted global hlview selectedhlview commitinterest if {$n == $curview} return set selid {} + set ymax [lindex [$canv cget -scrollregion] 3] + set span [$canv yview] + set ytop [expr {[lindex $span 0] * $ymax}] + set ybot [expr {[lindex $span 1] * $ymax}] + set yscreen [expr {($ybot - $ytop) / 2}] if {[info exists selectedline]} { set selid $currentid set y [yc $selectedline] - set ymax [lindex [$canv cget -scrollregion] 3] - set span [$canv yview] - set ytop [expr {[lindex $span 0] * $ymax}] - set ybot [expr {[lindex $span 1] * $ymax}] if {$ytop < $y && $y < $ybot} { set yscreen [expr {$y - $ytop}] - } else { - set yscreen [expr {($ybot - $ytop) / 2}] } } elseif {[info exists pending_select]} { set selid $pending_select @@ -2069,17 +2704,6 @@ proc showview {n} { } unselectline normalline - if {$curview >= 0} { - set vparentlist($curview) $parentlist - set vdisporder($curview) $displayorder - set vcmitlisted($curview) $commitlisted - if {$phase ne {} || - ![info exists viewdata($curview)] || - [lindex $viewdata($curview) 0] ne {}} { - set viewdata($curview) \ - [list $phase $rowidlist $rowisopt $rowfinal] - } - } catch {unset treediffs} clear_display if {[info exists hlview] && $hlview == $n} { @@ -2087,6 +2711,7 @@ proc showview {n} { set selectedhlview None } catch {unset commitinterest} + catch {unset cached_commitrow} set curview $n set selectedview $n @@ -2094,7 +2719,7 @@ proc showview {n} { .bar.view entryconf Delete* -state [expr {$n == 0? "disabled": "normal"}] run refill_reflist - if {![info exists viewdata($n)]} { + if {![info exists viewcomplete($n)]} { if {$selid ne {}} { set pending_select $selid } @@ -2102,14 +2727,11 @@ proc showview {n} { return } - set v $viewdata($n) - set phase [lindex $v 0] - set displayorder $vdisporder($n) - set parentlist $vparentlist($n) - set commitlisted $vcmitlisted($n) - set rowidlist [lindex $v 1] - set rowisopt [lindex $v 2] - set rowfinal [lindex $v 3] + set displayorder {} + set parentlist {} + set rowidlist {} + set rowisopt {} + set rowfinal {} set numcommits $commitidx($n) catch {unset colormap} @@ -2122,8 +2744,8 @@ proc showview {n} { set yf 0 set row {} set selectfirst 0 - if {$selid ne {} && [info exists commitrow($n,$selid)]} { - set row $commitrow($n,$selid) + if {$selid ne {} && [commitinview $selid $n]} { + set row [rowofcommit $selid] # try to get the selected row in the same position on the screen set ymax [lindex [$canv cget -scrollregion] 3] set ytop [expr {[yc $row] - $yscreen}] @@ -2146,11 +2768,12 @@ proc showview {n} { set selectfirst 1 } } - if {$phase ne {}} { - if {$phase eq "getcommits"} { + if {!$viewcomplete($n)} { + if {$numcommits == 0} { show_status "Reading commits..." + } else { + run chewcommits $n } - run chewcommits $n } elseif {$numcommits == 0} { show_status "No commits selected" } @@ -2219,17 +2842,13 @@ proc unbolden {} { } proc addvhighlight {n} { - global hlview curview viewdata vhl_done vhighlights commitidx + global hlview viewcomplete curview vhl_done vhighlights commitidx if {[info exists hlview]} { delvhighlight } set hlview $n - if {$n != $curview && ![info exists viewdata($n)]} { - set viewdata($n) [list getcommits {{}} 0 0 0] - set vparentlist($n) {} - set vdisporder($n) {} - set vcmitlisted($n) {} + if {$n != $curview && ![info exists viewcomplete($n)]} { start_rev_list $n } set vhl_done $commitidx($hlview) @@ -2248,22 +2867,16 @@ proc delvhighlight {} { } proc vhighlightmore {} { - global hlview vhl_done commitidx vhighlights - global displayorder vdisporder curview + global hlview vhl_done commitidx vhighlights curview set max $commitidx($hlview) - if {$hlview == $curview} { - set disp $displayorder - } else { - set disp $vdisporder($hlview) - } set vr [visiblerows] set r0 [lindex $vr 0] set r1 [lindex $vr 1] for {set i $vhl_done} {$i < $max} {incr i} { - set id [lindex $disp $i] - if {[info exists commitrow($curview,$id)]} { - set row $commitrow($curview,$id) + set id [commitonrow $i $hlview] + if {[commitinview $id $curview]} { + set row [rowofcommit $id] if {$r0 <= $row && $row <= $r1} { if {![highlighted $row]} { bolden $row mainfontbold @@ -2276,9 +2889,9 @@ proc vhighlightmore {} { } proc askvhighlight {row id} { - global hlview vhighlights commitrow iddrawn + global hlview vhighlights iddrawn - if {[info exists commitrow($hlview,$id)]} { + if {[commitinview $id $hlview]} { if {[info exists iddrawn($id)] && ![ishighlighted $row]} { bolden $row mainfontbold } @@ -2427,7 +3040,7 @@ proc askfilehighlight {row id} { } proc readfhighlight {} { - global filehighlight fhighlights commitrow curview iddrawn + global filehighlight fhighlights curview iddrawn global fhl_list find_dirn if {![info exists filehighlight]} { @@ -2440,14 +3053,14 @@ proc readfhighlight {} { if {$i < 0} continue for {set j 0} {$j < $i} {incr j} { set id [lindex $fhl_list $j] - if {[info exists commitrow($curview,$id)]} { - set fhighlights($commitrow($curview,$id)) 0 + if {[commitinview $id $curview]} { + set fhighlights([rowofcommit $id]) 0 } } set fhl_list [lrange $fhl_list [expr {$i+1}] end] if {$line eq {}} continue - if {![info exists commitrow($curview,$line)]} continue - set row $commitrow($curview,$line) + if {![commitinview $line $curview]} continue + set row [rowofcommit $line] if {[info exists iddrawn($line)] && ![ishighlighted $row]} { bolden $row mainfontbold } @@ -2568,16 +3181,16 @@ proc rhighlight_none {} { } proc is_descendent {a} { - global curview children commitrow descendent desc_todo + global curview children descendent desc_todo set v $curview - set la $commitrow($v,$a) + set la [rowofcommit $a] set todo $desc_todo set leftover {} set done 0 for {set i 0} {$i < [llength $todo]} {incr i} { set do [lindex $todo $i] - if {$commitrow($v,$do) < $la} { + if {[rowofcommit $do] < $la} { lappend leftover $do continue } @@ -2600,20 +3213,20 @@ proc is_descendent {a} { } proc is_ancestor {a} { - global curview parentlist commitrow ancestor anc_todo + global curview parents ancestor anc_todo set v $curview - set la $commitrow($v,$a) + set la [rowofcommit $a] set todo $anc_todo set leftover {} set done 0 for {set i 0} {$i < [llength $todo]} {incr i} { set do [lindex $todo $i] - if {![info exists commitrow($v,$do)] || $commitrow($v,$do) > $la} { + if {![commitinview $do $v] || [rowofcommit $do] > $la} { lappend leftover $do continue } - foreach np [lindex $parentlist $commitrow($v,$do)] { + foreach np $parents($v,$do) { if {![info exists ancestor($np)]} { set ancestor($np) 1 lappend todo $np @@ -2714,16 +3327,14 @@ proc idcol {idlist id {i 0}} { } proc initlayout {} { - global rowidlist rowisopt rowfinal displayorder commitlisted + global rowidlist rowisopt rowfinal displayorder parentlist global numcommits canvxmax canv global nextcolor - global parentlist global colormap rowtextx global selectfirst set numcommits 0 set displayorder {} - set commitlisted {} set parentlist {} set nextcolor 0 set rowidlist {} @@ -2774,8 +3385,8 @@ proc layoutmore {} { } proc showstuff {canshow last} { - global numcommits commitrow pending_select selectedline curview - global mainheadid displayorder selectfirst + global numcommits pending_select selectedline curview + global selectfirst global lastscrollset commitinterest if {$numcommits == 0} { @@ -2800,9 +3411,8 @@ proc showstuff {canshow last} { drawcommits $r0 $r1 } if {[info exists pending_select] && - [info exists commitrow($curview,$pending_select)] && - $commitrow($curview,$pending_select) < $numcommits} { - selectline $commitrow($curview,$pending_select) 1 + [commitinview $pending_select $curview]} { + selectline [rowofcommit $pending_select] 1 } if {$selectfirst} { if {[info exists selectedline] || [info exists pending_select]} { @@ -2816,10 +3426,9 @@ proc showstuff {canshow last} { } proc doshowlocalchanges {} { - global curview mainheadid phase commitrow + global curview mainheadid phase - if {[info exists commitrow($curview,$mainheadid)] && - ($phase eq {} || $commitrow($curview,$mainheadid) < $numcommits - 1)} { + if {[commitinview $mainheadid $curview]} { dodiffindex } elseif {$phase ne {}} { lappend commitinterest($mainheadid) {} @@ -2827,38 +3436,30 @@ proc doshowlocalchanges {} { } proc dohidelocalchanges {} { - global localfrow localirow lserial + global nullid nullid2 lserial curview - if {$localfrow >= 0} { - removerow $localfrow - set localfrow -1 - if {$localirow > 0} { - incr localirow -1 - } + if {[commitinview $nullid $curview]} { + removerow $nullid $curview } - if {$localirow >= 0} { - removerow $localirow - set localirow -1 + if {[commitinview $nullid2 $curview]} { + removerow $nullid2 $curview } incr lserial } # spawn off a process to do git diff-index --cached HEAD proc dodiffindex {} { - global localirow localfrow lserial showlocalchanges + global lserial showlocalchanges if {!$showlocalchanges} return incr lserial - set localfrow -1 - set localirow -1 set fd [open "|git diff-index --cached HEAD" r] fconfigure $fd -blocking 0 filerun $fd [list readdiffindex $fd $lserial] } proc readdiffindex {fd serial} { - global localirow commitrow mainheadid nullid2 curview - global commitinfo commitdata lserial + global mainheadid nullid2 curview commitinfo commitdata lserial set isdiff 1 if {[gets $fd line] < 0} { @@ -2877,19 +3478,18 @@ proc readdiffindex {fd serial} { filerun $fd [list readdifffiles $fd $serial] } - if {$isdiff && $serial == $lserial && $localirow == -1} { + if {$isdiff && $serial == $lserial && ![commitinview $nullid2 $curview]} { # add the line for the changes in the index to the graph - set localirow $commitrow($curview,$mainheadid) set hl "Local changes checked in to index but not committed" set commitinfo($nullid2) [list $hl {} {} {} {} " $hl\n"] set commitdata($nullid2) "\n $hl\n" - insertrow $localirow $nullid2 + insertrow $nullid2 $mainheadid $curview } return 0 } proc readdifffiles {fd serial} { - global localirow localfrow commitrow mainheadid nullid curview + global mainheadid nullid nullid2 curview global commitinfo commitdata lserial set isdiff 1 @@ -2902,50 +3502,49 @@ proc readdifffiles {fd serial} { # we only need to see one line and we don't really care what it says... close $fd - if {$isdiff && $serial == $lserial && $localfrow == -1} { + if {$isdiff && $serial == $lserial && ![commitinview $nullid $curview]} { # add the line for the local diff to the graph - if {$localirow >= 0} { - set localfrow $localirow - incr localirow - } else { - set localfrow $commitrow($curview,$mainheadid) - } set hl "Local uncommitted changes, not checked in to index" set commitinfo($nullid) [list $hl {} {} {} {} " $hl\n"] set commitdata($nullid) "\n $hl\n" - insertrow $localfrow $nullid + if {[commitinview $nullid2 $curview]} { + set p $nullid2 + } else { + set p $mainheadid + } + insertrow $nullid $p $curview } return 0 } proc nextuse {id row} { - global commitrow curview children + global curview children if {[info exists children($curview,$id)]} { foreach kid $children($curview,$id) { - if {![info exists commitrow($curview,$kid)]} { + if {![commitinview $kid $curview]} { return -1 } - if {$commitrow($curview,$kid) > $row} { - return $commitrow($curview,$kid) + if {[rowofcommit $kid] > $row} { + return [rowofcommit $kid] } } } - if {[info exists commitrow($curview,$id)]} { - return $commitrow($curview,$id) + if {[commitinview $id $curview]} { + return [rowofcommit $id] } return -1 } proc prevuse {id row} { - global commitrow curview children + global curview children set ret -1 if {[info exists children($curview,$id)]} { foreach kid $children($curview,$id) { - if {![info exists commitrow($curview,$kid)]} break - if {$commitrow($curview,$kid) < $row} { - set ret $commitrow($curview,$kid) + if {![commitinview $kid $curview]} break + if {[rowofcommit $kid] < $row} { + set ret [rowofcommit $kid] } } } @@ -2954,7 +3553,7 @@ proc prevuse {id row} { proc make_idlist {row} { global displayorder parentlist uparrowlen downarrowlen mingaplen - global commitidx curview ordertok children commitrow + global commitidx curview ordertok children set r [expr {$row - $mingaplen - $downarrowlen - 1}] if {$r < 0} { @@ -2968,6 +3567,7 @@ proc make_idlist {row} { if {$rb > $commitidx($curview)} { set rb $commitidx($curview) } + make_disporder $r [expr {$rb + 1}] set ids {} for {} {$r < $ra} {incr r} { set nextid [lindex $displayorder [expr {$r + 1}]] @@ -2995,7 +3595,7 @@ proc make_idlist {row} { while {$r < $rb} { foreach p [lindex $parentlist $r] { set firstkid [lindex $children($curview,$p) 0] - if {$commitrow($curview,$firstkid) < $row} { + if {[rowofcommit $firstkid] < $row} { lappend ids [list $ordertok($curview,$p) $p] } } @@ -3003,7 +3603,7 @@ proc make_idlist {row} { set id [lindex $displayorder $r] if {$id ne {}} { set firstkid [lindex $children($curview,$id) 0] - if {$firstkid ne {} && $commitrow($curview,$firstkid) < $row} { + if {$firstkid ne {} && [rowofcommit $firstkid] < $row} { lappend ids [list $ordertok($curview,$id) $id] } } @@ -3050,8 +3650,9 @@ proc layoutrows {row endrow} { global rowidlist rowisopt rowfinal displayorder global uparrowlen downarrowlen maxwidth mingaplen global children parentlist - global commitidx viewcomplete curview commitrow + global commitidx viewcomplete curview + make_disporder [expr {$row - 1}] [expr {$endrow + $uparrowlen}] set idlist {} if {$row > 0} { set rm1 [expr {$row - 1}] @@ -3107,7 +3708,7 @@ proc layoutrows {row endrow} { foreach p [lindex $parentlist $r] { if {[lsearch -exact $idlist $p] >= 0} continue set fk [lindex $children($curview,$p) 0] - if {$commitrow($curview,$fk) < $row} { + if {[rowofcommit $fk] < $row} { set x [idcol $idlist $p $x] set idlist [linsert $idlist $x $p] } @@ -3116,7 +3717,7 @@ proc layoutrows {row endrow} { set p [lindex $displayorder $r] if {[lsearch -exact $idlist $p] < 0} { set fk [lindex $children($curview,$p) 0] - if {$fk ne {} && $commitrow($curview,$fk) < $row} { + if {$fk ne {} && [rowofcommit $fk] < $row} { set x [idcol $idlist $p $x] set idlist [linsert $idlist $x $p] } @@ -3331,7 +3932,7 @@ proc linewidth {id} { } proc rowranges {id} { - global commitrow curview children uparrowlen downarrowlen + global curview children uparrowlen downarrowlen global rowidlist set kids $children($curview,$id) @@ -3341,13 +3942,13 @@ proc rowranges {id} { set ret {} lappend kids $id foreach child $kids { - if {![info exists commitrow($curview,$child)]} break - set row $commitrow($curview,$child) + if {![commitinview $child $curview]} break + set row [rowofcommit $child] if {![info exists prev]} { lappend ret [expr {$row + 1}] } else { if {$row <= $prevrow} { - puts "oops children out of order [shortids $id] $row < [shortids $prev] $prevrow" + puts "oops children of [shortids $id] out of order [shortids $child] $row <= [shortids $prev] $prevrow" } # see if the line extends the whole way from prevrow to row if {$row > $prevrow + $uparrowlen + $downarrowlen && @@ -3380,7 +3981,7 @@ proc rowranges {id} { if {$child eq $id} { lappend ret $row } - set prev $id + set prev $child set prevrow $row } return $ret @@ -3628,14 +4229,14 @@ proc drawlines {id} { } proc drawcmittext {id row col} { - global linespc canv canv2 canv3 canvy0 fgcolor curview - global commitlisted commitinfo rowidlist parentlist + global linespc canv canv2 canv3 fgcolor curview + global cmitlisted commitinfo rowidlist parentlist global rowtextx idpos idtags idheads idotherrefs global linehtag linentag linedtag selectedline global canvxmax boldrows boldnamerows fgcolor nullid nullid2 # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right - set listed [lindex $commitlisted $row] + set listed $cmitlisted($curview,$id) if {$id eq $nullid} { set ofill red } elseif {$id eq $nullid2} { @@ -3720,7 +4321,7 @@ proc drawcmittext {id row col} { proc drawcmitrow {row} { global displayorder rowidlist nrows_drawn global iddrawn markingmatches - global commitinfo parentlist numcommits + global commitinfo numcommits global filehighlight fhighlights findpattern nhighlights global hlview vhighlights global highlight_related rhighlights @@ -3840,6 +4441,24 @@ proc drawcommits {row {endrow {}}} { } } +proc undolayout {row} { + global uparrowlen mingaplen downarrowlen + global rowidlist rowisopt rowfinal need_redisplay + + set r [expr {$row - ($uparrowlen + $mingaplen + $downarrowlen)}] + if {$r < 0} { + set r 0 + } + if {[llength $rowidlist] > $r} { + incr r -1 + set rowidlist [lrange $rowidlist 0 $r] + set rowfinal [lrange $rowfinal 0 $r] + set rowisopt [lrange $rowisopt 0 $r] + set need_redisplay 1 + run drawvisible + } +} + proc drawfrac {f0 f1} { global canv linespc @@ -3909,7 +4528,7 @@ proc findcrossings {id} { proc assigncolor {id} { global colormap colors nextcolor - global commitrow parentlist children children curview + global parents children children curview if {[info exists colormap($id)]} return set ncolors [llength $colors] @@ -3921,7 +4540,7 @@ proc assigncolor {id} { if {[llength $kids] == 1} { set child [lindex $kids 0] if {[info exists colormap($child)] - && [llength [lindex $parentlist $commitrow($curview,$child)]] == 1} { + && [llength $parents($curview,$child)] == 1} { set colormap($id) $colormap($child) return } @@ -3949,7 +4568,7 @@ proc assigncolor {id} { && [lsearch -exact $badcolors $colormap($child)] < 0} { lappend badcolors $colormap($child) } - foreach p [lindex $parentlist $commitrow($curview,$child)] { + foreach p $parents($curview,$child) { if {[info exists colormap($p)] && [lsearch -exact $badcolors $colormap($p)] < 0} { lappend badcolors $colormap($p) @@ -3982,7 +4601,7 @@ proc bindline {t id} { proc drawtags {id x xt y1} { global idtags idheads idotherrefs mainhead global linespc lthickness - global canv commitrow rowtextx curview fgcolor bgcolor + global canv rowtextx curview fgcolor bgcolor set marks {} set ntags 0 @@ -4032,7 +4651,7 @@ proc drawtags {id x xt y1} { $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \ -width 1 -outline black -fill yellow -tags tag.$id] $canv bind $t <1> [list showtag $tag 1] - set rowtextx($commitrow($curview,$id)) [expr {$xr + $linespc}] + set rowtextx([rowofcommit $id]) [expr {$xr + $linespc}] } else { # draw a head or other ref if {[incr nheads -1] >= 0} { @@ -4086,103 +4705,6 @@ proc show_status {msg} { -tags text -fill $fgcolor } -# Insert a new commit as the child of the commit on row $row. -# The new commit will be displayed on row $row and the commits -# on that row and below will move down one row. -proc insertrow {row newcmit} { - global displayorder parentlist commitlisted children - global commitrow curview rowidlist rowisopt rowfinal numcommits - global numcommits - global selectedline commitidx ordertok - - if {$row >= $numcommits} { - puts "oops, inserting new row $row but only have $numcommits rows" - return - } - set p [lindex $displayorder $row] - set displayorder [linsert $displayorder $row $newcmit] - set parentlist [linsert $parentlist $row $p] - set kids $children($curview,$p) - lappend kids $newcmit - set children($curview,$p) $kids - set children($curview,$newcmit) {} - set commitlisted [linsert $commitlisted $row 1] - set l [llength $displayorder] - for {set r $row} {$r < $l} {incr r} { - set id [lindex $displayorder $r] - set commitrow($curview,$id) $r - } - incr commitidx($curview) - set ordertok($curview,$newcmit) $ordertok($curview,$p) - - if {$row < [llength $rowidlist]} { - set idlist [lindex $rowidlist $row] - if {$idlist ne {}} { - if {[llength $kids] == 1} { - set col [lsearch -exact $idlist $p] - lset idlist $col $newcmit - } else { - set col [llength $idlist] - lappend idlist $newcmit - } - } - set rowidlist [linsert $rowidlist $row $idlist] - set rowisopt [linsert $rowisopt $row 0] - set rowfinal [linsert $rowfinal $row [lindex $rowfinal $row]] - } - - incr numcommits - - if {[info exists selectedline] && $selectedline >= $row} { - incr selectedline - } - redisplay -} - -# Remove a commit that was inserted with insertrow on row $row. -proc removerow {row} { - global displayorder parentlist commitlisted children - global commitrow curview rowidlist rowisopt rowfinal numcommits - global numcommits - global linesegends selectedline commitidx - - if {$row >= $numcommits} { - puts "oops, removing row $row but only have $numcommits rows" - return - } - set rp1 [expr {$row + 1}] - set id [lindex $displayorder $row] - set p [lindex $parentlist $row] - set displayorder [lreplace $displayorder $row $row] - set parentlist [lreplace $parentlist $row $row] - set commitlisted [lreplace $commitlisted $row $row] - set kids $children($curview,$p) - set i [lsearch -exact $kids $id] - if {$i >= 0} { - set kids [lreplace $kids $i $i] - set children($curview,$p) $kids - } - set l [llength $displayorder] - for {set r $row} {$r < $l} {incr r} { - set id [lindex $displayorder $r] - set commitrow($curview,$id) $r - } - incr commitidx($curview) -1 - - if {$row < [llength $rowidlist]} { - set rowidlist [lreplace $rowidlist $row $row] - set rowisopt [lreplace $rowisopt $row $row] - set rowfinal [lreplace $rowfinal $row $row] - } - - incr numcommits -1 - - if {[info exists selectedline] && $selectedline > $row} { - incr selectedline -1 - } - redisplay -} - # Don't change the text pane cursor if it is currently the hand cursor, # showing that we are over a sha1 ID link. proc settextcursor {c} { @@ -4285,9 +4807,9 @@ proc stopfinding {} { proc findmore {} { global commitdata commitinfo numcommits findpattern findloc - global findstartline findcurline displayorder + global findstartline findcurline findallowwrap global find_dirn gdttype fhighlights fprogcoord - global findallowwrap + global curview varcorder vrownum varccommits if {![info exists find_dirn]} { return 0 @@ -4325,12 +4847,26 @@ proc findmore {} { } set found 0 set domore 1 + set ai [bsearch $vrownum($curview) $l] + set a [lindex $varcorder($curview) $ai] + set arow [lindex $vrownum($curview) $ai] + set ids [lindex $varccommits($curview,$a)] + set arowend [expr {$arow + [llength $ids]}] if {$gdttype eq "containing:"} { for {} {$n > 0} {incr n -1; incr l $find_dirn} { - set id [lindex $displayorder $l] + if {$l < $arow || $l >= $arowend} { + incr ai $find_dirn + set a [lindex $varcorder($curview) $ai] + set arow [lindex $vrownum($curview) $ai] + set ids [lindex $varccommits($curview,$a)] + set arowend [expr {$arow + [llength $ids]}] + } + set id [lindex $ids [expr {$l - $arow}]] # shouldn't happen unless git log doesn't give all the commits... - if {![info exists commitdata($id)]} continue - if {![doesmatch $commitdata($id)]} continue + if {![info exists commitdata($id)] || + ![doesmatch $commitdata($id)]} { + continue + } if {![info exists commitinfo($id)]} { getcommit $id } @@ -4346,7 +4882,14 @@ proc findmore {} { } } else { for {} {$n > 0} {incr n -1; incr l $find_dirn} { - set id [lindex $displayorder $l] + if {$l < $arow || $l >= $arowend} { + incr ai $find_dirn + set a [lindex $varcorder($curview) $ai] + set arow [lindex $vrownum($curview) $ai] + set ids [lindex $varccommits($curview,$a)] + set arowend [expr {$arow + [llength $ids]}] + } + set id [lindex $ids [expr {$l - $arow}]] if {![info exists fhighlights($l)]} { askfilehighlight $l $id if {$domore} { @@ -4470,7 +5013,7 @@ proc commit_descriptor {p} { # append some text to the ctext widget, and make any SHA1 ID # that we know about be a clickable link. proc appendwithlinks {text tags} { - global ctext commitrow linknum curview pendinglinks + global ctext linknum curview pendinglinks set start [$ctext index "end - 1c"] $ctext insert end $text $tags @@ -4488,11 +5031,11 @@ proc appendwithlinks {text tags} { } proc setlink {id lk} { - global curview commitrow ctext pendinglinks commitinterest + global curview ctext pendinglinks commitinterest - if {[info exists commitrow($curview,$id)]} { + if {[commitinview $id $curview]} { $ctext tag conf $lk -foreground blue -underline 1 - $ctext tag bind $lk <1> [list selectline $commitrow($curview,$id) 1] + $ctext tag bind $lk <1> [list selectline [rowofcommit $id] 1] $ctext tag bind $lk {linkcursor %W 1} $ctext tag bind $lk {linkcursor %W -1} } else { @@ -4543,7 +5086,7 @@ proc viewnextline {dir} { # add a list of tag or branch names at position pos # returns the number of names inserted proc appendrefs {pos ids var} { - global ctext commitrow linknum curview $var maxrefs + global ctext linknum curview $var maxrefs if {[catch {$ctext index $pos}]} { return 0 @@ -4646,8 +5189,7 @@ proc make_secsel {l} { proc selectline {l isnew} { global canv ctext commitinfo selectedline - global displayorder - global canvy0 linespc parentlist children curview + global canvy0 linespc parents children curview global currentid sha1entry global commentend idtags linknum global mergemax numcommits pending_select @@ -4703,7 +5245,7 @@ proc selectline {l isnew} { set selectedline $l - set id [lindex $displayorder $l] + set id [commitonrow $l] set currentid $id $sha1entry delete 0 end $sha1entry insert 0 $id @@ -4728,7 +5270,7 @@ proc selectline {l isnew} { } set headers {} - set olds [lindex $parentlist $l] + set olds $parents($curview,$id) if {[llength $olds] > 1} { set np 0 foreach p $olds { @@ -4786,7 +5328,7 @@ proc selectline {l isnew} { } elseif {[llength $olds] <= 1} { startdiff $id } else { - mergediff $id $l + mergediff $id } } @@ -5031,10 +5573,10 @@ proc getblobline {bf id} { return [expr {$nl >= 1000? 2: 1}] } -proc mergediff {id l} { +proc mergediff {id} { global diffmergeid mdifffd global diffids - global parentlist + global parents global limitdiffs viewfiles curview set diffmergeid $id @@ -5050,7 +5592,7 @@ proc mergediff {id l} { } fconfigure $mdf -blocking 0 set mdifffd($id) $mdf - set np [llength [lindex $parentlist $l]] + set np [llength $parents($curview,$id)] settabs $np filerun $mdf [list getmergediffline $mdf $id $np] } @@ -5678,7 +6220,7 @@ proc fontname {f} { } proc incrfont {inc} { - global mainfont textfont ctext canv phase cflist showrefstop + global mainfont textfont ctext canv cflist showrefstop global stopped entries fontattr unmarkmatches @@ -5729,8 +6271,7 @@ proc sha1change {n1 n2 op} { } proc gotocommit {} { - global sha1string currentid commitrow tagids headids - global displayorder numcommits curview + global sha1string tagids headids curview varcid if {$sha1string == {} || ([info exists currentid] && $sha1string == $currentid)} return @@ -5741,23 +6282,18 @@ proc gotocommit {} { } else { set id [string tolower $sha1string] if {[regexp {^[0-9a-f]{4,39}$} $id]} { - set matches {} - foreach i $displayorder { - if {[string match $id* $i]} { - lappend matches $i - } - } + set matches [array names varcid "$curview,$id*"] if {$matches ne {}} { if {[llength $matches] > 1} { error_popup "Short SHA1 id $id is ambiguous" return } - set id [lindex $matches 0] + set id [lindex [split [lindex $matches 0] ","] 1] } } } - if {[info exists commitrow($curview,$id)]} { - selectline $commitrow($curview,$id) 1 + if {[commitinview $id $curview]} { + selectline [rowofcommit $id] 1 return } if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} { @@ -5866,7 +6402,7 @@ proc arrowjump {id n y} { } proc lineclick {x y id isnew} { - global ctext commitinfo children canv thickerline curview commitrow + global ctext commitinfo children canv thickerline curview if {![info exists commitinfo($id)] && ![getcommit $id]} return unmarkmatches @@ -5934,9 +6470,9 @@ proc normalline {} { } proc selbyid {id} { - global commitrow curview - if {[info exists commitrow($curview,$id)]} { - selectline $commitrow($curview,$id) 1 + global curview + if {[commitinview $id $curview]} { + selectline [rowofcommit $id] 1 } } @@ -5949,13 +6485,13 @@ proc mstime {} { } proc rowmenu {x y id} { - global rowctxmenu commitrow selectedline rowmenuid curview + global rowctxmenu selectedline rowmenuid curview global nullid nullid2 fakerowmenu mainhead stopfinding set rowmenuid $id if {![info exists selectedline] - || $commitrow($curview,$id) eq $selectedline} { + || [rowofcommit $id] eq $selectedline} { set state disabled } else { set state normal @@ -5973,15 +6509,15 @@ proc rowmenu {x y id} { } proc diffvssel {dirn} { - global rowmenuid selectedline displayorder + global rowmenuid selectedline if {![info exists selectedline]} return if {$dirn} { - set oldid [lindex $displayorder $selectedline] + set oldid [commitonrow $selectedline] set newid $rowmenuid } else { set oldid $rowmenuid - set newid [lindex $displayorder $selectedline] + set newid [commitonrow $selectedline] } addtohistory [list doseldiff $oldid $newid] doseldiff $oldid $newid @@ -6163,23 +6699,23 @@ proc domktag {} { } proc redrawtags {id} { - global canv linehtag commitrow idpos selectedline curview + global canv linehtag idpos selectedline curview global canvxmax iddrawn - if {![info exists commitrow($curview,$id)]} return + if {![commitinview $id $curview]} return if {![info exists iddrawn($id)]} return - drawcommits $commitrow($curview,$id) + drawcommits [rowofcommit $id] $canv delete tag.$id set xt [eval drawtags $id $idpos($id)] - $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2] - set text [$canv itemcget $linehtag($commitrow($curview,$id)) -text] + $canv coords $linehtag([rowofcommit $id]) $xt [lindex $idpos($id) 2] + set text [$canv itemcget $linehtag([rowofcommit $id]) -text] set xr [expr {$xt + [font measure mainfont $text]}] if {$xr > $canvxmax} { set canvxmax $xr setcanvscroll } if {[info exists selectedline] - && $selectedline == $commitrow($curview,$id)} { + && $selectedline == [rowofcommit $id]} { selectline $selectedline 0 } } @@ -6306,7 +6842,7 @@ proc mkbrgo {top} { } proc cherrypick {} { - global rowmenuid curview commitrow + global rowmenuid curview global mainhead set oldhead [exec git rev-parse HEAD] @@ -6332,8 +6868,8 @@ proc cherrypick {} { return } addnewchild $newhead $oldhead - if {[info exists commitrow($curview,$oldhead)]} { - insertrow $commitrow($curview,$oldhead) $newhead + if {[commitinview $oldhead $curview]} { + insertrow $newhead $oldhead $curview if {$mainhead ne {}} { movehead $newhead $mainhead movedhead $newhead $mainhead @@ -6571,13 +7107,13 @@ proc reflistfilter_change {n1 n2 op} { proc refill_reflist {} { global reflist reflistfilter showrefstop headids tagids otherrefids - global commitrow curview commitinterest + global curview commitinterest if {![info exists showrefstop] || ![winfo exists $showrefstop]} return set refs {} foreach n [array names headids] { if {[string match $reflistfilter $n]} { - if {[info exists commitrow($curview,$headids($n))]} { + if {[commitinview $headids($n) $curview]} { lappend refs [list $n H] } else { set commitinterest($headids($n)) {run refill_reflist} @@ -6586,7 +7122,7 @@ proc refill_reflist {} { } foreach n [array names tagids] { if {[string match $reflistfilter $n]} { - if {[info exists commitrow($curview,$tagids($n))]} { + if {[commitinview $tagids($n) $curview]} { lappend refs [list $n T] } else { set commitinterest($tagids($n)) {run refill_reflist} @@ -6595,7 +7131,7 @@ proc refill_reflist {} { } foreach n [array names otherrefids] { if {[string match $reflistfilter $n]} { - if {[info exists commitrow($curview,$otherrefids($n))]} { + if {[commitinview $otherrefids($n) $curview]} { lappend refs [list $n o] } else { set commitinterest($otherrefids($n)) {run refill_reflist} @@ -8619,12 +9155,12 @@ set viewfiles(0) {} set viewperm(0) 0 set viewargs(0) {} +set loginstance 0 +set getdbg 0 set cmdlineok 0 set stopped 0 set stuffsaved 0 set patchnum 0 -set localirow -1 -set localfrow -1 set lserial 0 setcoords makewindow