From 1db95b00a2d2a001fd91cd860a71c639ea04eb53 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 9 May 2005 04:08:39 +0000 Subject: [PATCH 01/29] Add initial version of gitk to the CVS repository --- gitk | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100755 gitk diff --git a/gitk b/gitk new file mode 100755 index 0000000000..90b2eab355 --- /dev/null +++ b/gitk @@ -0,0 +1,418 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "${1+$@}" + +# Copyright (C) 2005 Paul Mackerras. All rights reserved. +# This program is free software; it may be used, copied, modified +# and distributed under the terms of the GNU General Public Licence, +# either version 2, or (at your option) any later version. + +set datemode 0 +set boldnames 0 +set revtreeargs {} + +foreach arg $argv { + switch -regexp -- $arg { + "^$" { } + "^-d" { set datemode 1 } + "^-b" { set boldnames 1 } + "^-.*" { + puts stderr "unrecognized option $arg" + exit 1 + } + default { + lappend revtreeargs $arg + } + } +} + +proc getcommits {rargs} { + global commits parents cdate nparents children nchildren + if {$rargs == {}} { + set rargs HEAD + } + set commits {} + foreach c [split [eval exec git-rev-tree $rargs] "\n"] { + set i 0 + set cid {} + foreach f $c { + if {$i == 0} { + set d $f + } else { + set id [lindex [split $f :] 0] + if {![info exists nchildren($id)]} { + set children($id) {} + set nchildren($id) 0 + } + if {$i == 1} { + set cid $id + lappend commits $id + set parents($id) {} + set cdate($id) $d + set nparents($id) 0 + } else { + lappend parents($cid) $id + incr nparents($cid) + incr nchildren($id) + lappend children($id) $cid + } + } + incr i + } + } +} + +proc readcommit {id} { + global commitinfo + set inhdr 1 + set comment {} + set headline {} + set auname {} + set audate {} + set comname {} + set comdate {} + foreach line [split [exec git-cat-file commit $id] "\n"] { + if {$inhdr} { + if {$line == {}} { + set inhdr 0 + } else { + set tag [lindex $line 0] + if {$tag == "author"} { + set x [expr {[llength $line] - 2}] + set audate [lindex $line $x] + set auname [lrange $line 1 [expr {$x - 1}]] + } elseif {$tag == "committer"} { + set x [expr {[llength $line] - 2}] + set comdate [lindex $line $x] + set comname [lrange $line 1 [expr {$x - 1}]] + } + } + } else { + if {$comment == {}} { + set headline $line + } else { + append comment "\n" + } + append comment $line + } + } + if {$audate != {}} { + set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"] + } + if {$comdate != {}} { + set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] + } + set commitinfo($id) [list $comment $auname $audate $comname $comdate] + return [list $headline $auname $audate] +} + +proc makewindow {} { + global canv linespc charspc ctext + frame .clist + set canv .clist.canv + canvas $canv -height [expr 30 * $linespc + 4] -width [expr 90 * $charspc] \ + -bg white -relief sunk -bd 1 \ + -yscrollincr $linespc -yscrollcommand ".clist.csb set" + scrollbar .clist.csb -command "$canv yview" -highlightthickness 0 + pack .clist.csb -side right -fill y + pack $canv -side bottom -fill both -expand 1 + pack .clist -side top -fill both -expand 1 + set ctext .ctext + text $ctext -bg white + pack $ctext -side top -fill x -expand 1 + + bind $canv <1> {selcanvline %x %y} + bind $canv {selcanvline %x %y} + bind $canv "$canv yview scroll -5 u" + bind $canv "$canv yview scroll 5 u" + bind $canv <2> "$canv scan mark 0 %y" + bind $canv "$canv scan dragto 0 %y" + bind . "$canv yview scroll -1 p" + bind . "$canv yview scroll 1 p" + bind . "$canv yview scroll -1 p" + bind . "$canv yview scroll -1 p" + bind . "$canv yview scroll 1 p" + bind . "$canv yview scroll -1 u" + bind . "$canv yview scroll 1 u" + bind . Q "set stopped 1; destroy ." +} + +proc truncatetofit {str width font} { + if {[font measure $font $str] <= $width} { + return $str + } + set best 0 + set bad [string length $str] + set tmp $str + while {$best < $bad - 1} { + set try [expr {int(($best + $bad) / 2)}] + set tmp "[string range $str 0 [expr $try-1]]..." + if {[font measure $font $tmp] <= $width} { + set best $try + } else { + set bad $try + } + } + return $tmp +} + +proc drawgraph {start} { + global parents children nparents nchildren commits + global canv mainfont namefont canvx0 canvy0 linespc namex datex + global datemode cdate + global lineid linehtag linentag linedtag + + set colors {green red blue magenta darkgrey brown orange} + set ncolors [llength $colors] + set nextcolor 0 + set colormap($start) [lindex $colors 0] + foreach id $commits { + set ncleft($id) $nchildren($id) + } + set todo [list $start] + set level 0 + set canvy $canvy0 + set linestarty(0) $canvy + set nullentry -1 + set lineno -1 + while 1 { + incr lineno + set nlines [llength $todo] + set id [lindex $todo $level] + set lineid($lineno) $id + foreach p $parents($id) { + incr ncleft($p) -1 + } + set cinfo [readcommit $id] + set x [expr $canvx0 + $level * $linespc] + set y2 [expr $canvy + $linespc] + if {$linestarty($level) < $canvy} { + set t [$canv create line $x $linestarty($level) $x $canvy \ + -width 2 -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] + $canv raise $t + set xt [expr $canvx0 + $nlines * $linespc] + set headline [lindex $cinfo 0] + set name [lindex $cinfo 1] + set date [lindex $cinfo 2] + set headline [truncatetofit $headline [expr $namex-$xt-$linespc] \ + $mainfont] + set linehtag($lineno) [$canv create text $xt $canvy -anchor w \ + -text $headline -font $mainfont ] + set name [truncatetofit $name [expr $datex-$namex-$linespc] $namefont] + set linentag($lineno) [$canv create text $namex $canvy -anchor w \ + -text $name -font $namefont] + set linedtag($lineno) [$canv create text $datex $canvy -anchor w \ + -text $date -font $mainfont] + if {!$datemode && $nparents($id) == 1} { + set p [lindex $parents($id) 0] + if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { + set todo [lreplace $todo $level $level $p] + set colormap($p) $colormap($id) + set canvy $y2 + $canv conf -scrollregion [list 0 0 0 $canvy] + update + continue + } + } + + set oldtodo $todo + set oldlevel $level + set lines {} + for {set i 0} {$i < $nlines} {incr i} { + if {[lindex $todo $i] == {}} continue + set oldstarty($i) $linestarty($i) + if {$i != $level} { + lappend lines [list $i [lindex $todo $i]] + } + } + unset linestarty + if {$nullentry >= 0} { + set todo [lreplace $todo $nullentry $nullentry] + if {$nullentry < $level} { + incr level -1 + } + } + + set badcolors [list $colormap($id)] + foreach p $parents($id) { + if {[info exists colormap($p)]} { + lappend badcolors $colormap($p) + } + } + set todo [lreplace $todo $level $level] + if {$nullentry > $level} { + incr nullentry -1 + } + set i $level + foreach p $parents($id) { + set k [lsearch -exact $todo $p] + if {$k < 0} { + set todo [linsert $todo $i $p] + if {$nullentry >= $i} { + incr nullentry + } + if {$nparents($id) == 1 && $nparents($p) == 1 + && $nchildren($p) == 1} { + set colormap($p) $colormap($id) + } else { + for {set j 0} {$j <= $ncolors} {incr j} { + if {[incr nextcolor] >= $ncolors} { + set nextcolor 0 + } + set c [lindex $colors $nextcolor] + # make sure the incoming and outgoing colors differ + if {[lsearch -exact $badcolors $c] < 0} break + } + set colormap($p) $c + lappend badcolors $c + } + } + lappend lines [list $oldlevel $p] + } + + # choose which one to do next time around + set todol [llength $todo] + set level -1 + set latest {} + for {set k $todol} {[incr k -1] >= 0} {} { + set p [lindex $todo $k] + if {$p == {}} continue + if {$ncleft($p) == 0} { + if {$datemode} { + if {$latest == {} || $cdate($p) > $latest} { + set level $k + set latest $cdate($p) + } + } else { + set level $k + break + } + } + } + if {$level < 0} { + if {$todo != {}} { + puts "ERROR: none of the pending commits can be done yet:" + foreach p $todo { + puts " $p" + } + } + break + } + + # If we are reducing, put in a null entry + if {$todol < $nlines} { + if {$nullentry >= 0} { + set i $nullentry + while {$i < $todol + && [lindex $oldtodo $i] == [lindex $todo $i]} { + incr i + } + } else { + set i $oldlevel + if {$level >= $i} { + incr i + } + } + if {$i >= $todol} { + set nullentry -1 + } else { + set nullentry $i + set todo [linsert $todo $nullentry {}] + if {$level >= $i} { + incr level + } + } + } else { + set nullentry -1 + } + + foreach l $lines { + set i [lindex $l 0] + set dst [lindex $l 1] + set j [lsearch -exact $todo $dst] + if {$i == $j} { + set linestarty($i) $oldstarty($i) + continue + } + set xi [expr {$canvx0 + $i * $linespc}] + set xj [expr {$canvx0 + $j * $linespc}] + set coords {} + if {$oldstarty($i) < $canvy} { + lappend coords $xi $oldstarty($i) + } + lappend coords $xi $canvy + if {$j < $i - 1} { + lappend coords [expr $xj + $linespc] $canvy + } elseif {$j > $i + 1} { + lappend coords [expr $xj - $linespc] $canvy + } + lappend coords $xj $y2 + set t [$canv create line $coords -width 2 -fill $colormap($dst)] + $canv lower $t + if {![info exists linestarty($j)]} { + set linestarty($j) $y2 + } + } + set canvy $y2 + $canv conf -scrollregion [list 0 0 0 $canvy] + update + } +} + +proc selcanvline {x y} { + global canv canvy0 ctext linespc selectedline + global lineid linehtag linentag linedtag commitinfo + set ymax [lindex [$canv cget -scrollregion] 3] + set yfrac [lindex [$canv yview] 0] + set y [expr {$y + $yfrac * $ymax}] + set l [expr {int(($y - $canvy0) / $linespc + 0.5)}] + if {$l < 0} { + set l 0 + } + if {[info exists selectedline] && $selectedline == $l} return + if {![info exists lineid($l)] || ![info exists linehtag($l)]} return + $canv select clear + $canv select from $linehtag($l) 0 + $canv select to $linehtag($l) end + set id $lineid($l) + $ctext delete 0.0 end + set info $commitinfo($id) + $ctext insert end "Author: [lindex $info 1] \t[lindex $info 2]\n" + $ctext insert end "Committer: [lindex $info 3] \t[lindex $info 4]\n" + $ctext insert end "\n" + $ctext insert end [lindex $info 0] +} + +getcommits $revtreeargs + +set mainfont {Helvetica 9} +set namefont $mainfont +if {$boldnames} { + lappend namefont bold +} +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] +set namex [expr 45 * $charspc] +set datex [expr 75 * $charspc] + +makewindow + +set start {} +foreach id $commits { + if {$nchildren($id) == 0} { + set start $id + break + } +} +if {$start != {}} { + drawgraph $start +} From 0327d27a18e0d92a75a36a9e57512f940a906d88 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 10 May 2005 00:23:42 +0000 Subject: [PATCH 02/29] Use a panedwindow Make it cope with commits having parents that aren't listed. --- gitk | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/gitk b/gitk index 90b2eab355..801afbca7a 100755 --- a/gitk +++ b/gitk @@ -7,6 +7,8 @@ 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.2 $ + set datemode 0 set boldnames 0 set revtreeargs {} @@ -63,7 +65,7 @@ proc getcommits {rargs} { } proc readcommit {id} { - global commitinfo + global commitinfo commitsummary set inhdr 1 set comment {} set headline {} @@ -103,23 +105,27 @@ proc readcommit {id} { set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] } set commitinfo($id) [list $comment $auname $audate $comname $comdate] - return [list $headline $auname $audate] + set commitsummary($id) [list $headline $auname $audate] } proc makewindow {} { global canv linespc charspc ctext - frame .clist - set canv .clist.canv + panedwindow .ctop -orient vertical + frame .ctop.clist + set canv .ctop.clist.canv canvas $canv -height [expr 30 * $linespc + 4] -width [expr 90 * $charspc] \ -bg white -relief sunk -bd 1 \ - -yscrollincr $linespc -yscrollcommand ".clist.csb set" - scrollbar .clist.csb -command "$canv yview" -highlightthickness 0 - pack .clist.csb -side right -fill y + -yscrollincr $linespc -yscrollcommand ".ctop.clist.csb set" + scrollbar .ctop.clist.csb -command "$canv yview" -highlightthickness 0 + pack .ctop.clist.csb -side right -fill y pack $canv -side bottom -fill both -expand 1 - pack .clist -side top -fill both -expand 1 - set ctext .ctext + .ctop add .ctop.clist + #pack .ctop.clist -side top -fill both -expand 1 + set ctext .ctop.ctext text $ctext -bg white - pack $ctext -side top -fill x -expand 1 + .ctop add .ctop.ctext + #pack $ctext -side top -fill x -expand 1 + pack .ctop -side top -fill both -expand 1 bind $canv <1> {selcanvline %x %y} bind $canv {selcanvline %x %y} @@ -160,7 +166,7 @@ proc drawgraph {start} { global parents children nparents nchildren commits global canv mainfont namefont canvx0 canvy0 linespc namex datex global datemode cdate - global lineid linehtag linentag linedtag + global lineid linehtag linentag linedtag commitsummary set colors {green red blue magenta darkgrey brown orange} set ncolors [llength $colors] @@ -180,10 +186,16 @@ proc drawgraph {start} { set nlines [llength $todo] set id [lindex $todo $level] set lineid($lineno) $id + set actualparents {} foreach p $parents($id) { - incr ncleft($p) -1 + if {[info exists ncleft($p)]} { + incr ncleft($p) -1 + lappend actualparents $p + } + } + if {![info exists commitsummary($id)]} { + readcommit $id } - set cinfo [readcommit $id] set x [expr $canvx0 + $level * $linespc] set y2 [expr $canvy + $linespc] if {$linestarty($level) < $canvy} { @@ -197,9 +209,9 @@ proc drawgraph {start} { -fill blue -outline black -width 1] $canv raise $t set xt [expr $canvx0 + $nlines * $linespc] - set headline [lindex $cinfo 0] - set name [lindex $cinfo 1] - set date [lindex $cinfo 2] + set headline [lindex $commitsummary($id) 0] + set name [lindex $commitsummary($id) 1] + set date [lindex $commitsummary($id) 2] set headline [truncatetofit $headline [expr $namex-$xt-$linespc] \ $mainfont] set linehtag($lineno) [$canv create text $xt $canvy -anchor w \ @@ -209,8 +221,8 @@ proc drawgraph {start} { -text $name -font $namefont] set linedtag($lineno) [$canv create text $datex $canvy -anchor w \ -text $date -font $mainfont] - if {!$datemode && $nparents($id) == 1} { - set p [lindex $parents($id) 0] + if {!$datemode && [llength $actualparents] == 1} { + set p [lindex $actualparents 0] if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { set todo [lreplace $todo $level $level $p] set colormap($p) $colormap($id) @@ -240,7 +252,7 @@ proc drawgraph {start} { } set badcolors [list $colormap($id)] - foreach p $parents($id) { + foreach p $actualparents { if {[info exists colormap($p)]} { lappend badcolors $colormap($p) } @@ -250,7 +262,7 @@ proc drawgraph {start} { incr nullentry -1 } set i $level - foreach p $parents($id) { + foreach p $actualparents { set k [lsearch -exact $todo $p] if {$k < 0} { set todo [linsert $todo $i $p] From 5ad588de729eb11629f8ff31a248e8abd44e4a9a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 10 May 2005 01:02:55 +0000 Subject: [PATCH 03/29] Display the list of changed files in a listbox pane. --- gitk | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/gitk b/gitk index 801afbca7a..1b411598f5 100755 --- 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.2 $ +# CVS $Revision: 1.3 $ set datemode 0 set boldnames 0 @@ -108,8 +108,22 @@ proc readcommit {id} { set commitsummary($id) [list $headline $auname $audate] } +proc gettreediffs {id} { + global treediffs parents + set p [lindex $parents($id) 0] + set diff {} + foreach line [split [exec git-diff-tree -r $p $id] "\n"] { + set type [lindex $line 1] + set file [lindex $line 3] + if {$type == "blob"} { + lappend diff $file + } + } + set treediffs($id) $diff +} + proc makewindow {} { - global canv linespc charspc ctext + global canv linespc charspc ctext cflist panedwindow .ctop -orient vertical frame .ctop.clist set canv .ctop.clist.canv @@ -121,10 +135,15 @@ proc makewindow {} { pack $canv -side bottom -fill both -expand 1 .ctop add .ctop.clist #pack .ctop.clist -side top -fill both -expand 1 - set ctext .ctop.ctext - text $ctext -bg white - .ctop add .ctop.ctext + panedwindow .ctop.cdet -orient horizontal + .ctop add .ctop.cdet + set ctext .ctop.cdet.ctext + text $ctext -bg white -state disabled + .ctop.cdet add $ctext #pack $ctext -side top -fill x -expand 1 + set cflist .ctop.cdet.cfiles + listbox $cflist -width 30 -bg white + .ctop.cdet add $cflist pack .ctop -side top -fill both -expand 1 bind $canv <1> {selcanvline %x %y} @@ -138,8 +157,8 @@ proc makewindow {} { bind . "$canv yview scroll -1 p" bind . "$canv yview scroll -1 p" bind . "$canv yview scroll 1 p" - bind . "$canv yview scroll -1 u" - bind . "$canv yview scroll 1 u" + bind . "selnextline -1" + bind . "selnextline 1" bind . Q "set stopped 1; destroy ." } @@ -164,7 +183,7 @@ proc truncatetofit {str width font} { proc drawgraph {start} { global parents children nparents nchildren commits - global canv mainfont namefont canvx0 canvy0 linespc namex datex + global canv mainfont namefont canvx0 canvy0 canvy linespc namex datex global datemode cdate global lineid linehtag linentag linedtag commitsummary @@ -388,17 +407,56 @@ proc selcanvline {x y} { set l 0 } if {[info exists selectedline] && $selectedline == $l} return + selectline $l +} + +proc selectline {l} { + global canv ctext commitinfo selectedline lineid linehtag + global canvy canvy0 linespc nparents + global cflist treediffs if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv select clear $canv select from $linehtag($l) 0 $canv select to $linehtag($l) end + set y [expr {$canvy0 + $l * $linespc}] + set ytop [expr {($y - $linespc / 2.0) / $canvy}] + set ybot [expr {($y + $linespc / 2.0) / $canvy}] + set wnow [$canv yview] + if {$ytop < [lindex $wnow 0]} { + $canv yview moveto $ytop + } elseif {$ybot > [lindex $wnow 1]} { + set wh [expr {[lindex $wnow 1] - [lindex $wnow 0]}] + $canv yview moveto [expr {$ybot - $wh}] + } + set selectedline $l + set id $lineid($l) + $ctext conf -state normal $ctext delete 0.0 end set info $commitinfo($id) $ctext insert end "Author: [lindex $info 1] \t[lindex $info 2]\n" $ctext insert end "Committer: [lindex $info 3] \t[lindex $info 4]\n" $ctext insert end "\n" $ctext insert end [lindex $info 0] + $ctext conf -state disabled + + $cflist delete 0 end + if {$nparents($id) == 1} { + if {![info exists treediffs($id)]} { + gettreediffs $id + } + foreach f $treediffs($id) { + $cflist insert end $f + } + } + +} + +proc selnextline {dir} { + global selectedline + if {![info exists selectedline]} return + set l [expr $selectedline + $dir] + selectline $l } getcommits $revtreeargs From b5721c72b7b69df1dd7417cf8f784aac7a8fee2e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 10 May 2005 12:08:22 +0000 Subject: [PATCH 04/29] source ~/.gitk for user-specific option settings use a panedwindow for the main list with three panes, and make them scroll together --- gitk | 107 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/gitk b/gitk index 1b411598f5..953b1e5838 100755 --- a/gitk +++ b/gitk @@ -7,12 +7,19 @@ 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.3 $ +# CVS $Revision: 1.4 $ set datemode 0 set boldnames 0 set revtreeargs {} +set mainfont {Helvetica 9} +set namefont $mainfont +if {$boldnames} { + lappend namefont bold +} +catch {source ~/.gitk} + foreach arg $argv { switch -regexp -- $arg { "^$" { } @@ -123,18 +130,29 @@ proc gettreediffs {id} { } proc makewindow {} { - global canv linespc charspc ctext cflist + global canv canv2 canv3 linespc charspc ctext cflist panedwindow .ctop -orient vertical - frame .ctop.clist - set canv .ctop.clist.canv - canvas $canv -height [expr 30 * $linespc + 4] -width [expr 90 * $charspc] \ - -bg white -relief sunk -bd 1 \ - -yscrollincr $linespc -yscrollcommand ".ctop.clist.csb set" - scrollbar .ctop.clist.csb -command "$canv yview" -highlightthickness 0 - pack .ctop.clist.csb -side right -fill y - pack $canv -side bottom -fill both -expand 1 + panedwindow .ctop.clist -orient horizontal -sashpad 0 -handlesize 4 .ctop add .ctop.clist - #pack .ctop.clist -side top -fill both -expand 1 + set canv .ctop.clist.canv + set cscroll .ctop.clist.dates.csb + canvas $canv -height [expr 30 * $linespc + 4] -width [expr 45 * $charspc] \ + -bg white -bd 0 \ + -yscrollincr $linespc -yscrollcommand "$cscroll set" + .ctop.clist add $canv + set canv2 .ctop.clist.canv2 + canvas $canv2 -height [expr 30 * $linespc +4] -width [expr 30 * $charspc] \ + -bg white -bd 0 -yscrollincr $linespc + .ctop.clist add $canv2 + frame .ctop.clist.dates + .ctop.clist add .ctop.clist.dates + set canv3 .ctop.clist.dates.canv3 + canvas $canv3 -height [expr 30 * $linespc +4] -width [expr 15 * $charspc] \ + -bg white -bd 0 -yscrollincr $linespc + scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 + pack .ctop.clist.dates.csb -side right -fill y + pack $canv3 -side left -fill both -expand 1 + panedwindow .ctop.cdet -orient horizontal .ctop add .ctop.cdet set ctext .ctop.cdet.ctext @@ -146,22 +164,36 @@ proc makewindow {} { .ctop.cdet add $cflist pack .ctop -side top -fill both -expand 1 - bind $canv <1> {selcanvline %x %y} - bind $canv {selcanvline %x %y} - bind $canv "$canv yview scroll -5 u" - bind $canv "$canv yview scroll 5 u" - bind $canv <2> "$canv scan mark 0 %y" - bind $canv "$canv scan dragto 0 %y" - bind . "$canv yview scroll -1 p" - bind . "$canv yview scroll 1 p" - bind . "$canv yview scroll -1 p" - bind . "$canv yview scroll -1 p" - bind . "$canv yview scroll 1 p" + bindall <1> {selcanvline %x %y} + bindall {selcanvline %x %y} + bindall "allcanvs yview scroll -5 u" + bindall "allcanvs yview scroll 5 u" + bindall <2> "allcanvs scan mark 0 %y" + bindall "allcanvs scan dragto 0 %y" + bind . "allcanvs yview scroll -1 p" + bind . "allcanvs yview scroll 1 p" + bind . "allcanvs yview scroll -1 p" + bind . "allcanvs yview scroll -1 p" + bind . "allcanvs yview scroll 1 p" bind . "selnextline -1" bind . "selnextline 1" bind . Q "set stopped 1; destroy ." } +proc allcanvs args { + global canv canv2 canv3 + eval $canv $args + eval $canv2 $args + eval $canv3 $args +} + +proc bindall {event action} { + global canv canv2 canv3 + bind $canv $event $action + bind $canv2 $event $action + bind $canv3 $event $action +} + proc truncatetofit {str width font} { if {[font measure $font $str] <= $width} { return $str @@ -183,7 +215,7 @@ proc truncatetofit {str width font} { proc drawgraph {start} { global parents children nparents nchildren commits - global canv mainfont namefont canvx0 canvy0 canvy linespc namex datex + global canv canv2 canv3 mainfont namefont canvx0 canvy0 canvy linespc global datemode cdate global lineid linehtag linentag linedtag commitsummary @@ -196,11 +228,14 @@ proc drawgraph {start} { } set todo [list $start] set level 0 - set canvy $canvy0 - set linestarty(0) $canvy + set y2 $canvy0 + set linestarty(0) $canvy0 set nullentry -1 set lineno -1 while 1 { + set canvy $y2 + allcanvs conf -scrollregion [list 0 0 0 $canvy] + update incr lineno set nlines [llength $todo] set id [lindex $todo $level] @@ -231,23 +266,17 @@ proc drawgraph {start} { set headline [lindex $commitsummary($id) 0] set name [lindex $commitsummary($id) 1] set date [lindex $commitsummary($id) 2] - set headline [truncatetofit $headline [expr $namex-$xt-$linespc] \ - $mainfont] set linehtag($lineno) [$canv create text $xt $canvy -anchor w \ -text $headline -font $mainfont ] - set name [truncatetofit $name [expr $datex-$namex-$linespc] $namefont] - set linentag($lineno) [$canv create text $namex $canvy -anchor w \ + set linentag($lineno) [$canv2 create text 3 $canvy -anchor w \ -text $name -font $namefont] - set linedtag($lineno) [$canv create text $datex $canvy -anchor w \ + set linedtag($lineno) [$canv3 create text 3 $canvy -anchor w \ -text $date -font $mainfont] if {!$datemode && [llength $actualparents] == 1} { set p [lindex $actualparents 0] if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { set todo [lreplace $todo $level $level $p] set colormap($p) $colormap($id) - set canvy $y2 - $canv conf -scrollregion [list 0 0 0 $canvy] - update continue } } @@ -390,9 +419,6 @@ proc drawgraph {start} { set linestarty($j) $y2 } } - set canvy $y2 - $canv conf -scrollregion [list 0 0 0 $canvy] - update } } @@ -423,10 +449,10 @@ proc selectline {l} { set ybot [expr {($y + $linespc / 2.0) / $canvy}] set wnow [$canv yview] if {$ytop < [lindex $wnow 0]} { - $canv yview moveto $ytop + allcanvs yview moveto $ytop } elseif {$ybot > [lindex $wnow 1]} { set wh [expr {[lindex $wnow 1] - [lindex $wnow 0]}] - $canv yview moveto [expr {$ybot - $wh}] + allcanvs yview moveto [expr {$ybot - $wh}] } set selectedline $l @@ -461,11 +487,6 @@ proc selnextline {dir} { getcommits $revtreeargs -set mainfont {Helvetica 9} -set namefont $mainfont -if {$boldnames} { - lappend namefont bold -} set linespc [font metrics $mainfont -linespace] set charspc [font measure $mainfont "m"] From d2610d110ea75e35e62ca492d6f410a62d74dbc9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 11 May 2005 00:45:38 +0000 Subject: [PATCH 05/29] Make getting file lists asynchronous Add some scrollbars --- gitk | 115 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 34 deletions(-) diff --git a/gitk b/gitk index 953b1e5838..b8da2ac599 100755 --- 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.4 $ +# CVS $Revision: 1.5 $ set datemode 0 set boldnames 0 @@ -115,20 +115,6 @@ proc readcommit {id} { set commitsummary($id) [list $headline $auname $audate] } -proc gettreediffs {id} { - global treediffs parents - set p [lindex $parents($id) 0] - set diff {} - foreach line [split [exec git-diff-tree -r $p $id] "\n"] { - set type [lindex $line 1] - set file [lindex $line 3] - if {$type == "blob"} { - lappend diff $file - } - } - set treediffs($id) $diff -} - proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist panedwindow .ctop -orient vertical @@ -155,13 +141,24 @@ proc makewindow {} { panedwindow .ctop.cdet -orient horizontal .ctop add .ctop.cdet - set ctext .ctop.cdet.ctext - text $ctext -bg white -state disabled - .ctop.cdet add $ctext - #pack $ctext -side top -fill x -expand 1 - set cflist .ctop.cdet.cfiles - listbox $cflist -width 30 -bg white - .ctop.cdet add $cflist + frame .ctop.cdet.left + set ctext .ctop.cdet.left.ctext + text $ctext -bg white -state disabled \ + -yscrollcommand ".ctop.cdet.left.sb set" + scrollbar .ctop.cdet.left.sb -command "$ctext yview" + pack .ctop.cdet.left.sb -side right -fill y + pack $ctext -side left -fill both -expand 1 + .ctop.cdet add .ctop.cdet.left + + frame .ctop.cdet.right + set cflist .ctop.cdet.right.cfiles + listbox $cflist -width 30 -bg white \ + -yscrollcommand ".ctop.cdet.right.sb set" + scrollbar .ctop.cdet.right.sb -command "$cflist yview" + pack .ctop.cdet.right.sb -side right -fill y + pack $cflist -side left -fill both -expand 1 + .ctop.cdet add .ctop.cdet.right + pack .ctop -side top -fill both -expand 1 bindall <1> {selcanvline %x %y} @@ -437,13 +434,23 @@ proc selcanvline {x y} { } proc selectline {l} { - global canv ctext commitinfo selectedline lineid linehtag - global canvy canvy0 linespc nparents - global cflist treediffs + global canv canv2 canv3 ctext commitinfo selectedline + global lineid linehtag linentag linedtag + global canvy canvy0 linespc nparents treepending + global cflist treediffs currentid if {![info exists lineid($l)] || ![info exists linehtag($l)]} return - $canv select clear - $canv select from $linehtag($l) 0 - $canv select to $linehtag($l) end + $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 set y [expr {$canvy0 + $l * $linespc}] set ytop [expr {($y - $linespc / 2.0) / $canvy}] set ybot [expr {($y + $linespc / 2.0) / $canvy}] @@ -460,24 +467,64 @@ proc selectline {l} { $ctext conf -state normal $ctext delete 0.0 end set info $commitinfo($id) - $ctext insert end "Author: [lindex $info 1] \t[lindex $info 2]\n" - $ctext insert end "Committer: [lindex $info 3] \t[lindex $info 4]\n" + $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" + $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" $ctext insert end "\n" $ctext insert end [lindex $info 0] $ctext conf -state disabled $cflist delete 0 end + set currentid $id if {$nparents($id) == 1} { if {![info exists treediffs($id)]} { - gettreediffs $id - } - foreach f $treediffs($id) { - $cflist insert end $f + if {![info exists treepending]} { + gettreediffs $id + } + } else { + addtocflist $id } } } +proc addtocflist {id} { + global currentid treediffs cflist treepending + if {$id != $currentid} { + gettreediffs $currentid + return + } + foreach f $treediffs($currentid) { + $cflist insert end $f + } +} + +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 selnextline {dir} { global selectedline if {![info exists selectedline]} return From e5c2d856444f495d41aa33747ce91beebf04aae9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 11 May 2005 23:44:54 +0000 Subject: [PATCH 06/29] Show the diffs when a commit is selected Selecting in the listbox reduces the text view to just the diff for the file(s) selected Added -c option for color-by-committer Added some more key bindings --- gitk | 255 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 202 insertions(+), 53 deletions(-) diff --git a/gitk b/gitk index b8da2ac599..132afd8fef 100755 --- a/gitk +++ b/gitk @@ -7,24 +7,31 @@ 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.5 $ +# CVS $Revision: 1.6 $ set datemode 0 set boldnames 0 set revtreeargs {} +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} foreach arg $argv { switch -regexp -- $arg { "^$" { } - "^-d" { set datemode 1 } "^-b" { set boldnames 1 } + "^-c" { set colorbycommitter 1 } + "^-d" { set datemode 1 } "^-.*" { puts stderr "unrecognized option $arg" exit 1 @@ -72,7 +79,7 @@ proc getcommits {rargs} { } proc readcommit {id} { - global commitinfo commitsummary + global commitinfo set inhdr 1 set comment {} set headline {} @@ -111,29 +118,30 @@ proc readcommit {id} { if {$comdate != {}} { set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] } - set commitinfo($id) [list $comment $auname $audate $comname $comdate] - set commitsummary($id) [list $headline $auname $audate] + set commitinfo($id) [list $headline $auname $audate \ + $comname $comdate $comment] } proc makewindow {} { - global canv canv2 canv3 linespc charspc ctext cflist + global canv canv2 canv3 linespc charspc ctext cflist textfont panedwindow .ctop -orient vertical panedwindow .ctop.clist -orient horizontal -sashpad 0 -handlesize 4 .ctop add .ctop.clist set canv .ctop.clist.canv set cscroll .ctop.clist.dates.csb - canvas $canv -height [expr 30 * $linespc + 4] -width [expr 45 * $charspc] \ + set height [expr 25 * $linespc + 4] + canvas $canv -height $height -width [expr 45 * $charspc] \ -bg white -bd 0 \ -yscrollincr $linespc -yscrollcommand "$cscroll set" .ctop.clist add $canv set canv2 .ctop.clist.canv2 - canvas $canv2 -height [expr 30 * $linespc +4] -width [expr 30 * $charspc] \ + canvas $canv2 -height $height -width [expr 30 * $charspc] \ -bg white -bd 0 -yscrollincr $linespc .ctop.clist add $canv2 frame .ctop.clist.dates .ctop.clist add .ctop.clist.dates set canv3 .ctop.clist.dates.canv3 - canvas $canv3 -height [expr 30 * $linespc +4] -width [expr 15 * $charspc] \ + canvas $canv3 -height $height -width [expr 15 * $charspc] \ -bg white -bd 0 -yscrollincr $linespc scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 pack .ctop.clist.dates.csb -side right -fill y @@ -143,16 +151,21 @@ proc makewindow {} { .ctop add .ctop.cdet frame .ctop.cdet.left set ctext .ctop.cdet.left.ctext - text $ctext -bg white -state disabled \ + text $ctext -bg white -state disabled -font $textfont -height 32 \ -yscrollcommand ".ctop.cdet.left.sb set" scrollbar .ctop.cdet.left.sb -command "$ctext yview" pack .ctop.cdet.left.sb -side right -fill y pack $ctext -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.left + $ctext tag conf filesep -font [concat $textfont bold] + $ctext tag conf hunksep -back blue -fore white + $ctext tag conf d0 -back "#ff8080" + $ctext tag conf d1 -back green + frame .ctop.cdet.right set cflist .ctop.cdet.right.cfiles - listbox $cflist -width 30 -bg white \ + listbox $cflist -width 30 -bg white -selectmode extended \ -yscrollcommand ".ctop.cdet.right.sb set" scrollbar .ctop.cdet.right.sb -command "$cflist yview" pack .ctop.cdet.right.sb -side right -fill y @@ -167,14 +180,20 @@ proc makewindow {} { bindall "allcanvs yview scroll 5 u" bindall <2> "allcanvs scan mark 0 %y" bindall "allcanvs scan dragto 0 %y" - bind . "allcanvs yview scroll -1 p" - bind . "allcanvs yview scroll 1 p" - bind . "allcanvs yview scroll -1 p" - bind . "allcanvs yview scroll -1 p" - bind . "allcanvs yview scroll 1 p" bind . "selnextline -1" bind . "selnextline 1" + bind . p "selnextline -1" + bind . n "selnextline 1" + bind . "allcanvs yview scroll -1 p" + bind . "allcanvs yview scroll 1 p" + bind . "$ctext yview scroll -1 p" + bind . "$ctext yview scroll -1 p" + bind . "$ctext yview scroll 1 p" + bind . b "$ctext yview scroll -1 p" + bind . d "$ctext yview scroll 18 u" + bind . u "$ctext yview scroll -18 u" bind . Q "set stopped 1; destroy ." + bind $cflist <> listboxsel } proc allcanvs args { @@ -210,16 +229,71 @@ proc truncatetofit {str width font} { return $tmp } +proc assigncolor {id} { + global commitinfo colormap commcolors colors nextcolor + global colorbycommitter + global parents nparents children nchildren + if [info exists colormap($id)] return + set ncolors [llength $colors] + if {$colorbycommitter} { + if {![info exists commitinfo($id)]} { + readcommit $id + } + set comm [lindex $commitinfo($id) 3] + if {![info exists commcolors($comm)]} { + set commcolors($comm) [lindex $colors $nextcolor] + if {[incr nextcolor] >= $ncolors} { + set nextcolor 0 + } + } + set colormap($id) $commcolors($comm) + } else { + if {$nparents($id) == 1 && $nchildren($id) == 1} { + set child [lindex $children($id) 0] + if {[info exists colormap($child)] + && $nparents($child) == 1} { + set colormap($id) $colormap($child) + return + } + } + set badcolors {} + foreach child $children($id) { + if {[info exists colormap($child)] + && [lsearch -exact $badcolors $colormap($child)] < 0} { + lappend badcolors $colormap($child) + } + if {[info exists parents($child)]} { + foreach p $parents($child) { + if {[info exists colormap($p)] + && [lsearch -exact $badcolors $colormap($p)] < 0} { + lappend badcolors $colormap($p) + } + } + } + } + if {[llength $badcolors] >= $ncolors} { + set badcolors {} + } + for {set i 0} {$i <= $ncolors} {incr i} { + set c [lindex $colors $nextcolor] + if {[incr nextcolor] >= $ncolors} { + set nextcolor 0 + } + if {[lsearch -exact $badcolors $c]} break + } + set colormap($id) $c + } +} + proc drawgraph {start} { global parents children nparents nchildren commits global canv canv2 canv3 mainfont namefont canvx0 canvy0 canvy linespc global datemode cdate - global lineid linehtag linentag linedtag commitsummary + global lineid linehtag linentag linedtag commitinfo + global nextcolor colormap - set colors {green red blue magenta darkgrey brown orange} - set ncolors [llength $colors] set nextcolor 0 - set colormap($start) [lindex $colors 0] + assigncolor $start foreach id $commits { set ncleft($id) $nchildren($id) } @@ -244,7 +318,7 @@ proc drawgraph {start} { lappend actualparents $p } } - if {![info exists commitsummary($id)]} { + if {![info exists commitinfo($id)]} { readcommit $id } set x [expr $canvx0 + $level * $linespc] @@ -260,9 +334,9 @@ proc drawgraph {start} { -fill blue -outline black -width 1] $canv raise $t set xt [expr $canvx0 + $nlines * $linespc] - set headline [lindex $commitsummary($id) 0] - set name [lindex $commitsummary($id) 1] - set date [lindex $commitsummary($id) 2] + set headline [lindex $commitinfo($id) 0] + set name [lindex $commitinfo($id) 1] + set date [lindex $commitinfo($id) 2] set linehtag($lineno) [$canv create text $xt $canvy -anchor w \ -text $headline -font $mainfont ] set linentag($lineno) [$canv2 create text 3 $canvy -anchor w \ @@ -272,8 +346,8 @@ proc drawgraph {start} { if {!$datemode && [llength $actualparents] == 1} { set p [lindex $actualparents 0] if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { + assigncolor $p set todo [lreplace $todo $level $level $p] - set colormap($p) $colormap($id) continue } } @@ -296,12 +370,6 @@ proc drawgraph {start} { } } - set badcolors [list $colormap($id)] - foreach p $actualparents { - if {[info exists colormap($p)]} { - lappend badcolors $colormap($p) - } - } set todo [lreplace $todo $level $level] if {$nullentry > $level} { incr nullentry -1 @@ -310,25 +378,11 @@ proc drawgraph {start} { foreach p $actualparents { set k [lsearch -exact $todo $p] if {$k < 0} { + assigncolor $p set todo [linsert $todo $i $p] if {$nullentry >= $i} { incr nullentry } - if {$nparents($id) == 1 && $nparents($p) == 1 - && $nchildren($p) == 1} { - set colormap($p) $colormap($id) - } else { - for {set j 0} {$j <= $ncolors} {incr j} { - if {[incr nextcolor] >= $ncolors} { - set nextcolor 0 - } - set c [lindex $colors $nextcolor] - # make sure the incoming and outgoing colors differ - if {[lsearch -exact $badcolors $c] < 0} break - } - set colormap($p) $c - lappend badcolors $c - } } lappend lines [list $oldlevel $p] } @@ -421,7 +475,7 @@ proc drawgraph {start} { proc selcanvline {x y} { global canv canvy0 ctext linespc selectedline - global lineid linehtag linentag linedtag commitinfo + global lineid linehtag linentag linedtag set ymax [lindex [$canv cget -scrollregion] 3] set yfrac [lindex [$canv yview] 0] set y [expr {$y + $yfrac * $ymax}] @@ -470,7 +524,9 @@ proc selectline {l} { $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" $ctext insert end "\n" - $ctext insert end [lindex $info 0] + $ctext insert end [lindex $info 5] + $ctext insert end "\n" + $ctext tag delete Comments $ctext conf -state disabled $cflist delete 0 end @@ -484,7 +540,13 @@ proc selectline {l} { addtocflist $id } } +} +proc selnextline {dir} { + global selectedline + if {![info exists selectedline]} return + set l [expr $selectedline + $dir] + selectline $l } proc addtocflist {id} { @@ -493,9 +555,11 @@ proc addtocflist {id} { gettreediffs $currentid return } + $cflist insert end "All files" foreach f $treediffs($currentid) { $cflist insert end $f } + getblobdiffs $id } proc gettreediffs {id} { @@ -525,11 +589,96 @@ proc gettreediffline {gdtf id} { } } -proc selnextline {dir} { - global selectedline - if {![info exists selectedline]} return - set l [expr $selectedline + $dir] - selectline $l +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 + 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 + } + } } getcommits $revtreeargs From 9a40c50c1e05c0658b7a7c68b56d615eb6f170dd Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 12 May 2005 23:46:16 +0000 Subject: [PATCH 07/29] Make behaviour when git-rev-tree fails nicer Fix crash benh saw with currentid undefined Add menu with file/quit and help/about items Add ^Q for quit --- gitk | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index 132afd8fef..fe954da0a9 100755 --- 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.6 $ +# CVS $Revision: 1.7 $ set datemode 0 set boldnames 0 @@ -48,7 +48,17 @@ proc getcommits {rargs} { set rargs HEAD } set commits {} - foreach c [split [eval exec git-rev-tree $rargs] "\n"] { + if [catch {set clist [eval exec git-rev-tree $rargs]} err] { + if {[string range $err 0 4] == "usage"} { + puts stderr "Error reading commits: bad arguments to git-rev-tree" + puts stderr "Note: arguments to gitk are passed to git-rev-tree" + puts stderr " to allow selection of commits to be displayed" + } else { + puts stderr "Error reading commits: $err" + } + return 0 + } + foreach c [split $clist "\n"] { set i 0 set cid {} foreach f $c { @@ -76,6 +86,7 @@ proc getcommits {rargs} { incr i } } + return 1 } proc readcommit {id} { @@ -124,6 +135,16 @@ proc readcommit {id} { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont + + menu .bar + .bar add cascade -label "File" -menu .bar.file + menu .bar.file + .bar.file add command -label "Quit" -command "set stopped 1; destroy ." + menu .bar.help + .bar add cascade -label "Help" -menu .bar.help + .bar.help add command -label "About gitk" -command about + . configure -menu .bar + panedwindow .ctop -orient vertical panedwindow .ctop.clist -orient horizontal -sashpad 0 -handlesize 4 .ctop add .ctop.clist @@ -193,6 +214,7 @@ proc makewindow {} { bind . d "$ctext yview scroll 18 u" bind . u "$ctext yview scroll -18 u" bind . Q "set stopped 1; destroy ." + bind . "set stopped 1; destroy ." bind $cflist <> listboxsel } @@ -210,6 +232,28 @@ proc bindall {event action} { bind $canv3 $event $action } +proc about {} { + set w .about + if {[winfo exists $w]} { + raise $w + return + } + toplevel $w + wm title $w "About gitk" + message $w.m -text { +Gitk version 0.9 + +Copyright © 2005 Paul Mackerras + +Use and redistribute under the terms of the GNU General Public License + +(CVS $Revision: 1.7 $)} \ + -justify center -aspect 400 + pack $w.m -side top -fill x -padx 20 -pady 20 + button $w.ok -text Close -command "destroy $w" + pack $w.ok -side bottom +} + proc truncatetofit {str width font} { if {[font measure $font $str] <= $width} { return $str @@ -291,6 +335,7 @@ proc drawgraph {start} { global datemode cdate global lineid linehtag linentag linedtag commitinfo global nextcolor colormap + global stopped set nextcolor 0 assigncolor $start @@ -307,6 +352,7 @@ proc drawgraph {start} { set canvy $y2 allcanvs conf -scrollregion [list 0 0 0 $canvy] update + if {$stopped} return incr lineno set nlines [llength $todo] set id [lindex $todo $level] @@ -662,6 +708,7 @@ proc getblobdiffline {bdf id} { 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 @@ -681,7 +728,9 @@ proc listboxsel {} { } } -getcommits $revtreeargs +if {![getcommits $revtreeargs]} { + exit 1 +} set linespc [font metrics $mainfont -linespace] set charspc [font measure $mainfont "m"] @@ -691,6 +740,7 @@ set canvx0 [expr 3 + 0.5 * $linespc] set namex [expr 45 * $charspc] set datex [expr 75 * $charspc] +set stopped 0 makewindow set start {} From 98f350e50124567f90691f6142e1c048c2b4600c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 15 May 2005 05:56:51 +0000 Subject: [PATCH 08/29] Add a widget to show the SHA1 ID of the current commit Add a find facility to search within the commits Cope with multiple starting points. --- gitk | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 197 insertions(+), 30 deletions(-) diff --git a/gitk b/gitk index fe954da0a9..3444bac558 100755 --- 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.7 $ +# CVS $Revision: 1.8 $ set datemode 0 set boldnames 0 @@ -135,6 +135,7 @@ proc readcommit {id} { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont + global sha1entry findtype findloc findstring menu .bar .bar add cascade -label "File" -menu .bar.file @@ -146,27 +147,48 @@ proc makewindow {} { . configure -menu .bar panedwindow .ctop -orient vertical - panedwindow .ctop.clist -orient horizontal -sashpad 0 -handlesize 4 - .ctop add .ctop.clist - set canv .ctop.clist.canv - set cscroll .ctop.clist.dates.csb + frame .ctop.top + frame .ctop.top.bar + pack .ctop.top.bar -side bottom -fill x + set cscroll .ctop.top.csb + scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 + pack $cscroll -side right -fill y + panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4 + pack .ctop.top.clist -side top -fill both -expand 1 + .ctop add .ctop.top + set canv .ctop.top.clist.canv set height [expr 25 * $linespc + 4] canvas $canv -height $height -width [expr 45 * $charspc] \ -bg white -bd 0 \ -yscrollincr $linespc -yscrollcommand "$cscroll set" - .ctop.clist add $canv - set canv2 .ctop.clist.canv2 + .ctop.top.clist add $canv + set canv2 .ctop.top.clist.canv2 canvas $canv2 -height $height -width [expr 30 * $charspc] \ -bg white -bd 0 -yscrollincr $linespc - .ctop.clist add $canv2 - frame .ctop.clist.dates - .ctop.clist add .ctop.clist.dates - set canv3 .ctop.clist.dates.canv3 + .ctop.top.clist add $canv2 + set canv3 .ctop.top.clist.canv3 canvas $canv3 -height $height -width [expr 15 * $charspc] \ -bg white -bd 0 -yscrollincr $linespc - scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 - pack .ctop.clist.dates.csb -side right -fill y - pack $canv3 -side left -fill both -expand 1 + .ctop.top.clist add $canv3 + + set sha1entry .ctop.top.bar.sha1 + label .ctop.top.bar.sha1label -text "SHA1 ID: " + pack .ctop.top.bar.sha1label -side left + entry $sha1entry -width 40 -font $textfont -state readonly + pack $sha1entry -side left -pady 2 + button .ctop.top.bar.findbut -text "Find" -command dofind + pack .ctop.top.bar.findbut -side left + set findstring {} + entry .ctop.top.bar.findstring -width 30 -font $textfont \ + -textvariable findstring + pack .ctop.top.bar.findstring -side left -expand 1 -fill x + set findtype Exact + tk_optionMenu .ctop.top.bar.findtype findtype Exact IgnCase Regexp + set findloc "All fields" + tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \ + Comments Author Committer + pack .ctop.top.bar.findloc -side right + pack .ctop.top.bar.findtype -side right panedwindow .ctop.cdet -orient horizontal .ctop add .ctop.cdet @@ -215,6 +237,9 @@ proc makewindow {} { bind . u "$ctext yview scroll -18 u" bind . Q "set stopped 1; destroy ." bind . "set stopped 1; destroy ." + bind . dofind + bind . findnext + bind . findprev bind $cflist <> listboxsel } @@ -247,7 +272,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.7 $)} \ +(CVS $Revision: 1.8 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -329,30 +354,33 @@ proc assigncolor {id} { } } -proc drawgraph {start} { +proc drawgraph {startlist} { global parents children nparents nchildren commits global canv canv2 canv3 mainfont namefont canvx0 canvy0 canvy linespc global datemode cdate global lineid linehtag linentag linedtag commitinfo - global nextcolor colormap + global nextcolor colormap numcommits global stopped set nextcolor 0 - assigncolor $start foreach id $commits { set ncleft($id) $nchildren($id) } - set todo [list $start] - set level 0 + foreach id $startlist { + assigncolor $id + } + set todo $startlist + set level [expr [llength $todo] - 1] set y2 $canvy0 - set linestarty(0) $canvy0 set nullentry -1 set lineno -1 + set numcommits 0 while 1 { set canvy $y2 allcanvs conf -scrollregion [list 0 0 0 $canvy] update if {$stopped} return + incr numcommits incr lineno set nlines [llength $todo] set id [lindex $todo $level] @@ -369,12 +397,12 @@ proc drawgraph {start} { } set x [expr $canvx0 + $level * $linespc] set y2 [expr $canvy + $linespc] - if {$linestarty($level) < $canvy} { + if {[info exists linestarty($level)] && $linestarty($level) < $canvy} { set t [$canv create line $x $linestarty($level) $x $canvy \ -width 2 -fill $colormap($id)] $canv lower $t - set linestarty($level) $canvy } + 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] @@ -403,12 +431,14 @@ proc drawgraph {start} { set lines {} for {set i 0} {$i < $nlines} {incr i} { if {[lindex $todo $i] == {}} continue - set oldstarty($i) $linestarty($i) + if {[info exists linestarty($i)]} { + set oldstarty($i) $linestarty($i) + unset linestarty($i) + } if {$i != $level} { lappend lines [list $i [lindex $todo $i]] } } - unset linestarty if {$nullentry >= 0} { set todo [lreplace $todo $nullentry $nullentry] if {$nullentry < $level} { @@ -494,13 +524,15 @@ proc drawgraph {start} { set dst [lindex $l 1] set j [lsearch -exact $todo $dst] if {$i == $j} { - set linestarty($i) $oldstarty($i) + if {[info exists oldstarty($i)]} { + set linestarty($i) $oldstarty($i) + } continue } set xi [expr {$canvx0 + $i * $linespc}] set xj [expr {$canvx0 + $j * $linespc}] set coords {} - if {$oldstarty($i) < $canvy} { + if {[info exists oldstarty($i)] && $oldstarty($i) < $canvy} { lappend coords $xi $oldstarty($i) } lappend coords $xi $canvy @@ -519,6 +551,133 @@ proc drawgraph {start} { } } +proc dofind {} { + global findtype findloc findstring markedmatches commitinfo + global numcommits lineid linehtag linentag linedtag + global mainfont namefont canv canv2 canv3 selectedline + global matchinglines + unmarkmatches + set matchinglines {} + set fldtypes {Headline Author Date Committer CDate Comment} + if {$findtype == "IgnCase"} { + set fstr [string tolower $findstring] + } else { + set fstr $findstring + } + set mlen [string length $findstring] + if {$mlen == 0} return + if {![info exists selectedline]} { + set oldsel -1 + } else { + set oldsel $selectedline + } + set didsel 0 + for {set l 0} {$l < $numcommits} {incr l} { + set id $lineid($l) + set info $commitinfo($id) + set doesmatch 0 + foreach f $info ty $fldtypes { + if {$findloc != "All fields" && $findloc != $ty} { + continue + } + if {$findtype == "Regexp"} { + set matches [regexp -indices -all -inline $fstr $f] + } else { + if {$findtype == "IgnCase"} { + set str [string tolower $f] + } else { + set str $f + } + set matches {} + set i 0 + while {[set j [string first $fstr $str $i]] >= 0} { + lappend matches [list $j [expr $j+$mlen-1]] + set i [expr $j + $mlen] + } + } + if {$matches == {}} continue + set doesmatch 1 + if {$ty == "Headline"} { + markmatches $canv $l $f $linehtag($l) $matches $mainfont + } elseif {$ty == "Author"} { + markmatches $canv2 $l $f $linentag($l) $matches $namefont + } elseif {$ty == "Date"} { + markmatches $canv3 $l $f $linedtag($l) $matches $mainfont + } + } + if {$doesmatch} { + lappend matchinglines $l + if {!$didsel && $l > $oldsel} { + selectline $l + set didsel 1 + } + } + } + if {$matchinglines == {}} { + bell + } elseif {!$didsel} { + selectline [lindex $matchinglines 0] + } +} + +proc findnext {} { + global matchinglines selectedline + if {![info exists matchinglines]} { + dofind + return + } + if {![info exists selectedline]} return + foreach l $matchinglines { + if {$l > $selectedline} { + selectline $l + return + } + } + bell +} + +proc findprev {} { + global matchinglines selectedline + if {![info exists matchinglines]} { + dofind + return + } + if {![info exists selectedline]} return + set prev {} + foreach l $matchinglines { + if {$l >= $selectedline} break + set prev $l + } + if {$prev != {}} { + selectline $prev + } else { + bell + } +} + +proc markmatches {canv l str tag matches font} { + set bbox [$canv bbox $tag] + set x0 [lindex $bbox 0] + set y0 [lindex $bbox 1] + set y1 [lindex $bbox 3] + foreach match $matches { + set start [lindex $match 0] + set end [lindex $match 1] + if {$start > $end} continue + set xoff [font measure $font [string range $str 0 [expr $start-1]]] + set xlen [font measure $font [string range $str 0 [expr $end]]] + set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \ + -outline {} -tags matches -fill yellow] + $canv lower $t + } +} + +proc unmarkmatches {} { + global matchinglines + allcanvs delete matches + catch {unset matchinglines} +} + proc selcanvline {x y} { global canv canvy0 ctext linespc selectedline global lineid linehtag linentag linedtag @@ -530,6 +689,7 @@ proc selcanvline {x y} { set l 0 } if {[info exists selectedline] && $selectedline == $l} return + unmarkmatches selectline $l } @@ -537,7 +697,7 @@ proc selectline {l} { global canv canv2 canv3 ctext commitinfo selectedline global lineid linehtag linentag linedtag global canvy canvy0 linespc nparents treepending - global cflist treediffs currentid + global cflist treediffs currentid sha1entry if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ @@ -564,6 +724,13 @@ proc selectline {l} { set selectedline $l set id $lineid($l) + $sha1entry conf -state normal + $sha1entry delete 0 end + $sha1entry insert 0 $id + $sha1entry selection from 0 + $sha1entry selection to end + $sha1entry conf -state readonly + $ctext conf -state normal $ctext delete 0.0 end set info $commitinfo($id) @@ -592,6 +759,7 @@ proc selnextline {dir} { global selectedline if {![info exists selectedline]} return set l [expr $selectedline + $dir] + unmarkmatches selectline $l } @@ -746,8 +914,7 @@ makewindow set start {} foreach id $commits { if {$nchildren($id) == 0} { - set start $id - break + lappend start $id } } if {$start != {}} { From 1d10f36d7fc8aa500198d0bccd3ec2dfad3762c0 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 15 May 2005 12:55:47 +0000 Subject: [PATCH 09/29] Made commit list reading asynchronous Added control+/- to increase/decrease font sizes Rearranged code a little. --- gitk | 255 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 163 insertions(+), 92 deletions(-) diff --git a/gitk b/gitk index 3444bac558..3fd260dbfe 100755 --- a/gitk +++ b/gitk @@ -7,48 +7,35 @@ 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.8 $ - -set datemode 0 -set boldnames 0 -set revtreeargs {} -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} - -foreach arg $argv { - switch -regexp -- $arg { - "^$" { } - "^-b" { set boldnames 1 } - "^-c" { set colorbycommitter 1 } - "^-d" { set datemode 1 } - "^-.*" { - puts stderr "unrecognized option $arg" - exit 1 - } - default { - lappend revtreeargs $arg - } - } -} +# CVS $Revision: 1.9 $ proc getcommits {rargs} { - global commits parents cdate nparents children nchildren + global commits commfd phase canv mainfont if {$rargs == {}} { set rargs HEAD } set commits {} - if [catch {set clist [eval exec git-rev-tree $rargs]} err] { + set phase getcommits + if [catch {set commfd [open "|git-rev-tree $rargs" r]} err] { + puts stder "Error executing git-rev-tree: $err" + exit 1 + } + fconfigure $commfd -blocking 0 + fileevent $commfd readable "getcommitline $commfd" + $canv delete all + $canv create text 3 3 -anchor nw -text "Reading commits..." \ + -font $mainfont -tags textitems +} + +proc getcommitline {commfd} { + global commits parents cdate nparents children nchildren + set n [gets $commfd line] + if {$n < 0} { + if {![eof $commfd]} return + if {![catch {close $commfd} err]} { + after idle drawgraph + return + } if {[string range $err 0 4] == "usage"} { puts stderr "Error reading commits: bad arguments to git-rev-tree" puts stderr "Note: arguments to gitk are passed to git-rev-tree" @@ -56,37 +43,35 @@ proc getcommits {rargs} { } else { puts stderr "Error reading commits: $err" } - return 0 + exit 1 } - foreach c [split $clist "\n"] { - set i 0 - set cid {} - foreach f $c { - if {$i == 0} { - set d $f - } else { - set id [lindex [split $f :] 0] - if {![info exists nchildren($id)]} { - set children($id) {} - set nchildren($id) 0 - } - if {$i == 1} { - set cid $id - lappend commits $id - set parents($id) {} - set cdate($id) $d - set nparents($id) 0 - } else { - lappend parents($cid) $id - incr nparents($cid) - incr nchildren($id) - lappend children($id) $cid - } + + set i 0 + set cid {} + foreach f $line { + if {$i == 0} { + set d $f + } else { + set id [lindex [split $f :] 0] + if {![info exists nchildren($id)]} { + set children($id) {} + set nchildren($id) 0 + } + if {$i == 1} { + set cid $id + lappend commits $id + set parents($id) {} + set cdate($id) $d + set nparents($id) 0 + } else { + lappend parents($cid) $id + incr nparents($cid) + incr nchildren($id) + lappend children($id) $cid } - incr i } + incr i } - return 1 } proc readcommit {id} { @@ -140,7 +125,7 @@ proc makewindow {} { menu .bar .bar add cascade -label "File" -menu .bar.file menu .bar.file - .bar.file add command -label "Quit" -command "set stopped 1; destroy ." + .bar.file add command -label "Quit" -command doquit menu .bar.help .bar add cascade -label "Help" -menu .bar.help .bar.help add command -label "About gitk" -command about @@ -235,11 +220,15 @@ proc makewindow {} { bind . b "$ctext yview scroll -1 p" bind . d "$ctext yview scroll 18 u" bind . u "$ctext yview scroll -18 u" - bind . Q "set stopped 1; destroy ." - bind . "set stopped 1; destroy ." + bind . Q doquit + bind . doquit bind . dofind bind . findnext bind . findprev + bind . {incrfont 1} + bind . {incrfont 1} + bind . {incrfont -1} + bind . {incrfont -1} bind $cflist <> listboxsel } @@ -272,7 +261,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.8 $)} \ +(CVS $Revision: 1.9 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -354,32 +343,45 @@ proc assigncolor {id} { } } -proc drawgraph {startlist} { +proc drawgraph {} { global parents children nparents nchildren commits global canv canv2 canv3 mainfont namefont canvx0 canvy0 canvy linespc global datemode cdate global lineid linehtag linentag linedtag commitinfo global nextcolor colormap numcommits - global stopped + global stopped phase redisplaying selectedline - set nextcolor 0 + allcanvs delete all + set start {} foreach id $commits { + if {$nchildren($id) == 0} { + lappend start $id + } set ncleft($id) $nchildren($id) } - foreach id $startlist { + if {$start == {}} { + $canv create text 3 3 -anchor nw -font $mainfont \ + -text "ERROR: No starting commits found" + set phase {} + return + } + + set nextcolor 0 + foreach id $start { assigncolor $id } - set todo $startlist + set todo $start set level [expr [llength $todo] - 1] set y2 $canvy0 set nullentry -1 set lineno -1 set numcommits 0 + set phase drawgraph while 1 { set canvy $y2 allcanvs conf -scrollregion [list 0 0 0 $canvy] update - if {$stopped} return + if {$stopped} break incr numcommits incr lineno set nlines [llength $todo] @@ -549,6 +551,18 @@ proc drawgraph {startlist} { } } } + set phase {} + if {$redisplaying} { + if {$stopped == 0 && [info exists selectedline]} { + selectline $selectedline + } + if {$stopped == 1} { + set stopped 0 + after idle drawgraph + } else { + set redisplaying 0 + } + } } proc dofind {} { @@ -896,27 +910,84 @@ proc listboxsel {} { } } -if {![getcommits $revtreeargs]} { - exit 1 +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] } -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] -set namex [expr 45 * $charspc] -set datex [expr 75 * $charspc] - -set stopped 0 -makewindow - -set start {} -foreach id $commits { - if {$nchildren($id) == 0} { - lappend start $id +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 } } -if {$start != {}} { - drawgraph $start + +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" + +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 revtreeargs {} +foreach arg $argv { + switch -regexp -- $arg { + "^$" { } + "^-b" { set boldnames 1 } + "^-c" { set colorbycommitter 1 } + "^-d" { set datemode 1 } + "^-.*" { + puts stderr "unrecognized option $arg" + exit 1 + } + default { + lappend revtreeargs $arg + } + } +} + +set stopped 0 +set redisplaying 0 +setcoords +makewindow +getcommits $revtreeargs From 276819b35bb457648d91ee431c29ad5af3c20bef Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 15 May 2005 12:57:02 +0000 Subject: [PATCH 10/29] Bumped version number --- gitk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index 3fd260dbfe..fbc6497a14 100755 --- 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.9 $ +# CVS $Revision: 1.10 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -255,13 +255,13 @@ proc about {} { toplevel $w wm title $w "About gitk" message $w.m -text { -Gitk version 0.9 +Gitk version 0.91 Copyright © 2005 Paul Mackerras Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.9 $)} \ +(CVS $Revision: 1.10 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" From e47120cb9390a32e3e52f39fb53373d1288c04b8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 15 May 2005 21:49:26 +0000 Subject: [PATCH 11/29] Fix stder -> stderr --- gitk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index fbc6497a14..5ac69ed76c 100755 --- 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.10 $ +# CVS $Revision: 1.11 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -17,7 +17,7 @@ proc getcommits {rargs} { set commits {} set phase getcommits if [catch {set commfd [open "|git-rev-tree $rargs" r]} err] { - puts stder "Error executing git-rev-tree: $err" + puts stderr "Error executing git-rev-tree: $err" exit 1 } fconfigure $commfd -blocking 0 @@ -261,7 +261,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.10 $)} \ +(CVS $Revision: 1.11 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" From 43bddeb43d86c2a8093aed0217137afd27eb821b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 15 May 2005 23:19:18 +0000 Subject: [PATCH 12/29] Resize the panes in the paned windows (commit list and details) to keep the proportionality of the pane widths as the overall window is resized. --- gitk | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index 5ac69ed76c..3166aa195d 100755 --- 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.11 $ +# CVS $Revision: 1.12 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -155,6 +155,7 @@ proc makewindow {} { canvas $canv3 -height $height -width [expr 15 * $charspc] \ -bg white -bd 0 -yscrollincr $linespc .ctop.top.clist add $canv3 + bind .ctop.top.clist {resizeclistpanes %W %w} set sha1entry .ctop.top.bar.sha1 label .ctop.top.bar.sha1label -text "SHA1 ID: " @@ -185,6 +186,7 @@ proc makewindow {} { pack .ctop.cdet.left.sb -side right -fill y pack $ctext -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.left + bind .ctop.cdet {resizecdetpanes %W %w} $ctext tag conf filesep -font [concat $textfont bold] $ctext tag conf hunksep -back blue -fore white @@ -232,6 +234,58 @@ proc makewindow {} { bind $cflist <> listboxsel } +proc resizeclistpanes {win w} { + global oldwidth + if [info exists oldwidth($win)] { + set s0 [$win sash coord 0] + set s1 [$win sash coord 1] + if {$w < 60} { + set sash0 [expr {int($w/2 - 2)}] + set sash1 [expr {int($w*5/6 - 2)}] + } else { + set factor [expr {1.0 * $w / $oldwidth($win)}] + set sash0 [expr {int($factor * [lindex $s0 0])}] + set sash1 [expr {int($factor * [lindex $s1 0])}] + if {$sash0 < 30} { + set sash0 30 + } + if {$sash1 < $sash0 + 20} { + set sash1 [expr $sash0 + 20] + } + if {$sash1 > $w - 10} { + set sash1 [expr $w - 10] + if {$sash0 > $sash1 - 20} { + set sash0 [expr $sash1 - 20] + } + } + } + $win sash place 0 $sash0 [lindex $s0 1] + $win sash place 1 $sash1 [lindex $s1 1] + } + set oldwidth($win) $w +} + +proc resizecdetpanes {win w} { + global oldwidth + if [info exists oldwidth($win)] { + set s0 [$win sash coord 0] + if {$w < 60} { + set sash0 [expr {int($w*3/4 - 2)}] + } else { + set factor [expr {1.0 * $w / $oldwidth($win)}] + set sash0 [expr {int($factor * [lindex $s0 0])}] + if {$sash0 < 45} { + set sash0 45 + } + if {$sash0 > $w - 15} { + set sash0 [expr $w - 15] + } + } + $win sash place 0 $sash0 [lindex $s0 1] + } + set oldwidth($win) $w +} + proc allcanvs args { global canv canv2 canv3 eval $canv $args @@ -261,7 +315,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.11 $)} \ +(CVS $Revision: 1.12 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" From 0fba86b3a9d3f74304b25c2f724f019831cd90ff Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 16 May 2005 23:54:58 +0000 Subject: [PATCH 13/29] save window geometry on exit, and restore it on startup --- gitk | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/gitk b/gitk index 3166aa195d..37a97acc12 100755 --- 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.12 $ +# CVS $Revision: 1.13 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -120,7 +120,7 @@ proc readcommit {id} { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont - global sha1entry findtype findloc findstring + global sha1entry findtype findloc findstring geometry menu .bar .bar add cascade -label "File" -menu .bar.file @@ -131,7 +131,19 @@ proc makewindow {} { .bar.help add command -label "About gitk" -command about . configure -menu .bar + if {![info exists geometry(canv1)]} { + set geometry(canv1) [expr 45 * $charspc] + set geometry(canv2) [expr 30 * $charspc] + set geometry(canv3) [expr 15 * $charspc] + set geometry(canvh) [expr 25 * $linespc + 4] + set geometry(ctextw) 80 + set geometry(ctexth) 30 + set geometry(cflistw) 30 + } panedwindow .ctop -orient vertical + if {[info exists geometry(width)]} { + .ctop conf -width $geometry(width) -height $geometry(height) + } frame .ctop.top frame .ctop.top.bar pack .ctop.top.bar -side bottom -fill x @@ -142,17 +154,16 @@ proc makewindow {} { pack .ctop.top.clist -side top -fill both -expand 1 .ctop add .ctop.top set canv .ctop.top.clist.canv - set height [expr 25 * $linespc + 4] - canvas $canv -height $height -width [expr 45 * $charspc] \ + canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ -bg white -bd 0 \ -yscrollincr $linespc -yscrollcommand "$cscroll set" .ctop.top.clist add $canv set canv2 .ctop.top.clist.canv2 - canvas $canv2 -height $height -width [expr 30 * $charspc] \ + canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ -bg white -bd 0 -yscrollincr $linespc .ctop.top.clist add $canv2 set canv3 .ctop.top.clist.canv3 - canvas $canv3 -height $height -width [expr 15 * $charspc] \ + canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \ -bg white -bd 0 -yscrollincr $linespc .ctop.top.clist add $canv3 bind .ctop.top.clist {resizeclistpanes %W %w} @@ -177,16 +188,22 @@ proc makewindow {} { pack .ctop.top.bar.findtype -side right panedwindow .ctop.cdet -orient horizontal + if {[info exists geometry(cdeth)]} { + .ctop.cdet conf -height $geometry(cdeth) + } .ctop add .ctop.cdet frame .ctop.cdet.left set ctext .ctop.cdet.left.ctext - text $ctext -bg white -state disabled -font $textfont -height 32 \ + text $ctext -bg white -state disabled -font $textfont \ + -width $geometry(ctextw) -height $geometry(ctexth) \ -yscrollcommand ".ctop.cdet.left.sb set" scrollbar .ctop.cdet.left.sb -command "$ctext yview" pack .ctop.cdet.left.sb -side right -fill y pack $ctext -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.left - bind .ctop.cdet {resizecdetpanes %W %w} + if {[info exists geometry(detlw)]} { + .ctop.cdet.left conf -width $geometry(detlw) + } $ctext tag conf filesep -font [concat $textfont bold] $ctext tag conf hunksep -back blue -fore white @@ -195,12 +212,16 @@ proc makewindow {} { frame .ctop.cdet.right set cflist .ctop.cdet.right.cfiles - listbox $cflist -width 30 -bg white -selectmode extended \ + listbox $cflist -width $geometry(cflistw) -bg white -selectmode extended \ -yscrollcommand ".ctop.cdet.right.sb set" scrollbar .ctop.cdet.right.sb -command "$cflist yview" pack .ctop.cdet.right.sb -side right -fill y pack $cflist -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.right + if {[info exists geometry(detsash)]} { + eval .ctop.cdet sash place 0 $geometry(detsash) + } + bind .ctop.cdet {resizecdetpanes %W %w} pack .ctop -side top -fill both -expand 1 @@ -232,6 +253,37 @@ proc makewindow {} { bind . {incrfont -1} bind . {incrfont -1} bind $cflist <> listboxsel + bind . {savestuff %W} +} + +proc savestuff {w} { + global canv canv2 canv3 ctext cflist mainfont textfont + global stuffsaved + if {$stuffsaved} return + catch { + set f [open "~/.gitk-new" w] + puts $f "set mainfont {$mainfont}" + puts $f "set textfont {$textfont}" + puts $f "set geometry(width) [winfo width .ctop]" + puts $f "set geometry(height) [winfo height .ctop]" + puts $f "set geometry(canv1) [winfo width $canv]" + puts $f "set geometry(canv2) [winfo width $canv2]" + puts $f "set geometry(canv3) [winfo width $canv3]" + puts $f "set geometry(canvh) [winfo height $canv]" + puts $f "set geometry(cdeth) [winfo height .ctop.cdet]" + 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" + close $f + file rename -force "~/.gitk-new" "~/.gitk" + } + set stuffsaved 1 } proc resizeclistpanes {win w} { @@ -315,7 +367,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.12 $)} \ +(CVS $Revision: 1.13 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -1042,6 +1094,7 @@ foreach arg $argv { set stopped 0 set redisplaying 0 +set stuffsaved 0 setcoords makewindow getcommits $revtreeargs From df3d83b143d0e149767acfebc91b2041f44507ef Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 17 May 2005 23:23:07 +0000 Subject: [PATCH 14/29] Error popups on error conditions rather than stderr msgs Stop . bindings firing on find string entry keypresses Fix geometry saving/restoring a bit Show the terminal commits Highlight comment matches in the comment window --- gitk | 209 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 139 insertions(+), 70 deletions(-) diff --git a/gitk b/gitk index 37a97acc12..35ae1018b6 100755 --- 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.13 $ +# CVS $Revision: 1.14 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -32,17 +32,21 @@ proc getcommitline {commfd} { set n [gets $commfd line] if {$n < 0} { if {![eof $commfd]} return + # this works around what is apparently a bug in Tcl... + fconfigure $commfd -blocking 1 if {![catch {close $commfd} err]} { after idle drawgraph return } if {[string range $err 0 4] == "usage"} { - puts stderr "Error reading commits: bad arguments to git-rev-tree" - puts stderr "Note: arguments to gitk are passed to git-rev-tree" - puts stderr " to allow selection of commits to be displayed" + set err "\ +Gitk: error reading commits: bad arguments to git-rev-tree.\n\ +(Note: arguments to gitk are passed to git-rev-tree\ +to allow selection of commits to be displayed.)" } else { - puts stderr "Error reading commits: $err" + set err "Error reading commits: $err" } + error_popup $err exit 1 } @@ -83,7 +87,8 @@ proc readcommit {id} { set audate {} set comname {} set comdate {} - foreach line [split [exec git-cat-file commit $id] "\n"] { + if [catch {set contents [exec git-cat-file commit $id]}] return + foreach line [split $contents "\n"] { if {$inhdr} { if {$line == {}} { set inhdr 0 @@ -118,9 +123,21 @@ proc readcommit {id} { $comname $comdate $comment] } +proc error_popup msg { + set w .error + toplevel $w + wm transient $w . + message $w.m -text $msg -justify center -aspect 400 + pack $w.m -side top -fill x -padx 20 -pady 20 + button $w.ok -text OK -command "destroy $w" + pack $w.ok -side bottom -fill x + bind $w "grab $w; focus $w" + tkwait window $w +} + proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont - global sha1entry findtype findloc findstring geometry + global sha1entry findtype findloc findstring fstring geometry menu .bar .bar add cascade -label "File" -menu .bar.file @@ -176,9 +193,11 @@ proc makewindow {} { button .ctop.top.bar.findbut -text "Find" -command dofind pack .ctop.top.bar.findbut -side left set findstring {} - entry .ctop.top.bar.findstring -width 30 -font $textfont \ - -textvariable findstring - pack .ctop.top.bar.findstring -side left -expand 1 -fill x + 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 "[bind Entry ]; break" + pack $fstring -side left -expand 1 -fill x set findtype Exact tk_optionMenu .ctop.top.bar.findtype findtype Exact IgnCase Regexp set findloc "All fields" @@ -188,9 +207,6 @@ proc makewindow {} { pack .ctop.top.bar.findtype -side right panedwindow .ctop.cdet -orient horizontal - if {[info exists geometry(cdeth)]} { - .ctop.cdet conf -height $geometry(cdeth) - } .ctop add .ctop.cdet frame .ctop.cdet.left set ctext .ctop.cdet.left.ctext @@ -201,14 +217,12 @@ proc makewindow {} { pack .ctop.cdet.left.sb -side right -fill y pack $ctext -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.left - if {[info exists geometry(detlw)]} { - .ctop.cdet.left conf -width $geometry(detlw) - } $ctext tag conf filesep -font [concat $textfont bold] $ctext tag conf hunksep -back blue -fore white $ctext tag conf d0 -back "#ff8080" $ctext tag conf d1 -back green + $ctext tag conf found -back yellow frame .ctop.cdet.right set cflist .ctop.cdet.right.cfiles @@ -218,9 +232,6 @@ proc makewindow {} { pack .ctop.cdet.right.sb -side right -fill y pack $cflist -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.right - if {[info exists geometry(detsash)]} { - eval .ctop.cdet sash place 0 $geometry(detsash) - } bind .ctop.cdet {resizecdetpanes %W %w} pack .ctop -side top -fill both -expand 1 @@ -231,19 +242,20 @@ proc makewindow {} { bindall "allcanvs yview scroll 5 u" bindall <2> "allcanvs scan mark 0 %y" bindall "allcanvs scan dragto 0 %y" - bind . "selnextline -1" - bind . "selnextline 1" - bind . p "selnextline -1" - bind . n "selnextline 1" - bind . "allcanvs yview scroll -1 p" - bind . "allcanvs yview scroll 1 p" - bind . "$ctext yview scroll -1 p" - bind . "$ctext yview scroll -1 p" - bind . "$ctext yview scroll 1 p" - bind . b "$ctext yview scroll -1 p" - bind . d "$ctext yview scroll 18 u" - bind . u "$ctext yview scroll -18 u" - bind . Q doquit + bindall "selnextline -1" + bindall "selnextline 1" + bindall "allcanvs yview scroll -1 p" + bindall "allcanvs yview scroll 1 p" + bindkey "$ctext yview scroll -1 p" + bindkey "$ctext yview scroll -1 p" + bindkey "$ctext yview scroll 1 p" + bindkey p "selnextline -1" + bindkey n "selnextline 1" + bindkey b "$ctext yview scroll -1 p" + bindkey d "$ctext yview scroll 18 u" + bindkey u "$ctext yview scroll -18 u" + bindkey / findnext + bindkey ? findprev bind . doquit bind . dofind bind . findnext @@ -254,23 +266,47 @@ proc makewindow {} { bind . {incrfont -1} bind $cflist <> listboxsel bind . {savestuff %W} + bind . "click %W" +} + +# when we make a key binding for the toplevel, make sure +# it doesn't get triggered when that key is pressed in the +# find string entry widget. +proc bindkey {ev script} { + global fstring + bind . $ev $script + set escript [bind Entry $ev] + if {$escript == {}} { + set escript [bind Entry ] + } + bind $fstring $ev "$escript; break" +} + +# set the focus back to the toplevel for any click outside +# the find string entry widget +proc click {w} { + global fstring + if {$w != $fstring} { + focus . + } } proc savestuff {w} { global canv canv2 canv3 ctext cflist mainfont textfont global stuffsaved if {$stuffsaved} return + if {![winfo viewable .]} return catch { set f [open "~/.gitk-new" w] puts $f "set mainfont {$mainfont}" puts $f "set textfont {$textfont}" puts $f "set geometry(width) [winfo width .ctop]" puts $f "set geometry(height) [winfo height .ctop]" - puts $f "set geometry(canv1) [winfo width $canv]" - puts $f "set geometry(canv2) [winfo width $canv2]" - puts $f "set geometry(canv3) [winfo width $canv3]" - puts $f "set geometry(canvh) [winfo height $canv]" - puts $f "set geometry(cdeth) [winfo height .ctop.cdet]" + puts $f "set geometry(canv1) [expr [winfo width $canv]-2]" + 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) \ @@ -361,13 +397,13 @@ proc about {} { toplevel $w wm title $w "About gitk" message $w.m -text { -Gitk version 0.91 +Gitk version 0.95 Copyright © 2005 Paul Mackerras Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.13 $)} \ +(CVS $Revision: 1.14 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -459,17 +495,18 @@ proc drawgraph {} { allcanvs delete all set start {} - foreach id $commits { + foreach id [array names nchildren] { if {$nchildren($id) == 0} { lappend start $id } set ncleft($id) $nchildren($id) + if {![info exists nparents($id)]} { + set nparents($id) 0 + } } if {$start == {}} { - $canv create text 3 3 -anchor nw -font $mainfont \ - -text "ERROR: No starting commits found" - set phase {} - return + error_popup "Gitk: ERROR: No starting commits found" + exit 1 } set nextcolor 0 @@ -494,14 +531,21 @@ proc drawgraph {} { set id [lindex $todo $level] set lineid($lineno) $id set actualparents {} - foreach p $parents($id) { - if {[info exists ncleft($p)]} { + if {[info exists parents($id)]} { + foreach p $parents($id) { incr ncleft($p) -1 + if {![info exists commitinfo($p)]} { + readcommit $p + if {![info exists commitinfo($p)]} continue + } lappend actualparents $p } } if {![info exists commitinfo($id)]} { readcommit $id + if {![info exists commitinfo($id)]} { + set commitinfo($id) {"No commit information available"} + } } set x [expr $canvx0 + $level * $linespc] set y2 [expr $canvy + $linespc] @@ -671,21 +715,42 @@ proc drawgraph {} { } } +proc findmatches {f} { + global findtype foundstring foundstrlen + if {$findtype == "Regexp"} { + set matches [regexp -indices -all -inline $foundstring $f] + } else { + if {$findtype == "IgnCase"} { + set str [string tolower $f] + } else { + set str $f + } + set matches {} + set i 0 + while {[set j [string first $foundstring $str $i]] >= 0} { + lappend matches [list $j [expr $j+$foundstrlen-1]] + set i [expr $j + $foundstrlen] + } + } + return $matches +} + proc dofind {} { global findtype findloc findstring markedmatches commitinfo global numcommits lineid linehtag linentag linedtag global mainfont namefont canv canv2 canv3 selectedline - global matchinglines + global matchinglines foundstring foundstrlen unmarkmatches + focus . set matchinglines {} set fldtypes {Headline Author Date Committer CDate Comment} if {$findtype == "IgnCase"} { - set fstr [string tolower $findstring] + set foundstring [string tolower $findstring] } else { - set fstr $findstring + set foundstring $findstring } - set mlen [string length $findstring] - if {$mlen == 0} return + set foundstrlen [string length $findstring] + if {$foundstrlen == 0} return if {![info exists selectedline]} { set oldsel -1 } else { @@ -700,21 +765,7 @@ proc dofind {} { if {$findloc != "All fields" && $findloc != $ty} { continue } - if {$findtype == "Regexp"} { - set matches [regexp -indices -all -inline $fstr $f] - } else { - if {$findtype == "IgnCase"} { - set str [string tolower $f] - } else { - set str $f - } - set matches {} - set i 0 - while {[set j [string first $fstr $str $i]] >= 0} { - lappend matches [list $j [expr $j+$mlen-1]] - set i [expr $j + $mlen] - } - } + set matches [findmatches $f] if {$matches == {}} continue set doesmatch 1 if {$ty == "Headline"} { @@ -728,7 +779,7 @@ proc dofind {} { if {$doesmatch} { lappend matchinglines $l if {!$didsel && $l > $oldsel} { - selectline $l + findselectline $l set didsel 1 } } @@ -736,7 +787,22 @@ proc dofind {} { if {$matchinglines == {}} { bell } elseif {!$didsel} { - selectline [lindex $matchinglines 0] + findselectline [lindex $matchinglines 0] + } +} + +proc findselectline {l} { + global findloc commentend ctext + selectline $l + if {$findloc == "All fields" || $findloc == "Comments"} { + # highlight the matches in the comments + set f [$ctext get 1.0 $commentend] + set matches [findmatches $f] + foreach match $matches { + set start [lindex $match 0] + set end [expr [lindex $match 1] + 1] + $ctext tag add found "1.0 + $start c" "1.0 + $end c" + } } } @@ -749,7 +815,7 @@ proc findnext {} { if {![info exists selectedline]} return foreach l $matchinglines { if {$l > $selectedline} { - selectline $l + findselectline $l return } } @@ -769,7 +835,7 @@ proc findprev {} { set prev $l } if {$prev != {}} { - selectline $prev + findselectline $prev } else { bell } @@ -818,6 +884,7 @@ proc selectline {l} { global lineid linehtag linentag linedtag global canvy canvy0 linespc nparents treepending global cflist treediffs currentid sha1entry + global commentend if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ @@ -860,7 +927,9 @@ proc selectline {l} { $ctext insert end [lindex $info 5] $ctext insert end "\n" $ctext tag delete Comments + $ctext tag remove found 1.0 end $ctext conf -state disabled + set commentend [$ctext index "end - 1c"] $cflist delete 0 end set currentid $id From 173860663e62b517e51a71cefe9c6d463afb281d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 18 May 2005 22:51:00 +0000 Subject: [PATCH 15/29] More fixes for geometry restoration Make up/down/pgup/pgdn work again Return in find string entry does find Scale circles and lines with font size Fix scrolling to make entire selected line visible Use white circle for commits not listed but put in to terminate lines Fix diff parsing for created and deleted files --- gitk | 101 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 35 deletions(-) diff --git a/gitk b/gitk index 35ae1018b6..5d65e74e42 100755 --- 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.15 $ 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 "[bind Entry ]; 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 "allcanvs yview scroll 5 u" bindall <2> "allcanvs scan mark 0 %y" bindall "allcanvs scan dragto 0 %y" - bindall "selnextline -1" - bindall "selnextline 1" - bindall "allcanvs yview scroll -1 p" - bindall "allcanvs yview scroll 1 p" + bind . "selnextline -1" + bind . "selnextline 1" + bind . "allcanvs yview scroll -1 p" + bind . "allcanvs yview scroll 1 p" bindkey "$ctext yview scroll -1 p" bindkey "$ctext yview scroll -1 p" bindkey "$ctext yview scroll 1 p" @@ -267,6 +268,7 @@ proc makewindow {} { bind $cflist <> listboxsel bind . {savestuff %W} bind . "click %W" + bind $fstring dofind } # when we make a key binding for the toplevel, make sure @@ -306,13 +308,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" @@ -403,7 +401,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.14 $)} \ +(CVS $Revision: 1.15 $)} \ -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 +518,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 +551,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 +696,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 +885,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 +902,24 @@ 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 / 2.0 - 1) / $ymax}] + set ybot [expr {($y + $linespc / 2.0 + 1) / $ymax}] set wnow [$canv yview] - if {$ytop < [lindex $wnow 0]} { + set scrincr [expr {$linespc * 1.0 / $ymax}] + set wtop [lindex $wnow 0] + if {$ytop < $wtop} { + if {$ytop > $wtop - $scrincr} { + set ytop [expr {$wtop - $scrincr}] + } 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 wh [expr {[lindex $wnow 1] - $wtop}] + set ytop [expr {$ybot - $wh}] + if {$ytop < $wtop + $scrincr} { + set ytop [expr {$wtop + $scrincr}] + } + allcanvs yview moveto $ytop } set selectedline $l @@ -942,6 +955,7 @@ proc selectline {l} { addtocflist $id } } + catch {unset seenfile} } proc selnextline {dir} { @@ -1008,13 +1022,15 @@ proc getblobdiffs {id} { } proc getblobdiffline {bdf id} { - global currentid blobdifffd ctext curdifftag curtagstart + global currentid blobdifffd ctext curdifftag curtagstart seenfile + global diffnexthead 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,11 +1039,16 @@ 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"] + if {[info exists diffnexthead]} { + set fname $diffnexthead + unset diffnexthead + } set curdifftag "f:$fname" $ctext tag delete $curdifftag set l [expr {(78 - [string length $fname]) / 2}] @@ -1035,6 +1056,10 @@ proc getblobdiffline {bdf id} { $ctext insert end "$pad $fname $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]} { + set diffnexthead $fn + } elseif {[string range $line 0 8] == "Deleted: "} { + set diffnexthead [string range $line 9 end] } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \ $line match f1l f1c f2l f2c rest]} { $ctext insert end "\t" hunksep @@ -1054,6 +1079,7 @@ proc getblobdiffline {bdf id} { 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 } @@ -1064,14 +1090,16 @@ proc getblobdiffline {bdf id} { } 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 +1107,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 +1163,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 { From 5842215ee93af489c0ed5d29942aafea5d042609 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 19 May 2005 10:56:42 +0000 Subject: [PATCH 16/29] Handle \ No newline at end of line lines in diff Put (deleted) or (created, mode xxx) in header lines Fix scrolling to bring lines on screen --- gitk | 61 ++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/gitk b/gitk index 5d65e74e42..7a46b872f4 100755 --- 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.15 $ +# CVS $Revision: 1.16 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -395,13 +395,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.15 $)} \ +(CVS $Revision: 1.16 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -903,23 +903,37 @@ proc selectline {l} { $canv3 lower $t set y [expr {$canvy0 + $l * $linespc}] set ymax [lindex [$canv cget -scrollregion] 3] - set ytop [expr {($y - $linespc / 2.0 - 1) / $ymax}] - set ybot [expr {($y + $linespc / 2.0 + 1) / $ymax}] + set ytop [expr {$y - $linespc - 1}] + set ybot [expr {$y + $linespc + 1}] set wnow [$canv yview] - set scrincr [expr {$linespc * 1.0 / $ymax}] - set wtop [lindex $wnow 0] + 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 {$ytop > $wtop - $scrincr} { - set ytop [expr {$wtop - $scrincr}] + if {$ybot < $wtop} { + set newtop [expr {$y - $wh / 2.0}] + } else { + set newtop $ytop + if {$newtop > $wtop - $linespc} { + set newtop [expr {$wtop - $linespc}] + } } - allcanvs yview moveto $ytop - } elseif {$ybot > [lindex $wnow 1]} { - set wh [expr {[lindex $wnow 1] - $wtop}] - set ytop [expr {$ybot - $wh}] - if {$ytop < $wtop + $scrincr} { - set ytop [expr {$wtop + $scrincr}] + } 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}] + } } - allcanvs yview moveto $ytop + } + if {$newtop != $wtop} { + if {$newtop < 0} { + set newtop 0 + } + allcanvs yview moveto [expr $newtop * 1.0 / $ymax] } set selectedline $l @@ -1023,7 +1037,7 @@ proc getblobdiffs {id} { proc getblobdiffline {bdf id} { global currentid blobdifffd ctext curdifftag curtagstart seenfile - global diffnexthead + global diffnexthead diffnextnote set n [gets $bdf line] if {$n < 0} { if {[eof $bdf]} { @@ -1045,21 +1059,25 @@ proc getblobdiffline {bdf id} { $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 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]} { + } 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 {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \ $line match f1l f1c f2l f2c rest]} { $ctext insert end "\t" hunksep @@ -1074,6 +1092,9 @@ 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"} { From 39ad85705cb2e9665a71d55e2d84b6ab8bc40d6d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 19 May 2005 12:35:53 +0000 Subject: [PATCH 17/29] Accommodate new git-diff-tree output format Add 'f' key for moving to next file --- gitk | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index 7a46b872f4..8d25c32d65 100755 --- 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.16 $ +# CVS $Revision: 1.17 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -257,6 +257,7 @@ proc makewindow {} { bindkey u "$ctext yview scroll -18 u" bindkey / findnext bindkey ? findprev + bindkey f nextfile bind . doquit bind . dofind bind . findnext @@ -401,7 +402,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.16 $)} \ +(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" @@ -1022,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] { @@ -1032,12 +1034,14 @@ 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 seenfile - global diffnexthead diffnextnote + global diffnexthead diffnextnote diffindex difffilestart set n [gets $bdf line] if {$n < 0} { if {[eof $bdf]} { @@ -1065,6 +1069,8 @@ proc getblobdiffline {bdf id} { 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 $header]) / 2}] @@ -1078,6 +1084,14 @@ proc getblobdiffline {bdf id} { } 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 @@ -1110,6 +1124,17 @@ 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 seenfile if {![info exists currentid]} return From 887fe3c4748b88b66cf2be88fb6c37ccaa5d37df Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 21 May 2005 07:35:37 +0000 Subject: [PATCH 18/29] Read tags from .git/refs/tags/* and mark commits with tags with a label. Allow SHA1 ids or tags to be entered in the SHA1 ID field. --- gitk | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 132 insertions(+), 17 deletions(-) diff --git a/gitk b/gitk index 8d25c32d65..15d9cf04e6 100755 --- 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.17 $ +# CVS $Revision: 1.18 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -123,6 +123,35 @@ proc readcommit {id} { $comname $comdate $comment] } +proc readrefs {} { + global tagids idtags + set tags [glob -nocomplain -types f .git/refs/tags/*] + foreach f $tags { + catch { + set fd [open $f r] + set line [read $fd] + if {[regexp {^[0-9a-f]{40}} $line id]} { + set contents [split [exec git-cat-file tag $id] "\n"] + set obj {} + set type {} + set tag {} + foreach l $contents { + if {$l == {}} break + switch -- [lindex $l 0] { + "object" {set obj [lindex $l 1]} + "type" {set type [lindex $l 1]} + "tag" {set tag [string range $l 4 end]} + } + } + if {$obj != {} && $type == "commit" && $tag != {}} { + set tagids($tag) $obj + lappend idtags($obj) $tag + } + } + } + } +} + proc error_popup msg { set w .error toplevel $w @@ -137,7 +166,8 @@ proc error_popup msg { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont - global sha1entry findtype findloc findstring fstring geometry + global findtype findloc findstring fstring geometry + global entries sha1entry sha1string sha1but menu .bar .bar add cascade -label "File" -menu .bar.file @@ -189,14 +219,20 @@ proc makewindow {} { bind .ctop.top.clist {resizeclistpanes %W %w} set sha1entry .ctop.top.bar.sha1 - label .ctop.top.bar.sha1label -text "SHA1 ID: " + set entries $sha1entry + set sha1but .ctop.top.bar.sha1label + button $sha1but -text "SHA1 ID: " -state disabled -relief flat \ + -command gotocommit -width 8 + $sha1but conf -disabledforeground [$sha1but cget -foreground] pack .ctop.top.bar.sha1label -side left - entry $sha1entry -width 40 -font $textfont -state readonly + entry $sha1entry -width 40 -font $textfont -textvariable sha1string + trace add variable sha1string write sha1change pack $sha1entry -side left -pady 2 button .ctop.top.bar.findbut -text "Find" -command dofind pack .ctop.top.bar.findbut -side left set findstring {} set fstring .ctop.top.bar.findstring + lappend entries $fstring entry $fstring -width 30 -font $textfont -textvariable findstring pack $fstring -side left -expand 1 -fill x set findtype Exact @@ -270,28 +306,32 @@ proc makewindow {} { bind . {savestuff %W} bind . "click %W" bind $fstring dofind + bind $sha1entry gotocommit } # when we make a key binding for the toplevel, make sure # it doesn't get triggered when that key is pressed in the # find string entry widget. proc bindkey {ev script} { - global fstring + global entries bind . $ev $script set escript [bind Entry $ev] if {$escript == {}} { set escript [bind Entry ] } - bind $fstring $ev "$escript; break" + foreach e $entries { + bind $e $ev "$escript; break" + } } # set the focus back to the toplevel for any click outside -# the find string entry widget +# the entry widgets proc click {w} { - global fstring - if {$w != $fstring} { - focus . + global entries + foreach e $entries { + if {$w == $e} return } + focus . } proc savestuff {w} { @@ -402,7 +442,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.17 $)} \ +(CVS $Revision: 1.18 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -490,7 +530,7 @@ proc drawgraph {} { global datemode cdate global lineid linehtag linentag linedtag commitinfo global nextcolor colormap numcommits - global stopped phase redisplaying selectedline + global stopped phase redisplaying selectedline idtags idline allcanvs delete all set start {} @@ -531,6 +571,7 @@ proc drawgraph {} { set nlines [llength $todo] set id [lindex $todo $level] set lineid($lineno) $id + set idline($id) $lineno set actualparents {} if {[info exists parents($id)]} { foreach p $parents($id) { @@ -563,6 +604,34 @@ proc drawgraph {} { -fill $ofill -outline black -width 1] $canv raise $t set xt [expr $canvx0 + $nlines * $linespc] + if {$nparents($id) > 2} { + set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] + } + if {[info exists idtags($id)] && $idtags($id) != {}} { + set delta [expr {int(0.5 * ($linespc - $lthickness))}] + set yt [expr $canvy - 0.5 * $linespc] + set yb [expr $yt + $linespc - 1] + set xvals {} + set wvals {} + foreach tag $idtags($id) { + set wid [font measure $mainfont $tag] + lappend xvals $xt + lappend wvals $wid + set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}] + } + set t [$canv create line $x $canvy [lindex $xvals end] $canvy \ + -width $lthickness -fill black] + $canv lower $t + foreach tag $idtags($id) x $xvals wid $wvals { + set xl [expr $x + $delta] + set xr [expr $x + $delta + $wid + $lthickness] + $canv create polygon $x [expr $yt + $delta] $xl $yt\ + $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ + -width 1 -outline black -fill yellow + $canv create text $xl $canvy -anchor w -text $tag \ + -font $mainfont + } + } set headline [lindex $commitinfo($id) 0] set name [lindex $commitinfo($id) 1] set date [lindex $commitinfo($id) 2] @@ -743,7 +812,7 @@ proc dofind {} { global findtype findloc findstring markedmatches commitinfo global numcommits lineid linehtag linentag linedtag global mainfont namefont canv canv2 canv3 selectedline - global matchinglines foundstring foundstrlen + global matchinglines foundstring foundstrlen idtags unmarkmatches focus . set matchinglines {} @@ -888,7 +957,7 @@ proc selectline {l} { global lineid linehtag linentag linedtag global canvy0 linespc nparents treepending global cflist treediffs currentid sha1entry - global commentend seenfile numcommits + global commentend seenfile numcommits idtags if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ @@ -939,18 +1008,24 @@ proc selectline {l} { set selectedline $l set id $lineid($l) - $sha1entry conf -state normal + set currentid $id $sha1entry delete 0 end $sha1entry insert 0 $id $sha1entry selection from 0 $sha1entry selection to end - $sha1entry conf -state readonly $ctext conf -state normal $ctext delete 0.0 end set info $commitinfo($id) $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" + if {[info exists idtags($id)]} { + $ctext insert end "Tags:" + foreach tag $idtags($id) { + $ctext insert end " $tag" + } + $ctext insert end "\n" + } $ctext insert end "\n" $ctext insert end [lindex $info 5] $ctext insert end "\n" @@ -960,7 +1035,6 @@ proc selectline {l} { set commentend [$ctext index "end - 1c"] $cflist delete 0 end - set currentid $id if {$nparents($id) == 1} { if {![info exists treediffs($id)]} { if {![info exists treepending]} { @@ -1191,12 +1265,52 @@ proc incrfont {inc} { setcoords $ctext conf -font $textfont $ctext tag conf filesep -font [concat $textfont bold] + foreach e $entries { + $e conf -font $mainfont + } if {$phase == "getcommits"} { $canv itemconf textitems -font $mainfont } redisplay } +proc sha1change {n1 n2 op} { + global sha1string currentid sha1but + if {$sha1string == {} + || ([info exists currentid] && $sha1string == $currentid)} { + set state disabled + } else { + set state normal + } + if {[$sha1but cget -state] == $state} return + if {$state == "normal"} { + $sha1but conf -state normal -relief raised -text "Goto: " + } else { + $sha1but conf -state disabled -relief flat -text "SHA1 ID: " + } +} + +proc gotocommit {} { + global sha1string currentid idline tagids + if {$sha1string == {} + || ([info exists currentid] && $sha1string == $currentid)} return + if {[info exists tagids($sha1string)]} { + set id $tagids($sha1string) + } else { + set id [string tolower $sha1string] + } + if {[info exists idline($id)]} { + selectline $idline($id) + return + } + if {[regexp {^[0-9a-fA-F]{40}$} $sha1string]} { + set type "SHA1 id" + } else { + set type "Tag" + } + error_popup "$type $sha1string is not known" +} + proc doquit {} { global stopped set stopped 100 @@ -1243,4 +1357,5 @@ set redisplaying 0 set stuffsaved 0 setcoords makewindow +readrefs getcommits $revtreeargs From cfb4563c836b40dca2e1ef9d4ef3d2b943645edb Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 31 May 2005 12:14:42 +0000 Subject: [PATCH 19/29] Use git-rev-list instead of git-rev-tree. Fix bug in changing font size in entry widgets. Fix bug with B1 click before anything has been drawn. Use "units" and "pages" instead of "u" and "p" for tk8.5. --- gitk | 121 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/gitk b/gitk index 15d9cf04e6..a8c028b548 100755 --- 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.18 $ +# CVS $Revision: 1.19 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -16,8 +16,8 @@ proc getcommits {rargs} { } set commits {} set phase getcommits - if [catch {set commfd [open "|git-rev-tree $rargs" r]} err] { - puts stderr "Error executing git-rev-tree: $err" + if [catch {set commfd [open "|git-rev-list $rargs" r]} err] { + puts stderr "Error executing git-rev-list: $err" exit 1 } fconfigure $commfd -blocking 0 @@ -35,13 +35,13 @@ proc getcommitline {commfd} { # this works around what is apparently a bug in Tcl... fconfigure $commfd -blocking 1 if {![catch {close $commfd} err]} { - after idle drawgraph + after idle readallcommits return } if {[string range $err 0 4] == "usage"} { set err "\ -Gitk: error reading commits: bad arguments to git-rev-tree.\n\ -(Note: arguments to gitk are passed to git-rev-tree\ +Gitk: error reading commits: bad arguments to git-rev-list.\n\ +(Note: arguments to gitk are passed to git-rev-list\ to allow selection of commits to be displayed.)" } else { set err "Error reading commits: $err" @@ -49,37 +49,24 @@ to allow selection of commits to be displayed.)" error_popup $err exit 1 } - - set i 0 - set cid {} - foreach f $line { - if {$i == 0} { - set d $f - } else { - set id [lindex [split $f :] 0] - if {![info exists nchildren($id)]} { - set children($id) {} - set nchildren($id) 0 - } - if {$i == 1} { - set cid $id - lappend commits $id - set parents($id) {} - set cdate($id) $d - set nparents($id) 0 - } else { - lappend parents($cid) $id - incr nparents($cid) - incr nchildren($id) - lappend children($id) $cid - } - } - incr i + if {![regexp {^[0-9a-f]{40}$} $line]} { + error_popup "Can't parse git-rev-tree output: {$line}" + exit 1 } + lappend commits $line +} + +proc readallcommits {} { + global commits + foreach id $commits { + readcommit $id + update + } + drawgraph } proc readcommit {id} { - global commitinfo + global commitinfo children nchildren parents nparents cdate set inhdr 1 set comment {} set headline {} @@ -87,6 +74,12 @@ proc readcommit {id} { set audate {} set comname {} set comdate {} + if {![info exists nchildren($id)]} { + set children($id) {} + set nchildren($id) 0 + } + set parents($id) {} + set nparents($id) 0 if [catch {set contents [exec git-cat-file commit $id]}] return foreach line [split $contents "\n"] { if {$inhdr} { @@ -94,7 +87,19 @@ proc readcommit {id} { set inhdr 0 } else { set tag [lindex $line 0] - if {$tag == "author"} { + if {$tag == "parent"} { + set p [lindex $line 1] + if {![info exists nchildren($p)]} { + set children($p) {} + set nchildren($p) 0 + } + lappend parents($id) $p + incr nparents($id) + if {[lsearch -exact $children($p) $id] < 0} { + lappend children($p) $id + incr nchildren($p) + } + } elseif {$tag == "author"} { set x [expr {[llength $line] - 2}] set audate [lindex $line $x] set auname [lrange $line 1 [expr {$x - 1}]] @@ -117,6 +122,7 @@ proc readcommit {id} { set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"] } if {$comdate != {}} { + set cdate($id) $comdate set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] } set commitinfo($id) [list $headline $auname $audate \ @@ -275,22 +281,22 @@ proc makewindow {} { bindall <1> {selcanvline %x %y} bindall {selcanvline %x %y} - bindall "allcanvs yview scroll -5 u" - bindall "allcanvs yview scroll 5 u" + bindall "allcanvs yview scroll -5 units" + bindall "allcanvs yview scroll 5 units" bindall <2> "allcanvs scan mark 0 %y" bindall "allcanvs scan dragto 0 %y" bind . "selnextline -1" bind . "selnextline 1" - bind . "allcanvs yview scroll -1 p" - bind . "allcanvs yview scroll 1 p" - bindkey "$ctext yview scroll -1 p" - bindkey "$ctext yview scroll -1 p" - bindkey "$ctext yview scroll 1 p" + bind . "allcanvs yview scroll -1 pages" + bind . "allcanvs yview scroll 1 pages" + bindkey "$ctext yview scroll -1 pages" + bindkey "$ctext yview scroll -1 pages" + bindkey "$ctext yview scroll 1 pages" bindkey p "selnextline -1" bindkey n "selnextline 1" - bindkey b "$ctext yview scroll -1 p" - bindkey d "$ctext yview scroll 18 u" - bindkey u "$ctext yview scroll -18 u" + bindkey b "$ctext yview scroll -1 pages" + bindkey d "$ctext yview scroll 18 units" + bindkey u "$ctext yview scroll -18 units" bindkey / findnext bindkey ? findprev bindkey f nextfile @@ -436,13 +442,13 @@ proc about {} { toplevel $w wm title $w "About gitk" message $w.m -text { -Gitk version 1.0 +Gitk version 1.1 Copyright © 2005 Paul Mackerras Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.18 $)} \ +(CVS $Revision: 1.19 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -573,14 +579,18 @@ proc drawgraph {} { set lineid($lineno) $id set idline($id) $lineno set actualparents {} + set ofill white if {[info exists parents($id)]} { foreach p $parents($id) { - incr ncleft($p) -1 - if {![info exists commitinfo($p)]} { - readcommit $p - if {![info exists commitinfo($p)]} continue + if {[info exists ncleft($p)]} { + incr ncleft($p) -1 + if {![info exists commitinfo($p)]} { + readcommit $p + if {![info exists commitinfo($p)]} continue + } + lappend actualparents $p + set ofill blue } - lappend actualparents $p } } if {![info exists commitinfo($id)]} { @@ -597,7 +607,6 @@ proc drawgraph {} { $canv lower $t } set linestarty($level) $canvy - 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] \ @@ -683,6 +692,7 @@ proc drawgraph {} { if {$nullentry >= $i} { incr nullentry } + incr i } lappend lines [list $oldlevel $p] } @@ -941,6 +951,7 @@ proc selcanvline {x y} { global canv canvy0 ctext linespc selectedline global lineid linehtag linentag linedtag set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax == {}} return set yfrac [lindex [$canv yview] 0] set y [expr {$y + $yfrac * $ymax}] set l [expr {int(($y - $canvy0) / $linespc + 0.5)}] @@ -1257,7 +1268,7 @@ proc redisplay {} { proc incrfont {inc} { global mainfont namefont textfont selectedline ctext canv phase - global stopped + global stopped entries unmarkmatches set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]] @@ -1342,10 +1353,6 @@ foreach arg $argv { "^-b" { set boldnames 1 } "^-c" { set colorbycommitter 1 } "^-d" { set datemode 1 } - "^-.*" { - puts stderr "unrecognized option $arg" - exit 1 - } default { lappend revtreeargs $arg } From d4e95cb6cf0c65ec1e9e40ae967e128d7f0e45a9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 1 Jun 2005 00:02:13 +0000 Subject: [PATCH 20/29] cope with changed git-diff-tree output format --- gitk | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/gitk b/gitk index a8c028b548..f7ff049b8f 100755 --- 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.19 $ +# CVS $Revision: 1.20 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -448,7 +448,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.19 $)} \ +(CVS $Revision: 1.20 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -1099,11 +1099,8 @@ proc gettreediffline {gdtf id} { addtocflist $id return } - set type [lindex $line 1] - set file [lindex $line 3] - if {$type == "blob"} { - lappend treediffs($id) $file - } + set file [lindex $line 5] + lappend treediffs($id) $file } proc getblobdiffs {id} { From c2f6a0225153fcaa92e94613d85ff0c463fabd9a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 10 Jun 2005 07:54:49 +0000 Subject: [PATCH 21/29] Show heads as well as tags --- gitk | 54 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/gitk b/gitk index f7ff049b8f..9656ef20e0 100755 --- 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.20 $ +# CVS $Revision: 1.21 $ proc getcommits {rargs} { global commits commfd phase canv mainfont @@ -50,7 +50,7 @@ to allow selection of commits to be displayed.)" exit 1 } if {![regexp {^[0-9a-f]{40}$} $line]} { - error_popup "Can't parse git-rev-tree output: {$line}" + error_popup "Can't parse git-rev-list output: {$line}" exit 1 } lappend commits $line @@ -130,7 +130,7 @@ proc readcommit {id} { } proc readrefs {} { - global tagids idtags + global tagids idtags headids idheads set tags [glob -nocomplain -types f .git/refs/tags/*] foreach f $tags { catch { @@ -154,6 +154,20 @@ proc readrefs {} { lappend idtags($obj) $tag } } + close $fd + } + } + set heads [glob -nocomplain -types f .git/refs/heads/*] + foreach f $heads { + catch { + set fd [open $f r] + set line [read $fd 40] + if {[regexp {^[0-9a-f]{40}} $line id]} { + set head [file tail $f] + set headids($head) $line + lappend idheads($line) $head + } + close $fd } } } @@ -448,7 +462,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.20 $)} \ +(CVS $Revision: 1.21 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -537,6 +551,7 @@ proc drawgraph {} { global lineid linehtag linentag linedtag commitinfo global nextcolor colormap numcommits global stopped phase redisplaying selectedline idtags idline + global idheads allcanvs delete all set start {} @@ -616,13 +631,22 @@ proc drawgraph {} { if {$nparents($id) > 2} { set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] } - if {[info exists idtags($id)] && $idtags($id) != {}} { + set marks {} + set ntags 0 + if {[info exists idtags($id)]} { + set marks $idtags($id) + set ntags [llength $marks] + } + if {[info exists idheads($id)]} { + set marks [concat $marks $idheads($id)] + } + if {$marks != {}} { set delta [expr {int(0.5 * ($linespc - $lthickness))}] set yt [expr $canvy - 0.5 * $linespc] set yb [expr $yt + $linespc - 1] set xvals {} set wvals {} - foreach tag $idtags($id) { + foreach tag $marks { set wid [font measure $mainfont $tag] lappend xvals $xt lappend wvals $wid @@ -631,12 +655,20 @@ proc drawgraph {} { set t [$canv create line $x $canvy [lindex $xvals end] $canvy \ -width $lthickness -fill black] $canv lower $t - foreach tag $idtags($id) x $xvals wid $wvals { + foreach tag $marks x $xvals wid $wvals { set xl [expr $x + $delta] set xr [expr $x + $delta + $wid + $lthickness] - $canv create polygon $x [expr $yt + $delta] $xl $yt\ - $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ - -width 1 -outline black -fill yellow + if {[incr ntags -1] >= 0} { + # draw a tag + $canv create polygon $x [expr $yt + $delta] $xl $yt\ + $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ + -width 1 -outline black -fill yellow + } else { + # draw a head + set xl [expr $xl - $delta/2] + $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \ + -width 1 -outline black -fill green + } $canv create text $xl $canvy -anchor w -text $tag \ -font $mainfont } @@ -1334,7 +1366,7 @@ set mainfont {Helvetica 9} set textfont {Courier 9} set colors {green red blue magenta darkgrey brown orange} -set colorbycommitter false +set colorbycommitter 0 catch {source ~/.gitk} From 9ccbdfbfbcd26ab751e3edaa9ccd9dff278857c1 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 16 Jun 2005 00:27:23 +0000 Subject: [PATCH 22/29] Restructure to do incremental drawing Some speedups from not doing update so often --- gitk | 794 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 457 insertions(+), 337 deletions(-) diff --git a/gitk b/gitk index 9656ef20e0..f33c3fa0cc 100755 --- a/gitk +++ b/gitk @@ -7,16 +7,20 @@ 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.21 $ +# CVS $Revision: 1.22 $ proc getcommits {rargs} { global commits commfd phase canv mainfont + global startmsecs nextupdate + if {$rargs == {}} { set rargs HEAD } set commits {} set phase getcommits - if [catch {set commfd [open "|git-rev-list $rargs" r]} err] { + set startmsecs [clock clicks -milliseconds] + set nextupdate [expr $startmsecs + 100] + if [catch {set commfd [open "|git-rev-list --merge-order $rargs" r]} err] { puts stderr "Error executing git-rev-list: $err" exit 1 } @@ -28,45 +32,77 @@ proc getcommits {rargs} { } proc getcommitline {commfd} { - global commits parents cdate nparents children nchildren + global commits parents cdate children nchildren ncleft + global commitlisted phase commitinfo nextupdate + global stopped redisplaying + set n [gets $commfd line] if {$n < 0} { if {![eof $commfd]} return # this works around what is apparently a bug in Tcl... fconfigure $commfd -blocking 1 if {![catch {close $commfd} err]} { - after idle readallcommits + after idle finishcommits return } if {[string range $err 0 4] == "usage"} { - set err "\ -Gitk: error reading commits: bad arguments to git-rev-list.\n\ -(Note: arguments to gitk are passed to git-rev-list\ -to allow selection of commits to be displayed.)" + set err \ +{Gitk: error reading commits: bad arguments to git-rev-list. +(Note: arguments to gitk are passed to git-rev-list +to allow selection of commits to be displayed.)} } else { set err "Error reading commits: $err" } error_popup $err exit 1 } - if {![regexp {^[0-9a-f]{40}$} $line]} { + if {![regexp {^[0-9a-f]{40}$} $line id]} { error_popup "Can't parse git-rev-list output: {$line}" exit 1 } - lappend commits $line + lappend commits $id + set commitlisted($id) 1 + if {![info exists commitinfo($id)]} { + readcommit $id + } + foreach p $parents($id) { + if {[info exists commitlisted($p)]} { + puts "oops, parent $p before child $id" + } + } + drawcommit $id + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + } + while {$redisplaying} { + set redisplaying 0 + if {$stopped == 1} { + set stopped 0 + set phase "getcommits" + foreach id $commits { + drawcommit $id + if {$stopped} break + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + } + } + } + } } -proc readallcommits {} { - global commits - foreach id $commits { - readcommit $id - update - } - drawgraph +proc doupdate {} { + global commfd nextupdate + + incr nextupdate 100 + fileevent $commfd readable {} + update + fileevent $commfd readable "getcommitline $commfd" } proc readcommit {id} { - global commitinfo children nchildren parents nparents cdate + global commitinfo children nchildren parents nparents cdate ncleft + global noreadobj + set inhdr 1 set comment {} set headline {} @@ -77,10 +113,17 @@ proc readcommit {id} { if {![info exists nchildren($id)]} { set children($id) {} set nchildren($id) 0 + set ncleft($id) 0 } set parents($id) {} set nparents($id) 0 - if [catch {set contents [exec git-cat-file commit $id]}] return + if {$noreadobj} { + if [catch {set contents [exec git-cat-file commit $id]}] return + } else { + if [catch {set x [readobj $id]}] return + if {[lindex $x 0] != "commit"} return + set contents [lindex $x 1] + } foreach line [split $contents "\n"] { if {$inhdr} { if {$line == {}} { @@ -92,12 +135,16 @@ proc readcommit {id} { if {![info exists nchildren($p)]} { set children($p) {} set nchildren($p) 0 + set ncleft($p) 0 } lappend parents($id) $p incr nparents($id) if {[lsearch -exact $children($p) $id] < 0} { lappend children($p) $id incr nchildren($p) + incr ncleft($p) + } else { + puts "child $id already in $p's list??" } } elseif {$tag == "author"} { set x [expr {[llength $line] - 2}] @@ -137,6 +184,9 @@ proc readrefs {} { set fd [open $f r] set line [read $fd] if {[regexp {^[0-9a-f]{40}} $line id]} { + set direct [file tail $f] + set tagids($direct) $id + lappend idtags($id) $direct set contents [split [exec git-cat-file tag $id] "\n"] set obj {} set type {} @@ -462,361 +512,431 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.21 $)} \ +(CVS $Revision: 1.22 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" pack $w.ok -side bottom } -proc truncatetofit {str width font} { - if {[font measure $font $str] <= $width} { - return $str - } - set best 0 - set bad [string length $str] - set tmp $str - while {$best < $bad - 1} { - set try [expr {int(($best + $bad) / 2)}] - set tmp "[string range $str 0 [expr $try-1]]..." - if {[font measure $font $tmp] <= $width} { - set best $try - } else { - set bad $try - } - } - return $tmp -} - proc assigncolor {id} { global commitinfo colormap commcolors colors nextcolor - global colorbycommitter global parents nparents children nchildren if [info exists colormap($id)] return set ncolors [llength $colors] - if {$colorbycommitter} { - if {![info exists commitinfo($id)]} { - readcommit $id + if {$nparents($id) == 1 && $nchildren($id) == 1} { + set child [lindex $children($id) 0] + if {[info exists colormap($child)] + && $nparents($child) == 1} { + set colormap($id) $colormap($child) + return } - set comm [lindex $commitinfo($id) 3] - if {![info exists commcolors($comm)]} { - set commcolors($comm) [lindex $colors $nextcolor] - if {[incr nextcolor] >= $ncolors} { - set nextcolor 0 - } + } + set badcolors {} + foreach child $children($id) { + if {[info exists colormap($child)] + && [lsearch -exact $badcolors $colormap($child)] < 0} { + lappend badcolors $colormap($child) } - set colormap($id) $commcolors($comm) - } else { - if {$nparents($id) == 1 && $nchildren($id) == 1} { - set child [lindex $children($id) 0] - if {[info exists colormap($child)] - && $nparents($child) == 1} { - set colormap($id) $colormap($child) - return - } - } - set badcolors {} - foreach child $children($id) { - if {[info exists colormap($child)] - && [lsearch -exact $badcolors $colormap($child)] < 0} { - lappend badcolors $colormap($child) - } - if {[info exists parents($child)]} { - foreach p $parents($child) { - if {[info exists colormap($p)] - && [lsearch -exact $badcolors $colormap($p)] < 0} { - lappend badcolors $colormap($p) - } + if {[info exists parents($child)]} { + foreach p $parents($child) { + if {[info exists colormap($p)] + && [lsearch -exact $badcolors $colormap($p)] < 0} { + lappend badcolors $colormap($p) } } } - if {[llength $badcolors] >= $ncolors} { - set badcolors {} + } + if {[llength $badcolors] >= $ncolors} { + set badcolors {} + } + for {set i 0} {$i <= $ncolors} {incr i} { + set c [lindex $colors $nextcolor] + if {[incr nextcolor] >= $ncolors} { + set nextcolor 0 } - for {set i 0} {$i <= $ncolors} {incr i} { - set c [lindex $colors $nextcolor] - if {[incr nextcolor] >= $ncolors} { - set nextcolor 0 - } - if {[lsearch -exact $badcolors $c]} break - } - set colormap($id) $c + if {[lsearch -exact $badcolors $c]} break + } + set colormap($id) $c +} + +proc initgraph {} { + global canvy canvy0 lineno numcommits lthickness nextcolor linespc + global linestarty + global nchildren ncleft + + allcanvs delete all + set nextcolor 0 + set canvy $canvy0 + set lineno -1 + set numcommits 0 + set lthickness [expr {int($linespc / 9) + 1}] + catch {unset linestarty} + foreach id [array names nchildren] { + set ncleft($id) $nchildren($id) } } -proc drawgraph {} { - global parents children nparents nchildren commits - global canv canv2 canv3 mainfont namefont canvx0 canvy0 canvy linespc +proc drawcommitline {level} { + global parents children nparents nchildren ncleft todo + global canv canv2 canv3 mainfont namefont canvx0 canvy linespc global datemode cdate global lineid linehtag linentag linedtag commitinfo - global nextcolor colormap numcommits - global stopped phase redisplaying selectedline idtags idline - global idheads + global colormap numcommits currentparents + global oldlevel oldnlines oldtodo + global idtags idline idheads + global lineno lthickness linestarty + global commitlisted - allcanvs delete all - set start {} - foreach id [array names nchildren] { - if {$nchildren($id) == 0} { - lappend start $id - } - set ncleft($id) $nchildren($id) - if {![info exists nparents($id)]} { + incr numcommits + incr lineno + set id [lindex $todo $level] + set lineid($lineno) $id + set idline($id) $lineno + set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}] + if {![info exists commitinfo($id)]} { + readcommit $id + if {![info exists commitinfo($id)]} { + set commitinfo($id) {"No commit information available"} set nparents($id) 0 } } - if {$start == {}} { - error_popup "Gitk: ERROR: No starting commits found" - exit 1 + set currentparents {} + if {[info exists commitlisted($id)] && [info exists parents($id)]} { + set currentparents $parents($id) + } + set x [expr $canvx0 + $level * $linespc] + set y1 $canvy + set canvy [expr $canvy + $linespc] + allcanvs conf -scrollregion \ + [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]] + if {[info exists linestarty($id)] && $linestarty($id) < $y1} { + set t [$canv create line $x $linestarty($id) $x $y1 \ + -width $lthickness -fill $colormap($id)] + $canv lower $t + } + set orad [expr {$linespc / 3}] + set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \ + [expr $x + $orad - 1] [expr $y1 + $orad - 1] \ + -fill $ofill -outline black -width 1] + $canv raise $t + set xt [expr $canvx0 + [llength $todo] * $linespc] + if {$nparents($id) > 2} { + set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] + } + set marks {} + set ntags 0 + if {[info exists idtags($id)]} { + set marks $idtags($id) + set ntags [llength $marks] + } + if {[info exists idheads($id)]} { + set marks [concat $marks $idheads($id)] + } + if {$marks != {}} { + set delta [expr {int(0.5 * ($linespc - $lthickness))}] + set yt [expr $y1 - 0.5 * $linespc] + set yb [expr $yt + $linespc - 1] + set xvals {} + set wvals {} + foreach tag $marks { + set wid [font measure $mainfont $tag] + lappend xvals $xt + lappend wvals $wid + set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}] + } + set t [$canv create line $x $y1 [lindex $xvals end] $y1 \ + -width $lthickness -fill black] + $canv lower $t + foreach tag $marks x $xvals wid $wvals { + set xl [expr $x + $delta] + set xr [expr $x + $delta + $wid + $lthickness] + if {[incr ntags -1] >= 0} { + # draw a tag + $canv create polygon $x [expr $yt + $delta] $xl $yt\ + $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ + -width 1 -outline black -fill yellow + } else { + # draw a head + set xl [expr $xl - $delta/2] + $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \ + -width 1 -outline black -fill green + } + $canv create text $xl $y1 -anchor w -text $tag \ + -font $mainfont + } + } + set headline [lindex $commitinfo($id) 0] + set name [lindex $commitinfo($id) 1] + set date [lindex $commitinfo($id) 2] + set linehtag($lineno) [$canv create text $xt $y1 -anchor w \ + -text $headline -font $mainfont ] + set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \ + -text $name -font $namefont] + set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \ + -text $date -font $mainfont] +} + +proc updatetodo {level noshortcut} { + global datemode currentparents ncleft todo + global linestarty oldlevel oldtodo oldnlines + global canvy linespc + global commitinfo + + foreach p $currentparents { + if {![info exists commitinfo($p)]} { + readcommit $p + } + } + if {!$noshortcut && [llength $currentparents] == 1} { + set p [lindex $currentparents 0] + if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { + assigncolor $p + set linestarty($p) [expr $canvy - $linespc] + set todo [lreplace $todo $level $level $p] + return 0 + } } - set nextcolor 0 - foreach id $start { - assigncolor $id + set oldlevel $level + set oldtodo $todo + set oldnlines [llength $todo] + set todo [lreplace $todo $level $level] + set i $level + foreach p $currentparents { + incr ncleft($p) -1 + set k [lsearch -exact $todo $p] + if {$k < 0} { + assigncolor $p + set todo [linsert $todo $i $p] + incr i + } } - set todo $start - set level [expr [llength $todo] - 1] - set y2 $canvy0 - set nullentry -1 - 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 [expr $canvy + 0.5 * $linespc + 2]] - update - if {$stopped} break - incr numcommits - incr lineno - set nlines [llength $todo] - set id [lindex $todo $level] - set lineid($lineno) $id - set idline($id) $lineno - set actualparents {} - set ofill white - if {[info exists parents($id)]} { - foreach p $parents($id) { - if {[info exists ncleft($p)]} { - incr ncleft($p) -1 - if {![info exists commitinfo($p)]} { - readcommit $p - if {![info exists commitinfo($p)]} continue - } - lappend actualparents $p - set ofill blue - } - } - } - if {![info exists commitinfo($id)]} { - readcommit $id - if {![info exists commitinfo($id)]} { - set commitinfo($id) {"No commit information available"} - } - } - set x [expr $canvx0 + $level * $linespc] - set y2 [expr $canvy + $linespc] - if {[info exists linestarty($level)] && $linestarty($level) < $canvy} { - set t [$canv create line $x $linestarty($level) $x $canvy \ - -width $lthickness -fill $colormap($id)] - $canv lower $t - } - set linestarty($level) $canvy - 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] - if {$nparents($id) > 2} { - set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] - } - set marks {} - set ntags 0 - if {[info exists idtags($id)]} { - set marks $idtags($id) - set ntags [llength $marks] - } - if {[info exists idheads($id)]} { - set marks [concat $marks $idheads($id)] - } - if {$marks != {}} { - set delta [expr {int(0.5 * ($linespc - $lthickness))}] - set yt [expr $canvy - 0.5 * $linespc] - set yb [expr $yt + $linespc - 1] - set xvals {} - set wvals {} - foreach tag $marks { - set wid [font measure $mainfont $tag] - lappend xvals $xt - lappend wvals $wid - set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}] - } - set t [$canv create line $x $canvy [lindex $xvals end] $canvy \ - -width $lthickness -fill black] - $canv lower $t - foreach tag $marks x $xvals wid $wvals { - set xl [expr $x + $delta] - set xr [expr $x + $delta + $wid + $lthickness] - if {[incr ntags -1] >= 0} { - # draw a tag - $canv create polygon $x [expr $yt + $delta] $xl $yt\ - $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ - -width 1 -outline black -fill yellow + return 1 +} + +proc drawslants {} { + global canv linestarty canvx0 canvy linespc + global oldlevel oldtodo todo currentparents + global lthickness linespc canvy colormap + + set y1 [expr $canvy - $linespc] + set y2 $canvy + set i -1 + foreach id $oldtodo { + incr i + if {$id == {}} continue + set xi [expr {$canvx0 + $i * $linespc}] + if {$i == $oldlevel} { + foreach p $currentparents { + set j [lsearch -exact $todo $p] + if {$i == $j && ![info exists linestarty($p)]} { + set linestarty($p) $y1 } else { - # draw a head - set xl [expr $xl - $delta/2] - $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \ - -width 1 -outline black -fill green - } - $canv create text $xl $canvy -anchor w -text $tag \ - -font $mainfont - } - } - set headline [lindex $commitinfo($id) 0] - set name [lindex $commitinfo($id) 1] - set date [lindex $commitinfo($id) 2] - set linehtag($lineno) [$canv create text $xt $canvy -anchor w \ - -text $headline -font $mainfont ] - set linentag($lineno) [$canv2 create text 3 $canvy -anchor w \ - -text $name -font $namefont] - set linedtag($lineno) [$canv3 create text 3 $canvy -anchor w \ - -text $date -font $mainfont] - if {!$datemode && [llength $actualparents] == 1} { - set p [lindex $actualparents 0] - if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { - assigncolor $p - set todo [lreplace $todo $level $level $p] - continue - } - } - - set oldtodo $todo - set oldlevel $level - set lines {} - for {set i 0} {$i < $nlines} {incr i} { - if {[lindex $todo $i] == {}} continue - if {[info exists linestarty($i)]} { - set oldstarty($i) $linestarty($i) - unset linestarty($i) - } - if {$i != $level} { - lappend lines [list $i [lindex $todo $i]] - } - } - if {$nullentry >= 0} { - set todo [lreplace $todo $nullentry $nullentry] - if {$nullentry < $level} { - incr level -1 - } - } - - set todo [lreplace $todo $level $level] - if {$nullentry > $level} { - incr nullentry -1 - } - set i $level - foreach p $actualparents { - set k [lsearch -exact $todo $p] - if {$k < 0} { - assigncolor $p - set todo [linsert $todo $i $p] - if {$nullentry >= $i} { - incr nullentry - } - incr i - } - lappend lines [list $oldlevel $p] - } - - # choose which one to do next time around - set todol [llength $todo] - set level -1 - set latest {} - for {set k $todol} {[incr k -1] >= 0} {} { - set p [lindex $todo $k] - if {$p == {}} continue - if {$ncleft($p) == 0} { - if {$datemode} { - if {$latest == {} || $cdate($p) > $latest} { - set level $k - set latest $cdate($p) + set xj [expr {$canvx0 + $j * $linespc}] + set coords [list $xi $y1] + if {$j < $i - 1} { + lappend coords [expr $xj + $linespc] $y1 + } elseif {$j > $i + 1} { + lappend coords [expr $xj - $linespc] $y1 + } + lappend coords $xj $y2 + set t [$canv create line $coords -width $lthickness \ + -fill $colormap($p)] + $canv lower $t + if {![info exists linestarty($p)]} { + set linestarty($p) $y2 } - } else { - set level $k - break } } - } - if {$level < 0} { - if {$todo != {}} { - puts "ERROR: none of the pending commits can be done yet:" - foreach p $todo { - puts " $p" - } - } - break - } - - # If we are reducing, put in a null entry - if {$todol < $nlines} { - if {$nullentry >= 0} { - set i $nullentry - while {$i < $todol - && [lindex $oldtodo $i] == [lindex $todo $i]} { - incr i - } - } else { - set i $oldlevel - if {$level >= $i} { - incr i - } - } - if {$i >= $todol} { - set nullentry -1 - } else { - set nullentry $i - set todo [linsert $todo $nullentry {}] - if {$level >= $i} { - incr level - } - } - } else { - set nullentry -1 - } - - foreach l $lines { - set i [lindex $l 0] - set dst [lindex $l 1] - set j [lsearch -exact $todo $dst] - if {$i == $j} { - if {[info exists oldstarty($i)]} { - set linestarty($i) $oldstarty($i) - } - continue - } - set xi [expr {$canvx0 + $i * $linespc}] + } elseif {[lindex $todo $i] != $id} { + set j [lsearch -exact $todo $id] set xj [expr {$canvx0 + $j * $linespc}] set coords {} - if {[info exists oldstarty($i)] && $oldstarty($i) < $canvy} { - lappend coords $xi $oldstarty($i) + if {[info exists linestarty($id)] && $linestarty($id) < $y1} { + lappend coords $xi $linestarty($id) } - lappend coords $xi $canvy - if {$j < $i - 1} { - lappend coords [expr $xj + $linespc] $canvy - } elseif {$j > $i + 1} { - lappend coords [expr $xj - $linespc] $canvy - } - lappend coords $xj $y2 + lappend coords $xi $y1 $xj $y2 set t [$canv create line $coords -width $lthickness \ - -fill $colormap($dst)] + -fill $colormap($id)] $canv lower $t - if {![info exists linestarty($j)]} { - set linestarty($j) $y2 + set linestarty($id) $y2 + } + } +} + +proc decidenext {} { + global parents children nchildren ncleft todo + global canv canv2 canv3 mainfont namefont canvx0 canvy linespc + global datemode cdate + global lineid linehtag linentag linedtag commitinfo + global currentparents oldlevel oldnlines oldtodo + global lineno lthickness + + # remove the null entry if present + set nullentry [lsearch -exact $todo {}] + if {$nullentry >= 0} { + set todo [lreplace $todo $nullentry $nullentry] + } + + # choose which one to do next time around + set todol [llength $todo] + set level -1 + set latest {} + for {set k $todol} {[incr k -1] >= 0} {} { + set p [lindex $todo $k] + if {$ncleft($p) == 0} { + if {$datemode} { + if {$latest == {} || $cdate($p) > $latest} { + set level $k + set latest $cdate($p) + } + } else { + set level $k + break } } } + if {$level < 0} { + if {$todo != {}} { + puts "ERROR: none of the pending commits can be done yet:" + foreach p $todo { + puts " $p" + } + } + return -1 + } + + # If we are reducing, put in a null entry + if {$todol < $oldnlines} { + if {$nullentry >= 0} { + set i $nullentry + while {$i < $todol + && [lindex $oldtodo $i] == [lindex $todo $i]} { + incr i + } + } else { + set i $oldlevel + if {$level >= $i} { + incr i + } + } + if {$i < $todol} { + set todo [linsert $todo $i {}] + if {$level >= $i} { + incr level + } + } + } + return $level +} + +proc drawcommit {id} { + global phase todo nchildren datemode nextupdate + global startcommits + + if {$phase != "incrdraw"} { + set phase incrdraw + set todo $id + set startcommits $id + initgraph + assigncolor $id + drawcommitline 0 + updatetodo 0 $datemode + } else { + if {$nchildren($id) == 0} { + lappend todo $id + lappend startcommits $id + assigncolor $id + } + set level [decidenext] + if {$id != [lindex $todo $level]} { + return + } + while 1 { + drawslants + drawcommitline $level + if {[updatetodo $level $datemode]} { + set level [decidenext] + } + set id [lindex $todo $level] + if {![info exists commitlisted($id)]} { + break + } + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + if {$stopped} break + } + } + } +} + +proc finishcommits {} { + global phase + global startcommits + + if {$phase != "incrdraw"} { + $canv delete all + $canv create text 3 3 -anchor nw -text "No commits selected" \ + -font $mainfont -tags textitems + set phase {} + return + } + drawslants + set level [decidenext] + drawrest $level [llength $startcommits] +} + +proc drawgraph {} { + global nextupdate startmsecs startcommits todo + + if {$startcommits == {}} return + set startmsecs [clock clicks -milliseconds] + set nextupdate [expr $startmsecs + 100] + initgraph + set todo [lindex $startcommits 0] + drawrest 0 1 +} + +proc drawrest {level startix} { + global phase stopped redisplaying selectedline + global datemode currentparents todo + global numcommits + global nextupdate startmsecs startcommits idline + + set phase drawgraph + set startid [lindex $startcommits $startix] + set startline -1 + if {$startid != {}} { + set startline $idline($startid) + } + while 1 { + if {$stopped} break + drawcommitline $level + set hard [updatetodo $level $datemode] + if {$numcommits == $startline} { + lappend todo $startid + set hard 1 + incr startix + set startid [lindex $startcommits $startix] + set startline -1 + if {$startid != {}} { + set startline $idline($startid) + } + } + if {$hard} { + set level [decidenext] + if {$level < 0} break + drawslants + } + if {[clock clicks -milliseconds] >= $nextupdate} { + update + incr nextupdate 100 + } + } set phase {} + set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs] + puts "overall $drawmsecs ms for $numcommits commits" if {$redisplaying} { if {$stopped == 0 && [info exists selectedline]} { selectline $selectedline @@ -854,7 +974,7 @@ proc dofind {} { global findtype findloc findstring markedmatches commitinfo global numcommits lineid linehtag linentag linedtag global mainfont namefont canv canv2 canv3 selectedline - global matchinglines foundstring foundstrlen idtags + global matchinglines foundstring foundstrlen unmarkmatches focus . set matchinglines {} @@ -1000,7 +1120,7 @@ proc selectline {l} { global lineid linehtag linentag linedtag global canvy0 linespc nparents treepending global cflist treediffs currentid sha1entry - global commentend seenfile numcommits idtags + global commentend seenfile idtags if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ @@ -1288,7 +1408,7 @@ proc redisplay {} { if {$stopped > 1} return if {$phase == "getcommits"} return set redisplaying 1 - if {$phase == "drawgraph"} { + if {$phase == "drawgraph" || $phase == "incrdraw"} { set stopped 1 } else { drawgraph @@ -1366,7 +1486,6 @@ set mainfont {Helvetica 9} set textfont {Courier 9} set colors {green red blue magenta darkgrey brown orange} -set colorbycommitter 0 catch {source ~/.gitk} @@ -1380,7 +1499,6 @@ foreach arg $argv { switch -regexp -- $arg { "^$" { } "^-b" { set boldnames 1 } - "^-c" { set colorbycommitter 1 } "^-d" { set datemode 1 } default { lappend revtreeargs $arg @@ -1388,6 +1506,8 @@ foreach arg $argv { } } +set noreadobj [load libreadobj.so.0.0] +set noreadobj 0 set stopped 0 set redisplaying 0 set stuffsaved 0 From ea13cba175bc35e1af3d60181b2419ac987f1938 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 16 Jun 2005 10:54:04 +0000 Subject: [PATCH 23/29] Fix operation without libreadobj.so.0.0 Display a watch cursor when reading the commits initially --- gitk | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index f33c3fa0cc..73c736d098 100755 --- a/gitk +++ b/gitk @@ -7,11 +7,12 @@ 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.22 $ +# CVS $Revision: 1.23 $ proc getcommits {rargs} { global commits commfd phase canv mainfont global startmsecs nextupdate + global ctext maincursor textcursor if {$rargs == {}} { set rargs HEAD @@ -29,6 +30,8 @@ proc getcommits {rargs} { $canv delete all $canv create text 3 3 -anchor nw -text "Reading commits..." \ -font $mainfont -tags textitems + . config -cursor watch + $ctext config -cursor watch } proc getcommitline {commfd} { @@ -238,6 +241,7 @@ proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont global findtype findloc findstring fstring geometry global entries sha1entry sha1string sha1but + global maincursor textcursor menu .bar .bar add cascade -label "File" -menu .bar.file @@ -377,6 +381,9 @@ proc makewindow {} { bind . "click %W" bind $fstring dofind bind $sha1entry gotocommit + + set maincursor [. cget -cursor] + set textcursor [$ctext cget -cursor] } # when we make a key binding for the toplevel, make sure @@ -512,7 +519,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.22 $)} \ +(CVS $Revision: 1.23 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -874,6 +881,7 @@ proc drawcommit {id} { proc finishcommits {} { global phase global startcommits + global ctext maincursor textcursor if {$phase != "incrdraw"} { $canv delete all @@ -885,6 +893,8 @@ proc finishcommits {} { drawslants set level [decidenext] drawrest $level [llength $startcommits] + . config -cursor $maincursor + $ctext config -cursor $textcursor } proc drawgraph {} { @@ -1506,8 +1516,7 @@ foreach arg $argv { } } -set noreadobj [load libreadobj.so.0.0] -set noreadobj 0 +set noreadobj [catch {load libreadobj.so.0.0}] set stopped 0 set redisplaying 0 set stuffsaved 0 From 84ba73458059ff0a50dbf1a63dff73be63f09795 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 17 Jun 2005 00:12:26 +0000 Subject: [PATCH 24/29] Draw graph lines as one continuous line where possible Added context menu on lines Added headline display when the mouse hovers over a line Removed some debug messages --- gitk | 152 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 30 deletions(-) diff --git a/gitk b/gitk index 73c736d098..f6c4ec2f1f 100755 --- a/gitk +++ b/gitk @@ -7,12 +7,12 @@ 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.23 $ +# CVS $Revision: 1.24 $ proc getcommits {rargs} { global commits commfd phase canv mainfont global startmsecs nextupdate - global ctext maincursor textcursor + global ctext maincursor textcursor nlines if {$rargs == {}} { set rargs HEAD @@ -25,6 +25,7 @@ proc getcommits {rargs} { puts stderr "Error executing git-rev-list: $err" exit 1 } + set nlines 0 fconfigure $commfd -blocking 0 fileevent $commfd readable "getcommitline $commfd" $canv delete all @@ -37,7 +38,7 @@ proc getcommits {rargs} { proc getcommitline {commfd} { global commits parents cdate children nchildren ncleft global commitlisted phase commitinfo nextupdate - global stopped redisplaying + global stopped redisplaying nlines set n [gets $commfd line] if {$n < 0} { @@ -59,6 +60,7 @@ to allow selection of commits to be displayed.)} error_popup $err exit 1 } + incr nlines if {![regexp {^[0-9a-f]{40}$} $line id]} { error_popup "Can't parse git-rev-list output: {$line}" exit 1 @@ -242,6 +244,7 @@ proc makewindow {} { global findtype findloc findstring fstring geometry global entries sha1entry sha1string sha1but global maincursor textcursor + global linectxmenu menu .bar .bar add cascade -label "File" -menu .bar.file @@ -384,6 +387,10 @@ proc makewindow {} { set maincursor [. cget -cursor] set textcursor [$ctext cget -cursor] + + set linectxmenu .linectxmenu + menu $linectxmenu -tearoff 0 + $linectxmenu add command -label "Select" -command lineselect } # when we make a key binding for the toplevel, make sure @@ -519,7 +526,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.23 $)} \ +(CVS $Revision: 1.24 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -569,7 +576,7 @@ proc assigncolor {id} { proc initgraph {} { global canvy canvy0 lineno numcommits lthickness nextcolor linespc - global linestarty + global glines global nchildren ncleft allcanvs delete all @@ -578,7 +585,7 @@ proc initgraph {} { set lineno -1 set numcommits 0 set lthickness [expr {int($linespc / 9) + 1}] - catch {unset linestarty} + catch {unset glines} foreach id [array names nchildren] { set ncleft($id) $nchildren($id) } @@ -592,7 +599,7 @@ proc drawcommitline {level} { global colormap numcommits currentparents global oldlevel oldnlines oldtodo global idtags idline idheads - global lineno lthickness linestarty + global lineno lthickness glines global commitlisted incr numcommits @@ -617,10 +624,15 @@ proc drawcommitline {level} { set canvy [expr $canvy + $linespc] allcanvs conf -scrollregion \ [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]] - if {[info exists linestarty($id)] && $linestarty($id) < $y1} { - set t [$canv create line $x $linestarty($id) $x $y1 \ + if {[info exists glines($id)]} { + lappend glines($id) $x $y1 + set t [$canv create line $glines($id) \ -width $lthickness -fill $colormap($id)] $canv lower $t + $canv bind $t "linemenu %X %Y $id" + $canv bind $t "lineenter %x %y $id" + $canv bind $t "linemotion %x %y $id" + $canv bind $t "lineleave $id" } set orad [expr {$linespc / 3}] set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \ @@ -655,6 +667,10 @@ proc drawcommitline {level} { set t [$canv create line $x $y1 [lindex $xvals end] $y1 \ -width $lthickness -fill black] $canv lower $t + $canv bind $t "linemenu %X %Y $id" + $canv bind $t "lineenter %x %y $id" + $canv bind $t "linemotion %x %y $id" + $canv bind $t "lineleave $id" foreach tag $marks x $xvals wid $wvals { set xl [expr $x + $delta] set xr [expr $x + $delta + $wid + $lthickness] @@ -686,8 +702,8 @@ proc drawcommitline {level} { proc updatetodo {level noshortcut} { global datemode currentparents ncleft todo - global linestarty oldlevel oldtodo oldnlines - global canvy linespc + global glines oldlevel oldtodo oldnlines + global canvx0 canvy linespc glines global commitinfo foreach p $currentparents { @@ -695,11 +711,13 @@ proc updatetodo {level noshortcut} { readcommit $p } } + set x [expr $canvx0 + $level * $linespc] + set y [expr $canvy - $linespc] if {!$noshortcut && [llength $currentparents] == 1} { set p [lindex $currentparents 0] if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { assigncolor $p - set linestarty($p) [expr $canvy - $linespc] + set glines($p) [list $x $y] set todo [lreplace $todo $level $level $p] return 0 } @@ -723,7 +741,7 @@ proc updatetodo {level noshortcut} { } proc drawslants {} { - global canv linestarty canvx0 canvy linespc + global canv glines canvx0 canvy linespc global oldlevel oldtodo todo currentparents global lthickness linespc canvy colormap @@ -737,8 +755,8 @@ proc drawslants {} { if {$i == $oldlevel} { foreach p $currentparents { set j [lsearch -exact $todo $p] - if {$i == $j && ![info exists linestarty($p)]} { - set linestarty($p) $y1 + if {$i == $j && ![info exists glines($p)]} { + set glines($p) [list $xi $y1] } else { set xj [expr {$canvx0 + $j * $linespc}] set coords [list $xi $y1] @@ -748,26 +766,23 @@ proc drawslants {} { lappend coords [expr $xj - $linespc] $y1 } lappend coords $xj $y2 - set t [$canv create line $coords -width $lthickness \ - -fill $colormap($p)] - $canv lower $t - if {![info exists linestarty($p)]} { - set linestarty($p) $y2 + if {![info exists glines($p)]} { + set glines($p) $coords + } else { + set t [$canv create line $coords -width $lthickness \ + -fill $colormap($p)] + $canv lower $t + $canv bind $t "linemenu %X %Y $p" + $canv bind $t "lineenter %x %y $p" + $canv bind $t "linemotion %x %y $p" + $canv bind $t "lineleave $p" } } } } elseif {[lindex $todo $i] != $id} { set j [lsearch -exact $todo $id] set xj [expr {$canvx0 + $j * $linespc}] - set coords {} - if {[info exists linestarty($id)] && $linestarty($id) < $y1} { - lappend coords $xi $linestarty($id) - } - lappend coords $xi $y1 $xj $y2 - set t [$canv create line $coords -width $lthickness \ - -fill $colormap($id)] - $canv lower $t - set linestarty($id) $y2 + lappend glines($id) $xi $y1 $xj $y2 } } } @@ -946,7 +961,7 @@ proc drawrest {level startix} { } set phase {} set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs] - puts "overall $drawmsecs ms for $numcommits commits" + #puts "overall $drawmsecs ms for $numcommits commits" if {$redisplaying} { if {$stopped == 0 && [info exists selectedline]} { selectline $selectedline @@ -1131,6 +1146,7 @@ proc selectline {l} { global canvy0 linespc nparents treepending global cflist treediffs currentid sha1entry global commentend seenfile idtags + $canv delete hover if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ @@ -1481,6 +1497,82 @@ proc gotocommit {} { error_popup "$type $sha1string is not known" } +proc linemenu {x y id} { + global linectxmenu linemenuid + set linemenuid $id + $linectxmenu post $x $y +} + +proc lineselect {} { + global linemenuid idline + if {[info exists linemenuid] && [info exists idline($linemenuid)]} { + selectline $idline($linemenuid) + } +} + +proc lineenter {x y id} { + global hoverx hovery hoverid hovertimer + global commitinfo canv + + if {![info exists commitinfo($id)]} return + set hoverx $x + set hovery $y + set hoverid $id + if {[info exists hovertimer]} { + after cancel $hovertimer + } + set hovertimer [after 500 linehover] + $canv delete hover +} + +proc linemotion {x y id} { + global hoverx hovery hoverid hovertimer + + if {[info exists hoverid] && $id == $hoverid} { + set hoverx $x + set hovery $y + if {[info exists hovertimer]} { + after cancel $hovertimer + } + set hovertimer [after 500 linehover] + } +} + +proc lineleave {id} { + global hoverid hovertimer canv + + if {[info exists hoverid] && $id == $hoverid} { + $canv delete hover + if {[info exists hovertimer]} { + after cancel $hovertimer + unset hovertimer + } + unset hoverid + } +} + +proc linehover {} { + global hoverx hovery hoverid hovertimer + global canv linespc lthickness + global commitinfo mainfont + + set text [lindex $commitinfo($hoverid) 0] + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax == {}} return + set yfrac [lindex [$canv yview] 0] + set x [expr {$hoverx + 2 * $linespc}] + 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 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] + $canv raise $t +} + proc doquit {} { global stopped set stopped 100 From a823a91131616c28f9c3ef5601b09b7e01393204 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 21 Jun 2005 10:01:38 +1000 Subject: [PATCH 25/29] Handle the case of a parent being listed twice in a merge. This happens in the linux-2.6 tree. We draw the graph line double-thick to show that this happened. Also fix a bug where we got a bogus "No commit information available" line at the end on simple repositories like this one. --- gitk | 136 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/gitk b/gitk index f6c4ec2f1f..d509998955 100755 --- a/gitk +++ b/gitk @@ -36,7 +36,7 @@ proc getcommits {rargs} { } proc getcommitline {commfd} { - global commits parents cdate children nchildren ncleft + global commits parents cdate children nchildren global commitlisted phase commitinfo nextupdate global stopped redisplaying nlines @@ -144,12 +144,11 @@ proc readcommit {id} { } lappend parents($id) $p incr nparents($id) + # sometimes we get a commit that lists a parent twice... if {[lsearch -exact $children($p) $id] < 0} { lappend children($p) $id incr nchildren($p) incr ncleft($p) - } else { - puts "child $id already in $p's list??" } } elseif {$tag == "author"} { set x [expr {[llength $line] - 2}] @@ -591,12 +590,21 @@ proc initgraph {} { } } +proc bindline {t id} { + global canv + + $canv bind $t "linemenu %X %Y $id" + $canv bind $t "lineenter %x %y $id" + $canv bind $t "linemotion %x %y $id" + $canv bind $t "lineleave $id" +} + proc drawcommitline {level} { - global parents children nparents nchildren ncleft todo + global parents children nparents nchildren todo global canv canv2 canv3 mainfont namefont canvx0 canvy linespc global datemode cdate global lineid linehtag linentag linedtag commitinfo - global colormap numcommits currentparents + global colormap numcommits currentparents dupparents global oldlevel oldnlines oldtodo global idtags idline idheads global lineno lthickness glines @@ -616,8 +624,16 @@ proc drawcommitline {level} { } } set currentparents {} + set dupparents {} if {[info exists commitlisted($id)] && [info exists parents($id)]} { - set currentparents $parents($id) + foreach p $parents($id) { + if {[lsearch -exact $currentparents $p] < 0} { + lappend currentparents $p + } else { + # remember that this parent was listed twice + lappend dupparents $p + } + } } set x [expr $canvx0 + $level * $linespc] set y1 $canvy @@ -629,10 +645,7 @@ proc drawcommitline {level} { set t [$canv create line $glines($id) \ -width $lthickness -fill $colormap($id)] $canv lower $t - $canv bind $t "linemenu %X %Y $id" - $canv bind $t "lineenter %x %y $id" - $canv bind $t "linemotion %x %y $id" - $canv bind $t "lineleave $id" + bindline $t $id } set orad [expr {$linespc / 3}] set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \ @@ -667,10 +680,6 @@ proc drawcommitline {level} { set t [$canv create line $x $y1 [lindex $xvals end] $y1 \ -width $lthickness -fill black] $canv lower $t - $canv bind $t "linemenu %X %Y $id" - $canv bind $t "lineenter %x %y $id" - $canv bind $t "linemotion %x %y $id" - $canv bind $t "lineleave $id" foreach tag $marks x $xvals wid $wvals { set xl [expr $x + $delta] set xr [expr $x + $delta + $wid + $lthickness] @@ -742,7 +751,7 @@ proc updatetodo {level noshortcut} { proc drawslants {} { global canv glines canvx0 canvy linespc - global oldlevel oldtodo todo currentparents + global oldlevel oldtodo todo currentparents dupparents global lthickness linespc canvy colormap set y1 [expr $canvy - $linespc] @@ -755,27 +764,36 @@ proc drawslants {} { if {$i == $oldlevel} { foreach p $currentparents { set j [lsearch -exact $todo $p] - if {$i == $j && ![info exists glines($p)]} { - set glines($p) [list $xi $y1] - } else { - set xj [expr {$canvx0 + $j * $linespc}] - set coords [list $xi $y1] - if {$j < $i - 1} { - lappend coords [expr $xj + $linespc] $y1 - } elseif {$j > $i + 1} { - lappend coords [expr $xj - $linespc] $y1 - } + set coords [list $xi $y1] + set xj [expr {$canvx0 + $j * $linespc}] + if {$j < $i - 1} { + lappend coords [expr $xj + $linespc] $y1 + } elseif {$j > $i + 1} { + lappend coords [expr $xj - $linespc] $y1 + } + if {[lsearch -exact $dupparents $p] >= 0} { + # draw a double-width line to indicate the doubled parent lappend coords $xj $y2 + set t [$canv create line $coords \ + -width [expr 2*$lthickness] -fill $colormap($p)] + $canv lower $t + bindline $t $p if {![info exists glines($p)]} { + set glines($p) [list $xj $y2] + } + } else { + # normal case, no parent duplicated + if {![info exists glines($p)]} { + if {$i != $j} { + lappend coords $xj $y2 + } set glines($p) $coords } else { - set t [$canv create line $coords -width $lthickness \ - -fill $colormap($p)] + lappend coords $xj $y2 + set t [$canv create line $coords \ + -width $lthickness -fill $colormap($p)] $canv lower $t - $canv bind $t "linemenu %X %Y $p" - $canv bind $t "lineenter %x %y $p" - $canv bind $t "linemotion %x %y $p" - $canv bind $t "lineleave $p" + bindline $t $p } } } @@ -929,34 +947,36 @@ proc drawrest {level startix} { global numcommits global nextupdate startmsecs startcommits idline - set phase drawgraph - set startid [lindex $startcommits $startix] - set startline -1 - if {$startid != {}} { - set startline $idline($startid) - } - while 1 { - if {$stopped} break - drawcommitline $level - set hard [updatetodo $level $datemode] - if {$numcommits == $startline} { - lappend todo $startid - set hard 1 - incr startix - set startid [lindex $startcommits $startix] - set startline -1 - if {$startid != {}} { - set startline $idline($startid) + if {$level >= 0} { + set phase drawgraph + set startid [lindex $startcommits $startix] + set startline -1 + if {$startid != {}} { + set startline $idline($startid) + } + while 1 { + if {$stopped} break + drawcommitline $level + set hard [updatetodo $level $datemode] + if {$numcommits == $startline} { + lappend todo $startid + set hard 1 + incr startix + set startid [lindex $startcommits $startix] + set startline -1 + if {$startid != {}} { + set startline $idline($startid) + } + } + if {$hard} { + set level [decidenext] + if {$level < 0} break + drawslants + } + if {[clock clicks -milliseconds] >= $nextupdate} { + update + incr nextupdate 100 } - } - if {$hard} { - set level [decidenext] - if {$level < 0} break - drawslants - } - if {[clock clicks -milliseconds] >= $nextupdate} { - update - incr nextupdate 100 } } set phase {} From 2efef4b9b5e65b436eff3b481edc273204453c72 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 21 Jun 2005 10:20:04 +1000 Subject: [PATCH 26/29] Pass arguments through git-rev-parse. This allows the user to specify ranges more flexibly; for instance the user can now do "gitk v2.6.12.." and see all the changes since 2.6.12. --- gitk | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index d509998955..fef705ce97 100755 --- a/gitk +++ b/gitk @@ -14,14 +14,22 @@ proc getcommits {rargs} { global startmsecs nextupdate global ctext maincursor textcursor nlines - if {$rargs == {}} { - set rargs HEAD - } set commits {} set phase getcommits set startmsecs [clock clicks -milliseconds] set nextupdate [expr $startmsecs + 100] - if [catch {set commfd [open "|git-rev-list --merge-order $rargs" r]} err] { + if [catch { + set parse_args [concat --default HEAD --merge-order $rargs] + set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"] + }] { + if {$rargs == {}} { + set rargs HEAD + } + set parsed_args [concat --merge-order $rargs] + } + if [catch { + set commfd [open "|git-rev-list $parsed_args" r] + } err] { puts stderr "Error executing git-rev-list: $err" exit 1 } From b490a991761bb3bebdb720957f15dee222a052ab Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 22 Jun 2005 10:25:38 +1000 Subject: [PATCH 27/29] Use git-rev-list --header. With --header, git-rev-list gives us the contents of the commit in-line, so we don't need to exec a git-cat-file to get it, and we don't need the readobj command either. Also fixed a residual problem with handling the commit that has a parent listed twice. --- gitk | 188 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/gitk b/gitk index fef705ce97..922701ca75 100755 --- a/gitk +++ b/gitk @@ -12,30 +12,31 @@ exec wish "$0" -- "${1+$@}" proc getcommits {rargs} { global commits commfd phase canv mainfont global startmsecs nextupdate - global ctext maincursor textcursor nlines + global ctext maincursor textcursor leftover set commits {} set phase getcommits set startmsecs [clock clicks -milliseconds] set nextupdate [expr $startmsecs + 100] if [catch { - set parse_args [concat --default HEAD --merge-order $rargs] + set parse_args [concat --default HEAD $rargs] set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"] }] { + # if git-rev-parse failed for some reason... if {$rargs == {}} { set rargs HEAD } - set parsed_args [concat --merge-order $rargs] + set parsed_args $rargs } if [catch { - set commfd [open "|git-rev-list $parsed_args" r] + set commfd [open "|git-rev-list --header --merge-order $parsed_args" r] } err] { puts stderr "Error executing git-rev-list: $err" exit 1 } - set nlines 0 - fconfigure $commfd -blocking 0 - fileevent $commfd readable "getcommitline $commfd" + set leftover {} + fconfigure $commfd -blocking 0 -translation binary + fileevent $commfd readable "getcommitlines $commfd" $canv delete all $canv create text 3 3 -anchor nw -text "Reading commits..." \ -font $mainfont -tags textitems @@ -43,13 +44,13 @@ proc getcommits {rargs} { $ctext config -cursor watch } -proc getcommitline {commfd} { +proc getcommitlines {commfd} { global commits parents cdate children nchildren global commitlisted phase commitinfo nextupdate - global stopped redisplaying nlines + global stopped redisplaying leftover - set n [gets $commfd line] - if {$n < 0} { + set stuff [read $commfd] + if {$stuff == {}} { if {![eof $commfd]} return # this works around what is apparently a bug in Tcl... fconfigure $commfd -blocking 1 @@ -68,35 +69,41 @@ to allow selection of commits to be displayed.)} error_popup $err exit 1 } - incr nlines - if {![regexp {^[0-9a-f]{40}$} $line id]} { - error_popup "Can't parse git-rev-list output: {$line}" - exit 1 - } - lappend commits $id - set commitlisted($id) 1 - if {![info exists commitinfo($id)]} { - readcommit $id - } - foreach p $parents($id) { - if {[info exists commitlisted($p)]} { - puts "oops, parent $p before child $id" + set start 0 + while 1 { + set i [string first "\0" $stuff $start] + if {$i < 0} { + set leftover [string range $stuff $start end] + return } - } - drawcommit $id - if {[clock clicks -milliseconds] >= $nextupdate} { - doupdate - } - while {$redisplaying} { - set redisplaying 0 - if {$stopped == 1} { - set stopped 0 - set phase "getcommits" - foreach id $commits { - drawcommit $id - if {$stopped} break - if {[clock clicks -milliseconds] >= $nextupdate} { - doupdate + set cmit [string range $stuff $start [expr {$i - 1}]] + if {$start == 0} { + set cmit "$leftover$cmit" + } + set start [expr {$i + 1}] + if {![regexp {^([0-9a-f]{40})\n} $cmit match id]} { + error_popup "Can't parse git-rev-list output: {$cmit}" + exit 1 + } + set cmit [string range $cmit 41 end] + lappend commits $id + set commitlisted($id) 1 + parsecommit $id $cmit 1 + drawcommit $id + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + } + while {$redisplaying} { + set redisplaying 0 + if {$stopped == 1} { + set stopped 0 + set phase "getcommits" + foreach id $commits { + drawcommit $id + if {$stopped} break + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + } } } } @@ -109,12 +116,16 @@ proc doupdate {} { incr nextupdate 100 fileevent $commfd readable {} update - fileevent $commfd readable "getcommitline $commfd" + fileevent $commfd readable "getcommitlines $commfd" } proc readcommit {id} { + if [catch {set contents [exec git-cat-file commit $id]}] return + parsecommit $id $contents 0 +} + +proc parsecommit {id contents listed} { global commitinfo children nchildren parents nparents cdate ncleft - global noreadobj set inhdr 1 set comment {} @@ -130,13 +141,6 @@ proc readcommit {id} { } set parents($id) {} set nparents($id) 0 - if {$noreadobj} { - if [catch {set contents [exec git-cat-file commit $id]}] return - } else { - if [catch {set x [readobj $id]}] return - if {[lindex $x 0] != "commit"} return - set contents [lindex $x 1] - } foreach line [split $contents "\n"] { if {$inhdr} { if {$line == {}} { @@ -153,7 +157,7 @@ proc readcommit {id} { lappend parents($id) $p incr nparents($id) # sometimes we get a commit that lists a parent twice... - if {[lsearch -exact $children($p) $id] < 0} { + if {$listed && [lsearch -exact $children($p) $id] < 0} { lappend children($p) $id incr nchildren($p) incr ncleft($p) @@ -545,7 +549,7 @@ proc assigncolor {id} { global parents nparents children nchildren if [info exists colormap($id)] return set ncolors [llength $colors] - if {$nparents($id) == 1 && $nchildren($id) == 1} { + if {$nparents($id) <= 1 && $nchildren($id) == 1} { set child [lindex $children($id) 0] if {[info exists colormap($child)] && $nparents($child) == 1} { @@ -583,7 +587,7 @@ proc assigncolor {id} { proc initgraph {} { global canvy canvy0 lineno numcommits lthickness nextcolor linespc - global glines + global mainline sidelines global nchildren ncleft allcanvs delete all @@ -592,7 +596,8 @@ proc initgraph {} { set lineno -1 set numcommits 0 set lthickness [expr {int($linespc / 9) + 1}] - catch {unset glines} + catch {unset mainline} + catch {unset sidelines} foreach id [array names nchildren] { set ncleft($id) $nchildren($id) } @@ -610,12 +615,11 @@ proc bindline {t id} { proc drawcommitline {level} { global parents children nparents nchildren todo global canv canv2 canv3 mainfont namefont canvx0 canvy linespc - global datemode cdate global lineid linehtag linentag linedtag commitinfo global colormap numcommits currentparents dupparents global oldlevel oldnlines oldtodo global idtags idline idheads - global lineno lthickness glines + global lineno lthickness mainline sidelines global commitlisted incr numcommits @@ -631,6 +635,7 @@ proc drawcommitline {level} { set nparents($id) 0 } } + assigncolor $id set currentparents {} set dupparents {} if {[info exists commitlisted($id)] && [info exists parents($id)]} { @@ -648,21 +653,31 @@ proc drawcommitline {level} { set canvy [expr $canvy + $linespc] allcanvs conf -scrollregion \ [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]] - if {[info exists glines($id)]} { - lappend glines($id) $x $y1 - set t [$canv create line $glines($id) \ + if {[info exists mainline($id)]} { + lappend mainline($id) $x $y1 + set t [$canv create line $mainline($id) \ -width $lthickness -fill $colormap($id)] $canv lower $t bindline $t $id } + if {[info exists sidelines($id)]} { + foreach ls $sidelines($id) { + set coords [lindex $ls 0] + set thick [lindex $ls 1] + set t [$canv create line $coords -fill $colormap($id) \ + -width [expr {$thick * $lthickness}]] + $canv lower $t + bindline $t $id + } + } set orad [expr {$linespc / 3}] set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \ [expr $x + $orad - 1] [expr $y1 + $orad - 1] \ -fill $ofill -outline black -width 1] $canv raise $t set xt [expr $canvx0 + [llength $todo] * $linespc] - if {$nparents($id) > 2} { - set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] + if {[llength $currentparents] > 2} { + set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}] } set marks {} set ntags 0 @@ -718,38 +733,32 @@ proc drawcommitline {level} { } proc updatetodo {level noshortcut} { - global datemode currentparents ncleft todo - global glines oldlevel oldtodo oldnlines - global canvx0 canvy linespc glines + global currentparents ncleft todo + global mainline oldlevel oldtodo oldnlines + global canvx0 canvy linespc mainline global commitinfo - foreach p $currentparents { - if {![info exists commitinfo($p)]} { - readcommit $p - } - } - set x [expr $canvx0 + $level * $linespc] - set y [expr $canvy - $linespc] + set oldlevel $level + set oldtodo $todo + set oldnlines [llength $todo] if {!$noshortcut && [llength $currentparents] == 1} { set p [lindex $currentparents 0] - if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { - assigncolor $p - set glines($p) [list $x $y] + if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} { + set ncleft($p) 0 + set x [expr $canvx0 + $level * $linespc] + set y [expr $canvy - $linespc] + set mainline($p) [list $x $y] set todo [lreplace $todo $level $level $p] return 0 } } - set oldlevel $level - set oldtodo $todo - set oldnlines [llength $todo] set todo [lreplace $todo $level $level] set i $level foreach p $currentparents { incr ncleft($p) -1 set k [lsearch -exact $todo $p] if {$k < 0} { - assigncolor $p set todo [linsert $todo $i $p] incr i } @@ -758,7 +767,7 @@ proc updatetodo {level noshortcut} { } proc drawslants {} { - global canv glines canvx0 canvy linespc + global canv mainline sidelines canvx0 canvy linespc global oldlevel oldtodo todo currentparents dupparents global lthickness linespc canvy colormap @@ -782,33 +791,27 @@ proc drawslants {} { if {[lsearch -exact $dupparents $p] >= 0} { # draw a double-width line to indicate the doubled parent lappend coords $xj $y2 - set t [$canv create line $coords \ - -width [expr 2*$lthickness] -fill $colormap($p)] - $canv lower $t - bindline $t $p - if {![info exists glines($p)]} { - set glines($p) [list $xj $y2] + lappend sidelines($p) [list $coords 2] + if {![info exists mainline($p)]} { + set mainline($p) [list $xj $y2] } } else { # normal case, no parent duplicated - if {![info exists glines($p)]} { + if {![info exists mainline($p)]} { if {$i != $j} { lappend coords $xj $y2 } - set glines($p) $coords + set mainline($p) $coords } else { lappend coords $xj $y2 - set t [$canv create line $coords \ - -width $lthickness -fill $colormap($p)] - $canv lower $t - bindline $t $p + lappend sidelines($p) [list $coords 1] } } } } elseif {[lindex $todo $i] != $id} { set j [lsearch -exact $todo $id] set xj [expr {$canvx0 + $j * $linespc}] - lappend glines($id) $xi $y1 $xj $y2 + lappend mainline($id) $xi $y1 $xj $y2 } } } @@ -849,7 +852,7 @@ proc decidenext {} { if {$todo != {}} { puts "ERROR: none of the pending commits can be done yet:" foreach p $todo { - puts " $p" + puts " $p ($ncleft($p))" } } return -1 @@ -888,14 +891,12 @@ proc drawcommit {id} { set todo $id set startcommits $id initgraph - assigncolor $id drawcommitline 0 updatetodo 0 $datemode } else { if {$nchildren($id) == 0} { lappend todo $id lappend startcommits $id - assigncolor $id } set level [decidenext] if {$id != [lindex $todo $level]} { @@ -1636,7 +1637,6 @@ foreach arg $argv { } } -set noreadobj [catch {load libreadobj.so.0.0}] set stopped 0 set redisplaying 0 set stuffsaved 0 From 806ce0971895249d1ebb641b77f1fa870d86d73e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 22 Jun 2005 18:15:15 +1000 Subject: [PATCH 28/29] Account for indentation of the checkin comments by git-rev-list This involves adding indentation when we read a commit with git-cat-file and trimming the whitespace from the headline. --- gitk | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gitk b/gitk index 922701ca75..1606c38d09 100755 --- a/gitk +++ b/gitk @@ -174,10 +174,15 @@ proc parsecommit {id contents listed} { } } else { if {$comment == {}} { - set headline $line + set headline [string trim $line] } else { append comment "\n" } + if {!$listed} { + # git-rev-list indents the comment by 4 spaces; + # if we got this via git-cat-file, add the indentation + append comment " " + } append comment $line } } From 6c20ff3423e39f9982436953b6b9103f3f8447f8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 22 Jun 2005 19:53:32 +1000 Subject: [PATCH 29/29] Try to assign colors so crossing lines have different colors In particular try hard to give different colors to lines that cross at a corner in one of the lines. --- gitk | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/gitk b/gitk index 1606c38d09..faaffe13a0 100755 --- a/gitk +++ b/gitk @@ -552,6 +552,8 @@ Use and redistribute under the terms of the GNU General Public License proc assigncolor {id} { global commitinfo colormap commcolors colors nextcolor global parents nparents children nchildren + global cornercrossings crossings + if [info exists colormap($id)] return set ncolors [llength $colors] if {$nparents($id) <= 1 && $nchildren($id) == 1} { @@ -563,22 +565,50 @@ proc assigncolor {id} { } } set badcolors {} - foreach child $children($id) { - if {[info exists colormap($child)] - && [lsearch -exact $badcolors $colormap($child)] < 0} { - lappend badcolors $colormap($child) + if {[info exists cornercrossings($id)]} { + foreach x $cornercrossings($id) { + if {[info exists colormap($x)] + && [lsearch -exact $badcolors $colormap($x)] < 0} { + lappend badcolors $colormap($x) + } } - if {[info exists parents($child)]} { - foreach p $parents($child) { - if {[info exists colormap($p)] - && [lsearch -exact $badcolors $colormap($p)] < 0} { - lappend badcolors $colormap($p) + if {[llength $badcolors] >= $ncolors} { + set badcolors {} + } + } + 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 - 1} { + foreach child $children($id) { + if {[info exists colormap($child)] + && [lsearch -exact $badcolors $colormap($child)] < 0} { + lappend badcolors $colormap($child) + } + if {[info exists parents($child)]} { + foreach p $parents($child) { + if {[info exists colormap($p)] + && [lsearch -exact $badcolors $colormap($p)] < 0} { + lappend badcolors $colormap($p) + } } } } - } - if {[llength $badcolors] >= $ncolors} { - set badcolors {} + if {[llength $badcolors] >= $ncolors} { + set badcolors $origbad + } } for {set i 0} {$i <= $ncolors} {incr i} { set c [lindex $colors $nextcolor] @@ -771,6 +801,34 @@ proc updatetodo {level noshortcut} { return 1 } +proc notecrossings {id lo hi corner} { + global oldtodo crossings cornercrossings + + for {set i $lo} {[incr i] < $hi} {} { + set p [lindex $oldtodo $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 drawslants {} { global canv mainline sidelines canvx0 canvy linespc global oldlevel oldtodo todo currentparents dupparents @@ -790,8 +848,10 @@ proc drawslants {} { set xj [expr {$canvx0 + $j * $linespc}] if {$j < $i - 1} { lappend coords [expr $xj + $linespc] $y1 + notecrossings $p $j $i [expr {$j + 1}] } elseif {$j > $i + 1} { lappend coords [expr $xj - $linespc] $y1 + notecrossings $p $i $j [expr {$j - 1}] } if {[lsearch -exact $dupparents $p] >= 0} { # draw a double-width line to indicate the doubled parent