Code

gitk: Fix a couple of bugs
[git.git] / gitk
diff --git a/gitk b/gitk
index 39e452aba96ec0c15fcdefcfb10bff05d6631eb9..34fe33771fc947ee096b197c77ba35037fe5429f 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -82,11 +82,13 @@ proc dorunq {} {
 proc start_rev_list {view} {
     global startmsecs
     global commfd leftover tclencoding datemode
 proc start_rev_list {view} {
     global startmsecs
     global commfd leftover tclencoding datemode
-    global viewargs viewfiles commitidx
-    global lookingforhead showlocalchanges
+    global viewargs viewfiles commitidx viewcomplete vnextroot
+    global showlocalchanges commitinterest mainheadid
 
     set startmsecs [clock clicks -milliseconds]
     set commitidx($view) 0
 
     set startmsecs [clock clicks -milliseconds]
     set commitidx($view) 0
+    set viewcomplete($view) 0
+    set vnextroot($view) 0
     set order "--topo-order"
     if {$datemode} {
        set order "--date-order"
     set order "--topo-order"
     if {$datemode} {
        set order "--date-order"
@@ -100,8 +102,10 @@ proc start_rev_list {view} {
     }
     set commfd($view) $fd
     set leftover($view) {}
     }
     set commfd($view) $fd
     set leftover($view) {}
-    set lookingforhead $showlocalchanges
-    fconfigure $fd -blocking 0 -translation lf
+    if {$showlocalchanges} {
+       lappend commitinterest($mainheadid) {dodiffindex}
+    }
+    fconfigure $fd -blocking 0 -translation lf -eofchar {}
     if {$tclencoding != {}} {
        fconfigure $fd -encoding $tclencoding
     }
     if {$tclencoding != {}} {
        fconfigure $fd -encoding $tclencoding
     }
@@ -131,18 +135,54 @@ proc getcommits {} {
     show_status "Reading commits..."
 }
 
     show_status "Reading commits..."
 }
 
+# This makes a string representation of a positive integer which
+# sorts as a string in numerical order
+proc strrep {n} {
+    if {$n < 16} {
+       return [format "%x" $n]
+    } elseif {$n < 256} {
+       return [format "x%.2x" $n]
+    } elseif {$n < 65536} {
+       return [format "y%.4x" $n]
+    }
+    return [format "z%.8x" $n]
+}
+
 proc getcommitlines {fd view}  {
 proc getcommitlines {fd view}  {
-    global commitlisted
+    global commitlisted commitinterest
     global leftover commfd
     global leftover commfd
-    global displayorder commitidx commitrow commitdata
+    global displayorder commitidx viewcomplete commitrow commitdata
     global parentlist children curview hlview
     global vparentlist vdisporder vcmitlisted
     global parentlist children curview hlview
     global vparentlist vdisporder vcmitlisted
+    global ordertok vnextroot idpending
 
     set stuff [read $fd 500000]
 
     set stuff [read $fd 500000]
+    # git log doesn't terminate the last commit with a null...
+    if {$stuff == {} && $leftover($view) ne {} && [eof $fd]} {
+       set stuff "\0"
+    }
     if {$stuff == {}} {
        if {![eof $fd]} {
            return 1
        }
     if {$stuff == {}} {
        if {![eof $fd]} {
            return 1
        }
+       # Check if we have seen any ids listed as parents that haven't
+       # appeared in the list
+       foreach vid [array names idpending "$view,*"] {
+           # should only get here if git log is buggy
+           set id [lindex [split $vid ","] 1]
+           set commitrow($vid) $commitidx($view)
+           incr commitidx($view)
+           if {$view == $curview} {
+               lappend parentlist {}
+               lappend displayorder $id
+               lappend commitlisted 0
+           } else {
+               lappend vparentlist($view) {}
+               lappend vdisporder($view) $id
+               lappend vcmitlisted($view) 0
+           }
+       }
+       set viewcomplete($view) 1
        global viewname
        unset commfd($view)
        notbusy $view
        global viewname
        unset commfd($view)
        notbusy $view
@@ -217,14 +257,35 @@ proc getcommitlines {fd view}  {
            exit 1
        }
        set id [lindex $ids 0]
            exit 1
        }
        set id [lindex $ids 0]
+       if {![info exists ordertok($view,$id)]} {
+           set otok "o[strrep $vnextroot($view)]"
+           incr vnextroot($view)
+           set ordertok($view,$id) $otok
+       } else {
+           set otok $ordertok($view,$id)
+           unset idpending($view,$id)
+       }
        if {$listed} {
            set olds [lrange $ids 1 end]
        if {$listed} {
            set olds [lrange $ids 1 end]
-           set i 0
-           foreach p $olds {
-               if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
-                   lappend children($view,$p) $id
+           if {[llength $olds] == 1} {
+               set p [lindex $olds 0]
+               lappend children($view,$p) $id
+               if {![info exists ordertok($view,$p)]} {
+                   set ordertok($view,$p) $ordertok($view,$id)
+                   set idpending($view,$p) 1
+               }
+           } else {
+               set i 0
+               foreach p $olds {
+                   if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
+                       lappend children($view,$p) $id
+                   }
+                   if {![info exists ordertok($view,$p)]} {
+                       set ordertok($view,$p) "$otok[strrep $i]]"
+                       set idpending($view,$p) 1
+                   }
+                   incr i
                }
                }
-               incr i
            }
        } else {
            set olds {}
            }
        } else {
            set olds {}
@@ -244,6 +305,12 @@ proc getcommitlines {fd view}  {
            lappend vdisporder($view) $id
            lappend vcmitlisted($view) $listed
        }
            lappend vdisporder($view) $id
            lappend vcmitlisted($view) $listed
        }
+       if {[info exists commitinterest($id)]} {
+           foreach script $commitinterest($id) {
+               eval [string map [list "%I" $id] $script]
+           }
+           unset commitinterest($id)
+       }
        set gotsome 1
     }
     if {$gotsome} {
        set gotsome 1
     }
     if {$gotsome} {
@@ -253,20 +320,17 @@ proc getcommitlines {fd view}  {
 }
 
 proc chewcommits {view} {
 }
 
 proc chewcommits {view} {
-    global curview hlview commfd
+    global curview hlview viewcomplete
     global selectedline pending_select
 
     global selectedline pending_select
 
-    set more 0
     if {$view == $curview} {
     if {$view == $curview} {
-       set allread [expr {![info exists commfd($view)]}]
-       set tlimit [expr {[clock clicks -milliseconds] + 50}]
-       set more [layoutmore $tlimit $allread]
-       if {$allread && !$more} {
-           global displayorder nullid commitidx phase
+       layoutmore
+       if {$viewcomplete($view)} {
+           global displayorder commitidx phase
            global numcommits startmsecs
 
            if {[info exists pending_select]} {
            global numcommits startmsecs
 
            if {[info exists pending_select]} {
-               set row [expr {[lindex $displayorder 0] eq $nullid}]
+               set row [first_real_row]
                selectline $row 1
            }
            if {$commitidx($curview) > 0} {
                selectline $row 1
            }
            if {$commitidx($curview) > 0} {
@@ -282,7 +346,7 @@ proc chewcommits {view} {
     if {[info exists hlview] && $view == $hlview} {
        vhighlightmore
     }
     if {[info exists hlview] && $view == $hlview} {
        vhighlightmore
     }
-    return $more
+    return 0
 }
 
 proc readcommit {id} {
 }
 
 proc readcommit {id} {
@@ -291,8 +355,8 @@ proc readcommit {id} {
 }
 
 proc updatecommits {} {
 }
 
 proc updatecommits {} {
-    global viewdata curview phase displayorder
-    global children commitrow selectedline thickerline
+    global viewdata curview phase displayorder ordertok idpending
+    global children commitrow selectedline thickerline showneartags
 
     if {$phase ne {}} {
        stop_rev_list
 
     if {$phase ne {}} {
        stop_rev_list
@@ -302,6 +366,10 @@ proc updatecommits {} {
     foreach id $displayorder {
        catch {unset children($n,$id)}
        catch {unset commitrow($n,$id)}
     foreach id $displayorder {
        catch {unset children($n,$id)}
        catch {unset commitrow($n,$id)}
+       catch {unset ordertok($n,$id)}
+    }
+    foreach vid [array names idpending "$n,*"] {
+       unset idpending($vid)
     }
     set curview -1
     catch {unset selectedline}
     }
     set curview -1
     catch {unset selectedline}
@@ -309,7 +377,9 @@ proc updatecommits {} {
     catch {unset viewdata($n)}
     readrefs
     changedrefs
     catch {unset viewdata($n)}
     readrefs
     changedrefs
-    regetallcommits
+    if {$showneartags} {
+       getallcommits
+    }
     showview $n
 }
 
     showview $n
 }
 
@@ -423,7 +493,7 @@ proc readrefs {} {
            lappend idotherrefs($id) $name
        }
     }
            lappend idotherrefs($id) $name
        }
     }
-    close $refd
+    catch {close $refd}
     set mainhead {}
     set mainheadid {}
     catch {
     set mainhead {}
     set mainheadid {}
     catch {
@@ -437,6 +507,19 @@ proc readrefs {} {
     }
 }
 
     }
 }
 
+# skip over fake commits
+proc first_real_row {} {
+    global nullid nullid2 displayorder numcommits
+
+    for {set row 0} {$row < $numcommits} {incr row} {
+       set id [lindex $displayorder $row]
+       if {$id ne $nullid && $id ne $nullid2} {
+           break
+       }
+    }
+    return $row
+}
+
 # update things for a head moved to a child of its previous location
 proc movehead {id name} {
     global headids idheads
 # update things for a head moved to a child of its previous location
 proc movehead {id name} {
     global headids idheads
@@ -500,6 +583,7 @@ proc makewindow {} {
     global textfont mainfont uifont tabstop
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global textfont mainfont uifont tabstop
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
+    global diffcontextstring diffcontext
     global maincursor textcursor curtextcursor
     global rowctxmenu fakerowmenu mergemax wrapcomment
     global highlight_files gdttype
     global maincursor textcursor curtextcursor
     global rowctxmenu fakerowmenu mergemax wrapcomment
     global highlight_files gdttype
@@ -513,6 +597,7 @@ proc makewindow {} {
     menu .bar.file
     .bar.file add command -label "Update" -command updatecommits
     .bar.file add command -label "Reread references" -command rereadrefs
     menu .bar.file
     .bar.file add command -label "Update" -command updatecommits
     .bar.file add command -label "Reread references" -command rereadrefs
+    .bar.file add command -label "List references" -command showrefs
     .bar.file add command -label "Quit" -command doquit
     .bar.file configure -font $uifont
     menu .bar.edit
     .bar.file add command -label "Quit" -command doquit
     .bar.file configure -font $uifont
     menu .bar.edit
@@ -621,62 +706,43 @@ proc makewindow {} {
        -state disabled -width 26
     pack .tf.bar.rightbut -side left -fill y
 
        -state disabled -width 26
     pack .tf.bar.rightbut -side left -fill y
 
-    button .tf.bar.findbut -text "Find" -command dofind -font $uifont
-    pack .tf.bar.findbut -side left
+    # build up the bottom bar of upper window
+    label .tf.lbar.flabel -text "Find " -font $uifont
+    button .tf.lbar.fnext -text "next" -command dofind -font $uifont
+    button .tf.lbar.fprev -text "prev" -command {dofind 1} -font $uifont
+    label .tf.lbar.flab2 -text " commit " -font $uifont
+    pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \
+       -side left -fill y
+    set gdttype "containing:"
+    set gm [tk_optionMenu .tf.lbar.gdttype gdttype \
+               "containing:" \
+               "touching paths:" \
+               "adding/removing string:"]
+    trace add variable gdttype write gdttype_change
+    $gm conf -font $uifont
+    .tf.lbar.gdttype conf -font $uifont
+    pack .tf.lbar.gdttype -side left -fill y
+
     set findstring {}
     set findstring {}
-    set fstring .tf.bar.findstring
+    set fstring .tf.lbar.findstring
     lappend entries $fstring
     entry $fstring -width 30 -font $textfont -textvariable findstring
     trace add variable findstring write find_change
     lappend entries $fstring
     entry $fstring -width 30 -font $textfont -textvariable findstring
     trace add variable findstring write find_change
-    pack $fstring -side left -expand 1 -fill x -in .tf.bar
     set findtype Exact
     set findtype Exact
-    set findtypemenu [tk_optionMenu .tf.bar.findtype \
+    set findtypemenu [tk_optionMenu .tf.lbar.findtype \
                      findtype Exact IgnCase Regexp]
                      findtype Exact IgnCase Regexp]
-    trace add variable findtype write find_change
-    .tf.bar.findtype configure -font $uifont
-    .tf.bar.findtype.menu configure -font $uifont
+    trace add variable findtype write findcom_change
+    .tf.lbar.findtype configure -font $uifont
+    .tf.lbar.findtype.menu configure -font $uifont
     set findloc "All fields"
     set findloc "All fields"
-    tk_optionMenu .tf.bar.findloc findloc "All fields" Headline \
+    tk_optionMenu .tf.lbar.findloc findloc "All fields" Headline \
        Comments Author Committer
     trace add variable findloc write find_change
        Comments Author Committer
     trace add variable findloc write find_change
-    .tf.bar.findloc configure -font $uifont
-    .tf.bar.findloc.menu configure -font $uifont
-    pack .tf.bar.findloc -side right
-    pack .tf.bar.findtype -side right
-
-    # build up the bottom bar of upper window
-    label .tf.lbar.flabel -text "Highlight:  Commits " \
-    -font $uifont
-    pack .tf.lbar.flabel -side left -fill y
-    set gdttype "touching paths:"
-    set gm [tk_optionMenu .tf.lbar.gdttype gdttype "touching paths:" \
-       "adding/removing string:"]
-    trace add variable gdttype write hfiles_change
-    $gm conf -font $uifont
-    .tf.lbar.gdttype conf -font $uifont
-    pack .tf.lbar.gdttype -side left -fill y
-    entry .tf.lbar.fent -width 25 -font $textfont \
-       -textvariable highlight_files
-    trace add variable highlight_files write hfiles_change
-    lappend entries .tf.lbar.fent
-    pack .tf.lbar.fent -side left -fill x -expand 1
-    label .tf.lbar.vlabel -text " OR in view" -font $uifont
-    pack .tf.lbar.vlabel -side left -fill y
-    global viewhlmenu selectedhlview
-    set viewhlmenu [tk_optionMenu .tf.lbar.vhl selectedhlview None]
-    $viewhlmenu entryconf None -command delvhighlight
-    $viewhlmenu conf -font $uifont
-    .tf.lbar.vhl conf -font $uifont
-    pack .tf.lbar.vhl -side left -fill y
-    label .tf.lbar.rlabel -text " OR " -font $uifont
-    pack .tf.lbar.rlabel -side left -fill y
-    global highlight_related
-    set m [tk_optionMenu .tf.lbar.relm highlight_related None \
-       "Descendent" "Not descendent" "Ancestor" "Not ancestor"]
-    $m conf -font $uifont
-    .tf.lbar.relm conf -font $uifont
-    trace add variable highlight_related write vrel_change
-    pack .tf.lbar.relm -side left -fill y
+    .tf.lbar.findloc configure -font $uifont
+    .tf.lbar.findloc.menu configure -font $uifont
+    pack .tf.lbar.findloc -side right
+    pack .tf.lbar.findtype -side right
+    pack $fstring -side left -expand 1 -fill x
 
     # Finish putting the upper half of the viewer together
     pack .tf.lbar -in .tf -side bottom -fill x
 
     # Finish putting the upper half of the viewer together
     pack .tf.lbar -in .tf -side bottom -fill x
@@ -714,7 +780,17 @@ proc makewindow {} {
        -command changediffdisp -variable diffelide -value {0 1}
     radiobutton .bleft.mid.new -text "New version" \
        -command changediffdisp -variable diffelide -value {1 0}
        -command changediffdisp -variable diffelide -value {0 1}
     radiobutton .bleft.mid.new -text "New version" \
        -command changediffdisp -variable diffelide -value {1 0}
+    label .bleft.mid.labeldiffcontext -text "      Lines of context: " \
+       -font $uifont
     pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
     pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
+    spinbox .bleft.mid.diffcontext -width 5 -font $textfont \
+       -from 1 -increment 1 -to 10000000 \
+       -validate all -validatecommand "diffcontextvalidate %P" \
+       -textvariable diffcontextstring
+    .bleft.mid.diffcontext set $diffcontext
+    trace add variable diffcontextstring write diffcontextchange
+    lappend entries .bleft.mid.diffcontext
+    pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left
     set ctext .bleft.ctext
     text $ctext -background $bgcolor -foreground $fgcolor \
        -tabs "[expr {$tabstop * $charspc}]" \
     set ctext .bleft.ctext
     text $ctext -background $bgcolor -foreground $fgcolor \
        -tabs "[expr {$tabstop * $charspc}]" \
@@ -796,30 +872,39 @@ proc makewindow {} {
         wm geometry . "$geometry(main)"
     }
 
         wm geometry . "$geometry(main)"
     }
 
+    if {[tk windowingsystem] eq {aqua}} {
+        set M1B M1
+    } else {
+        set M1B Control
+    }
+
     bind .pwbottom <Configure> {resizecdetpanes %W %w}
     pack .ctop -fill both -expand 1
     bindall <1> {selcanvline %W %x %y}
     #bindall <B1-Motion> {selcanvline %W %x %y}
     bind .pwbottom <Configure> {resizecdetpanes %W %w}
     pack .ctop -fill both -expand 1
     bindall <1> {selcanvline %W %x %y}
     #bindall <B1-Motion> {selcanvline %W %x %y}
-    bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
-    bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+    if {[tk windowingsystem] == "win32"} {
+       bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D }
+       bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break }
+    } else {
+       bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
+       bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+    }
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
     bindkey <Home> selfirstline
     bindkey <End> sellastline
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
     bindkey <Home> selfirstline
     bindkey <End> sellastline
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
-    bind . <Shift-Key-Up> "next_highlight -1"
-    bind . <Shift-Key-Down> "next_highlight 1"
     bindkey <Key-Right> "goforw"
     bindkey <Key-Left> "goback"
     bind . <Key-Prior> "selnextpage -1"
     bind . <Key-Next> "selnextpage 1"
     bindkey <Key-Right> "goforw"
     bindkey <Key-Left> "goback"
     bind . <Key-Prior> "selnextpage -1"
     bind . <Key-Next> "selnextpage 1"
-    bind . <Control-Home> "allcanvs yview moveto 0.0"
-    bind . <Control-End> "allcanvs yview moveto 1.0"
-    bind . <Control-Key-Up> "allcanvs yview scroll -1 units"
-    bind . <Control-Key-Down> "allcanvs yview scroll 1 units"
-    bind . <Control-Key-Prior> "allcanvs yview scroll -1 pages"
-    bind . <Control-Key-Next> "allcanvs yview scroll 1 pages"
+    bind . <$M1B-Home> "allcanvs yview moveto 0.0"
+    bind . <$M1B-End> "allcanvs yview moveto 1.0"
+    bind . <$M1B-Key-Up> "allcanvs yview scroll -1 units"
+    bind . <$M1B-Key-Down> "allcanvs yview scroll 1 units"
+    bind . <$M1B-Key-Prior> "allcanvs yview scroll -1 pages"
+    bind . <$M1B-Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
@@ -839,15 +924,15 @@ proc makewindow {} {
     bindkey ? findprev
     bindkey f nextfile
     bindkey <F5> updatecommits
     bindkey ? findprev
     bindkey f nextfile
     bindkey <F5> updatecommits
-    bind . <Control-q> doquit
-    bind . <Control-f> dofind
-    bind . <Control-g> {findnext 0}
-    bind . <Control-r> dosearchback
-    bind . <Control-s> dosearch
-    bind . <Control-equal> {incrfont 1}
-    bind . <Control-KP_Add> {incrfont 1}
-    bind . <Control-minus> {incrfont -1}
-    bind . <Control-KP_Subtract> {incrfont -1}
+    bind . <$M1B-q> doquit
+    bind . <$M1B-f> dofind
+    bind . <$M1B-g> {findnext 0}
+    bind . <$M1B-r> dosearchback
+    bind . <$M1B-s> dosearch
+    bind . <$M1B-equal> {incrfont 1}
+    bind . <$M1B-KP_Add> {incrfont 1}
+    bind . <$M1B-minus> {incrfont -1}
+    bind . <$M1B-KP_Subtract> {incrfont -1}
     wm protocol . WM_DELETE_WINDOW doquit
     bind . <Button-1> "click %W"
     bind $fstring <Key-Return> dofind
     wm protocol . WM_DELETE_WINDOW doquit
     bind . <Button-1> "click %W"
     bind $fstring <Key-Return> dofind
@@ -856,6 +941,7 @@ proc makewindow {} {
     bind $cflist <1> {sel_flist %W %x %y; break}
     bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
     bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
     bind $cflist <1> {sel_flist %W %x %y; break}
     bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
     bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
+    bind $cflist <Button-3> {pop_flist_menu %W %X %Y %x %y}
 
     set maincursor [. cget -cursor]
     set textcursor [$ctext cget -cursor]
 
     set maincursor [. cget -cursor]
     set textcursor [$ctext cget -cursor]
@@ -893,6 +979,32 @@ proc makewindow {} {
        -command cobranch
     $headctxmenu add command -label "Remove this branch" \
        -command rmbranch
        -command cobranch
     $headctxmenu add command -label "Remove this branch" \
        -command rmbranch
+
+    global flist_menu
+    set flist_menu .flistctxmenu
+    menu $flist_menu -tearoff 0
+    $flist_menu add command -label "Highlight this too" \
+       -command {flist_hl 0}
+    $flist_menu add command -label "Highlight this only" \
+       -command {flist_hl 1}
+}
+
+# Windows sends all mouse wheel events to the current focused window, not
+# the one where the mouse hovers, so bind those events here and redirect
+# to the correct window
+proc windows_mousewheel_redirector {W X Y D} {
+    global canv canv2 canv3
+    set w [winfo containing -displayof $W $X $Y]
+    if {$w ne ""} {
+       set u [expr {$D < 0 ? 5 : -5}]
+       if {$w == $canv || $w == $canv2 || $w == $canv3} {
+           allcanvs yview scroll $u units
+       } else {
+           catch {
+               $w yview scroll $u units
+           }
+       }
+    }
 }
 
 # mouse-2 makes all windows scan vertically, but only the one
 }
 
 # mouse-2 makes all windows scan vertically, but only the one
@@ -932,8 +1044,8 @@ proc bindkey {ev script} {
 # set the focus back to the toplevel for any click outside
 # the entry widgets
 proc click {w} {
 # set the focus back to the toplevel for any click outside
 # the entry widgets
 proc click {w} {
-    global entries
-    foreach e $entries {
+    global ctext entries
+    foreach e [concat $entries $ctext] {
        if {$w == $e} return
     }
     focus .
        if {$w == $e} return
     }
     focus .
@@ -944,8 +1056,8 @@ proc savestuff {w} {
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth showneartags showlocalchanges
     global viewname viewfiles viewargs viewperm nextviewnum
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth showneartags showlocalchanges
     global viewname viewfiles viewargs viewperm nextviewnum
-    global cmitmode wrapcomment
-    global colors bgcolor fgcolor diffcolors selectbgcolor
+    global cmitmode wrapcomment datetimeformat
+    global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -962,10 +1074,12 @@ proc savestuff {w} {
        puts $f [list set wrapcomment $wrapcomment]
        puts $f [list set showneartags $showneartags]
        puts $f [list set showlocalchanges $showlocalchanges]
        puts $f [list set wrapcomment $wrapcomment]
        puts $f [list set showneartags $showneartags]
        puts $f [list set showlocalchanges $showlocalchanges]
+       puts $f [list set datetimeformat $datetimeformat]
        puts $f [list set bgcolor $bgcolor]
        puts $f [list set fgcolor $fgcolor]
        puts $f [list set colors $colors]
        puts $f [list set diffcolors $diffcolors]
        puts $f [list set bgcolor $bgcolor]
        puts $f [list set fgcolor $fgcolor]
        puts $f [list set colors $colors]
        puts $f [list set diffcolors $diffcolors]
+       puts $f [list set diffcontext $diffcontext]
        puts $f [list set selectbgcolor $selectbgcolor]
 
        puts $f "set geometry(main) [wm geometry .]"
        puts $f [list set selectbgcolor $selectbgcolor]
 
        puts $f "set geometry(main) [wm geometry .]"
@@ -1088,12 +1202,17 @@ proc keys {} {
        raise $w
        return
     }
        raise $w
        return
     }
+    if {[tk windowingsystem] eq {aqua}} {
+       set M1T Cmd
+    } else {
+       set M1T Ctrl
+    }
     toplevel $w
     wm title $w "Gitk key bindings"
     toplevel $w
     wm title $w "Gitk key bindings"
-    message $w.m -text {
+    message $w.m -text "
 Gitk key bindings:
 
 Gitk key bindings:
 
-<Ctrl-Q>               Quit
+<$M1T-Q>               Quit
 <Home>         Move to first commit
 <End>          Move to last commit
 <Up>, p, i     Move up one commit
 <Home>         Move to first commit
 <End>          Move to last commit
 <Up>, p, i     Move up one commit
@@ -1102,12 +1221,12 @@ Gitk key bindings:
 <Right>, x, l  Go forward in history list
 <PageUp>       Move up one page in commit list
 <PageDown>     Move down one page in commit list
 <Right>, x, l  Go forward in history list
 <PageUp>       Move up one page in commit list
 <PageDown>     Move down one page in commit list
-<Ctrl-Home>    Scroll to top of commit list
-<Ctrl-End>     Scroll to bottom of commit list
-<Ctrl-Up>      Scroll commit list up one line
-<Ctrl-Down>    Scroll commit list down one line
-<Ctrl-PageUp>  Scroll commit list up one page
-<Ctrl-PageDown>        Scroll commit list down one page
+<$M1T-Home>    Scroll to top of commit list
+<$M1T-End>     Scroll to bottom of commit list
+<$M1T-Up>      Scroll commit list up one line
+<$M1T-Down>    Scroll commit list down one line
+<$M1T-PageUp>  Scroll commit list up one page
+<$M1T-PageDown>        Scroll commit list down one page
 <Shift-Up>     Move to previous highlighted line
 <Shift-Down>   Move to next highlighted line
 <Delete>, b    Scroll diff view up one page
 <Shift-Up>     Move to previous highlighted line
 <Shift-Down>   Move to next highlighted line
 <Delete>, b    Scroll diff view up one page
@@ -1115,20 +1234,20 @@ Gitk key bindings:
 <Space>                Scroll diff view down one page
 u              Scroll diff view up 18 lines
 d              Scroll diff view down 18 lines
 <Space>                Scroll diff view down one page
 u              Scroll diff view up 18 lines
 d              Scroll diff view down 18 lines
-<Ctrl-F>               Find
-<Ctrl-G>               Move to next find hit
+<$M1T-F>               Find
+<$M1T-G>               Move to next find hit
 <Return>       Move to next find hit
 /              Move to next find hit, or redo find
 ?              Move to previous find hit
 f              Scroll diff view to next file
 <Return>       Move to next find hit
 /              Move to next find hit, or redo find
 ?              Move to previous find hit
 f              Scroll diff view to next file
-<Ctrl-S>               Search for next hit in diff view
-<Ctrl-R>               Search for previous hit in diff view
-<Ctrl-KP+>     Increase font size
-<Ctrl-plus>    Increase font size
-<Ctrl-KP->     Decrease font size
-<Ctrl-minus>   Decrease font size
+<$M1T-S>               Search for next hit in diff view
+<$M1T-R>               Search for previous hit in diff view
+<$M1T-KP+>     Increase font size
+<$M1T-plus>    Increase font size
+<$M1T-KP->     Decrease font size
+<$M1T-minus>   Decrease font size
 <F5>           Update
 <F5>           Update
-} \
+" \
            -justify left -bg white -border 2 -relief groove
     pack $w.m -side top -fill both -padx 2 -pady 2
     $w.m configure -font $uifont
            -justify left -bg white -border 2 -relief groove
     pack $w.m -side top -fill both -padx 2 -pady 2
     $w.m configure -font $uifont
@@ -1391,6 +1510,38 @@ image create bitmap tri-dn -background black -foreground blue -data {
        0x00, 0x00};
 }
 
        0x00, 0x00};
 }
 
+image create bitmap reficon-T -background black -foreground yellow -data {
+    #define tagicon_width 13
+    #define tagicon_height 9
+    static unsigned char tagicon_bits[] = {
+       0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf8, 0x07,
+       0xfc, 0x07, 0xf8, 0x07, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00};
+} -maskdata {
+    #define tagicon-mask_width 13
+    #define tagicon-mask_height 9
+    static unsigned char tagicon-mask_bits[] = {
+       0x00, 0x00, 0xf0, 0x0f, 0xf8, 0x0f, 0xfc, 0x0f,
+       0xfe, 0x0f, 0xfc, 0x0f, 0xf8, 0x0f, 0xf0, 0x0f, 0x00, 0x00};
+}
+set rectdata {
+    #define headicon_width 13
+    #define headicon_height 9
+    static unsigned char headicon_bits[] = {
+       0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0xf8, 0x07,
+       0xf8, 0x07, 0xf8, 0x07, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00};
+}
+set rectmask {
+    #define headicon-mask_width 13
+    #define headicon-mask_height 9
+    static unsigned char headicon-mask_bits[] = {
+       0x00, 0x00, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f,
+       0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0x00, 0x00};
+}
+image create bitmap reficon-H -background black -foreground green \
+    -data $rectdata -maskdata $rectmask
+image create bitmap reficon-o -background black -foreground "#ddddff" \
+    -data $rectdata -maskdata $rectmask
+
 proc init_flist {first} {
     global cflist cflist_top selectedline difffilestart
 
 proc init_flist {first} {
     global cflist cflist_top selectedline difffilestart
 
@@ -1471,6 +1622,33 @@ proc sel_flist {w x y} {
     }
 }
 
     }
 }
 
+proc pop_flist_menu {w X Y x y} {
+    global ctext cflist cmitmode flist_menu flist_menu_file
+    global treediffs diffids
+
+    set l [lindex [split [$w index "@$x,$y"] "."] 0]
+    if {$l <= 1} return
+    if {$cmitmode eq "tree"} {
+       set e [linetoelt $l]
+       if {[string index $e end] eq "/"} return
+    } else {
+       set e [lindex $treediffs($diffids) [expr {$l-2}]]
+    }
+    set flist_menu_file $e
+    tk_popup $flist_menu $X $Y
+}
+
+proc flist_hl {only} {
+    global flist_menu_file highlight_files
+
+    set x [shellquote $flist_menu_file]
+    if {$only || $highlight_files eq {}} {
+       set highlight_files $x
+    } else {
+       append highlight_files " " $x
+    }
+}
+
 # Functions for adding and removing shell-type quoting
 
 proc shellquote {str} {
 # Functions for adding and removing shell-type quoting
 
 proc shellquote {str} {
@@ -1653,10 +1831,10 @@ proc doviewmenu {m first cmd op argv} {
 }
 
 proc allviewmenus {n op args} {
 }
 
 proc allviewmenus {n op args} {
-    global viewhlmenu
+    global viewhlmenu
 
     doviewmenu .bar.view 5 [list showview $n] $op $args
 
     doviewmenu .bar.view 5 [list showview $n] $op $args
-    doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args
+    doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args
 }
 
 proc newviewok {top n} {
 }
 
 proc newviewok {top n} {
@@ -1699,8 +1877,8 @@ proc newviewok {top n} {
            set viewname($n) $newviewname($n)
            doviewmenu .bar.view 5 [list showview $n] \
                entryconf [list -label $viewname($n)]
            set viewname($n) $newviewname($n)
            doviewmenu .bar.view 5 [list showview $n] \
                entryconf [list -label $viewname($n)]
-           doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
-               entryconf [list -label $viewname($n) -value $viewname($n)]
+           doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
+               entryconf [list -label $viewname($n) -value $viewname($n)]
        }
        if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} {
            set viewfiles($n) $files
        }
        if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} {
            set viewfiles($n) $files
@@ -1732,8 +1910,8 @@ proc addviewmenu {n} {
 
     .bar.view add radiobutton -label $viewname($n) \
        -command [list showview $n] -variable selectedview -value $n
 
     .bar.view add radiobutton -label $viewname($n) \
        -command [list showview $n] -variable selectedview -value $n
-    $viewhlmenu add radiobutton -label $viewname($n) \
-       -command [list addvhighlight $n] -variable selectedhlview
+    #$viewhlmenu add radiobutton -label $viewname($n) \
+    #  -command [list addvhighlight $n] -variable selectedhlview
 }
 
 proc flatten {var} {
 }
 
 proc flatten {var} {
@@ -1757,17 +1935,17 @@ proc unflatten {var l} {
 
 proc showview {n} {
     global curview viewdata viewfiles
 
 proc showview {n} {
     global curview viewdata viewfiles
-    global displayorder parentlist rowidlist rowoffsets
+    global displayorder parentlist rowidlist rowisopt rowfinal
     global colormap rowtextx commitrow nextcolor canvxmax
     global colormap rowtextx commitrow nextcolor canvxmax
-    global numcommits rowrangelist commitlisted idrowranges rowchk
+    global numcommits commitlisted
     global selectedline currentid canv canvy0
     global treediffs
     global pending_select phase
     global selectedline currentid canv canvy0
     global treediffs
     global pending_select phase
-    global commitidx rowlaidout rowoptim
+    global commitidx
     global commfd
     global selectedview selectfirst
     global vparentlist vdisporder vcmitlisted
     global commfd
     global selectedview selectfirst
     global vparentlist vdisporder vcmitlisted
-    global hlview selectedhlview
+    global hlview selectedhlview commitinterest
 
     if {$n == $curview} return
     set selid {}
 
     if {$n == $curview} return
     set selid {}
@@ -1793,15 +1971,11 @@ proc showview {n} {
        set vparentlist($curview) $parentlist
        set vdisporder($curview) $displayorder
        set vcmitlisted($curview) $commitlisted
        set vparentlist($curview) $parentlist
        set vdisporder($curview) $displayorder
        set vcmitlisted($curview) $commitlisted
-       if {$phase ne {}} {
+       if {$phase ne {} ||
+           ![info exists viewdata($curview)] ||
+           [lindex $viewdata($curview) 0] ne {}} {
            set viewdata($curview) \
            set viewdata($curview) \
-               [list $phase $rowidlist $rowoffsets $rowrangelist \
-                    [flatten idrowranges] [flatten idinlist] \
-                    $rowlaidout $rowoptim $numcommits]
-       } elseif {![info exists viewdata($curview)]
-                 || [lindex $viewdata($curview) 0] ne {}} {
-           set viewdata($curview) \
-               [list {} $rowidlist $rowoffsets $rowrangelist]
+               [list $phase $rowidlist $rowisopt $rowfinal]
        }
     }
     catch {unset treediffs}
        }
     }
     catch {unset treediffs}
@@ -1810,12 +1984,14 @@ proc showview {n} {
        unset hlview
        set selectedhlview None
     }
        unset hlview
        set selectedhlview None
     }
+    catch {unset commitinterest}
 
     set curview $n
     set selectedview $n
     .bar.view entryconf Edit* -state [expr {$n == 0? "disabled": "normal"}]
     .bar.view entryconf Delete* -state [expr {$n == 0? "disabled": "normal"}]
 
 
     set curview $n
     set selectedview $n
     .bar.view entryconf Edit* -state [expr {$n == 0? "disabled": "normal"}]
     .bar.view entryconf Delete* -state [expr {$n == 0? "disabled": "normal"}]
 
+    run refill_reflist
     if {![info exists viewdata($n)]} {
        if {$selid ne {}} {
            set pending_select $selid
     if {![info exists viewdata($n)]} {
        if {$selid ne {}} {
            set pending_select $selid
@@ -1830,19 +2006,9 @@ proc showview {n} {
     set parentlist $vparentlist($n)
     set commitlisted $vcmitlisted($n)
     set rowidlist [lindex $v 1]
     set parentlist $vparentlist($n)
     set commitlisted $vcmitlisted($n)
     set rowidlist [lindex $v 1]
-    set rowoffsets [lindex $v 2]
-    set rowrangelist [lindex $v 3]
-    if {$phase eq {}} {
-       set numcommits [llength $displayorder]
-       catch {unset idrowranges}
-    } else {
-       unflatten idrowranges [lindex $v 4]
-       unflatten idinlist [lindex $v 5]
-       set rowlaidout [lindex $v 6]
-       set rowoptim [lindex $v 7]
-       set numcommits [lindex $v 8]
-       catch {unset rowchk}
-    }
+    set rowisopt [lindex $v 2]
+    set rowfinal [lindex $v 3]
+    set numcommits $commitidx($n)
 
     catch {unset colormap}
     catch {unset rowtextx}
 
     catch {unset colormap}
     catch {unset rowtextx}
@@ -1871,7 +2037,7 @@ proc showview {n} {
     } elseif {$selid ne {}} {
        set pending_select $selid
     } else {
     } elseif {$selid ne {}} {
        set pending_select $selid
     } else {
-       set row [expr {[lindex $displayorder 0] eq $nullid}]
+       set row [first_real_row]
        if {$row < $numcommits} {
            selectline $row 0
        } else {
        if {$row < $numcommits} {
            selectline $row 0
        } else {
@@ -1958,7 +2124,7 @@ proc addvhighlight {n} {
     }
     set hlview $n
     if {$n != $curview && ![info exists viewdata($n)]} {
     }
     set hlview $n
     if {$n != $curview && ![info exists viewdata($n)]} {
-       set viewdata($n) [list getcommits {{}} {{}} {} {} {} 0 0 0 {}]
+       set viewdata($n) [list getcommits {{}} 0 0 0]
        set vparentlist($n) {}
        set vdisporder($n) {}
        set vcmitlisted($n) {}
        set vparentlist($n) {}
        set vdisporder($n) {}
        set vcmitlisted($n) {}
@@ -2021,9 +2187,9 @@ proc askvhighlight {row id} {
     }
 }
 
     }
 }
 
-proc hfiles_change {name ix op} {
+proc hfiles_change {} {
     global highlight_files filehighlight fhighlights fh_serial
     global highlight_files filehighlight fhighlights fh_serial
-    global mainfont highlight_paths
+    global mainfont highlight_paths gdttype
 
     if {[info exists filehighlight]} {
        # delete previous highlights
 
     if {[info exists filehighlight]} {
        # delete previous highlights
@@ -2041,6 +2207,66 @@ proc hfiles_change {name ix op} {
     }
 }
 
     }
 }
 
+proc gdttype_change {name ix op} {
+    global gdttype highlight_files findstring findpattern
+
+    if {$findstring ne {}} {
+       if {$gdttype eq "containing:"} {
+           if {$highlight_files ne {}} {
+               set highlight_files {}
+               hfiles_change
+           }
+           findcom_change
+       } else {
+           if {$findpattern ne {}} {
+               set findpattern {}
+               findcom_change
+           }
+           set highlight_files $findstring
+           hfiles_change
+       }
+       drawvisible
+    }
+    # enable/disable findtype/findloc menus too
+}
+
+proc find_change {name ix op} {
+    global gdttype findstring highlight_files
+
+    if {$gdttype eq "containing:"} {
+       findcom_change
+    } else {
+       if {$highlight_files ne $findstring} {
+           set highlight_files $findstring
+           hfiles_change
+       }
+    }
+    drawvisible
+}
+
+proc findcom_change {} {
+    global nhighlights mainfont boldnamerows
+    global findpattern findtype findstring gdttype
+
+    # delete previous highlights, if any
+    foreach row $boldnamerows {
+       bolden_name $row $mainfont
+    }
+    set boldnamerows {}
+    catch {unset nhighlights}
+    unbolden
+    unmarkmatches
+    if {$gdttype ne "containing:" || $findstring eq {}} {
+       set findpattern {}
+    } elseif {$findtype eq "Regexp"} {
+       set findpattern $findstring
+    } else {
+       set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
+                  $findstring]
+       set findpattern "*$e*"
+    }
+}
+
 proc makepatterns {l} {
     set ret {}
     foreach e $l {
 proc makepatterns {l} {
     set ret {}
     foreach e $l {
@@ -2063,8 +2289,11 @@ proc do_file_hl {serial} {
        set highlight_paths [makepatterns $paths]
        highlight_filelist
        set gdtargs [concat -- $paths]
        set highlight_paths [makepatterns $paths]
        highlight_filelist
        set gdtargs [concat -- $paths]
-    } else {
+    } elseif {$gdttype eq "adding/removing string:"} {
        set gdtargs [list "-S$highlight_files"]
        set gdtargs [list "-S$highlight_files"]
+    } else {
+       # must be "containing:", i.e. we're searching commit info
+       return
     }
     set cmd [concat | git diff-tree -r -s --stdin $gdtargs]
     set filehighlight [open $cmd r+]
     }
     set cmd [concat | git diff-tree -r -s --stdin $gdtargs]
     set filehighlight [open $cmd r+]
@@ -2095,7 +2324,7 @@ proc askfilehighlight {row id} {
 
 proc readfhighlight {} {
     global filehighlight fhighlights commitrow curview mainfont iddrawn
 
 proc readfhighlight {} {
     global filehighlight fhighlights commitrow curview mainfont iddrawn
-    global fhl_list
+    global fhl_list find_dirn
 
     if {![info exists filehighlight]} {
        return 0
 
     if {![info exists filehighlight]} {
        return 0
@@ -2127,36 +2356,21 @@ proc readfhighlight {} {
        unset filehighlight
        return 0
     }
        unset filehighlight
        return 0
     }
-    next_hlcont
-    return 1
-}
-
-proc find_change {name ix op} {
-    global nhighlights mainfont boldnamerows
-    global findstring findpattern findtype markingmatches
-
-    # delete previous highlights, if any
-    foreach row $boldnamerows {
-       bolden_name $row $mainfont
-    }
-    set boldnamerows {}
-    catch {unset nhighlights}
-    unbolden
-    unmarkmatches
-    if {$findtype ne "Regexp"} {
-       set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
-                  $findstring]
-       set findpattern "*$e*"
+    if {[info exists find_dirn]} {
+       if {$find_dirn > 0} {
+           run findmore
+       } else {
+           run findmorerev
+       }
     }
     }
-    set markingmatches [expr {$findstring ne {}}]
-    drawvisible
+    return 1
 }
 
 proc doesmatch {f} {
 }
 
 proc doesmatch {f} {
-    global findtype findstring findpattern
+    global findtype findpattern
 
     if {$findtype eq "Regexp"} {
 
     if {$findtype eq "Regexp"} {
-       return [regexp $findstring $f]
+       return [regexp $findpattern $f]
     } elseif {$findtype eq "IgnCase"} {
        return [string match -nocase $findpattern $f]
     } else {
     } elseif {$findtype eq "IgnCase"} {
        return [string match -nocase $findpattern $f]
     } else {
@@ -2194,26 +2408,32 @@ proc askfindhighlight {row id} {
            }
        }
        if {$markingmatches} {
            }
        }
        if {$markingmatches} {
-           markrowmatches $row [lindex $info 0] [lindex $info 1]
+           markrowmatches $row $id
        }
     }
     set nhighlights($row) $isbold
 }
 
        }
     }
     set nhighlights($row) $isbold
 }
 
-proc markrowmatches {row headline author} {
-    global canv canv2 linehtag linentag
+proc markrowmatches {row id} {
+    global canv canv2 linehtag linentag commitinfo findloc
 
 
+    set headline [lindex $commitinfo($id) 0]
+    set author [lindex $commitinfo($id) 1]
     $canv delete match$row
     $canv2 delete match$row
     $canv delete match$row
     $canv2 delete match$row
-    set m [findmatches $headline]
-    if {$m ne {}} {
-       markmatches $canv $row $headline $linehtag($row) $m \
-           [$canv itemcget $linehtag($row) -font]
+    if {$findloc eq "All fields" || $findloc eq "Headline"} {
+       set m [findmatches $headline]
+       if {$m ne {}} {
+           markmatches $canv $row $headline $linehtag($row) $m \
+               [$canv itemcget $linehtag($row) -font] $row
+       }
     }
     }
-    set m [findmatches $author]
-    if {$m ne {}} {
-       markmatches $canv2 $row $author $linentag($row) $m \
-           [$canv2 itemcget $linentag($row) -font]
+    if {$findloc eq "All fields" || $findloc eq "Author"} {
+       set m [findmatches $author]
+       if {$m ne {}} {
+           markmatches $canv2 $row $author $linentag($row) $m \
+               [$canv2 itemcget $linentag($row) -font] $row
+       }
     }
 }
 
     }
 }
 
@@ -2343,81 +2563,6 @@ proc askrelhighlight {row id} {
     set rhighlights($row) $isbold
 }
 
     set rhighlights($row) $isbold
 }
 
-proc next_hlcont {} {
-    global fhl_row fhl_dirn displayorder numcommits
-    global vhighlights fhighlights nhighlights rhighlights
-    global hlview filehighlight findstring highlight_related
-
-    if {![info exists fhl_dirn] || $fhl_dirn == 0} return
-    set row $fhl_row
-    while {1} {
-       if {$row < 0 || $row >= $numcommits} {
-           bell
-           set fhl_dirn 0
-           return
-       }
-       set id [lindex $displayorder $row]
-       if {[info exists hlview]} {
-           if {![info exists vhighlights($row)]} {
-               askvhighlight $row $id
-           }
-           if {$vhighlights($row) > 0} break
-       }
-       if {$findstring ne {}} {
-           if {![info exists nhighlights($row)]} {
-               askfindhighlight $row $id
-           }
-           if {$nhighlights($row) > 0} break
-       }
-       if {$highlight_related ne "None"} {
-           if {![info exists rhighlights($row)]} {
-               askrelhighlight $row $id
-           }
-           if {$rhighlights($row) > 0} break
-       }
-       if {[info exists filehighlight]} {
-           if {![info exists fhighlights($row)]} {
-               # ask for a few more while we're at it...
-               set r $row
-               for {set n 0} {$n < 100} {incr n} {
-                   if {![info exists fhighlights($r)]} {
-                       askfilehighlight $r [lindex $displayorder $r]
-                   }
-                   incr r $fhl_dirn
-                   if {$r < 0 || $r >= $numcommits} break
-               }
-               flushhighlights
-           }
-           if {$fhighlights($row) < 0} {
-               set fhl_row $row
-               return
-           }
-           if {$fhighlights($row) > 0} break
-       }
-       incr row $fhl_dirn
-    }
-    set fhl_dirn 0
-    selectline $row 1
-}
-
-proc next_highlight {dirn} {
-    global selectedline fhl_row fhl_dirn
-    global hlview filehighlight findstring highlight_related
-
-    if {![info exists selectedline]} return
-    if {!([info exists hlview] || $findstring ne {} ||
-         $highlight_related ne "None" || [info exists filehighlight])} return
-    set fhl_row [expr {$selectedline + $dirn}]
-    set fhl_dirn $dirn
-    next_hlcont
-}
-
-proc cancel_next_highlight {} {
-    global fhl_dirn
-
-    set fhl_dirn 0
-}
-
 # Graph layout functions
 
 proc shortids {ids} {
 # Graph layout functions
 
 proc shortids {ids} {
@@ -2434,108 +2579,43 @@ proc shortids {ids} {
     return $res
 }
 
     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 {}
 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 curview
-
-    if {[info exists commitrow($curview,$id)]} {
-       set r $commitrow($curview,$id)
-       if {$l1 <= $r && $r <= $l2} {
-           return [expr {$r - $l1 + 1}]
+    set o [list $o]
+    for {set mask 1} {$mask <= $n} {incr mask $mask} {
+       if {($n & $mask) != 0} {
+           set ret [concat $ret $o]
        }
        }
+       set o [concat $o $o]
     }
     }
-    set kids $children($curview,$id)
-    foreach c $kids {
-       set r $commitrow($curview,$c)
-       if {$l1 <= $r && $r <= $l2} {
-           return [expr {$r - $l1 + 1}]
-       }
-    }
-    return 0
+    return $ret
 }
 
 }
 
-proc sanity {row {full 0}} {
-    global rowidlist rowoffsets
+# Work out where id should go in idlist so that order-token
+# values increase from left to right
+proc idcol {idlist id {i 0}} {
+    global ordertok curview
 
 
-    set col -1
-    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 [lindex $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 [lindex $rowidlist $i]]} offs={[lindex $rowoffsets $i]}"
-               }
-               break
-           }
-           if {!$full} break
-           set o [lindex $rowoffsets $y $x]
+    set t $ordertok($curview,$id)
+    if {$i >= [llength $idlist] ||
+       $t < $ordertok($curview,[lindex $idlist $i])} {
+       if {$i > [llength $idlist]} {
+           set i [llength $idlist]
        }
        }
-    }
-}
-
-proc makeuparrow {oid x y z} {
-    global rowidlist rowoffsets uparrowlen idrowranges displayorder
-
-    for {set i 1} {$i < $uparrowlen && $y > 1} {incr i} {
-       incr y -1
-       incr x $z
-       set off0 [lindex $rowoffsets $y]
-       for {set x0 $x} {1} {incr x0} {
-           if {$x0 >= [llength $off0]} {
-               set x0 [llength [lindex $rowoffsets [expr {$y-1}]]]
-               break
-           }
-           set z [lindex $off0 $x0]
-           if {$z ne {}} {
-               incr x0 $z
-               break
-           }
+       while {[incr i -1] >= 0 &&
+              $t < $ordertok($curview,[lindex $idlist $i])} {}
+       incr i
+    } else {
+       if {$t > $ordertok($curview,[lindex $idlist $i])} {
+           while {[incr i] < [llength $idlist] &&
+                  $t >= $ordertok($curview,[lindex $idlist $i])} {}
        }
        }
-       set z [expr {$x0 - $x}]
-       lset rowidlist $y [linsert [lindex $rowidlist $y] $x $oid]
-       lset rowoffsets $y [linsert [lindex $rowoffsets $y] $x $z]
     }
     }
-    set tmp [lreplace [lindex $rowoffsets $y] $x $x {}]
-    lset rowoffsets $y [incrange $tmp [expr {$x+1}] -1]
-    lappend idrowranges($oid) [lindex $displayorder $y]
+    return $i
 }
 
 proc initlayout {} {
 }
 
 proc initlayout {} {
-    global rowidlist rowoffsets displayorder commitlisted
-    global rowlaidout rowoptim
-    global idinlist rowchk rowrangelist idrowranges
+    global rowidlist rowisopt rowfinal displayorder commitlisted
     global numcommits canvxmax canv
     global nextcolor
     global parentlist
     global numcommits canvxmax canv
     global nextcolor
     global parentlist
@@ -2546,18 +2626,13 @@ proc initlayout {} {
     set displayorder {}
     set commitlisted {}
     set parentlist {}
     set displayorder {}
     set commitlisted {}
     set parentlist {}
-    set rowrangelist {}
     set nextcolor 0
     set nextcolor 0
-    set rowidlist {{}}
-    set rowoffsets {{}}
-    catch {unset idinlist}
-    catch {unset rowchk}
-    set rowlaidout 0
-    set rowoptim 0
+    set rowidlist {}
+    set rowisopt {}
+    set rowfinal {}
     set canvxmax [$canv cget -width]
     catch {unset colormap}
     catch {unset rowtextx}
     set canvxmax [$canv cget -width]
     catch {unset colormap}
     catch {unset rowtextx}
-    catch {unset idrowranges}
     set selectfirst 1
 }
 
     set selectfirst 1
 }
 
@@ -2589,62 +2664,20 @@ proc visiblerows {} {
     return [list $r0 $r1]
 }
 
     return [list $r0 $r1]
 }
 
-proc layoutmore {tmax allread} {
-    global rowlaidout rowoptim commitidx numcommits optim_delay
-    global uparrowlen curview rowidlist idinlist
+proc layoutmore {} {
+    global commitidx viewcomplete numcommits
+    global uparrowlen downarrowlen mingaplen curview
 
 
-    set showlast 0
-    set showdelay $optim_delay
-    set optdelay [expr {$uparrowlen + 1}]
-    while {1} {
-       if {$rowoptim - $showdelay > $numcommits} {
-           showstuff [expr {$rowoptim - $showdelay}] $showlast
-       } elseif {$rowlaidout - $optdelay > $rowoptim} {
-           set nr [expr {$rowlaidout - $optdelay - $rowoptim}]
-           if {$nr > 100} {
-               set nr 100
-           }
-           optimize_rows $rowoptim 0 [expr {$rowoptim + $nr}]
-           incr rowoptim $nr
-       } elseif {$commitidx($curview) > $rowlaidout} {
-           set nr [expr {$commitidx($curview) - $rowlaidout}]
-           # may need to increase this threshold if uparrowlen or
-           # mingaplen are increased...
-           if {$nr > 150} {
-               set nr 150
-           }
-           set row $rowlaidout
-           set rowlaidout [layoutrows $row [expr {$row + $nr}] $allread]
-           if {$rowlaidout == $row} {
-               return 0
-           }
-       } elseif {$allread} {
-           set optdelay 0
-           set nrows $commitidx($curview)
-           if {[lindex $rowidlist $nrows] ne {} ||
-               [array names idinlist] ne {}} {
-               layouttail
-               set rowlaidout $commitidx($curview)
-           } elseif {$rowoptim == $nrows} {
-               set showdelay 0
-               set showlast 1
-               if {$numcommits == $nrows} {
-                   return 0
-               }
-           }
-       } else {
-           return 0
-       }
-       if {$tmax ne {} && [clock clicks -milliseconds] >= $tmax} {
-           return 1
-       }
+    set show $commitidx($curview)
+    if {$show > $numcommits} {
+       showstuff $show $viewcomplete($curview)
     }
 }
 
 proc showstuff {canshow last} {
     global numcommits commitrow pending_select selectedline curview
     }
 }
 
 proc showstuff {canshow last} {
     global numcommits commitrow pending_select selectedline curview
-    global lookingforhead mainheadid displayorder nullid selectfirst
-    global lastscrollset
+    global mainheadid displayorder selectfirst
+    global lastscrollset commitinterest
 
     if {$numcommits == 0} {
        global phase
 
     if {$numcommits == 0} {
        global phase
@@ -2676,274 +2709,435 @@ proc showstuff {canshow last} {
        if {[info exists selectedline] || [info exists pending_select]} {
            set selectfirst 0
        } else {
        if {[info exists selectedline] || [info exists pending_select]} {
            set selectfirst 0
        } else {
-           set l [expr {[lindex $displayorder 0] eq $nullid}]
+           set l [first_real_row]
            selectline $l 1
            set selectfirst 0
        }
     }
            selectline $l 1
            set selectfirst 0
        }
     }
-    if {$lookingforhead && [info exists commitrow($curview,$mainheadid)]
-       && ($last || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
-       set lookingforhead 0
-       dodiffindex
-    }
 }
 
 proc doshowlocalchanges {} {
 }
 
 proc doshowlocalchanges {} {
-    global lookingforhead curview mainheadid phase commitrow
+    global curview mainheadid phase commitrow
 
     if {[info exists commitrow($curview,$mainheadid)] &&
        ($phase eq {} || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
        dodiffindex
     } elseif {$phase ne {}} {
 
     if {[info exists commitrow($curview,$mainheadid)] &&
        ($phase eq {} || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
        dodiffindex
     } elseif {$phase ne {}} {
-       set lookingforhead 1
+       lappend commitinterest($mainheadid) {}
     }
 }
 
 proc dohidelocalchanges {} {
     }
 }
 
 proc dohidelocalchanges {} {
-    global lookingforhead localrow lserial
+    global localfrow localirow lserial
 
 
-    set lookingforhead 0
-    if {$localrow >= 0} {
-       removerow $localrow
-       set localrow -1
+    if {$localfrow >= 0} {
+       removerow $localfrow
+       set localfrow -1
+       if {$localirow > 0} {
+           incr localirow -1
+       }
+    }
+    if {$localirow >= 0} {
+       removerow $localirow
+       set localirow -1
     }
     incr lserial
 }
 
     }
     incr lserial
 }
 
-# spawn off a process to do git diff-index HEAD
+# spawn off a process to do git diff-index --cached HEAD
 proc dodiffindex {} {
 proc dodiffindex {} {
-    global localrow lserial
+    global localirow localfrow lserial showlocalchanges
 
 
+    if {!$showlocalchanges} return
     incr lserial
     incr lserial
-    set localrow -1
-    set fd [open "|git diff-index HEAD" r]
+    set localfrow -1
+    set localirow -1
+    set fd [open "|git diff-index --cached HEAD" r]
     fconfigure $fd -blocking 0
     filerun $fd [list readdiffindex $fd $lserial]
 }
 
 proc readdiffindex {fd serial} {
     fconfigure $fd -blocking 0
     filerun $fd [list readdiffindex $fd $lserial]
 }
 
 proc readdiffindex {fd serial} {
-    global localrow commitrow mainheadid nullid curview
+    global localirow commitrow mainheadid nullid2 curview
     global commitinfo commitdata lserial
 
     global commitinfo commitdata lserial
 
+    set isdiff 1
     if {[gets $fd line] < 0} {
     if {[gets $fd line] < 0} {
-       if {[eof $fd]} {
-           close $fd
-           return 0
+       if {![eof $fd]} {
+           return 1
        }
        }
-       return 1
+       set isdiff 0
+    }
+    # we only need to see one line and we don't really care what it says...
+    close $fd
+
+    # now see if there are any local changes not checked in to the index
+    if {$serial == $lserial} {
+       set fd [open "|git diff-files" r]
+       fconfigure $fd -blocking 0
+       filerun $fd [list readdifffiles $fd $serial]
+    }
+
+    if {$isdiff && $serial == $lserial && $localirow == -1} {
+       # add the line for the changes in the index to the graph
+       set localirow $commitrow($curview,$mainheadid)
+       set hl "Local changes checked in to index but not committed"
+       set commitinfo($nullid2) [list  $hl {} {} {} {} "    $hl\n"]
+       set commitdata($nullid2) "\n    $hl\n"
+       insertrow $localirow $nullid2
+    }
+    return 0
+}
+
+proc readdifffiles {fd serial} {
+    global localirow localfrow commitrow mainheadid nullid curview
+    global commitinfo commitdata lserial
+
+    set isdiff 1
+    if {[gets $fd line] < 0} {
+       if {![eof $fd]} {
+           return 1
+       }
+       set isdiff 0
     }
     # we only need to see one line and we don't really care what it says...
     close $fd
 
     }
     # we only need to see one line and we don't really care what it says...
     close $fd
 
-    if {$serial == $lserial && $localrow == -1} {
+    if {$isdiff && $serial == $lserial && $localfrow == -1} {
        # add the line for the local diff to the graph
        # add the line for the local diff to the graph
-       set localrow $commitrow($curview,$mainheadid)
-       set hl "Local uncommitted changes"
+       if {$localirow >= 0} {
+           set localfrow $localirow
+           incr localirow
+       } else {
+           set localfrow $commitrow($curview,$mainheadid)
+       }
+       set hl "Local uncommitted changes, not checked in to index"
        set commitinfo($nullid) [list  $hl {} {} {} {} "    $hl\n"]
        set commitdata($nullid) "\n    $hl\n"
        set commitinfo($nullid) [list  $hl {} {} {} {} "    $hl\n"]
        set commitdata($nullid) "\n    $hl\n"
-       insertrow $localrow $nullid
+       insertrow $localfrow $nullid
     }
     return 0
 }
 
     }
     return 0
 }
 
-proc layoutrows {row endrow last} {
-    global rowidlist rowoffsets displayorder
-    global uparrowlen downarrowlen maxwidth mingaplen
-    global children parentlist
-    global idrowranges
-    global commitidx curview
-    global idinlist rowchk rowrangelist
+proc nextuse {id row} {
+    global commitrow curview children
 
 
-    set idlist [lindex $rowidlist $row]
-    set offs [lindex $rowoffsets $row]
-    while {$row < $endrow} {
-       set id [lindex $displayorder $row]
-       set oldolds {}
-       set newolds {}
-       foreach p [lindex $parentlist $row] {
-           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($curview)} 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
-                       set rm1 [expr {$row - 1}]
-                       lappend idrowranges($i) [lindex $displayorder $rm1]
-                       if {[incr nev -1] <= 0} break
-                       continue
-                   }
-                   set rowchk($id) [expr {$row + $r}]
-               }
+    if {[info exists children($curview,$id)]} {
+       foreach kid $children($curview,$id) {
+           if {![info exists commitrow($curview,$kid)]} {
+               return -1
+           }
+           if {$commitrow($curview,$kid) > $row} {
+               return $commitrow($curview,$kid)
            }
            }
-           lset rowidlist $row $idlist
-           lset rowoffsets $row $offs
        }
        }
-       set col [lsearch -exact $idlist $id]
-       if {$col < 0} {
-           set col [llength $idlist]
-           lappend idlist $id
-           lset rowidlist $row $idlist
-           set z {}
-           if {$children($curview,$id) ne {}} {
-               set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
-               unset idinlist($id)
-           }
-           lappend offs $z
-           lset rowoffsets $row $offs
-           if {$z ne {}} {
-               makeuparrow $id $col $row $z
+    }
+    if {[info exists commitrow($curview,$id)]} {
+       return $commitrow($curview,$id)
+    }
+    return -1
+}
+
+proc prevuse {id row} {
+    global commitrow curview children
+
+    set ret -1
+    if {[info exists children($curview,$id)]} {
+       foreach kid $children($curview,$id) {
+           if {![info exists commitrow($curview,$kid)]} break
+           if {$commitrow($curview,$kid) < $row} {
+               set ret $commitrow($curview,$kid)
            }
            }
-       } else {
-           unset idinlist($id)
-       }
-       set ranges {}
-       if {[info exists idrowranges($id)]} {
-           set ranges $idrowranges($id)
-           lappend ranges $id
-           unset idrowranges($id)
-       }
-       lappend rowrangelist $ranges
-       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]]
+       }
+    }
+    return $ret
+}
+
+proc make_idlist {row} {
+    global displayorder parentlist uparrowlen downarrowlen mingaplen
+    global commitidx curview ordertok children commitrow
+
+    set r [expr {$row - $mingaplen - $downarrowlen - 1}]
+    if {$r < 0} {
+       set r 0
+    }
+    set ra [expr {$row - $downarrowlen}]
+    if {$ra < 0} {
+       set ra 0
+    }
+    set rb [expr {$row + $uparrowlen}]
+    if {$rb > $commitidx($curview)} {
+       set rb $commitidx($curview)
+    }
+    set ids {}
+    for {} {$r < $ra} {incr r} {
+       set nextid [lindex $displayorder [expr {$r + 1}]]
+       foreach p [lindex $parentlist $r] {
+           if {$p eq $nextid} continue
+           set rn [nextuse $p $r]
+           if {$rn >= $row &&
+               $rn <= $r + $downarrowlen + $mingaplen + $uparrowlen} {
+               lappend ids [list $ordertok($curview,$p) $p]
            }
            }
-       } else {
-           lset offs $col {}
        }
        }
-       foreach i $newolds {
-           set idinlist($i) 1
-           set idrowranges($i) $id
+    }
+    for {} {$r < $row} {incr r} {
+       set nextid [lindex $displayorder [expr {$r + 1}]]
+       foreach p [lindex $parentlist $r] {
+           if {$p eq $nextid} continue
+           set rn [nextuse $p $r]
+           if {$rn < 0 || $rn >= $row} {
+               lappend ids [list $ordertok($curview,$p) $p]
+           }
        }
        }
-       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 id [lindex $displayorder $row]
+    lappend ids [list $ordertok($curview,$id) $id]
+    while {$r < $rb} {
+       foreach p [lindex $parentlist $r] {
+           set firstkid [lindex $children($curview,$p) 0]
+           if {$commitrow($curview,$firstkid) < $row} {
+               lappend ids [list $ordertok($curview,$p) $p]
+           }
+       }
+       incr r
+       set id [lindex $displayorder $r]
+       if {$id ne {}} {
+           set firstkid [lindex $children($curview,$id) 0]
+           if {$firstkid ne {} && $commitrow($curview,$firstkid) < $row} {
+               lappend ids [list $ordertok($curview,$id) $id]
+           }
        }
        }
-       lappend rowidlist $idlist
-       lappend rowoffsets $offs
     }
     }
-    return $row
+    set idlist {}
+    foreach idx [lsort -unique $ids] {
+       lappend idlist [lindex $idx 1]
+    }
+    return $idlist
 }
 
 }
 
-proc addextraid {id row} {
-    global displayorder commitrow commitinfo
-    global commitidx commitlisted
-    global parentlist children curview
+proc rowsequal {a b} {
+    while {[set i [lsearch -exact $a {}]] >= 0} {
+       set a [lreplace $a $i $i]
+    }
+    while {[set i [lsearch -exact $b {}]] >= 0} {
+       set b [lreplace $b $i $i]
+    }
+    return [expr {$a eq $b}]
+}
 
 
-    incr commitidx($curview)
-    lappend displayorder $id
-    lappend commitlisted 0
-    lappend parentlist {}
-    set commitrow($curview,$id) $row
-    readcommit $id
-    if {![info exists commitinfo($id)]} {
-       set commitinfo($id) {"No commit information available"}
+proc makeupline {id row rend col} {
+    global rowidlist uparrowlen downarrowlen mingaplen
+
+    for {set r $rend} {1} {set r $rstart} {
+       set rstart [prevuse $id $r]
+       if {$rstart < 0} return
+       if {$rstart < $row} break
+    }
+    if {$rstart + $uparrowlen + $mingaplen + $downarrowlen < $rend} {
+       set rstart [expr {$rend - $uparrowlen - 1}]
     }
     }
-    if {![info exists children($curview,$id)]} {
-       set children($curview,$id) {}
+    for {set r $rstart} {[incr r] <= $row} {} {
+       set idlist [lindex $rowidlist $r]
+       if {$idlist ne {} && [lsearch -exact $idlist $id] < 0} {
+           set col [idcol $idlist $id $col]
+           lset rowidlist $r [linsert $idlist $col $id]
+           changedrow $r
+       }
     }
 }
 
     }
 }
 
-proc layouttail {} {
-    global rowidlist rowoffsets idinlist commitidx curview
-    global idrowranges rowrangelist
+proc layoutrows {row endrow} {
+    global rowidlist rowisopt rowfinal displayorder
+    global uparrowlen downarrowlen maxwidth mingaplen
+    global children parentlist
+    global commitidx viewcomplete curview commitrow
+
+    set idlist {}
+    if {$row > 0} {
+       set rm1 [expr {$row - 1}]
+       foreach id [lindex $rowidlist $rm1] {
+           if {$id ne {}} {
+               lappend idlist $id
+           }
+       }
+       set final [lindex $rowfinal $rm1]
+    }
+    for {} {$row < $endrow} {incr row} {
+       set rm1 [expr {$row - 1}]
+       if {$rm1 < 0 || $idlist eq {}} {
+           set idlist [make_idlist $row]
+           set final 1
+       } else {
+           set id [lindex $displayorder $rm1]
+           set col [lsearch -exact $idlist $id]
+           set idlist [lreplace $idlist $col $col]
+           foreach p [lindex $parentlist $rm1] {
+               if {[lsearch -exact $idlist $p] < 0} {
+                   set col [idcol $idlist $p $col]
+                   set idlist [linsert $idlist $col $p]
+                   # if not the first child, we have to insert a line going up
+                   if {$id ne [lindex $children($curview,$p) 0]} {
+                       makeupline $p $rm1 $row $col
+                   }
+               }
+           }
+           set id [lindex $displayorder $row]
+           if {$row > $downarrowlen} {
+               set termrow [expr {$row - $downarrowlen - 1}]
+               foreach p [lindex $parentlist $termrow] {
+                   set i [lsearch -exact $idlist $p]
+                   if {$i < 0} continue
+                   set nr [nextuse $p $termrow]
+                   if {$nr < 0 || $nr >= $row + $mingaplen + $uparrowlen} {
+                       set idlist [lreplace $idlist $i $i]
+                   }
+               }
+           }
+           set col [lsearch -exact $idlist $id]
+           if {$col < 0} {
+               set col [idcol $idlist $id]
+               set idlist [linsert $idlist $col $id]
+               if {$children($curview,$id) ne {}} {
+                   makeupline $id $rm1 $row $col
+               }
+           }
+           set r [expr {$row + $uparrowlen - 1}]
+           if {$r < $commitidx($curview)} {
+               set x $col
+               foreach p [lindex $parentlist $r] {
+                   if {[lsearch -exact $idlist $p] >= 0} continue
+                   set fk [lindex $children($curview,$p) 0]
+                   if {$commitrow($curview,$fk) < $row} {
+                       set x [idcol $idlist $p $x]
+                       set idlist [linsert $idlist $x $p]
+                   }
+               }
+               if {[incr r] < $commitidx($curview)} {
+                   set p [lindex $displayorder $r]
+                   if {[lsearch -exact $idlist $p] < 0} {
+                       set fk [lindex $children($curview,$p) 0]
+                       if {$fk ne {} && $commitrow($curview,$fk) < $row} {
+                           set x [idcol $idlist $p $x]
+                           set idlist [linsert $idlist $x $p]
+                       }
+                   }
+               }
+           }
+       }
+       if {$final && !$viewcomplete($curview) &&
+           $row + $uparrowlen + $mingaplen + $downarrowlen
+               >= $commitidx($curview)} {
+           set final 0
+       }
+       set l [llength $rowidlist]
+       if {$row == $l} {
+           lappend rowidlist $idlist
+           lappend rowisopt 0
+           lappend rowfinal $final
+       } elseif {$row < $l} {
+           if {![rowsequal $idlist [lindex $rowidlist $row]]} {
+               lset rowidlist $row $idlist
+               changedrow $row
+           }
+           lset rowfinal $row $final
+       } else {
+           set pad [ntimes [expr {$row - $l}] {}]
+           set rowidlist [concat $rowidlist $pad]
+           lappend rowidlist $idlist
+           set rowfinal [concat $rowfinal $pad]
+           lappend rowfinal $final
+           set rowisopt [concat $rowisopt [ntimes [expr {$row - $l + 1}] 0]]
+       }
+    }
+    return $row
+}
 
 
-    set row $commitidx($curview)
-    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 idrowranges($id) $id
-       lappend rowrangelist $idrowranges($id)
-       unset idrowranges($id)
-       incr row
-       set offs [ntimes $col 0]
-       set idlist [lreplace $idlist $col $col]
-       lappend rowidlist $idlist
-       lappend rowoffsets $offs
-    }
-
-    foreach id [array names idinlist] {
-       unset idinlist($id)
-       addextraid $id $row
-       lset rowidlist $row [list $id]
-       lset rowoffsets $row 0
-       makeuparrow $id 0 $row 0
-       lappend idrowranges($id) $id
-       lappend rowrangelist $idrowranges($id)
-       unset idrowranges($id)
-       incr row
-       lappend rowidlist {}
-       lappend rowoffsets {}
+proc changedrow {row} {
+    global displayorder iddrawn rowisopt need_redisplay
+
+    set l [llength $rowisopt]
+    if {$row < $l} {
+       lset rowisopt $row 0
+       if {$row + 1 < $l} {
+           lset rowisopt [expr {$row + 1}] 0
+           if {$row + 2 < $l} {
+               lset rowisopt [expr {$row + 2}] 0
+           }
+       }
+    }
+    set id [lindex $displayorder $row]
+    if {[info exists iddrawn($id)]} {
+       set need_redisplay 1
     }
 }
 
 proc insert_pad {row col npad} {
     }
 }
 
 proc insert_pad {row col npad} {
-    global rowidlist rowoffsets
+    global rowidlist
 
     set pad [ntimes $npad {}]
 
     set pad [ntimes $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}]]
+    set idlist [lindex $rowidlist $row]
+    set bef [lrange $idlist 0 [expr {$col - 1}]]
+    set aft [lrange $idlist $col end]
+    set i [lsearch -exact $aft {}]
+    if {$i > 0} {
+       set aft [lreplace $aft $i $i]
+    }
+    lset rowidlist $row [concat $bef $pad $aft]
+    changedrow $row
 }
 
 proc optimize_rows {row col endrow} {
 }
 
 proc optimize_rows {row col endrow} {
-    global rowidlist rowoffsets displayorder
+    global rowidlist rowisopt displayorder curview children
 
 
-    for {} {$row < $endrow} {incr row} {
-       set idlist [lindex $rowidlist $row]
-       set offs [lindex $rowoffsets $row]
+    if {$row < 1} {
+       set row 1
+    }
+    for {} {$row < $endrow} {incr row; set col 0} {
+       if {[lindex $rowisopt $row]} continue
        set haspad 0
        set haspad 0
-       for {} {$col < [llength $offs]} {incr col} {
-           if {[lindex $idlist $col] eq {}} {
+       set y0 [expr {$row - 1}]
+       set ym [expr {$row - 2}]
+       set idlist [lindex $rowidlist $row]
+       set previdlist [lindex $rowidlist $y0]
+       if {$idlist eq {} || $previdlist eq {}} continue
+       if {$ym >= 0} {
+           set pprevidlist [lindex $rowidlist $ym]
+           if {$pprevidlist eq {}} continue
+       } else {
+           set pprevidlist {}
+       }
+       set x0 -1
+       set xm -1
+       for {} {$col < [llength $idlist]} {incr col} {
+           set id [lindex $idlist $col]
+           if {[lindex $previdlist $col] eq $id} continue
+           if {$id eq {}} {
                set haspad 1
                continue
            }
                set haspad 1
                continue
            }
-           set z [lindex $offs $col]
-           if {$z eq {}} continue
+           set x0 [lsearch -exact $previdlist $id]
+           if {$x0 < 0} continue
+           set z [expr {$x0 - $col}]
            set isarrow 0
            set isarrow 0
-           set x0 [expr {$col + $z}]
-           set y0 [expr {$row - 1}]
-           set z0 [lindex $rowoffsets $y0 $x0]
+           set z0 {}
+           if {$ym >= 0} {
+               set xm [lsearch -exact $pprevidlist $id]
+               if {$xm >= 0} {
+                   set z0 [expr {$xm - $x0}]
+               }
+           }
            if {$z0 eq {}} {
            if {$z0 eq {}} {
-               set id [lindex $idlist $col]
-               set ranges [rowranges $id]
-               if {$ranges ne {} && $y0 > [lindex $ranges 0]} {
+               # if row y0 is the first child of $id then it's not an arrow
+               if {[lindex $children($curview,$id) 0] ne
+                   [lindex $displayorder $y0]} {
                    set isarrow 1
                }
            }
                    set isarrow 1
                }
            }
+           if {!$isarrow && $id ne [lindex $displayorder $row] &&
+               [lsearch -exact [lindex $rowidlist [expr {$row+1}]] $id] < 0} {
+               set isarrow 1
+           }
            # Looking at lines from this row to the previous row,
            # make them go straight up if they end in an arrow on
            # the previous row; otherwise make them go straight up
            # Looking at lines from this row to the previous row,
            # make them go straight up if they end in an arrow on
            # the previous row; otherwise make them go straight up
@@ -2952,43 +3146,32 @@ proc optimize_rows {row col endrow} {
                # Line currently goes left too much;
                # insert pads in the previous row, then optimize it
                set npad [expr {-1 - $z + $isarrow}]
                # Line currently goes left too much;
                # insert pads in the previous row, then optimize it
                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
                }
                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]
+               set previdlist [lindex $rowidlist $y0]
+               set x0 [lsearch -exact $previdlist $id]
+               set z [expr {$x0 - $col}]
+               if {$z0 ne {}} {
+                   set pprevidlist [lindex $rowidlist $ym]
+                   set xm [lsearch -exact $pprevidlist $id]
+                   set z0 [expr {$xm - $x0}]
+               }
            } elseif {$z > 1 || ($z > 0 && $isarrow)} {
                # Line currently goes right too much;
            } elseif {$z > 1 || ($z > 0 && $isarrow)} {
                # Line currently goes right too much;
-               # insert pads in this line and adjust the next's rowoffsets
+               # insert pads in this line
                set npad [expr {$z - 1 + $isarrow}]
                set npad [expr {$z - 1 + $isarrow}]
-               set y1 [expr {$row + 1}]
-               set offs2 [lindex $rowoffsets $y1]
-               set x1 -1
-               foreach z $offs2 {
-                   incr x1
-                   if {$z eq {} || $x1 + $z < $col} continue
-                   if {$x1 + $z > $col} {
-                       incr npad
-                   }
-                   lset 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]
+               insert_pad $row $col $npad
+               set idlist [lindex $rowidlist $row]
                incr col $npad
                incr col $npad
-               set offs [incrange $tmp $col [expr {-$npad}]]
-               set z [lindex $offs $col]
+               set z [expr {$x0 - $col}]
                set haspad 1
            }
                set haspad 1
            }
-           if {$z0 eq {} && !$isarrow} {
+           if {$z0 eq {} && !$isarrow && $ym >= 0} {
                # this line links to its first child on row $row-2
                # 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]
+               set id [lindex $displayorder $ym]
+               set xc [lsearch -exact $pprevidlist $id]
                if {$xc >= 0} {
                    set z0 [expr {$xc - $x0}]
                }
                if {$xc >= 0} {
                    set z0 [expr {$xc - $x0}]
                }
@@ -2996,52 +3179,35 @@ proc optimize_rows {row col endrow} {
            # avoid lines jigging left then immediately right
            if {$z0 ne {} && $z < 0 && $z0 > 0} {
                insert_pad $y0 $x0 1
            # avoid lines jigging left then immediately right
            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
+               incr x0
+               optimize_rows $y0 $x0 $row
+               set previdlist [lindex $rowidlist $y0]
            }
        }
        if {!$haspad} {
            }
        }
        if {!$haspad} {
-           set o {}
            # Find the first column that doesn't have a line going right
            for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
            # Find the first column that doesn't have a line going right
            for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
-               set o [lindex $offs $col]
-               if {$o eq {}} {
+               set id [lindex $idlist $col]
+               if {$id eq {}} break
+               set x0 [lsearch -exact $previdlist $id]
+               if {$x0 < 0} {
                    # check if this is the link to the first child
                    # check if this is the link to the first child
-                   set id [lindex $idlist $col]
-                   set ranges [rowranges $id]
-                   if {$ranges ne {} && $row == [lindex $ranges 0]} {
+                   set kid [lindex $displayorder $y0]
+                   if {[lindex $children($curview,$id) 0] eq $kid} {
                        # it is, work out offset to child
                        # 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}]
-                       }
+                       set x0 [lsearch -exact $previdlist $kid]
                    }
                }
                    }
                }
-               if {$o eq {} || $o <= 0} break
+               if {$x0 <= $col} break
            }
            # Insert a pad at that column as long as it has a line and
            }
            # Insert a pad at that column as long as it has a line and
-           # isn't the last column, and adjust the next row' offsets
-           if {$o ne {} && [incr col] < [llength $idlist]} {
-               set y1 [expr {$row + 1}]
-               set offs2 [lindex $rowoffsets $y1]
-               set x1 -1
-               foreach z $offs2 {
-                   incr x1
-                   if {$z eq {} || $x1 + $z < $col} continue
-                   lset rowoffsets $y1 [incrange $offs2 $x1 1]
-                   break
-               }
+           # isn't the last column
+           if {$x0 >= 0 && [incr col] < [llength $idlist]} {
                set idlist [linsert $idlist $col {}]
                set idlist [linsert $idlist $col {}]
-               set tmp [linsert $offs $col {}]
-               incr col
-               set offs [incrange $tmp $col -1]
+               lset rowidlist $row $idlist
+               changedrow $row
            }
        }
            }
        }
-       lset rowidlist $row $idlist
-       lset rowoffsets $row $offs
-       set col 0
     }
 }
 
     }
 }
 
@@ -3066,51 +3232,64 @@ proc linewidth {id} {
 }
 
 proc rowranges {id} {
 }
 
 proc rowranges {id} {
-    global phase idrowranges commitrow rowlaidout rowrangelist curview
-
-    set ranges {}
-    if {$phase eq {} ||
-       ([info exists commitrow($curview,$id)]
-        && $commitrow($curview,$id) < $rowlaidout)} {
-       set ranges [lindex $rowrangelist $commitrow($curview,$id)]
-    } elseif {[info exists idrowranges($id)]} {
-       set ranges $idrowranges($id)
-    }
-    set linenos {}
-    foreach rid $ranges {
-       lappend linenos $commitrow($curview,$rid)
-    }
-    if {$linenos ne {}} {
-       lset linenos 0 [expr {[lindex $linenos 0] + 1}]
-    }
-    return $linenos
-}
-
-# work around tk8.4 refusal to draw arrows on diagonal segments
-proc adjarrowhigh {coords} {
-    global linespc
-
-    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]
+    global commitrow curview children uparrowlen downarrowlen
+    global rowidlist
+
+    set kids $children($curview,$id)
+    if {$kids eq {}} {
+       return {}
+    }
+    set ret {}
+    lappend kids $id
+    foreach child $kids {
+       if {![info exists commitrow($curview,$child)]} break
+       set row $commitrow($curview,$child)
+       if {![info exists prev]} {
+           lappend ret [expr {$row + 1}]
        } else {
        } 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]
+           if {$row <= $prevrow} {
+               puts "oops children out of order [shortids $id] $row < [shortids $prev] $prevrow"
+           }
+           # see if the line extends the whole way from prevrow to row
+           if {$row > $prevrow + $uparrowlen + $downarrowlen &&
+               [lsearch -exact [lindex $rowidlist \
+                           [expr {int(($row + $prevrow) / 2)}]] $id] < 0} {
+               # it doesn't, see where it ends
+               set r [expr {$prevrow + $downarrowlen}]
+               if {[lsearch -exact [lindex $rowidlist $r] $id] < 0} {
+                   while {[incr r -1] > $prevrow &&
+                          [lsearch -exact [lindex $rowidlist $r] $id] < 0} {}
+               } else {
+                   while {[incr r] <= $row &&
+                          [lsearch -exact [lindex $rowidlist $r] $id] >= 0} {}
+                   incr r -1
+               }
+               lappend ret $r
+               # see where it starts up again
+               set r [expr {$row - $uparrowlen}]
+               if {[lsearch -exact [lindex $rowidlist $r] $id] < 0} {
+                   while {[incr r] < $row &&
+                          [lsearch -exact [lindex $rowidlist $r] $id] < 0} {}
+               } else {
+                   while {[incr r -1] >= $prevrow &&
+                          [lsearch -exact [lindex $rowidlist $r] $id] >= 0} {}
+                   incr r
+               }
+               lappend ret $r
+           }
        }
        }
+       if {$child eq $id} {
+           lappend ret $row
+       }
+       set prev $id
+       set prevrow $row
     }
     }
-    return $coords
+    return $ret
 }
 
 proc drawlineseg {id row endrow arrowlow} {
     global rowidlist displayorder iddrawn linesegs
 }
 
 proc drawlineseg {id row endrow arrowlow} {
     global rowidlist displayorder iddrawn linesegs
-    global canv colormap linespc curview maxlinelen
+    global canv colormap linespc curview maxlinelen parentlist
 
     set cols [list [lsearch -exact [lindex $rowidlist $row] $id]]
     set le [expr {$row + 1}]
 
     set cols [list [lsearch -exact [lindex $rowidlist $row] $id]]
     set le [expr {$row + 1}]
@@ -3185,9 +3364,11 @@ proc drawlineseg {id row endrow arrowlow} {
        set itl [lindex $lines [expr {$i-1}] 2]
        set al [$canv itemcget $itl -arrow]
        set arrowlow [expr {$al eq "last" || $al eq "both"}]
        set itl [lindex $lines [expr {$i-1}] 2]
        set al [$canv itemcget $itl -arrow]
        set arrowlow [expr {$al eq "last" || $al eq "both"}]
-    } elseif {$arrowlow &&
-             [lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0} {
-       set arrowlow 0
+    } elseif {$arrowlow} {
+       if {[lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0 ||
+           [lsearch -exact [lindex $parentlist [expr {$row-1}]] $id] >= 0} {
+           set arrowlow 0
+       }
     }
     set arrow [lindex {none first last both} [expr {$arrowhigh + 2*$arrowlow}]]
     for {set y $le} {[incr y -1] > $row} {} {
     }
     set arrow [lindex {none first last both} [expr {$arrowhigh + 2*$arrowlow}]]
     for {set y $le} {[incr y -1] > $row} {} {
@@ -3206,8 +3387,19 @@ proc drawlineseg {id row endrow arrowlow} {
            set xc [lsearch -exact [lindex $rowidlist $row] $ch]
            if {$xc < 0} {
                puts "oops: drawlineseg: child $ch not on row $row"
            set xc [lsearch -exact [lindex $rowidlist $row] $ch]
            if {$xc < 0} {
                puts "oops: drawlineseg: child $ch not on row $row"
-           } else {
-               if {$xc < $x - 1} {
+           } elseif {$xc != $x} {
+               if {($arrowhigh && $le == $row + 1) || $dir == 0} {
+                   set d [expr {int(0.5 * $linespc)}]
+                   set x1 [xc $row $x]
+                   if {$xc < $x} {
+                       set x2 [expr {$x1 - $d}]
+                   } else {
+                       set x2 [expr {$x1 + $d}]
+                   }
+                   set y2 [yc $row]
+                   set y1 [expr {$y2 + $d}]
+                   lappend coords $x1 $y1 $x2 $y2
+               } elseif {$xc < $x - 1} {
                    lappend coords [xc $row [expr {$x-1}]] [yc $row]
                } elseif {$xc > $x + 1} {
                    lappend coords [xc $row [expr {$x+1}]] [yc $row]
                    lappend coords [xc $row [expr {$x-1}]] [yc $row]
                } elseif {$xc > $x + 1} {
                    lappend coords [xc $row [expr {$x+1}]] [yc $row]
@@ -3218,23 +3410,9 @@ proc drawlineseg {id row endrow arrowlow} {
        } else {
            set xn [xc $row $xp]
            set yn [yc $row]
        } else {
            set xn [xc $row $xp]
            set yn [yc $row]
-           # work around tk8.4 refusal to draw arrows on diagonal segments
-           if {$arrowlow && $xn != [lindex $coords end-1]} {
-               if {[llength $coords] < 4 ||
-                   [lindex $coords end-3] != [lindex $coords end-1] ||
-                   [lindex $coords end] - $yn > 2 * $linespc} {
-                   set xn [xc $row [expr {$xp - 0.5 * $dir}]]
-                   set yo [yc [expr {$row + 0.5}]]
-                   lappend coords $xn $yo $xn $yn
-               }
-           } else {
-               lappend coords $xn $yn
-           }
+           lappend coords $xn $yn
        }
        if {!$joinhigh} {
        }
        if {!$joinhigh} {
-           if {$arrowhigh} {
-               set coords [adjarrowhigh $coords]
-           }
            assigncolor $id
            set t [$canv create line $coords -width [linewidth $id] \
                       -fill $colormap($id) -tags lines.$id -arrow $arrow]
            assigncolor $id
            set t [$canv create line $coords -width [linewidth $id] \
                       -fill $colormap($id) -tags lines.$id -arrow $arrow]
@@ -3258,9 +3436,6 @@ proc drawlineseg {id row endrow arrowlow} {
        set coords [concat $coords $clow]
        if {!$joinhigh} {
            lset lines [expr {$i-1}] 1 $le
        set coords [concat $coords $clow]
        if {!$joinhigh} {
            lset lines [expr {$i-1}] 1 $le
-           if {$arrowhigh} {
-               set coords [adjarrowhigh $coords]
-           }
        } else {
            # coalesce two pieces
            $canv delete $ith
        } else {
            # coalesce two pieces
            $canv delete $ith
@@ -3280,7 +3455,7 @@ proc drawlineseg {id row endrow arrowlow} {
 
 proc drawparentlinks {id row} {
     global rowidlist canv colormap curview parentlist
 
 proc drawparentlinks {id row} {
     global rowidlist canv colormap curview parentlist
-    global idpos
+    global idpos linespc
 
     set rowids [lindex $rowidlist $row]
     set col [lsearch -exact $rowids $id]
 
     set rowids [lindex $rowidlist $row]
     set col [lsearch -exact $rowids $id]
@@ -3290,6 +3465,8 @@ proc drawparentlinks {id row} {
     set x [xc $row $col]
     set y [yc $row]
     set y2 [yc $row2]
     set x [xc $row $col]
     set y [yc $row]
     set y2 [yc $row2]
+    set d [expr {int(0.5 * $linespc)}]
+    set ymid [expr {$y + $d}]
     set ids [lindex $rowidlist $row2]
     # rmx = right-most X coord used
     set rmx 0
     set ids [lindex $rowidlist $row2]
     # rmx = right-most X coord used
     set rmx 0
@@ -3303,19 +3480,37 @@ proc drawparentlinks {id row} {
        if {$x2 > $rmx} {
            set rmx $x2
        }
        if {$x2 > $rmx} {
            set rmx $x2
        }
-       if {[lsearch -exact $rowids $p] < 0} {
+       set j [lsearch -exact $rowids $p]
+       if {$j < 0} {
            # drawlineseg will do this one for us
            continue
        }
        assigncolor $p
        # should handle duplicated parents here...
        set coords [list $x $y]
            # drawlineseg will do this one for us
            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
+       if {$i != $col} {
+           # if attaching to a vertical segment, draw a smaller
+           # slant for visual distinctness
+           if {$i == $j} {
+               if {$i < $col} {
+                   lappend coords [expr {$x2 + $d}] $y $x2 $ymid
+               } else {
+                   lappend coords [expr {$x2 - $d}] $y $x2 $ymid
+               }
+           } elseif {$i < $col && $i < $j} {
+               # segment slants towards us already
+               lappend coords [xc $row $j] $y
+           } else {
+               if {$i < $col - 1} {
+                   lappend coords [expr {$x2 + $linespc}] $y
+               } elseif {$i > $col + 1} {
+                   lappend coords [expr {$x2 - $linespc}] $y
+               }
+               lappend coords $x2 $y2
+           }
+       } else {
+           lappend coords $x2 $y2
        }
        }
-       lappend coords $x2 $y2
        set t [$canv create line $coords -width [linewidth $p] \
                   -fill $colormap($p) -tags lines.$p]
        $canv lower $t
        set t [$canv create line $coords -width [linewidth $p] \
                   -fill $colormap($p) -tags lines.$p]
        $canv lower $t
@@ -3337,13 +3532,15 @@ proc drawcmittext {id row col} {
     global linespc canv canv2 canv3 canvy0 fgcolor curview
     global commitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
     global linespc canv canv2 canv3 canvy0 fgcolor curview
     global commitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
-    global linehtag linentag linedtag markingmatches
-    global mainfont canvxmax boldrows boldnamerows fgcolor nullid
+    global linehtag linentag linedtag selectedline
+    global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
 
     # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
     set listed [lindex $commitlisted $row]
     if {$id eq $nullid} {
        set ofill red
 
     # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
     set listed [lindex $commitlisted $row]
     if {$id eq $nullid} {
        set ofill red
+    } elseif {$id eq $nullid2} {
+       set ofill green
     } else {
        set ofill [expr {$listed != 0? "blue": "white"}]
     }
     } else {
        set ofill [expr {$listed != 0? "blue": "white"}]
     }
@@ -3411,10 +3608,10 @@ proc drawcmittext {id row col} {
                            -text $name -font $nfont -tags text]
     set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
                            -text $date -font $mainfont -tags text]
                            -text $name -font $nfont -tags text]
     set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
                            -text $date -font $mainfont -tags text]
-    set xr [expr {$xt + [font measure $mainfont $headline]}]
-    if {$markingmatches} {
-       markrowmatches $row $headline $name
+    if {[info exists selectedline] && $selectedline == $row} {
+       make_secsel $row
     }
     }
+    set xr [expr {$xt + [font measure $mainfont $headline]}]
     if {$xr > $canvxmax} {
        set canvxmax $xr
        setcanvscroll
     if {$xr > $canvxmax} {
        set canvxmax $xr
        setcanvscroll
@@ -3422,10 +3619,10 @@ proc drawcmittext {id row col} {
 }
 
 proc drawcmitrow {row} {
 }
 
 proc drawcmitrow {row} {
-    global displayorder rowidlist
-    global iddrawn
+    global displayorder rowidlist nrows_drawn
+    global iddrawn markingmatches
     global commitinfo parentlist numcommits
     global commitinfo parentlist numcommits
-    global filehighlight fhighlights findstring nhighlights
+    global filehighlight fhighlights findpattern nhighlights
     global hlview vhighlights
     global highlight_related rhighlights
 
     global hlview vhighlights
     global highlight_related rhighlights
 
@@ -3438,29 +3635,34 @@ proc drawcmitrow {row} {
     if {[info exists filehighlight] && ![info exists fhighlights($row)]} {
        askfilehighlight $row $id
     }
     if {[info exists filehighlight] && ![info exists fhighlights($row)]} {
        askfilehighlight $row $id
     }
-    if {$findstring ne {} && ![info exists nhighlights($row)]} {
+    if {$findpattern ne {} && ![info exists nhighlights($row)]} {
        askfindhighlight $row $id
     }
     if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
        askrelhighlight $row $id
     }
        askfindhighlight $row $id
     }
     if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
        askrelhighlight $row $id
     }
-    if {[info exists iddrawn($id)]} return
-    set col [lsearch -exact [lindex $rowidlist $row] $id]
-    if {$col < 0} {
-       puts "oops, row $row id $id not in list"
-       return
+    if {![info exists iddrawn($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)]} {
+           getcommit $id
+       }
+       assigncolor $id
+       drawcmittext $id $row $col
+       set iddrawn($id) 1
+       incr nrows_drawn
     }
     }
-    if {![info exists commitinfo($id)]} {
-       getcommit $id
+    if {$markingmatches} {
+       markrowmatches $row $id
     }
     }
-    assigncolor $id
-    drawcmittext $id $row $col
-    set iddrawn($id) 1
 }
 
 proc drawcommits {row {endrow {}}} {
 }
 
 proc drawcommits {row {endrow {}}} {
-    global numcommits iddrawn displayorder curview
-    global parentlist rowidlist
+    global numcommits iddrawn displayorder curview need_redisplay
+    global parentlist rowidlist rowfinal uparrowlen downarrowlen nrows_drawn
 
     if {$row < 0} {
        set row 0
 
     if {$row < 0} {
        set row 0
@@ -3472,6 +3674,35 @@ proc drawcommits {row {endrow {}}} {
        set endrow [expr {$numcommits - 1}]
     }
 
        set endrow [expr {$numcommits - 1}]
     }
 
+    set rl1 [expr {$row - $downarrowlen - 3}]
+    if {$rl1 < 0} {
+       set rl1 0
+    }
+    set ro1 [expr {$row - 3}]
+    if {$ro1 < 0} {
+       set ro1 0
+    }
+    set r2 [expr {$endrow + $uparrowlen + 3}]
+    if {$r2 > $numcommits} {
+       set r2 $numcommits
+    }
+    for {set r $rl1} {$r < $r2} {incr r} {
+       if {[lindex $rowidlist $r] ne {} && [lindex $rowfinal $r]} {
+           if {$rl1 < $r} {
+               layoutrows $rl1 $r
+           }
+           set rl1 [expr {$r + 1}]
+       }
+    }
+    if {$rl1 < $r} {
+       layoutrows $rl1 $r
+    }
+    optimize_rows $ro1 0 $r2
+    if {$need_redisplay || $nrows_drawn > 2000} {
+       clear_display
+       drawvisible
+    }
+
     # make the lines join to already-drawn rows either side
     set r [expr {$row - 1}]
     if {$r < 0 || ![info exists iddrawn([lindex $displayorder $r])]} {
     # make the lines join to already-drawn rows either side
     set r [expr {$row - 1}]
     if {$r < 0 || ![info exists iddrawn([lindex $displayorder $r])]} {
@@ -3539,7 +3770,7 @@ proc drawvisible {} {
 }
 
 proc clear_display {} {
 }
 
 proc clear_display {} {
-    global iddrawn linesegs
+    global iddrawn linesegs need_redisplay nrows_drawn
     global vhighlights fhighlights nhighlights rhighlights
 
     allcanvs delete all
     global vhighlights fhighlights nhighlights rhighlights
 
     allcanvs delete all
@@ -3549,10 +3780,12 @@ proc clear_display {} {
     catch {unset fhighlights}
     catch {unset nhighlights}
     catch {unset rhighlights}
     catch {unset fhighlights}
     catch {unset nhighlights}
     catch {unset rhighlights}
+    set need_redisplay 0
+    set nrows_drawn 0
 }
 
 proc findcrossings {id} {
 }
 
 proc findcrossings {id} {
-    global rowidlist parentlist numcommits rowoffsets displayorder
+    global rowidlist parentlist numcommits displayorder
 
     set cross {}
     set ccross {}
 
     set cross {}
     set ccross {}
@@ -3561,12 +3794,9 @@ proc findcrossings {id} {
            set e [expr {$numcommits - 1}]
        }
        if {$e <= $s} continue
            set e [expr {$numcommits - 1}]
        }
        if {$e <= $s} continue
-       set x [lsearch -exact [lindex $rowidlist $e] $id]
-       if {$x < 0} {
-           puts "findcrossings: oops, no [shortids $id] in row $e"
-           continue
-       }
        for {set row $e} {[incr row -1] >= $s} {} {
        for {set row $e} {[incr row -1] >= $s} {} {
+           set x [lsearch -exact [lindex $rowidlist $row] $id]
+           if {$x < 0} break
            set olds [lindex $parentlist $row]
            set kid [lindex $displayorder $row]
            set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
            set olds [lindex $parentlist $row]
            set kid [lindex $displayorder $row]
            set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
@@ -3584,9 +3814,6 @@ proc findcrossings {id} {
                    }
                }
            }
                    }
                }
            }
-           set inc [lindex $rowoffsets $row $x]
-           if {$inc eq {}} break
-           incr x $inc
        }
     }
     return [concat $ccross {{}} $cross]
        }
     }
     return [concat $ccross {{}} $cross]
@@ -3776,9 +4003,9 @@ proc show_status {msg} {
 # on that row and below will move down one row.
 proc insertrow {row newcmit} {
     global displayorder parentlist commitlisted children
 # on that row and below will move down one row.
 proc insertrow {row newcmit} {
     global displayorder parentlist commitlisted children
-    global commitrow curview rowidlist rowoffsets numcommits
-    global rowrangelist rowlaidout rowoptim numcommits
-    global selectedline rowchk commitidx
+    global commitrow curview rowidlist rowisopt rowfinal numcommits
+    global numcommits
+    global selectedline commitidx ordertok
 
     if {$row >= $numcommits} {
        puts "oops, inserting new row $row but only have $numcommits rows"
 
     if {$row >= $numcommits} {
        puts "oops, inserting new row $row but only have $numcommits rows"
@@ -3798,45 +4025,24 @@ proc insertrow {row newcmit} {
        set commitrow($curview,$id) $r
     }
     incr commitidx($curview)
        set commitrow($curview,$id) $r
     }
     incr commitidx($curview)
+    set ordertok($curview,$newcmit) $ordertok($curview,$p)
 
 
-    set idlist [lindex $rowidlist $row]
-    set offs [lindex $rowoffsets $row]
-    set newoffs {}
-    foreach x $idlist {
-       if {$x eq {} || ($x eq $p && [llength $kids] == 1)} {
-           lappend newoffs {}
-       } else {
-           lappend newoffs 0
-       }
-    }
-    if {[llength $kids] == 1} {
-       set col [lsearch -exact $idlist $p]
-       lset idlist $col $newcmit
-    } else {
-       set col [llength $idlist]
-       lappend idlist $newcmit
-       lappend offs {}
-       lset rowoffsets $row $offs
-    }
-    set rowidlist [linsert $rowidlist $row $idlist]
-    set rowoffsets [linsert $rowoffsets [expr {$row+1}] $newoffs]
-
-    set rowrangelist [linsert $rowrangelist $row {}]
-    if {[llength $kids] > 1} {
-       set rp1 [expr {$row + 1}]
-       set ranges [lindex $rowrangelist $rp1]
-       if {$ranges eq {}} {
-           set ranges [list $newcmit $p]
-       } elseif {[lindex $ranges end-1] eq $p} {
-           lset ranges end-1 $newcmit
+    if {$row < [llength $rowidlist]} {
+       set idlist [lindex $rowidlist $row]
+       if {$idlist ne {}} {
+           if {[llength $kids] == 1} {
+               set col [lsearch -exact $idlist $p]
+               lset idlist $col $newcmit
+           } else {
+               set col [llength $idlist]
+               lappend idlist $newcmit
+           }
        }
        }
-       lset rowrangelist $rp1 $ranges
+       set rowidlist [linsert $rowidlist $row $idlist]
+       set rowisopt [linsert $rowisopt $row 0]
+       set rowfinal [linsert $rowfinal $row [lindex $rowfinal $row]]
     }
 
     }
 
-    catch {unset rowchk}
-
-    incr rowlaidout
-    incr rowoptim
     incr numcommits
 
     if {[info exists selectedline] && $selectedline >= $row} {
     incr numcommits
 
     if {[info exists selectedline] && $selectedline >= $row} {
@@ -3848,9 +4054,9 @@ proc insertrow {row newcmit} {
 # Remove a commit that was inserted with insertrow on row $row.
 proc removerow {row} {
     global displayorder parentlist commitlisted children
 # Remove a commit that was inserted with insertrow on row $row.
 proc removerow {row} {
     global displayorder parentlist commitlisted children
-    global commitrow curview rowidlist rowoffsets numcommits
-    global rowrangelist idrowranges rowlaidout rowoptim numcommits
-    global linesegends selectedline rowchk commitidx
+    global commitrow curview rowidlist rowisopt rowfinal numcommits
+    global numcommits
+    global linesegends selectedline commitidx
 
     if {$row >= $numcommits} {
        puts "oops, removing row $row but only have $numcommits rows"
 
     if {$row >= $numcommits} {
        puts "oops, removing row $row but only have $numcommits rows"
@@ -3875,27 +4081,12 @@ proc removerow {row} {
     }
     incr commitidx($curview) -1
 
     }
     incr commitidx($curview) -1
 
-    set rowidlist [lreplace $rowidlist $row $row]
-    set rowoffsets [lreplace $rowoffsets $rp1 $rp1]
-    if {$kids ne {}} {
-       set offs [lindex $rowoffsets $row]
-       set offs [lreplace $offs end end]
-       lset rowoffsets $row $offs
-    }
-
-    set rowrangelist [lreplace $rowrangelist $row $row]
-    if {[llength $kids] > 0} {
-       set ranges [lindex $rowrangelist $row]
-       if {[lindex $ranges end-1] eq $id} {
-           set ranges [lreplace $ranges end-1 end]
-           lset rowrangelist $row $ranges
-       }
+    if {$row < [llength $rowidlist]} {
+       set rowidlist [lreplace $rowidlist $row $row]
+       set rowisopt [lreplace $rowisopt $row $row]
+       set rowfinal [lreplace $rowfinal $row $row]
     }
 
     }
 
-    catch {unset rowchk}
-
-    incr rowlaidout -1
-    incr rowoptim -1
     incr numcommits -1
 
     if {[info exists selectedline] && $selectedline > $row} {
     incr numcommits -1
 
     if {[info exists selectedline] && $selectedline > $row} {
@@ -3958,9 +4149,9 @@ proc findmatches {f} {
 
 proc dofind {{rev 0}} {
     global findstring findstartline findcurline selectedline numcommits
 
 proc dofind {{rev 0}} {
     global findstring findstartline findcurline selectedline numcommits
+    global gdttype filehighlight fh_serial find_dirn
 
     unmarkmatches
 
     unmarkmatches
-    cancel_next_highlight
     focus .
     if {$findstring eq {} || $numcommits == 0} return
     if {![info exists selectedline]} {
     focus .
     if {$findstring eq {} || $numcommits == 0} return
     if {![info exists selectedline]} {
@@ -3970,20 +4161,24 @@ proc dofind {{rev 0}} {
     }
     set findcurline $findstartline
     nowbusy finding
     }
     set findcurline $findstartline
     nowbusy finding
+    if {$gdttype ne "containing:" && ![info exists filehighlight]} {
+       after cancel do_file_hl $fh_serial
+       do_file_hl $fh_serial
+    }
     if {!$rev} {
     if {!$rev} {
+       set find_dirn 1
        run findmore
     } else {
        run findmore
     } else {
-       set findcurline $findstartline
-       if {$findcurline == 0} {
-           set findcurline $numcommits
-       }
-       incr findcurline -1
+       set find_dirn -1
        run findmorerev
     }
 }
 
 proc findnext {restart} {
        run findmorerev
     }
 }
 
 proc findnext {restart} {
-    global findcurline
+    global findcurline find_dirn
+
+    if {[info exists find_dirn]} return
+    set find_dirn 1
     if {![info exists findcurline]} {
        if {$restart} {
            dofind
     if {![info exists findcurline]} {
        if {$restart} {
            dofind
@@ -3997,7 +4192,10 @@ proc findnext {restart} {
 }
 
 proc findprev {} {
 }
 
 proc findprev {} {
-    global findcurline
+    global findcurline find_dirn
+
+    if {[info exists find_dirn]} return
+    set find_dirn -1
     if {![info exists findcurline]} {
        dofind 1
     } else {
     if {![info exists findcurline]} {
        dofind 1
     } else {
@@ -4007,8 +4205,9 @@ proc findprev {} {
 }
 
 proc findmore {} {
 }
 
 proc findmore {} {
-    global commitdata commitinfo numcommits findstring findpattern findloc
-    global findstartline findcurline markingmatches displayorder
+    global commitdata commitinfo numcommits findpattern findloc
+    global findstartline findcurline displayorder
+    global find_dirn gdttype fhighlights
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l [expr {$findcurline + 1}]
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l [expr {$findcurline + 1}]
@@ -4023,27 +4222,56 @@ proc findmore {} {
     if {$lim - $l > 500} {
        set lim [expr {$l + 500}]
     }
     if {$lim - $l > 500} {
        set lim [expr {$l + 500}]
     }
-    set last 0
-    for {} {$l < $lim} {incr l} {
-       set id [lindex $displayorder $l]
-       if {![doesmatch $commitdata($id)]} continue
-       if {![info exists commitinfo($id)]} {
-           getcommit $id
+    set found 0
+    set domore 1
+    if {$gdttype eq "containing:"} {
+       for {} {$l < $lim} {incr l} {
+           set id [lindex $displayorder $l]
+           # shouldn't happen unless git log doesn't give all the commits...
+           if {![info exists commitdata($id)]} continue
+           if {![doesmatch $commitdata($id)]} continue
+           if {![info exists commitinfo($id)]} {
+               getcommit $id
+           }
+           set info $commitinfo($id)
+           foreach f $info ty $fldtypes {
+               if {($findloc eq "All fields" || $findloc eq $ty) &&
+                   [doesmatch $f]} {
+                   set found 1
+                   break
+               }
+           }
+           if {$found} break
        }
        }
-       set info $commitinfo($id)
-       foreach f $info ty $fldtypes {
-           if {($findloc eq "All fields" || $findloc eq $ty) &&
-               [doesmatch $f]} {
-               set markingmatches 1
-               findselectline $l
-               notbusy finding
-               return 0
+    } else {
+       for {} {$l < $lim} {incr l} {
+           set id [lindex $displayorder $l]
+           if {![info exists fhighlights($l)]} {
+               askfilehighlight $l $id
+               if {$domore} {
+                   set domore 0
+                   set findcurline [expr {$l - 1}]
+               }
+           } elseif {$fhighlights($l)} {
+               set found $domore
+               break
            }
        }
     }
            }
        }
     }
+    if {$found} {
+       unset find_dirn
+       findselectline $l
+       notbusy finding
+       return 0
+    }
+    if {!$domore} {
+       flushhighlights
+       return 0
+    }
     if {$l == $findstartline + 1} {
        bell
        unset findcurline
     if {$l == $findstartline + 1} {
        bell
        unset findcurline
+       unset find_dirn
        notbusy finding
        return 0
     }
        notbusy finding
        return 0
     }
@@ -4052,8 +4280,9 @@ proc findmore {} {
 }
 
 proc findmorerev {} {
 }
 
 proc findmorerev {} {
-    global commitdata commitinfo numcommits findstring findpattern findloc
-    global findstartline findcurline markingmatches displayorder
+    global commitdata commitinfo numcommits findpattern findloc
+    global findstartline findcurline displayorder
+    global find_dirn gdttype fhighlights
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l $findcurline
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l $findcurline
@@ -4069,27 +4298,55 @@ proc findmorerev {} {
     if {$l - $lim > 500} {
        set lim [expr {$l - 500}]
     }
     if {$l - $lim > 500} {
        set lim [expr {$l - 500}]
     }
-    set last 0
-    for {} {$l > $lim} {incr l -1} {
-       set id [lindex $displayorder $l]
-       if {![doesmatch $commitdata($id)]} continue
-       if {![info exists commitinfo($id)]} {
-           getcommit $id
+    set found 0
+    set domore 1
+    if {$gdttype eq "containing:"} {
+       for {} {$l > $lim} {incr l -1} {
+           set id [lindex $displayorder $l]
+           if {![info exists commitdata($id)]} continue
+           if {![doesmatch $commitdata($id)]} continue
+           if {![info exists commitinfo($id)]} {
+               getcommit $id
+           }
+           set info $commitinfo($id)
+           foreach f $info ty $fldtypes {
+               if {($findloc eq "All fields" || $findloc eq $ty) &&
+                   [doesmatch $f]} {
+                   set found 1
+                   break
+               }
+           }
+           if {$found} break
        }
        }
-       set info $commitinfo($id)
-       foreach f $info ty $fldtypes {
-           if {($findloc eq "All fields" || $findloc eq $ty) &&
-               [doesmatch $f]} {
-               set markingmatches 1
-               findselectline $l
-               notbusy finding
-               return 0
+    } else {
+       for {} {$l > $lim} {incr l -1} {
+           set id [lindex $displayorder $l]
+           if {![info exists fhighlights($l)]} {
+               askfilehighlight $l $id
+               if {$domore} {
+                   set domore 0
+                   set findcurline [expr {$l + 1}]
+               }
+           } elseif {$fhighlights($l)} {
+               set found $domore
+               break
            }
        }
     }
            }
        }
     }
+    if {$found} {
+       unset find_dirn
+       findselectline $l
+       notbusy finding
+       return 0
+    }
+    if {!$domore} {
+       flushhighlights
+       return 0
+    }
     if {$l == -1} {
        bell
        unset findcurline
     if {$l == -1} {
        bell
        unset findcurline
+       unset find_dirn
        notbusy finding
        return 0
     }
        notbusy finding
        return 0
     }
@@ -4098,7 +4355,10 @@ proc findmorerev {} {
 }
 
 proc findselectline {l} {
 }
 
 proc findselectline {l} {
-    global findloc commentend ctext
+    global findloc commentend ctext findcurline markingmatches gdttype
+
+    set markingmatches 1
+    set findcurline $l
     selectline $l 1
     if {$findloc == "All fields" || $findloc == "Comments"} {
        # highlight the matches in the comments
     selectline $l 1
     if {$findloc == "All fields" || $findloc == "Comments"} {
        # highlight the matches in the comments
@@ -4110,10 +4370,13 @@ proc findselectline {l} {
            $ctext tag add found "1.0 + $start c" "1.0 + $end c"
        }
     }
            $ctext tag add found "1.0 + $start c" "1.0 + $end c"
        }
     }
+    drawvisible
 }
 
 # mark the bits of a headline or author that match a find string
 }
 
 # mark the bits of a headline or author that match a find string
-proc markmatches {canv l str tag matches font} {
+proc markmatches {canv l str tag matches font row} {
+    global selectedline
+
     set bbox [$canv bbox $tag]
     set x0 [lindex $bbox 0]
     set y0 [lindex $bbox 1]
     set bbox [$canv bbox $tag]
     set x0 [lindex $bbox 0]
     set y0 [lindex $bbox 1]
@@ -4128,6 +4391,9 @@ proc markmatches {canv l str tag matches font} {
                   [expr {$x0+$xlen+2}] $y1 \
                   -outline {} -tags [list match$l matches] -fill yellow]
        $canv lower $t
                   [expr {$x0+$xlen+2}] $y1 \
                   -outline {} -tags [list match$l matches] -fill yellow]
        $canv lower $t
+       if {[info exists selectedline] && $row == $selectedline} {
+           $canv raise $t secsel
+       }
     }
 }
 
     }
 }
 
@@ -4173,7 +4439,7 @@ proc commit_descriptor {p} {
 # append some text to the ctext widget, and make any SHA1 ID
 # that we know about be a clickable link.
 proc appendwithlinks {text tags} {
 # append some text to the ctext widget, and make any SHA1 ID
 # that we know about be a clickable link.
 proc appendwithlinks {text tags} {
-    global ctext commitrow linknum curview
+    global ctext commitrow linknum curview pendinglinks
 
     set start [$ctext index "end - 1c"]
     $ctext insert end $text $tags
 
     set start [$ctext index "end - 1c"]
     $ctext insert end $text $tags
@@ -4182,17 +4448,49 @@ proc appendwithlinks {text tags} {
        set s [lindex $l 0]
        set e [lindex $l 1]
        set linkid [string range $text $s $e]
        set s [lindex $l 0]
        set e [lindex $l 1]
        set linkid [string range $text $s $e]
-       if {![info exists commitrow($curview,$linkid)]} continue
        incr e
        incr e
-       $ctext tag add link "$start + $s c" "$start + $e c"
+       $ctext tag delete link$linknum
        $ctext tag add link$linknum "$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 $commitrow($curview,$linkid) 1]
+       setlink $linkid link$linknum
        incr linknum
     }
        incr linknum
     }
-    $ctext tag conf link -foreground blue -underline 1
-    $ctext tag bind link <Enter> { %W configure -cursor hand2 }
-    $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
+}
+
+proc setlink {id lk} {
+    global curview commitrow ctext pendinglinks commitinterest
+
+    if {[info exists commitrow($curview,$id)]} {
+       $ctext tag conf $lk -foreground blue -underline 1
+       $ctext tag bind $lk <1> [list selectline $commitrow($curview,$id) 1]
+       $ctext tag bind $lk <Enter> {linkcursor %W 1}
+       $ctext tag bind $lk <Leave> {linkcursor %W -1}
+    } else {
+       lappend pendinglinks($id) $lk
+       lappend commitinterest($id) {makelink %I}
+    }
+}
+
+proc makelink {id} {
+    global pendinglinks
+
+    if {![info exists pendinglinks($id)]} return
+    foreach lk $pendinglinks($id) {
+       setlink $id $lk
+    }
+    unset pendinglinks($id)
+}
+
+proc linkcursor {w inc} {
+    global linkentercount curtextcursor
+
+    if {[incr linkentercount $inc] > 0} {
+       $w configure -cursor hand2
+    } else {
+       $w configure -cursor $curtextcursor
+       if {$linkentercount < 0} {
+           set linkentercount 0
+       }
+    }
 }
 
 proc viewnextline {dir} {
 }
 
 proc viewnextline {dir} {
@@ -4239,15 +4537,7 @@ proc appendrefs {pos ids var} {
            $ctext tag delete $lk
            $ctext insert $pos $sep
            $ctext insert $pos [lindex $ti 0] $lk
            $ctext tag delete $lk
            $ctext insert $pos $sep
            $ctext insert $pos [lindex $ti 0] $lk
-           if {[info exists commitrow($curview,$id)]} {
-               $ctext tag conf $lk -foreground blue
-               $ctext tag bind $lk <1> \
-                   [list selectline $commitrow($curview,$id) 1]
-               $ctext tag conf $lk -underline 1
-               $ctext tag bind $lk <Enter> { %W configure -cursor hand2 }
-               $ctext tag bind $lk <Leave> \
-                   { %W configure -cursor $curtextcursor }
-           }
+           setlink $id $lk
            set sep ", "
        }
     }
            set sep ", "
        }
     }
@@ -4305,9 +4595,27 @@ proc dispnexttag {} {
     }
 }
 
     }
 }
 
+proc make_secsel {l} {
+    global linehtag linentag linedtag canv canv2 canv3
+
+    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
+}
+
 proc selectline {l isnew} {
 proc selectline {l isnew} {
-    global canv canv2 canv3 ctext commitinfo selectedline
-    global displayorder linehtag linentag linedtag
+    global canv ctext commitinfo selectedline
+    global displayorder
     global canvy0 linespc parentlist children curview
     global currentid sha1entry
     global commentend idtags linknum
     global canvy0 linespc parentlist children curview
     global currentid sha1entry
     global commentend idtags linknum
@@ -4317,7 +4625,7 @@ proc selectline {l isnew} {
     catch {unset pending_select}
     $canv delete hover
     normalline
     catch {unset pending_select}
     $canv delete hover
     normalline
-    cancel_next_highlight
+    unsel_reflist
     if {$l < 0 || $l >= $numcommits} return
     set y [expr {$canvy0 + $l * $linespc}]
     set ymax [lindex [$canv cget -scrollregion] 3]
     if {$l < 0 || $l >= $numcommits} return
     set y [expr {$canvy0 + $l * $linespc}]
     set ymax [lindex [$canv cget -scrollregion] 3]
@@ -4355,19 +4663,7 @@ proc selectline {l isnew} {
        drawvisible
     }
 
        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
+    make_secsel $l
 
     if {$isnew} {
        addtohistory [list selectline $l 0]
 
     if {$isnew} {
        addtohistory [list selectline $l 0]
@@ -4476,6 +4772,7 @@ proc sellastline {} {
 
 proc selnextline {dir} {
     global selectedline
 
 proc selnextline {dir} {
     global selectedline
+    focus .
     if {![info exists selectedline]} return
     set l [expr {$selectedline + $dir}]
     unmarkmatches
     if {![info exists selectedline]} return
     set l [expr {$selectedline + $dir}]
     unmarkmatches
@@ -4509,7 +4806,6 @@ proc unselectline {} {
     catch {unset currentid}
     allcanvs delete secsel
     rhighlight_none
     catch {unset currentid}
     allcanvs delete secsel
     rhighlight_none
-    cancel_next_highlight
 }
 
 proc reselectline {} {
 }
 
 proc reselectline {} {
@@ -4556,6 +4852,7 @@ proc godo {elt} {
 
 proc goback {} {
     global history historyindex
 
 proc goback {} {
     global history historyindex
+    focus .
 
     if {$historyindex > 1} {
        incr historyindex -1
 
     if {$historyindex > 1} {
        incr historyindex -1
@@ -4569,6 +4866,7 @@ proc goback {} {
 
 proc goforw {} {
     global history historyindex
 
 proc goforw {} {
     global history historyindex
+    focus .
 
     if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
 
     if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
@@ -4582,16 +4880,19 @@ proc goforw {} {
 }
 
 proc gettree {id} {
 }
 
 proc gettree {id} {
-    global treefilelist treeidlist diffids diffmergeid treepending nullid
+    global treefilelist treeidlist diffids diffmergeid treepending
+    global nullid nullid2
 
     set diffids $id
     catch {unset diffmergeid}
     if {![info exists treefilelist($id)]} {
        if {![info exists treepending]} {
 
     set diffids $id
     catch {unset diffmergeid}
     if {![info exists treefilelist($id)]} {
        if {![info exists treepending]} {
-           if {$id ne $nullid} {
-               set cmd [concat | git ls-tree -r $id]
+           if {$id eq $nullid} {
+               set cmd [list | git ls-files]
+           } elseif {$id eq $nullid2} {
+               set cmd [list | git ls-files --stage -t]
            } else {
            } else {
-               set cmd [concat | git ls-files]
+               set cmd [list | git ls-tree -r $id]
            }
            if {[catch {set gtf [open $cmd r]}]} {
                return
            }
            if {[catch {set gtf [open $cmd r]}]} {
                return
@@ -4608,12 +4909,14 @@ proc gettree {id} {
 }
 
 proc gettreeline {gtf id} {
 }
 
 proc gettreeline {gtf id} {
-    global treefilelist treeidlist treepending cmitmode diffids nullid
+    global treefilelist treeidlist treepending cmitmode diffids nullid nullid2
 
     set nl 0
     while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
 
     set nl 0
     while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
-       if {$diffids ne $nullid} {
-           if {[lindex $line 1] ne "blob"} continue
+       if {$diffids eq $nullid} {
+           set fname $line
+       } else {
+           if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
            set i [string first "\t" $line]
            if {$i < 0} continue
            set sha1 [lindex $line 2]
            set i [string first "\t" $line]
            if {$i < 0} continue
            set sha1 [lindex $line 2]
@@ -4622,8 +4925,6 @@ proc gettreeline {gtf id} {
                set fname [lindex $fname 0]
            }
            lappend treeidlist($id) $sha1
                set fname [lindex $fname 0]
            }
            lappend treeidlist($id) $sha1
-       } else {
-           set fname $line
        }
        lappend treefilelist($id) $fname
     }
        }
        lappend treefilelist($id) $fname
     }
@@ -4645,7 +4946,7 @@ proc gettreeline {gtf id} {
 }
 
 proc showfile {f} {
 }
 
 proc showfile {f} {
-    global treefilelist treeidlist diffids nullid
+    global treefilelist treeidlist diffids nullid nullid2
     global ctext commentend
 
     set i [lsearch -exact $treefilelist($diffids) $f]
     global ctext commentend
 
     set i [lsearch -exact $treefilelist($diffids) $f]
@@ -4653,15 +4954,15 @@ proc showfile {f} {
        puts "oops, $f not in list for id $diffids"
        return
     }
        puts "oops, $f not in list for id $diffids"
        return
     }
-    if {$diffids ne $nullid} {
-       set blob [lindex $treeidlist($diffids) $i]
-       if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
-           puts "oops, error reading blob $blob: $err"
+    if {$diffids eq $nullid} {
+       if {[catch {set bf [open $f r]} err]} {
+           puts "oops, can't read $f: $err"
            return
        }
     } else {
            return
        }
     } else {
-       if {[catch {set bf [open $f r]} err]} {
-           puts "oops, can't read $f: $err"
+       set blob [lindex $treeidlist($diffids) $i]
+       if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
+           puts "oops, error reading blob $blob: $err"
            return
        }
     }
            return
        }
     }
@@ -4789,11 +5090,13 @@ proc getmergediffline {mdf id np} {
 }
 
 proc startdiff {ids} {
 }
 
 proc startdiff {ids} {
-    global treediffs diffids treepending diffmergeid nullid
+    global treediffs diffids treepending diffmergeid nullid nullid2
 
     set diffids $ids
     catch {unset diffmergeid}
 
     set diffids $ids
     catch {unset diffmergeid}
-    if {![info exists treediffs($ids)] || [lsearch -exact $ids $nullid] >= 0} {
+    if {![info exists treediffs($ids)] ||
+       [lsearch -exact $ids $nullid] >= 0 ||
+       [lsearch -exact $ids $nullid2] >= 0} {
        if {![info exists treepending]} {
            gettreediffs $ids
        }
        if {![info exists treepending]} {
            gettreediffs $ids
        }
@@ -4809,22 +5112,41 @@ proc addtocflist {ids} {
 }
 
 proc diffcmd {ids flags} {
 }
 
 proc diffcmd {ids flags} {
-    global nullid
+    global nullid nullid2
 
     set i [lsearch -exact $ids $nullid]
 
     set i [lsearch -exact $ids $nullid]
+    set j [lsearch -exact $ids $nullid2]
     if {$i >= 0} {
     if {$i >= 0} {
-       set cmd [concat | git diff-index $flags]
+       if {[llength $ids] > 1 && $j < 0} {
+           # comparing working directory with some specific revision
+           set cmd [concat | git diff-index $flags]
+           if {$i == 0} {
+               lappend cmd -R [lindex $ids 1]
+           } else {
+               lappend cmd [lindex $ids 0]
+           }
+       } else {
+           # comparing working directory with index
+           set cmd [concat | git diff-files $flags]
+           if {$j == 1} {
+               lappend cmd -R
+           }
+       }
+    } elseif {$j >= 0} {
+       set cmd [concat | git diff-index --cached $flags]
        if {[llength $ids] > 1} {
        if {[llength $ids] > 1} {
+           # comparing index with specific revision
            if {$i == 0} {
                lappend cmd -R [lindex $ids 1]
            } else {
                lappend cmd [lindex $ids 0]
            }
        } else {
            if {$i == 0} {
                lappend cmd -R [lindex $ids 1]
            } else {
                lappend cmd [lindex $ids 0]
            }
        } else {
+           # comparing index with HEAD
            lappend cmd HEAD
        }
     } else {
            lappend cmd HEAD
        }
     } else {
-       set cmd [concat | git diff-tree --no-commit-id -r $flags $ids]
+       set cmd [concat | git diff-tree -r $flags $ids]
     }
     return $cmd
 }
     }
     return $cmd
 }
@@ -4834,7 +5156,7 @@ proc gettreediffs {ids} {
 
     set treepending $ids
     set treediff {}
 
     set treepending $ids
     set treediff {}
-    if {[catch {set gdtf [open [diffcmd $ids {}] r]}]} return
+    if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
     fconfigure $gdtf -blocking 0
     filerun $gdtf [list gettreediffline $gdtf $ids]
 }
     fconfigure $gdtf -blocking 0
     filerun $gdtf [list gettreediffline $gdtf $ids]
 }
@@ -4872,12 +5194,29 @@ proc gettreediffline {gdtf ids} {
     return 0
 }
 
     return 0
 }
 
+# empty string or positive integer
+proc diffcontextvalidate {v} {
+    return [regexp {^(|[1-9][0-9]*)$} $v]
+}
+
+proc diffcontextchange {n1 n2 op} {
+    global diffcontextstring diffcontext
+
+    if {[string is integer -strict $diffcontextstring]} {
+       if {$diffcontextstring > 0} {
+           set diffcontext $diffcontextstring
+           reselectline
+       }
+    }
+}
+
 proc getblobdiffs {ids} {
     global diffopts blobdifffd diffids env
     global diffinhdr treediffs
 proc getblobdiffs {ids} {
     global diffopts blobdifffd diffids env
     global diffinhdr treediffs
+    global diffcontext
 
     set env(GIT_DIFF_OPTS) $diffopts
 
     set env(GIT_DIFF_OPTS) $diffopts
-    if {[catch {set bdf [open [diffcmd $ids {-p -C}] r]} err]} {
+    if {[catch {set bdf [open [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"] r]} err]} {
        puts "error getting diffs: $err"
        return
     }
        puts "error getting diffs: $err"
        return
     }
@@ -4936,8 +5275,8 @@ proc getblobdiffline {bdf ids} {
            # the middle char will be a space, and the two bits either
            # side will be a/name and b/name, or "a/name" and "b/name".
            # If the name has changed we'll get "rename from" and
            # the middle char will be a space, and the two bits either
            # side will be a/name and b/name, or "a/name" and "b/name".
            # If the name has changed we'll get "rename from" and
-           # "rename to" lines following this, and we'll use them
-           # to get the filenames.
+           # "rename to" or "copy from" and "copy to" lines following this,
+           # and we'll use them to get the filenames.
            # This complexity is necessary because spaces in the filename(s)
            # don't get escaped.
            set l [string length $line]
            # This complexity is necessary because spaces in the filename(s)
            # don't get escaped.
            set l [string length $line]
@@ -4961,8 +5300,9 @@ proc getblobdiffline {bdf ids} {
            set diffinhdr 0
 
        } elseif {$diffinhdr} {
            set diffinhdr 0
 
        } elseif {$diffinhdr} {
-           if {![string compare -length 12 "rename from " $line]} {
-               set fname [string range $line 12 end]
+           if {![string compare -length 12 "rename from " $line] ||
+               ![string compare -length 10 "copy from " $line]} {
+               set fname [string range $line [expr 6 + [string first " from " $line] ] end]
                if {[string index $fname 0] eq "\""} {
                    set fname [lindex $fname 0]
                }
                if {[string index $fname 0] eq "\""} {
                    set fname [lindex $fname 0]
                }
@@ -4970,8 +5310,9 @@ proc getblobdiffline {bdf ids} {
                if {$i >= 0} {
                    setinlist difffilestart $i $curdiffstart
                }
                if {$i >= 0} {
                    setinlist difffilestart $i $curdiffstart
                }
-           } elseif {![string compare -length 10 $line "rename to "]} {
-               set fname [string range $line 10 end]
+           } elseif {![string compare -length 10 $line "rename to "] ||
+                     ![string compare -length 8 $line "copy to "]} {
+               set fname [string range $line [expr 4 + [string first " to " $line] ] end]
                if {[string index $fname 0] eq "\""} {
                    set fname [lindex $fname 0]
                }
                if {[string index $fname 0] eq "\""} {
                    set fname [lindex $fname 0]
                }
@@ -5041,6 +5382,7 @@ proc nextfile {} {
 
 proc clear_ctext {{first 1.0}} {
     global ctext smarktop smarkbot
 
 proc clear_ctext {{first 1.0}} {
     global ctext smarktop smarkbot
+    global pendinglinks
 
     set l [lindex [split $first .] 0]
     if {![info exists smarktop] || [$ctext compare $first < $smarktop.0]} {
 
     set l [lindex [split $first .] 0]
     if {![info exists smarktop] || [$ctext compare $first < $smarktop.0]} {
@@ -5050,6 +5392,9 @@ proc clear_ctext {{first 1.0}} {
        set smarkbot $l
     }
     $ctext delete $first end
        set smarkbot $l
     }
     $ctext delete $first end
+    if {$first eq "1.0"} {
+       catch {unset pendinglinks}
+    }
 }
 
 proc incrsearch {name ix op} {
 }
 
 proc incrsearch {name ix op} {
@@ -5202,7 +5547,7 @@ proc redisplay {} {
 }
 
 proc incrfont {inc} {
 }
 
 proc incrfont {inc} {
-    global mainfont textfont ctext canv phase cflist
+    global mainfont textfont ctext canv phase cflist showrefstop
     global charspc tabstop
     global stopped entries
     unmarkmatches
     global charspc tabstop
     global stopped entries
     unmarkmatches
@@ -5218,6 +5563,9 @@ proc incrfont {inc} {
     if {$phase eq "getcommits"} {
        $canv itemconf textitems -font $mainfont
     }
     if {$phase eq "getcommits"} {
        $canv itemconf textitems -font $mainfont
     }
+    if {[info exists showrefstop] && [winfo exists $showrefstop]} {
+       $showrefstop.list conf -font $mainfont
+    }
     redisplay
 }
 
     redisplay
 }
 
@@ -5382,7 +5730,7 @@ proc arrowjump {id n y} {
 }
 
 proc lineclick {x y id isnew} {
 }
 
 proc lineclick {x y id isnew} {
-    global ctext commitinfo children canv thickerline curview
+    global ctext commitinfo children canv thickerline curview commitrow
 
     if {![info exists commitinfo($id)] && ![getcommit $id]} return
     unmarkmatches
 
     if {![info exists commitinfo($id)] && ![getcommit $id]} return
     unmarkmatches
@@ -5410,12 +5758,9 @@ proc lineclick {x y id isnew} {
     # fill the details pane with info about this line
     $ctext conf -state normal
     clear_ctext
     # fill the details pane with info about this line
     $ctext conf -state normal
     clear_ctext
-    $ctext tag conf link -foreground blue -underline 1
-    $ctext tag bind link <Enter> { %W configure -cursor hand2 }
-    $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
     $ctext insert end "Parent:\t"
     $ctext insert end "Parent:\t"
-    $ctext insert end $id [list link link0]
-    $ctext tag bind link0 <1> [list selbyid $id]
+    $ctext insert end $id link0
+    setlink $id link0
     set info $commitinfo($id)
     $ctext insert end "\n\t[lindex $info 0]\n"
     $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
     set info $commitinfo($id)
     $ctext insert end "\n\t[lindex $info 0]\n"
     $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
@@ -5430,8 +5775,8 @@ proc lineclick {x y id isnew} {
            if {![info exists commitinfo($child)] && ![getcommit $child]} continue
            set info $commitinfo($child)
            $ctext insert end "\n\t"
            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]
-           $ctext tag bind link$i <1> [list selbyid $child]
+           $ctext insert end $child link$i
+           setlink $child link$i
            $ctext insert end "\n\t[lindex $info 0]"
            $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
            set date [formatdate [lindex $info 2]]
            $ctext insert end "\n\t[lindex $info 0]"
            $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
            set date [formatdate [lindex $info 2]]
@@ -5468,7 +5813,7 @@ proc mstime {} {
 
 proc rowmenu {x y id} {
     global rowctxmenu commitrow selectedline rowmenuid curview
 
 proc rowmenu {x y id} {
     global rowctxmenu commitrow selectedline rowmenuid curview
-    global nullid fakerowmenu mainhead
+    global nullid nullid2 fakerowmenu mainhead
 
     set rowmenuid $id
     if {![info exists selectedline]
 
     set rowmenuid $id
     if {![info exists selectedline]
@@ -5477,7 +5822,7 @@ proc rowmenu {x y id} {
     } else {
        set state normal
     }
     } else {
        set state normal
     }
-    if {$id ne $nullid} {
+    if {$id ne $nullid && $id ne $nullid2} {
        set menu $rowctxmenu
        $menu entryconfigure 7 -label "Reset $mainhead branch to here"
     } else {
        set menu $rowctxmenu
        $menu entryconfigure 7 -label "Reset $mainhead branch to here"
     } else {
@@ -5512,16 +5857,13 @@ proc doseldiff {oldid newid} {
     clear_ctext
     init_flist "Top"
     $ctext insert end "From "
     clear_ctext
     init_flist "Top"
     $ctext insert end "From "
-    $ctext tag conf link -foreground blue -underline 1
-    $ctext tag bind link <Enter> { %W configure -cursor hand2 }
-    $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
-    $ctext tag bind link0 <1> [list selbyid $oldid]
-    $ctext insert end $oldid [list link link0]
+    $ctext insert end $oldid link0
+    setlink $oldid link0
     $ctext insert end "\n     "
     $ctext insert end [lindex $commitinfo($oldid) 0]
     $ctext insert end "\n\nTo   "
     $ctext insert end "\n     "
     $ctext insert end [lindex $commitinfo($oldid) 0]
     $ctext insert end "\n\nTo   "
-    $ctext tag bind link1 <1> [list selbyid $newid]
-    $ctext insert end $newid [list link link1]
+    $ctext insert end $newid link1
+    setlink $newid link1
     $ctext insert end "\n     "
     $ctext insert end [lindex $commitinfo($newid) 0]
     $ctext insert end "\n"
     $ctext insert end "\n     "
     $ctext insert end [lindex $commitinfo($newid) 0]
     $ctext insert end "\n"
@@ -5596,18 +5938,14 @@ proc mkpatchrev {} {
 }
 
 proc mkpatchgo {} {
 }
 
 proc mkpatchgo {} {
-    global patchtop nullid
+    global patchtop nullid nullid2
 
     set oldid [$patchtop.fromsha1 get]
     set newid [$patchtop.tosha1 get]
     set fname [$patchtop.fname get]
 
     set oldid [$patchtop.fromsha1 get]
     set newid [$patchtop.tosha1 get]
     set fname [$patchtop.fname get]
-    if {$newid eq $nullid} {
-       set cmd [list git diff-index -p $oldid]
-    } elseif {$oldid eq $nullid} {
-       set cmd [list git diff-index -p -R $newid]
-    } else {
-       set cmd [list git diff-tree -p $oldid $newid]
-    }
+    set cmd [diffcmd [list $oldid $newid] -p]
+    # trim off the initial "|"
+    set cmd [lrange $cmd 1 end]
     lappend cmd >$fname &
     if {[catch {eval exec $cmd} err]} {
        error_popup "Error creating patch: $err"
     lappend cmd >$fname &
     if {[catch {eval exec $cmd} err]} {
        error_popup "Error creating patch: $err"
@@ -5682,6 +6020,8 @@ proc domktag {} {
     lappend idtags($id) $tag
     redrawtags $id
     addedtag $id
     lappend idtags($id) $tag
     redrawtags $id
     addedtag $id
+    dispneartags 0
+    run refill_reflist
 }
 
 proc redrawtags {id} {
 }
 
 proc redrawtags {id} {
@@ -5823,6 +6163,7 @@ proc mkbrgo {top} {
        notbusy newbranch
        redrawtags $id
        dispneartags 0
        notbusy newbranch
        redrawtags $id
        dispneartags 0
+       run refill_reflist
     }
 }
 
     }
 }
 
@@ -5867,7 +6208,6 @@ proc cherrypick {} {
 
 proc resethead {} {
     global mainheadid mainhead rowmenuid confirm_ok resettype
 
 proc resethead {} {
     global mainheadid mainhead rowmenuid confirm_ok resettype
-    global showlocalchanges
 
     set confirm_ok 0
     set w ".confirmreset"
 
     set confirm_ok 0
     set w ".confirmreset"
@@ -5994,7 +6334,7 @@ proc cobranch {} {
 
 proc rmbranch {} {
     global headmenuid headmenuhead mainhead
 
 proc rmbranch {} {
     global headmenuid headmenuhead mainhead
-    global headids idheads
+    global idheads
 
     set head $headmenuhead
     set id $headmenuid
 
     set head $headmenuhead
     set id $headmenuid
@@ -6004,7 +6344,7 @@ proc rmbranch {} {
        return
     }
     set dheads [descheads $id]
        return
     }
     set dheads [descheads $id]
-    if {$dheads eq $headids($head)} {
+    if {[llength $dheads] == 1 && $idheads($dheads) eq $head} {
        # the stuff on this branch isn't on any other branch
        if {![confirm_popup "The commits on branch $head aren't on any other\
                        branch.\nReally delete branch $head?"]} return
        # the stuff on this branch isn't on any other branch
        if {![confirm_popup "The commits on branch $head aren't on any other\
                        branch.\nReally delete branch $head?"]} return
@@ -6021,33 +6361,220 @@ proc rmbranch {} {
     redrawtags $id
     notbusy rmbranch
     dispneartags 0
     redrawtags $id
     notbusy rmbranch
     dispneartags 0
+    run refill_reflist
 }
 
 }
 
-# Stuff for finding nearby tags
-proc getallcommits {} {
-    global allcommits allids nbmp nextarc seeds
+# Display a list of tags and heads
+proc showrefs {} {
+    global showrefstop bgcolor fgcolor selectbgcolor mainfont
+    global bglist fglist uifont reflistfilter reflist maincursor
 
 
-    set allids {}
-    set nbmp 0
-    set nextarc 0
-    set allcommits 0
-    set seeds {}
-    regetallcommits
+    set top .showrefs
+    set showrefstop $top
+    if {[winfo exists $top]} {
+       raise $top
+       refill_reflist
+       return
+    }
+    toplevel $top
+    wm title $top "Tags and heads: [file tail [pwd]]"
+    text $top.list -background $bgcolor -foreground $fgcolor \
+       -selectbackground $selectbgcolor -font $mainfont \
+       -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
+       -width 30 -height 20 -cursor $maincursor \
+       -spacing1 1 -spacing3 1 -state disabled
+    $top.list tag configure highlight -background $selectbgcolor
+    lappend bglist $top.list
+    lappend fglist $top.list
+    scrollbar $top.ysb -command "$top.list yview" -orient vertical
+    scrollbar $top.xsb -command "$top.list xview" -orient horizontal
+    grid $top.list $top.ysb -sticky nsew
+    grid $top.xsb x -sticky ew
+    frame $top.f
+    label $top.f.l -text "Filter: " -font $uifont
+    entry $top.f.e -width 20 -textvariable reflistfilter -font $uifont
+    set reflistfilter "*"
+    trace add variable reflistfilter write reflistfilter_change
+    pack $top.f.e -side right -fill x -expand 1
+    pack $top.f.l -side left
+    grid $top.f - -sticky ew -pady 2
+    button $top.close -command [list destroy $top] -text "Close" \
+       -font $uifont
+    grid $top.close -
+    grid columnconfigure $top 0 -weight 1
+    grid rowconfigure $top 0 -weight 1
+    bind $top.list <1> {break}
+    bind $top.list <B1-Motion> {break}
+    bind $top.list <ButtonRelease-1> {sel_reflist %W %x %y; break}
+    set reflist {}
+    refill_reflist
 }
 
 }
 
-# Called when the graph might have changed
-proc regetallcommits {} {
-    global allcommits seeds
+proc sel_reflist {w x y} {
+    global showrefstop reflist headids tagids otherrefids
 
 
-    set cmd [concat | git rev-list --all --parents]
-    foreach id $seeds {
-       lappend cmd "^$id"
+    if {![winfo exists $showrefstop]} return
+    set l [lindex [split [$w index "@$x,$y"] "."] 0]
+    set ref [lindex $reflist [expr {$l-1}]]
+    set n [lindex $ref 0]
+    switch -- [lindex $ref 1] {
+       "H" {selbyid $headids($n)}
+       "T" {selbyid $tagids($n)}
+       "o" {selbyid $otherrefids($n)}
+    }
+    $showrefstop.list tag add highlight $l.0 "$l.0 lineend"
+}
+
+proc unsel_reflist {} {
+    global showrefstop
+
+    if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
+    $showrefstop.list tag remove highlight 0.0 end
+}
+
+proc reflistfilter_change {n1 n2 op} {
+    global reflistfilter
+
+    after cancel refill_reflist
+    after 200 refill_reflist
+}
+
+proc refill_reflist {} {
+    global reflist reflistfilter showrefstop headids tagids otherrefids
+    global commitrow curview commitinterest
+
+    if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
+    set refs {}
+    foreach n [array names headids] {
+       if {[string match $reflistfilter $n]} {
+           if {[info exists commitrow($curview,$headids($n))]} {
+               lappend refs [list $n H]
+           } else {
+               set commitinterest($headids($n)) {run refill_reflist}
+           }
+       }
+    }
+    foreach n [array names tagids] {
+       if {[string match $reflistfilter $n]} {
+           if {[info exists commitrow($curview,$tagids($n))]} {
+               lappend refs [list $n T]
+           } else {
+               set commitinterest($tagids($n)) {run refill_reflist}
+           }
+       }
+    }
+    foreach n [array names otherrefids] {
+       if {[string match $reflistfilter $n]} {
+           if {[info exists commitrow($curview,$otherrefids($n))]} {
+               lappend refs [list $n o]
+           } else {
+               set commitinterest($otherrefids($n)) {run refill_reflist}
+           }
+       }
+    }
+    set refs [lsort -index 0 $refs]
+    if {$refs eq $reflist} return
+
+    # Update the contents of $showrefstop.list according to the
+    # differences between $reflist (old) and $refs (new)
+    $showrefstop.list conf -state normal
+    $showrefstop.list insert end "\n"
+    set i 0
+    set j 0
+    while {$i < [llength $reflist] || $j < [llength $refs]} {
+       if {$i < [llength $reflist]} {
+           if {$j < [llength $refs]} {
+               set cmp [string compare [lindex $reflist $i 0] \
+                            [lindex $refs $j 0]]
+               if {$cmp == 0} {
+                   set cmp [string compare [lindex $reflist $i 1] \
+                                [lindex $refs $j 1]]
+               }
+           } else {
+               set cmp -1
+           }
+       } else {
+           set cmp 1
+       }
+       switch -- $cmp {
+           -1 {
+               $showrefstop.list delete "[expr {$j+1}].0" "[expr {$j+2}].0"
+               incr i
+           }
+           0 {
+               incr i
+               incr j
+           }
+           1 {
+               set l [expr {$j + 1}]
+               $showrefstop.list image create $l.0 -align baseline \
+                   -image reficon-[lindex $refs $j 1] -padx 2
+               $showrefstop.list insert $l.1 "[lindex $refs $j 0]\n"
+               incr j
+           }
+       }
+    }
+    set reflist $refs
+    # delete last newline
+    $showrefstop.list delete end-2c end-1c
+    $showrefstop.list conf -state disabled
+}
+
+# Stuff for finding nearby tags
+proc getallcommits {} {
+    global allcommits nextarc seeds allccache allcwait cachedarcs allcupdate
+    global idheads idtags idotherrefs allparents tagobjid
+
+    if {![info exists allcommits]} {
+       set nextarc 0
+       set allcommits 0
+       set seeds {}
+       set allcwait 0
+       set cachedarcs 0
+       set allccache [file join [gitdir] "gitk.cache"]
+       if {![catch {
+           set f [open $allccache r]
+           set allcwait 1
+           getcache $f
+       }]} return
+    }
+
+    if {$allcwait} {
+       return
+    }
+    set cmd [list | git rev-list --parents]
+    set allcupdate [expr {$seeds ne {}}]
+    if {!$allcupdate} {
+       set ids "--all"
+    } else {
+       set refs [concat [array names idheads] [array names idtags] \
+                     [array names idotherrefs]]
+       set ids {}
+       set tagobjs {}
+       foreach name [array names tagobjid] {
+           lappend tagobjs $tagobjid($name)
+       }
+       foreach id [lsort -unique $refs] {
+           if {![info exists allparents($id)] &&
+               [lsearch -exact $tagobjs $id] < 0} {
+               lappend ids $id
+           }
+       }
+       if {$ids ne {}} {
+           foreach id $seeds {
+               lappend ids "^$id"
+           }
+       }
+    }
+    if {$ids ne {}} {
+       set fd [open [concat $cmd $ids] r]
+       fconfigure $fd -blocking 0
+       incr allcommits
+       nowbusy allcommits
+       filerun $fd [list getallclines $fd]
+    } else {
+       dispneartags 0
     }
     }
-    set fd [open $cmd r]
-    fconfigure $fd -blocking 0
-    incr allcommits
-    nowbusy allcommits
-    filerun $fd [list getallclines $fd]
 }
 
 # Since most commits have 1 parent and 1 child, we group strings of
 }
 
 # Since most commits have 1 parent and 1 child, we group strings of
@@ -6066,10 +6593,10 @@ proc regetallcommits {} {
 # coming from descendents, and "outgoing" means going towards ancestors.
 
 proc getallclines {fd} {
 # coming from descendents, and "outgoing" means going towards ancestors.
 
 proc getallclines {fd} {
-    global allids allparents allchildren idtags idheads nextarc nbmp
+    global allparents allchildren idtags idheads nextarc
     global arcnos arcids arctags arcout arcend arcstart archeads growing
     global arcnos arcids arctags arcout arcend arcstart archeads growing
-    global seeds allcommits
-
+    global seeds allcommits cachedarcs allcupdate
+    
     set nid 0
     while {[incr nid] <= 1000 && [gets $fd line] >= 0} {
        set id [lindex $line 0]
     set nid 0
     while {[incr nid] <= 1000 && [gets $fd line] >= 0} {
        set id [lindex $line 0]
@@ -6077,7 +6604,7 @@ proc getallclines {fd} {
            # seen it already
            continue
        }
            # seen it already
            continue
        }
-       lappend allids $id
+       set cachedarcs 0
        set olds [lrange $line 1 end]
        set allparents($id) $olds
        if {![info exists allchildren($id)]} {
        set olds [lrange $line 1 end]
        set allparents($id) $olds
        if {![info exists allchildren($id)]} {
@@ -6108,7 +6635,6 @@ proc getallclines {fd} {
                continue
            }
        }
                continue
            }
        }
-       incr nbmp
        foreach a $arcnos($id) {
            lappend arcids($a) $id
            set arcend($a) $id
        foreach a $arcnos($id) {
            lappend arcids($a) $id
            set arcend($a) $id
@@ -6148,9 +6674,28 @@ proc getallclines {fd} {
     if {![eof $fd]} {
        return [expr {$nid >= 1000? 2: 1}]
     }
     if {![eof $fd]} {
        return [expr {$nid >= 1000? 2: 1}]
     }
-    close $fd
+    set cacheok 1
+    if {[catch {
+       fconfigure $fd -blocking 1
+       close $fd
+    } err]} {
+       # got an error reading the list of commits
+       # if we were updating, try rereading the whole thing again
+       if {$allcupdate} {
+           incr allcommits -1
+           dropcache $err
+           return
+       }
+       error_popup "Error reading commit topology information;\
+               branch and preceding/following tag information\
+               will be incomplete.\n($err)"
+       set cacheok 0
+    }
     if {[incr allcommits -1] == 0} {
        notbusy allcommits
     if {[incr allcommits -1] == 0} {
        notbusy allcommits
+       if {$cacheok} {
+           run savecache
+       }
     }
     dispneartags 0
     return 0
     }
     dispneartags 0
     return 0
@@ -6174,7 +6719,7 @@ proc recalcarc {a} {
 }
 
 proc splitarc {p} {
 }
 
 proc splitarc {p} {
-    global arcnos arcids nextarc nbmp arctags archeads idtags idheads
+    global arcnos arcids nextarc arctags archeads idtags idheads
     global arcstart arcend arcout allparents growing
 
     set a $arcnos($p)
     global arcstart arcend arcout allparents growing
 
     set a $arcnos($p)
@@ -6206,7 +6751,6 @@ proc splitarc {p} {
        set growing($na) 1
        unset growing($a)
     }
        set growing($na) 1
        unset growing($a)
     }
-    incr nbmp
 
     foreach id $tail {
        if {[llength $arcnos($id)] == 1} {
 
     foreach id $tail {
        if {[llength $arcnos($id)] == 1} {
@@ -6230,16 +6774,15 @@ proc splitarc {p} {
 # Update things for a new commit added that is a child of one
 # existing commit.  Used when cherry-picking.
 proc addnewchild {id p} {
 # Update things for a new commit added that is a child of one
 # existing commit.  Used when cherry-picking.
 proc addnewchild {id p} {
-    global allids allparents allchildren idtags nextarc nbmp
+    global allparents allchildren idtags nextarc
     global arcnos arcids arctags arcout arcend arcstart archeads growing
     global arcnos arcids arctags arcout arcend arcstart archeads growing
-    global seeds
+    global seeds allcommits
 
 
-    lappend allids $id
+    if {![info exists allcommits]} return
     set allparents($id) [list $p]
     set allchildren($id) {}
     set arcnos($id) {}
     lappend seeds $id
     set allparents($id) [list $p]
     set allchildren($id) {}
     set arcnos($id) {}
     lappend seeds $id
-    incr nbmp
     lappend allchildren($p) $id
     set a [incr nextarc]
     set arcstart($a) $id
     lappend allchildren($p) $id
     set a [incr nextarc]
     set arcstart($a) $id
@@ -6254,6 +6797,172 @@ proc addnewchild {id p} {
     set arcout($id) [list $a]
 }
 
     set arcout($id) [list $a]
 }
 
+# This implements a cache for the topology information.
+# The cache saves, for each arc, the start and end of the arc,
+# the ids on the arc, and the outgoing arcs from the end.
+proc readcache {f} {
+    global arcnos arcids arcout arcstart arcend arctags archeads nextarc
+    global idtags idheads allparents cachedarcs possible_seeds seeds growing
+    global allcwait
+
+    set a $nextarc
+    set lim $cachedarcs
+    if {$lim - $a > 500} {
+       set lim [expr {$a + 500}]
+    }
+    if {[catch {
+       if {$a == $lim} {
+           # finish reading the cache and setting up arctags, etc.
+           set line [gets $f]
+           if {$line ne "1"} {error "bad final version"}
+           close $f
+           foreach id [array names idtags] {
+               if {[info exists arcnos($id)] && [llength $arcnos($id)] == 1 &&
+                   [llength $allparents($id)] == 1} {
+                   set a [lindex $arcnos($id) 0]
+                   if {$arctags($a) eq {}} {
+                       recalcarc $a
+                   }
+               }
+           }
+           foreach id [array names idheads] {
+               if {[info exists arcnos($id)] && [llength $arcnos($id)] == 1 &&
+                   [llength $allparents($id)] == 1} {
+                   set a [lindex $arcnos($id) 0]
+                   if {$archeads($a) eq {}} {
+                       recalcarc $a
+                   }
+               }
+           }
+           foreach id [lsort -unique $possible_seeds] {
+               if {$arcnos($id) eq {}} {
+                   lappend seeds $id
+               }
+           }
+           set allcwait 0
+       } else {
+           while {[incr a] <= $lim} {
+               set line [gets $f]
+               if {[llength $line] != 3} {error "bad line"}
+               set s [lindex $line 0]
+               set arcstart($a) $s
+               lappend arcout($s) $a
+               if {![info exists arcnos($s)]} {
+                   lappend possible_seeds $s
+                   set arcnos($s) {}
+               }
+               set e [lindex $line 1]
+               if {$e eq {}} {
+                   set growing($a) 1
+               } else {
+                   set arcend($a) $e
+                   if {![info exists arcout($e)]} {
+                       set arcout($e) {}
+                   }
+               }
+               set arcids($a) [lindex $line 2]
+               foreach id $arcids($a) {
+                   lappend allparents($s) $id
+                   set s $id
+                   lappend arcnos($id) $a
+               }
+               if {![info exists allparents($s)]} {
+                   set allparents($s) {}
+               }
+               set arctags($a) {}
+               set archeads($a) {}
+           }
+           set nextarc [expr {$a - 1}]
+       }
+    } err]} {
+       dropcache $err
+       return 0
+    }
+    if {!$allcwait} {
+       getallcommits
+    }
+    return $allcwait
+}
+
+proc getcache {f} {
+    global nextarc cachedarcs possible_seeds
+
+    if {[catch {
+       set line [gets $f]
+       if {[llength $line] != 2 || [lindex $line 0] ne "1"} {error "bad version"}
+       # make sure it's an integer
+       set cachedarcs [expr {int([lindex $line 1])}]
+       if {$cachedarcs < 0} {error "bad number of arcs"}
+       set nextarc 0
+       set possible_seeds {}
+       run readcache $f
+    } err]} {
+       dropcache $err
+    }
+    return 0
+}
+
+proc dropcache {err} {
+    global allcwait nextarc cachedarcs seeds
+
+    #puts "dropping cache ($err)"
+    foreach v {arcnos arcout arcids arcstart arcend growing \
+                  arctags archeads allparents allchildren} {
+       global $v
+       catch {unset $v}
+    }
+    set allcwait 0
+    set nextarc 0
+    set cachedarcs 0
+    set seeds {}
+    getallcommits
+}
+
+proc writecache {f} {
+    global cachearc cachedarcs allccache
+    global arcstart arcend arcnos arcids arcout
+
+    set a $cachearc
+    set lim $cachedarcs
+    if {$lim - $a > 1000} {
+       set lim [expr {$a + 1000}]
+    }
+    if {[catch {
+       while {[incr a] <= $lim} {
+           if {[info exists arcend($a)]} {
+               puts $f [list $arcstart($a) $arcend($a) $arcids($a)]
+           } else {
+               puts $f [list $arcstart($a) {} $arcids($a)]
+           }
+       }
+    } err]} {
+       catch {close $f}
+       catch {file delete $allccache}
+       #puts "writing cache failed ($err)"
+       return 0
+    }
+    set cachearc [expr {$a - 1}]
+    if {$a > $cachedarcs} {
+       puts $f "1"
+       close $f
+       return 0
+    }
+    return 1
+}
+
+proc savecache {} {
+    global nextarc cachedarcs cachearc allccache
+
+    if {$nextarc == $cachedarcs} return
+    set cachearc 0
+    set cachedarcs $nextarc
+    catch {
+       set f [open $allccache w]
+       puts $f [list 1 $cachedarcs]
+       run writecache $f
+    }
+}
+
 # Returns 1 if a is an ancestor of b, -1 if b is an ancestor of a,
 # or 0 if neither is true.
 proc anc_or_desc {a b} {
 # Returns 1 if a is an ancestor of b, -1 if b is an ancestor of a,
 # or 0 if neither is true.
 proc anc_or_desc {a b} {
@@ -6922,6 +7631,7 @@ proc rereadrefs {} {
            redrawtags $id
        }
     }
            redrawtags $id
        }
     }
+    run refill_reflist
 }
 
 proc listrefs {id} {
 }
 
 proc listrefs {id} {
@@ -7142,8 +7852,9 @@ proc prefsok {} {
 }
 
 proc formatdate {d} {
 }
 
 proc formatdate {d} {
+    global datetimeformat
     if {$d ne {}} {
     if {$d ne {}} {
-       set d [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+       set d [clock format $d -format $datetimeformat]
     }
     return $d
 }
     }
     return $d
 }
@@ -7447,20 +8158,22 @@ set maxgraphpct 50
 set maxwidth 16
 set revlistorder 0
 set fastdate 0
 set maxwidth 16
 set revlistorder 0
 set fastdate 0
-set uparrowlen 7
-set downarrowlen 7
-set mingaplen 30
+set uparrowlen 5
+set downarrowlen 5
+set mingaplen 100
 set cmitmode "patch"
 set wrapcomment "none"
 set showneartags 1
 set maxrefs 20
 set maxlinelen 200
 set showlocalchanges 1
 set cmitmode "patch"
 set wrapcomment "none"
 set showneartags 1
 set maxrefs 20
 set maxlinelen 200
 set showlocalchanges 1
+set datetimeformat "%Y-%m-%d %H:%M:%S"
 
 set colors {green red blue magenta darkgrey brown orange}
 set bgcolor white
 set fgcolor black
 set diffcolors {red "#00a000" blue}
 
 set colors {green red blue magenta darkgrey brown orange}
 set bgcolor white
 set fgcolor black
 set diffcolors {red "#00a000" blue}
+set diffcontext 3
 set selectbgcolor gray85
 
 catch {source ~/.gitk}
 set selectbgcolor gray85
 
 catch {source ~/.gitk}
@@ -7468,7 +8181,10 @@ catch {source ~/.gitk}
 font create optionfont -family sans-serif -size -12
 
 # check that we can find a .git directory somewhere...
 font create optionfont -family sans-serif -size -12
 
 # check that we can find a .git directory somewhere...
-set gitdir [gitdir]
+if {[catch {set gitdir [gitdir]}]} {
+    show_error {} . "Cannot find a git repository here."
+    exit 1
+}
 if {![file isdirectory $gitdir]} {
     show_error {} . "Cannot find the git directory \"$gitdir\"."
     exit 1
 if {![file isdirectory $gitdir]} {
     show_error {} . "Cannot find the git directory \"$gitdir\"."
     exit 1
@@ -7522,6 +8238,8 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
 }
 
 set nullid "0000000000000000000000000000000000000000"
 }
 
 set nullid "0000000000000000000000000000000000000000"
+set nullid2 "0000000000000000000000000000000000000001"
+
 
 set runq {}
 set history {}
 
 set runq {}
 set history {}
@@ -7529,18 +8247,22 @@ set historyindex 0
 set fh_serial 0
 set nhl_names {}
 set highlight_paths {}
 set fh_serial 0
 set nhl_names {}
 set highlight_paths {}
+set findpattern {}
 set searchdirn -forwards
 set boldrows {}
 set boldnamerows {}
 set diffelide {0 0}
 set markingmatches 0
 set searchdirn -forwards
 set boldrows {}
 set boldnamerows {}
 set diffelide {0 0}
 set markingmatches 0
-
-set optim_delay 16
+set linkentercount 0
+set need_redisplay 0
+set nrows_drawn 0
 
 set nextviewnum 1
 set curview 0
 set selectedview 0
 set selectedhlview None
 
 set nextviewnum 1
 set curview 0
 set selectedview 0
 set selectedhlview None
+set highlight_related None
+set highlight_files {}
 set viewfiles(0) {}
 set viewperm(0) 0
 set viewargs(0) {}
 set viewfiles(0) {}
 set viewperm(0) 0
 set viewargs(0) {}
@@ -7549,11 +8271,13 @@ set cmdlineok 0
 set stopped 0
 set stuffsaved 0
 set patchnum 0
 set stopped 0
 set stuffsaved 0
 set patchnum 0
-set lookingforhead 0
-set localrow -1
+set localirow -1
+set localfrow -1
 set lserial 0
 setcoords
 makewindow
 set lserial 0
 setcoords
 makewindow
+# wait for the window to become visible
+tkwait visibility .
 wm title . "[file tail $argv0]: [file tail [pwd]]"
 readrefs
 
 wm title . "[file tail $argv0]: [file tail [pwd]]"
 readrefs