+proc selnextline {dir} {
+ global selectedline
+ if {![info exists selectedline]} return
+ set l [expr $selectedline + $dir]
+ unmarkmatches
+ selectline $l
+}
+
+proc addtocflist {id} {
+ global currentid treediffs cflist treepending
+ if {$id != $currentid} {
+ gettreediffs $currentid
+ return
+ }
+ $cflist insert end "All files"
+ foreach f $treediffs($currentid) {
+ $cflist insert end $f
+ }
+ getblobdiffs $id
+}
+
+proc gettreediffs {id} {
+ global treediffs parents treepending
+ set treepending $id
+ set treediffs($id) {}
+ set p [lindex $parents($id) 0]
+ if [catch {set gdtf [open "|git-diff-tree -r $p $id" r]}] return
+ fconfigure $gdtf -blocking 0
+ fileevent $gdtf readable "gettreediffline $gdtf $id"
+}
+
+proc gettreediffline {gdtf id} {
+ global treediffs treepending
+ set n [gets $gdtf line]
+ if {$n < 0} {
+ if {![eof $gdtf]} return
+ close $gdtf
+ unset treepending
+ addtocflist $id
+ return
+ }
+ set type [lindex $line 1]
+ set file [lindex $line 3]
+ if {$type == "blob"} {
+ lappend treediffs($id) $file
+ }
+}
+
+proc getblobdiffs {id} {
+ global parents diffopts blobdifffd env curdifftag curtagstart
+ 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] {
+ puts "error getting diffs: $err"
+ return
+ }
+ fconfigure $bdf -blocking 0
+ set blobdifffd($id) $bdf
+ set curdifftag Comments
+ set curtagstart 0.0
+ fileevent $bdf readable "getblobdiffline $bdf $id"
+}
+
+proc getblobdiffline {bdf id} {
+ global currentid blobdifffd ctext curdifftag curtagstart
+ 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
+ }
+ }
+ return
+ }
+ if {$id != $currentid || $bdf != $blobdifffd($id)} {
+ return
+ }
+ $ctext conf -state normal
+ if {[regexp {^---[ \t]+([^/])+/(.*)} $line match s1 fname]} {
+ # start of a new file
+ $ctext insert end "\n"
+ $ctext tag add $curdifftag $curtagstart end
+ set curtagstart [$ctext index "end - 1c"]
+ set curdifftag "f:$fname"
+ $ctext tag delete $curdifftag
+ set l [expr {(78 - [string length $fname]) / 2}]
+ set pad [string range "----------------------------------------" 1 $l]
+ $ctext insert end "$pad $fname $pad\n" filesep
+ } elseif {[string range $line 0 2] == "+++"} {
+ # no need to do anything with this
+ } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
+ $line match f1l f1c f2l f2c rest]} {
+ $ctext insert end "\t" hunksep
+ $ctext insert end " $f1l " d0 " $f2l " d1
+ $ctext insert end " $rest \n" hunksep
+ } else {
+ set x [string range $line 0 0]
+ if {$x == "-" || $x == "+"} {
+ set tag [expr {$x == "+"}]
+ set line [string range $line 1 end]
+ $ctext insert end "$line\n" d$tag
+ } elseif {$x == " "} {
+ set line [string range $line 1 end]
+ $ctext insert end "$line\n"
+ } else {
+ # Something else we don't recognize
+ if {$curdifftag != "Comments"} {
+ $ctext insert end "\n"
+ $ctext tag add $curdifftag $curtagstart end
+ set curtagstart [$ctext index "end - 1c"]
+ set curdifftag Comments
+ }
+ $ctext insert end "$line\n" filesep
+ }
+ }
+ $ctext conf -state disabled
+}
+
+proc listboxsel {} {
+ global ctext cflist currentid treediffs
+ 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
+ }
+ } else {
+ # just show selected files
+ $ctext tag conf Comments -elide 1
+ set i 1
+ foreach f $treediffs($currentid) {
+ set elide [expr {[lsearch -exact $sel $i] < 0}]
+ $ctext tag conf "f:$f" -elide $elide
+ incr i
+ }
+ }
+}
+
+proc setcoords {} {
+ global linespc charspc canvx0 canvy0 mainfont
+ set linespc [font metrics $mainfont -linespace]
+ set charspc [font measure $mainfont "m"]
+ set canvy0 [expr 3 + 0.5 * $linespc]
+ set canvx0 [expr 3 + 0.5 * $linespc]
+}
+
+proc redisplay {} {
+ global selectedline stopped redisplaying phase
+ if {$stopped > 1} return
+ if {$phase == "getcommits"} return
+ set redisplaying 1
+ if {$phase == "drawgraph"} {
+ set stopped 1
+ } else {
+ drawgraph
+ }
+}
+
+proc incrfont {inc} {
+ global mainfont namefont textfont selectedline ctext canv phase
+ global stopped
+ unmarkmatches
+ set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
+ set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
+ set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
+ setcoords
+ $ctext conf -font $textfont
+ $ctext tag conf filesep -font [concat $textfont bold]
+ if {$phase == "getcommits"} {
+ $canv itemconf textitems -font $mainfont
+ }
+ redisplay
+}
+
+proc doquit {} {
+ global stopped
+ set stopped 100
+ destroy .
+}
+
+# defaults...
+set datemode 0
+set boldnames 0
+set diffopts "-U 5 -p"