Use a panedwindow
[git/dkf.git] / gitk
blob801afbca7a988ee64b559454e2bb1bf69a2c696e
1 #!/bin/sh
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 $
12 set datemode 0
13 set boldnames 0
14 set revtreeargs {}
16 foreach arg $argv {
17 switch -regexp -- $arg {
18 "^$" { }
19 "^-d" { set datemode 1 }
20 "^-b" { set boldnames 1 }
21 "^-.*" {
22 puts stderr "unrecognized option $arg"
23 exit 1
25 default {
26 lappend revtreeargs $arg
31 proc getcommits {rargs} {
32 global commits parents cdate nparents children nchildren
33 if {$rargs == {}} {
34 set rargs HEAD
36 set commits {}
37 foreach c [split [eval exec git-rev-tree $rargs] "\n"] {
38 set i 0
39 set cid {}
40 foreach f $c {
41 if {$i == 0} {
42 set d $f
43 } else {
44 set id [lindex [split $f :] 0]
45 if {![info exists nchildren($id)]} {
46 set children($id) {}
47 set nchildren($id) 0
49 if {$i == 1} {
50 set cid $id
51 lappend commits $id
52 set parents($id) {}
53 set cdate($id) $d
54 set nparents($id) 0
55 } else {
56 lappend parents($cid) $id
57 incr nparents($cid)
58 incr nchildren($id)
59 lappend children($id) $cid
62 incr i
67 proc readcommit {id} {
68 global commitinfo commitsummary
69 set inhdr 1
70 set comment {}
71 set headline {}
72 set auname {}
73 set audate {}
74 set comname {}
75 set comdate {}
76 foreach line [split [exec git-cat-file commit $id] "\n"] {
77 if {$inhdr} {
78 if {$line == {}} {
79 set inhdr 0
80 } else {
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}]]
92 } else {
93 if {$comment == {}} {
94 set headline $line
95 } else {
96 append comment "\n"
98 append comment $line
101 if {$audate != {}} {
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]
111 proc makewindow {} {
112 global canv linespc charspc ctext
113 panedwindow .ctop -orient vertical
114 frame .ctop.clist
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} {
148 return $str
150 set best 0
151 set bad [string length $str]
152 set tmp $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} {
157 set best $try
158 } else {
159 set bad $try
162 return $tmp
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]
173 set nextcolor 0
174 set colormap($start) [lindex $colors 0]
175 foreach id $commits {
176 set ncleft($id) $nchildren($id)
178 set todo [list $start]
179 set level 0
180 set canvy $canvy0
181 set linestarty(0) $canvy
182 set nullentry -1
183 set lineno -1
184 while 1 {
185 incr lineno
186 set nlines [llength $todo]
187 set id [lindex $todo $level]
188 set lineid($lineno) $id
189 set actualparents {}
190 foreach p $parents($id) {
191 if {[info exists ncleft($p)]} {
192 incr ncleft($p) -1
193 lappend actualparents $p
196 if {![info exists commitsummary($id)]} {
197 readcommit $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)]
204 $canv lower $t
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]
210 $canv raise $t
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] \
216 $mainfont]
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)
229 set canvy $y2
230 $canv conf -scrollregion [list 0 0 0 $canvy]
231 update
232 continue
236 set oldtodo $todo
237 set oldlevel $level
238 set lines {}
239 for {set i 0} {$i < $nlines} {incr i} {
240 if {[lindex $todo $i] == {}} continue
241 set oldstarty($i) $linestarty($i)
242 if {$i != $level} {
243 lappend lines [list $i [lindex $todo $i]]
246 unset linestarty
247 if {$nullentry >= 0} {
248 set todo [lreplace $todo $nullentry $nullentry]
249 if {$nullentry < $level} {
250 incr level -1
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} {
262 incr nullentry -1
264 set i $level
265 foreach p $actualparents {
266 set k [lsearch -exact $todo $p]
267 if {$k < 0} {
268 set todo [linsert $todo $i $p]
269 if {$nullentry >= $i} {
270 incr nullentry
272 if {$nparents($id) == 1 && $nparents($p) == 1
273 && $nchildren($p) == 1} {
274 set colormap($p) $colormap($id)
275 } else {
276 for {set j 0} {$j <= $ncolors} {incr j} {
277 if {[incr nextcolor] >= $ncolors} {
278 set nextcolor 0
280 set c [lindex $colors $nextcolor]
281 # make sure the incoming and outgoing colors differ
282 if {[lsearch -exact $badcolors $c] < 0} break
284 set colormap($p) $c
285 lappend badcolors $c
288 lappend lines [list $oldlevel $p]
291 # choose which one to do next time around
292 set todol [llength $todo]
293 set level -1
294 set latest {}
295 for {set k $todol} {[incr k -1] >= 0} {} {
296 set p [lindex $todo $k]
297 if {$p == {}} continue
298 if {$ncleft($p) == 0} {
299 if {$datemode} {
300 if {$latest == {} || $cdate($p) > $latest} {
301 set level $k
302 set latest $cdate($p)
304 } else {
305 set level $k
306 break
310 if {$level < 0} {
311 if {$todo != {}} {
312 puts "ERROR: none of the pending commits can be done yet:"
313 foreach p $todo {
314 puts " $p"
317 break
320 # If we are reducing, put in a null entry
321 if {$todol < $nlines} {
322 if {$nullentry >= 0} {
323 set i $nullentry
324 while {$i < $todol
325 && [lindex $oldtodo $i] == [lindex $todo $i]} {
326 incr i
328 } else {
329 set i $oldlevel
330 if {$level >= $i} {
331 incr i
334 if {$i >= $todol} {
335 set nullentry -1
336 } else {
337 set nullentry $i
338 set todo [linsert $todo $nullentry {}]
339 if {$level >= $i} {
340 incr level
343 } else {
344 set nullentry -1
347 foreach l $lines {
348 set i [lindex $l 0]
349 set dst [lindex $l 1]
350 set j [lsearch -exact $todo $dst]
351 if {$i == $j} {
352 set linestarty($i) $oldstarty($i)
353 continue
355 set xi [expr {$canvx0 + $i * $linespc}]
356 set xj [expr {$canvx0 + $j * $linespc}]
357 set coords {}
358 if {$oldstarty($i) < $canvy} {
359 lappend coords $xi $oldstarty($i)
361 lappend coords $xi $canvy
362 if {$j < $i - 1} {
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)]
369 $canv lower $t
370 if {![info exists linestarty($j)]} {
371 set linestarty($j) $y2
374 set canvy $y2
375 $canv conf -scrollregion [list 0 0 0 $canvy]
376 update
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)}]
387 if {$l < 0} {
388 set l 0
390 if {[info exists selectedline] && $selectedline == $l} return
391 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
392 $canv select clear
393 $canv select from $linehtag($l) 0
394 $canv select to $linehtag($l) end
395 set id $lineid($l)
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
408 if {$boldnames} {
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]
419 makewindow
421 set start {}
422 foreach id $commits {
423 if {$nchildren($id) == 0} {
424 set start $id
425 break
428 if {$start != {}} {
429 drawgraph $start