Clean-up trivially redundant diff.
[gitweb.git] / gitk
diff --git a/gitk b/gitk
index ef41f75765b89dead227017c08c3a19d7f239568..fa1e83c494ea6da8ba397d7c0314abd250ef3487 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -39,13 +39,14 @@ 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"
     }
     if {[catch {
        set commfd [open [concat | git-rev-list --header $order \
-                             --parents $rlargs] r]
+                             --parents --boundary $rlargs] r]
     } err]} {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
@@ -71,10 +72,9 @@ proc getcommits {rargs} {
 }
 
 proc getcommitlines {commfd}  {
-    global parents cdate children nchildren
     global commitlisted nextupdate
-    global stopped leftover
-    global canv
+    global leftover
+    global displayorder commitidx commitrow commitdata
 
     set stuff [read $commfd]
     if {$stuff == {}} {
@@ -97,25 +97,33 @@ 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]
        set ok 0
+       set listed 1
        if {$j >= 0} {
            set ids [string range $cmit 0 [expr {$j - 1}]]
+           if {[string range $ids 0 0] == "-"} {
+               set listed 0
+               set ids [string range $ids 1 end]
+           }
            set ok 1
            foreach id $ids {
-               if {![regexp {^[0-9a-f]{40}$} $id]} {
+               if {[string length $id] != 40} {
                    set ok 0
                    break
                }
@@ -130,13 +138,22 @@ proc getcommitlines {commfd}  {
            exit 1
        }
        set id [lindex $ids 0]
-       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
+       if {$listed} {
+           set olds [lrange $ids 1 end]
+           set commitlisted($id) 1
+       } else {
+           set olds {}
+       }
+       updatechildren $id $olds
+       set commitdata($id) [string range $cmit [expr {$j + 1}] end]
+       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 +181,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 +220,7 @@ proc updatechildren {id olds} {
     }
 }
 
-proc parsecommit {id contents listed olds} {
+proc parsecommit {id contents listed} {
     global commitinfo cdate
 
     set inhdr 1
@@ -212,7 +230,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...
@@ -256,6 +273,21 @@ proc parsecommit {id contents listed olds} {
                             $comname $comdate $comment]
 }
 
+proc getcommit {id} {
+    global commitdata commitinfo nparents
+
+    if {[info exists commitdata($id)]} {
+       parsecommit $id $commitdata($id) 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
@@ -309,6 +341,7 @@ proc error_popup msg {
     button $w.ok -text OK -command "destroy $w"
     pack $w.ok -side bottom -fill x
     bind $w <Visibility> "grab $w; focus $w"
+    bind $w <Key-Return> "destroy $w"
     tkwait window $w
 }
 
@@ -479,8 +512,8 @@ proc makewindow {rargs} {
     #bindall <B1-Motion> {selcanvline %W %x %y}
     bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
     bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
-    bindall <2> "allcanvs scan mark 0 %y"
-    bindall <B2-Motion> "allcanvs scan dragto 0 %y"
+    bindall <2> "canvscan mark %W %x %y"
+    bindall <B2-Motion> "canvscan dragto %W %x %y"
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
     bind . <Key-Right> "goforw"
@@ -535,6 +568,19 @@ proc makewindow {rargs} {
     $rowctxmenu add command -label "Write commit to file" -command writecommit
 }
 
+# mouse-2 makes all windows scan vertically, but only the one
+# the cursor is in scans horizontally
+proc canvscan {op w x y} {
+    global canv canv2 canv3
+    foreach c [list $canv $canv2 $canv3] {
+       if {$c == $w} {
+           $c scan $op $x $y
+       } else {
+           $c scan $op 0 $y
+       }
+    }
+}
+
 proc scrollcanv {cscroll f0 f1} {
     $cscroll set $f0 $f1
     drawfrac $f0 $f1
@@ -741,30 +787,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 +821,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 +834,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,13 +846,29 @@ proc initlayout {} {
     global rowidlist rowoffsets displayorder
     global rowlaidout rowoptim
     global idinlist rowchk
+    global commitidx numcommits canvxmax canv
+    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
     set rowoptim 0
+    set canvxmax [$canv cget -width]
+}
+
+proc setcanvscroll {} {
+    global canv canv2 canv3 numcommits linespc canvxmax canvy0
+
+    set ymax [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]
+    $canv conf -scrollregion [list 0 0 $canvxmax $ymax]
+    $canv2 conf -scrollregion [list 0 0 0 $ymax]
+    $canv3 conf -scrollregion [list 0 0 0 $ymax]
 }
 
 proc visiblerows {} {
@@ -848,13 +910,16 @@ proc layoutmore {} {
 
 proc showstuff {canshow} {
     global numcommits
-    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 \
-       [list 0 0 0 [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]]
+    setcanvscroll
     set rows [visiblerows]
     set r0 [lindex $rows 0]
     set r1 [lindex $rows 1]
@@ -866,7 +931,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
                    }
                }
@@ -890,8 +955,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 {}
@@ -917,29 +982,30 @@ 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
                    }
                    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
            }
@@ -947,7 +1013,6 @@ proc layoutrows {row endrow last} {
            unset idinlist($id)
        }
        if {[info exists idrowranges($id)]} {
-           lappend linesegends($row) $id
            lappend idrowranges($id) $row
        }
        incr row
@@ -981,20 +1046,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"}
@@ -1004,32 +1068,32 @@ proc addextraid {id row} {
 
 proc layouttail {} {
     global rowidlist rowoffsets idinlist commitidx
-    global idrowranges linesegends
+    global idrowranges
 
     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]
        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
+       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 +1101,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
+    global rowidlist rowoffsets idrowranges linesegends displayorder
 
     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 +1123,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 +1140,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 +1152,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 {}]
@@ -1099,6 +1163,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]
@@ -1106,18 +1179,33 @@ 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 $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 +1214,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
     }
 }
@@ -1142,16 +1230,27 @@ 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 displayorder
+    global canv colormap linespc
 
     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]
+    set col [lsearch -exact [lindex $rowidlist $row] $id]
     if {$col < 0} {
        puts "oops: drawline: id $id not on row $row"
        return
@@ -1159,7 +1258,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
@@ -1171,38 +1270,81 @@ proc drawlineseg {id i wid} {
        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 \
+    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 $row]
+           } elseif {$ccol > $col + 1} {
+               lappend coords [xc $row [expr {$col + 1}]] [yc $row]
+           }
+           lappend coords $x $y
+       }
+    }
+    if {[llength $coords] < 4} return
+    set last [expr {[llength $idrowranges($id)] / 2 - 1}]
+    if {$i < $last} {
+       # This line has an arrow at the lower end: check if the arrow is
+       # on a diagonal segment, and if so, work around the Tk 8.4
+       # refusal to draw arrows on diagonal lines.
+       set x0 [lindex $coords 0]
+       set x1 [lindex $coords 2]
+       if {$x0 != $x1} {
+           set y0 [lindex $coords 1]
+           set y1 [lindex $coords 3]
+           if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
+               # we have a nearby vertical segment, just trim off the diag bit
+               set coords [lrange $coords 2 end]
+           } else {
+               set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
+               set xi [expr {$x0 - $slope * $linespc / 2}]
+               set yi [expr {$y0 - $linespc / 2}]
+               set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
+           }
+       }
+    }
+    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
     bindline $t $id
 }
 
-proc drawparentlinks {id row col olds wid} {
-    global rowoffsets rowidlist canv colormap lthickness
+proc drawparentlinks {id row col olds} {
+    global rowidlist canv colormap idrowranges
 
     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}]
     foreach p $olds {
        set i [lsearch -exact $ids $p]
        if {$i < 0} {
            puts "oops, parent $p of $id not in list"
            continue
        }
+       set x2 [xc $row2 $i]
+       if {$x2 > $rmx} {
+           set rmx $x2
+       }
+       if {[info exists idrowranges($p)] &&
+           $row2 == [lindex $idrowranges($p) 0] &&
+           $row2 < [lindex $idrowranges($p) 1]} {
+           # drawlineseg will do this one for us
+           continue
+       }
        assigncolor $p
        # should handle duplicated parents here...
        set coords [list $x $y]
@@ -1211,12 +1353,8 @@ proc drawparentlinks {id row col olds wid} {
        } 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 \
+       set t [$canv create line $coords -width [linewidth $p] \
                   -fill $colormap($p) -tags lines.$p]
        $canv lower $t
        bindline $t $p
@@ -1224,26 +1362,25 @@ 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)]} {
        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
+                   drawparentlinks $child $row $col [list $id]
                }
            }
        }
@@ -1255,7 +1392,7 @@ proc drawcmittext {id row col rmx} {
     global commitlisted commitinfo rowidlist
     global rowtextx idpos idtags idheads idotherrefs
     global linehtag linentag linedtag
-    global mainfont namefont
+    global mainfont namefont canvxmax
 
     set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
     set x [xc $row $col]
@@ -1266,7 +1403,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
     }
@@ -1287,15 +1424,20 @@ proc drawcmittext {id row col rmx} {
                            -text $name -font $namefont]
     set linedtag($row) [$canv3 create text 3 $y -anchor w \
                            -text $date -font $mainfont]
+    set xr [expr {$xt + [font measure $mainfont $headline]}]
+    if {$xr > $canvxmax} {
+       set canvxmax $xr
+       setcanvscroll
+    }
 }
 
 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) {
@@ -1304,7 +1446,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
@@ -1314,22 +1456,18 @@ 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
     }
     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
     }
     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
     }
@@ -1442,15 +1580,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 +1661,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 +1681,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,39 +1717,23 @@ 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 commitidx phase
     global canv mainfont ctext maincursor textcursor
+    global findinprogress
 
-    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
+    if {![info exists findinprogress]} {
+       . config -cursor $maincursor
+       settextcursor $textcursor
+    }
+    set phase {}
 }
 
 # Don't change the text pane cursor if it is currently the hand cursor,
@@ -1635,7 +1748,6 @@ proc settextcursor {c} {
 }
 
 proc drawrest {} {
-    global phase
     global numcommits
     global startmsecs
     global canvy0 numcommits linespc
@@ -1647,7 +1759,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"
 }
@@ -1674,9 +1785,10 @@ 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
+    global matchinglines foundstring foundstrlen matchstring
+    global commitdata
 
     stopfindproc
     unmarkmatches
@@ -1693,6 +1805,8 @@ proc dofind {} {
     }
     set foundstrlen [string length $findstring]
     if {$foundstrlen == 0} return
+    regsub -all {[*?\[\\]} $foundstring {\\&} matchstring
+    set matchstring "*$matchstring*"
     if {$findloc == "Files"} {
        findfiles
        return
@@ -1704,8 +1818,21 @@ 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 l -1
+    foreach id $displayorder {
+       set d $commitdata($id)
+       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
+       if {![info exists commitinfo($id)]} {
+           getcommit $id
+       }
        set info $commitinfo($id)
        set doesmatch 0
        foreach f $info ty $fldtypes {
@@ -1830,7 +1957,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 +1974,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 +2045,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 +2063,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 +2092,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 +2162,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 +2189,7 @@ proc findcont {id} {
            set l 0
        }
        if {$l == $findstartline} break
-       set id $lineid($l)
+       set id [lindex $displayorder $l]
     }
     stopfindproc
     if {!$finddidsel} {
@@ -2073,7 +2200,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)]
@@ -2161,15 +2288,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 +2353,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
@@ -2290,9 +2417,9 @@ proc selectline {l isnew} {
 
     $cflist delete 0 end
     $cflist insert end "Comments"
-    if {$nparents($id) == 1} {
+    if {$nparents($id) <= 1} {
        startdiff $id
-    } elseif {$nparents($id) > 1} {
+    } else {
        mergediff $id
     }
 }
@@ -2364,9 +2491,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
@@ -2383,7 +2511,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} {
@@ -2392,7 +2520,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
@@ -2502,13 +2631,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
     }
@@ -2584,7 +2711,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]} {
@@ -2659,15 +2788,14 @@ proc setcoords {} {
 }
 
 proc redisplay {} {
-    global canv canvy0 linespc numcommits
+    global canv
     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}]]
+    setcanvscroll
     allcanvs yview moveto [lindex $span 0]
     drawvisible
     if {[info exists selectedline]} {
@@ -2719,7 +2847,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
@@ -2729,9 +2857,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* $lineid($l)]} {
-                   lappend matches $lineid($l)
+           foreach i $displayorder {
+               if {[string match $id* $i]} {
+                   lappend matches $i
                }
            }
            if {$matches ne {}} {
@@ -2759,7 +2887,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
@@ -2853,13 +2981,14 @@ 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
     $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
@@ -2894,6 +3023,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]
@@ -2912,8 +3042,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
     }
 }
 
@@ -2948,15 +3079,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