2 # Tcl ignores the next line -*- tcl -*- \
3 exec wish "$0" -- "${1+$@}"
5 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
6 # This program is free software; it may be used, copied, modified
7 # and distributed under the terms of the GNU General Public Licence,
8 # either version 2, or (at your option) any later version.
10 # CVS $Revision: 1.2 $
17 switch -regexp -- $arg {
19 "^-d" { set datemode 1 }
20 "^-b" { set boldnames 1 }
22 puts stderr "unrecognized option $arg"
26 lappend revtreeargs $arg
31 proc getcommits {rargs} {
32 global commits parents cdate nparents children nchildren
37 foreach c [split [eval exec git-rev-tree $rargs] "\n"] {
44 set id [lindex [split $f :] 0]
45 if {![info exists nchildren($id)]} {
56 lappend parents($cid) $id
59 lappend children($id) $cid
67 proc readcommit {id} {
68 global commitinfo commitsummary
76 foreach line [split [exec git-cat-file commit $id] "\n"] {
81 set tag [lindex $line 0]
82 if {$tag == "author"} {
83 set x [expr {[llength $line] - 2}]
84 set audate [lindex $line $x]
85 set auname [lrange $line 1 [expr {$x - 1}]]
86 } elseif {$tag == "committer"} {
87 set x [expr {[llength $line] - 2}]
88 set comdate [lindex $line $x]
89 set comname [lrange $line 1 [expr {$x - 1}]]
102 set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
104 if {$comdate != {}} {
105 set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
107 set commitinfo($id) [list $comment $auname $audate $comname $comdate]
108 set commitsummary($id) [list $headline $auname $audate]
112 global canv linespc charspc ctext
113 panedwindow .ctop -orient vertical
115 set canv .ctop.clist.canv
116 canvas $canv -height [expr 30 * $linespc + 4] -width [expr 90 * $charspc] \
117 -bg white -relief sunk -bd 1 \
118 -yscrollincr $linespc -yscrollcommand ".ctop.clist.csb set"
119 scrollbar .ctop.clist.csb -command "$canv yview" -highlightthickness 0
120 pack .ctop.clist.csb -side right -fill y
121 pack $canv -side bottom -fill both -expand 1
122 .ctop add .ctop.clist
123 #pack .ctop.clist -side top -fill both -expand 1
124 set ctext .ctop.ctext
125 text $ctext -bg white
126 .ctop add .ctop.ctext
127 #pack $ctext -side top -fill x -expand 1
128 pack .ctop -side top -fill both -expand 1
130 bind $canv <1> {selcanvline %x %y}
131 bind $canv <B1-Motion> {selcanvline %x %y}
132 bind $canv <ButtonRelease-4> "$canv yview scroll -5 u"
133 bind $canv <ButtonRelease-5> "$canv yview scroll 5 u"
134 bind $canv <2> "$canv scan mark 0 %y"
135 bind $canv <B2-Motion> "$canv scan dragto 0 %y"
136 bind . <Key-Prior> "$canv yview scroll -1 p"
137 bind . <Key-Next> "$canv yview scroll 1 p"
138 bind . <Key-Delete> "$canv yview scroll -1 p"
139 bind . <Key-BackSpace> "$canv yview scroll -1 p"
140 bind . <Key-space> "$canv yview scroll 1 p"
141 bind . <Key-Up> "$canv yview scroll -1 u"
142 bind . <Key-Down> "$canv yview scroll 1 u"
143 bind . Q "set stopped 1; destroy ."
146 proc truncatetofit {str width font} {
147 if {[font measure $font $str] <= $width} {
151 set bad [string length $str]
153 while {$best < $bad - 1} {
154 set try [expr {int(($best + $bad) / 2)}]
155 set tmp "[string range $str 0 [expr $try-1]]..."
156 if {[font measure $font $tmp] <= $width} {
165 proc drawgraph {start} {
166 global parents children nparents nchildren commits
167 global canv mainfont namefont canvx0 canvy0 linespc namex datex
168 global datemode cdate
169 global lineid linehtag linentag linedtag commitsummary
171 set colors {green red blue magenta darkgrey brown orange}
172 set ncolors [llength $colors]
174 set colormap($start) [lindex $colors 0]
175 foreach id $commits {
176 set ncleft($id) $nchildren($id)
178 set todo [list $start]
181 set linestarty(0) $canvy
186 set nlines [llength $todo]
187 set id [lindex $todo $level]
188 set lineid($lineno) $id
190 foreach p $parents($id) {
191 if {[info exists ncleft($p)]} {
193 lappend actualparents $p
196 if {![info exists commitsummary($id)]} {
199 set x [expr $canvx0 + $level * $linespc]
200 set y2 [expr $canvy + $linespc]
201 if {$linestarty($level) < $canvy} {
202 set t [$canv create line $x $linestarty($level) $x $canvy \
203 -width 2 -fill $colormap($id)]
205 set linestarty($level) $canvy
207 set t [$canv create oval [expr $x - 4] [expr $canvy - 4] \
208 [expr $x + 3] [expr $canvy + 3] \
209 -fill blue -outline black -width 1]
211 set xt [expr $canvx0 + $nlines * $linespc]
212 set headline [lindex $commitsummary($id) 0]
213 set name [lindex $commitsummary($id) 1]
214 set date [lindex $commitsummary($id) 2]
215 set headline [truncatetofit $headline [expr $namex-$xt-$linespc] \
217 set linehtag($lineno) [$canv create text $xt $canvy -anchor w \
218 -text $headline -font $mainfont ]
219 set name [truncatetofit $name [expr $datex-$namex-$linespc] $namefont]
220 set linentag($lineno) [$canv create text $namex $canvy -anchor w \
221 -text $name -font $namefont]
222 set linedtag($lineno) [$canv create text $datex $canvy -anchor w \
223 -text $date -font $mainfont]
224 if {!$datemode && [llength $actualparents] == 1} {
225 set p [lindex $actualparents 0]
226 if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} {
227 set todo [lreplace $todo $level $level $p]
228 set colormap($p) $colormap($id)
230 $canv conf -scrollregion [list 0 0 0 $canvy]
239 for {set i 0} {$i < $nlines} {incr i} {
240 if {[lindex $todo $i] == {}} continue
241 set oldstarty($i) $linestarty($i)
243 lappend lines [list $i [lindex $todo $i]]
247 if {$nullentry >= 0} {
248 set todo [lreplace $todo $nullentry $nullentry]
249 if {$nullentry < $level} {
254 set badcolors [list $colormap($id)]
255 foreach p $actualparents {
256 if {[info exists colormap($p)]} {
257 lappend badcolors $colormap($p)
260 set todo [lreplace $todo $level $level]
261 if {$nullentry > $level} {
265 foreach p $actualparents {
266 set k [lsearch -exact $todo $p]
268 set todo [linsert $todo $i $p]
269 if {$nullentry >= $i} {
272 if {$nparents($id) == 1 && $nparents($p) == 1
273 && $nchildren($p) == 1} {
274 set colormap($p) $colormap($id)
276 for {set j 0} {$j <= $ncolors} {incr j} {
277 if {[incr nextcolor] >= $ncolors} {
280 set c [lindex $colors $nextcolor]
281 # make sure the incoming and outgoing colors differ
282 if {[lsearch -exact $badcolors $c] < 0} break
288 lappend lines [list $oldlevel $p]
291 # choose which one to do next time around
292 set todol [llength $todo]
295 for {set k $todol} {[incr k -1] >= 0} {} {
296 set p [lindex $todo $k]
297 if {$p == {}} continue
298 if {$ncleft($p) == 0} {
300 if {$latest == {} || $cdate($p) > $latest} {
302 set latest $cdate($p)
312 puts "ERROR: none of the pending commits can be done yet:"
320 # If we are reducing, put in a null entry
321 if {$todol < $nlines} {
322 if {$nullentry >= 0} {
325 && [lindex $oldtodo $i] == [lindex $todo $i]} {
338 set todo [linsert $todo $nullentry {}]
349 set dst [lindex $l 1]
350 set j [lsearch -exact $todo $dst]
352 set linestarty($i) $oldstarty($i)
355 set xi [expr {$canvx0 + $i * $linespc}]
356 set xj [expr {$canvx0 + $j * $linespc}]
358 if {$oldstarty($i) < $canvy} {
359 lappend coords $xi $oldstarty($i)
361 lappend coords $xi $canvy
363 lappend coords [expr $xj + $linespc] $canvy
364 } elseif {$j > $i + 1} {
365 lappend coords [expr $xj - $linespc] $canvy
367 lappend coords $xj $y2
368 set t [$canv create line $coords -width 2 -fill $colormap($dst)]
370 if {![info exists linestarty($j)]} {
371 set linestarty($j) $y2
375 $canv conf -scrollregion [list 0 0 0 $canvy]
380 proc selcanvline {x y} {
381 global canv canvy0 ctext linespc selectedline
382 global lineid linehtag linentag linedtag commitinfo
383 set ymax [lindex [$canv cget -scrollregion] 3]
384 set yfrac [lindex [$canv yview] 0]
385 set y [expr {$y + $yfrac * $ymax}]
386 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
390 if {[info exists selectedline] && $selectedline == $l} return
391 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
393 $canv select from $linehtag($l) 0
394 $canv select to $linehtag($l) end
396 $ctext delete 0.0 end
397 set info $commitinfo($id)
398 $ctext insert end "Author: [lindex $info 1] \t[lindex $info 2]\n"
399 $ctext insert end "Committer: [lindex $info 3] \t[lindex $info 4]\n"
400 $ctext insert end "\n"
401 $ctext insert end [lindex $info 0]
404 getcommits $revtreeargs
406 set mainfont {Helvetica 9}
407 set namefont $mainfont
409 lappend namefont bold
411 set linespc [font metrics $mainfont -linespace]
412 set charspc [font measure $mainfont "m"]
414 set canvy0 [expr 3 + 0.5 * $linespc]
415 set canvx0 [expr 3 + 0.5 * $linespc]
416 set namex [expr 45 * $charspc]
417 set datex [expr 75 * $charspc]
422 foreach id $commits {
423 if {$nchildren($id) == 0} {