From 9f1afe05c3ab7228e21ba3666c6e35d693149b37 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 19 Feb 2006 22:44:47 +1100 Subject: [PATCH 01/13] gitk: New improved gitk This is a new version of gitk which is much faster and has much better graph layout. It achieves the speed by only drawing the parts of the canvases that are actually visible. It also draws the commits in the order that git-rev-list produces them, so if you use -d, you need to have a recent enough git-rev-list that understands the --date-order flag. Signed-off-by: Paul Mackerras --- gitk | 1549 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 823 insertions(+), 726 deletions(-) diff --git a/gitk b/gitk index f4c662423c..502f2665af 100755 --- a/gitk +++ b/gitk @@ -34,13 +34,17 @@ proc parse_args {rargs} { proc start_rev_list {rlargs} { global startmsecs nextupdate ncmupdate - global commfd leftover tclencoding + global commfd leftover tclencoding datemode set startmsecs [clock clicks -milliseconds] set nextupdate [expr {$startmsecs + 100}] set ncmupdate 1 + set order "--topo-order" + if {$datemode} { + set order "--date-order" + } if {[catch { - set commfd [open [concat | git-rev-list --header --topo-order \ + set commfd [open [concat | git-rev-list --header $order \ --parents $rlargs] r] } err]} { puts stderr "Error executing git-rev-list: $err" @@ -77,7 +81,7 @@ proc getcommits {rargs} { proc getcommitlines {commfd} { global oldcommits commits parents cdate children nchildren global commitlisted phase nextupdate - global stopped redisplaying leftover + global stopped leftover global canv set stuff [read $commfd] @@ -105,7 +109,7 @@ proc getcommitlines {commfd} { set i [string first "\0" $stuff $start] if {$i < 0} { append leftover [string range $stuff $start end] - return + break } set cmit [string range $stuff $start [expr {$i - 1}]] if {$start == 0} { @@ -140,23 +144,10 @@ proc getcommitlines {commfd} { set commitlisted($id) 1 parsecommit $id $cmit 1 [lrange $ids 1 end] drawcommit $id 1 - if {[clock clicks -milliseconds] >= $nextupdate} { - doupdate 1 - } - while {$redisplaying} { - set redisplaying 0 - if {$stopped == 1} { - set stopped 0 - set phase "getcommits" - foreach id $commits { - drawcommit $id 1 - if {$stopped} break - if {[clock clicks -milliseconds] >= $nextupdate} { - doupdate 1 - } - } - } - } + } + layoutmore + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate 1 } } @@ -193,7 +184,7 @@ proc updatecommits {rargs} { global parsed_args global canv mainfont global oldcommits commits - global parents nchildren children ncleft + global parents nchildren children set old_args $parsed_args parse_args $rargs @@ -276,12 +267,11 @@ proc updatecommits {rargs} { } proc updatechildren {id olds} { - global children nchildren parents nparents ncleft + global children nchildren parents nparents if {![info exists nchildren($id)]} { set children($id) {} set nchildren($id) 0 - set ncleft($id) 0 } set parents($id) $olds set nparents($id) [llength $olds] @@ -289,11 +279,9 @@ proc updatechildren {id olds} { if {![info exists nchildren($p)]} { set children($p) [list $id] set nchildren($p) 1 - set ncleft($p) 1 } elseif {[lsearch -exact $children($p) $id] < 0} { lappend children($p) $id incr nchildren($p) - incr ncleft($p) } } } @@ -457,7 +445,7 @@ proc makewindow {rargs} { set canv .ctop.top.clist.canv canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ -bg white -bd 0 \ - -yscrollincr $linespc -yscrollcommand "$cscroll set" + -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll" .ctop.top.clist add $canv set canv2 .ctop.top.clist.canv2 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ @@ -631,6 +619,11 @@ proc makewindow {rargs} { $rowctxmenu add command -label "Write commit to file" -command writecommit } +proc scrollcanv {cscroll f0 f1} { + $cscroll set $f0 $f1 + drawfrac $f0 $f1 +} + # when we make a key binding for the toplevel, make sure # it doesn't get triggered when that key is pressed in the # find string entry widget. @@ -763,9 +756,9 @@ proc about {} { toplevel $w wm title $w "About gitk" message $w.m -text { -Gitk version 1.2 +Gitk - a commit viewer for git -Copyright © 2005 Paul Mackerras +Copyright © 2005-2006 Paul Mackerras Use and redistribute under the terms of the GNU General Public License} \ -justify center -aspect 400 @@ -774,6 +767,694 @@ Use and redistribute under the terms of the GNU General Public License} \ pack $w.ok -side bottom } +proc shortids {ids} { + set res {} + foreach id $ids { + if {[llength $id] > 1} { + lappend res [shortids $id] + } elseif {[regexp {^[0-9a-f]{40}$} $id]} { + lappend res [string range $id 0 7] + } else { + lappend res $id + } + } + return $res +} + +proc incrange {l x o} { + set n [llength $l] + while {$x < $n} { + set e [lindex $l $x] + if {$e ne {}} { + lset l $x [expr {$e + $o}] + } + incr x + } + return $l +} + +proc ntimes {n o} { + set ret {} + for {} {$n > 0} {incr n -1} { + lappend ret $o + } + return $ret +} + +proc usedinrange {id l1 l2} { + global children commitrow + + if {[info exists commitrow($id)]} { + set r $commitrow($id) + if {$l1 <= $r && $r <= $l2} { + return [expr {$r - $l1 + 1}] + } + } + foreach c $children($id) { + if {[info exists commitrow($c)]} { + set r $commitrow($c) + if {$l1 <= $r && $r <= $l2} { + return [expr {$r - $l1 + 1}] + } + } + } + return 0 +} + +proc sanity {row {full 0}} { + global rowidlist rowoffsets + + set col -1 + set ids $rowidlist($row) + foreach id $ids { + incr col + if {$id eq {}} continue + if {$col < [llength $ids] - 1 && + [lsearch -exact -start [expr {$col+1}] $ids $id] >= 0} { + puts "oops: [shortids $id] repeated in row $row col $col: {[shortids $rowidlist($row)]}" + } + set o [lindex $rowoffsets($row) $col] + set y $row + set x $col + while {$o ne {}} { + incr y -1 + incr x $o + if {[lindex $rowidlist($y) $x] != $id} { + puts "oops: rowoffsets wrong at row [expr {$y+1}] col [expr {$x-$o}]" + puts " id=[shortids $id] check started at row $row" + for {set i $row} {$i >= $y} {incr i -1} { + puts " row $i ids={[shortids $rowidlist($i)]} offs={$rowoffsets($i)}" + } + break + } + if {!$full} break + set o [lindex $rowoffsets($y) $x] + } + } +} + +proc makeuparrow {oid x y z} { + global rowidlist rowoffsets uparrowlen idrowranges + + for {set i 1} {$i < $uparrowlen && $y > 1} {incr i} { + incr y -1 + incr x $z + set off0 $rowoffsets($y) + for {set x0 $x} {1} {incr x0} { + if {$x0 >= [llength $off0]} { + set x0 [llength $rowoffsets([expr {$y-1}])] + break + } + set z [lindex $off0 $x0] + if {$z ne {}} { + incr x0 $z + break + } + } + set z [expr {$x0 - $x}] + set rowidlist($y) [linsert $rowidlist($y) $x $oid] + set rowoffsets($y) [linsert $rowoffsets($y) $x $z] + } + set tmp [lreplace $rowoffsets($y) $x $x {}] + set rowoffsets($y) [incrange $tmp [expr {$x+1}] -1] + lappend idrowranges($oid) $y +} + +proc initlayout {} { + global rowidlist rowoffsets displayorder + global rowlaidout rowoptim + global idinlist rowchk + + set rowidlist(0) {} + set rowoffsets(0) {} + catch {unset idinlist} + catch {unset rowchk} + set rowlaidout 0 + set rowoptim 0 +} + +proc visiblerows {} { + global canv numcommits linespc + + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax eq {} || $ymax == 0} return + set f [$canv yview] + set y0 [expr {int([lindex $f 0] * $ymax)}] + set r0 [expr {int(($y0 - 3) / $linespc) - 1}] + if {$r0 < 0} { + set r0 0 + } + set y1 [expr {int([lindex $f 1] * $ymax)}] + set r1 [expr {int(($y1 - 3) / $linespc) + 1}] + if {$r1 >= $numcommits} { + set r1 [expr {$numcommits - 1}] + } + return [list $r0 $r1] +} + +proc layoutmore {} { + global rowlaidout rowoptim commitidx numcommits optim_delay + global uparrowlen + + set row $rowlaidout + set rowlaidout [layoutrows $row $commitidx 0] + set orow [expr {$rowlaidout - $uparrowlen - 1}] + if {$orow > $rowoptim} { + checkcrossings $rowoptim $orow + optimize_rows $rowoptim 0 $orow + set rowoptim $orow + } + set canshow [expr {$rowoptim - $optim_delay}] + if {$canshow > $numcommits} { + showstuff $canshow + } +} + +proc showstuff {canshow} { + global numcommits + global canvy0 linespc + global linesegends idrowranges idrangedrawn + + set row $numcommits + set numcommits $canshow + allcanvs conf -scrollregion \ + [list 0 0 0 [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]] + set rows [visiblerows] + set r0 [lindex $rows 0] + set r1 [lindex $rows 1] + for {set r $row} {$r < $canshow} {incr r} { + if {[info exists linesegends($r)]} { + foreach id $linesegends($r) { + set i -1 + foreach {s e} $idrowranges($id) { + incr i + if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0 + && ![info exists idrangedrawn($id,$i)]} { + drawlineseg $id $i 1 + set idrangedrawn($id,$i) 1 + } + } + } + } + } + if {$canshow > $r1} { + set canshow $r1 + } + while {$row < $canshow} { + drawcmitrow $row + incr row + } +} + +proc layoutrows {row endrow last} { + global rowidlist rowoffsets displayorder + global uparrowlen downarrowlen maxwidth mingaplen + global nchildren parents nparents + global idrowranges linesegends + global commitidx + global idinlist rowchk + + set idlist $rowidlist($row) + set offs $rowoffsets($row) + while {$row < $endrow} { + set id [lindex $displayorder $row] + set oldolds {} + set newolds {} + foreach p $parents($id) { + if {![info exists idinlist($p)]} { + lappend newolds $p + } elseif {!$idinlist($p)} { + lappend oldolds $p + } + } + set nev [expr {[llength $idlist] + [llength $newolds] + + [llength $oldolds] - $maxwidth + 1}] + if {$nev > 0} { + if {!$last && $row + $uparrowlen + $mingaplen >= $commitidx} break + for {set x [llength $idlist]} {[incr x -1] >= 0} {} { + set i [lindex $idlist $x] + if {![info exists rowchk($i)] || $row >= $rowchk($i)} { + set r [usedinrange $i [expr {$row - $downarrowlen}] \ + [expr {$row + $uparrowlen + $mingaplen}]] + if {$r == 0} { + set idlist [lreplace $idlist $x $x] + set offs [lreplace $offs $x $x] + set offs [incrange $offs $x 1] + set idinlist($i) 0 + lappend linesegends($row) $i + lappend idrowranges($i) [expr {$row-1}] + if {[incr nev -1] <= 0} break + continue + } + set rowchk($id) [expr {$row + $r}] + } + } + set rowidlist($row) $idlist + set rowoffsets($row) $offs + } + set col [lsearch -exact $idlist $id] + if {$col < 0} { + set col [llength $idlist] + lappend idlist $id + set rowidlist($row) $idlist + set z {} + if {$nchildren($id) > 0} { + set z [expr {[llength $rowidlist([expr {$row-1}])] - $col}] + unset idinlist($id) + } + lappend offs $z + set rowoffsets($row) $offs + if {$z ne {}} { + makeuparrow $id $col $row $z + } + } else { + unset idinlist($id) + } + if {[info exists idrowranges($id)]} { + lappend linesegends($row) $id + lappend idrowranges($id) $row + } + incr row + set offs [ntimes [llength $idlist] 0] + set l [llength $newolds] + set idlist [eval lreplace \$idlist $col $col $newolds] + set o 0 + if {$l != 1} { + set offs [lrange $offs 0 [expr {$col - 1}]] + foreach x $newolds { + lappend offs {} + incr o -1 + } + incr o + set tmp [expr {[llength $idlist] - [llength $offs]}] + if {$tmp > 0} { + set offs [concat $offs [ntimes $tmp $o]] + } + } else { + lset offs $col {} + } + foreach i $newolds { + set idinlist($i) 1 + set idrowranges($i) $row + } + incr col $l + foreach oid $oldolds { + set idinlist($oid) 1 + set idlist [linsert $idlist $col $oid] + set offs [linsert $offs $col $o] + makeuparrow $oid $col $row $o + incr col + } + set rowidlist($row) $idlist + set rowoffsets($row) $offs + } + return $row +} + +proc addextraid {id row} { + global displayorder commitrow lineid commitinfo nparents + global commitidx + + incr commitidx + lappend displayorder $id + set commitrow($id) $row + set lineid($row) $id + readcommit $id + if {![info exists commitinfo($id)]} { + set commitinfo($id) {"No commit information available"} + set nparents($id) 0 + } +} + +proc layouttail {} { + global rowidlist rowoffsets idinlist commitidx + global idrowranges linesegends + + set row $commitidx + set idlist $rowidlist($row) + while {$idlist ne {}} { + set col [expr {[llength $idlist] - 1}] + set id [lindex $idlist $col] + addextraid $id $row + unset idinlist($id) + lappend linesegends($row) $id + lappend idrowranges($id) $row + incr row + set offs [ntimes $col 0] + set idlist [lreplace $idlist $col $col] + set rowidlist($row) $idlist + set rowoffsets($row) $offs + } + + foreach id [array names idinlist] { + addextraid $id $row + set rowidlist($row) [list $id] + set rowoffsets($row) 0 + makeuparrow $id 0 $row 0 + lappend linesegends($row) $id + lappend idrowranges($id) $row + incr row + } +} + +proc insert_pad {row col npad} { + global rowidlist rowoffsets + + set pad [ntimes $npad {}] + set rowidlist($row) [eval linsert \$rowidlist($row) $col $pad] + set tmp [eval linsert \$rowoffsets($row) $col $pad] + set rowoffsets($row) [incrange $tmp [expr {$col + $npad}] [expr {-$npad}]] +} + +proc optimize_rows {row col endrow} { + global rowidlist rowoffsets idrowranges + + for {} {$row < $endrow} {incr row} { + set idlist $rowidlist($row) + set offs $rowoffsets($row) + set haspad 0 + for {} {$col < [llength $offs]} {incr col} { + if {[lindex $idlist $col] eq {}} { + set haspad 1 + continue + } + set z [lindex $offs $col] + if {$z eq {}} continue + set isarrow 0 + set x0 [expr {$col + $z}] + set y0 [expr {$row - 1}] + set z0 [lindex $rowoffsets($y0) $x0] + if {$z0 eq {}} { + set id [lindex $idlist $col] + if {[info exists idrowranges($id)] && + $y0 > [lindex $idrowranges($id) 0]} { + set isarrow 1 + } + } + if {$z < -1 || ($z < 0 && $isarrow)} { + set npad [expr {-1 - $z + $isarrow}] + set offs [incrange $offs $col $npad] + insert_pad $y0 $x0 $npad + if {$y0 > 0} { + optimize_rows $y0 $x0 $row + } + set z [lindex $offs $col] + set x0 [expr {$col + $z}] + set z0 [lindex $rowoffsets($y0) $x0] + } elseif {$z > 1 || ($z > 0 && $isarrow)} { + set npad [expr {$z - 1 + $isarrow}] + set y1 [expr {$row + 1}] + set offs2 $rowoffsets($y1) + set x1 -1 + foreach z $offs2 { + incr x1 + if {$z eq {} || $x1 + $z < $col} continue + if {$x1 + $z > $col} { + incr npad + } + set rowoffsets($y1) [incrange $offs2 $x1 $npad] + break + } + set pad [ntimes $npad {}] + set idlist [eval linsert \$idlist $col $pad] + set tmp [eval linsert \$offs $col $pad] + incr col $npad + set offs [incrange $tmp $col [expr {-$npad}]] + set z [lindex $offs $col] + set haspad 1 + } + if {$z0 ne {} && $z < 0 && $z0 > 0} { + insert_pad $y0 $x0 1 + set offs [incrange $offs $col 1] + optimize_rows $y0 [expr {$x0 + 1}] $row + } + } + if {!$haspad} { + for {set col [llength $idlist]} {[incr col -1] >= 0} {} { + set o [lindex $offs $col] + if {$o eq {} || $o <= 0} break + } + if {[incr col] < [llength $idlist]} { + set y1 [expr {$row + 1}] + set offs2 $rowoffsets($y1) + set x1 -1 + foreach z $offs2 { + incr x1 + if {$z eq {} || $x1 + $z < $col} continue + set rowoffsets($y1) [incrange $offs2 $x1 1] + break + } + set idlist [linsert $idlist $col {}] + set tmp [linsert $offs $col {}] + incr col + set offs [incrange $tmp $col -1] + } + } + set rowidlist($row) $idlist + set rowoffsets($row) $offs + set col 0 + } +} + +proc xc {row col} { + global canvx0 linespc + return [expr {$canvx0 + $col * $linespc}] +} + +proc yc {row} { + global canvy0 linespc + return [expr {$canvy0 + $row * $linespc}] +} + +proc drawlineseg {id i wid} { + global rowoffsets rowidlist idrowranges + global canv colormap lthickness + + set startrow [lindex $idrowranges($id) [expr {2 * $i}]] + set row [lindex $idrowranges($id) [expr {2 * $i + 1}]] + if {$startrow == $row} return + assigncolor $id + set coords {} + set col [lsearch -exact $rowidlist($row) $id] + if {$col < 0} { + puts "oops: drawline: id $id not on row $row" + return + } + set lasto {} + set ns 0 + while {1} { + set o [lindex $rowoffsets($row) $col] + if {$o eq {}} break + if {$o ne $lasto} { + # changing direction + set x [xc $row $col] + set y [yc $row] + lappend coords $x $y + set lasto $o + } + incr col $o + incr row -1 + } + if {$coords eq {}} return + set last [expr {[llength $idrowranges($id)] / 2 - 1}] + set arrow [expr {2 * ($i > 0) + ($i < $last)}] + set arrow [lindex {none first last both} $arrow] + set wid [expr {$wid * $lthickness}] + set x [xc $row $col] + set y [yc $row] + lappend coords $x $y + set t [$canv create line $coords -width $wid \ + -fill $colormap($id) -tags lines.$id -arrow $arrow] + $canv lower $t + bindline $t $id +} + +proc drawparentlinks {id row col olds wid} { + global rowoffsets rowidlist canv colormap lthickness + + set row2 [expr {$row + 1}] + set x [xc $row $col] + set y [yc $row] + set y2 [yc $row2] + set ids $rowidlist($row2) + set offs $rowidlist($row2) + # rmx = right-most X coord used + set rmx 0 + set wid [expr {$wid * $lthickness}] + foreach p $olds { + set i [lsearch -exact $ids $p] + if {$i < 0} { + puts "oops, parent $p of $id not in list" + continue + } + assigncolor $p + # should handle duplicated parents here... + set coords [list $x $y] + if {$i < $col - 1} { + lappend coords [xc $row [expr {$i + 1}]] $y + } elseif {$i > $col + 1} { + lappend coords [xc $row [expr {$i - 1}]] $y + } + set x2 [xc $row2 $i] + if {$x2 > $rmx} { + set rmx $x2 + } + lappend coords $x2 $y2 + set t [$canv create line $coords -width $wid \ + -fill $colormap($p) -tags lines.$p] + $canv lower $t + bindline $t $p + } + return $rmx +} + +proc drawlines {id xtra} { + global colormap canv + global idrowranges idrangedrawn + global children iddrawn commitrow rowidlist + + $canv delete lines.$id + set wid [expr {$xtra + 1}] + set nr [expr {[llength $idrowranges($id)] / 2}] + for {set i 0} {$i < $nr} {incr i} { + if {[info exists idrangedrawn($id,$i)]} { + drawlineseg $id $i $wid + } + } + if {[info exists children($id)]} { + foreach child $children($id) { + if {[info exists iddrawn($child)]} { + set row $commitrow($child) + set col [lsearch -exact $rowidlist($row) $child] + if {$col >= 0} { + drawparentlinks $child $row $col [list $id] $wid + } + } + } + } +} + +proc drawcmittext {id row col rmx} { + global linespc canv canv2 canv3 canvy0 + global commitlisted commitinfo rowidlist + global rowtextx idpos idtags idheads idotherrefs + global linehtag linentag linedtag + global mainfont namefont + + set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}] + set x [xc $row $col] + set y [yc $row] + set orad [expr {$linespc / 3}] + set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \ + [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \ + -fill $ofill -outline black -width 1] + $canv raise $t + $canv bind $t <1> {selcanvline {} %x %y} + set xt [xc $row [llength $rowidlist($row)]] + if {$xt < $rmx} { + set xt $rmx + } + set rowtextx($row) $xt + set idpos($id) [list $x $xt $y] + if {[info exists idtags($id)] || [info exists idheads($id)] + || [info exists idotherrefs($id)]} { + set xt [drawtags $id $x $xt $y] + } + set headline [lindex $commitinfo($id) 0] + set name [lindex $commitinfo($id) 1] + set date [lindex $commitinfo($id) 2] + set date [formatdate $date] + set linehtag($row) [$canv create text $xt $y -anchor w \ + -text $headline -font $mainfont ] + $canv bind $linehtag($row) "rowmenu %X %Y $id" + set linentag($row) [$canv2 create text 3 $y -anchor w \ + -text $name -font $namefont] + set linedtag($row) [$canv3 create text 3 $y -anchor w \ + -text $date -font $mainfont] +} + +proc drawcmitrow {row} { + global displayorder rowidlist rowoffsets + global idrowranges idrangedrawn iddrawn + global commitinfo commitlisted parents numcommits + + if {![info exists rowidlist($row)]} return + foreach id $rowidlist($row) { + if {![info exists idrowranges($id)]} continue + set i -1 + foreach {s e} $idrowranges($id) { + incr i + if {$row < $s} continue + if {$e eq {}} break + if {$row <= $e} { + if {$e < $numcommits && ![info exists idrangedrawn($id,$i)]} { + drawlineseg $id $i 1 + set idrangedrawn($id,$i) 1 + } + break + } + } + } + + set id [lindex $displayorder $row] + if {[info exists iddrawn($id)]} return + set col [lsearch -exact $rowidlist($row) $id] + if {$col < 0} { + puts "oops, row $row id $id not in list" + return + } + if {![info exists commitinfo($id)]} { + readcommit $id + if {![info exists commitinfo($id)]} { + set commitinfo($id) {"No commit information available"} + set nparents($id) 0 + } + } + assigncolor $id + if {[info exists commitlisted($id)] && [info exists parents($id)] + && $parents($id) ne {}} { + set rmx [drawparentlinks $id $row $col $parents($id) 1] + } else { + set rmx 0 + } + drawcmittext $id $row $col $rmx + set iddrawn($id) 1 +} + +proc drawfrac {f0 f1} { + global numcommits canv + global linespc + + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax eq {} || $ymax == 0} return + set y0 [expr {int($f0 * $ymax)}] + set row [expr {int(($y0 - 3) / $linespc) - 1}] + if {$row < 0} { + set row 0 + } + set y1 [expr {int($f1 * $ymax)}] + set endrow [expr {int(($y1 - 3) / $linespc) + 1}] + if {$endrow >= $numcommits} { + set endrow [expr {$numcommits - 1}] + } + for {} {$row <= $endrow} {incr row} { + drawcmitrow $row + } +} + +proc drawvisible {} { + global canv + eval drawfrac [$canv yview] +} + +proc clear_display {} { + global iddrawn idrangedrawn + + allcanvs delete all + catch {unset iddrawn} + catch {unset idrangedrawn} +} + proc assigncolor {id} { global colormap commcolors colors nextcolor global parents nparents children nchildren @@ -781,7 +1462,7 @@ proc assigncolor {id} { if {[info exists colormap($id)]} return set ncolors [llength $colors] - if {$nparents($id) <= 1 && $nchildren($id) == 1} { + if {$nchildren($id) == 1} { set child [lindex $children($id) 0] if {[info exists colormap($child)] && $nparents($child) == 1} { @@ -846,25 +1527,16 @@ proc assigncolor {id} { } proc initgraph {} { - global canvy canvy0 lineno numcommits nextcolor linespc - global nchildren ncleft - global displist nhyperspace + global numcommits nextcolor linespc + global nchildren allcanvs delete all set nextcolor 0 - set canvy $canvy0 - set lineno -1 set numcommits 0 - foreach v {mainline mainlinearrow sidelines colormap cornercrossings - crossings idline lineid} { + foreach v {colormap cornercrossings crossings lineid} { global $v catch {unset $v} } - foreach id [array names nchildren] { - set ncleft($id) $nchildren($id) - } - set displist {} - set nhyperspace 0 } proc bindline {t id} { @@ -876,121 +1548,10 @@ proc bindline {t id} { $canv bind $t "lineclick %x %y $id 1" } -proc drawlines {id xtra delold} { - global mainline mainlinearrow sidelines lthickness colormap canv - - if {$delold} { - $canv delete lines.$id - } - if {[info exists mainline($id)]} { - set t [$canv create line $mainline($id) \ - -width [expr {($xtra + 1) * $lthickness}] \ - -fill $colormap($id) -tags lines.$id \ - -arrow $mainlinearrow($id)] - $canv lower $t - bindline $t $id - } - if {[info exists sidelines($id)]} { - foreach ls $sidelines($id) { - set coords [lindex $ls 0] - set thick [lindex $ls 1] - set arrow [lindex $ls 2] - set t [$canv create line $coords -fill $colormap($id) \ - -width [expr {($thick + $xtra) * $lthickness}] \ - -arrow $arrow -tags lines.$id] - $canv lower $t - bindline $t $id - } - } -} - -# level here is an index in displist -proc drawcommitline {level} { - global parents children nparents displist - global canv canv2 canv3 mainfont namefont canvy linespc - global lineid linehtag linentag linedtag commitinfo - global colormap numcommits currentparents dupparents - global idtags idline idheads idotherrefs - global lineno lthickness mainline mainlinearrow sidelines - global commitlisted rowtextx idpos lastuse displist - global oldnlines olddlevel olddisplist - - incr numcommits - incr lineno - set id [lindex $displist $level] - set lastuse($id) $lineno - set lineid($lineno) $id - set idline($id) $lineno - set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}] - if {![info exists commitinfo($id)]} { - readcommit $id - if {![info exists commitinfo($id)]} { - set commitinfo($id) {"No commit information available"} - set nparents($id) 0 - } - } - assigncolor $id - set currentparents {} - set dupparents {} - if {[info exists commitlisted($id)] && [info exists parents($id)]} { - foreach p $parents($id) { - if {[lsearch -exact $currentparents $p] < 0} { - lappend currentparents $p - } else { - # remember that this parent was listed twice - lappend dupparents $p - } - } - } - set x [xcoord $level $level $lineno] - set y1 $canvy - set canvy [expr {$canvy + $linespc}] - allcanvs conf -scrollregion \ - [list 0 0 0 [expr {$y1 + 0.5 * $linespc + 2}]] - if {[info exists mainline($id)]} { - lappend mainline($id) $x $y1 - if {$mainlinearrow($id) ne "none"} { - set mainline($id) [trimdiagstart $mainline($id)] - } - } - drawlines $id 0 0 - set orad [expr {$linespc / 3}] - set t [$canv create oval [expr {$x - $orad}] [expr {$y1 - $orad}] \ - [expr {$x + $orad - 1}] [expr {$y1 + $orad - 1}] \ - -fill $ofill -outline black -width 1] - $canv raise $t - $canv bind $t <1> {selcanvline {} %x %y} - set xt [xcoord [llength $displist] $level $lineno] - if {[llength $currentparents] > 2} { - set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}] - } - set rowtextx($lineno) $xt - set idpos($id) [list $x $xt $y1] - if {[info exists idtags($id)] || [info exists idheads($id)] - || [info exists idotherrefs($id)]} { - set xt [drawtags $id $x $xt $y1] - } - set headline [lindex $commitinfo($id) 0] - set name [lindex $commitinfo($id) 1] - set date [lindex $commitinfo($id) 2] - set date [formatdate $date] - set linehtag($lineno) [$canv create text $xt $y1 -anchor w \ - -text $headline -font $mainfont ] - $canv bind $linehtag($lineno) "rowmenu %X %Y $id" - set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \ - -text $name -font $namefont] - set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \ - -text $date -font $mainfont] - - set olddlevel $level - set olddisplist $displist - set oldnlines [llength $displist] -} - proc drawtags {id x xt y1} { global idtags idheads idotherrefs global linespc lthickness - global canv mainfont idline rowtextx + global canv mainfont commitrow rowtextx set marks {} set ntags 0 @@ -1033,7 +1594,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($idline($id)) [expr {$xr + $linespc}] + set rowtextx($commitrow($id)) [expr {$xr + $linespc}] } else { # draw a head or other ref if {[incr nheads -1] >= 0} { @@ -1054,11 +1615,32 @@ proc drawtags {id x xt y1} { return $xt } -proc notecrossings {id lo hi corner} { - global olddisplist crossings cornercrossings +proc checkcrossings {row endrow} { + global displayorder parents rowidlist + + for {} {$row < $endrow} {incr row} { + set id [lindex $displayorder $row] + set i [lsearch -exact $rowidlist($row) $id] + if {$i < 0} continue + set idlist $rowidlist([expr {$row+1}]) + foreach p $parents($id) { + set j [lsearch -exact $idlist $p] + if {$j > 0} { + if {$j < $i - 1} { + notecrossings $row $p $j $i [expr {$j+1}] + } elseif {$j > $i + 1} { + notecrossings $row $p $i $j [expr {$j-1}] + } + } + } + } +} + +proc notecrossings {row id lo hi corner} { + global rowidlist crossings cornercrossings for {set i $lo} {[incr i] < $hi} {} { - set p [lindex $olddisplist $i] + set p [lindex $rowidlist($row) $i] if {$p == {}} continue if {$i == $corner} { if {![info exists cornercrossings($id)] @@ -1094,491 +1676,29 @@ proc xcoord {i level ln} { return $x } -# it seems Tk can't draw arrows on the end of diagonal line segments... -proc trimdiagend {line} { - while {[llength $line] > 4} { - set x1 [lindex $line end-3] - set y1 [lindex $line end-2] - set x2 [lindex $line end-1] - set y2 [lindex $line end] - if {($x1 == $x2) != ($y1 == $y2)} break - set line [lreplace $line end-1 end] - } - return $line -} - -proc trimdiagstart {line} { - while {[llength $line] > 4} { - set x1 [lindex $line 0] - set y1 [lindex $line 1] - set x2 [lindex $line 2] - set y2 [lindex $line 3] - if {($x1 == $x2) != ($y1 == $y2)} break - set line [lreplace $line 0 1] - } - return $line -} - -proc drawslants {id needonscreen nohs} { - global canv mainline mainlinearrow sidelines - global canvx0 canvy xspc1 xspc2 lthickness - global currentparents dupparents - global lthickness linespc canvy colormap lineno geometry - global maxgraphpct maxwidth - global displist onscreen lastuse - global parents commitlisted - global oldnlines olddlevel olddisplist - global nhyperspace numcommits nnewparents - - if {$lineno < 0} { - lappend displist $id - set onscreen($id) 1 - return 0 - } - - set y1 [expr {$canvy - $linespc}] - set y2 $canvy - - # work out what we need to get back on screen - set reins {} - if {$onscreen($id) < 0} { - # next to do isn't displayed, better get it on screen... - lappend reins [list $id 0] - } - # make sure all the previous commits's parents are on the screen - foreach p $currentparents { - if {$onscreen($p) < 0} { - lappend reins [list $p 0] - } - } - # bring back anything requested by caller - if {$needonscreen ne {}} { - lappend reins $needonscreen - } - - # try the shortcut - if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} { - set dlevel $olddlevel - set x [xcoord $dlevel $dlevel $lineno] - set mainline($id) [list $x $y1] - set mainlinearrow($id) none - set lastuse($id) $lineno - set displist [lreplace $displist $dlevel $dlevel $id] - set onscreen($id) 1 - set xspc1([expr {$lineno + 1}]) $xspc1($lineno) - return $dlevel - } - - # update displist - set displist [lreplace $displist $olddlevel $olddlevel] - set j $olddlevel - foreach p $currentparents { - set lastuse($p) $lineno - if {$onscreen($p) == 0} { - set displist [linsert $displist $j $p] - set onscreen($p) 1 - incr j - } - } - if {$onscreen($id) == 0} { - lappend displist $id - set onscreen($id) 1 - } - - # remove the null entry if present - set nullentry [lsearch -exact $displist {}] - if {$nullentry >= 0} { - set displist [lreplace $displist $nullentry $nullentry] - } - - # bring back the ones we need now (if we did it earlier - # it would change displist and invalidate olddlevel) - foreach pi $reins { - # test again in case of duplicates in reins - set p [lindex $pi 0] - if {$onscreen($p) < 0} { - set onscreen($p) 1 - set lastuse($p) $lineno - set displist [linsert $displist [lindex $pi 1] $p] - incr nhyperspace -1 - } - } - - set lastuse($id) $lineno - - # see if we need to make any lines jump off into hyperspace - set displ [llength $displist] - if {$displ > $maxwidth} { - set ages {} - foreach x $displist { - lappend ages [list $lastuse($x) $x] - } - set ages [lsort -integer -index 0 $ages] - set k 0 - while {$displ > $maxwidth} { - set use [lindex $ages $k 0] - set victim [lindex $ages $k 1] - if {$use >= $lineno - 5} break - incr k - if {[lsearch -exact $nohs $victim] >= 0} continue - set i [lsearch -exact $displist $victim] - set displist [lreplace $displist $i $i] - set onscreen($victim) -1 - incr nhyperspace - incr displ -1 - if {$i < $nullentry} { - incr nullentry -1 - } - set x [lindex $mainline($victim) end-1] - lappend mainline($victim) $x $y1 - set line [trimdiagend $mainline($victim)] - set arrow "last" - if {$mainlinearrow($victim) ne "none"} { - set line [trimdiagstart $line] - set arrow "both" - } - lappend sidelines($victim) [list $line 1 $arrow] - unset mainline($victim) - } - } - - set dlevel [lsearch -exact $displist $id] - - # If we are reducing, put in a null entry - if {$displ < $oldnlines} { - # does the next line look like a merge? - # i.e. does it have > 1 new parent? - if {$nnewparents($id) > 1} { - set i [expr {$dlevel + 1}] - } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} { - set i $olddlevel - if {$nullentry >= 0 && $nullentry < $i} { - incr i -1 - } - } elseif {$nullentry >= 0} { - set i $nullentry - while {$i < $displ - && [lindex $olddisplist $i] == [lindex $displist $i]} { - incr i - } - } else { - set i $olddlevel - if {$dlevel >= $i} { - incr i - } - } - if {$i < $displ} { - set displist [linsert $displist $i {}] - incr displ - if {$dlevel >= $i} { - incr dlevel - } - } - } - - # decide on the line spacing for the next line - set lj [expr {$lineno + 1}] - set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}] - if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} { - set xspc1($lj) $xspc2 - } else { - set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}] - if {$xspc1($lj) < $lthickness} { - set xspc1($lj) $lthickness - } - } - - foreach idi $reins { - set id [lindex $idi 0] - set j [lsearch -exact $displist $id] - set xj [xcoord $j $dlevel $lj] - set mainline($id) [list $xj $y2] - set mainlinearrow($id) first - } - - set i -1 - foreach id $olddisplist { - incr i - if {$id == {}} continue - if {$onscreen($id) <= 0} continue - set xi [xcoord $i $olddlevel $lineno] - if {$i == $olddlevel} { - foreach p $currentparents { - set j [lsearch -exact $displist $p] - set coords [list $xi $y1] - set xj [xcoord $j $dlevel $lj] - if {$xj < $xi - $linespc} { - lappend coords [expr {$xj + $linespc}] $y1 - notecrossings $p $j $i [expr {$j + 1}] - } elseif {$xj > $xi + $linespc} { - lappend coords [expr {$xj - $linespc}] $y1 - notecrossings $p $i $j [expr {$j - 1}] - } - if {[lsearch -exact $dupparents $p] >= 0} { - # draw a double-width line to indicate the doubled parent - lappend coords $xj $y2 - lappend sidelines($p) [list $coords 2 none] - if {![info exists mainline($p)]} { - set mainline($p) [list $xj $y2] - set mainlinearrow($p) none - } - } else { - # normal case, no parent duplicated - set yb $y2 - set dx [expr {abs($xi - $xj)}] - if {0 && $dx < $linespc} { - set yb [expr {$y1 + $dx}] - } - if {![info exists mainline($p)]} { - if {$xi != $xj} { - lappend coords $xj $yb - } - set mainline($p) $coords - set mainlinearrow($p) none - } else { - lappend coords $xj $yb - if {$yb < $y2} { - lappend coords $xj $y2 - } - lappend sidelines($p) [list $coords 1 none] - } - } - } - } else { - set j $i - if {[lindex $displist $i] != $id} { - set j [lsearch -exact $displist $id] - } - if {$j != $i || $xspc1($lineno) != $xspc1($lj) - || ($olddlevel < $i && $i < $dlevel) - || ($dlevel < $i && $i < $olddlevel)} { - set xj [xcoord $j $dlevel $lj] - lappend mainline($id) $xi $y1 $xj $y2 - } - } - } - return $dlevel -} - -# search for x in a list of lists -proc llsearch {llist x} { - set i 0 - foreach l $llist { - if {$l == $x || [lsearch -exact $l $x] >= 0} { - return $i - } - incr i - } - return -1 -} - -proc drawmore {reading} { - global displayorder numcommits ncmupdate nextupdate - global stopped nhyperspace parents commitlisted - global maxwidth onscreen displist currentparents olddlevel - - set n [llength $displayorder] - while {$numcommits < $n} { - set id [lindex $displayorder $numcommits] - set ctxend [expr {$numcommits + 10}] - if {!$reading && $ctxend > $n} { - set ctxend $n - } - set dlist {} - if {$numcommits > 0} { - set dlist [lreplace $displist $olddlevel $olddlevel] - set i $olddlevel - foreach p $currentparents { - if {$onscreen($p) == 0} { - set dlist [linsert $dlist $i $p] - incr i - } - } - } - set nohs {} - set reins {} - set isfat [expr {[llength $dlist] > $maxwidth}] - if {$nhyperspace > 0 || $isfat} { - if {$ctxend > $n} break - # work out what to bring back and - # what we want to don't want to send into hyperspace - set room 1 - for {set k $numcommits} {$k < $ctxend} {incr k} { - set x [lindex $displayorder $k] - set i [llsearch $dlist $x] - if {$i < 0} { - set i [llength $dlist] - lappend dlist $x - } - if {[lsearch -exact $nohs $x] < 0} { - lappend nohs $x - } - if {$reins eq {} && $onscreen($x) < 0 && $room} { - set reins [list $x $i] - } - set newp {} - if {[info exists commitlisted($x)]} { - set right 0 - foreach p $parents($x) { - if {[llsearch $dlist $p] < 0} { - lappend newp $p - if {[lsearch -exact $nohs $p] < 0} { - lappend nohs $p - } - if {$reins eq {} && $onscreen($p) < 0 && $room} { - set reins [list $p [expr {$i + $right}]] - } - } - set right 1 - } - } - set l [lindex $dlist $i] - if {[llength $l] == 1} { - set l $newp - } else { - set j [lsearch -exact $l $x] - set l [concat [lreplace $l $j $j] $newp] - } - set dlist [lreplace $dlist $i $i $l] - if {$room && $isfat && [llength $newp] <= 1} { - set room 0 - } - } - } - - set dlevel [drawslants $id $reins $nohs] - drawcommitline $dlevel - if {[clock clicks -milliseconds] >= $nextupdate - && $numcommits >= $ncmupdate} { - doupdate $reading - if {$stopped} break - } - } -} - -# level here is an index in todo -proc updatetodo {level noshortcut} { - global ncleft todo nnewparents - global commitlisted parents onscreen - - set id [lindex $todo $level] - set olds {} - if {[info exists commitlisted($id)]} { - foreach p $parents($id) { - if {[lsearch -exact $olds $p] < 0} { - lappend olds $p - } - } - } - if {!$noshortcut && [llength $olds] == 1} { - set p [lindex $olds 0] - if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} { - set ncleft($p) 0 - set todo [lreplace $todo $level $level $p] - set onscreen($p) 0 - set nnewparents($id) 1 - return 0 - } - } - - set todo [lreplace $todo $level $level] - set i $level - set n 0 - foreach p $olds { - incr ncleft($p) -1 - set k [lsearch -exact $todo $p] - if {$k < 0} { - set todo [linsert $todo $i $p] - set onscreen($p) 0 - incr i - incr n - } - } - set nnewparents($id) $n - - return 1 -} - -proc decidenext {{noread 0}} { - global ncleft todo - global datemode cdate - global commitinfo - - # choose which one to do next time around - set todol [llength $todo] - set level -1 - set latest {} - for {set k $todol} {[incr k -1] >= 0} {} { - set p [lindex $todo $k] - if {$ncleft($p) == 0} { - if {$datemode} { - if {![info exists commitinfo($p)]} { - if {$noread} { - return {} - } - readcommit $p - } - if {$latest == {} || $cdate($p) > $latest} { - set level $k - set latest $cdate($p) - } - } else { - set level $k - break - } - } - } - - return $level -} - proc drawcommit {id reading} { - global phase todo nchildren datemode nextupdate revlistorder ncleft - global numcommits ncmupdate displayorder todo onscreen parents - global commitlisted commitordered + global phase todo nchildren nextupdate + global displayorder parents + global commitrow commitidx lineid if {$phase != "incrdraw"} { set phase incrdraw set displayorder {} set todo {} + set commitidx 0 + initlayout initgraph - catch {unset commitordered} } - set commitordered($id) 1 - if {$nchildren($id) == 0} { - lappend todo $id - set onscreen($id) 0 - } - if {$revlistorder} { - set level [lsearch -exact $todo $id] - if {$level < 0} { - error_popup "oops, $id isn't in todo" - return - } - lappend displayorder $id - updatetodo $level 0 - } else { - set level [decidenext 1] - if {$level == {} || $level < 0} return - while 1 { - set id [lindex $todo $level] - if {![info exists commitordered($id)]} { - break - } - lappend displayorder [lindex $todo $level] - if {[updatetodo $level $datemode]} { - set level [decidenext 1] - if {$level == {} || $level < 0} break - } - } - } - drawmore $reading + set commitrow($id) $commitidx + set lineid($commitidx) $id + incr commitidx + lappend displayorder $id } proc finishcommits {} { global phase oldcommits commits global canv mainfont ctext maincursor textcursor - global parents displayorder todo + global parents todo if {$phase == "incrdraw" || $phase == "removecommits"} { foreach id $oldcommits { @@ -1613,61 +1733,22 @@ proc settextcursor {c} { set curtextcursor $c } -proc drawgraph {} { - global nextupdate startmsecs ncmupdate - global displayorder onscreen - - if {$displayorder == {}} return - set startmsecs [clock clicks -milliseconds] - set nextupdate [expr {$startmsecs + 100}] - set ncmupdate 1 - initgraph - foreach id $displayorder { - set onscreen($id) 0 - } - drawmore 0 -} - proc drawrest {} { - global phase stopped redisplaying selectedline - global datemode todo displayorder ncleft - global numcommits ncmupdate - global nextupdate startmsecs revlistorder + global phase + global numcommits + global startmsecs + global canvy0 numcommits linespc + global rowlaidout commitidx - set level [decidenext] - if {$level >= 0} { - set phase drawgraph - while 1 { - lappend displayorder [lindex $todo $level] - set hard [updatetodo $level $datemode] - if {$hard} { - set level [decidenext] - if {$level < 0} break - } - } - } - if {$todo != {}} { - puts "ERROR: none of the pending commits can be done yet:" - foreach p $todo { - puts " $p ($ncleft($p))" - } - } + set row $rowlaidout + layoutrows $rowlaidout $commitidx 1 + layouttail + optimize_rows $row 0 $commitidx + showstuff $commitidx - drawmore 0 set phase {} set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}] #puts "overall $drawmsecs ms for $numcommits commits" - if {$redisplaying} { - if {$stopped == 0 && [info exists selectedline]} { - selectline $selectedline 0 - } - if {$stopped == 1} { - set stopped 0 - after idle drawgraph - } else { - set redisplaying 0 - } - } } proc findmatches {f} { @@ -1734,10 +1815,13 @@ proc dofind {} { if {$matches == {}} continue set doesmatch 1 if {$ty == "Headline"} { + drawcmitrow $l markmatches $canv $l $f $linehtag($l) $matches $mainfont } elseif {$ty == "Author"} { + drawcmitrow $l markmatches $canv2 $l $f $linentag($l) $matches $namefont } elseif {$ty == "Date"} { + drawcmitrow $l markmatches $canv3 $l $f $linedtag($l) $matches $mainfont } } @@ -1886,7 +1970,7 @@ proc findpatches {} { proc readfindproc {} { global findprocfile finddidsel - global idline matchinglines findinsertpos + global commitrow matchinglines findinsertpos set n [gets $findprocfile line] if {$n < 0} { @@ -1903,11 +1987,11 @@ proc readfindproc {} { stopfindproc return } - if {![info exists idline($id)]} { + if {![info exists commitrow($id)]} { puts stderr "spurious id: $id" return } - set l $idline($id) + set l $commitrow($id) insertmatch $l $id } @@ -2090,6 +2174,7 @@ proc findcont {id} { proc markheadline {l id} { global canv mainfont linehtag commitinfo + drawcmitrow $l set bbox [$canv bbox $linehtag($l)] set t [$canv create rect $bbox -outline {} -tags matches -fill yellow] $canv lower $t @@ -2123,7 +2208,7 @@ proc unmarkmatches {} { proc selcanvline {w x y} { global canv canvy0 ctext linespc - global lineid linehtag linentag linedtag rowtextx + global rowtextx set ymax [lindex [$canv cget -scrollregion] 3] if {$ymax == {}} return set yfrac [lindex [$canv yview] 0] @@ -2151,7 +2236,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} { - global ctext idline linknum + global ctext commitrow linknum set start [$ctext index "end - 1c"] $ctext insert end $text @@ -2161,11 +2246,11 @@ proc appendwithlinks {text} { set s [lindex $l 0] set e [lindex $l 1] set linkid [string range $text $s $e] - if {![info exists idline($linkid)]} continue + if {![info exists commitrow($linkid)]} continue incr e $ctext tag add link "$start + $s c" "$start + $e c" $ctext tag add link$linknum "$start + $s c" "$start + $e c" - $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1] + $ctext tag bind link$linknum <1> [list selectline $commitrow($linkid) 1] incr linknum } $ctext tag conf link -foreground blue -underline 1 @@ -2178,24 +2263,12 @@ proc selectline {l isnew} { global lineid linehtag linentag linedtag global canvy0 linespc parents nparents children global cflist currentid sha1entry - global commentend idtags idline linknum + global commentend idtags linknum global mergemax $canv delete hover normalline - if {![info exists lineid($l)] || ![info exists linehtag($l)]} return - $canv delete secsel - set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ - -tags secsel -fill [$canv cget -selectbackground]] - $canv lower $t - $canv2 delete secsel - set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ - -tags secsel -fill [$canv2 cget -selectbackground]] - $canv2 lower $t - $canv3 delete secsel - set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ - -tags secsel -fill [$canv3 cget -selectbackground]] - $canv3 lower $t + if {![info exists lineid($l)]} return set y [expr {$canvy0 + $l * $linespc}] set ymax [lindex [$canv cget -scrollregion] 3] set ytop [expr {$y - $linespc - 1}] @@ -2229,8 +2302,23 @@ proc selectline {l isnew} { set newtop 0 } allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}] + drawvisible } + if {![info exists linehtag($l)]} return + $canv delete secsel + set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ + -tags secsel -fill [$canv cget -selectbackground]] + $canv lower $t + $canv2 delete secsel + set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ + -tags secsel -fill [$canv2 cget -selectbackground]] + $canv2 lower $t + $canv3 delete secsel + set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ + -tags secsel -fill [$canv3 cget -selectbackground]] + $canv3 lower $t + if {$isnew} { addtohistory [list selectline $l 0] } @@ -2662,22 +2750,27 @@ proc setcoords {} { set linespc [font metrics $mainfont -linespace] set charspc [font measure $mainfont "m"] - set canvy0 [expr {3 + 0.5 * $linespc}] - set canvx0 [expr {3 + 0.5 * $linespc}] + set canvy0 [expr {int(3 + 0.5 * $linespc)}] + set canvx0 [expr {int(3 + 0.5 * $linespc)}] set lthickness [expr {int($linespc / 9) + 1}] set xspc1(0) $linespc set xspc2 $linespc } proc redisplay {} { - global stopped redisplaying phase - if {$stopped > 1} return - if {$phase == "getcommits"} return - set redisplaying 1 - if {$phase == "drawgraph" || $phase == "incrdraw"} { - set stopped 1 - } else { - drawgraph + global canv canvy0 linespc numcommits + global selectedline + + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax eq {} || $ymax == 0} return + set span [$canv yview] + clear_display + allcanvs conf -scrollregion \ + [list 0 0 0 [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]] + allcanvs yview moveto [lindex $span 0] + drawvisible + if {[info exists selectedline]} { + selectline $selectedline 0 } } @@ -2724,7 +2817,7 @@ proc sha1change {n1 n2 op} { } proc gotocommit {} { - global sha1string currentid idline tagids + global sha1string currentid commitrow tagids global lineid numcommits if {$sha1string == {} @@ -2749,8 +2842,8 @@ proc gotocommit {} { } } } - if {[info exists idline($id)]} { - selectline $idline($id) 1 + if {[info exists commitrow($id)]} { + selectline $commitrow($id) 1 return } if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} { @@ -2905,7 +2998,7 @@ proc lineclick {x y id isnew} { normalline $canv delete hover # draw this line thicker than normal - drawlines $id 1 1 + drawlines $id 1 set thickerline $id if {$isnew} { set ymax [lindex [$canv cget -scrollregion] 3] @@ -2959,15 +3052,15 @@ proc lineclick {x y id isnew} { proc normalline {} { global thickerline if {[info exists thickerline]} { - drawlines $thickerline 0 1 + drawlines $thickerline 0 unset thickerline } } proc selbyid {id} { - global idline - if {[info exists idline($id)]} { - selectline $idline($id) 1 + global commitrow + if {[info exists commitrow($id)]} { + selectline $commitrow($id) 1 } } @@ -2980,9 +3073,9 @@ proc mstime {} { } proc rowmenu {x y id} { - global rowctxmenu idline selectedline rowmenuid + global rowctxmenu commitrow selectedline rowmenuid - if {![info exists selectedline] || $idline($id) eq $selectedline} { + if {![info exists selectedline] || $commitrow($id) eq $selectedline} { set state disabled } else { set state normal @@ -3185,13 +3278,14 @@ proc domktag {} { } proc redrawtags {id} { - global canv linehtag idline idpos selectedline + global canv linehtag commitrow idpos selectedline - if {![info exists idline($id)]} return + if {![info exists commitrow($id)]} return + drawcmitrow $commitrow($id) $canv delete tag.$id set xt [eval drawtags $id $idpos($id)] - $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2] - if {[info exists selectedline] && $selectedline == $idline($id)} { + $canv coords $linehtag($commitrow($id)) $xt [lindex $idpos($id) 2] + if {[info exists selectedline] && $selectedline == $commitrow($id)} { selectline $selectedline 0 } } @@ -3697,6 +3791,9 @@ set maxgraphpct 50 set maxwidth 16 set revlistorder 0 set fastdate 0 +set uparrowlen 7 +set downarrowlen 7 +set mingaplen 30 set colors {green red blue magenta darkgrey brown orange} @@ -3711,7 +3808,6 @@ foreach arg $argv { switch -regexp -- $arg { "^$" { } "^-d" { set datemode 1 } - "^-r" { set revlistorder 1 } default { lappend revtreeargs $arg } @@ -3721,8 +3817,9 @@ foreach arg $argv { set history {} set historyindex 0 +set optim_delay 16 + set stopped 0 -set redisplaying 0 set stuffsaved 0 set patchnum 0 setcoords From f634248052d3b9bd58d2d28e06ffde0ba46bad8d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 28 Feb 2006 10:02:03 +1100 Subject: [PATCH 02/13] gitk: Fix clicks on arrows on line ends With the new representation of the graph lines, this turns out much simpler now. Signed-off-by: Paul Mackerras --- gitk | 67 ++++++++++++------------------------------------------------ 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/gitk b/gitk index 502f2665af..4e66d865f1 100755 --- a/gitk +++ b/gitk @@ -2918,65 +2918,26 @@ proc linehover {} { } proc clickisonarrow {id y} { - global mainline mainlinearrow sidelines lthickness + global lthickness idrowranges set thresh [expr {2 * $lthickness + 6}] - if {[info exists mainline($id)]} { - if {$mainlinearrow($id) ne "none"} { - if {abs([lindex $mainline($id) 1] - $y) < $thresh} { - return "up" - } - } - } - if {[info exists sidelines($id)]} { - foreach ls $sidelines($id) { - set coords [lindex $ls 0] - set arrow [lindex $ls 2] - if {$arrow eq "first" || $arrow eq "both"} { - if {abs([lindex $coords 1] - $y) < $thresh} { - return "up" - } - } - if {$arrow eq "last" || $arrow eq "both"} { - if {abs([lindex $coords end] - $y) < $thresh} { - return "down" - } - } + set n [expr {[llength $idrowranges($id)] - 1}] + for {set i 1} {$i < $n} {incr i} { + set row [lindex $idrowranges($id) $i] + if {abs([yc $row] - $y) < $thresh} { + return $i } } return {} } -proc arrowjump {id dirn y} { - global mainline sidelines canv canv2 canv3 +proc arrowjump {id n y} { + global idrowranges canv - set yt {} - if {$dirn eq "down"} { - if {[info exists mainline($id)]} { - set y1 [lindex $mainline($id) 1] - if {$y1 > $y} { - set yt $y1 - } - } - if {[info exists sidelines($id)]} { - foreach ls $sidelines($id) { - set y1 [lindex $ls 0 1] - if {$y1 > $y && ($yt eq {} || $y1 < $yt)} { - set yt $y1 - } - } - } - } else { - if {[info exists sidelines($id)]} { - foreach ls $sidelines($id) { - set y1 [lindex $ls 0 end] - if {$y1 < $y && ($yt eq {} || $y1 > $yt)} { - set yt $y1 - } - } - } - } - if {$yt eq {}} return + # 1 <-> 2, 3 <-> 4, etc... + set n [expr {(($n - 1) ^ 1) + 1}] + set row [lindex $idrowranges($id) $n] + set yt [yc $row] set ymax [lindex [$canv cget -scrollregion] 3] if {$ymax eq {} || $ymax <= 0} return set view [$canv yview] @@ -2985,9 +2946,7 @@ proc arrowjump {id dirn y} { if {$yfrac < 0} { set yfrac 0 } - $canv yview moveto $yfrac - $canv2 yview moveto $yfrac - $canv3 yview moveto $yfrac + allcanvs yview moveto $yfrac } proc lineclick {x y id isnew} { From aa81d97476de941015224c99092cb1f49f451a23 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 28 Feb 2006 11:27:12 +1100 Subject: [PATCH 03/13] gitk: Fix Update menu item This just does the simple thing of resetting everything, reading all the commits, and redoing the whole layout from scratch. Hopefully things are now fast enough that this simple approach is acceptable. Also, this fits in better with future plans for adding the ability to restrict the tree to just a few files and then expand back to the whole tree. Signed-off-by: Paul Mackerras --- gitk | 138 ++++++++++------------------------------------------------- 1 file changed, 23 insertions(+), 115 deletions(-) diff --git a/gitk b/gitk index 4e66d865f1..ef41f75765 100755 --- a/gitk +++ b/gitk @@ -61,16 +61,8 @@ proc start_rev_list {rlargs} { } proc getcommits {rargs} { - global oldcommits commits phase canv mainfont env + global phase canv mainfont - # check that we can find a .git directory somewhere... - set gitdir [gitdir] - if {![file isdirectory $gitdir]} { - error_popup "Cannot find the git directory \"$gitdir\"." - exit 1 - } - set oldcommits {} - set commits {} set phase getcommits start_rev_list [parse_args $rargs] $canv delete all @@ -79,8 +71,8 @@ proc getcommits {rargs} { } proc getcommitlines {commfd} { - global oldcommits commits parents cdate children nchildren - global commitlisted phase nextupdate + global parents cdate children nchildren + global commitlisted nextupdate global stopped leftover global canv @@ -140,7 +132,6 @@ proc getcommitlines {commfd} { set id [lindex $ids 0] set olds [lrange $ids 1 end] set cmit [string range $cmit [expr {$j + 1}] end] - lappend commits $id set commitlisted($id) 1 parsecommit $id $cmit 1 [lrange $ids 1 end] drawcommit $id 1 @@ -177,93 +168,18 @@ proc readcommit {id} { } proc updatecommits {rargs} { - global commitlisted commfd phase - global startmsecs nextupdate ncmupdate - global idtags idheads idotherrefs - global leftover - global parsed_args - global canv mainfont - global oldcommits commits - global parents nchildren children - - set old_args $parsed_args - parse_args $rargs - - if {$phase == "getcommits" || $phase == "incrdraw"} { - # havent read all the old commits, just start again from scratch - stopfindproc - set oldcommits {} - set commits {} - foreach v {children nchildren parents commitlisted commitinfo - selectedline matchinglines treediffs - mergefilelist currentid rowtextx} { - global $v - catch {unset $v} - } - readrefs - if {$phase == "incrdraw"} { - allcanvs delete all - $canv create text 3 3 -anchor nw -text "Reading commits..." \ - -font $mainfont -tags textitems - set phase getcommits - } - start_rev_list $parsed_args - return + stopfindproc + foreach v {children nchildren parents nparents commitlisted + commitinfo colormap selectedline matchinglines treediffs + mergefilelist currentid rowtextx commitrow lineid + rowidlist rowoffsets idrowranges idrangedrawn iddrawn + linesegends crossings cornercrossings} { + global $v + catch {unset $v} } - - foreach id $old_args { - if {![regexp {^[0-9a-f]{40}$} $id]} continue - if {[info exists oldref($id)]} continue - set oldref($id) $id - lappend ignoreold "^$id" - } - foreach id $parsed_args { - if {![regexp {^[0-9a-f]{40}$} $id]} continue - if {[info exists ref($id)]} continue - set ref($id) $id - lappend ignorenew "^$id" - } - - foreach a $old_args { - if {![info exists ref($a)]} { - lappend ignorenew $a - } - } - - set phase updatecommits - set oldcommits $commits - set commits {} - set removed_commits [split [eval exec git-rev-list $ignorenew] "\n" ] - if {[llength $removed_commits] > 0} { - allcanvs delete all - foreach c $removed_commits { - set i [lsearch -exact $oldcommits $c] - if {$i >= 0} { - set oldcommits [lreplace $oldcommits $i $i] - unset commitlisted($c) - foreach p $parents($c) { - if {[info exists nchildren($p)]} { - set j [lsearch -exact $children($p) $c] - if {$j >= 0} { - set children($p) [lreplace $children($p) $j $j] - incr nchildren($p) -1 - } - } - } - } - } - set phase removecommits - } - - set args {} - foreach a $parsed_args { - if {![info exists oldref($a)]} { - lappend args $a - } - } - + allcanvs delete all readrefs - start_rev_list [concat $ignoreold $args] + getcommits $rargs } proc updatechildren {id olds} { @@ -1456,7 +1372,7 @@ proc clear_display {} { } proc assigncolor {id} { - global colormap commcolors colors nextcolor + global colormap colors nextcolor global parents nparents children nchildren global cornercrossings crossings @@ -1533,10 +1449,6 @@ proc initgraph {} { allcanvs delete all set nextcolor 0 set numcommits 0 - foreach v {colormap cornercrossings crossings lineid} { - global $v - catch {unset $v} - } } proc bindline {t id} { @@ -1696,22 +1608,11 @@ proc drawcommit {id reading} { } proc finishcommits {} { - global phase oldcommits commits + global phase global canv mainfont ctext maincursor textcursor - global parents todo - if {$phase == "incrdraw" || $phase == "removecommits"} { - foreach id $oldcommits { - lappend commits $id - drawcommit $id 0 - } - set oldcommits {} + if {$phase == "incrdraw"} { drawrest - } elseif {$phase == "updatecommits"} { - # there were no new commits, in fact - set commits $oldcommits - set oldcommits {} - set phase {} } else { $canv delete all $canv create text 3 3 -anchor nw -text "No commits selected" \ @@ -3773,6 +3674,13 @@ foreach arg $argv { } } +# check that we can find a .git directory somewhere... +set gitdir [gitdir] +if {![file isdirectory $gitdir]} { + error_popup "Cannot find the git directory \"$gitdir\"." + exit 1 +} + set history {} set historyindex 0 From 8f7d0cecf4b4999f71e0c5346de2f24beebd67dd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 28 Feb 2006 22:10:19 +1100 Subject: [PATCH 04/13] gitk: Various speed improvements This rearranges the code a little to eliminate some procedure calls and reduce the number of globals accessed. It makes rowidlist and rowoffsets lists rather than arrays, and removes the lineid array, since $lineid($l) was the same as [lindex $displayorder $l], and the latter is a little faster. Signed-off-by: Paul Mackerras --- gitk | 228 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 112 insertions(+), 116 deletions(-) diff --git a/gitk b/gitk index ef41f75765..cca9d355f6 100755 --- a/gitk +++ b/gitk @@ -39,6 +39,7 @@ proc start_rev_list {rlargs} { set startmsecs [clock clicks -milliseconds] set nextupdate [expr {$startmsecs + 100}] set ncmupdate 1 + initlayout set order "--topo-order" if {$datemode} { set order "--date-order" @@ -72,9 +73,10 @@ proc getcommits {rargs} { proc getcommitlines {commfd} { global parents cdate children nchildren - global commitlisted nextupdate + global commitlisted commitinfo phase nextupdate global stopped leftover global canv + global displayorder commitidx commitrow set stuff [read $commfd] if {$stuff == {}} { @@ -97,16 +99,19 @@ proc getcommitlines {commfd} { exit 1 } set start 0 + set gotsome 0 while 1 { set i [string first "\0" $stuff $start] if {$i < 0} { append leftover [string range $stuff $start end] break } - set cmit [string range $stuff $start [expr {$i - 1}]] if {$start == 0} { - set cmit "$leftover$cmit" + set cmit $leftover + append cmit [string range $stuff 0 [expr {$i - 1}]] set leftover {} + } else { + set cmit [string range $stuff $start [expr {$i - 1}]] } set start [expr {$i + 1}] set j [string first "\n" $cmit] @@ -115,7 +120,7 @@ proc getcommitlines {commfd} { set ids [string range $cmit 0 [expr {$j - 1}]] set ok 1 foreach id $ids { - if {![regexp {^[0-9a-f]{40}$} $id]} { + if {[string length $id] != 40} { set ok 0 break } @@ -133,10 +138,18 @@ proc getcommitlines {commfd} { set olds [lrange $ids 1 end] set cmit [string range $cmit [expr {$j + 1}] end] set commitlisted($id) 1 - parsecommit $id $cmit 1 [lrange $ids 1 end] - drawcommit $id 1 + updatechildren $id [lrange $ids 1 end] + if {![info exists commitinfo($id)]} { + parsecommit $id $cmit 1 + } + set commitrow($id) $commitidx + incr commitidx + lappend displayorder $id + set gotsome 1 + } + if {$gotsome} { + layoutmore } - layoutmore if {[clock clicks -milliseconds] >= $nextupdate} { doupdate 1 } @@ -164,14 +177,15 @@ proc doupdate {reading} { proc readcommit {id} { if {[catch {set contents [exec git-cat-file commit $id]}]} return - parsecommit $id $contents 0 {} + updatechildren $id {} + parsecommit $id $contents 0 } proc updatecommits {rargs} { stopfindproc foreach v {children nchildren parents nparents commitlisted - commitinfo colormap selectedline matchinglines treediffs - mergefilelist currentid rowtextx commitrow lineid + colormap selectedline matchinglines treediffs + mergefilelist currentid rowtextx commitrow rowidlist rowoffsets idrowranges idrangedrawn iddrawn linesegends crossings cornercrossings} { global $v @@ -202,7 +216,7 @@ proc updatechildren {id olds} { } } -proc parsecommit {id contents listed olds} { +proc parsecommit {id contents listed} { global commitinfo cdate set inhdr 1 @@ -212,7 +226,6 @@ proc parsecommit {id contents listed olds} { set audate {} set comname {} set comdate {} - updatechildren $id $olds set hdrend [string first "\n\n" $contents] if {$hdrend < 0} { # should never happen... @@ -741,30 +754,30 @@ proc sanity {row {full 0}} { global rowidlist rowoffsets set col -1 - set ids $rowidlist($row) + set ids [lindex $rowidlist $row] foreach id $ids { incr col if {$id eq {}} continue if {$col < [llength $ids] - 1 && [lsearch -exact -start [expr {$col+1}] $ids $id] >= 0} { - puts "oops: [shortids $id] repeated in row $row col $col: {[shortids $rowidlist($row)]}" + puts "oops: [shortids $id] repeated in row $row col $col: {[shortids [lindex $rowidlist $row]]}" } - set o [lindex $rowoffsets($row) $col] + set o [lindex $rowoffsets $row $col] set y $row set x $col while {$o ne {}} { incr y -1 incr x $o - if {[lindex $rowidlist($y) $x] != $id} { + if {[lindex $rowidlist $y $x] != $id} { puts "oops: rowoffsets wrong at row [expr {$y+1}] col [expr {$x-$o}]" puts " id=[shortids $id] check started at row $row" for {set i $row} {$i >= $y} {incr i -1} { - puts " row $i ids={[shortids $rowidlist($i)]} offs={$rowoffsets($i)}" + puts " row $i ids={[shortids [lindex $rowidlist $i]]} offs={[lindex $rowoffsets $i]}" } break } if {!$full} break - set o [lindex $rowoffsets($y) $x] + set o [lindex $rowoffsets $y $x] } } } @@ -775,10 +788,10 @@ proc makeuparrow {oid x y z} { for {set i 1} {$i < $uparrowlen && $y > 1} {incr i} { incr y -1 incr x $z - set off0 $rowoffsets($y) + set off0 [lindex $rowoffsets $y] for {set x0 $x} {1} {incr x0} { if {$x0 >= [llength $off0]} { - set x0 [llength $rowoffsets([expr {$y-1}])] + set x0 [llength [lindex $rowoffsets [expr {$y-1}]]] break } set z [lindex $off0 $x0] @@ -788,11 +801,11 @@ proc makeuparrow {oid x y z} { } } set z [expr {$x0 - $x}] - set rowidlist($y) [linsert $rowidlist($y) $x $oid] - set rowoffsets($y) [linsert $rowoffsets($y) $x $z] + lset rowidlist $y [linsert [lindex $rowidlist $y] $x $oid] + lset rowoffsets $y [linsert [lindex $rowoffsets $y] $x $z] } - set tmp [lreplace $rowoffsets($y) $x $x {}] - set rowoffsets($y) [incrange $tmp [expr {$x+1}] -1] + set tmp [lreplace [lindex $rowoffsets $y] $x $x {}] + lset rowoffsets $y [incrange $tmp [expr {$x+1}] -1] lappend idrowranges($oid) $y } @@ -800,9 +813,15 @@ proc initlayout {} { global rowidlist rowoffsets displayorder global rowlaidout rowoptim global idinlist rowchk + global commitidx numcommits + global nextcolor - set rowidlist(0) {} - set rowoffsets(0) {} + set commitidx 0 + set numcommits 0 + set displayorder {} + set nextcolor 0 + set rowidlist {{}} + set rowoffsets {{}} catch {unset idinlist} catch {unset rowchk} set rowlaidout 0 @@ -851,6 +870,11 @@ proc showstuff {canshow} { global canvy0 linespc global linesegends idrowranges idrangedrawn + if {$numcommits == 0} { + global phase + set phase "incrdraw" + allcanvs delete all + } set row $numcommits set numcommits $canshow allcanvs conf -scrollregion \ @@ -890,8 +914,8 @@ proc layoutrows {row endrow last} { global commitidx global idinlist rowchk - set idlist $rowidlist($row) - set offs $rowoffsets($row) + set idlist [lindex $rowidlist $row] + set offs [lindex $rowoffsets $row] while {$row < $endrow} { set id [lindex $displayorder $row] set oldolds {} @@ -925,21 +949,21 @@ proc layoutrows {row endrow last} { set rowchk($id) [expr {$row + $r}] } } - set rowidlist($row) $idlist - set rowoffsets($row) $offs + lset rowidlist $row $idlist + lset rowoffsets $row $offs } set col [lsearch -exact $idlist $id] if {$col < 0} { set col [llength $idlist] lappend idlist $id - set rowidlist($row) $idlist + lset rowidlist $row $idlist set z {} if {$nchildren($id) > 0} { - set z [expr {[llength $rowidlist([expr {$row-1}])] - $col}] + set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}] unset idinlist($id) } lappend offs $z - set rowoffsets($row) $offs + lset rowoffsets $row $offs if {$z ne {}} { makeuparrow $id $col $row $z } @@ -981,20 +1005,19 @@ proc layoutrows {row endrow last} { makeuparrow $oid $col $row $o incr col } - set rowidlist($row) $idlist - set rowoffsets($row) $offs + lappend rowidlist $idlist + lappend rowoffsets $offs } return $row } proc addextraid {id row} { - global displayorder commitrow lineid commitinfo nparents + global displayorder commitrow commitinfo nparents global commitidx incr commitidx lappend displayorder $id set commitrow($id) $row - set lineid($row) $id readcommit $id if {![info exists commitinfo($id)]} { set commitinfo($id) {"No commit information available"} @@ -1007,7 +1030,7 @@ proc layouttail {} { global idrowranges linesegends set row $commitidx - set idlist $rowidlist($row) + set idlist [lindex $rowidlist $row] while {$idlist ne {}} { set col [expr {[llength $idlist] - 1}] set id [lindex $idlist $col] @@ -1018,18 +1041,20 @@ proc layouttail {} { incr row set offs [ntimes $col 0] set idlist [lreplace $idlist $col $col] - set rowidlist($row) $idlist - set rowoffsets($row) $offs + lappend rowidlist $idlist + lappend rowoffsets $offs } foreach id [array names idinlist] { addextraid $id $row - set rowidlist($row) [list $id] - set rowoffsets($row) 0 + lset rowidlist $row [list $id] + lset rowoffsets $row 0 makeuparrow $id 0 $row 0 lappend linesegends($row) $id lappend idrowranges($id) $row incr row + lappend rowidlist {} + lappend rowoffsets {} } } @@ -1037,17 +1062,17 @@ proc insert_pad {row col npad} { global rowidlist rowoffsets set pad [ntimes $npad {}] - set rowidlist($row) [eval linsert \$rowidlist($row) $col $pad] - set tmp [eval linsert \$rowoffsets($row) $col $pad] - set rowoffsets($row) [incrange $tmp [expr {$col + $npad}] [expr {-$npad}]] + lset rowidlist $row [eval linsert [list [lindex $rowidlist $row]] $col $pad] + set tmp [eval linsert [list [lindex $rowoffsets $row]] $col $pad] + lset rowoffsets $row [incrange $tmp [expr {$col + $npad}] [expr {-$npad}]] } proc optimize_rows {row col endrow} { global rowidlist rowoffsets idrowranges for {} {$row < $endrow} {incr row} { - set idlist $rowidlist($row) - set offs $rowoffsets($row) + set idlist [lindex $rowidlist $row] + set offs [lindex $rowoffsets $row] set haspad 0 for {} {$col < [llength $offs]} {incr col} { if {[lindex $idlist $col] eq {}} { @@ -1059,7 +1084,7 @@ proc optimize_rows {row col endrow} { set isarrow 0 set x0 [expr {$col + $z}] set y0 [expr {$row - 1}] - set z0 [lindex $rowoffsets($y0) $x0] + set z0 [lindex $rowoffsets $y0 $x0] if {$z0 eq {}} { set id [lindex $idlist $col] if {[info exists idrowranges($id)] && @@ -1076,11 +1101,11 @@ proc optimize_rows {row col endrow} { } set z [lindex $offs $col] set x0 [expr {$col + $z}] - set z0 [lindex $rowoffsets($y0) $x0] + set z0 [lindex $rowoffsets $y0 $x0] } elseif {$z > 1 || ($z > 0 && $isarrow)} { set npad [expr {$z - 1 + $isarrow}] set y1 [expr {$row + 1}] - set offs2 $rowoffsets($y1) + set offs2 [lindex $rowoffsets $y1] set x1 -1 foreach z $offs2 { incr x1 @@ -1088,7 +1113,7 @@ proc optimize_rows {row col endrow} { if {$x1 + $z > $col} { incr npad } - set rowoffsets($y1) [incrange $offs2 $x1 $npad] + lset rowoffsets $y1 [incrange $offs2 $x1 $npad] break } set pad [ntimes $npad {}] @@ -1112,12 +1137,12 @@ proc optimize_rows {row col endrow} { } if {[incr col] < [llength $idlist]} { set y1 [expr {$row + 1}] - set offs2 $rowoffsets($y1) + set offs2 [lindex $rowoffsets $y1] set x1 -1 foreach z $offs2 { incr x1 if {$z eq {} || $x1 + $z < $col} continue - set rowoffsets($y1) [incrange $offs2 $x1 1] + lset rowoffsets $y1 [incrange $offs2 $x1 1] break } set idlist [linsert $idlist $col {}] @@ -1126,8 +1151,8 @@ proc optimize_rows {row col endrow} { set offs [incrange $tmp $col -1] } } - set rowidlist($row) $idlist - set rowoffsets($row) $offs + lset rowidlist $row $idlist + lset rowoffsets $row $offs set col 0 } } @@ -1151,7 +1176,7 @@ proc drawlineseg {id i wid} { if {$startrow == $row} return assigncolor $id set coords {} - set col [lsearch -exact $rowidlist($row) $id] + set col [lsearch -exact [lindex $rowidlist $row] $id] if {$col < 0} { puts "oops: drawline: id $id not on row $row" return @@ -1159,7 +1184,7 @@ proc drawlineseg {id i wid} { set lasto {} set ns 0 while {1} { - set o [lindex $rowoffsets($row) $col] + set o [lindex $rowoffsets $row $col] if {$o eq {}} break if {$o ne $lasto} { # changing direction @@ -1186,14 +1211,13 @@ proc drawlineseg {id i wid} { } proc drawparentlinks {id row col olds wid} { - global rowoffsets rowidlist canv colormap lthickness + global rowidlist canv colormap lthickness set row2 [expr {$row + 1}] set x [xc $row $col] set y [yc $row] set y2 [yc $row2] - set ids $rowidlist($row2) - set offs $rowidlist($row2) + set ids [lindex $rowidlist $row2] # rmx = right-most X coord used set rmx 0 set wid [expr {$wid * $lthickness}] @@ -1241,7 +1265,7 @@ proc drawlines {id xtra} { foreach child $children($id) { if {[info exists iddrawn($child)]} { set row $commitrow($child) - set col [lsearch -exact $rowidlist($row) $child] + set col [lsearch -exact [lindex $rowidlist $row] $child] if {$col >= 0} { drawparentlinks $child $row $col [list $id] $wid } @@ -1266,7 +1290,7 @@ proc drawcmittext {id row col rmx} { -fill $ofill -outline black -width 1] $canv raise $t $canv bind $t <1> {selcanvline {} %x %y} - set xt [xc $row [llength $rowidlist($row)]] + set xt [xc $row [llength [lindex $rowidlist $row]]] if {$xt < $rmx} { set xt $rmx } @@ -1290,12 +1314,12 @@ proc drawcmittext {id row col rmx} { } proc drawcmitrow {row} { - global displayorder rowidlist rowoffsets + global displayorder rowidlist global idrowranges idrangedrawn iddrawn global commitinfo commitlisted parents numcommits - if {![info exists rowidlist($row)]} return - foreach id $rowidlist($row) { + if {$row >= $numcommits} return + foreach id [lindex $rowidlist $row] { if {![info exists idrowranges($id)]} continue set i -1 foreach {s e} $idrowranges($id) { @@ -1314,7 +1338,7 @@ proc drawcmitrow {row} { set id [lindex $displayorder $row] if {[info exists iddrawn($id)]} return - set col [lsearch -exact $rowidlist($row) $id] + set col [lsearch -exact [lindex $rowidlist $row] $id] if {$col < 0} { puts "oops, row $row id $id not in list" return @@ -1442,15 +1466,6 @@ proc assigncolor {id} { set colormap($id) $c } -proc initgraph {} { - global numcommits nextcolor linespc - global nchildren - - allcanvs delete all - set nextcolor 0 - set numcommits 0 -} - proc bindline {t id} { global canv @@ -1532,9 +1547,9 @@ proc checkcrossings {row endrow} { for {} {$row < $endrow} {incr row} { set id [lindex $displayorder $row] - set i [lsearch -exact $rowidlist($row) $id] + set i [lsearch -exact [lindex $rowidlist $row] $id] if {$i < 0} continue - set idlist $rowidlist([expr {$row+1}]) + set idlist [lindex $rowidlist [expr {$row+1}]] foreach p $parents($id) { set j [lsearch -exact $idlist $p] if {$j > 0} { @@ -1552,7 +1567,7 @@ proc notecrossings {row id lo hi corner} { global rowidlist crossings cornercrossings for {set i $lo} {[incr i] < $hi} {} { - set p [lindex $rowidlist($row) $i] + set p [lindex [lindex $rowidlist $row] $i] if {$p == {}} continue if {$i == $corner} { if {![info exists cornercrossings($id)] @@ -1588,25 +1603,6 @@ proc xcoord {i level ln} { return $x } -proc drawcommit {id reading} { - global phase todo nchildren nextupdate - global displayorder parents - global commitrow commitidx lineid - - if {$phase != "incrdraw"} { - set phase incrdraw - set displayorder {} - set todo {} - set commitidx 0 - initlayout - initgraph - } - set commitrow($id) $commitidx - set lineid($commitidx) $id - incr commitidx - lappend displayorder $id -} - proc finishcommits {} { global phase global canv mainfont ctext maincursor textcursor @@ -1674,7 +1670,7 @@ proc findmatches {f} { proc dofind {} { global findtype findloc findstring markedmatches commitinfo - global numcommits lineid linehtag linentag linedtag + global numcommits displayorder linehtag linentag linedtag global mainfont namefont canv canv2 canv3 selectedline global matchinglines foundstring foundstrlen @@ -1705,7 +1701,7 @@ proc dofind {} { set didsel 0 set fldtypes {Headline Author Date Committer CDate Comment} for {set l 0} {$l < $numcommits} {incr l} { - set id $lineid($l) + set id [lindex $displayorder $l] set info $commitinfo($id) set doesmatch 0 foreach f $info ty $fldtypes { @@ -1830,7 +1826,7 @@ proc stopfindproc {{done 0}} { proc findpatches {} { global findstring selectedline numcommits global findprocpid findprocfile - global finddidsel ctext lineid findinprogress + global finddidsel ctext displayorder findinprogress global findinsertpos if {$numcommits == 0} return @@ -1847,7 +1843,7 @@ proc findpatches {} { if {[incr l] >= $numcommits} { set l 0 } - append inputids $lineid($l) "\n" + append inputids [lindex $displayorder $l] "\n" } if {[catch { @@ -1918,7 +1914,7 @@ proc insertmatch {l id} { } proc findfiles {} { - global selectedline numcommits lineid ctext + global selectedline numcommits displayorder ctext global ffileline finddidsel parents nparents global findinprogress findstartline findinsertpos global treediffs fdiffid fdiffsneeded fdiffpos @@ -1936,7 +1932,7 @@ proc findfiles {} { set diffsneeded {} set fdiffsneeded {} while 1 { - set id $lineid($l) + set id [lindex $displayorder $l] if {$findmergefiles || $nparents($id) == 1} { if {![info exists treediffs($id)]} { append diffsneeded "$id\n" @@ -1965,7 +1961,7 @@ proc findfiles {} { set finddidsel 0 set findinsertpos end - set id $lineid($l) + set id [lindex $displayorder $l] . config -cursor watch settextcursor watch set findinprogress 1 @@ -2035,7 +2031,7 @@ proc donefilediff {} { proc findcont {id} { global findid treediffs parents nparents global ffileline findstartline finddidsel - global lineid numcommits matchinglines findinprogress + global displayorder numcommits matchinglines findinprogress global findmergefiles set l $ffileline @@ -2062,7 +2058,7 @@ proc findcont {id} { set l 0 } if {$l == $findstartline} break - set id $lineid($l) + set id [lindex $displayorder $l] } stopfindproc if {!$finddidsel} { @@ -2161,15 +2157,15 @@ proc appendwithlinks {text} { proc selectline {l isnew} { global canv canv2 canv3 ctext commitinfo selectedline - global lineid linehtag linentag linedtag + global displayorder linehtag linentag linedtag global canvy0 linespc parents nparents children global cflist currentid sha1entry global commentend idtags linknum - global mergemax + global mergemax numcommits $canv delete hover normalline - if {![info exists lineid($l)]} return + if {$l < 0 || $l >= $numcommits} return set y [expr {$canvy0 + $l * $linespc}] set ymax [lindex [$canv cget -scrollregion] 3] set ytop [expr {$y - $linespc - 1}] @@ -2226,7 +2222,7 @@ proc selectline {l isnew} { set selectedline $l - set id $lineid($l) + set id [lindex $displayorder $l] set currentid $id $sha1entry delete 0 end $sha1entry insert 0 $id @@ -2719,7 +2715,7 @@ proc sha1change {n1 n2 op} { proc gotocommit {} { global sha1string currentid commitrow tagids - global lineid numcommits + global displayorder numcommits if {$sha1string == {} || ([info exists currentid] && $sha1string == $currentid)} return @@ -2730,8 +2726,8 @@ proc gotocommit {} { if {[regexp {^[0-9a-f]{4,39}$} $id]} { set matches {} for {set l 0} {$l < $numcommits} {incr l} { - if {[string match $id* $lineid($l)]} { - lappend matches $lineid($l) + if {[string match $id* [lindex $displayorder $l]]} { + lappend matches [lindex $displayorder $l] } } if {$matches ne {}} { @@ -2948,15 +2944,15 @@ proc rowmenu {x y id} { } proc diffvssel {dirn} { - global rowmenuid selectedline lineid + global rowmenuid selectedline displayorder if {![info exists selectedline]} return if {$dirn} { - set oldid $lineid($selectedline) + set oldid [lindex $displayorder $selectedline] set newid $rowmenuid } else { set oldid $rowmenuid - set newid $lineid($selectedline) + set newid [lindex $displayorder $selectedline] } addtohistory [list doseldiff $oldid $newid] doseldiff $oldid $newid From 8ed164841564802cc0b063a6b365fb19e9a513d1 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 2 Mar 2006 22:56:44 +1100 Subject: [PATCH 05/13] gitk: Further speedups Now we don't parse the commits as we are reading them, we just put commit data on a list as a blob, and instead parse the commit when we need the various parts of it, such as when a commit is drawn on the canvas. This makes searching a bit more interesting: now we scan through the commit blobs doing a string or regexp match to find commits that might match, then for those that might match, we parse the commit info (if it isn't already parsed) and do the matching for the various fields as before. Signed-off-by: Paul Mackerras --- gitk | 79 ++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/gitk b/gitk index cca9d355f6..8d7b25870c 100755 --- a/gitk +++ b/gitk @@ -35,6 +35,7 @@ proc parse_args {rargs} { proc start_rev_list {rlargs} { global startmsecs nextupdate ncmupdate global commfd leftover tclencoding datemode + global commitdata set startmsecs [clock clicks -milliseconds] set nextupdate [expr {$startmsecs + 100}] @@ -52,6 +53,7 @@ proc start_rev_list {rlargs} { exit 1 } set leftover {} + set commitdata {} fconfigure $commfd -blocking 0 -translation lf if {$tclencoding != {}} { fconfigure $commfd -encoding $tclencoding @@ -72,11 +74,9 @@ proc getcommits {rargs} { } proc getcommitlines {commfd} { - global parents cdate children nchildren - global commitlisted commitinfo phase nextupdate - global stopped leftover - global canv - global displayorder commitidx commitrow + global commitlisted nextupdate + global leftover + global displayorder commitidx commitrow commitdata set stuff [read $commfd] if {$stuff == {}} { @@ -136,12 +136,9 @@ proc getcommitlines {commfd} { } set id [lindex $ids 0] set olds [lrange $ids 1 end] - set cmit [string range $cmit [expr {$j + 1}] end] set commitlisted($id) 1 updatechildren $id [lrange $ids 1 end] - if {![info exists commitinfo($id)]} { - parsecommit $id $cmit 1 - } + lappend commitdata [string range $cmit [expr {$j + 1}] end] set commitrow($id) $commitidx incr commitidx lappend displayorder $id @@ -269,6 +266,25 @@ proc parsecommit {id contents listed} { $comname $comdate $comment] } +proc getcommit {id {row {}}} { + global commitdata commitrow commitinfo nparents + + if {$row eq {}} { + if {![info exists commitrow($id)]} {return 0} + set row $commitrow($id) + } + if {$row < [llength $commitdata]} { + parsecommit $id [lindex $commitdata $row] 1 + } else { + readcommit $id + if {![info exists commitinfo($id)]} { + set commitinfo($id) {"No commit information available"} + set nparents($id) 0 + } + } + return 1 +} + proc readrefs {} { global tagids idtags headids idheads tagcontents global otherrefids idotherrefs @@ -1317,6 +1333,7 @@ proc drawcmitrow {row} { global displayorder rowidlist global idrowranges idrangedrawn iddrawn global commitinfo commitlisted parents numcommits + global commitdata if {$row >= $numcommits} return foreach id [lindex $rowidlist $row] { @@ -1344,11 +1361,7 @@ proc drawcmitrow {row} { return } if {![info exists commitinfo($id)]} { - readcommit $id - if {![info exists commitinfo($id)]} { - set commitinfo($id) {"No commit information available"} - set nparents($id) 0 - } + getcommit $id $row } assigncolor $id if {[info exists commitlisted($id)] && [info exists parents($id)] @@ -1604,19 +1617,19 @@ proc xcoord {i level ln} { } proc finishcommits {} { - global phase + global commitidx phase global canv mainfont ctext maincursor textcursor - if {$phase == "incrdraw"} { + if {$commitidx > 0} { drawrest } else { $canv delete all $canv create text 3 3 -anchor nw -text "No commits selected" \ -font $mainfont -tags textitems - set phase {} } . config -cursor $maincursor settextcursor $textcursor + set phase {} } # Don't change the text pane cursor if it is currently the hand cursor, @@ -1672,7 +1685,8 @@ proc dofind {} { global findtype findloc findstring markedmatches commitinfo global numcommits displayorder linehtag linentag linedtag global mainfont namefont canv canv2 canv3 selectedline - global matchinglines foundstring foundstrlen + global matchinglines foundstring foundstrlen matchstring + global commitdata stopfindproc unmarkmatches @@ -1689,6 +1703,8 @@ proc dofind {} { } set foundstrlen [string length $findstring] if {$foundstrlen == 0} return + regsub -all {[*?\[\\]} $foundstring {\\&} matchstring + set matchstring "*$matchstring*" if {$findloc == "Files"} { findfiles return @@ -1700,8 +1716,21 @@ proc dofind {} { } set didsel 0 set fldtypes {Headline Author Date Committer CDate Comment} - for {set l 0} {$l < $numcommits} {incr l} { + set l -1 + foreach d $commitdata { + incr l + if {$findtype == "Regexp"} { + set doesmatch [regexp $foundstring $d] + } elseif {$findtype == "IgnCase"} { + set doesmatch [string match -nocase $matchstring $d] + } else { + set doesmatch [string match $matchstring $d] + } + if {!$doesmatch} continue set id [lindex $displayorder $l] + if {![info exists commitinfo($id)]} { + getcommit $id $l + } set info $commitinfo($id) set doesmatch 0 foreach f $info ty $fldtypes { @@ -2069,7 +2098,7 @@ proc findcont {id} { # mark a commit as matching by putting a yellow background # behind the headline proc markheadline {l id} { - global canv mainfont linehtag commitinfo + global canv mainfont linehtag drawcmitrow $l set bbox [$canv bbox $linehtag($l)] @@ -2725,9 +2754,9 @@ proc gotocommit {} { set id [string tolower $sha1string] if {[regexp {^[0-9a-f]{4,39}$} $id]} { set matches {} - for {set l 0} {$l < $numcommits} {incr l} { - if {[string match $id* [lindex $displayorder $l]]} { - lappend matches [lindex $displayorder $l] + foreach i $displayorder { + if {[string match $id* $i]} { + lappend matches $i } } if {$matches ne {}} { @@ -2755,7 +2784,7 @@ proc lineenter {x y id} { global hoverx hovery hoverid hovertimer global commitinfo canv - if {![info exists commitinfo($id)]} return + if {![info exists commitinfo($id)] && ![getcommit $id]} return set hoverx $x set hovery $y set hoverid $id @@ -2849,6 +2878,7 @@ proc arrowjump {id n y} { proc lineclick {x y id isnew} { global ctext commitinfo children cflist canv thickerline + if {![info exists commitinfo($id)] && ![getcommit $id]} return unmarkmatches unselectline normalline @@ -2890,6 +2920,7 @@ proc lineclick {x y id isnew} { set i 0 foreach child $children($id) { incr i + if {![info exists commitinfo($child)] && ![getcommit $child]} continue set info $commitinfo($child) $ctext insert end "\n\t" $ctext insert end $child [list link link$i] From c934a8a3a32896e44123c0a489367a1df1108c4a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 2 Mar 2006 23:00:44 +1100 Subject: [PATCH 06/13] gitk: Fix a bug in drawing the selected line as a thick line If you clicked on a line, so that it was drawn double-thickness, and then scrolled to bring on-screen a child that hadn't previously been drawn, the lines from it to the selected line were drawn single-thickness. This fixes it so they are drawn double-thickness. This also removes an unnecessary setting of phase in drawrest. Signed-off-by: Paul Mackerras --- gitk | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/gitk b/gitk index 8d7b25870c..a70787a879 100755 --- a/gitk +++ b/gitk @@ -906,7 +906,7 @@ proc showstuff {canshow} { incr i if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0 && ![info exists idrangedrawn($id,$i)]} { - drawlineseg $id $i 1 + drawlineseg $id $i set idrangedrawn($id,$i) 1 } } @@ -1183,9 +1183,19 @@ proc yc {row} { return [expr {$canvy0 + $row * $linespc}] } -proc drawlineseg {id i wid} { +proc linewidth {id} { + global thickerline lthickness + + set wid $lthickness + if {[info exists thickerline] && $id eq $thickerline} { + set wid [expr {2 * $lthickness}] + } + return $wid +} + +proc drawlineseg {id i} { global rowoffsets rowidlist idrowranges - global canv colormap lthickness + global canv colormap set startrow [lindex $idrowranges($id) [expr {2 * $i}]] set row [lindex $idrowranges($id) [expr {2 * $i + 1}]] @@ -1216,18 +1226,17 @@ proc drawlineseg {id i wid} { set last [expr {[llength $idrowranges($id)] / 2 - 1}] set arrow [expr {2 * ($i > 0) + ($i < $last)}] set arrow [lindex {none first last both} $arrow] - set wid [expr {$wid * $lthickness}] set x [xc $row $col] set y [yc $row] lappend coords $x $y - set t [$canv create line $coords -width $wid \ + set t [$canv create line $coords -width [linewidth $id] \ -fill $colormap($id) -tags lines.$id -arrow $arrow] $canv lower $t bindline $t $id } -proc drawparentlinks {id row col olds wid} { - global rowidlist canv colormap lthickness +proc drawparentlinks {id row col olds} { + global rowidlist canv colormap set row2 [expr {$row + 1}] set x [xc $row $col] @@ -1236,7 +1245,6 @@ proc drawparentlinks {id row col olds wid} { set ids [lindex $rowidlist $row2] # rmx = right-most X coord used set rmx 0 - set wid [expr {$wid * $lthickness}] foreach p $olds { set i [lsearch -exact $ids $p] if {$i < 0} { @@ -1256,7 +1264,7 @@ proc drawparentlinks {id row col olds wid} { set rmx $x2 } lappend coords $x2 $y2 - set t [$canv create line $coords -width $wid \ + set t [$canv create line $coords -width [linewidth $p] \ -fill $colormap($p) -tags lines.$p] $canv lower $t bindline $t $p @@ -1264,17 +1272,16 @@ proc drawparentlinks {id row col olds wid} { return $rmx } -proc drawlines {id xtra} { +proc drawlines {id} { global colormap canv global idrowranges idrangedrawn global children iddrawn commitrow rowidlist $canv delete lines.$id - set wid [expr {$xtra + 1}] set nr [expr {[llength $idrowranges($id)] / 2}] for {set i 0} {$i < $nr} {incr i} { if {[info exists idrangedrawn($id,$i)]} { - drawlineseg $id $i $wid + drawlineseg $id $i } } if {[info exists children($id)]} { @@ -1283,7 +1290,7 @@ proc drawlines {id xtra} { set row $commitrow($child) set col [lsearch -exact [lindex $rowidlist $row] $child] if {$col >= 0} { - drawparentlinks $child $row $col [list $id] $wid + drawparentlinks $child $row $col [list $id] } } } @@ -1345,7 +1352,7 @@ proc drawcmitrow {row} { if {$e eq {}} break if {$row <= $e} { if {$e < $numcommits && ![info exists idrangedrawn($id,$i)]} { - drawlineseg $id $i 1 + drawlineseg $id $i set idrangedrawn($id,$i) 1 } break @@ -1366,7 +1373,7 @@ proc drawcmitrow {row} { assigncolor $id if {[info exists commitlisted($id)] && [info exists parents($id)] && $parents($id) ne {}} { - set rmx [drawparentlinks $id $row $col $parents($id) 1] + set rmx [drawparentlinks $id $row $col $parents($id)] } else { set rmx 0 } @@ -1644,7 +1651,6 @@ proc settextcursor {c} { } proc drawrest {} { - global phase global numcommits global startmsecs global canvy0 numcommits linespc @@ -1656,7 +1662,6 @@ proc drawrest {} { optimize_rows $row 0 $commitidx showstuff $commitidx - set phase {} set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}] #puts "overall $drawmsecs ms for $numcommits commits" } @@ -2884,8 +2889,8 @@ proc lineclick {x y id isnew} { normalline $canv delete hover # draw this line thicker than normal - drawlines $id 1 set thickerline $id + drawlines $id if {$isnew} { set ymax [lindex [$canv cget -scrollregion] 3] if {$ymax eq {}} return @@ -2939,8 +2944,9 @@ proc lineclick {x y id isnew} { proc normalline {} { global thickerline if {[info exists thickerline]} { - drawlines $thickerline 0 + set id $thickerline unset thickerline + drawlines $id } } From 9f841cf1fbe4150a78555a45fd8a7794010975d4 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Thu, 2 Mar 2006 13:15:05 +0100 Subject: [PATCH 07/13] [PATCH] gitk: Make error_popup react to Return The error popup window can be now closed not only by clicking the button, but also by pressing Return. Signed-Off-By: Martin Mares Signed-off-by: Paul Mackerras --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index a70787a879..36e8647b33 100755 --- a/gitk +++ b/gitk @@ -338,6 +338,7 @@ proc error_popup msg { button $w.ok -text OK -command "destroy $w" pack $w.ok -side bottom -fill x bind $w "grab $w; focus $w" + bind $w "destroy $w" tkwait window $w } From b06bc2a0784cfb5cd9e1313201a16e08c73ff1c6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 8 Mar 2006 09:15:32 +1100 Subject: [PATCH 08/13] gitk: Fix display of diff lines beginning with --- or +++ Lines in a diff beginning with --- or +++ were not being displayed at all. Thanks to Robert Fitzsimons for pointing out the obvious fix, that lines beginning with --- or +++ are only to be suppressed in the diff header. I also took the opportunity to replace a regexp call with a couple of string compare calls, which should be faster. Signed-off-by: Paul Mackerras --- gitk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gitk b/gitk index 36e8647b33..3b8ecd03c5 100755 --- a/gitk +++ b/gitk @@ -2615,7 +2615,9 @@ proc getblobdiffline {bdf ids} { set pad [string range "----------------------------------------" 1 $l] $ctext insert end "$pad $header $pad\n" filesep set diffinhdr 1 - } elseif {[regexp {^(---|\+\+\+)} $line]} { + } elseif {$diffinhdr && [string compare -length 3 $line "---"] == 0} { + # do nothing + } elseif {$diffinhdr && [string compare -length 3 $line "+++"] == 0} { set diffinhdr 0 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \ $line match f1l f1c f2l f2c rest]} { From f7a3e8d254bf0034edfacd5aaf6e13ce2ed58d19 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 18 Mar 2006 10:04:48 +1100 Subject: [PATCH 09/13] gitk: Make commitdata an array rather than a list This turns out to be slightly simpler and faster, and will make things a little easier when we do multiple view support. Signed-off-by: Paul Mackerras --- gitk | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/gitk b/gitk index 3b8ecd03c5..ad2fe3b215 100755 --- a/gitk +++ b/gitk @@ -35,7 +35,6 @@ proc parse_args {rargs} { proc start_rev_list {rlargs} { global startmsecs nextupdate ncmupdate global commfd leftover tclencoding datemode - global commitdata set startmsecs [clock clicks -milliseconds] set nextupdate [expr {$startmsecs + 100}] @@ -53,7 +52,6 @@ proc start_rev_list {rlargs} { exit 1 } set leftover {} - set commitdata {} fconfigure $commfd -blocking 0 -translation lf if {$tclencoding != {}} { fconfigure $commfd -encoding $tclencoding @@ -137,8 +135,8 @@ proc getcommitlines {commfd} { set id [lindex $ids 0] set olds [lrange $ids 1 end] set commitlisted($id) 1 - updatechildren $id [lrange $ids 1 end] - lappend commitdata [string range $cmit [expr {$j + 1}] end] + updatechildren $id $olds + set commitdata($id) [string range $cmit [expr {$j + 1}] end] set commitrow($id) $commitidx incr commitidx lappend displayorder $id @@ -266,15 +264,11 @@ proc parsecommit {id contents listed} { $comname $comdate $comment] } -proc getcommit {id {row {}}} { - global commitdata commitrow commitinfo nparents +proc getcommit {id} { + global commitdata commitinfo nparents - if {$row eq {}} { - if {![info exists commitrow($id)]} {return 0} - set row $commitrow($id) - } - if {$row < [llength $commitdata]} { - parsecommit $id [lindex $commitdata $row] 1 + if {[info exists commitdata($id)]} { + parsecommit $id $commitdata($id) 1 } else { readcommit $id if {![info exists commitinfo($id)]} { @@ -1341,7 +1335,6 @@ proc drawcmitrow {row} { global displayorder rowidlist global idrowranges idrangedrawn iddrawn global commitinfo commitlisted parents numcommits - global commitdata if {$row >= $numcommits} return foreach id [lindex $rowidlist $row] { @@ -1369,7 +1362,7 @@ proc drawcmitrow {row} { return } if {![info exists commitinfo($id)]} { - getcommit $id $row + getcommit $id } assigncolor $id if {[info exists commitlisted($id)] && [info exists parents($id)] @@ -1723,7 +1716,8 @@ proc dofind {} { set didsel 0 set fldtypes {Headline Author Date Committer CDate Comment} set l -1 - foreach d $commitdata { + foreach id $displayorder { + set d $commitdata($id) incr l if {$findtype == "Regexp"} { set doesmatch [regexp $foundstring $d] @@ -1733,9 +1727,8 @@ proc dofind {} { set doesmatch [string match $matchstring $d] } if {!$doesmatch} continue - set id [lindex $displayorder $l] if {![info exists commitinfo($id)]} { - getcommit $id $l + getcommit $id } set info $commitinfo($id) set doesmatch 0 From f4171a19f0a4091093bca4c1671c77b8caa93533 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 18 Mar 2006 16:02:51 +1100 Subject: [PATCH 10/13] gitk: Don't change cursor at end of layout if find in progress If the user is doing a find in files or patches, which changed the cursor to a watch, don't change it back to a pointer when we reach the end of laying out the graph. Signed-off-by: Paul Mackerras --- gitk | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index ad2fe3b215..34f55bc1ec 100755 --- a/gitk +++ b/gitk @@ -1620,6 +1620,7 @@ proc xcoord {i level ln} { proc finishcommits {} { global commitidx phase global canv mainfont ctext maincursor textcursor + global findinprogress if {$commitidx > 0} { drawrest @@ -1628,8 +1629,10 @@ proc finishcommits {} { $canv create text 3 3 -anchor nw -text "No commits selected" \ -font $mainfont -tags textitems } - . config -cursor $maincursor - settextcursor $textcursor + if {![info exists findinprogress]} { + . config -cursor $maincursor + settextcursor $textcursor + } set phase {} } @@ -1657,7 +1660,7 @@ proc drawrest {} { showstuff $commitidx set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}] - #puts "overall $drawmsecs ms for $numcommits commits" + puts "overall $drawmsecs ms for $numcommits commits" } proc findmatches {f} { From d8d2df08f6c5f804878bf9faf0820db87dbd68f5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 18 Mar 2006 20:42:46 +1100 Subject: [PATCH 11/13] gitk: Make downward-pointing arrows end in vertical line segment It seems Tk 8.4 can't draw arrows on diagonal line segments. This adds code to the optimizer to make the last bit of a line go vertically before being terminated with an arrow pointing downwards, so that it will be drawn correctly by Tk 8.4. Signed-off-by: Paul Mackerras --- gitk | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/gitk b/gitk index 34f55bc1ec..69d67ee64a 100755 --- a/gitk +++ b/gitk @@ -952,8 +952,9 @@ proc layoutrows {row endrow last} { set offs [lreplace $offs $x $x] set offs [incrange $offs $x 1] set idinlist($i) 0 - lappend linesegends($row) $i - lappend idrowranges($i) [expr {$row-1}] + set rm1 [expr {$row - 1}] + lappend linesegends($rm1) $i + lappend idrowranges($i) $rm1 if {[incr nev -1] <= 0} break continue } @@ -982,7 +983,6 @@ proc layoutrows {row endrow last} { unset idinlist($id) } if {[info exists idrowranges($id)]} { - lappend linesegends($row) $id lappend idrowranges($id) $row } incr row @@ -1038,7 +1038,7 @@ proc addextraid {id row} { proc layouttail {} { global rowidlist rowoffsets idinlist commitidx - global idrowranges linesegends + global idrowranges set row $commitidx set idlist [lindex $rowidlist $row] @@ -1047,7 +1047,6 @@ proc layouttail {} { set id [lindex $idlist $col] addextraid $id $row unset idinlist($id) - lappend linesegends($row) $id lappend idrowranges($id) $row incr row set offs [ntimes $col 0] @@ -1061,7 +1060,6 @@ proc layouttail {} { lset rowidlist $row [list $id] lset rowoffsets $row 0 makeuparrow $id 0 $row 0 - lappend linesegends($row) $id lappend idrowranges($id) $row incr row lappend rowidlist {} @@ -1079,12 +1077,23 @@ proc insert_pad {row col npad} { } proc optimize_rows {row col endrow} { - global rowidlist rowoffsets idrowranges + global rowidlist rowoffsets idrowranges linesegends displayorder for {} {$row < $endrow} {incr row} { set idlist [lindex $rowidlist $row] set offs [lindex $rowoffsets $row] set haspad 0 + set downarrowcols {} + if {[info exists linesegends($row)]} { + set downarrowcols $linesegends($row) + if {$col > 0} { + while {$downarrowcols ne {}} { + set i [lsearch -exact $idlist [lindex $downarrowcols 0]] + if {$i < 0 || $i >= $col} break + set downarrowcols [lrange $downarrowcols 1 end] + } + } + } for {} {$col < [llength $offs]} {incr col} { if {[lindex $idlist $col] eq {}} { set haspad 1 @@ -1102,6 +1111,10 @@ proc optimize_rows {row col endrow} { $y0 > [lindex $idrowranges($id) 0]} { set isarrow 1 } + } elseif {$downarrowcols ne {} && + [lindex $idlist $col] eq [lindex $downarrowcols 0]} { + set downarrowcols [lrange $downarrowcols 1 end] + set isarrow 1 } if {$z < -1 || ($z < 0 && $isarrow)} { set npad [expr {-1 - $z + $isarrow}] @@ -1660,7 +1673,7 @@ proc drawrest {} { showstuff $commitidx set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}] - puts "overall $drawmsecs ms for $numcommits commits" + #puts "overall $drawmsecs ms for $numcommits commits" } proc findmatches {f} { From eb447a126ce90fa1e8a4887d50fb04902167e57a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 18 Mar 2006 23:11:37 +1100 Subject: [PATCH 12/13] gitk: Improve appearance of first child links The point where the line for a parent joins to the first child shown is visually different from the lines to the other children, because the line doesn't branch, but terminates at the child. Because of this, we now treat the first child a little differently in the optimizer, and we draw its link in drawlineseg rather than drawparentlinks. This improves the appearance of the graph. Signed-off-by: Paul Mackerras --- gitk | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/gitk b/gitk index 69d67ee64a..9f61e68c73 100755 --- a/gitk +++ b/gitk @@ -1148,6 +1148,15 @@ proc optimize_rows {row col endrow} { set z [lindex $offs $col] set haspad 1 } + if {$z0 eq {} && !$isarrow} { + # this line links to its first child on row $row-2 + set rm2 [expr {$row - 2}] + set id [lindex $displayorder $rm2] + set xc [lsearch -exact [lindex $rowidlist $rm2] $id] + if {$xc >= 0} { + set z0 [expr {$xc - $x0}] + } + } if {$z0 ne {} && $z < 0 && $z0 > 0} { insert_pad $y0 $x0 1 set offs [incrange $offs $col 1] @@ -1155,11 +1164,26 @@ proc optimize_rows {row col endrow} { } } if {!$haspad} { + set o {} for {set col [llength $idlist]} {[incr col -1] >= 0} {} { set o [lindex $offs $col] + if {$o eq {}} { + # check if this is the link to the first child + set id [lindex $idlist $col] + if {[info exists idrowranges($id)] && + $row == [lindex $idrowranges($id) 0]} { + # it is, work out offset to child + set y0 [expr {$row - 1}] + set id [lindex $displayorder $y0] + set x0 [lsearch -exact [lindex $rowidlist $y0] $id] + if {$x0 >= 0} { + set o [expr {$x0 - $col}] + } + } + } if {$o eq {} || $o <= 0} break } - if {[incr col] < [llength $idlist]} { + if {$o ne {} && [incr col] < [llength $idlist]} { set y1 [expr {$row + 1}] set offs2 [lindex $rowoffsets $y1] set x1 -1 @@ -1203,6 +1227,7 @@ proc linewidth {id} { proc drawlineseg {id i} { global rowoffsets rowidlist idrowranges + global displayorder global canv colormap set startrow [lindex $idrowranges($id) [expr {2 * $i}]] @@ -1230,13 +1255,29 @@ proc drawlineseg {id i} { incr col $o incr row -1 } - if {$coords eq {}} return - set last [expr {[llength $idrowranges($id)] / 2 - 1}] - set arrow [expr {2 * ($i > 0) + ($i < $last)}] - set arrow [lindex {none first last both} $arrow] set x [xc $row $col] set y [yc $row] lappend coords $x $y + if {$i == 0} { + # draw the link to the first child as part of this line + incr row -1 + set child [lindex $displayorder $row] + set ccol [lsearch -exact [lindex $rowidlist $row] $child] + if {$ccol >= 0} { + set x [xc $row $ccol] + set y [yc $row] + if {$ccol < $col - 1} { + lappend coords [xc $row [expr {$col - 1}]] $yc + } elseif {$ccol > $col + 1} { + lappend coords [xc $row [expr {$col + 1}]] $yc + } + lappend coords $x $y + } + } + if {[llength $coords] < 4} return + set last [expr {[llength $idrowranges($id)] / 2 - 1}] + set arrow [expr {2 * ($i > 0) + ($i < $last)}] + set arrow [lindex {none first last both} $arrow] set t [$canv create line $coords -width [linewidth $id] \ -fill $colormap($id) -tags lines.$id -arrow $arrow] $canv lower $t @@ -1244,7 +1285,7 @@ proc drawlineseg {id i} { } proc drawparentlinks {id row col olds} { - global rowidlist canv colormap + global rowidlist canv colormap idrowranges set row2 [expr {$row + 1}] set x [xc $row $col] @@ -1254,6 +1295,12 @@ proc drawparentlinks {id row col olds} { # rmx = right-most X coord used set rmx 0 foreach p $olds { + if {[info exists idrowranges($p)] && + $row2 == [lindex $idrowranges($p) 0] && + $row2 < [lindex $idrowranges($p) 1]} { + # drawlineseg will do this one for us + continue + } set i [lsearch -exact $ids $p] if {$i < 0} { puts "oops, parent $p of $id not in list" From 7a1d9d14c8475715c6b923f378eb72be096c7963 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 22 Mar 2006 10:21:45 +1100 Subject: [PATCH 13/13] gitk: Fix two bugs reported by users The first was a simple typo where I put $yc instead of [yc $row]. The second was that I broke the logic for keeping up with fast movement through the commits, e.g. when you select a commit and then press down-arrow and let it autorepeat. That got broken when I changed the merge diff display to use git-diff-tree --cc. Signed-off-by: Paul Mackerras --- gitk | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/gitk b/gitk index 9f61e68c73..03cd475f09 100755 --- a/gitk +++ b/gitk @@ -1267,9 +1267,9 @@ proc drawlineseg {id i} { set x [xc $row $ccol] set y [yc $row] if {$ccol < $col - 1} { - lappend coords [xc $row [expr {$col - 1}]] $yc + lappend coords [xc $row [expr {$col - 1}]] [yc $row] } elseif {$ccol > $col + 1} { - lappend coords [xc $row [expr {$col + 1}]] $yc + lappend coords [xc $row [expr {$col + 1}]] [yc $row] } lappend coords $x $y } @@ -2451,9 +2451,10 @@ proc goforw {} { proc mergediff {id} { global parents diffmergeid diffopts mdifffd - global difffilestart + global difffilestart diffids set diffmergeid $id + set diffids $id catch {unset difffilestart} # this doesn't seem to actually affect anything... set env(GIT_DIFF_OPTS) $diffopts @@ -2470,7 +2471,7 @@ proc mergediff {id} { proc getmergediffline {mdf id} { global diffmergeid ctext cflist nextupdate nparents mergemax - global difffilestart + global difffilestart mdifffd set n [gets $mdf line] if {$n < 0} { @@ -2479,7 +2480,8 @@ proc getmergediffline {mdf id} { } return } - if {![info exists diffmergeid] || $id != $diffmergeid} { + if {![info exists diffmergeid] || $id != $diffmergeid + || $mdf != $mdifffd($id)} { return } $ctext conf -state normal @@ -2589,13 +2591,11 @@ proc gettreediffline {gdtf ids} { set treediffs($ids) $treediff unset treepending if {$ids != $diffids} { - gettreediffs $diffids - } else { - if {[info exists diffmergeid]} { - contmergediff $ids - } else { - addtocflist $ids + if {![info exists diffmergeid]} { + gettreediffs $diffids } + } else { + addtocflist $ids } return }