lstat_cache(): small cleanup and optimisation
[gitweb.git] / gitk-git / gitk
index 3353f4a2717ceb72634b9311985b5570f06fe560..dc2a439618ffd92a92d9ca954a8597ba31875dab 100644 (file)
@@ -155,18 +155,16 @@ proc parseviewargs {n arglist} {
                set origargs [lreplace $origargs $i $i]
                incr i -1
            }
-           # These request or affect diff output, which we don't want.
-           # Some could be used to set our defaults for diff display.
            "-[puabwcrRBMC]" -
            "--no-renames" - "--full-index" - "--binary" - "--abbrev=*" -
            "--find-copies-harder" - "-l*" - "--ext-diff" - "--no-ext-diff" -
            "--src-prefix=*" - "--dst-prefix=*" - "--no-prefix" -
            "-O*" - "--text" - "--full-diff" - "--ignore-space-at-eol" -
            "--ignore-space-change" - "-U*" - "--unified=*" {
+               # These request or affect diff output, which we don't want.
+               # Some could be used to set our defaults for diff display.
                lappend diffargs $arg
            }
-           # These cause our parsing of git log's output to fail, or else
-           # they're options we want to set ourselves, so ignore them.
            "--raw" - "--patch-with-raw" - "--patch-with-stat" -
            "--name-only" - "--name-status" - "--color" - "--color-words" -
            "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" -
@@ -174,36 +172,34 @@ proc parseviewargs {n arglist} {
            "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" -
            "--timestamp" - "relative-date" - "--date=*" - "--stdin" -
            "--objects" - "--objects-edge" - "--reverse" {
+               # These cause our parsing of git log's output to fail, or else
+               # they're options we want to set ourselves, so ignore them.
            }
-           # These are harmless, and some are even useful
            "--stat=*" - "--numstat" - "--shortstat" - "--summary" -
            "--check" - "--exit-code" - "--quiet" - "--topo-order" -
            "--full-history" - "--dense" - "--sparse" -
            "--follow" - "--left-right" - "--encoding=*" {
+               # These are harmless, and some are even useful
                lappend glflags $arg
            }
-           # These mean that we get a subset of the commits
            "--diff-filter=*" - "--no-merges" - "--unpacked" -
            "--max-count=*" - "--skip=*" - "--since=*" - "--after=*" -
            "--until=*" - "--before=*" - "--max-age=*" - "--min-age=*" -
            "--author=*" - "--committer=*" - "--grep=*" - "-[iE]" -
            "--remove-empty" - "--first-parent" - "--cherry-pick" -
-           "-S*" - "--pickaxe-all" - "--pickaxe-regex" - {
+           "-S*" - "--pickaxe-all" - "--pickaxe-regex" {
+               # These mean that we get a subset of the commits
                set filtered 1
                lappend glflags $arg
            }
-           # This appears to be the only one that has a value as a
-           # separate word following it
            "-n" {
+               # This appears to be the only one that has a value as a
+               # separate word following it
                set filtered 1
                set nextisval 1
                lappend glflags $arg
            }
-           "--not" {
-               set notflag [expr {!$notflag}]
-               lappend revargs $arg
-           }
-           "--all" {
+           "--not" - "--all" {
                lappend revargs $arg
            }
            "--merge" {
@@ -211,8 +207,8 @@ proc parseviewargs {n arglist} {
                # git rev-parse doesn't understand --merge
                lappend revargs --gitk-symmetric-diff-marker MERGE_HEAD...HEAD
            }
-           # Other flag arguments including -<n>
            "-*" {
+               # Other flag arguments including -<n>
                if {[string is digit -strict [string range $arg 1 end]]} {
                    set filtered 1
                } else {
@@ -222,8 +218,8 @@ proc parseviewargs {n arglist} {
                }
                lappend glflags $arg
            }
-           # Non-flag arguments specify commits or ranges of commits
            default {
+               # Non-flag arguments specify commits or ranges of commits
                if {[string match "*...*" $arg]} {
                    lappend revargs --gitk-symmetric-diff-marker
                }
@@ -309,7 +305,7 @@ proc start_rev_list {view} {
     global viewargs viewargscmd viewfiles vfilelimit
     global showlocalchanges
     global viewactive viewinstances vmergeonly
-    global mainheadid
+    global mainheadid viewmainheadid viewmainheadid_orig
     global vcanopt vflags vrevs vorigargs
 
     set startmsecs [clock clicks -milliseconds]
@@ -367,8 +363,13 @@ proc start_rev_list {view} {
     }
     set i [reg_instance $fd]
     set viewinstances($view) [list $i]
-    if {$showlocalchanges && $mainheadid ne {}} {
-       interestedin $mainheadid dodiffindex
+    set viewmainheadid($view) $mainheadid
+    set viewmainheadid_orig($view) $mainheadid
+    if {$files ne {} && $mainheadid ne {}} {
+       get_viewmainhead $view
+    }
+    if {$showlocalchanges && $viewmainheadid($view) ne {}} {
+       interestedin $viewmainheadid($view) dodiffindex
     }
     fconfigure $fd -blocking 0 -translation lf -eofchar {}
     if {$tclencoding != {}} {
@@ -446,22 +447,26 @@ proc updatecommits {} {
     global curview vcanopt vorigargs vfilelimit viewinstances
     global viewactive viewcomplete tclencoding
     global startmsecs showneartags showlocalchanges
-    global mainheadid pending_select
+    global mainheadid viewmainheadid viewmainheadid_orig pending_select
     global isworktree
     global varcid vposids vnegids vflags vrevs
 
     set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
-    set oldmainid $mainheadid
     rereadrefs
-    if {$showlocalchanges} {
-       if {$mainheadid ne $oldmainid} {
+    set view $curview
+    if {$mainheadid ne $viewmainheadid_orig($view)} {
+       if {$showlocalchanges} {
            dohidelocalchanges
        }
-       if {[commitinview $mainheadid $curview]} {
-           dodiffindex
+       set viewmainheadid($view) $mainheadid
+       set viewmainheadid_orig($view) $mainheadid
+       if {$vfilelimit($view) ne {}} {
+           get_viewmainhead $view
        }
     }
-    set view $curview
+    if {$showlocalchanges} {
+       doshowlocalchanges
+    }
     if {$vcanopt($view)} {
        set oldpos $vposids($view)
        set oldneg $vnegids($view)
@@ -1596,13 +1601,14 @@ proc parsecommit {id contents listed} {
     set header [string range $contents 0 [expr {$hdrend - 1}]]
     set comment [string range $contents [expr {$hdrend + 2}] end]
     foreach line [split $header "\n"] {
+       set line [split $line " "]
        set tag [lindex $line 0]
        if {$tag == "author"} {
            set audate [lindex $line end-1]
-           set auname [lrange $line 1 end-2]
+           set auname [join [lrange $line 1 end-2] " "]
        } elseif {$tag == "committer"} {
            set comdate [lindex $line end-1]
-           set comname [lrange $line 1 end-2]
+           set comname [join [lrange $line 1 end-2] " "]
        }
     }
     set headline {}
@@ -1906,6 +1912,9 @@ proc makewindow {} {
            {mc "Reload" command reloadcommits -accelerator Meta1-F5}
            {mc "Reread references" command rereadrefs}
            {mc "List references" command showrefs -accelerator F2}
+           {xx "" separator}
+           {mc "Start git gui" command {exec git gui &}}
+           {xx "" separator}
            {mc "Quit" command doquit -accelerator Meta1-Q}
        }}
        {mc "Edit" cascade {
@@ -2271,7 +2280,7 @@ proc makewindow {} {
     bindkey b prevfile
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
-    bindkey / {dofind 1 1}
+    bindkey / {focus $fstring}
     bindkey <Key-Return> {dofind 1 1}
     bindkey ? {dofind -1 1}
     bindkey f nextfile
@@ -2652,7 +2661,7 @@ proc keys {} {
 [mc "<%s-F>            Find" $M1T]
 [mc "<%s-G>            Move to next find hit" $M1T]
 [mc "<Return>  Move to next find hit"]
-[mc "/         Move to next find hit, or redo find"]
+[mc "/         Focus the search box"]
 [mc "?         Move to previous find hit"]
 [mc "f         Scroll diff view to next file"]
 [mc "<%s-S>            Search for next hit in diff view" $M1T]
@@ -3310,8 +3319,27 @@ proc index_sha1 {fname} {
     return {}
 }
 
+# Turn an absolute path into one relative to the current directory
+proc make_relative {f} {
+    set elts [file split $f]
+    set here [file split [pwd]]
+    set ei 0
+    set hi 0
+    set res {}
+    foreach d $here {
+       if {$ei < $hi || $ei >= [llength $elts] || [lindex $elts $ei] ne $d} {
+           lappend res ".."
+       } else {
+           incr ei
+       }
+       incr hi
+    }
+    set elts [concat $res [lrange $elts $ei end]]
+    return [eval file join $elts]
+}
+
 proc external_blame {parent_idx {line {}}} {
-    global flist_menu_file
+    global flist_menu_file gitdir
     global nullid nullid2
     global parentlist selectedline currentid
 
@@ -3330,7 +3358,12 @@ proc external_blame {parent_idx {line {}}} {
     if {$line ne {} && $line > 1} {
        lappend cmdline "--line=$line"
     }
-    lappend cmdline $base_commit $flist_menu_file
+    set f [file join [file dirname $gitdir] $flist_menu_file]
+    # Unfortunately it seems git gui blame doesn't like
+    # being given an absolute path...
+    set f [make_relative $f]
+    lappend cmdline $base_commit $f
+    puts "cmdline={$cmdline}"
     if {[catch {eval exec $cmdline &} err]} {
        error_popup "[mc "git gui blame: command failed:"] $err"
     }
@@ -3374,6 +3407,8 @@ proc show_line_source {} {
                    error_popup [mc "Error reading index: %s" $err]
                    return
                }
+           } else {
+               set id $parents($curview,$currentid)
            }
        } else {
            set id [lindex $parents($curview,$currentid) $pi]
@@ -3390,13 +3425,14 @@ proc show_line_source {} {
     } else {
        lappend blameargs $id
     }
-    lappend blameargs -- $flist_menu_file
+    lappend blameargs -- [file join [file dirname $gitdir] $flist_menu_file]
     if {[catch {
        set f [open $blameargs r]
     } err]} {
        error_popup [mc "Couldn't start git blame: %s" $err]
        return
     }
+    nowbusy blaming [mc "Searching"]
     fconfigure $f -blocking 0
     set i [reg_instance $f]
     set blamestuff($i) {}
@@ -3410,6 +3446,7 @@ proc stopblaming {} {
     if {[info exists blameinst]} {
        stop_instance $blameinst
        unset blameinst
+       notbusy blaming
     }
 }
 
@@ -3424,6 +3461,7 @@ proc read_line_source {fd inst} {
     }
     unset commfd($inst)
     unset blameinst
+    notbusy blaming
     fconfigure $fd -blocking 1
     if {[catch {close $fd} err]} {
        error_popup [mc "Error running git blame: %s" $err]
@@ -4004,31 +4042,31 @@ proc ishighlighted {id} {
     return 0
 }
 
-proc bolden {row font} {
-    global canv linehtag selectedline boldrows need_redisplay
+proc bolden {id font} {
+    global canv linehtag currentid boldids need_redisplay
 
     # need_redisplay = 1 means the display is stale and about to be redrawn
     if {$need_redisplay} return
-    lappend boldrows $row
-    $canv itemconf $linehtag($row) -font $font
-    if {$row == $selectedline} {
+    lappend boldids $id
+    $canv itemconf $linehtag($id) -font $font
+    if {[info exists currentid] && $id eq $currentid} {
        $canv delete secsel
-       set t [eval $canv create rect [$canv bbox $linehtag($row)] \
+       set t [eval $canv create rect [$canv bbox $linehtag($id)] \
                   -outline {{}} -tags secsel \
                   -fill [$canv cget -selectbackground]]
        $canv lower $t
     }
 }
 
-proc bolden_name {row font} {
-    global canv2 linentag selectedline boldnamerows need_redisplay
+proc bolden_name {id font} {
+    global canv2 linentag currentid boldnameids need_redisplay
 
     if {$need_redisplay} return
-    lappend boldnamerows $row
-    $canv2 itemconf $linentag($row) -font $font
-    if {$row == $selectedline} {
+    lappend boldnameids $id
+    $canv2 itemconf $linentag($id) -font $font
+    if {[info exists currentid] && $id eq $currentid} {
        $canv2 delete secsel
-       set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \
+       set t [eval $canv2 create rect [$canv2 bbox $linentag($id)] \
                   -outline {{}} -tags secsel \
                   -fill [$canv2 cget -selectbackground]]
        $canv2 lower $t
@@ -4036,17 +4074,17 @@ proc bolden_name {row font} {
 }
 
 proc unbolden {} {
-    global boldrows
+    global boldids
 
     set stillbold {}
-    foreach row $boldrows {
-       if {![ishighlighted [commitonrow $row]]} {
-           bolden $row mainfont
+    foreach id $boldids {
+       if {![ishighlighted $id]} {
+           bolden $id mainfont
        } else {
-           lappend stillbold $row
+           lappend stillbold $id
        }
     }
-    set boldrows $stillbold
+    set boldids $stillbold
 }
 
 proc addvhighlight {n} {
@@ -4087,7 +4125,7 @@ proc vhighlightmore {} {
            set row [rowofcommit $id]
            if {$r0 <= $row && $row <= $r1} {
                if {![highlighted $row]} {
-                   bolden $row mainfontbold
+                   bolden $id mainfontbold
                }
                set vhighlights($id) 1
            }
@@ -4102,7 +4140,7 @@ proc askvhighlight {row id} {
 
     if {[commitinview $id $hlview]} {
        if {[info exists iddrawn($id)] && ![ishighlighted $id]} {
-           bolden $row mainfontbold
+           bolden $id mainfontbold
        }
        set vhighlights($id) 1
     } else {
@@ -4112,7 +4150,7 @@ proc askvhighlight {row id} {
 
 proc hfiles_change {} {
     global highlight_files filehighlight fhighlights fh_serial
-    global highlight_paths gdttype
+    global highlight_paths
 
     if {[info exists filehighlight]} {
        # delete previous highlights
@@ -4170,15 +4208,15 @@ proc find_change {name ix op} {
 }
 
 proc findcom_change args {
-    global nhighlights boldnamerows
+    global nhighlights boldnameids
     global findpattern findtype findstring gdttype
 
     stopfinding
     # delete previous highlights, if any
-    foreach row $boldnamerows {
-       bolden_name $row mainfont
+    foreach id $boldnameids {
+       bolden_name $id mainfont
     }
-    set boldnamerows {}
+    set boldnameids {}
     catch {unset nhighlights}
     unbolden
     unmarkmatches
@@ -4267,9 +4305,8 @@ proc readfhighlight {} {
        set fhl_list [lrange $fhl_list [expr {$i+1}] end]
        if {$line eq {}} continue
        if {![commitinview $line $curview]} continue
-       set row [rowofcommit $line]
        if {[info exists iddrawn($line)] && ![ishighlighted $line]} {
-           bolden $row mainfontbold
+           bolden $line mainfontbold
        }
        set fhighlights($line) 1
     }
@@ -4321,9 +4358,9 @@ proc askfindhighlight {row id} {
     }
     if {$isbold && [info exists iddrawn($id)]} {
        if {![ishighlighted $id]} {
-           bolden $row mainfontbold
+           bolden $id mainfontbold
            if {$isbold > 1} {
-               bolden_name $row mainfontbold
+               bolden_name $id mainfontbold
            }
        }
        if {$markingmatches} {
@@ -4343,15 +4380,15 @@ proc markrowmatches {row id} {
     if {$findloc eq [mc "All fields"] || $findloc eq [mc "Headline"]} {
        set m [findmatches $headline]
        if {$m ne {}} {
-           markmatches $canv $row $headline $linehtag($row) $m \
-               [$canv itemcget $linehtag($row) -font] $row
+           markmatches $canv $row $headline $linehtag($id) $m \
+               [$canv itemcget $linehtag($id) -font] $row
        }
     }
     if {$findloc eq [mc "All fields"] || $findloc eq [mc "Author"]} {
        set m [findmatches $author]
        if {$m ne {}} {
-           markmatches $canv2 $row $author $linentag($row) $m \
-               [$canv2 itemcget $linentag($row) -font] $row
+           markmatches $canv2 $row $author $linentag($id) $m \
+               [$canv2 itemcget $linentag($id) -font] $row
        }
     }
 }
@@ -4476,7 +4513,7 @@ proc askrelhighlight {row id} {
     }
     if {[info exists iddrawn($id)]} {
        if {$isbold && ![ishighlighted $id]} {
-           bolden $row mainfontbold
+           bolden $id mainfontbold
        }
     }
     set rhighlights($id) $isbold
@@ -4644,14 +4681,56 @@ proc layoutmore {} {
     drawvisible
 }
 
+# With path limiting, we mightn't get the actual HEAD commit,
+# so ask git rev-list what is the first ancestor of HEAD that
+# touches a file in the path limit.
+proc get_viewmainhead {view} {
+    global viewmainheadid vfilelimit viewinstances mainheadid
+
+    catch {
+       set rfd [open [concat | git rev-list -1 $mainheadid \
+                          -- $vfilelimit($view)] r]
+       set j [reg_instance $rfd]
+       lappend viewinstances($view) $j
+       fconfigure $rfd -blocking 0
+       filerun $rfd [list getviewhead $rfd $j $view]
+       set viewmainheadid($curview) {}
+    }
+}
+
+# git rev-list should give us just 1 line to use as viewmainheadid($view)
+proc getviewhead {fd inst view} {
+    global viewmainheadid commfd curview viewinstances showlocalchanges
+
+    set id {}
+    if {[gets $fd line] < 0} {
+       if {![eof $fd]} {
+           return 1
+       }
+    } elseif {[string length $line] == 40 && [string is xdigit $line]} {
+       set id $line
+    }
+    set viewmainheadid($view) $id
+    close $fd
+    unset commfd($inst)
+    set i [lsearch -exact $viewinstances($view) $inst]
+    if {$i >= 0} {
+       set viewinstances($view) [lreplace $viewinstances($view) $i $i]
+    }
+    if {$showlocalchanges && $id ne {} && $view == $curview} {
+       doshowlocalchanges
+    }
+    return 0
+}
+
 proc doshowlocalchanges {} {
-    global curview mainheadid
+    global curview viewmainheadid
 
-    if {$mainheadid eq {}} return
-    if {[commitinview $mainheadid $curview]} {
+    if {$viewmainheadid($curview) eq {}} return
+    if {[commitinview $viewmainheadid($curview) $curview]} {
        dodiffindex
     } else {
-       interestedin $mainheadid dodiffindex
+       interestedin $viewmainheadid($curview) dodiffindex
     }
 }
 
@@ -4669,19 +4748,24 @@ proc dohidelocalchanges {} {
 
 # spawn off a process to do git diff-index --cached HEAD
 proc dodiffindex {} {
-    global lserial showlocalchanges
+    global lserial showlocalchanges vfilelimit curview
     global isworktree
 
     if {!$showlocalchanges || !$isworktree} return
     incr lserial
-    set fd [open "|git diff-index --cached HEAD" r]
+    set cmd "|git diff-index --cached HEAD"
+    if {$vfilelimit($curview) ne {}} {
+       set cmd [concat $cmd -- $vfilelimit($curview)]
+    }
+    set fd [open $cmd r]
     fconfigure $fd -blocking 0
     set i [reg_instance $fd]
     filerun $fd [list readdiffindex $fd $lserial $i]
 }
 
 proc readdiffindex {fd serial inst} {
-    global mainheadid nullid nullid2 curview commitinfo commitdata lserial
+    global viewmainheadid nullid nullid2 curview commitinfo commitdata lserial
+    global vfilelimit
 
     set isdiff 1
     if {[gets $fd line] < 0} {
@@ -4698,7 +4782,11 @@ proc readdiffindex {fd serial inst} {
     }
 
     # now see if there are any local changes not checked in to the index
-    set fd [open "|git diff-files" r]
+    set cmd "|git diff-files"
+    if {$vfilelimit($curview) ne {}} {
+       set cmd [concat $cmd -- $vfilelimit($curview)]
+    }
+    set fd [open $cmd r]
     fconfigure $fd -blocking 0
     set i [reg_instance $fd]
     filerun $fd [list readdifffiles $fd $serial $i]
@@ -4711,15 +4799,18 @@ proc readdiffindex {fd serial inst} {
        if {[commitinview $nullid $curview]} {
            removefakerow $nullid
        }
-       insertfakerow $nullid2 $mainheadid
+       insertfakerow $nullid2 $viewmainheadid($curview)
     } elseif {!$isdiff && [commitinview $nullid2 $curview]} {
+       if {[commitinview $nullid $curview]} {
+           removefakerow $nullid
+       }
        removefakerow $nullid2
     }
     return 0
 }
 
 proc readdifffiles {fd serial inst} {
-    global mainheadid nullid nullid2 curview
+    global viewmainheadid nullid nullid2 curview
     global commitinfo commitdata lserial
 
     set isdiff 1
@@ -4744,7 +4835,7 @@ proc readdifffiles {fd serial inst} {
        if {[commitinview $nullid2 $curview]} {
            set p $nullid2
        } else {
-           set p $mainheadid
+           set p $viewmainheadid($curview)
        }
        insertfakerow $nullid $p
     } elseif {!$isdiff && [commitinview $nullid $curview]} {
@@ -5469,7 +5560,7 @@ proc drawcmittext {id row col} {
     global cmitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
     global linehtag linentag linedtag selectedline
-    global canvxmax boldrows boldnamerows fgcolor
+    global canvxmax boldids boldnameids fgcolor
     global mainheadid nullid nullid2 circleitem circlecolors ctxbut
 
     # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right
@@ -5534,22 +5625,22 @@ proc drawcmittext {id row col} {
     set nfont mainfont
     set isbold [ishighlighted $id]
     if {$isbold > 0} {
-       lappend boldrows $row
+       lappend boldids $id
        set font mainfontbold
        if {$isbold > 1} {
-           lappend boldnamerows $row
+           lappend boldnameids $id
            set nfont mainfontbold
        }
     }
-    set linehtag($row) [$canv create text $xt $y -anchor w -fill $fgcolor \
-                           -text $headline -font $font -tags text]
-    $canv bind $linehtag($row) $ctxbut "rowmenu %X %Y $id"
-    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 linehtag($id) [$canv create text $xt $y -anchor w -fill $fgcolor \
+                          -text $headline -font $font -tags text]
+    $canv bind $linehtag($id) $ctxbut "rowmenu %X %Y $id"
+    set linentag($id) [$canv2 create text 3 $y -anchor w -fill $fgcolor \
+                          -text $name -font $nfont -tags text]
+    set linedtag($id) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
+                          -text $date -font mainfont -tags text]
     if {$selectedline == $row} {
-       make_secsel $row
+       make_secsel $id
     }
     set xr [expr {$xt + [font measure $font $headline]}]
     if {$xr > $canvxmax} {
@@ -5757,7 +5848,7 @@ proc drawvisible {} {
 proc clear_display {} {
     global iddrawn linesegs need_redisplay nrows_drawn
     global vhighlights fhighlights nhighlights rhighlights
-    global linehtag linentag linedtag boldrows boldnamerows
+    global linehtag linentag linedtag boldids boldnameids
 
     allcanvs delete all
     catch {unset iddrawn}
@@ -5765,8 +5856,8 @@ proc clear_display {} {
     catch {unset linehtag}
     catch {unset linentag}
     catch {unset linedtag}
-    set boldrows {}
-    set boldnamerows {}
+    set boldids {}
+    set boldnameids {}
     catch {unset vhighlights}
     catch {unset fhighlights}
     catch {unset nhighlights}
@@ -6224,10 +6315,11 @@ proc findmore {} {
 proc findselectline {l} {
     global findloc commentend ctext findcurline markingmatches gdttype
 
-    set markingmatches 1
+    set markingmatches [expr {$gdttype eq [mc "containing:"]}]
     set findcurline $l
     selectline $l 1
-    if {$findloc == [mc "All fields"] || $findloc == [mc "Comments"]} {
+    if {$markingmatches &&
+       ($findloc eq [mc "All fields"] || $findloc eq [mc "Comments"])} {
        # highlight the matches in the comments
        set f [$ctext get 1.0 $commentend]
        set matches [findmatches $f]
@@ -6474,20 +6566,20 @@ proc dispnexttag {} {
     }
 }
 
-proc make_secsel {l} {
+proc make_secsel {id} {
     global linehtag linentag linedtag canv canv2 canv3
 
-    if {![info exists linehtag($l)]} return
+    if {![info exists linehtag($id)]} return
     $canv delete secsel
-    set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
+    set t [eval $canv create rect [$canv bbox $linehtag($id)] -outline {{}} \
               -tags secsel -fill [$canv cget -selectbackground]]
     $canv lower $t
     $canv2 delete secsel
-    set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
+    set t [eval $canv2 create rect [$canv2 bbox $linentag($id)] -outline {{}} \
               -tags secsel -fill [$canv2 cget -selectbackground]]
     $canv2 lower $t
     $canv3 delete secsel
-    set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
+    set t [eval $canv3 create rect [$canv3 bbox $linedtag($id)] -outline {{}} \
               -tags secsel -fill [$canv3 cget -selectbackground]]
     $canv3 lower $t
 }
@@ -6553,7 +6645,7 @@ proc selectline {l isnew {desired_loc {}}} {
        drawvisible
     }
 
-    make_secsel $l
+    make_secsel $id
 
     if {$isnew} {
        addtohistory [list selbyid $id]
@@ -7067,7 +7159,7 @@ proc gettreediffline {gdtf ids} {
        set treediffs($ids) $treediff
     }
     unset treepending
-    if {$cmitmode eq "tree"} {
+    if {$cmitmode eq "tree" && [llength $diffids] == 1} {
        gettree $diffids
     } elseif {$ids != $diffids} {
        if {![info exists diffmergeid]} {
@@ -7888,7 +7980,7 @@ proc rowmenu {x y id} {
     if {$id ne $nullid && $id ne $nullid2} {
        set menu $rowctxmenu
        if {$mainhead ne {}} {
-           $menu entryconfigure 7 -label [mc "Reset %s branch to here" $mainhead]
+           $menu entryconfigure 7 -label [mc "Reset %s branch to here" $mainhead] -state normal
        } else {
            $menu entryconfigure 7 -label [mc "Detached head: can't reset" $mainhead] -state disabled
        }
@@ -8109,16 +8201,16 @@ proc redrawtags {id} {
     $canv itemconf $circleitem($row) -fill $ofill
     $canv delete tag.$id
     set xt [eval drawtags $id $idpos($id)]
-    $canv coords $linehtag($row) $xt [lindex $idpos($id) 2]
-    set text [$canv itemcget $linehtag($row) -text]
-    set font [$canv itemcget $linehtag($row) -font]
+    $canv coords $linehtag($id) $xt [lindex $idpos($id) 2]
+    set text [$canv itemcget $linehtag($id) -text]
+    set font [$canv itemcget $linehtag($id) -font]
     set xr [expr {$xt + [font measure $font $text]}]
     if {$xr > $canvxmax} {
        set canvxmax $xr
        setcanvscroll
     }
     if {[info exists currentid] && $currentid == $id} {
-       make_secsel $row
+       make_secsel $id
     }
 }
 
@@ -8208,7 +8300,6 @@ proc mkbranch {} {
     grid $top.id $top.sha1 -sticky w
     label $top.nlab -text [mc "Name:"]
     entry $top.name -width 40
-    bind $top.name <Key-Return> "[list mkbrgo $top]"
     grid $top.nlab $top.name -sticky w
     frame $top.buts
     button $top.buts.go -text [mc "Create"] -command [list mkbrgo $top]
@@ -8342,6 +8433,7 @@ proc cherrypick {} {
     }
     addnewchild $newhead $oldhead
     if {[commitinview $oldhead $curview]} {
+       # XXX this isn't right if we have a path limit...
        insertrow $newhead $oldhead $curview
        if {$mainhead ne {}} {
            movehead $newhead $mainhead
@@ -8449,7 +8541,7 @@ proc headmenu {x y id head} {
 
 proc cobranch {} {
     global headmenuid headmenuhead headids
-    global showlocalchanges mainheadid
+    global showlocalchanges
 
     # check the tree is clean first??
     nowbusy checkout [mc "Checking out"]
@@ -8470,6 +8562,7 @@ proc cobranch {} {
 
 proc readcheckoutstat {fd newhead newheadid} {
     global mainhead mainheadid headids showlocalchanges progresscoords
+    global viewmainheadid curview
 
     if {[gets $fd line] >= 0} {
        if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
@@ -8487,6 +8580,7 @@ proc readcheckoutstat {fd newhead newheadid} {
     set oldmainid $mainheadid
     set mainhead $newhead
     set mainheadid $newheadid
+    set viewmainheadid($curview) $newheadid
     redrawtags $oldmainid
     redrawtags $newheadid
     selbyid $newheadid
@@ -10012,15 +10106,11 @@ proc doprefs {} {
        -font optionfont
     spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
     grid x $top.maxpctl $top.maxpct -sticky w
-    frame $top.showlocal
-    label $top.showlocal.l -text [mc "Show local changes"] -font optionfont
-    checkbutton $top.showlocal.b -variable showlocalchanges
-    pack $top.showlocal.b $top.showlocal.l -side left
+    checkbutton $top.showlocal -text [mc "Show local changes"] \
+       -font optionfont -variable showlocalchanges
     grid x $top.showlocal -sticky w
-    frame $top.autoselect
-    label $top.autoselect.l -text [mc "Auto-select SHA1"] -font optionfont
-    checkbutton $top.autoselect.b -variable autoselect
-    pack $top.autoselect.b $top.autoselect.l -side left
+    checkbutton $top.autoselect -text [mc "Auto-select SHA1"] \
+       -font optionfont -variable autoselect
     grid x $top.autoselect -sticky w
 
     label $top.ddisp -text [mc "Diff display options"]
@@ -10028,20 +10118,14 @@ proc doprefs {} {
     label $top.tabstopl -text [mc "Tab spacing"] -font optionfont
     spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
     grid x $top.tabstopl $top.tabstop -sticky w
-    frame $top.ntag
-    label $top.ntag.l -text [mc "Display nearby tags"] -font optionfont
-    checkbutton $top.ntag.b -variable showneartags
-    pack $top.ntag.b $top.ntag.l -side left
+    checkbutton $top.ntag -text [mc "Display nearby tags"] \
+       -font optionfont -variable showneartags
     grid x $top.ntag -sticky w
-    frame $top.ldiff
-    label $top.ldiff.l -text [mc "Limit diffs to listed paths"] -font optionfont
-    checkbutton $top.ldiff.b -variable limitdiffs
-    pack $top.ldiff.b $top.ldiff.l -side left
+    checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
+       -font optionfont -variable limitdiffs
     grid x $top.ldiff -sticky w
-    frame $top.lattr
-    label $top.lattr.l -text [mc "Support per-file encodings"] -font optionfont
-    checkbutton $top.lattr.b -variable perfile_attrs
-    pack $top.lattr.b $top.lattr.l -side left
+    checkbutton $top.lattr -text [mc "Support per-file encodings"] \
+       -font optionfont -variable perfile_attrs
     grid x $top.lattr -sticky w
 
     entry $top.extdifft -textvariable extdifftool
@@ -10057,26 +10141,26 @@ proc doprefs {} {
     grid $top.cdisp - -sticky w -pady 10
     label $top.bg -padx 40 -relief sunk -background $bgcolor
     button $top.bgbut -text [mc "Background"] -font optionfont \
-       -command [list choosecolor bgcolor {} $top.bg background setbg]
+       -command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
     grid x $top.bgbut $top.bg -sticky w
     label $top.fg -padx 40 -relief sunk -background $fgcolor
     button $top.fgbut -text [mc "Foreground"] -font optionfont \
-       -command [list choosecolor fgcolor {} $top.fg foreground setfg]
+       -command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
     grid x $top.fgbut $top.fg -sticky w
     label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
     button $top.diffoldbut -text [mc "Diff: old lines"] -font optionfont \
-       -command [list choosecolor diffcolors 0 $top.diffold "diff old lines" \
+       -command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
                      [list $ctext tag conf d0 -foreground]]
     grid x $top.diffoldbut $top.diffold -sticky w
     label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
     button $top.diffnewbut -text [mc "Diff: new lines"] -font optionfont \
-       -command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
+       -command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
                      [list $ctext tag conf dresult -foreground]]
     grid x $top.diffnewbut $top.diffnew -sticky w
     label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
     button $top.hunksepbut -text [mc "Diff: hunk header"] -font optionfont \
        -command [list choosecolor diffcolors 2 $top.hunksep \
-                     "diff hunk header" \
+                     [mc "diff hunk header"] \
                      [list $ctext tag conf hunksep -foreground]]
     grid x $top.hunksepbut $top.hunksep -sticky w
     label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
@@ -10087,7 +10171,7 @@ proc doprefs {} {
     grid x $top.markbgbut $top.markbgsep -sticky w
     label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
     button $top.selbgbut -text [mc "Select bg"] -font optionfont \
-       -command [list choosecolor selectbgcolor {} $top.selbgsep background setselbg]
+       -command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
     grid x $top.selbgbut $top.selbgsep -sticky w
 
     label $top.cfont -text [mc "Fonts: press to choose"]
@@ -10766,8 +10850,8 @@ set nhl_names {}
 set highlight_paths {}
 set findpattern {}
 set searchdirn -forwards
-set boldrows {}
-set boldnamerows {}
+set boldids {}
+set boldnameids {}
 set diffelide {0 0}
 set markingmatches 0
 set linkentercount 0
@@ -10830,4 +10914,9 @@ if {[info exists permviews]} {
        addviewmenu $n
     }
 }
+
+if {[tk windowingsystem] eq "win32"} {
+    focus -force .
+}
+
 getcommits {}