Accommodate new git-diff-tree output format
[git.git] / gitk
diff --git a/gitk b/gitk
index 35ae101..8d25c32 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -7,7 +7,7 @@ exec wish "$0" -- "${1+$@}"
 # and distributed under the terms of the GNU General Public Licence,
 # either version 2, or (at your option) any later version.
 
-# CVS $Revision: 1.14 $
+# CVS $Revision: 1.17 $
 
 proc getcommits {rargs} {
     global commits commfd phase canv mainfont
@@ -160,6 +160,9 @@ proc makewindow {} {
     panedwindow .ctop -orient vertical
     if {[info exists geometry(width)]} {
        .ctop conf -width $geometry(width) -height $geometry(height)
+       set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
+       set geometry(ctexth) [expr {($texth - 8) /
+                                   [font metrics $textfont -linespace]}]
     }
     frame .ctop.top
     frame .ctop.top.bar
@@ -195,8 +198,6 @@ proc makewindow {} {
     set findstring {}
     set fstring .ctop.top.bar.findstring
     entry $fstring -width 30 -font $textfont -textvariable findstring
-    # stop the toplevel events from firing on key presses
-    bind $fstring <Key> "[bind Entry <Key>]; break"
     pack $fstring -side left -expand 1 -fill x
     set findtype Exact
     tk_optionMenu .ctop.top.bar.findtype findtype Exact IgnCase Regexp
@@ -226,7 +227,7 @@ proc makewindow {} {
 
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
-    listbox $cflist -width $geometry(cflistw) -bg white -selectmode extended \
+    listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
        -yscrollcommand ".ctop.cdet.right.sb set"
     scrollbar .ctop.cdet.right.sb -command "$cflist yview"
     pack .ctop.cdet.right.sb -side right -fill y
@@ -242,10 +243,10 @@ proc makewindow {} {
     bindall <ButtonRelease-5> "allcanvs yview scroll 5 u"
     bindall <2> "allcanvs scan mark 0 %y"
     bindall <B2-Motion> "allcanvs scan dragto 0 %y"
-    bindall <Key-Up> "selnextline -1"
-    bindall <Key-Down> "selnextline 1"
-    bindall <Key-Prior> "allcanvs yview scroll -1 p"
-    bindall <Key-Next> "allcanvs yview scroll 1 p"
+    bind . <Key-Up> "selnextline -1"
+    bind . <Key-Down> "selnextline 1"
+    bind . <Key-Prior> "allcanvs yview scroll -1 p"
+    bind . <Key-Next> "allcanvs yview scroll 1 p"
     bindkey <Key-Delete> "$ctext yview scroll -1 p"
     bindkey <Key-BackSpace> "$ctext yview scroll -1 p"
     bindkey <Key-space> "$ctext yview scroll 1 p"
@@ -256,6 +257,7 @@ proc makewindow {} {
     bindkey u "$ctext yview scroll -18 u"
     bindkey / findnext
     bindkey ? findprev
+    bindkey f nextfile
     bind . <Control-q> doquit
     bind . <Control-f> dofind
     bind . <Control-g> findnext
@@ -267,6 +269,7 @@ proc makewindow {} {
     bind $cflist <<ListboxSelect>> listboxsel
     bind . <Destroy> {savestuff %W}
     bind . <Button-1> "click %W"
+    bind $fstring <Key-Return> dofind
 }
 
 # when we make a key binding for the toplevel, make sure
@@ -306,13 +309,9 @@ proc savestuff {w} {
        puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
        puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
        puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
-       puts $f "set geometry(csash) {[.ctop sash coord 0]}"
        set wid [expr {([winfo width $ctext] - 8) \
                           / [font measure $textfont "0"]}]
-       set ht [expr {([winfo height $ctext] - 8) \
-                         / [font metrics $textfont -linespace]}]
        puts $f "set geometry(ctextw) $wid"
-       puts $f "set geometry(ctexth) $ht"
        set wid [expr {([winfo width $cflist] - 11) \
                           / [font measure [$cflist cget -font] "0"]}]
        puts $f "set geometry(cflistw) $wid"
@@ -397,13 +396,13 @@ proc about {} {
     toplevel $w
     wm title $w "About gitk"
     message $w.m -text {
-Gitk version 0.95
+Gitk version 1.0
 
 Copyright © 2005 Paul Mackerras
 
 Use and redistribute under the terms of the GNU General Public License
 
-(CVS $Revision: 1.14 $)} \
+(CVS $Revision: 1.17 $)} \
            -justify center -aspect 400
     pack $w.m -side top -fill x -padx 20 -pady 20
     button $w.ok -text Close -command "destroy $w"
@@ -520,9 +519,11 @@ proc drawgraph {} {
     set lineno -1
     set numcommits 0
     set phase drawgraph
+    set lthickness [expr {($linespc / 9) + 1}]
     while 1 {
        set canvy $y2
-       allcanvs conf -scrollregion [list 0 0 0 $canvy]
+       allcanvs conf -scrollregion \
+           [list 0 0 0 [expr $canvy + 0.5 * $linespc + 2]]
        update
        if {$stopped} break
        incr numcommits
@@ -551,13 +552,15 @@ proc drawgraph {} {
        set y2 [expr $canvy + $linespc]
        if {[info exists linestarty($level)] && $linestarty($level) < $canvy} {
            set t [$canv create line $x $linestarty($level) $x $canvy \
-                      -width 2 -fill $colormap($id)]
+                      -width $lthickness -fill $colormap($id)]
            $canv lower $t
        }
        set linestarty($level) $canvy
-       set t [$canv create oval [expr $x - 4] [expr $canvy - 4] \
-                  [expr $x + 3] [expr $canvy + 3] \
-                  -fill blue -outline black -width 1]
+       set ofill [expr {[info exists parents($id)]? "blue": "white"}]
+       set orad [expr {$linespc / 3}]
+       set t [$canv create oval [expr $x - $orad] [expr $canvy - $orad] \
+                  [expr $x + $orad - 1] [expr $canvy + $orad - 1] \
+                  -fill $ofill -outline black -width 1]
        $canv raise $t
        set xt [expr $canvx0 + $nlines * $linespc]
        set headline [lindex $commitinfo($id) 0]
@@ -694,7 +697,8 @@ proc drawgraph {} {
                lappend coords [expr $xj - $linespc] $canvy
            }
            lappend coords $xj $y2
-           set t [$canv create line $coords -width 2 -fill $colormap($dst)]
+           set t [$canv create line $coords -width $lthickness \
+                      -fill $colormap($dst)]
            $canv lower $t
            if {![info exists linestarty($j)]} {
                set linestarty($j) $y2
@@ -882,9 +886,9 @@ proc selcanvline {x y} {
 proc selectline {l} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global lineid linehtag linentag linedtag
-    global canvy canvy0 linespc nparents treepending
+    global canvy0 linespc nparents treepending
     global cflist treediffs currentid sha1entry
-    global commentend
+    global commentend seenfile numcommits
     if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
     $canv delete secsel
     set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
@@ -899,14 +903,38 @@ proc selectline {l} {
               -tags secsel -fill [$canv3 cget -selectbackground]]
     $canv3 lower $t
     set y [expr {$canvy0 + $l * $linespc}]
-    set ytop [expr {($y - $linespc / 2.0) / $canvy}]
-    set ybot [expr {($y + $linespc / 2.0) / $canvy}]
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    set ytop [expr {$y - $linespc - 1}]
+    set ybot [expr {$y + $linespc + 1}]
     set wnow [$canv yview]
-    if {$ytop < [lindex $wnow 0]} {
-       allcanvs yview moveto $ytop
-    } elseif {$ybot > [lindex $wnow 1]} {
-       set wh [expr {[lindex $wnow 1] - [lindex $wnow 0]}]
-       allcanvs yview moveto [expr {$ybot - $wh}]
+    set wtop [expr [lindex $wnow 0] * $ymax]
+    set wbot [expr [lindex $wnow 1] * $ymax]
+    set wh [expr {$wbot - $wtop}]
+    set newtop $wtop
+    if {$ytop < $wtop} {
+       if {$ybot < $wtop} {
+           set newtop [expr {$y - $wh / 2.0}]
+       } else {
+           set newtop $ytop
+           if {$newtop > $wtop - $linespc} {
+               set newtop [expr {$wtop - $linespc}]
+           }
+       }
+    } elseif {$ybot > $wbot} {
+       if {$ytop > $wbot} {
+           set newtop [expr {$y - $wh / 2.0}]
+       } else {
+           set newtop [expr {$ybot - $wh}]
+           if {$newtop < $wtop + $linespc} {
+               set newtop [expr {$wtop + $linespc}]
+           }
+       }
+    }
+    if {$newtop != $wtop} {
+       if {$newtop < 0} {
+           set newtop 0
+       }
+       allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
     }
     set selectedline $l
 
@@ -942,6 +970,7 @@ proc selectline {l} {
            addtocflist $id
        }
     }
+    catch {unset seenfile}
 }
 
 proc selnextline {dir} {
@@ -994,6 +1023,7 @@ proc gettreediffline {gdtf id} {
 
 proc getblobdiffs {id} {
     global parents diffopts blobdifffd env curdifftag curtagstart
+    global diffindex difffilestart
     set p [lindex $parents($id) 0]
     set env(GIT_DIFF_OPTS) $diffopts
     if [catch {set bdf [open "|git-diff-tree -r -p $p $id" r]} err] {
@@ -1004,17 +1034,21 @@ proc getblobdiffs {id} {
     set blobdifffd($id) $bdf
     set curdifftag Comments
     set curtagstart 0.0
+    set diffindex 0
+    catch {unset difffilestart}
     fileevent $bdf readable "getblobdiffline $bdf $id"
 }
 
 proc getblobdiffline {bdf id} {
-    global currentid blobdifffd ctext curdifftag curtagstart
+    global currentid blobdifffd ctext curdifftag curtagstart seenfile
+    global diffnexthead diffnextnote diffindex difffilestart
     set n [gets $bdf line]
     if {$n < 0} {
        if {[eof $bdf]} {
            close $bdf
            if {$id == $currentid && $bdf == $blobdifffd($id)} {
                $ctext tag add $curdifftag $curtagstart end
+               set seenfile($curdifftag) 1
            }
        }
        return
@@ -1023,18 +1057,41 @@ proc getblobdiffline {bdf id} {
        return
     }
     $ctext conf -state normal
-    if {[regexp {^---[ \t]+([^/])+/(.*)} $line match s1 fname]} {
+    if {[regexp {^---[ \t]+([^/])*/(.*)} $line match s1 fname]} {
        # start of a new file
        $ctext insert end "\n"
        $ctext tag add $curdifftag $curtagstart end
+       set seenfile($curdifftag) 1
        set curtagstart [$ctext index "end - 1c"]
+       set header $fname
+       if {[info exists diffnexthead]} {
+           set fname $diffnexthead
+           set header "$diffnexthead ($diffnextnote)"
+           unset diffnexthead
+       }
+       set difffilestart($diffindex) [$ctext index "end - 1c"]
+       incr diffindex
        set curdifftag "f:$fname"
        $ctext tag delete $curdifftag
-       set l [expr {(78 - [string length $fname]) / 2}]
+       set l [expr {(78 - [string length $header]) / 2}]
        set pad [string range "----------------------------------------" 1 $l]
-       $ctext insert end "$pad $fname $pad\n" filesep
+       $ctext insert end "$pad $header $pad\n" filesep
     } elseif {[string range $line 0 2] == "+++"} {
        # no need to do anything with this
+    } elseif {[regexp {^Created: (.*) \((mode: *[0-7]*)\)} $line match fn m]} {
+       set diffnexthead $fn
+       set diffnextnote "created, mode $m"
+    } elseif {[string range $line 0 8] == "Deleted: "} {
+       set diffnexthead [string range $line 9 end]
+       set diffnextnote "deleted"
+    } elseif {[regexp {^diff --git a/(.*) b/} $line match fn]} {
+       # save the filename in case the next thing is "new file mode ..."
+       set diffnexthead $fn
+       set diffnextnote "modified"
+    } elseif {[regexp {^new file mode ([0-7]+)} $line match m]} {
+       set diffnextnote "new file, mode $m"
+    } elseif {[string range $line 0 11] == "deleted file"} {
+       set diffnextnote "deleted"
     } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
                   $line match f1l f1c f2l f2c rest]} {
        $ctext insert end "\t" hunksep
@@ -1049,11 +1106,15 @@ proc getblobdiffline {bdf id} {
        } elseif {$x == " "} {
            set line [string range $line 1 end]
            $ctext insert end "$line\n"
+       } elseif {$x == "\\"} {
+           # e.g. "\ No newline at end of file"
+           $ctext insert end "$line\n" filesep
        } else {
            # Something else we don't recognize
            if {$curdifftag != "Comments"} {
                $ctext insert end "\n"
                $ctext tag add $curdifftag $curtagstart end
+               set seenfile($curdifftag) 1
                set curtagstart [$ctext index "end - 1c"]
                set curdifftag Comments
            }
@@ -1063,15 +1124,28 @@ proc getblobdiffline {bdf id} {
     $ctext conf -state disabled
 }
 
+proc nextfile {} {
+    global difffilestart ctext
+    set here [$ctext index @0,0]
+    for {set i 0} {[info exists difffilestart($i)]} {incr i} {
+       if {[$ctext compare $difffilestart($i) > $here]} {
+           $ctext yview $difffilestart($i)
+           break
+       }
+    }
+}
+
 proc listboxsel {} {
-    global ctext cflist currentid treediffs
+    global ctext cflist currentid treediffs seenfile
     if {![info exists currentid]} return
     set sel [$cflist curselection]
     if {$sel == {} || [lsearch -exact $sel 0] >= 0} {
        # show everything
        $ctext tag conf Comments -elide 0
        foreach f $treediffs($currentid) {
-           $ctext tag conf "f:$f" -elide 0
+           if [info exists seenfile(f:$f)] {
+               $ctext tag conf "f:$f" -elide 0
+           }
        }
     } else {
        # just show selected files
@@ -1079,7 +1153,9 @@ proc listboxsel {} {
        set i 1
        foreach f $treediffs($currentid) {
            set elide [expr {[lsearch -exact $sel $i] < 0}]
-           $ctext tag conf "f:$f" -elide $elide
+           if [info exists seenfile(f:$f)] {
+               $ctext tag conf "f:$f" -elide $elide
+           }
            incr i
        }
     }
@@ -1133,17 +1209,18 @@ set boldnames 0
 set diffopts "-U 5 -p"
 
 set mainfont {Helvetica 9}
-set namefont $mainfont
 set textfont {Courier 9}
-if {$boldnames} {
-    lappend namefont bold
-}
 
 set colors {green red blue magenta darkgrey brown orange}
 set colorbycommitter false
 
 catch {source ~/.gitk}
 
+set namefont $mainfont
+if {$boldnames} {
+    lappend namefont bold
+}
+
 set revtreeargs {}
 foreach arg $argv {
     switch -regexp -- $arg {