Merge branch 'master' into new
authorPaul Mackerras <paulus@samba.org>
Sun, 23 Apr 2006 12:47:07 +0000 (22:47 +1000)
committerPaul Mackerras <paulus@samba.org>
Sun, 23 Apr 2006 12:47:07 +0000 (22:47 +1000)
1  2 
gitk

diff --combined gitk
--- 1/gitk
--- 2/gitk
+++ b/gitk
@@@ -16,26 -16,21 +16,26 @@@ proc gitdir {} 
      }
  }
  
 -proc start_rev_list {rlargs} {
 +proc start_rev_list {} {
      global startmsecs nextupdate ncmupdate
      global commfd leftover tclencoding datemode
 +    global revtreeargs curview viewfiles
  
      set startmsecs [clock clicks -milliseconds]
      set nextupdate [expr {$startmsecs + 100}]
      set ncmupdate 1
      initlayout
 +    set args $revtreeargs
 +    if {$viewfiles($curview) ne {}} {
 +      set args [concat $args "--" $viewfiles($curview)]
 +    }
      set order "--topo-order"
      if {$datemode} {
        set order "--date-order"
      }
      if {[catch {
        set commfd [open [concat | git-rev-list --header $order \
 -                            --parents --boundary --default HEAD $rlargs] r]
 +                            --parents --boundary --default HEAD $args] r]
      } err]} {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
      settextcursor watch
  }
  
 -proc getcommits {rargs} {
 +proc stop_rev_list {} {
 +    global commfd
 +
 +    if {![info exists commfd]} return
 +    catch {
 +      set pid [pid $commfd]
 +      exec kill $pid
 +    }
 +    catch {close $commfd}
 +    unset commfd
 +}
 +
 +proc getcommits {} {
      global phase canv mainfont
  
      set phase getcommits
 -    start_rev_list $rargs
 +    start_rev_list
      $canv delete all
      $canv create text 3 3 -anchor nw -text "Reading commits..." \
        -font $mainfont -tags textitems
@@@ -142,12 -125,11 +142,12 @@@ proc getcommitlines {commfd}  
        set id [lindex $ids 0]
        if {$listed} {
            set olds [lrange $ids 1 end]
 -          if {[llength $olds] > 1} {
 -              set olds [lsort -unique $olds]
 -          }
 +          set i 0
            foreach p $olds {
 -              lappend children($p) $id
 +              if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
 +                  lappend children($p) $id
 +              }
 +              incr i
            }
        } else {
            set olds {}
        lappend parentlist $olds
        if {[info exists children($id)]} {
            lappend childlist $children($id)
 +          unset children($id)
        } else {
            lappend childlist {}
        }
@@@ -199,18 -180,18 +199,18 @@@ proc readcommit {id} 
      parsecommit $id $contents 0
  }
  
 -proc updatecommits {rargs} {
 -    stopfindproc
 -    foreach v {colormap selectedline matchinglines treediffs
 -      mergefilelist currentid rowtextx commitrow
 -      rowidlist rowoffsets idrowranges idrangedrawn iddrawn
 -      linesegends crossings cornercrossings} {
 -      global $v
 -      catch {unset $v}
 +proc updatecommits {} {
 +    global viewdata curview revtreeargs phase
 +
 +    if {$phase ne {}} {
 +      stop_rev_list
 +      set phase {}
      }
 -    allcanvs delete all
 +    set n $curview
 +    set curview -1
 +    catch {unset viewdata($n)}
      readrefs
 -    getcommits $rargs
 +    showview $n
  }
  
  proc parsecommit {id contents listed} {
@@@ -337,9 -318,8 +337,9 @@@ proc error_popup msg 
      tkwait window $w
  }
  
 -proc makewindow {rargs} {
 -    global canv canv2 canv3 linespc charspc ctext cflist textfont mainfont uifont
 +proc makewindow {} {
 +    global canv canv2 canv3 linespc charspc ctext cflist
 +    global textfont mainfont uifont
      global findtype findtypemenu findloc findstring fstring geometry
      global entries sha1entry sha1string sha1but
      global maincursor textcursor curtextcursor
      .bar add cascade -label "File" -menu .bar.file
      .bar configure -font $uifont
      menu .bar.file
 -    .bar.file add command -label "Update" -command [list updatecommits $rargs]
 +    .bar.file add command -label "Update" -command updatecommits
      .bar.file add command -label "Reread references" -command rereadrefs
      .bar.file add command -label "Quit" -command doquit
      .bar.file configure -font $uifont
      .bar add cascade -label "Edit" -menu .bar.edit
      .bar.edit add command -label "Preferences" -command doprefs
      .bar.edit configure -font $uifont
 +    menu .bar.view -font $uifont
 +    .bar add cascade -label "View" -menu .bar.view
 +    .bar.view add command -label "New view..." -command newview
 +    .bar.view add command -label "Delete view" -command delview -state disabled
 +    .bar.view add separator
 +    .bar.view add command -label "All files" -command {showview 0}
      menu .bar.help
      .bar add cascade -label "Help" -menu .bar.help
      .bar.help add command -label "About gitk" -command about
@@@ -796,220 -770,6 +796,220 @@@ f              Scroll diff view to next fil
      pack $w.ok -side bottom
  }
  
 +proc newview {} {
 +    global newviewname nextviewnum newviewtop
 +
 +    set top .gitkview
 +    if {[winfo exists $top]} {
 +      raise $top
 +      return
 +    }
 +    set newviewtop $top
 +    toplevel $top
 +    wm title $top "Gitk view definition"
 +    label $top.nl -text "Name"
 +    entry $top.name -width 20 -textvariable newviewname
 +    set newviewname "View $nextviewnum"
 +    grid $top.nl $top.name -sticky w
 +    label $top.l -text "Files and directories to include:"
 +    grid $top.l - -sticky w -pady 10
 +    text $top.t -width 30 -height 10
 +    grid $top.t - -sticky w
 +    frame $top.buts
 +    button $top.buts.ok -text "OK" -command newviewok
 +    button $top.buts.can -text "Cancel" -command newviewcan
 +    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
 +    grid $top.buts - -pady 10 -sticky ew
 +    focus $top.t
 +}
 +
 +proc newviewok {} {
 +    global newviewtop nextviewnum
 +    global viewname viewfiles
 +
 +    set n $nextviewnum
 +    incr nextviewnum
 +    set viewname($n) [$newviewtop.name get]
 +    set files {}
 +    foreach f [split [$newviewtop.t get 0.0 end] "\n"] {
 +      set ft [string trim $f]
 +      if {$ft ne {}} {
 +          lappend files $ft
 +      }
 +    }
 +    set viewfiles($n) $files
 +    catch {destroy $newviewtop}
 +    unset newviewtop
 +    .bar.view add command -label $viewname($n) -command [list showview $n]
 +    after idle showview $n
 +}
 +
 +proc newviewcan {} {
 +    global newviewtop
 +
 +    catch {destroy $newviewtop}
 +    unset newviewtop
 +}
 +
 +proc delview {} {
 +    global curview viewdata
 +
 +    if {$curview == 0} return
 +    set nmenu [.bar.view index end]
 +    set targetcmd [list showview $curview]
 +    for {set i 5} {$i <= $nmenu} {incr i} {
 +      if {[.bar.view entrycget $i -command] eq $targetcmd} {
 +          .bar.view delete $i
 +          break
 +      }
 +    }
 +    set viewdata($curview) {}
 +    showview 0
 +}
 +
 +proc flatten {var} {
 +    global $var
 +
 +    set ret {}
 +    foreach i [array names $var] {
 +      lappend ret $i [set $var\($i\)]
 +    }
 +    return $ret
 +}
 +
 +proc unflatten {var l} {
 +    global $var
 +
 +    catch {unset $var}
 +    foreach {i v} $l {
 +      set $var\($i\) $v
 +    }
 +}
 +
 +proc showview {n} {
 +    global curview viewdata viewfiles
 +    global displayorder parentlist childlist rowidlist rowoffsets
 +    global colormap rowtextx commitrow
 +    global numcommits rowrangelist commitlisted idrowranges
 +    global selectedline currentid canv canvy0
 +    global matchinglines treediffs
 +    global pending_select phase
 +    global commitidx rowlaidout rowoptim linesegends leftover
 +    global commfd nextupdate
 +
 +    if {$n == $curview} return
 +    set selid {}
 +    if {[info exists selectedline]} {
 +      set selid $currentid
 +      set y [yc $selectedline]
 +      set ymax [lindex [$canv cget -scrollregion] 3]
 +      set span [$canv yview]
 +      set ytop [expr {[lindex $span 0] * $ymax}]
 +      set ybot [expr {[lindex $span 1] * $ymax}]
 +      if {$ytop < $y && $y < $ybot} {
 +          set yscreen [expr {$y - $ytop}]
 +      } else {
 +          set yscreen [expr {($ybot - $ytop) / 2}]
 +      }
 +    }
 +    unselectline
 +    normalline
 +    stopfindproc
 +    if {$curview >= 0} {
 +      if {$phase ne {}} {
 +          set viewdata($curview) \
 +              [list $phase $displayorder $parentlist $childlist $rowidlist \
 +                   $rowoffsets $rowrangelist $commitlisted \
 +                   [flatten children] [flatten idrowranges] \
 +                   [flatten idinlist] \
 +                   $commitidx $rowlaidout $rowoptim $numcommits \
 +                   $linesegends $leftover $commfd]
 +          fileevent $commfd readable {}
 +      } elseif {![info exists viewdata($curview)]
 +                || [lindex $viewdata($curview) 0] ne {}} {
 +          set viewdata($curview) \
 +              [list {} $displayorder $parentlist $childlist $rowidlist \
 +                   $rowoffsets $rowrangelist $commitlisted]
 +      }
 +    }
 +    catch {unset matchinglines}
 +    catch {unset treediffs}
 +    clear_display
 +
 +    set curview $n
 +    .bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}]
 +
 +    if {![info exists viewdata($n)]} {
 +      set pending_select $selid
 +      getcommits
 +      return
 +    }
 +
 +    set v $viewdata($n)
 +    set phase [lindex $v 0]
 +    set displayorder [lindex $v 1]
 +    set parentlist [lindex $v 2]
 +    set childlist [lindex $v 3]
 +    set rowidlist [lindex $v 4]
 +    set rowoffsets [lindex $v 5]
 +    set rowrangelist [lindex $v 6]
 +    set commitlisted [lindex $v 7]
 +    if {$phase eq {}} {
 +      set numcommits [llength $displayorder]
 +      catch {unset idrowranges}
 +      catch {unset children}
 +    } else {
 +      unflatten children [lindex $v 8]
 +      unflatten idrowranges [lindex $v 9]
 +      unflatten idinlist [lindex $v 10]
 +      set commitidx [lindex $v 11]
 +      set rowlaidout [lindex $v 12]
 +      set rowoptim [lindex $v 13]
 +      set numcommits [lindex $v 14]
 +      set linesegends [lindex $v 15]
 +      set leftover [lindex $v 16]
 +      set commfd [lindex $v 17]
 +      fileevent $commfd readable [list getcommitlines $commfd]
 +      set nextupdate [expr {[clock clicks -milliseconds] + 100}]
 +    }
 +
 +    catch {unset colormap}
 +    catch {unset rowtextx}
 +    catch {unset commitrow}
 +    set curview $n
 +    set row 0
 +    foreach id $displayorder {
 +      set commitrow($id) $row
 +      incr row
 +    }
 +    setcanvscroll
 +    set yf 0
 +    set row 0
 +    if {$selid ne {} && [info exists commitrow($selid)]} {
 +      set row $commitrow($selid)
 +      # try to get the selected row in the same position on the screen
 +      set ymax [lindex [$canv cget -scrollregion] 3]
 +      set ytop [expr {[yc $row] - $yscreen}]
 +      if {$ytop < 0} {
 +          set ytop 0
 +      }
 +      set yf [expr {$ytop * 1.0 / $ymax}]
 +    }
 +    allcanvs yview moveto $yf
 +    drawvisible
 +    selectline $row 0
 +    if {$phase eq {}} {
 +      global maincursor textcursor
 +      . config -cursor $maincursor
 +      settextcursor $textcursor
 +    } else {
 +      . config -cursor watch
 +      settextcursor watch
 +    }
 +}
 +
  proc shortids {ids} {
      set res {}
      foreach id $ids {
@@@ -1045,21 -805,20 +1045,21 @@@ proc ntimes {n o} 
  }
  
  proc usedinrange {id l1 l2} {
 -    global children commitrow
 +    global children commitrow childlist
  
      if {[info exists commitrow($id)]} {
        set r $commitrow($id)
        if {$l1 <= $r && $r <= $l2} {
            return [expr {$r - $l1 + 1}]
        }
 +      set kids [lindex $childlist $r]
 +    } else {
 +      set kids $children($id)
      }
 -    foreach c $children($id) {
 -      if {[info exists commitrow($c)]} {
 -          set r $commitrow($c)
 -          if {$l1 <= $r && $r <= $l2} {
 -              return [expr {$r - $l1 + 1}]
 -          }
 +    foreach c $kids {
 +      set r $commitrow($c)
 +      if {$l1 <= $r && $r <= $l2} {
 +          return [expr {$r - $l1 + 1}]
        }
      }
      return 0
@@@ -1127,12 -886,10 +1127,12 @@@ proc makeuparrow {oid x y z} 
  proc initlayout {} {
      global rowidlist rowoffsets displayorder commitlisted
      global rowlaidout rowoptim
 -    global idinlist rowchk
 +    global idinlist rowchk rowrangelist idrowranges
      global commitidx numcommits canvxmax canv
      global nextcolor
      global parentlist childlist children
 +    global colormap rowtextx commitrow
 +    global linesegends
  
      set commitidx 0
      set numcommits 0
      set commitlisted {}
      set parentlist {}
      set childlist {}
 +    set rowrangelist {}
      catch {unset children}
      set nextcolor 0
      set rowidlist {{}}
      set rowlaidout 0
      set rowoptim 0
      set canvxmax [$canv cget -width]
 +    catch {unset colormap}
 +    catch {unset rowtextx}
 +    catch {unset commitrow}
 +    catch {unset idrowranges}
 +    set linesegends {}
  }
  
  proc setcanvscroll {} {
@@@ -1193,6 -944,7 +1193,6 @@@ proc layoutmore {} 
      set rowlaidout [layoutrows $row $commitidx 0]
      set orow [expr {$rowlaidout - $uparrowlen - 1}]
      if {$orow > $rowoptim} {
 -      checkcrossings $rowoptim $orow
        optimize_rows $rowoptim 0 $orow
        set rowoptim $orow
      }
  }
  
  proc showstuff {canshow} {
 -    global numcommits
 +    global numcommits commitrow pending_select selectedline
      global linesegends idrowranges idrangedrawn
  
      if {$numcommits == 0} {
      set rows [visiblerows]
      set r0 [lindex $rows 0]
      set r1 [lindex $rows 1]
 +    set selrow -1
      for {set r $row} {$r < $canshow} {incr r} {
 -      if {[info exists linesegends($r)]} {
 -          foreach id $linesegends($r) {
 -              set i -1
 -              foreach {s e} $idrowranges($id) {
 -                  incr i
 -                  if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
 -                      && ![info exists idrangedrawn($id,$i)]} {
 -                      drawlineseg $id $i
 -                      set idrangedrawn($id,$i) 1
 -                  }
 +      foreach id [lindex $linesegends [expr {$r+1}]] {
 +          set i -1
 +          foreach {s e} [rowranges $id] {
 +              incr i
 +              if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
 +                  && ![info exists idrangedrawn($id,$i)]} {
 +                  drawlineseg $id $i
 +                  set idrangedrawn($id,$i) 1
                }
            }
        }
        drawcmitrow $row
        incr row
      }
 +    if {[info exists pending_select] &&
 +      [info exists commitrow($pending_select)] &&
 +      $commitrow($pending_select) < $numcommits} {
 +      selectline $commitrow($pending_select) 1
 +    }
 +    if {![info exists selectedline] && ![info exists pending_select]} {
 +      selectline 0 1
 +    }
  }
  
  proc layoutrows {row endrow last} {
      global childlist parentlist
      global idrowranges linesegends
      global commitidx
 -    global idinlist rowchk
 +    global idinlist rowchk rowrangelist
  
      set idlist [lindex $rowidlist $row]
      set offs [lindex $rowoffsets $row]
                lappend oldolds $p
            }
        }
 +      set lse {}
        set nev [expr {[llength $idlist] + [llength $newolds]
                       + [llength $oldolds] - $maxwidth + 1}]
        if {$nev > 0} {
                        set offs [incrange $offs $x 1]
                        set idinlist($i) 0
                        set rm1 [expr {$row - 1}]
 -                      lappend linesegends($rm1) $i
 +                      lappend lse $i
                        lappend idrowranges($i) $rm1
                        if {[incr nev -1] <= 0} break
                        continue
            lset rowidlist $row $idlist
            lset rowoffsets $row $offs
        }
 +      lappend linesegends $lse
        set col [lsearch -exact $idlist $id]
        if {$col < 0} {
            set col [llength $idlist]
        } else {
            unset idinlist($id)
        }
 +      set ranges {}
        if {[info exists idrowranges($id)]} {
 -          lappend idrowranges($id) $row
 +          set ranges $idrowranges($id)
 +          lappend ranges $row
 +          unset idrowranges($id)
        }
 +      lappend rowrangelist $ranges
        incr row
        set offs [ntimes [llength $idlist] 0]
        set l [llength $newolds]
  
  proc addextraid {id row} {
      global displayorder commitrow commitinfo
-     global commitidx
+     global commitidx commitlisted
      global parentlist childlist children
  
      incr commitidx
      lappend displayorder $id
+     lappend commitlisted 0
      lappend parentlist {}
      set commitrow($id) $row
      readcommit $id
      }
      if {[info exists children($id)]} {
        lappend childlist $children($id)
 +      unset children($id)
      } else {
        lappend childlist {}
      }
  
  proc layouttail {} {
      global rowidlist rowoffsets idinlist commitidx
 -    global idrowranges
 +    global idrowranges rowrangelist
  
      set row $commitidx
      set idlist [lindex $rowidlist $row]
        addextraid $id $row
        unset idinlist($id)
        lappend idrowranges($id) $row
 +      lappend rowrangelist $idrowranges($id)
 +      unset idrowranges($id)
        incr row
        set offs [ntimes $col 0]
        set idlist [lreplace $idlist $col $col]
        lset rowoffsets $row 0
        makeuparrow $id 0 $row 0
        lappend idrowranges($id) $row
 +      lappend rowrangelist $idrowranges($id)
 +      unset idrowranges($id)
        incr row
        lappend rowidlist {}
        lappend rowoffsets {}
@@@ -1425,7 -1160,7 +1426,7 @@@ proc insert_pad {row col npad} 
  }
  
  proc optimize_rows {row col endrow} {
 -    global rowidlist rowoffsets idrowranges linesegends displayorder
 +    global rowidlist rowoffsets idrowranges displayorder
  
      for {} {$row < $endrow} {incr row} {
        set idlist [lindex $rowidlist $row]
            set z0 [lindex $rowoffsets $y0 $x0]
            if {$z0 eq {}} {
                set id [lindex $idlist $col]
 -              if {[info exists idrowranges($id)] &&
 -                  $y0 > [lindex $idrowranges($id) 0]} {
 +              set ranges [rowranges $id]
 +              if {$ranges ne {} && $y0 > [lindex $ranges 0]} {
                    set isarrow 1
                }
            }
                if {$o eq {}} {
                    # check if this is the link to the first child
                    set id [lindex $idlist $col]
 -                  if {[info exists idrowranges($id)] &&
 -                      $row == [lindex $idrowranges($id) 0]} {
 +                  set ranges [rowranges $id]
 +                  if {$ranges ne {} && $row == [lindex $ranges 0]} {
                        # it is, work out offset to child
                        set y0 [expr {$row - 1}]
                        set id [lindex $displayorder $y0]
@@@ -1558,34 -1293,13 +1559,34 @@@ proc linewidth {id} 
      return $wid
  }
  
 +proc rowranges {id} {
 +    global phase idrowranges commitrow rowlaidout rowrangelist
 +
 +    set ranges {}
 +    if {$phase eq {} ||
 +      ([info exists commitrow($id)] && $commitrow($id) < $rowlaidout)} {
 +      set ranges [lindex $rowrangelist $commitrow($id)]
 +    } elseif {[info exists idrowranges($id)]} {
 +      set ranges $idrowranges($id)
 +    }
 +    return $ranges
 +}
 +
  proc drawlineseg {id i} {
 -    global rowoffsets rowidlist idrowranges
 +    global rowoffsets rowidlist
      global displayorder
      global canv colormap linespc
 +    global numcommits commitrow
  
 -    set startrow [lindex $idrowranges($id) [expr {2 * $i}]]
 -    set row [lindex $idrowranges($id) [expr {2 * $i + 1}]]
 +    set ranges [rowranges $id]
 +    set downarrow 1
 +    if {[info exists commitrow($id)] && $commitrow($id) < $numcommits} {
 +      set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
 +    } else {
 +      set downarrow 1
 +    }
 +    set startrow [lindex $ranges [expr {2 * $i}]]
 +    set row [lindex $ranges [expr {2 * $i + 1}]]
      if {$startrow == $row} return
      assigncolor $id
      set coords {}
        }
      }
      if {[llength $coords] < 4} return
 -    set last [expr {[llength $idrowranges($id)] / 2 - 1}]
 -    if {$i < $last} {
 +    if {$downarrow} {
        # This line has an arrow at the lower end: check if the arrow is
        # on a diagonal segment, and if so, work around the Tk 8.4
        # refusal to draw arrows on diagonal lines.
            }
        }
      }
 -    set arrow [expr {2 * ($i > 0) + ($i < $last)}]
 +    set arrow [expr {2 * ($i > 0) + $downarrow}]
      set arrow [lindex {none first last both} $arrow]
      set t [$canv create line $coords -width [linewidth $id] \
               -fill $colormap($id) -tags lines.$id -arrow $arrow]
  }
  
  proc drawparentlinks {id row col olds} {
 -    global rowidlist canv colormap idrowranges
 +    global rowidlist canv colormap
  
      set row2 [expr {$row + 1}]
      set x [xc $row $col]
        if {$x2 > $rmx} {
            set rmx $x2
        }
 -      if {[info exists idrowranges($p)] &&
 -          $row2 == [lindex $idrowranges($p) 0] &&
 -          $row2 < [lindex $idrowranges($p) 1]} {
 +      set ranges [rowranges $p]
 +      if {$ranges ne {} && $row2 == [lindex $ranges 0]
 +          && $row2 < [lindex $ranges 1]} {
            # drawlineseg will do this one for us
            continue
        }
  
  proc drawlines {id} {
      global colormap canv
 -    global idrowranges idrangedrawn
 +    global idrangedrawn
      global childlist iddrawn commitrow rowidlist
  
      $canv delete lines.$id
 -    set nr [expr {[llength $idrowranges($id)] / 2}]
 +    set nr [expr {[llength [rowranges $id]] / 2}]
      for {set i 0} {$i < $nr} {incr i} {
        if {[info exists idrangedrawn($id,$i)]} {
            drawlineseg $id $i
@@@ -1769,14 -1484,14 +1770,14 @@@ proc drawcmittext {id row col rmx} 
  
  proc drawcmitrow {row} {
      global displayorder rowidlist
 -    global idrowranges idrangedrawn iddrawn
 +    global idrangedrawn iddrawn
-     global commitinfo commitlisted parentlist numcommits
+     global commitinfo parentlist numcommits
  
      if {$row >= $numcommits} return
      foreach id [lindex $rowidlist $row] {
 -      if {![info exists idrowranges($id)]} continue
 +      if {$id eq {}} continue
        set i -1
 -      foreach {s e} $idrowranges($id) {
 +      foreach {s e} [rowranges $id] {
            incr i
            if {$row < $s} continue
            if {$e eq {}} break
@@@ -1845,50 -1560,10 +1846,50 @@@ proc clear_display {} 
      catch {unset idrangedrawn}
  }
  
 +proc findcrossings {id} {
 +    global rowidlist parentlist numcommits rowoffsets displayorder
 +
 +    set cross {}
 +    set ccross {}
 +    foreach {s e} [rowranges $id] {
 +      if {$e >= $numcommits} {
 +          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 olds [lindex $parentlist $row]
 +          set kid [lindex $displayorder $row]
 +          set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
 +          if {$kidx < 0} continue
 +          set nextrow [lindex $rowidlist [expr {$row + 1}]]
 +          foreach p $olds {
 +              set px [lsearch -exact $nextrow $p]
 +              if {$px < 0} continue
 +              if {($kidx < $x && $x < $px) || ($px < $x && $x < $kidx)} {
 +                  if {[lsearch -exact $ccross $p] >= 0} continue
 +                  if {$x == $px + ($kidx < $px? -1: 1)} {
 +                      lappend ccross $p
 +                  } elseif {[lsearch -exact $cross $p] < 0} {
 +                      lappend cross $p
 +                  }
 +              }
 +          }
 +          set inc [lindex $rowoffsets $row $x]
 +          if {$inc eq {}} break
 +          incr x $inc
 +      }
 +    }
 +    return [concat $ccross {{}} $cross]
 +}
 +
  proc assigncolor {id} {
      global colormap colors nextcolor
      global commitrow parentlist children childlist
 -    global cornercrossings crossings
  
      if {[info exists colormap($id)]} return
      set ncolors [llength $colors]
        }
      }
      set badcolors {}
 -    if {[info exists cornercrossings($id)]} {
 -      foreach x $cornercrossings($id) {
 -          if {[info exists colormap($x)]
 -              && [lsearch -exact $badcolors $colormap($x)] < 0} {
 -              lappend badcolors $colormap($x)
 -          }
 +    set origbad {}
 +    foreach x [findcrossings $id] {
 +      if {$x eq {}} {
 +          # delimiter between corner crossings and other crossings
 +          if {[llength $badcolors] >= $ncolors - 1} break
 +          set origbad $badcolors
        }
 -      if {[llength $badcolors] >= $ncolors} {
 -          set badcolors {}
 +      if {[info exists colormap($x)]
 +          && [lsearch -exact $badcolors $colormap($x)] < 0} {
 +          lappend badcolors $colormap($x)
        }
      }
 -    set origbad $badcolors
 -    if {[llength $badcolors] < $ncolors - 1} {
 -      if {[info exists crossings($id)]} {
 -          foreach x $crossings($id) {
 -              if {[info exists colormap($x)]
 -                  && [lsearch -exact $badcolors $colormap($x)] < 0} {
 -                  lappend badcolors $colormap($x)
 -              }
 -          }
 -          if {[llength $badcolors] >= $ncolors} {
 -              set badcolors $origbad
 -          }
 -      }
 -      set origbad $badcolors
 +    if {[llength $badcolors] >= $ncolors} {
 +      set badcolors $origbad
      }
 +    set origbad $badcolors
      if {[llength $badcolors] < $ncolors - 1} {
        foreach child $kids {
            if {[info exists colormap($child)]
@@@ -2027,6 -1712,55 +2028,6 @@@ proc drawtags {id x xt y1} 
      return $xt
  }
  
 -proc checkcrossings {row endrow} {
 -    global displayorder parentlist rowidlist
 -
 -    for {} {$row < $endrow} {incr row} {
 -      set id [lindex $displayorder $row]
 -      set i [lsearch -exact [lindex $rowidlist $row] $id]
 -      if {$i < 0} continue
 -      set idlist [lindex $rowidlist [expr {$row+1}]]
 -      foreach p [lindex $parentlist $row] {
 -          set j [lsearch -exact $idlist $p]
 -          if {$j > 0} {
 -              if {$j < $i - 1} {
 -                  notecrossings $row $p $j $i [expr {$j+1}]
 -              } elseif {$j > $i + 1} {
 -                  notecrossings $row $p $i $j [expr {$j-1}]
 -              }
 -          }
 -      }
 -    }
 -}
 -
 -proc notecrossings {row id lo hi corner} {
 -    global rowidlist crossings cornercrossings
 -
 -    for {set i $lo} {[incr i] < $hi} {} {
 -      set p [lindex [lindex $rowidlist $row] $i]
 -      if {$p == {}} continue
 -      if {$i == $corner} {
 -          if {![info exists cornercrossings($id)]
 -              || [lsearch -exact $cornercrossings($id) $p] < 0} {
 -              lappend cornercrossings($id) $p
 -          }
 -          if {![info exists cornercrossings($p)]
 -              || [lsearch -exact $cornercrossings($p) $id] < 0} {
 -              lappend cornercrossings($p) $id
 -          }
 -      } else {
 -          if {![info exists crossings($id)]
 -              || [lsearch -exact $crossings($id) $p] < 0} {
 -              lappend crossings($id) $p
 -          }
 -          if {![info exists crossings($p)]
 -              || [lsearch -exact $crossings($p) $id] < 0} {
 -              lappend crossings($p) $id
 -          }
 -      }
 -    }
 -}
 -
  proc xcoord {i level ln} {
      global canvx0 xspc1 xspc2
  
  proc finishcommits {} {
      global commitidx phase
      global canv mainfont ctext maincursor textcursor
 -    global findinprogress
 +    global findinprogress pending_select
  
      if {$commitidx > 0} {
        drawrest
        settextcursor $textcursor
      }
      set phase {}
 +    catch {unset pending_select}
  }
  
  # Don't change the text pane cursor if it is currently the hand cursor,
@@@ -2075,16 -1808,12 +2076,16 @@@ proc drawrest {} 
      global startmsecs
      global canvy0 numcommits linespc
      global rowlaidout commitidx
 +    global pending_select
  
      set row $rowlaidout
      layoutrows $rowlaidout $commitidx 1
      layouttail
      optimize_rows $row 0 $commitidx
      showstuff $commitidx
 +    if {[info exists pending_select]} {
 +      selectline 0 1
 +    }
  
      set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
      #puts "overall $drawmsecs ms for $numcommits commits"
@@@ -2274,7 -2003,7 +2275,7 @@@ proc stopfindproc {{done 0}} 
      }
      if {[info exists findinprogress]} {
        unset findinprogress
 -      if {$phase != "incrdraw"} {
 +      if {$phase eq {}} {
            . config -cursor $maincursor
            settextcursor $textcursor
        }
@@@ -2635,9 -2364,8 +2636,9 @@@ proc selectline {l isnew} 
      global canvy0 linespc parentlist childlist
      global cflist currentid sha1entry
      global commentend idtags linknum
 -    global mergemax numcommits
 +    global mergemax numcommits pending_select
  
 +    catch {unset pending_select}
      $canv delete hover
      normalline
      if {$l < 0 || $l >= $numcommits} return
@@@ -2805,26 -2533,24 +2806,26 @@@ proc selnextpage {dir} 
  }
  
  proc unselectline {} {
 -    global selectedline
 +    global selectedline currentid
  
      catch {unset selectedline}
 +    catch {unset currentid}
      allcanvs delete secsel
  }
  
  proc addtohistory {cmd} {
 -    global history historyindex
 +    global history historyindex curview
  
 +    set elt [list $curview $cmd]
      if {$historyindex > 0
 -      && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
 +      && [lindex $history [expr {$historyindex - 1}]] == $elt} {
        return
      }
  
      if {$historyindex < [llength $history]} {
 -      set history [lreplace $history $historyindex end $cmd]
 +      set history [lreplace $history $historyindex end $elt]
      } else {
 -      lappend history $cmd
 +      lappend history $elt
      }
      incr historyindex
      if {$historyindex > 1} {
      .ctop.top.bar.rightbut conf -state disabled
  }
  
 +proc godo {elt} {
 +    global curview
 +
 +    set view [lindex $elt 0]
 +    set cmd [lindex $elt 1]
 +    if {$curview != $view} {
 +      showview $view
 +    }
 +    eval $cmd
 +}
 +
  proc goback {} {
      global history historyindex
  
      if {$historyindex > 1} {
        incr historyindex -1
 -      set cmd [lindex $history [expr {$historyindex - 1}]]
 -      eval $cmd
 +      godo [lindex $history [expr {$historyindex - 1}]]
        .ctop.top.bar.rightbut conf -state normal
      }
      if {$historyindex <= 1} {
@@@ -2865,7 -2581,7 +2866,7 @@@ proc goforw {} 
      if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
        incr historyindex
 -      eval $cmd
 +      godo $cmd
        .ctop.top.bar.leftbut conf -state normal
      }
      if {$historyindex >= [llength $history]} {
@@@ -3201,7 -2917,7 +3202,7 @@@ proc incrfont {inc} 
      foreach e $entries {
        $e conf -font $mainfont
      }
 -    if {$phase == "getcommits"} {
 +    if {$phase eq "getcommits"} {
        $canv itemconf textitems -font $mainfont
      }
      redisplay
@@@ -3334,13 -3050,12 +3335,13 @@@ proc linehover {} 
  }
  
  proc clickisonarrow {id y} {
 -    global lthickness idrowranges
 +    global lthickness
  
 +    set ranges [rowranges $id]
      set thresh [expr {2 * $lthickness + 6}]
 -    set n [expr {[llength $idrowranges($id)] - 1}]
 +    set n [expr {[llength $ranges] - 1}]
      for {set i 1} {$i < $n} {incr i} {
 -      set row [lindex $idrowranges($id) $i]
 +      set row [lindex $ranges $i]
        if {abs([yc $row] - $y) < $thresh} {
            return $i
        }
  }
  
  proc arrowjump {id n y} {
 -    global idrowranges canv
 +    global canv
  
      # 1 <-> 2, 3 <-> 4, etc...
      set n [expr {(($n - 1) ^ 1) + 1}]
 -    set row [lindex $idrowranges($id) $n]
 +    set row [lindex [rowranges $id] $n]
      set yt [yc $row]
      set ymax [lindex [$canv cget -scrollregion] 3]
      if {$ymax eq {} || $ymax <= 0} return
@@@ -4206,35 -3921,10 +4207,35 @@@ set historyindex 
  
  set optim_delay 16
  
 +set nextviewnum 1
 +set curview 0
 +set viewfiles(0) {}
 +
  set stopped 0
  set stuffsaved 0
  set patchnum 0
  setcoords
 -makewindow $revtreeargs
 +makewindow
  readrefs
 -getcommits $revtreeargs
 +
 +set cmdline_files {}
 +catch {
 +    set fileargs [eval exec git-rev-parse --no-revs --no-flags $revtreeargs]
 +    set cmdline_files [split $fileargs "\n"]
 +    set n [llength $cmdline_files]
 +    set revtreeargs [lrange $revtreeargs 0 end-$n]
 +}
 +if {[lindex $revtreeargs end] eq "--"} {
 +    set revtreeargs [lrange $revtreeargs 0 end-1]
 +}
 +
 +if {$cmdline_files ne {}} {
 +    # create a view for the files/dirs specified on the command line
 +    set curview 1
 +    set nextviewnum 2
 +    set viewname(1) "Command line"
 +    set viewfiles(1) $cmdline_files
 +    .bar.view add command -label $viewname(1) -command {showview 1}
 +    .bar.view entryconf 2 -state normal
 +}
 +getcommits