Merge branch 'dev'
authorPaul Mackerras <paulus@samba.org>
Sat, 27 Oct 2007 11:23:20 +0000 (21:23 +1000)
committerPaul Mackerras <paulus@samba.org>
Sat, 27 Oct 2007 11:23:20 +0000 (21:23 +1000)
1  2 
gitk
diff --combined gitk
index ff5eb5e8c48392a408b854c3da337749cd91bdce,5230e3bb9df53c6b7244ccd5c573021275d3c93c..4efcbb79574d91fdc8f03b1bf38db937fd2ec0c4
--- 1/gitk
--- 2/gitk
+++ b/gitk
@@@ -82,11 -82,14 +82,14 @@@ proc dorunq {} 
  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
+     global progressdirn progresscoords proglastnc curview
  
      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 commfd($view) $fd
      set leftover($view) {}
-     set lookingforhead $showlocalchanges
+     if {$showlocalchanges} {
+       lappend commitinterest($mainheadid) {dodiffindex}
+     }
      fconfigure $fd -blocking 0 -translation lf -eofchar {}
      if {$tclencoding != {}} {
        fconfigure $fd -encoding $tclencoding
      }
      filerun $fd [list getcommitlines $fd $view]
-     nowbusy $view
+     nowbusy $view "Reading"
+     if {$view == $curview} {
+       set progressdirn 1
+       set progresscoords {0 0}
+       set proglastnc 0
+     }
  }
  
  proc stop_rev_list {} {
  }
  
  proc getcommits {} {
-     global phase canv mainfont curview
+     global phase canv curview
  
      set phase getcommits
      initlayout
      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}  {
-     global commitlisted
+     global commitlisted commitinterest
      global leftover commfd
-     global displayorder commitidx commitrow commitdata
+     global displayorder commitidx viewcomplete commitrow commitdata
      global parentlist children curview hlview
      global vparentlist vdisporder vcmitlisted
+     global ordertok vnextroot idpending
  
      set stuff [read $fd 500000]
      # git log doesn't terminate the last commit with a null...
        if {![eof $fd]} {
            return 1
        }
-       global viewname
+       # 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 progresscoords
        unset commfd($view)
        notbusy $view
+       set progresscoords {0 0}
+       adjustprogress
        # set it blocking so we wait for the process to terminate
        fconfigure $fd -blocking 1
        if {[catch {close $fd} err]} {
            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]
-           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 {}
            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} {
        run chewcommits $view
+       if {$view == $curview} {
+           # update progress bar
+           global progressdirn progresscoords proglastnc
+           set inc [expr {($commitidx($view) - $proglastnc) * 0.0002}]
+           set proglastnc $commitidx($view)
+           set l [lindex $progresscoords 0]
+           set r [lindex $progresscoords 1]
+           if {$progressdirn} {
+               set r [expr {$r + $inc}]
+               if {$r >= 1.0} {
+                   set r 1.0
+                   set progressdirn 0
+               }
+               if {$r > 0.2} {
+                   set l [expr {$r - 0.2}]
+               }
+           } else {
+               set l [expr {$l - $inc}]
+               if {$l <= 0.0} {
+                   set l 0.0
+                   set progressdirn 1
+               }
+               set r [expr {$l + 0.2}]
+           }
+           set progresscoords [list $l $r]
+           adjustprogress
+       }
      }
      return 2
  }
  
  proc chewcommits {view} {
-     global curview hlview commfd
+     global curview hlview viewcomplete
      global selectedline pending_select
  
-     set more 0
      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} {
+       layoutmore
+       if {$viewcomplete($view)} {
            global displayorder commitidx phase
            global numcommits startmsecs
  
      if {[info exists hlview] && $view == $hlview} {
        vhighlightmore
      }
-     return $more
+     return 0
  }
  
  proc readcommit {id} {
  }
  
  proc updatecommits {} {
-     global viewdata curview phase displayorder
+     global viewdata curview phase displayorder ordertok idpending
      global children commitrow selectedline thickerline showneartags
  
      if {$phase ne {}} {
      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}
@@@ -516,7 -615,7 +615,7 @@@ proc confirm_popup msg 
  
  proc makewindow {} {
      global canv canv2 canv3 linespc charspc ctext cflist
-     global textfont mainfont uifont tabstop
+     global tabstop
      global findtype findtypemenu findloc findstring fstring geometry
      global entries sha1entry sha1string sha1but
      global diffcontextstring diffcontext
      global highlight_files gdttype
      global searchstring sstring
      global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
-     global headctxmenu
+     global headctxmenu progresscanv progressitem progresscoords statusw
+     global fprogitem fprogcoord lastprogupdate progupdatepending
+     global rprogitem rprogcoord
+     global have_tk85
  
      menu .bar
      .bar add cascade -label "File" -menu .bar.file
-     .bar configure -font $uifont
+     .bar configure -font uifont
      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
+     .bar.file configure -font uifont
      menu .bar.edit
      .bar add cascade -label "Edit" -menu .bar.edit
      .bar.edit add command -label "Preferences" -command doprefs
-     .bar.edit configure -font $uifont
+     .bar.edit configure -font uifont
  
-     menu .bar.view -font $uifont
+     menu .bar.view -font uifont
      .bar add cascade -label "View" -menu .bar.view
      .bar.view add command -label "New view..." -command {newview 0}
      .bar.view add command -label "Edit view..." -command editview \
      .bar add cascade -label "Help" -menu .bar.help
      .bar.help add command -label "About gitk" -command about
      .bar.help add command -label "Key bindings" -command keys
-     .bar.help configure -font $uifont
+     .bar.help configure -font uifont
      . configure -menu .bar
  
      # the gui has upper and lower half, parts of a paned window.
      set entries $sha1entry
      set sha1but .tf.bar.sha1label
      button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
-       -command gotocommit -width 8 -font $uifont
+       -command gotocommit -width 8 -font uifont
      $sha1but conf -disabledforeground [$sha1but cget -foreground]
      pack .tf.bar.sha1label -side left
-     entry $sha1entry -width 40 -font $textfont -textvariable sha1string
+     entry $sha1entry -width 40 -font textfont -textvariable sha1string
      trace add variable sha1string write sha1change
      pack $sha1entry -side left -pady 2
  
        -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
+     # Status label and progress bar
+     set statusw .tf.bar.status
+     label $statusw -width 15 -relief sunken -font uifont
+     pack $statusw -side left -padx 5
+     set h [expr {[font metrics uifont -linespace] + 2}]
+     set progresscanv .tf.bar.progress
+     canvas $progresscanv -relief sunken -height $h -borderwidth 2
+     set progressitem [$progresscanv create rect -1 0 0 $h -fill green]
+     set fprogitem [$progresscanv create rect -1 0 0 $h -fill yellow]
+     set rprogitem [$progresscanv create rect -1 0 0 $h -fill red]
+     pack $progresscanv -side right -expand 1 -fill x
+     set progresscoords {0 0}
+     set fprogcoord 0
+     set rprogcoord 0
+     bind $progresscanv <Configure> adjustprogress
+     set lastprogupdate [clock clicks -milliseconds]
+     set progupdatepending 0
+     # build up the bottom bar of upper window
+     label .tf.lbar.flabel -text "Find " -font uifont
+     button .tf.lbar.fnext -text "next" -command {dofind 1 1} -font uifont
+     button .tf.lbar.fprev -text "prev" -command {dofind -1 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 fstring .tf.bar.findstring
+     set fstring .tf.lbar.findstring
      lappend entries $fstring
-     entry $fstring -width 30 -font $textfont -textvariable findstring
+     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 findtypemenu [tk_optionMenu .tf.bar.findtype \
+     set findtypemenu [tk_optionMenu .tf.lbar.findtype \
                      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"
-     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
-     .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
      frame .bleft.mid
  
      button .bleft.top.search -text "Search" -command dosearch \
-       -font $uifont
+       -font uifont
      pack .bleft.top.search -side left -padx 5
      set sstring .bleft.top.sstring
-     entry $sstring -width 20 -font $textfont -textvariable searchstring
+     entry $sstring -width 20 -font textfont -textvariable searchstring
      lappend entries $sstring
      trace add variable searchstring write incrsearch
      pack $sstring -side left -expand 1 -fill x
      radiobutton .bleft.mid.new -text "New version" \
        -command changediffdisp -variable diffelide -value {1 0}
      label .bleft.mid.labeldiffcontext -text "      Lines of context: " \
-       -font $uifont
+       -font uifont
      pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
-     spinbox .bleft.mid.diffcontext -width 5 -font $textfont \
+     spinbox .bleft.mid.diffcontext -width 5 -font textfont \
        -from 1 -increment 1 -to 10000000 \
        -validate all -validatecommand "diffcontextvalidate %P" \
        -textvariable diffcontextstring
      pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left
      set ctext .bleft.ctext
      text $ctext -background $bgcolor -foreground $fgcolor \
-       -tabs "[expr {$tabstop * $charspc}]" \
-       -state disabled -font $textfont \
+       -state disabled -font textfont \
        -yscrollcommand scrolltext -wrap none
+     if {$have_tk85} {
+       $ctext conf -tabstyle wordprocessor
+     }
      scrollbar .bleft.sb -command "$ctext yview"
      pack .bleft.top -side top -fill x
      pack .bleft.mid -side top -fill x
      lappend fglist $ctext
  
      $ctext tag conf comment -wrap $wrapcomment
-     $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
+     $ctext tag conf filesep -font textfontbold -back "#aaaaaa"
      $ctext tag conf hunksep -fore [lindex $diffcolors 2]
      $ctext tag conf d0 -fore [lindex $diffcolors 0]
      $ctext tag conf d1 -fore [lindex $diffcolors 1]
      $ctext tag conf m15 -fore "#ff70b0"
      $ctext tag conf mmax -fore darkgrey
      set mergemax 16
-     $ctext tag conf mresult -font [concat $textfont bold]
-     $ctext tag conf msep -font [concat $textfont bold]
+     $ctext tag conf mresult -font textfontbold
+     $ctext tag conf msep -font textfontbold
      $ctext tag conf found -back yellow
  
      .pwbottom add .bleft
      frame .bright.mode
      radiobutton .bright.mode.patch -text "Patch" \
        -command reselectline -variable cmitmode -value "patch"
-     .bright.mode.patch configure -font $uifont
+     .bright.mode.patch configure -font uifont
      radiobutton .bright.mode.tree -text "Tree" \
        -command reselectline -variable cmitmode -value "tree"
-     .bright.mode.tree configure -font $uifont
+     .bright.mode.tree configure -font uifont
      grid .bright.mode.patch .bright.mode.tree -sticky ew
      pack .bright.mode -side top -fill x
      set cflist .bright.cfiles
-     set indent [font measure $mainfont "nn"]
+     set indent [font measure mainfont "nn"]
      text $cflist \
        -selectbackground $selectbgcolor \
        -background $bgcolor -foreground $fgcolor \
-       -font $mainfont \
+       -font mainfont \
        -tabs [list $indent [expr {2 * $indent}]] \
        -yscrollcommand ".bright.sb set" \
        -cursor [. cget -cursor] \
      pack $cflist -side left -fill both -expand 1
      $cflist tag configure highlight \
        -background [$cflist cget -selectbackground]
-     $cflist tag configure bold -font [concat $mainfont bold]
+     $cflist tag configure bold -font mainfontbold
  
      .pwbottom add .bright
      .ctop add .pwbottom
      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"
+     bind . <Shift-Key-Up> "dofind -1 0"
+     bind . <Shift-Key-Down> "dofind 1 0"
      bindkey <Key-Right> "goforw"
      bindkey <Key-Left> "goback"
      bind . <Key-Prior> "selnextpage -1"
      bindkey b "$ctext yview scroll -1 pages"
      bindkey d "$ctext yview scroll 18 units"
      bindkey u "$ctext yview scroll -18 units"
-     bindkey / {findnext 1}
-     bindkey <Key-Return> {findnext 0}
-     bindkey ? findprev
+     bindkey / {dofind 1 1}
+     bindkey <Key-Return> {dofind 1 1}
+     bindkey ? {dofind -1 1}
      bindkey f nextfile
      bindkey <F5> updatecommits
      bind . <$M1B-q> doquit
-     bind . <$M1B-f> dofind
-     bind . <$M1B-g> {findnext 0}
+     bind . <$M1B-f> {dofind 1 1}
+     bind . <$M1B-g> {dofind 1 0}
      bind . <$M1B-r> dosearchback
      bind . <$M1B-s> dosearch
      bind . <$M1B-equal> {incrfont 1}
      bind . <$M1B-KP_Subtract> {incrfont -1}
      wm protocol . WM_DELETE_WINDOW doquit
      bind . <Button-1> "click %W"
-     bind $fstring <Key-Return> dofind
+     bind $fstring <Key-Return> {dofind 1 1}
      bind $sha1entry <Key-Return> gotocommit
      bind $sha1entry <<PasteSelection>> clearsha1
      bind $cflist <1> {sel_flist %W %x %y; break}
@@@ -1014,8 -1117,41 +1117,41 @@@ proc click {w} 
      focus .
  }
  
+ # Adjust the progress bar for a change in requested extent or canvas size
+ proc adjustprogress {} {
+     global progresscanv progressitem progresscoords
+     global fprogitem fprogcoord lastprogupdate progupdatepending
+     global rprogitem rprogcoord
+     set w [expr {[winfo width $progresscanv] - 4}]
+     set x0 [expr {$w * [lindex $progresscoords 0]}]
+     set x1 [expr {$w * [lindex $progresscoords 1]}]
+     set h [winfo height $progresscanv]
+     $progresscanv coords $progressitem $x0 0 $x1 $h
+     $progresscanv coords $fprogitem 0 0 [expr {$w * $fprogcoord}] $h
+     $progresscanv coords $rprogitem 0 0 [expr {$w * $rprogcoord}] $h
+     set now [clock clicks -milliseconds]
+     if {$now >= $lastprogupdate + 100} {
+       set progupdatepending 0
+       update
+     } elseif {!$progupdatepending} {
+       set progupdatepending 1
+       after [expr {$lastprogupdate + 100 - $now}] doprogupdate
+     }
+ }
+ proc doprogupdate {} {
+     global lastprogupdate progupdatepending
+     if {$progupdatepending} {
+       set progupdatepending 0
+       set lastprogupdate [clock clicks -milliseconds]
+       update
+     }
+ }
  proc savestuff {w} {
-     global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop
+     global canv canv2 canv3 mainfont textfont uifont tabstop
      global stuffsaved findmergefiles maxgraphpct
      global maxwidth showneartags showlocalchanges
      global viewname viewfiles viewargs viewperm nextviewnum
@@@ -1150,10 -1286,10 +1286,10 @@@ Copyright Â© 2005-2006 Paul Mackerra
  Use and redistribute under the terms of the GNU General Public License} \
            -justify center -aspect 400 -border 2 -bg white -relief groove
      pack $w.m -side top -fill x -padx 2 -pady 2
-     $w.m configure -font $uifont
+     $w.m configure -font uifont
      button $w.ok -text Close -command "destroy $w" -default active
      pack $w.ok -side bottom
-     $w.ok configure -font $uifont
+     $w.ok configure -font uifont
      bind $w <Visibility> "focus $w.ok"
      bind $w <Key-Escape> "destroy $w"
      bind $w <Key-Return> "destroy $w"
@@@ -1191,8 -1327,8 +1327,8 @@@ Gitk key bindings
  <$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
+ <Shift-Up>    Find backwards (upwards, later commits)
+ <Shift-Down>  Find forwards (downwards, earlier commits)
  <Delete>, b   Scroll diff view up one page
  <Backspace>   Scroll diff view up one page
  <Space>               Scroll diff view down one page
@@@ -1214,10 -1350,10 +1350,10 @@@ f            Scroll diff view to next fil
  " \
            -justify left -bg white -border 2 -relief groove
      pack $w.m -side top -fill both -padx 2 -pady 2
-     $w.m configure -font $uifont
+     $w.m configure -font uifont
      button $w.ok -text Close -command "destroy $w" -default active
      pack $w.ok -side bottom
-     $w.ok configure -font $uifont
+     $w.ok configure -font uifont
      bind $w <Visibility> "focus $w.ok"
      bind $w <Key-Escape> "destroy $w"
      bind $w <Key-Return> "destroy $w"
@@@ -1590,6 -1726,7 +1726,7 @@@ proc pop_flist_menu {w X Y x y} 
      global ctext cflist cmitmode flist_menu flist_menu_file
      global treediffs diffids
  
+     stopfinding
      set l [lindex [split [$w index "@$x,$y"] "."] 0]
      if {$l <= 1} return
      if {$cmitmode eq "tree"} {
  }
  
  proc flist_hl {only} {
-     global flist_menu_file highlight_files
+     global flist_menu_file findstring gdttype
  
      set x [shellquote $flist_menu_file]
-     if {$only || $highlight_files eq {}} {
-       set highlight_files $x
+     if {$only || $findstring eq {} || $gdttype ne "touching paths:"} {
+       set findstring $x
      } else {
-       append highlight_files " " $x
+       append findstring " " $x
      }
+     set gdttype "touching paths:"
  }
  
  # Functions for adding and removing shell-type quoting
@@@ -1747,22 -1885,22 +1885,22 @@@ proc vieweditor {top n title} 
  
      toplevel $top
      wm title $top $title
-     label $top.nl -text "Name" -font $uifont
-     entry $top.name -width 20 -textvariable newviewname($n) -font $uifont
+     label $top.nl -text "Name" -font uifont
+     entry $top.name -width 20 -textvariable newviewname($n) -font uifont
      grid $top.nl $top.name -sticky w -pady 5
      checkbutton $top.perm -text "Remember this view" -variable newviewperm($n) \
-       -font $uifont
+       -font uifont
      grid $top.perm - -pady 5 -sticky w
-     message $top.al -aspect 1000 -font $uifont \
+     message $top.al -aspect 1000 -font uifont \
        -text "Commits to include (arguments to git rev-list):"
      grid $top.al - -sticky w -pady 5
      entry $top.args -width 50 -textvariable newviewargs($n) \
-       -background white -font $uifont
+       -background white -font uifont
      grid $top.args - -sticky ew -padx 5
-     message $top.l -aspect 1000 -font $uifont \
+     message $top.l -aspect 1000 -font uifont \
        -text "Enter files and directories to include, one per line:"
      grid $top.l - -sticky w
-     text $top.t -width 40 -height 10 -background white -font $uifont
+     text $top.t -width 40 -height 10 -background white -font uifont
      if {[info exists viewfiles($n)]} {
        foreach f $viewfiles($n) {
            $top.t insert end $f
      grid $top.t - -sticky ew -padx 5
      frame $top.buts
      button $top.buts.ok -text "OK" -command [list newviewok $top $n] \
-       -font $uifont
+       -font uifont
      button $top.buts.can -text "Cancel" -command [list destroy $top] \
-       -font $uifont
+       -font uifont
      grid $top.buts.ok $top.buts.can
      grid columnconfigure $top.buts 0 -weight 1 -uniform a
      grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@@ -1795,10 -1933,10 +1933,10 @@@ proc doviewmenu {m first cmd op argv} 
  }
  
  proc allviewmenus {n op args} {
-     global viewhlmenu
+     global viewhlmenu
  
      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} {
            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
@@@ -1874,8 -2012,8 +2012,8 @@@ proc addviewmenu {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} {
@@@ -1899,17 -2037,17 +2037,17 @@@ proc unflatten {var l} 
  
  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 numcommits rowrangelist commitlisted idrowranges rowchk
+     global numcommits commitlisted
      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 hlview selectedhlview
+     global hlview selectedhlview commitinterest
  
      if {$n == $curview} return
      set selid {}
        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) \
-               [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}
        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"}]
  
+     run refill_reflist
      if {![info exists viewdata($n)]} {
        if {$selid ne {}} {
            set pending_select $selid
      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}
      } elseif {$numcommits == 0} {
        show_status "No commits selected"
      }
-     run refill_reflist
  }
  
  # Stuff relating to the highlighting facility
@@@ -2080,12 -2205,12 +2205,12 @@@ proc bolden_name {row font} 
  }
  
  proc unbolden {} {
-     global mainfont boldrows
+     global boldrows
  
      set stillbold {}
      foreach row $boldrows {
        if {![ishighlighted $row]} {
-           bolden $row $mainfont
+           bolden $row mainfont
        } else {
            lappend stillbold $row
        }
@@@ -2101,7 -2226,7 +2226,7 @@@ proc addvhighlight {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) {}
@@@ -2124,9 -2249,8 +2249,8 @@@ proc delvhighlight {} 
  
  proc vhighlightmore {} {
      global hlview vhl_done commitidx vhighlights
-     global displayorder vdisporder curview mainfont
+     global displayorder vdisporder curview
  
-     set font [concat $mainfont bold]
      set max $commitidx($hlview)
      if {$hlview == $curview} {
        set disp $displayorder
            set row $commitrow($curview,$id)
            if {$r0 <= $row && $row <= $r1} {
                if {![highlighted $row]} {
-                   bolden $row $font
+                   bolden $row mainfontbold
                }
                set vhighlights($row) 1
            }
  }
  
  proc askvhighlight {row id} {
-     global hlview vhighlights commitrow iddrawn mainfont
+     global hlview vhighlights commitrow iddrawn
  
      if {[info exists commitrow($hlview,$id)]} {
        if {[info exists iddrawn($id)] && ![ishighlighted $row]} {
-           bolden $row [concat $mainfont bold]
+           bolden $row mainfontbold
        }
        set vhighlights($row) 1
      } else {
      }
  }
  
- proc hfiles_change {name ix op} {
+ proc hfiles_change {} {
      global highlight_files filehighlight fhighlights fh_serial
-     global mainfont highlight_paths
+     global highlight_paths gdttype
  
      if {[info exists filehighlight]} {
        # delete previous highlights
      }
  }
  
+ proc gdttype_change {name ix op} {
+     global gdttype highlight_files findstring findpattern
+     stopfinding
+     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
+     stopfinding
+     if {$gdttype eq "containing:"} {
+       findcom_change
+     } else {
+       if {$highlight_files ne $findstring} {
+           set highlight_files $findstring
+           hfiles_change
+       }
+     }
+     drawvisible
+ }
+ proc findcom_change args {
+     global nhighlights boldnamerows
+     global findpattern findtype findstring gdttype
+     stopfinding
+     # 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 {
@@@ -2206,8 -2393,11 +2393,11 @@@ proc do_file_hl {serial} 
        set highlight_paths [makepatterns $paths]
        highlight_filelist
        set gdtargs [concat -- $paths]
-     } else {
+     } elseif {$gdttype eq "adding/removing string:"} {
        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+]
@@@ -2237,8 -2427,8 +2427,8 @@@ proc askfilehighlight {row id} 
  }
  
  proc readfhighlight {} {
-     global filehighlight fhighlights commitrow curview mainfont iddrawn
-     global fhl_list
+     global filehighlight fhighlights commitrow curview iddrawn
+     global fhl_list find_dirn
  
      if {![info exists filehighlight]} {
        return 0
        if {![info exists commitrow($curview,$line)]} continue
        set row $commitrow($curview,$line)
        if {[info exists iddrawn($line)] && ![ishighlighted $row]} {
-           bolden $row [concat $mainfont bold]
+           bolden $row mainfontbold
        }
        set fhighlights($row) 1
      }
        unset filehighlight
        return 0
      }
-     next_hlcont
-     return 1
- }
- proc find_change {name ix op} {
-     global nhighlights mainfont boldnamerows
-     global findstring findpattern findtype
-     # 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]} {
+       run findmore
      }
-     drawvisible
+     return 1
  }
  
  proc doesmatch {f} {
-     global findtype findstring findpattern
+     global findtype findpattern
  
      if {$findtype eq "Regexp"} {
-       return [regexp $findstring $f]
+       return [regexp $findpattern $f]
      } elseif {$findtype eq "IgnCase"} {
        return [string match -nocase $findpattern $f]
      } else {
  }
  
  proc askfindhighlight {row id} {
-     global nhighlights commitinfo iddrawn mainfont
+     global nhighlights commitinfo iddrawn
      global findloc
      global markingmatches
  
        }
      }
      if {$isbold && [info exists iddrawn($id)]} {
-       set f [concat $mainfont bold]
        if {![ishighlighted $row]} {
-           bolden $row $f
+           bolden $row mainfontbold
            if {$isbold > 1} {
-               bolden_name $row $f
+               bolden_name $row mainfontbold
            }
        }
        if {$markingmatches} {
@@@ -2461,7 -2632,7 +2632,7 @@@ proc is_ancestor {a} 
  }
  
  proc askrelhighlight {row id} {
-     global descendent highlight_related iddrawn mainfont rhighlights
+     global descendent highlight_related iddrawn rhighlights
      global selectedline ancestor
  
      if {![info exists selectedline]} return
      }
      if {[info exists iddrawn($id)]} {
        if {$isbold && ![ishighlighted $row]} {
-           bolden $row [concat $mainfont bold]
+           bolden $row mainfontbold
        }
      }
      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} {
      return $res
  }
  
- proc incrange {l x o} {
-     set n [llength $l]
-     while {$x < $n} {
-       set e [lindex $l $x]
-       if {$e ne {}} {
-           lset l $x [expr {$e + $o}]
-       }
-       incr x
-     }
-     return $l
- }
  proc ntimes {n o} {
      set ret {}
-     for {} {$n > 0} {incr n -1} {
-       lappend ret $o
-     }
-     return $ret
- }
- proc usedinrange {id l1 l2} {
-     global children commitrow 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 {} {
-     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
      set displayorder {}
      set commitlisted {}
      set parentlist {}
-     set rowrangelist {}
      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}
-     catch {unset idrowranges}
      set selectfirst 1
  }
  
@@@ -2737,61 -2763,19 +2763,19 @@@ proc visiblerows {} 
      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 || $viewcomplete($curview)} {
+       showstuff $show $viewcomplete($curview)
      }
  }
  
  proc showstuff {canshow last} {
      global numcommits commitrow pending_select selectedline curview
-     global lookingforhead mainheadid displayorder selectfirst
+     global mainheadid displayorder selectfirst
      global lastscrollset commitinterest
  
      if {$numcommits == 0} {
        set phase "incrdraw"
        allcanvs delete all
      }
-     for {set l $numcommits} {$l < $canshow} {incr l} {
-       set id [lindex $displayorder $l]
-       if {[info exists commitinterest($id)]} {
-           foreach script $commitinterest($id) {
-               eval [string map [list "%I" $id] $script]
-           }
-           unset commitinterest($id)
-       }
-     }
      set r0 $numcommits
      set prev $numcommits
      set numcommits $canshow
            set selectfirst 0
        }
      }
-     if {$lookingforhead && [info exists commitrow($curview,$mainheadid)]
-       && ($last || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
-       set lookingforhead 0
-       dodiffindex
-     }
  }
  
  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 {}} {
-       set lookingforhead 1
+       lappend commitinterest($mainheadid) {}
      }
  }
  
  proc dohidelocalchanges {} {
-     global lookingforhead localfrow localirow lserial
+     global localfrow localirow lserial
  
-     set lookingforhead 0
      if {$localfrow >= 0} {
        removerow $localfrow
        set localfrow -1
  
  # spawn off a process to do git diff-index --cached HEAD
  proc dodiffindex {} {
-     global localirow localfrow lserial
+     global localirow localfrow lserial showlocalchanges
  
+     if {!$showlocalchanges} return
      incr lserial
      set localfrow -1
      set localirow -1
@@@ -2948,207 -2918,325 +2918,325 @@@ proc readdifffiles {fd serial} 
      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 nev [expr {[llength $idlist] - $maxwidth + 1}]
-       foreach p [lindex $parentlist $row] {
-           if {![info exists idinlist($p)] || !$idinlist($p)} {
-               incr nev
-           }
-       }
-       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($i) [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 oldolds {}
-       set newolds {}
-       foreach p [lindex $parentlist $row] {
-           if {![info exists idinlist($p)]} {
-               lappend newolds $p
-           } elseif {!$idinlist($p)} {
-               lappend oldolds $p
+     }
+     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)
            }
-           set idinlist($p) 1
        }
-       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
+     }
+     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 {
-           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]]
+       }
+     }
+     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]
            }
-       } else {
-           lset offs $col {}
        }
-       foreach i $newolds {
-           set idrowranges($i) $id
+     }
+     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 col $l
-       foreach oid $oldolds {
-           set idlist [linsert $idlist $col $oid]
-           set offs [linsert $offs $col $o]
-           makeuparrow $oid $col $row $o
-           incr col
+       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 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}]
  }
  
- proc addextraid {id row} {
-     global displayorder commitrow commitinfo
-     global commitidx commitlisted
-     global parentlist children curview
+ proc makeupline {id row rend col} {
+     global rowidlist uparrowlen downarrowlen mingaplen
  
-     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"}
+     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 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
-       catch {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 {}
+     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
+ }
+ 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} {
-     global rowidlist rowoffsets
+     global rowidlist
  
      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} {
-     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
-       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 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 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 {}} {
-               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
                }
            }
+           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
                # 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
                }
-               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;
-               # insert pads in this line and adjust the next's rowoffsets
+               # insert pads in this line
                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
-               set offs [incrange $tmp $col [expr {-$npad}]]
-               set z [lindex $offs $col]
+               set z [expr {$x0 - $col}]
                set haspad 1
            }
-           if {$z0 eq {} && !$isarrow} {
+           if {$z0 eq {} && !$isarrow && $ym >= 0} {
                # 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}]
                }
            # 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} {
-           set o {}
            # 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
-                   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
-                       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
-           # 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 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
      }
  }
  
@@@ -3271,51 -3331,64 +3331,64 @@@ proc linewidth {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 {
-           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
-     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 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 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]
        } 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 {$arrowhigh} {
-               set coords [adjarrowhigh $coords]
-           }
            assigncolor $id
            set t [$canv create line $coords -width [linewidth $id] \
                       -fill $colormap($id) -tags lines.$id -arrow $arrow]
        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
  
  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 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
        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]
-       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
@@@ -3542,8 -3631,8 +3631,8 @@@ 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 linehtag linentag linedtag
-     global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
+     global linehtag linentag linedtag selectedline
+     global canvxmax boldrows boldnamerows fgcolor nullid nullid2
  
      # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
      set listed [lindex $commitlisted $row]
      set name [lindex $commitinfo($id) 1]
      set date [lindex $commitinfo($id) 2]
      set date [formatdate $date]
-     set font $mainfont
-     set nfont $mainfont
+     set font mainfont
+     set nfont mainfont
      set isbold [ishighlighted $row]
      if {$isbold > 0} {
        lappend boldrows $row
-       lappend font bold
+       set font mainfontbold
        if {$isbold > 1} {
            lappend boldnamerows $row
-           lappend nfont bold
+           set nfont mainfontbold
        }
      }
      set linehtag($row) [$canv create text $xt $y -anchor w -fill $fgcolor \
      set linentag($row) [$canv2 create text 3 $y -anchor w -fill $fgcolor \
                            -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]}]
+                           -text $date -font mainfont -tags text]
+     if {[info exists selectedline] && $selectedline == $row} {
+       make_secsel $row
+     }
+     set xr [expr {$xt + [font measure $font $headline]}]
      if {$xr > $canvxmax} {
        set canvxmax $xr
        setcanvscroll
  }
  
  proc drawcmitrow {row} {
-     global displayorder rowidlist
+     global displayorder rowidlist nrows_drawn
      global iddrawn markingmatches
      global commitinfo parentlist numcommits
-     global filehighlight fhighlights findstring nhighlights
+     global filehighlight fhighlights findpattern nhighlights
      global hlview vhighlights
      global highlight_related rhighlights
  
      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)]} {
        assigncolor $id
        drawcmittext $id $row $col
        set iddrawn($id) 1
+       incr nrows_drawn
      }
      if {$markingmatches} {
        markrowmatches $row $id
  }
  
  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
        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])]} {
@@@ -3736,7 -3858,7 +3858,7 @@@ proc drawvisible {} 
  }
  
  proc clear_display {} {
-     global iddrawn linesegs
+     global iddrawn linesegs need_redisplay nrows_drawn
      global vhighlights fhighlights nhighlights rhighlights
  
      allcanvs delete all
      catch {unset fhighlights}
      catch {unset nhighlights}
      catch {unset rhighlights}
+     set need_redisplay 0
+     set nrows_drawn 0
  }
  
  proc findcrossings {id} {
-     global rowidlist parentlist numcommits rowoffsets displayorder
+     global rowidlist parentlist numcommits displayorder
  
      set cross {}
      set ccross {}
            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} {} {
+           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 inc [lindex $rowoffsets $row $x]
-           if {$inc eq {}} break
-           incr x $inc
        }
      }
      return [concat $ccross {{}} $cross]
@@@ -3864,7 -3982,7 +3982,7 @@@ proc bindline {t id} 
  proc drawtags {id x xt y1} {
      global idtags idheads idotherrefs mainhead
      global linespc lthickness
-     global canv mainfont commitrow rowtextx curview fgcolor bgcolor
+     global canv commitrow rowtextx curview fgcolor bgcolor
  
      set marks {}
      set ntags 0
      foreach tag $marks {
        incr i
        if {$i >= $ntags && $i < $ntags + $nheads && $tag eq $mainhead} {
-           set wid [font measure [concat $mainfont bold] $tag]
+           set wid [font measure mainfontbold $tag]
        } else {
-           set wid [font measure $mainfont $tag]
+           set wid [font measure mainfont $tag]
        }
        lappend xvals $xt
        lappend wvals $wid
      foreach tag $marks x $xvals wid $wvals {
        set xl [expr {$x + $delta}]
        set xr [expr {$x + $delta + $wid + $lthickness}]
-       set font $mainfont
+       set font mainfont
        if {[incr ntags -1] >= 0} {
            # draw a tag
            set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
            if {[incr nheads -1] >= 0} {
                set col green
                if {$tag eq $mainhead} {
-                   lappend font bold
+                   set font mainfontbold
                }
            } else {
                set col "#ddddff"
            $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
                -width 1 -outline black -fill $col -tags tag.$id
            if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
-               set rwid [font measure $mainfont $remoteprefix]
+               set rwid [font measure mainfont $remoteprefix]
                set xi [expr {$x + 1}]
                set yti [expr {$yt + 1}]
                set xri [expr {$x + $rwid}]
@@@ -3961,10 -4079,10 +4079,10 @@@ proc xcoord {i level ln} 
  }
  
  proc show_status {msg} {
-     global canv mainfont fgcolor
+     global canv fgcolor
  
      clear_display
-     $canv create text 3 3 -anchor nw -text $msg -font $mainfont \
+     $canv create text 3 3 -anchor nw -text $msg -font mainfont \
        -tags text -fill $fgcolor
  }
  
  # 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"
        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} {
  # 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"
      }
      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} {
@@@ -4112,20 -4194,30 +4194,30 @@@ proc settextcursor {c} 
      set curtextcursor $c
  }
  
- proc nowbusy {what} {
-     global isbusy
+ proc nowbusy {what {name {}}} {
+     global isbusy busyname statusw
  
      if {[array names isbusy] eq {}} {
        . config -cursor watch
        settextcursor watch
      }
      set isbusy($what) 1
+     set busyname($what) $name
+     if {$name ne {}} {
+       $statusw conf -text $name
+     }
  }
  
  proc notbusy {what} {
-     global isbusy maincursor textcursor
+     global isbusy maincursor textcursor busyname statusw
  
-     catch {unset isbusy($what)}
+     catch {
+       unset isbusy($what)
+       if {$busyname($what) ne {} &&
+           [$statusw cget -text] eq $busyname($what)} {
+           $statusw conf -text {}
+       }
+     }
      if {[array names isbusy] eq {}} {
        . config -cursor $maincursor
        settextcursor $textcursor
@@@ -4153,148 -4245,149 +4245,149 @@@ proc findmatches {f} 
      return $matches
  }
  
- proc dofind {{rev 0}} {
+ proc dofind {{dirn 1} {wrap 1}} {
      global findstring findstartline findcurline selectedline numcommits
+     global gdttype filehighlight fh_serial find_dirn findallowwrap
  
-     unmarkmatches
-     cancel_next_highlight
+     if {[info exists find_dirn]} {
+       if {$find_dirn == $dirn} return
+       stopfinding
+     }
      focus .
      if {$findstring eq {} || $numcommits == 0} return
      if {![info exists selectedline]} {
-       set findstartline [lindex [visiblerows] $rev]
+       set findstartline [lindex [visiblerows] [expr {$dirn < 0}]]
      } else {
        set findstartline $selectedline
      }
      set findcurline $findstartline
-     nowbusy finding
-     if {!$rev} {
-       run findmore
-     } else {
-       if {$findcurline == 0} {
-           set findcurline $numcommits
-       }
-       incr findcurline -1
-       run findmorerev
+     nowbusy finding "Searching"
+     if {$gdttype ne "containing:" && ![info exists filehighlight]} {
+       after cancel do_file_hl $fh_serial
+       do_file_hl $fh_serial
      }
+     set find_dirn $dirn
+     set findallowwrap $wrap
+     run findmore
  }
  
- proc findnext {restart} {
-     global findcurline
-     if {![info exists findcurline]} {
-       if {$restart} {
-           dofind
-       } else {
-           bell
-       }
-     } else {
-       run findmore
-       nowbusy finding
-     }
- }
+ proc stopfinding {} {
+     global find_dirn findcurline fprogcoord
  
- proc findprev {} {
-     global findcurline
-     if {![info exists findcurline]} {
-       dofind 1
-     } else {
-       run findmorerev
-       nowbusy finding
+     if {[info exists find_dirn]} {
+       unset find_dirn
+       unset findcurline
+       notbusy finding
+       set fprogcoord 0
+       adjustprogress
      }
  }
  
  proc findmore {} {
-     global commitdata commitinfo numcommits findstring findpattern findloc
+     global commitdata commitinfo numcommits findpattern findloc
      global findstartline findcurline displayorder
+     global find_dirn gdttype fhighlights fprogcoord
+     global findallowwrap
  
-     set fldtypes {Headline Author Date Committer CDate Comments}
-     set l [expr {$findcurline + 1}]
-     if {$l >= $numcommits} {
-       set l 0
-     }
-     if {$l <= $findstartline} {
-       set lim [expr {$findstartline + 1}]
-     } else {
-       set lim $numcommits
-     }
-     if {$lim - $l > 500} {
-       set lim [expr {$l + 500}]
-     }
-     set last 0
-     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]} {
-               findselectline $l
-               notbusy finding
-               return 0
-           }
-       }
-     }
-     if {$l == $findstartline + 1} {
-       bell
-       unset findcurline
-       notbusy finding
+     if {![info exists find_dirn]} {
        return 0
      }
-     set findcurline [expr {$l - 1}]
-     return 1
- }
- proc findmorerev {} {
-     global commitdata commitinfo numcommits findstring findpattern findloc
-     global findstartline findcurline displayorder
      set fldtypes {Headline Author Date Committer CDate Comments}
      set l $findcurline
-     if {$l == 0} {
-       set l $numcommits
-     }
-     incr l -1
-     if {$l >= $findstartline} {
-       set lim [expr {$findstartline - 1}]
+     set moretodo 0
+     if {$find_dirn > 0} {
+       incr l
+       if {$l >= $numcommits} {
+           set l 0
+       }
+       if {$l <= $findstartline} {
+           set lim [expr {$findstartline + 1}]
+       } else {
+           set lim $numcommits
+           set moretodo $findallowwrap
+       }
      } else {
-       set lim -1
-     }
-     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
+       if {$l == 0} {
+           set l $numcommits
+       }
+       incr l -1
+       if {$l >= $findstartline} {
+           set lim [expr {$findstartline - 1}]
+       } else {
+           set lim -1
+           set moretodo $findallowwrap
+       }
+     }
+     set n [expr {($lim - $l) * $find_dirn}]
+     if {$n > 500} {
+       set n 500
+       set moretodo 1
+     }
+     set found 0
+     set domore 1
+     if {$gdttype eq "containing:"} {
+       for {} {$n > 0} {incr n -1; incr l $find_dirn} {
+           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]} {
-               findselectline $l
-               notbusy finding
-               return 0
+     } else {
+       for {} {$n > 0} {incr n -1; incr l $find_dirn} {
+           set id [lindex $displayorder $l]
+           if {![info exists fhighlights($l)]} {
+               askfilehighlight $l $id
+               if {$domore} {
+                   set domore 0
+                   set findcurline [expr {$l - $find_dirn}]
+               }
+           } elseif {$fhighlights($l)} {
+               set found $domore
+               break
            }
        }
      }
-     if {$l == -1} {
-       bell
+     if {$found || ($domore && !$moretodo)} {
        unset findcurline
+       unset find_dirn
        notbusy finding
+       set fprogcoord 0
+       adjustprogress
+       if {$found} {
+           findselectline $l
+       } else {
+           bell
+       }
        return 0
      }
-     set findcurline [expr {$l + 1}]
-     return 1
+     if {!$domore} {
+       flushhighlights
+     } else {
+       set findcurline [expr {$l - $find_dirn}]
+     }
+     set n [expr {($findcurline - $findstartline) * $find_dirn - 1}]
+     if {$n < 0} {
+       incr n $numcommits
+     }
+     set fprogcoord [expr {$n * 1.0 / $numcommits}]
+     adjustprogress
+     return $domore
  }
  
  proc findselectline {l} {
-     global findloc commentend ctext findcurline markingmatches
+     global findloc commentend ctext findcurline markingmatches gdttype
  
      set markingmatches 1
      set findcurline $l
@@@ -4337,12 -4430,11 +4430,11 @@@ proc markmatches {canv l str tag matche
  }
  
  proc unmarkmatches {} {
-     global findids markingmatches findcurline
+     global markingmatches
  
      allcanvs delete matches
-     catch {unset findids}
      set markingmatches 0
-     catch {unset findcurline}
+     stopfinding
  }
  
  proc selcanvline {w x y} {
@@@ -4378,7 -4470,7 +4470,7 @@@ proc commit_descriptor {p} 
  # append some text to the ctext widget, and make any SHA1 ID
  # that we know about be a clickable link.
  proc appendwithlinks {text tags} {
-     global ctext commitrow linknum curview
+     global ctext commitrow linknum curview pendinglinks
  
      set start [$ctext index "end - 1c"]
      $ctext insert end $text $tags
        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
-       $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 bind link$linknum <1> \
-           [list selectline $commitrow($curview,$linkid) 1]
+       setlink $linkid link$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} {
@@@ -4444,15 -4568,7 +4568,7 @@@ proc appendrefs {pos ids var} 
            $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 ", "
        }
      }
@@@ -4510,9 -4626,27 +4626,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} {
-     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
      catch {unset pending_select}
      $canv delete hover
      normalline
-     cancel_next_highlight
      unsel_reflist
+     stopfinding
      if {$l < 0 || $l >= $numcommits} return
      set y [expr {$canvy0 + $l * $linespc}]
      set ymax [lindex [$canv cget -scrollregion] 3]
        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]
@@@ -4716,7 -4838,6 +4838,6 @@@ proc unselectline {} 
      catch {unset currentid}
      allcanvs delete secsel
      rhighlight_none
-     cancel_next_highlight
  }
  
  proc reselectline {} {
@@@ -4885,6 -5006,7 +5006,7 @@@ proc showfile {f} 
      $ctext insert end "$f\n" filesep
      $ctext config -state disabled
      $ctext yview $commentend
+     settabs 0
  }
  
  proc getblobline {bf id} {
  }
  
  proc mergediff {id l} {
-     global diffmergeid diffopts mdifffd
+     global diffmergeid mdifffd
      global diffids
      global parentlist
      global limitdiffs viewfiles curview
      set diffmergeid $id
      set diffids $id
      # this doesn't seem to actually affect anything...
-     set env(GIT_DIFF_OPTS) $diffopts
      set cmd [concat | git diff-tree --no-commit-id --cc $id]
      if {$limitdiffs && $viewfiles($curview) ne {}} {
        set cmd [concat $cmd -- $viewfiles($curview)]
      fconfigure $mdf -blocking 0
      set mdifffd($id) $mdf
      set np [llength [lindex $parentlist $l]]
+     settabs $np
      filerun $mdf [list getmergediffline $mdf $id $np]
  }
  
@@@ -5007,6 -5129,7 +5129,7 @@@ proc getmergediffline {mdf id np} 
  proc startdiff {ids} {
      global treediffs diffids treepending diffmergeid nullid nullid2
  
+     settabs 1
      set diffids $ids
      catch {unset diffmergeid}
      if {![info exists treediffs($ids)] ||
  proc path_filter {filter name} {
      foreach p $filter {
        set l [string length $p]
 -      if {[string compare -length $l $p $name] == 0 &&
 -          ([string length $name] == $l || [string index $name $l] eq "/")} {
 -          return 1
 +      if {[string index $p end] eq "/"} {
 +          if {[string compare -length $l $p $name] == 0} {
 +              return 1
 +          }
 +      } else {
 +          if {[string compare -length $l $p $name] == 0 &&
 +              ([string length $name] == $l ||
 +               [string index $name $l] eq "/")} {
 +              return 1
 +          }
        }
      }
      return 0
  }
  
  proc addtocflist {ids} {
 -    global treediffs cflist viewfiles curview limitdiffs
 +    global treediffs
  
 -    if {$limitdiffs && $viewfiles($curview) ne {}} {
 -      set flist {}
 -      foreach f $treediffs($ids) {
 -          if {[path_filter $viewfiles($curview) $f]} {
 -              lappend flist $f
 -          }
 -      }
 -    } else {
 -      set flist $treediffs($ids)
 -    }
 -    add_flist $flist
 +    add_flist $treediffs($ids)
      getblobdiffs $ids
  }
  
@@@ -5097,7 -5223,7 +5220,7 @@@ proc gettreediffs {ids} 
  
  proc gettreediffline {gdtf ids} {
      global treediff treediffs treepending diffids diffmergeid
 -    global cmitmode
 +    global cmitmode viewfiles curview limitdiffs
  
      set nr 0
      while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
        return [expr {$nr >= 1000? 2: 1}]
      }
      close $gdtf
 -    set treediffs($ids) $treediff
 +    if {$limitdiffs && $viewfiles($curview) ne {}} {
 +      set flist {}
 +      foreach f $treediff {
 +          if {[path_filter $viewfiles($curview) $f]} {
 +              lappend flist $f
 +          }
 +      }
 +      set treediffs($ids) $flist
 +    } else {
 +      set treediffs($ids) $treediff
 +    }
      unset treepending
      if {$cmitmode eq "tree"} {
        gettree $diffids
@@@ -5155,12 -5271,11 +5278,11 @@@ proc diffcontextchange {n1 n2 op} 
  }
  
  proc getblobdiffs {ids} {
-     global diffopts blobdifffd diffids env
+     global blobdifffd diffids env
      global diffinhdr treediffs
      global diffcontext
      global limitdiffs viewfiles curview
  
-     set env(GIT_DIFF_OPTS) $diffopts
      set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
      if {$limitdiffs && $viewfiles($curview) ne {}} {
        set cmd [concat $cmd -- $viewfiles($curview)]
@@@ -5330,6 -5445,7 +5452,7 @@@ proc nextfile {} 
  
  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 smarkbot $l
      }
      $ctext delete $first end
+     if {$first eq "1.0"} {
+       catch {unset pendinglinks}
+     }
+ }
+ proc settabs {{firstab {}}} {
+     global firsttabstop tabstop ctext have_tk85
+     if {$firstab ne {} && $have_tk85} {
+       set firsttabstop $firstab
+     }
+     set w [font measure textfont "0"]
+     if {$firsttabstop != 0} {
+       $ctext conf -tabs [list [expr {($firsttabstop + $tabstop) * $w}] \
+                              [expr {($firsttabstop + 2 * $tabstop) * $w}]]
+     } elseif {$have_tk85 || $tabstop != 8} {
+       $ctext conf -tabs [expr {$tabstop * $w}]
+     } else {
+       $ctext conf -tabs {}
+     }
  }
  
  proc incrsearch {name ix op} {
@@@ -5461,11 -5597,11 +5604,11 @@@ proc scrolltext {f0 f1} 
  }
  
  proc setcoords {} {
-     global linespc charspc canvx0 canvy0 mainfont
+     global linespc charspc canvx0 canvy0
      global xspc1 xspc2 lthickness
  
-     set linespc [font metrics $mainfont -linespace]
-     set charspc [font measure $mainfont "m"]
+     set linespc [font metrics mainfont -linespace]
+     set charspc [font measure mainfont "m"]
      set canvy0 [expr {int(3 + 0.5 * $linespc)}]
      set canvx0 [expr {int(3 + 0.5 * $linespc)}]
      set lthickness [expr {int($linespc / 9) + 1}]
@@@ -5490,26 -5626,75 +5633,75 @@@ proc redisplay {} 
      }
  }
  
+ proc parsefont {f n} {
+     global fontattr
+     set fontattr($f,family) [lindex $n 0]
+     set s [lindex $n 1]
+     if {$s eq {} || $s == 0} {
+       set s 10
+     } elseif {$s < 0} {
+       set s [expr {int(-$s / [winfo fpixels . 1p] + 0.5)}]
+     }
+     set fontattr($f,size) $s
+     set fontattr($f,weight) normal
+     set fontattr($f,slant) roman
+     foreach style [lrange $n 2 end] {
+       switch -- $style {
+           "normal" -
+           "bold"   {set fontattr($f,weight) $style}
+           "roman" -
+           "italic" {set fontattr($f,slant) $style}
+       }
+     }
+ }
+ proc fontflags {f {isbold 0}} {
+     global fontattr
+     return [list -family $fontattr($f,family) -size $fontattr($f,size) \
+               -weight [expr {$isbold? "bold": $fontattr($f,weight)}] \
+               -slant $fontattr($f,slant)]
+ }
+ proc fontname {f} {
+     global fontattr
+     set n [list $fontattr($f,family) $fontattr($f,size)]
+     if {$fontattr($f,weight) eq "bold"} {
+       lappend n "bold"
+     }
+     if {$fontattr($f,slant) eq "italic"} {
+       lappend n "italic"
+     }
+     return $n
+ }
  proc incrfont {inc} {
      global mainfont textfont ctext canv phase cflist showrefstop
-     global charspc tabstop
-     global stopped entries
+     global stopped entries fontattr
      unmarkmatches
-     set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
-     set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
+     set s $fontattr(mainfont,size)
+     incr s $inc
+     if {$s < 1} {
+       set s 1
+     }
+     set fontattr(mainfont,size) $s
+     font config mainfont -size $s
+     font config mainfontbold -size $s
+     set mainfont [fontname mainfont]
+     set s $fontattr(textfont,size)
+     incr s $inc
+     if {$s < 1} {
+       set s 1
+     }
+     set fontattr(textfont,size) $s
+     font config textfont -size $s
+     font config textfontbold -size $s
+     set textfont [fontname textfont]
      setcoords
-     $ctext conf -font $textfont -tabs "[expr {$tabstop * $charspc}]"
-     $cflist conf -font $textfont
-     $ctext tag conf filesep -font [concat $textfont bold]
-     foreach e $entries {
-       $e conf -font $mainfont
-     }
-     if {$phase eq "getcommits"} {
-       $canv itemconf textitems -font $mainfont
-     }
-     if {[info exists showrefstop] && [winfo exists $showrefstop]} {
-       $showrefstop.list conf -font $mainfont
-     }
+     settabs
      redisplay
  }
  
@@@ -5620,7 -5805,7 +5812,7 @@@ proc lineleave {id} 
  proc linehover {} {
      global hoverx hovery hoverid hovertimer
      global canv linespc lthickness
-     global commitinfo mainfont
+     global commitinfo
  
      set text [lindex $commitinfo($hoverid) 0]
      set ymax [lindex [$canv cget -scrollregion] 3]
      set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
      set x0 [expr {$x - 2 * $lthickness}]
      set y0 [expr {$y - 2 * $lthickness}]
-     set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
+     set x1 [expr {$x + [font measure mainfont $text] + 2 * $lthickness}]
      set y1 [expr {$y + $linespc + 2 * $lthickness}]
      set t [$canv create rectangle $x0 $y0 $x1 $y1 \
               -fill \#ffff80 -outline black -width 1 -tags hover]
      $canv raise $t
      set t [$canv create text $x $y -anchor nw -text $text -tags hover \
-              -font $mainfont]
+              -font mainfont]
      $canv raise $t
  }
  
@@@ -5674,7 -5859,7 +5866,7 @@@ proc arrowjump {id n y} 
  }
  
  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
      # 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 }
+     settabs 0
      $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"
            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]]
@@@ -5762,6 -5945,7 +5952,7 @@@ proc rowmenu {x y id} 
      global rowctxmenu commitrow selectedline rowmenuid curview
      global nullid nullid2 fakerowmenu mainhead
  
+     stopfinding
      set rowmenuid $id
      if {![info exists selectedline]
        || $commitrow($curview,$id) eq $selectedline} {
@@@ -5804,16 -5988,13 +5995,13 @@@ proc doseldiff {oldid newid} 
      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 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"
@@@ -5894,6 -6075,8 +6082,8 @@@ proc mkpatchgo {} 
      set newid [$patchtop.tosha1 get]
      set fname [$patchtop.fname get]
      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"
@@@ -5974,7 -6157,7 +6164,7 @@@ proc domktag {} 
  
  proc redrawtags {id} {
      global canv linehtag commitrow idpos selectedline curview
-     global mainfont canvxmax iddrawn
+     global canvxmax iddrawn
  
      if {![info exists commitrow($curview,$id)]} return
      if {![info exists iddrawn($id)]} return
      set xt [eval drawtags $id $idpos($id)]
      $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2]
      set text [$canv itemcget $linehtag($commitrow($curview,$id)) -text]
-     set xr [expr {$xt + [font measure $mainfont $text]}]
+     set xr [expr {$xt + [font measure mainfont $text]}]
      if {$xr > $canvxmax} {
        set canvxmax $xr
        setcanvscroll
@@@ -6126,7 -6309,7 +6316,7 @@@ proc cherrypick {} 
                        included in branch $mainhead -- really re-apply it?"]
        if {!$ok} return
      }
-     nowbusy cherrypick
+     nowbusy cherrypick "Cherry-picking"
      update
      # Unfortunately git-cherry-pick writes stuff to stderr even when
      # no error occurs, and exec takes that as an indication of error...
  
  proc resethead {} {
      global mainheadid mainhead rowmenuid confirm_ok resettype
-     global showlocalchanges
  
      set confirm_ok 0
      set w ".confirmreset"
        error_popup $err
      } else {
        dohidelocalchanges
-       set w ".resetprogress"
-       filerun $fd [list readresetstat $fd $w]
-       toplevel $w
-       wm transient $w
-       wm title $w "Reset progress"
-       message $w.m -text "Reset in progress, please wait..." \
-           -justify center -aspect 1000
-       pack $w.m -side top -fill x -padx 20 -pady 5
-       canvas $w.c -width 150 -height 20 -bg white
-       $w.c create rect 0 0 0 20 -fill green -tags rect
-       pack $w.c -side top -fill x -padx 20 -pady 5 -expand 1
-       nowbusy reset
+       filerun $fd [list readresetstat $fd]
+       nowbusy reset "Resetting"
      }
  }
  
- proc readresetstat {fd w} {
-     global mainhead mainheadid showlocalchanges
+ proc readresetstat {fd} {
+     global mainhead mainheadid showlocalchanges rprogcoord
  
      if {[gets $fd line] >= 0} {
        if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
-           set x [expr {($m * 150) / $n}]
-           $w.c coords rect 0 0 $x 20
+           set rprogcoord [expr {1.0 * $m / $n}]
+           adjustprogress
        }
        return 1
      }
-     destroy $w
+     set rprogcoord 0
+     adjustprogress
      notbusy reset
      if {[catch {close $fd} err]} {
        error_popup $err
  proc headmenu {x y id head} {
      global headmenuid headmenuhead headctxmenu mainhead
  
+     stopfinding
      set headmenuid $id
      set headmenuhead $head
      set state normal
@@@ -6259,7 -6433,7 +6440,7 @@@ proc cobranch {} 
  
      # check the tree is clean first??
      set oldmainhead $mainhead
-     nowbusy checkout
+     nowbusy checkout "Checking out"
      update
      dohidelocalchanges
      if {[catch {
@@@ -6315,8 -6489,8 +6496,8 @@@ proc rmbranch {} 
  
  # Display a list of tags and heads
  proc showrefs {} {
-     global showrefstop bgcolor fgcolor selectbgcolor mainfont
-     global bglist fglist uifont reflistfilter reflist maincursor
+     global showrefstop bgcolor fgcolor selectbgcolor
+     global bglist fglist reflistfilter reflist maincursor
  
      set top .showrefs
      set showrefstop $top
      toplevel $top
      wm title $top "Tags and heads: [file tail [pwd]]"
      text $top.list -background $bgcolor -foreground $fgcolor \
-       -selectbackground $selectbgcolor -font $mainfont \
+       -selectbackground $selectbgcolor -font mainfont \
        -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
        -width 30 -height 20 -cursor $maincursor \
        -spacing1 1 -spacing3 1 -state disabled
      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
+     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
+       -font uifont
      grid $top.close -
      grid columnconfigure $top 0 -weight 1
      grid rowconfigure $top 0 -weight 1
@@@ -6471,25 -6645,59 +6652,59 @@@ proc refill_reflist {} 
  
  # Stuff for finding nearby tags
  proc getallcommits {} {
-     global allcommits allids nbmp nextarc seeds
+     global allcommits nextarc seeds allccache allcwait cachedarcs allcupdate
+     global idheads idtags idotherrefs allparents tagobjid
  
      if {![info exists allcommits]} {
-       set allids {}
-       set nbmp 0
        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
      }
  
-     set cmd [concat | git rev-list --all --parents]
-     foreach id $seeds {
-       lappend cmd "^$id"
+     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
  # 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 seeds allcommits
+     global seeds allcommits cachedarcs allcupdate
+     
      set nid 0
      while {[incr nid] <= 1000 && [gets $fd line] >= 0} {
        set id [lindex $line 0]
            # 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)]} {
                continue
            }
        }
-       incr nbmp
        foreach a $arcnos($id) {
            lappend arcids($a) $id
            set arcend($a) $id
      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 {$cacheok} {
+           run savecache
+       }
      }
      dispneartags 0
      return 0
@@@ -6616,7 -6842,7 +6849,7 @@@ proc recalcarc {a} 
  }
  
  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)
        set growing($na) 1
        unset growing($a)
      }
-     incr nbmp
  
      foreach id $tail {
        if {[llength $arcnos($id)] == 1} {
  # 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 seeds allcommits
  
      if {![info exists allcommits] || ![info exists arcnos($p)]} return
-     lappend allids $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
      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} {
@@@ -7394,6 -7783,7 +7790,7 @@@ proc showtag {tag isnew} 
      }
      $ctext conf -state normal
      clear_ctext
+     settabs 0
      set linknum 0
      if {![info exists tagcontents($tag)]} {
        catch {
@@@ -7417,8 -7807,132 +7814,132 @@@ proc doquit {} 
      destroy .
  }
  
+ proc mkfontdisp {font top which} {
+     global fontattr fontpref $font
+     set fontpref($font) [set $font]
+     button $top.${font}but -text $which -font optionfont \
+       -command [list choosefont $font $which]
+     label $top.$font -relief flat -font $font \
+       -text $fontattr($font,family) -justify left
+     grid x $top.${font}but $top.$font -sticky w
+ }
+ proc choosefont {font which} {
+     global fontparam fontlist fonttop fontattr
+     set fontparam(which) $which
+     set fontparam(font) $font
+     set fontparam(family) [font actual $font -family]
+     set fontparam(size) $fontattr($font,size)
+     set fontparam(weight) $fontattr($font,weight)
+     set fontparam(slant) $fontattr($font,slant)
+     set top .gitkfont
+     set fonttop $top
+     if {![winfo exists $top]} {
+       font create sample
+       eval font config sample [font actual $font]
+       toplevel $top
+       wm title $top "Gitk font chooser"
+       label $top.l -textvariable fontparam(which) -font uifont
+       pack $top.l -side top
+       set fontlist [lsort [font families]]
+       frame $top.f
+       listbox $top.f.fam -listvariable fontlist \
+           -yscrollcommand [list $top.f.sb set]
+       bind $top.f.fam <<ListboxSelect>> selfontfam
+       scrollbar $top.f.sb -command [list $top.f.fam yview]
+       pack $top.f.sb -side right -fill y
+       pack $top.f.fam -side left -fill both -expand 1
+       pack $top.f -side top -fill both -expand 1
+       frame $top.g
+       spinbox $top.g.size -from 4 -to 40 -width 4 \
+           -textvariable fontparam(size) \
+           -validatecommand {string is integer -strict %s}
+       checkbutton $top.g.bold -padx 5 \
+           -font {{Times New Roman} 12 bold} -text "B" -indicatoron 0 \
+           -variable fontparam(weight) -onvalue bold -offvalue normal
+       checkbutton $top.g.ital -padx 5 \
+           -font {{Times New Roman} 12 italic} -text "I" -indicatoron 0  \
+           -variable fontparam(slant) -onvalue italic -offvalue roman
+       pack $top.g.size $top.g.bold $top.g.ital -side left
+       pack $top.g -side top
+       canvas $top.c -width 150 -height 50 -border 2 -relief sunk \
+           -background white
+       $top.c create text 100 25 -anchor center -text $which -font sample \
+           -fill black -tags text
+       bind $top.c <Configure> [list centertext $top.c]
+       pack $top.c -side top -fill x
+       frame $top.buts
+       button $top.buts.ok -text "OK" -command fontok -default active \
+           -font uifont
+       button $top.buts.can -text "Cancel" -command fontcan -default normal \
+           -font uifont
+       grid $top.buts.ok $top.buts.can
+       grid columnconfigure $top.buts 0 -weight 1 -uniform a
+       grid columnconfigure $top.buts 1 -weight 1 -uniform a
+       pack $top.buts -side bottom -fill x
+       trace add variable fontparam write chg_fontparam
+     } else {
+       raise $top
+       $top.c itemconf text -text $which
+     }
+     set i [lsearch -exact $fontlist $fontparam(family)]
+     if {$i >= 0} {
+       $top.f.fam selection set $i
+       $top.f.fam see $i
+     }
+ }
+ proc centertext {w} {
+     $w coords text [expr {[winfo width $w] / 2}] [expr {[winfo height $w] / 2}]
+ }
+ proc fontok {} {
+     global fontparam fontpref prefstop
+     set f $fontparam(font)
+     set fontpref($f) [list $fontparam(family) $fontparam(size)]
+     if {$fontparam(weight) eq "bold"} {
+       lappend fontpref($f) "bold"
+     }
+     if {$fontparam(slant) eq "italic"} {
+       lappend fontpref($f) "italic"
+     }
+     set w $prefstop.$f
+     $w conf -text $fontparam(family) -font $fontpref($f)
+       
+     fontcan
+ }
+ proc fontcan {} {
+     global fonttop fontparam
+     if {[info exists fonttop]} {
+       catch {destroy $fonttop}
+       catch {font delete sample}
+       unset fonttop
+       unset fontparam
+     }
+ }
+ proc selfontfam {} {
+     global fonttop fontparam
+     set i [$fonttop.f.fam curselection]
+     if {$i ne {}} {
+       set fontparam(family) [$fonttop.f.fam get $i]
+     }
+ }
+ proc chg_fontparam {v sub op} {
+     global fontparam
+     font config sample -$sub $fontparam($sub)
+ }
  proc doprefs {} {
-     global maxwidth maxgraphpct diffopts
+     global maxwidth maxgraphpct
      global oldprefs prefstop showneartags showlocalchanges
      global bgcolor fgcolor ctext diffcolors selectbgcolor
      global uifont tabstop limitdiffs
        raise $top
        return
      }
-     foreach v {maxwidth maxgraphpct diffopts showneartags showlocalchanges \
+     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
                   limitdiffs tabstop} {
        set oldprefs($v) [set $v]
      }
      toplevel $top
      wm title $top "Gitk preferences"
      label $top.ldisp -text "Commit list display options"
-     $top.ldisp configure -font $uifont
+     $top.ldisp configure -font uifont
      grid $top.ldisp - -sticky w -pady 10
      label $top.spacer -text " "
      label $top.maxwidthl -text "Maximum graph width (lines)" \
      grid x $top.showlocal -sticky w
  
      label $top.ddisp -text "Diff display options"
-     $top.ddisp configure -font $uifont
+     $top.ddisp configure -font uifont
      grid $top.ddisp - -sticky w -pady 10
-     label $top.diffoptl -text "Options for diff program" \
-       -font optionfont
-     entry $top.diffopt -width 20 -textvariable diffopts
-     grid x $top.diffoptl $top.diffopt -sticky w
      label $top.tabstopl -text "Tab spacing" -font optionfont
      spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
      grid x $top.tabstopl $top.tabstop -sticky w
      grid x $top.ldiff -sticky w
  
      label $top.cdisp -text "Colors: press to choose"
-     $top.cdisp configure -font $uifont
+     $top.cdisp configure -font uifont
      grid $top.cdisp - -sticky w -pady 10
      label $top.bg -padx 40 -relief sunk -background $bgcolor
      button $top.bgbut -text "Background" -font optionfont \
        -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg]
      grid x $top.selbgbut $top.selbgsep -sticky w
  
+     label $top.cfont -text "Fonts: press to choose"
+     $top.cfont configure -font uifont
+     grid $top.cfont - -sticky w -pady 10
+     mkfontdisp mainfont $top "Main font"
+     mkfontdisp textfont $top "Diff display font"
+     mkfontdisp uifont $top "User interface font"
      frame $top.buts
      button $top.buts.ok -text "OK" -command prefsok -default active
-     $top.buts.ok configure -font $uifont
+     $top.buts.ok configure -font uifont
      button $top.buts.can -text "Cancel" -command prefscan -default normal
-     $top.buts.can configure -font $uifont
+     $top.buts.can configure -font uifont
      grid $top.buts.ok $top.buts.can
      grid columnconfigure $top.buts 0 -weight 1 -uniform a
      grid columnconfigure $top.buts 1 -weight 1 -uniform a
@@@ -7560,23 -8077,46 +8084,46 @@@ proc setfg {c} 
  proc prefscan {} {
      global oldprefs prefstop
  
-     foreach v {maxwidth maxgraphpct diffopts showneartags showlocalchanges \
+     foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
                   limitdiffs tabstop} {
        global $v
        set $v $oldprefs($v)
      }
      catch {destroy $prefstop}
      unset prefstop
+     fontcan
  }
  
  proc prefsok {} {
      global maxwidth maxgraphpct
      global oldprefs prefstop showneartags showlocalchanges
-     global charspc ctext tabstop limitdiffs treediffs
+     global fontpref mainfont textfont uifont
 -    global limitdiffs
++    global limitdiffs treediffs
  
      catch {destroy $prefstop}
      unset prefstop
-     $ctext configure -tabs "[expr {$tabstop * $charspc}]"
+     fontcan
+     set fontchanged 0
+     if {$mainfont ne $fontpref(mainfont)} {
+       set mainfont $fontpref(mainfont)
+       parsefont mainfont $mainfont
+       eval font configure mainfont [fontflags mainfont]
+       eval font configure mainfontbold [fontflags mainfont 1]
+       setcoords
+       set fontchanged 1
+     }
+     if {$textfont ne $fontpref(textfont)} {
+       set textfont $fontpref(textfont)
+       parsefont textfont $textfont
+       eval font configure textfont [fontflags textfont]
+       eval font configure textfontbold [fontflags textfont 1]
+     }
+     if {$uifont ne $fontpref(uifont)} {
+       set uifont $fontpref(uifont)
+       parsefont uifont $uifont
+       eval font configure uifont [fontflags uifont]
+     }
+     settabs
      if {$showlocalchanges != $oldprefs(showlocalchanges)} {
        if {$showlocalchanges} {
            doshowlocalchanges
            dohidelocalchanges
        }
      }
-     if {$maxwidth != $oldprefs(maxwidth)
 +    if {$limitdiffs != $oldprefs(limitdiffs)} {
 +      # treediffs elements are limited by path
 +      catch {unset treediffs}
 +    }
+     if {$fontchanged || $maxwidth != $oldprefs(maxwidth)
        || $maxgraphpct != $oldprefs(maxgraphpct)} {
        redisplay
      } elseif {$showneartags != $oldprefs(showneartags) ||
@@@ -7887,7 -8423,6 +8434,6 @@@ if {[catch {package require Tk 8.4} err
  
  # defaults...
  set datemode 0
- set diffopts "-U 5 -p"
  set wrcomcmd "git diff-tree --stdin -p --pretty"
  
  set gitencoding {}
@@@ -7911,9 -8446,9 +8457,9 @@@ set maxgraphpct 5
  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
@@@ -7934,6 -8469,17 +8480,17 @@@ catch {source ~/.gitk
  
  font create optionfont -family sans-serif -size -12
  
+ parsefont mainfont $mainfont
+ eval font create mainfont [fontflags mainfont]
+ eval font create mainfontbold [fontflags mainfont 1]
+ parsefont textfont $textfont
+ eval font create textfont [fontflags textfont]
+ eval font create textfontbold [fontflags textfont 1]
+ parsefont uifont $uifont
+ eval font create uifont [fontflags uifont]
  # check that we can find a .git directory somewhere...
  if {[catch {set gitdir [gitdir]}]} {
      show_error {} . "Cannot find a git repository here."
@@@ -8033,6 -8579,7 +8590,7 @@@ if {$mergeonly} 
  set nullid "0000000000000000000000000000000000000000"
  set nullid2 "0000000000000000000000000000000000000001"
  
+ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
  
  set runq {}
  set history {}
@@@ -8040,18 -8587,23 +8598,23 @@@ set historyindex 
  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 optim_delay 16
+ set linkentercount 0
+ set need_redisplay 0
+ set nrows_drawn 0
+ set firsttabstop 0
  
  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) {}
@@@ -8060,7 -8612,6 +8623,6 @@@ set cmdlineok 
  set stopped 0
  set stuffsaved 0
  set patchnum 0
- set lookingforhead 0
  set localirow -1
  set localfrow -1
  set lserial 0