blob: a847ef69c7ae87c9035aff23af359e1832abceea [file] [log] [blame]
Paul Mackerras1db95b02005-05-09 04:08:39 +00001#!/bin/sh
2# Tcl ignores the next line -*- tcl -*- \
Paul Mackerras9e026d32005-09-27 10:29:41 +10003exec wish "$0" -- "$@"
Paul Mackerras1db95b02005-05-09 04:08:39 +00004
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.
9
Junio C Hamano73b6a6c2005-07-28 00:28:44 -070010proc gitdir {} {
11 global env
12 if {[info exists env(GIT_DIR)]} {
13 return $env(GIT_DIR)
14 } else {
15 return ".git"
16 }
17}
18
Paul Mackerras1db95b02005-05-09 04:08:39 +000019proc getcommits {rargs} {
Paul Mackerrase2ede2b2005-06-27 10:37:11 +100020 global commits commfd phase canv mainfont env
Paul Mackerras466e4fd2005-08-10 22:50:28 +100021 global startmsecs nextupdate ncmupdate
Pavel Roskin495473c2005-11-22 23:15:01 -050022 global ctext maincursor textcursor leftover gitencoding
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +000023
Paul Mackerrase2ede2b2005-06-27 10:37:11 +100024 # check that we can find a .git directory somewhere...
Junio C Hamano73b6a6c2005-07-28 00:28:44 -070025 set gitdir [gitdir]
Paul Mackerrase2ede2b2005-06-27 10:37:11 +100026 if {![file isdirectory $gitdir]} {
27 error_popup "Cannot find the git directory \"$gitdir\"."
28 exit 1
29 }
Paul Mackerras1db95b02005-05-09 04:08:39 +000030 set commits {}
Paul Mackerras1d10f362005-05-15 12:55:47 +000031 set phase getcommits
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +000032 set startmsecs [clock clicks -milliseconds]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -080033 set nextupdate [expr {$startmsecs + 100}]
Paul Mackerrasb6645502005-08-11 09:56:23 +100034 set ncmupdate 1
Paul Mackerras2efef4b2005-06-21 10:20:04 +100035 if [catch {
Paul Mackerrasb490a992005-06-22 10:25:38 +100036 set parse_args [concat --default HEAD $rargs]
Paul Mackerras2efef4b2005-06-21 10:20:04 +100037 set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
38 }] {
Paul Mackerrasb490a992005-06-22 10:25:38 +100039 # if git-rev-parse failed for some reason...
Paul Mackerras2efef4b2005-06-21 10:20:04 +100040 if {$rargs == {}} {
41 set rargs HEAD
42 }
Paul Mackerrasb490a992005-06-22 10:25:38 +100043 set parsed_args $rargs
Paul Mackerras2efef4b2005-06-21 10:20:04 +100044 }
45 if [catch {
Paul Mackerrase5ea7012005-08-18 20:40:39 +100046 set commfd [open "|git-rev-list --header --topo-order --parents $parsed_args" r]
Paul Mackerras2efef4b2005-06-21 10:20:04 +100047 } err] {
Paul Mackerrascfb45632005-05-31 12:14:42 +000048 puts stderr "Error executing git-rev-list: $err"
Paul Mackerras1d10f362005-05-15 12:55:47 +000049 exit 1
50 }
Paul Mackerrasb490a992005-06-22 10:25:38 +100051 set leftover {}
Pavel Roskin495473c2005-11-22 23:15:01 -050052 fconfigure $commfd -blocking 0 -translation lf -encoding $gitencoding
Paul Mackerras466e4fd2005-08-10 22:50:28 +100053 fileevent $commfd readable [list getcommitlines $commfd]
Paul Mackerras1d10f362005-05-15 12:55:47 +000054 $canv delete all
55 $canv create text 3 3 -anchor nw -text "Reading commits..." \
56 -font $mainfont -tags textitems
Paul Mackerrasea13cba2005-06-16 10:54:04 +000057 . config -cursor watch
Paul Mackerras94a2eed2005-08-07 15:27:57 +100058 settextcursor watch
Paul Mackerras1d10f362005-05-15 12:55:47 +000059}
60
Paul Mackerrasb490a992005-06-22 10:25:38 +100061proc getcommitlines {commfd} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +100062 global commits parents cdate children
Paul Mackerras232475d2005-11-15 10:34:03 +110063 global commitlisted phase nextupdate
Paul Mackerrasb490a992005-06-22 10:25:38 +100064 global stopped redisplaying leftover
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +000065
Paul Mackerrasb490a992005-06-22 10:25:38 +100066 set stuff [read $commfd]
67 if {$stuff == {}} {
Paul Mackerras1d10f362005-05-15 12:55:47 +000068 if {![eof $commfd]} return
Paul Mackerrasf0654862005-07-18 14:29:03 -040069 # set it blocking so we wait for the process to terminate
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +000070 fconfigure $commfd -blocking 1
Paul Mackerras1d10f362005-05-15 12:55:47 +000071 if {![catch {close $commfd} err]} {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +000072 after idle finishcommits
Paul Mackerras1d10f362005-05-15 12:55:47 +000073 return
74 }
Paul Mackerras9a40c502005-05-12 23:46:16 +000075 if {[string range $err 0 4] == "usage"} {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +000076 set err \
Jeff Hobbs2ed49d52005-11-22 17:39:53 -080077 "Gitk: error reading commits: bad arguments to git-rev-list.\
78 (Note: arguments to gitk are passed to git-rev-list\
79 to allow selection of commits to be displayed.)"
Paul Mackerras9a40c502005-05-12 23:46:16 +000080 } else {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +000081 set err "Error reading commits: $err"
Paul Mackerras9a40c502005-05-12 23:46:16 +000082 }
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +000083 error_popup $err
Paul Mackerras1d10f362005-05-15 12:55:47 +000084 exit 1
Paul Mackerras9a40c502005-05-12 23:46:16 +000085 }
Paul Mackerrasb490a992005-06-22 10:25:38 +100086 set start 0
87 while 1 {
88 set i [string first "\0" $stuff $start]
89 if {$i < 0} {
Paul Mackerras7e952e72005-06-27 20:04:26 +100090 append leftover [string range $stuff $start end]
Paul Mackerrasb490a992005-06-22 10:25:38 +100091 return
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +000092 }
Paul Mackerrasb490a992005-06-22 10:25:38 +100093 set cmit [string range $stuff $start [expr {$i - 1}]]
94 if {$start == 0} {
95 set cmit "$leftover$cmit"
Paul Mackerras7e952e72005-06-27 20:04:26 +100096 set leftover {}
Paul Mackerrasb490a992005-06-22 10:25:38 +100097 }
98 set start [expr {$i + 1}]
Paul Mackerrase5ea7012005-08-18 20:40:39 +100099 set j [string first "\n" $cmit]
100 set ok 0
101 if {$j >= 0} {
102 set ids [string range $cmit 0 [expr {$j - 1}]]
103 set ok 1
104 foreach id $ids {
105 if {![regexp {^[0-9a-f]{40}$} $id]} {
106 set ok 0
107 break
108 }
109 }
110 }
111 if {!$ok} {
Paul Mackerras7e952e72005-06-27 20:04:26 +1000112 set shortcmit $cmit
113 if {[string length $shortcmit] > 80} {
114 set shortcmit "[string range $shortcmit 0 80]..."
115 }
116 error_popup "Can't parse git-rev-list output: {$shortcmit}"
Paul Mackerrasb490a992005-06-22 10:25:38 +1000117 exit 1
118 }
Paul Mackerrase5ea7012005-08-18 20:40:39 +1000119 set id [lindex $ids 0]
120 set olds [lrange $ids 1 end]
121 set cmit [string range $cmit [expr {$j + 1}] end]
Paul Mackerrasb490a992005-06-22 10:25:38 +1000122 lappend commits $id
123 set commitlisted($id) 1
Paul Mackerrase5ea7012005-08-18 20:40:39 +1000124 parsecommit $id $cmit 1 [lrange $ids 1 end]
Paul Mackerrasb490a992005-06-22 10:25:38 +1000125 drawcommit $id
Paul Mackerrasb6645502005-08-11 09:56:23 +1000126 if {[clock clicks -milliseconds] >= $nextupdate} {
127 doupdate 1
Paul Mackerrasb490a992005-06-22 10:25:38 +1000128 }
129 while {$redisplaying} {
130 set redisplaying 0
131 if {$stopped == 1} {
132 set stopped 0
133 set phase "getcommits"
134 foreach id $commits {
135 drawcommit $id
136 if {$stopped} break
Paul Mackerrasb6645502005-08-11 09:56:23 +1000137 if {[clock clicks -milliseconds] >= $nextupdate} {
138 doupdate 1
Paul Mackerrasb490a992005-06-22 10:25:38 +1000139 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000140 }
141 }
142 }
143 }
Paul Mackerrascfb45632005-05-31 12:14:42 +0000144}
145
Paul Mackerrasb6645502005-08-11 09:56:23 +1000146proc doupdate {reading} {
147 global commfd nextupdate numcommits ncmupdate
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000148
Paul Mackerrasb6645502005-08-11 09:56:23 +1000149 if {$reading} {
150 fileevent $commfd readable {}
151 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000152 update
Paul Mackerrasb6645502005-08-11 09:56:23 +1000153 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
154 if {$numcommits < 100} {
155 set ncmupdate [expr {$numcommits + 1}]
156 } elseif {$numcommits < 10000} {
157 set ncmupdate [expr {$numcommits + 10}]
158 } else {
159 set ncmupdate [expr {$numcommits + 100}]
160 }
161 if {$reading} {
162 fileevent $commfd readable [list getcommitlines $commfd]
163 }
Paul Mackerras1db95b02005-05-09 04:08:39 +0000164}
165
166proc readcommit {id} {
Paul Mackerrasb490a992005-06-22 10:25:38 +1000167 if [catch {set contents [exec git-cat-file commit $id]}] return
Paul Mackerrase5ea7012005-08-18 20:40:39 +1000168 parsecommit $id $contents 0 {}
Paul Mackerrasb490a992005-06-22 10:25:38 +1000169}
170
Paul Mackerrase5ea7012005-08-18 20:40:39 +1000171proc parsecommit {id contents listed olds} {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000172 global commitinfo children nchildren parents nparents cdate ncleft
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000173
Paul Mackerras1db95b02005-05-09 04:08:39 +0000174 set inhdr 1
175 set comment {}
176 set headline {}
177 set auname {}
178 set audate {}
179 set comname {}
180 set comdate {}
Paul Mackerrascfb45632005-05-31 12:14:42 +0000181 if {![info exists nchildren($id)]} {
182 set children($id) {}
183 set nchildren($id) 0
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000184 set ncleft($id) 0
Paul Mackerrascfb45632005-05-31 12:14:42 +0000185 }
Paul Mackerrase5ea7012005-08-18 20:40:39 +1000186 set parents($id) $olds
187 set nparents($id) [llength $olds]
188 foreach p $olds {
189 if {![info exists nchildren($p)]} {
190 set children($p) [list $id]
191 set nchildren($p) 1
192 set ncleft($p) 1
193 } elseif {[lsearch -exact $children($p) $id] < 0} {
194 lappend children($p) $id
195 incr nchildren($p)
196 incr ncleft($p)
Paul Mackerras244edd12005-08-17 21:27:55 +1000197 }
198 }
Paul Mackerras232475d2005-11-15 10:34:03 +1100199 set hdrend [string first "\n\n" $contents]
200 if {$hdrend < 0} {
201 # should never happen...
202 set hdrend [string length $contents]
203 }
204 set header [string range $contents 0 [expr {$hdrend - 1}]]
205 set comment [string range $contents [expr {$hdrend + 2}] end]
206 foreach line [split $header "\n"] {
207 set tag [lindex $line 0]
208 if {$tag == "author"} {
209 set audate [lindex $line end-1]
210 set auname [lrange $line 1 end-2]
211 } elseif {$tag == "committer"} {
212 set comdate [lindex $line end-1]
213 set comname [lrange $line 1 end-2]
Paul Mackerras1db95b02005-05-09 04:08:39 +0000214 }
215 }
Paul Mackerras232475d2005-11-15 10:34:03 +1100216 set headline {}
217 # take the first line of the comment as the headline
218 set i [string first "\n" $comment]
219 if {$i >= 0} {
220 set headline [string trim [string range $comment 0 $i]]
Paul Mackerrasf6e28692005-11-20 23:08:22 +1100221 } else {
222 set headline $comment
Paul Mackerras232475d2005-11-15 10:34:03 +1100223 }
224 if {!$listed} {
225 # git-rev-list indents the comment by 4 spaces;
226 # if we got this via git-cat-file, add the indentation
227 set newcomment {}
228 foreach line [split $comment "\n"] {
229 append newcomment " "
230 append newcomment $line
Paul Mackerrasf6e28692005-11-20 23:08:22 +1100231 append newcomment "\n"
Paul Mackerras232475d2005-11-15 10:34:03 +1100232 }
233 set comment $newcomment
Paul Mackerras1db95b02005-05-09 04:08:39 +0000234 }
235 if {$comdate != {}} {
Paul Mackerrascfb45632005-05-31 12:14:42 +0000236 set cdate($id) $comdate
Paul Mackerras1db95b02005-05-09 04:08:39 +0000237 }
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000238 set commitinfo($id) [list $headline $auname $audate \
239 $comname $comdate $comment]
Paul Mackerras1db95b02005-05-09 04:08:39 +0000240}
241
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000242proc readrefs {} {
Paul Mackerras106288c2005-08-19 23:11:39 +1000243 global tagids idtags headids idheads tagcontents
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000244 global otherrefids idotherrefs
245
Junio C Hamano36a7cad2005-11-18 23:54:17 -0800246 set refd [open [list | git-ls-remote [gitdir]] r]
247 while {0 <= [set n [gets $refd line]]} {
248 if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
249 match id path]} {
250 continue
251 }
252 if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
253 set type others
254 set name $path
255 }
256 if {$type == "tags"} {
257 set tagids($name) $id
258 lappend idtags($id) $name
259 set obj {}
260 set type {}
261 set tag {}
262 catch {
263 set commit [exec git-rev-parse "$id^0"]
264 if {"$commit" != "$id"} {
265 set tagids($name) $commit
266 lappend idtags($commit) $name
267 }
268 }
269 catch {
270 set tagcontents($name) [exec git-cat-file tag "$id"]
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000271 }
Junio C Hamano36a7cad2005-11-18 23:54:17 -0800272 } elseif { $type == "heads" } {
273 set headids($name) $id
274 lappend idheads($id) $name
275 } else {
276 set otherrefids($name) $id
277 lappend idotherrefs($id) $name
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000278 }
279 }
Junio C Hamano36a7cad2005-11-18 23:54:17 -0800280 close $refd
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000281}
282
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000283proc error_popup msg {
284 set w .error
285 toplevel $w
286 wm transient $w .
287 message $w.m -text $msg -justify center -aspect 400
288 pack $w.m -side top -fill x -padx 20 -pady 20
289 button $w.ok -text OK -command "destroy $w"
290 pack $w.ok -side bottom -fill x
291 bind $w <Visibility> "grab $w; focus $w"
292 tkwait window $w
293}
294
Paul Mackerras1db95b02005-05-09 04:08:39 +0000295proc makewindow {} {
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000296 global canv canv2 canv3 linespc charspc ctext cflist textfont
Paul Mackerrasb74fd572005-07-16 07:46:13 -0400297 global findtype findtypemenu findloc findstring fstring geometry
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000298 global entries sha1entry sha1string sha1but
Paul Mackerras94a2eed2005-08-07 15:27:57 +1000299 global maincursor textcursor curtextcursor
Paul Mackerras712fcc02005-11-30 09:28:16 +1100300 global rowctxmenu mergemax
Paul Mackerras9a40c502005-05-12 23:46:16 +0000301
302 menu .bar
303 .bar add cascade -label "File" -menu .bar.file
304 menu .bar.file
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000305 .bar.file add command -label "Reread references" -command rereadrefs
Paul Mackerras1d10f362005-05-15 12:55:47 +0000306 .bar.file add command -label "Quit" -command doquit
Paul Mackerras712fcc02005-11-30 09:28:16 +1100307 menu .bar.edit
308 .bar add cascade -label "Edit" -menu .bar.edit
309 .bar.edit add command -label "Preferences" -command doprefs
Paul Mackerras9a40c502005-05-12 23:46:16 +0000310 menu .bar.help
311 .bar add cascade -label "Help" -menu .bar.help
312 .bar.help add command -label "About gitk" -command about
313 . configure -menu .bar
314
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000315 if {![info exists geometry(canv1)]} {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800316 set geometry(canv1) [expr {45 * $charspc}]
317 set geometry(canv2) [expr {30 * $charspc}]
318 set geometry(canv3) [expr {15 * $charspc}]
319 set geometry(canvh) [expr {25 * $linespc + 4}]
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000320 set geometry(ctextw) 80
321 set geometry(ctexth) 30
322 set geometry(cflistw) 30
323 }
Paul Mackerras0327d272005-05-10 00:23:42 +0000324 panedwindow .ctop -orient vertical
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000325 if {[info exists geometry(width)]} {
326 .ctop conf -width $geometry(width) -height $geometry(height)
Paul Mackerras17386062005-05-18 22:51:00 +0000327 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
328 set geometry(ctexth) [expr {($texth - 8) /
329 [font metrics $textfont -linespace]}]
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000330 }
Paul Mackerras98f350e2005-05-15 05:56:51 +0000331 frame .ctop.top
332 frame .ctop.top.bar
333 pack .ctop.top.bar -side bottom -fill x
334 set cscroll .ctop.top.csb
335 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
336 pack $cscroll -side right -fill y
337 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
338 pack .ctop.top.clist -side top -fill both -expand 1
339 .ctop add .ctop.top
340 set canv .ctop.top.clist.canv
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000341 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
Paul Mackerrasb5721c72005-05-10 12:08:22 +0000342 -bg white -bd 0 \
343 -yscrollincr $linespc -yscrollcommand "$cscroll set"
Paul Mackerras98f350e2005-05-15 05:56:51 +0000344 .ctop.top.clist add $canv
345 set canv2 .ctop.top.clist.canv2
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000346 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
Paul Mackerrasb5721c72005-05-10 12:08:22 +0000347 -bg white -bd 0 -yscrollincr $linespc
Paul Mackerras98f350e2005-05-15 05:56:51 +0000348 .ctop.top.clist add $canv2
349 set canv3 .ctop.top.clist.canv3
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000350 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
Paul Mackerrasb5721c72005-05-10 12:08:22 +0000351 -bg white -bd 0 -yscrollincr $linespc
Paul Mackerras98f350e2005-05-15 05:56:51 +0000352 .ctop.top.clist add $canv3
Paul Mackerras43bddeb2005-05-15 23:19:18 +0000353 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
Paul Mackerras98f350e2005-05-15 05:56:51 +0000354
355 set sha1entry .ctop.top.bar.sha1
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000356 set entries $sha1entry
357 set sha1but .ctop.top.bar.sha1label
358 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
359 -command gotocommit -width 8
360 $sha1but conf -disabledforeground [$sha1but cget -foreground]
Paul Mackerras98f350e2005-05-15 05:56:51 +0000361 pack .ctop.top.bar.sha1label -side left
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000362 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
363 trace add variable sha1string write sha1change
Paul Mackerras98f350e2005-05-15 05:56:51 +0000364 pack $sha1entry -side left -pady 2
Paul Mackerrasd6982062005-08-06 22:06:06 +1000365
366 image create bitmap bm-left -data {
367 #define left_width 16
368 #define left_height 16
369 static unsigned char left_bits[] = {
370 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
371 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
372 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
373 }
374 image create bitmap bm-right -data {
375 #define right_width 16
376 #define right_height 16
377 static unsigned char right_bits[] = {
378 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
379 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
380 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
381 }
382 button .ctop.top.bar.leftbut -image bm-left -command goback \
383 -state disabled -width 26
384 pack .ctop.top.bar.leftbut -side left -fill y
385 button .ctop.top.bar.rightbut -image bm-right -command goforw \
386 -state disabled -width 26
387 pack .ctop.top.bar.rightbut -side left -fill y
388
Paul Mackerras98f350e2005-05-15 05:56:51 +0000389 button .ctop.top.bar.findbut -text "Find" -command dofind
390 pack .ctop.top.bar.findbut -side left
391 set findstring {}
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000392 set fstring .ctop.top.bar.findstring
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000393 lappend entries $fstring
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000394 entry $fstring -width 30 -font $textfont -textvariable findstring
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000395 pack $fstring -side left -expand 1 -fill x
Paul Mackerras98f350e2005-05-15 05:56:51 +0000396 set findtype Exact
Paul Mackerrasb74fd572005-07-16 07:46:13 -0400397 set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
398 findtype Exact IgnCase Regexp]
Paul Mackerras98f350e2005-05-15 05:56:51 +0000399 set findloc "All fields"
400 tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
Paul Mackerrasb74fd572005-07-16 07:46:13 -0400401 Comments Author Committer Files Pickaxe
Paul Mackerras98f350e2005-05-15 05:56:51 +0000402 pack .ctop.top.bar.findloc -side right
403 pack .ctop.top.bar.findtype -side right
Paul Mackerrasb74fd572005-07-16 07:46:13 -0400404 # for making sure type==Exact whenever loc==Pickaxe
405 trace add variable findloc write findlocchange
Paul Mackerrasb5721c72005-05-10 12:08:22 +0000406
Paul Mackerras5ad588d2005-05-10 01:02:55 +0000407 panedwindow .ctop.cdet -orient horizontal
408 .ctop add .ctop.cdet
Paul Mackerrasd2610d12005-05-11 00:45:38 +0000409 frame .ctop.cdet.left
410 set ctext .ctop.cdet.left.ctext
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000411 text $ctext -bg white -state disabled -font $textfont \
412 -width $geometry(ctextw) -height $geometry(ctexth) \
Linus Torvaldsb1ba39e2005-08-08 20:04:20 -0700413 -yscrollcommand ".ctop.cdet.left.sb set" -wrap none
Paul Mackerrasd2610d12005-05-11 00:45:38 +0000414 scrollbar .ctop.cdet.left.sb -command "$ctext yview"
415 pack .ctop.cdet.left.sb -side right -fill y
416 pack $ctext -side left -fill both -expand 1
417 .ctop.cdet add .ctop.cdet.left
418
Paul Mackerrasf0654862005-07-18 14:29:03 -0400419 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
Paul Mackerras712fcc02005-11-30 09:28:16 +1100420 $ctext tag conf hunksep -fore blue
421 $ctext tag conf d0 -fore red
422 $ctext tag conf d1 -fore "#00a000"
423 $ctext tag conf m0 -fore red
424 $ctext tag conf m1 -fore blue
425 $ctext tag conf m2 -fore green
426 $ctext tag conf m3 -fore purple
427 $ctext tag conf m4 -fore brown
428 $ctext tag conf mmax -fore darkgrey
429 set mergemax 5
430 $ctext tag conf mresult -font [concat $textfont bold]
431 $ctext tag conf msep -font [concat $textfont bold]
432 $ctext tag conf found -back yellow
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000433
Paul Mackerrasd2610d12005-05-11 00:45:38 +0000434 frame .ctop.cdet.right
435 set cflist .ctop.cdet.right.cfiles
Paul Mackerras17386062005-05-18 22:51:00 +0000436 listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
Paul Mackerrasd2610d12005-05-11 00:45:38 +0000437 -yscrollcommand ".ctop.cdet.right.sb set"
438 scrollbar .ctop.cdet.right.sb -command "$cflist yview"
439 pack .ctop.cdet.right.sb -side right -fill y
440 pack $cflist -side left -fill both -expand 1
441 .ctop.cdet add .ctop.cdet.right
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000442 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
Paul Mackerrasd2610d12005-05-11 00:45:38 +0000443
Paul Mackerras0327d272005-05-10 00:23:42 +0000444 pack .ctop -side top -fill both -expand 1
Paul Mackerras1db95b02005-05-09 04:08:39 +0000445
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000446 bindall <1> {selcanvline %W %x %y}
447 #bindall <B1-Motion> {selcanvline %W %x %y}
Paul Mackerrascfb45632005-05-31 12:14:42 +0000448 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
449 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
Paul Mackerrasb5721c72005-05-10 12:08:22 +0000450 bindall <2> "allcanvs scan mark 0 %y"
451 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
Paul Mackerras17386062005-05-18 22:51:00 +0000452 bind . <Key-Up> "selnextline -1"
453 bind . <Key-Down> "selnextline 1"
Robert Suetterlin6e2dda32005-09-22 10:07:36 +1000454 bind . <Key-Right> "goforw"
455 bind . <Key-Left> "goback"
Paul Mackerrascfb45632005-05-31 12:14:42 +0000456 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
457 bind . <Key-Next> "allcanvs yview scroll 1 pages"
458 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
459 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
460 bindkey <Key-space> "$ctext yview scroll 1 pages"
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000461 bindkey p "selnextline -1"
462 bindkey n "selnextline 1"
Robert Suetterlin6e2dda32005-09-22 10:07:36 +1000463 bindkey z "goback"
464 bindkey x "goforw"
465 bindkey i "selnextline -1"
466 bindkey k "selnextline 1"
467 bindkey j "goback"
468 bindkey l "goforw"
Paul Mackerrascfb45632005-05-31 12:14:42 +0000469 bindkey b "$ctext yview scroll -1 pages"
470 bindkey d "$ctext yview scroll 18 units"
471 bindkey u "$ctext yview scroll -18 units"
Paul Mackerrasb74fd572005-07-16 07:46:13 -0400472 bindkey / {findnext 1}
473 bindkey <Key-Return> {findnext 0}
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000474 bindkey ? findprev
Paul Mackerras39ad8572005-05-19 12:35:53 +0000475 bindkey f nextfile
Paul Mackerras1d10f362005-05-15 12:55:47 +0000476 bind . <Control-q> doquit
Paul Mackerras98f350e2005-05-15 05:56:51 +0000477 bind . <Control-f> dofind
Paul Mackerrasb74fd572005-07-16 07:46:13 -0400478 bind . <Control-g> {findnext 0}
Paul Mackerras98f350e2005-05-15 05:56:51 +0000479 bind . <Control-r> findprev
Paul Mackerras1d10f362005-05-15 12:55:47 +0000480 bind . <Control-equal> {incrfont 1}
481 bind . <Control-KP_Add> {incrfont 1}
482 bind . <Control-minus> {incrfont -1}
483 bind . <Control-KP_Subtract> {incrfont -1}
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000484 bind $cflist <<ListboxSelect>> listboxsel
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000485 bind . <Destroy> {savestuff %W}
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000486 bind . <Button-1> "click %W"
Paul Mackerras17386062005-05-18 22:51:00 +0000487 bind $fstring <Key-Return> dofind
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000488 bind $sha1entry <Key-Return> gotocommit
Paul Mackerrasee3dc722005-06-25 16:37:13 +1000489 bind $sha1entry <<PasteSelection>> clearsha1
Paul Mackerrasea13cba2005-06-16 10:54:04 +0000490
491 set maincursor [. cget -cursor]
492 set textcursor [$ctext cget -cursor]
Paul Mackerras94a2eed2005-08-07 15:27:57 +1000493 set curtextcursor $textcursor
Paul Mackerras84ba7342005-06-17 00:12:26 +0000494
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000495 set rowctxmenu .rowctxmenu
496 menu $rowctxmenu -tearoff 0
497 $rowctxmenu add command -label "Diff this -> selected" \
498 -command {diffvssel 0}
499 $rowctxmenu add command -label "Diff selected -> this" \
500 -command {diffvssel 1}
Paul Mackerras74daedb2005-06-27 19:27:32 +1000501 $rowctxmenu add command -label "Make patch" -command mkpatch
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000502 $rowctxmenu add command -label "Create tag" -command mktag
Paul Mackerras4a2139f2005-06-29 09:47:48 +1000503 $rowctxmenu add command -label "Write commit to file" -command writecommit
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000504}
505
506# when we make a key binding for the toplevel, make sure
507# it doesn't get triggered when that key is pressed in the
508# find string entry widget.
509proc bindkey {ev script} {
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000510 global entries
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000511 bind . $ev $script
512 set escript [bind Entry $ev]
513 if {$escript == {}} {
514 set escript [bind Entry <Key>]
515 }
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000516 foreach e $entries {
517 bind $e $ev "$escript; break"
518 }
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000519}
520
521# set the focus back to the toplevel for any click outside
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000522# the entry widgets
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000523proc click {w} {
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000524 global entries
525 foreach e $entries {
526 if {$w == $e} return
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000527 }
Paul Mackerras887fe3c2005-05-21 07:35:37 +0000528 focus .
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000529}
530
531proc savestuff {w} {
532 global canv canv2 canv3 ctext cflist mainfont textfont
Paul Mackerras712fcc02005-11-30 09:28:16 +1100533 global stuffsaved findmergefiles maxgraphpct
Paul Mackerras04c13d32005-08-19 10:22:24 +1000534 global maxwidth
Paul Mackerras4ef17532005-07-27 22:16:51 -0500535
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000536 if {$stuffsaved} return
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000537 if {![winfo viewable .]} return
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000538 catch {
539 set f [open "~/.gitk-new" w]
Paul Mackerrasf0654862005-07-18 14:29:03 -0400540 puts $f [list set mainfont $mainfont]
541 puts $f [list set textfont $textfont]
542 puts $f [list set findmergefiles $findmergefiles]
Paul Mackerras8d858d12005-08-05 09:52:16 +1000543 puts $f [list set maxgraphpct $maxgraphpct]
Paul Mackerras04c13d32005-08-19 10:22:24 +1000544 puts $f [list set maxwidth $maxwidth]
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000545 puts $f "set geometry(width) [winfo width .ctop]"
546 puts $f "set geometry(height) [winfo height .ctop]"
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800547 puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
548 puts $f "set geometry(canv2) [expr {[winfo width $canv2]-2}]"
549 puts $f "set geometry(canv3) [expr {[winfo width $canv3]-2}]"
550 puts $f "set geometry(canvh) [expr {[winfo height $canv]-2}]"
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000551 set wid [expr {([winfo width $ctext] - 8) \
552 / [font measure $textfont "0"]}]
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000553 puts $f "set geometry(ctextw) $wid"
Paul Mackerras0fba86b2005-05-16 23:54:58 +0000554 set wid [expr {([winfo width $cflist] - 11) \
555 / [font measure [$cflist cget -font] "0"]}]
556 puts $f "set geometry(cflistw) $wid"
557 close $f
558 file rename -force "~/.gitk-new" "~/.gitk"
559 }
560 set stuffsaved 1
Paul Mackerras1db95b02005-05-09 04:08:39 +0000561}
562
Paul Mackerras43bddeb2005-05-15 23:19:18 +0000563proc resizeclistpanes {win w} {
564 global oldwidth
565 if [info exists oldwidth($win)] {
566 set s0 [$win sash coord 0]
567 set s1 [$win sash coord 1]
568 if {$w < 60} {
569 set sash0 [expr {int($w/2 - 2)}]
570 set sash1 [expr {int($w*5/6 - 2)}]
571 } else {
572 set factor [expr {1.0 * $w / $oldwidth($win)}]
573 set sash0 [expr {int($factor * [lindex $s0 0])}]
574 set sash1 [expr {int($factor * [lindex $s1 0])}]
575 if {$sash0 < 30} {
576 set sash0 30
577 }
578 if {$sash1 < $sash0 + 20} {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800579 set sash1 [expr {$sash0 + 20}]
Paul Mackerras43bddeb2005-05-15 23:19:18 +0000580 }
581 if {$sash1 > $w - 10} {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800582 set sash1 [expr {$w - 10}]
Paul Mackerras43bddeb2005-05-15 23:19:18 +0000583 if {$sash0 > $sash1 - 20} {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800584 set sash0 [expr {$sash1 - 20}]
Paul Mackerras43bddeb2005-05-15 23:19:18 +0000585 }
586 }
587 }
588 $win sash place 0 $sash0 [lindex $s0 1]
589 $win sash place 1 $sash1 [lindex $s1 1]
590 }
591 set oldwidth($win) $w
592}
593
594proc resizecdetpanes {win w} {
595 global oldwidth
596 if [info exists oldwidth($win)] {
597 set s0 [$win sash coord 0]
598 if {$w < 60} {
599 set sash0 [expr {int($w*3/4 - 2)}]
600 } else {
601 set factor [expr {1.0 * $w / $oldwidth($win)}]
602 set sash0 [expr {int($factor * [lindex $s0 0])}]
603 if {$sash0 < 45} {
604 set sash0 45
605 }
606 if {$sash0 > $w - 15} {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800607 set sash0 [expr {$w - 15}]
Paul Mackerras43bddeb2005-05-15 23:19:18 +0000608 }
609 }
610 $win sash place 0 $sash0 [lindex $s0 1]
611 }
612 set oldwidth($win) $w
613}
614
Paul Mackerrasb5721c72005-05-10 12:08:22 +0000615proc allcanvs args {
616 global canv canv2 canv3
617 eval $canv $args
618 eval $canv2 $args
619 eval $canv3 $args
620}
621
622proc bindall {event action} {
623 global canv canv2 canv3
624 bind $canv $event $action
625 bind $canv2 $event $action
626 bind $canv3 $event $action
627}
628
Paul Mackerras9a40c502005-05-12 23:46:16 +0000629proc about {} {
630 set w .about
631 if {[winfo exists $w]} {
632 raise $w
633 return
634 }
635 toplevel $w
636 wm title $w "About gitk"
637 message $w.m -text {
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000638Gitk version 1.2
Paul Mackerras9a40c502005-05-12 23:46:16 +0000639
640Copyright © 2005 Paul Mackerras
641
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000642Use and redistribute under the terms of the GNU General Public License} \
Paul Mackerras9a40c502005-05-12 23:46:16 +0000643 -justify center -aspect 400
644 pack $w.m -side top -fill x -padx 20 -pady 20
645 button $w.ok -text Close -command "destroy $w"
646 pack $w.ok -side bottom
647}
648
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000649proc assigncolor {id} {
Paul Mackerras232475d2005-11-15 10:34:03 +1100650 global colormap commcolors colors nextcolor
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000651 global parents nparents children nchildren
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000652 global cornercrossings crossings
653
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000654 if [info exists colormap($id)] return
655 set ncolors [llength $colors]
Paul Mackerrasb490a992005-06-22 10:25:38 +1000656 if {$nparents($id) <= 1 && $nchildren($id) == 1} {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000657 set child [lindex $children($id) 0]
658 if {[info exists colormap($child)]
659 && $nparents($child) == 1} {
660 set colormap($id) $colormap($child)
661 return
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000662 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000663 }
664 set badcolors {}
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000665 if {[info exists cornercrossings($id)]} {
666 foreach x $cornercrossings($id) {
667 if {[info exists colormap($x)]
668 && [lsearch -exact $badcolors $colormap($x)] < 0} {
669 lappend badcolors $colormap($x)
670 }
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000671 }
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000672 if {[llength $badcolors] >= $ncolors} {
673 set badcolors {}
674 }
675 }
676 set origbad $badcolors
677 if {[llength $badcolors] < $ncolors - 1} {
678 if {[info exists crossings($id)]} {
679 foreach x $crossings($id) {
680 if {[info exists colormap($x)]
681 && [lsearch -exact $badcolors $colormap($x)] < 0} {
682 lappend badcolors $colormap($x)
683 }
684 }
685 if {[llength $badcolors] >= $ncolors} {
686 set badcolors $origbad
687 }
688 }
689 set origbad $badcolors
690 }
691 if {[llength $badcolors] < $ncolors - 1} {
692 foreach child $children($id) {
693 if {[info exists colormap($child)]
694 && [lsearch -exact $badcolors $colormap($child)] < 0} {
695 lappend badcolors $colormap($child)
696 }
697 if {[info exists parents($child)]} {
698 foreach p $parents($child) {
699 if {[info exists colormap($p)]
700 && [lsearch -exact $badcolors $colormap($p)] < 0} {
701 lappend badcolors $colormap($p)
702 }
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000703 }
704 }
705 }
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000706 if {[llength $badcolors] >= $ncolors} {
707 set badcolors $origbad
708 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000709 }
710 for {set i 0} {$i <= $ncolors} {incr i} {
711 set c [lindex $colors $nextcolor]
712 if {[incr nextcolor] >= $ncolors} {
713 set nextcolor 0
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000714 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000715 if {[lsearch -exact $badcolors $c]} break
716 }
717 set colormap($id) $c
718}
719
720proc initgraph {} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000721 global canvy canvy0 lineno numcommits nextcolor linespc
722 global mainline mainlinearrow sidelines
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000723 global nchildren ncleft
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000724 global displist nhyperspace
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000725
726 allcanvs delete all
727 set nextcolor 0
728 set canvy $canvy0
729 set lineno -1
730 set numcommits 0
Paul Mackerrasb490a992005-06-22 10:25:38 +1000731 catch {unset mainline}
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000732 catch {unset mainlinearrow}
Paul Mackerrasb490a992005-06-22 10:25:38 +1000733 catch {unset sidelines}
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000734 foreach id [array names nchildren] {
735 set ncleft($id) $nchildren($id)
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000736 }
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000737 set displist {}
738 set nhyperspace 0
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000739}
740
Paul Mackerrasa823a912005-06-21 10:01:38 +1000741proc bindline {t id} {
742 global canv
743
Paul Mackerrasa823a912005-06-21 10:01:38 +1000744 $canv bind $t <Enter> "lineenter %x %y $id"
745 $canv bind $t <Motion> "linemotion %x %y $id"
746 $canv bind $t <Leave> "lineleave $id"
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +1000747 $canv bind $t <Button-1> "lineclick %x %y $id 1"
Paul Mackerrasa823a912005-06-21 10:01:38 +1000748}
749
Paul Mackerras232475d2005-11-15 10:34:03 +1100750proc drawlines {id xtra delold} {
Paul Mackerras9843c302005-08-30 10:57:11 +1000751 global mainline mainlinearrow sidelines lthickness colormap canv
752
Paul Mackerras232475d2005-11-15 10:34:03 +1100753 if {$delold} {
754 $canv delete lines.$id
755 }
Paul Mackerras9843c302005-08-30 10:57:11 +1000756 if {[info exists mainline($id)]} {
757 set t [$canv create line $mainline($id) \
758 -width [expr {($xtra + 1) * $lthickness}] \
759 -fill $colormap($id) -tags lines.$id \
760 -arrow $mainlinearrow($id)]
761 $canv lower $t
762 bindline $t $id
763 }
764 if {[info exists sidelines($id)]} {
765 foreach ls $sidelines($id) {
766 set coords [lindex $ls 0]
767 set thick [lindex $ls 1]
768 set arrow [lindex $ls 2]
769 set t [$canv create line $coords -fill $colormap($id) \
770 -width [expr {($thick + $xtra) * $lthickness}] \
771 -arrow $arrow -tags lines.$id]
772 $canv lower $t
773 bindline $t $id
774 }
775 }
776}
777
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000778# level here is an index in displist
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000779proc drawcommitline {level} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000780 global parents children nparents displist
Paul Mackerras8d858d12005-08-05 09:52:16 +1000781 global canv canv2 canv3 mainfont namefont canvy linespc
Paul Mackerrase5c2d852005-05-11 23:44:54 +0000782 global lineid linehtag linentag linedtag commitinfo
Paul Mackerrasa823a912005-06-21 10:01:38 +1000783 global colormap numcommits currentparents dupparents
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000784 global idtags idline idheads idotherrefs
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000785 global lineno lthickness mainline mainlinearrow sidelines
786 global commitlisted rowtextx idpos lastuse displist
787 global oldnlines olddlevel olddisplist
Paul Mackerras1db95b02005-05-09 04:08:39 +0000788
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000789 incr numcommits
790 incr lineno
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000791 set id [lindex $displist $level]
792 set lastuse($id) $lineno
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000793 set lineid($lineno) $id
794 set idline($id) $lineno
795 set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
796 if {![info exists commitinfo($id)]} {
797 readcommit $id
798 if {![info exists commitinfo($id)]} {
799 set commitinfo($id) {"No commit information available"}
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +0000800 set nparents($id) 0
801 }
Paul Mackerras1db95b02005-05-09 04:08:39 +0000802 }
Paul Mackerrasb490a992005-06-22 10:25:38 +1000803 assigncolor $id
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000804 set currentparents {}
Paul Mackerrasa823a912005-06-21 10:01:38 +1000805 set dupparents {}
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000806 if {[info exists commitlisted($id)] && [info exists parents($id)]} {
Paul Mackerrasa823a912005-06-21 10:01:38 +1000807 foreach p $parents($id) {
808 if {[lsearch -exact $currentparents $p] < 0} {
809 lappend currentparents $p
810 } else {
811 # remember that this parent was listed twice
812 lappend dupparents $p
813 }
814 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000815 }
Paul Mackerras8d858d12005-08-05 09:52:16 +1000816 set x [xcoord $level $level $lineno]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000817 set y1 $canvy
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800818 set canvy [expr {$canvy + $linespc}]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000819 allcanvs conf -scrollregion \
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800820 [list 0 0 0 [expr {$y1 + 0.5 * $linespc + 2}]]
Paul Mackerrasb490a992005-06-22 10:25:38 +1000821 if {[info exists mainline($id)]} {
822 lappend mainline($id) $x $y1
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000823 if {$mainlinearrow($id) ne "none"} {
824 set mainline($id) [trimdiagstart $mainline($id)]
825 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000826 }
Paul Mackerras232475d2005-11-15 10:34:03 +1100827 drawlines $id 0 0
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000828 set orad [expr {$linespc / 3}]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800829 set t [$canv create oval [expr {$x - $orad}] [expr {$y1 - $orad}] \
830 [expr {$x + $orad - 1}] [expr {$y1 + $orad - 1}] \
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000831 -fill $ofill -outline black -width 1]
832 $canv raise $t
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000833 $canv bind $t <1> {selcanvline {} %x %y}
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000834 set xt [xcoord [llength $displist] $level $lineno]
Paul Mackerrasb490a992005-06-22 10:25:38 +1000835 if {[llength $currentparents] > 2} {
836 set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000837 }
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000838 set rowtextx($lineno) $xt
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000839 set idpos($id) [list $x $xt $y1]
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000840 if {[info exists idtags($id)] || [info exists idheads($id)]
841 || [info exists idotherrefs($id)]} {
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000842 set xt [drawtags $id $x $xt $y1]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000843 }
844 set headline [lindex $commitinfo($id) 0]
845 set name [lindex $commitinfo($id) 1]
846 set date [lindex $commitinfo($id) 2]
Paul Mackerras232475d2005-11-15 10:34:03 +1100847 set date [formatdate $date]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000848 set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
849 -text $headline -font $mainfont ]
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +1000850 $canv bind $linehtag($lineno) <Button-3> "rowmenu %X %Y $id"
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000851 set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \
852 -text $name -font $namefont]
853 set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \
854 -text $date -font $mainfont]
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000855
856 set olddlevel $level
857 set olddisplist $displist
858 set oldnlines [llength $displist]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000859}
860
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000861proc drawtags {id x xt y1} {
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000862 global idtags idheads idotherrefs
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000863 global linespc lthickness
Paul Mackerras106288c2005-08-19 23:11:39 +1000864 global canv mainfont idline rowtextx
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000865
866 set marks {}
867 set ntags 0
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000868 set nheads 0
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000869 if {[info exists idtags($id)]} {
870 set marks $idtags($id)
871 set ntags [llength $marks]
872 }
873 if {[info exists idheads($id)]} {
874 set marks [concat $marks $idheads($id)]
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000875 set nheads [llength $idheads($id)]
876 }
877 if {[info exists idotherrefs($id)]} {
878 set marks [concat $marks $idotherrefs($id)]
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000879 }
880 if {$marks eq {}} {
881 return $xt
882 }
883
884 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800885 set yt [expr {$y1 - 0.5 * $linespc}]
886 set yb [expr {$yt + $linespc - 1}]
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000887 set xvals {}
888 set wvals {}
889 foreach tag $marks {
890 set wid [font measure $mainfont $tag]
891 lappend xvals $xt
892 lappend wvals $wid
893 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
894 }
895 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
896 -width $lthickness -fill black -tags tag.$id]
897 $canv lower $t
898 foreach tag $marks x $xvals wid $wvals {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800899 set xl [expr {$x + $delta}]
900 set xr [expr {$x + $delta + $wid + $lthickness}]
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000901 if {[incr ntags -1] >= 0} {
902 # draw a tag
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800903 set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
904 $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
Paul Mackerras106288c2005-08-19 23:11:39 +1000905 -width 1 -outline black -fill yellow -tags tag.$id]
906 $canv bind $t <1> [list showtag $tag 1]
907 set rowtextx($idline($id)) [expr {$xr + $linespc}]
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000908 } else {
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000909 # draw a head or other ref
910 if {[incr nheads -1] >= 0} {
911 set col green
912 } else {
913 set col "#ddddff"
914 }
Jeff Hobbs2ed49d52005-11-22 17:39:53 -0800915 set xl [expr {$xl - $delta/2}]
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000916 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +1000917 -width 1 -outline black -fill $col -tags tag.$id
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000918 }
Paul Mackerras106288c2005-08-19 23:11:39 +1000919 set t [$canv create text $xl $y1 -anchor w -text $tag \
920 -font $mainfont -tags tag.$id]
921 if {$ntags >= 0} {
922 $canv bind $t <1> [list showtag $tag 1]
923 }
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +1000924 }
925 return $xt
926}
927
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000928proc notecrossings {id lo hi corner} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000929 global olddisplist crossings cornercrossings
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000930
931 for {set i $lo} {[incr i] < $hi} {} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000932 set p [lindex $olddisplist $i]
Paul Mackerras6c20ff32005-06-22 19:53:32 +1000933 if {$p == {}} continue
934 if {$i == $corner} {
935 if {![info exists cornercrossings($id)]
936 || [lsearch -exact $cornercrossings($id) $p] < 0} {
937 lappend cornercrossings($id) $p
938 }
939 if {![info exists cornercrossings($p)]
940 || [lsearch -exact $cornercrossings($p) $id] < 0} {
941 lappend cornercrossings($p) $id
942 }
943 } else {
944 if {![info exists crossings($id)]
945 || [lsearch -exact $crossings($id) $p] < 0} {
946 lappend crossings($id) $p
947 }
948 if {![info exists crossings($p)]
949 || [lsearch -exact $crossings($p) $id] < 0} {
950 lappend crossings($p) $id
951 }
952 }
953 }
954}
955
Paul Mackerras8d858d12005-08-05 09:52:16 +1000956proc xcoord {i level ln} {
957 global canvx0 xspc1 xspc2
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +0000958
Paul Mackerras8d858d12005-08-05 09:52:16 +1000959 set x [expr {$canvx0 + $i * $xspc1($ln)}]
960 if {$i > 0 && $i == $level} {
961 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
962 } elseif {$i > $level} {
963 set x [expr {$x + $xspc2 - $xspc1($ln)}]
964 }
965 return $x
966}
967
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000968# it seems Tk can't draw arrows on the end of diagonal line segments...
969proc trimdiagend {line} {
970 while {[llength $line] > 4} {
971 set x1 [lindex $line end-3]
972 set y1 [lindex $line end-2]
973 set x2 [lindex $line end-1]
974 set y2 [lindex $line end]
975 if {($x1 == $x2) != ($y1 == $y2)} break
976 set line [lreplace $line end-1 end]
977 }
978 return $line
979}
980
981proc trimdiagstart {line} {
982 while {[llength $line] > 4} {
983 set x1 [lindex $line 0]
984 set y1 [lindex $line 1]
985 set x2 [lindex $line 2]
986 set y2 [lindex $line 3]
987 if {($x1 == $x2) != ($y1 == $y2)} break
988 set line [lreplace $line 0 1]
989 }
990 return $line
991}
992
993proc drawslants {id needonscreen nohs} {
994 global canv mainline mainlinearrow sidelines
995 global canvx0 canvy xspc1 xspc2 lthickness
996 global currentparents dupparents
Paul Mackerras8d858d12005-08-05 09:52:16 +1000997 global lthickness linespc canvy colormap lineno geometry
Paul Mackerrasf6075eb2005-08-18 09:30:10 +1000998 global maxgraphpct maxwidth
999 global displist onscreen lastuse
1000 global parents commitlisted
1001 global oldnlines olddlevel olddisplist
1002 global nhyperspace numcommits nnewparents
1003
1004 if {$lineno < 0} {
1005 lappend displist $id
1006 set onscreen($id) 1
1007 return 0
1008 }
1009
1010 set y1 [expr {$canvy - $linespc}]
1011 set y2 $canvy
1012
1013 # work out what we need to get back on screen
1014 set reins {}
1015 if {$onscreen($id) < 0} {
1016 # next to do isn't displayed, better get it on screen...
1017 lappend reins [list $id 0]
1018 }
1019 # make sure all the previous commits's parents are on the screen
1020 foreach p $currentparents {
1021 if {$onscreen($p) < 0} {
1022 lappend reins [list $p 0]
1023 }
1024 }
1025 # bring back anything requested by caller
1026 if {$needonscreen ne {}} {
1027 lappend reins $needonscreen
1028 }
1029
1030 # try the shortcut
1031 if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} {
1032 set dlevel $olddlevel
1033 set x [xcoord $dlevel $dlevel $lineno]
1034 set mainline($id) [list $x $y1]
1035 set mainlinearrow($id) none
1036 set lastuse($id) $lineno
1037 set displist [lreplace $displist $dlevel $dlevel $id]
1038 set onscreen($id) 1
1039 set xspc1([expr {$lineno + 1}]) $xspc1($lineno)
1040 return $dlevel
1041 }
1042
1043 # update displist
1044 set displist [lreplace $displist $olddlevel $olddlevel]
1045 set j $olddlevel
1046 foreach p $currentparents {
1047 set lastuse($p) $lineno
1048 if {$onscreen($p) == 0} {
1049 set displist [linsert $displist $j $p]
1050 set onscreen($p) 1
1051 incr j
1052 }
1053 }
1054 if {$onscreen($id) == 0} {
1055 lappend displist $id
Paul Mackerras022bc2a2005-08-19 10:22:04 +10001056 set onscreen($id) 1
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001057 }
1058
1059 # remove the null entry if present
1060 set nullentry [lsearch -exact $displist {}]
1061 if {$nullentry >= 0} {
1062 set displist [lreplace $displist $nullentry $nullentry]
1063 }
1064
1065 # bring back the ones we need now (if we did it earlier
1066 # it would change displist and invalidate olddlevel)
1067 foreach pi $reins {
1068 # test again in case of duplicates in reins
1069 set p [lindex $pi 0]
1070 if {$onscreen($p) < 0} {
1071 set onscreen($p) 1
1072 set lastuse($p) $lineno
1073 set displist [linsert $displist [lindex $pi 1] $p]
1074 incr nhyperspace -1
1075 }
1076 }
1077
1078 set lastuse($id) $lineno
1079
1080 # see if we need to make any lines jump off into hyperspace
1081 set displ [llength $displist]
1082 if {$displ > $maxwidth} {
1083 set ages {}
1084 foreach x $displist {
1085 lappend ages [list $lastuse($x) $x]
1086 }
1087 set ages [lsort -integer -index 0 $ages]
1088 set k 0
1089 while {$displ > $maxwidth} {
1090 set use [lindex $ages $k 0]
1091 set victim [lindex $ages $k 1]
1092 if {$use >= $lineno - 5} break
1093 incr k
1094 if {[lsearch -exact $nohs $victim] >= 0} continue
1095 set i [lsearch -exact $displist $victim]
1096 set displist [lreplace $displist $i $i]
1097 set onscreen($victim) -1
1098 incr nhyperspace
1099 incr displ -1
1100 if {$i < $nullentry} {
1101 incr nullentry -1
1102 }
1103 set x [lindex $mainline($victim) end-1]
1104 lappend mainline($victim) $x $y1
1105 set line [trimdiagend $mainline($victim)]
1106 set arrow "last"
1107 if {$mainlinearrow($victim) ne "none"} {
1108 set line [trimdiagstart $line]
1109 set arrow "both"
1110 }
1111 lappend sidelines($victim) [list $line 1 $arrow]
1112 unset mainline($victim)
1113 }
1114 }
1115
1116 set dlevel [lsearch -exact $displist $id]
1117
1118 # If we are reducing, put in a null entry
1119 if {$displ < $oldnlines} {
1120 # does the next line look like a merge?
1121 # i.e. does it have > 1 new parent?
1122 if {$nnewparents($id) > 1} {
1123 set i [expr {$dlevel + 1}]
1124 } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} {
1125 set i $olddlevel
1126 if {$nullentry >= 0 && $nullentry < $i} {
1127 incr i -1
1128 }
1129 } elseif {$nullentry >= 0} {
1130 set i $nullentry
1131 while {$i < $displ
1132 && [lindex $olddisplist $i] == [lindex $displist $i]} {
1133 incr i
1134 }
1135 } else {
1136 set i $olddlevel
1137 if {$dlevel >= $i} {
1138 incr i
1139 }
1140 }
1141 if {$i < $displ} {
1142 set displist [linsert $displist $i {}]
1143 incr displ
1144 if {$dlevel >= $i} {
1145 incr dlevel
1146 }
1147 }
1148 }
Paul Mackerras8d858d12005-08-05 09:52:16 +10001149
1150 # decide on the line spacing for the next line
1151 set lj [expr {$lineno + 1}]
1152 set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}]
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001153 if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} {
Paul Mackerras8d858d12005-08-05 09:52:16 +10001154 set xspc1($lj) $xspc2
1155 } else {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001156 set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}]
Paul Mackerras8d858d12005-08-05 09:52:16 +10001157 if {$xspc1($lj) < $lthickness} {
1158 set xspc1($lj) $lthickness
1159 }
1160 }
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001161
1162 foreach idi $reins {
1163 set id [lindex $idi 0]
1164 set j [lsearch -exact $displist $id]
1165 set xj [xcoord $j $dlevel $lj]
1166 set mainline($id) [list $xj $y2]
1167 set mainlinearrow($id) first
1168 }
1169
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001170 set i -1
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001171 foreach id $olddisplist {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001172 incr i
1173 if {$id == {}} continue
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001174 if {$onscreen($id) <= 0} continue
1175 set xi [xcoord $i $olddlevel $lineno]
1176 if {$i == $olddlevel} {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001177 foreach p $currentparents {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001178 set j [lsearch -exact $displist $p]
Paul Mackerrasa823a912005-06-21 10:01:38 +10001179 set coords [list $xi $y1]
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001180 set xj [xcoord $j $dlevel $lj]
Paul Mackerras8d858d12005-08-05 09:52:16 +10001181 if {$xj < $xi - $linespc} {
1182 lappend coords [expr {$xj + $linespc}] $y1
Paul Mackerras6c20ff32005-06-22 19:53:32 +10001183 notecrossings $p $j $i [expr {$j + 1}]
Paul Mackerras8d858d12005-08-05 09:52:16 +10001184 } elseif {$xj > $xi + $linespc} {
1185 lappend coords [expr {$xj - $linespc}] $y1
Paul Mackerras6c20ff32005-06-22 19:53:32 +10001186 notecrossings $p $i $j [expr {$j - 1}]
Paul Mackerrasa823a912005-06-21 10:01:38 +10001187 }
1188 if {[lsearch -exact $dupparents $p] >= 0} {
1189 # draw a double-width line to indicate the doubled parent
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001190 lappend coords $xj $y2
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001191 lappend sidelines($p) [list $coords 2 none]
Paul Mackerrasb490a992005-06-22 10:25:38 +10001192 if {![info exists mainline($p)]} {
1193 set mainline($p) [list $xj $y2]
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001194 set mainlinearrow($p) none
Paul Mackerrasa823a912005-06-21 10:01:38 +10001195 }
1196 } else {
1197 # normal case, no parent duplicated
Paul Mackerras8d858d12005-08-05 09:52:16 +10001198 set yb $y2
1199 set dx [expr {abs($xi - $xj)}]
1200 if {0 && $dx < $linespc} {
1201 set yb [expr {$y1 + $dx}]
1202 }
Paul Mackerrasb490a992005-06-22 10:25:38 +10001203 if {![info exists mainline($p)]} {
Paul Mackerras8d858d12005-08-05 09:52:16 +10001204 if {$xi != $xj} {
1205 lappend coords $xj $yb
Paul Mackerrasa823a912005-06-21 10:01:38 +10001206 }
Paul Mackerrasb490a992005-06-22 10:25:38 +10001207 set mainline($p) $coords
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001208 set mainlinearrow($p) none
Paul Mackerras84ba7342005-06-17 00:12:26 +00001209 } else {
Paul Mackerras8d858d12005-08-05 09:52:16 +10001210 lappend coords $xj $yb
1211 if {$yb < $y2} {
1212 lappend coords $xj $y2
1213 }
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001214 lappend sidelines($p) [list $coords 1 none]
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001215 }
Paul Mackerras1db95b02005-05-09 04:08:39 +00001216 }
1217 }
Paul Mackerras8d858d12005-08-05 09:52:16 +10001218 } else {
1219 set j $i
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001220 if {[lindex $displist $i] != $id} {
1221 set j [lsearch -exact $displist $id]
Paul Mackerras8d858d12005-08-05 09:52:16 +10001222 }
1223 if {$j != $i || $xspc1($lineno) != $xspc1($lj)
Paul Mackerras022bc2a2005-08-19 10:22:04 +10001224 || ($olddlevel < $i && $i < $dlevel)
1225 || ($dlevel < $i && $i < $olddlevel)} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001226 set xj [xcoord $j $dlevel $lj]
Paul Mackerras022bc2a2005-08-19 10:22:04 +10001227 lappend mainline($id) $xi $y1 $xj $y2
Paul Mackerras8d858d12005-08-05 09:52:16 +10001228 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001229 }
1230 }
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001231 return $dlevel
1232}
1233
1234# search for x in a list of lists
1235proc llsearch {llist x} {
1236 set i 0
1237 foreach l $llist {
1238 if {$l == $x || [lsearch -exact $l $x] >= 0} {
1239 return $i
1240 }
1241 incr i
1242 }
1243 return -1
1244}
1245
1246proc drawmore {reading} {
1247 global displayorder numcommits ncmupdate nextupdate
1248 global stopped nhyperspace parents commitlisted
1249 global maxwidth onscreen displist currentparents olddlevel
1250
1251 set n [llength $displayorder]
1252 while {$numcommits < $n} {
1253 set id [lindex $displayorder $numcommits]
1254 set ctxend [expr {$numcommits + 10}]
1255 if {!$reading && $ctxend > $n} {
1256 set ctxend $n
1257 }
1258 set dlist {}
1259 if {$numcommits > 0} {
1260 set dlist [lreplace $displist $olddlevel $olddlevel]
1261 set i $olddlevel
1262 foreach p $currentparents {
1263 if {$onscreen($p) == 0} {
1264 set dlist [linsert $dlist $i $p]
1265 incr i
1266 }
1267 }
1268 }
1269 set nohs {}
1270 set reins {}
1271 set isfat [expr {[llength $dlist] > $maxwidth}]
1272 if {$nhyperspace > 0 || $isfat} {
1273 if {$ctxend > $n} break
1274 # work out what to bring back and
1275 # what we want to don't want to send into hyperspace
1276 set room 1
1277 for {set k $numcommits} {$k < $ctxend} {incr k} {
1278 set x [lindex $displayorder $k]
1279 set i [llsearch $dlist $x]
1280 if {$i < 0} {
1281 set i [llength $dlist]
1282 lappend dlist $x
1283 }
1284 if {[lsearch -exact $nohs $x] < 0} {
1285 lappend nohs $x
1286 }
1287 if {$reins eq {} && $onscreen($x) < 0 && $room} {
1288 set reins [list $x $i]
1289 }
1290 set newp {}
1291 if {[info exists commitlisted($x)]} {
1292 set right 0
1293 foreach p $parents($x) {
1294 if {[llsearch $dlist $p] < 0} {
1295 lappend newp $p
1296 if {[lsearch -exact $nohs $p] < 0} {
1297 lappend nohs $p
1298 }
1299 if {$reins eq {} && $onscreen($p) < 0 && $room} {
1300 set reins [list $p [expr {$i + $right}]]
1301 }
1302 }
1303 set right 1
1304 }
1305 }
1306 set l [lindex $dlist $i]
1307 if {[llength $l] == 1} {
1308 set l $newp
1309 } else {
1310 set j [lsearch -exact $l $x]
1311 set l [concat [lreplace $l $j $j] $newp]
1312 }
1313 set dlist [lreplace $dlist $i $i $l]
1314 if {$room && $isfat && [llength $newp] <= 1} {
1315 set room 0
1316 }
1317 }
1318 }
1319
1320 set dlevel [drawslants $id $reins $nohs]
1321 drawcommitline $dlevel
1322 if {[clock clicks -milliseconds] >= $nextupdate
1323 && $numcommits >= $ncmupdate} {
1324 doupdate $reading
1325 if {$stopped} break
1326 }
1327 }
1328}
1329
1330# level here is an index in todo
1331proc updatetodo {level noshortcut} {
1332 global ncleft todo nnewparents
1333 global commitlisted parents onscreen
1334
1335 set id [lindex $todo $level]
1336 set olds {}
1337 if {[info exists commitlisted($id)]} {
1338 foreach p $parents($id) {
1339 if {[lsearch -exact $olds $p] < 0} {
1340 lappend olds $p
1341 }
1342 }
1343 }
1344 if {!$noshortcut && [llength $olds] == 1} {
1345 set p [lindex $olds 0]
1346 if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} {
1347 set ncleft($p) 0
1348 set todo [lreplace $todo $level $level $p]
1349 set onscreen($p) 0
1350 set nnewparents($id) 1
1351 return 0
1352 }
1353 }
1354
1355 set todo [lreplace $todo $level $level]
1356 set i $level
1357 set n 0
1358 foreach p $olds {
1359 incr ncleft($p) -1
1360 set k [lsearch -exact $todo $p]
1361 if {$k < 0} {
1362 set todo [linsert $todo $i $p]
1363 set onscreen($p) 0
1364 incr i
1365 incr n
1366 }
1367 }
1368 set nnewparents($id) $n
1369
1370 return 1
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001371}
1372
Paul Mackerras8a0a74a2005-06-27 13:38:29 +10001373proc decidenext {{noread 0}} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001374 global ncleft todo
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001375 global datemode cdate
Paul Mackerras8a0a74a2005-06-27 13:38:29 +10001376 global commitinfo
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001377
1378 # choose which one to do next time around
1379 set todol [llength $todo]
1380 set level -1
1381 set latest {}
1382 for {set k $todol} {[incr k -1] >= 0} {} {
1383 set p [lindex $todo $k]
1384 if {$ncleft($p) == 0} {
1385 if {$datemode} {
Paul Mackerras8a0a74a2005-06-27 13:38:29 +10001386 if {![info exists commitinfo($p)]} {
1387 if {$noread} {
1388 return {}
1389 }
1390 readcommit $p
1391 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001392 if {$latest == {} || $cdate($p) > $latest} {
1393 set level $k
1394 set latest $cdate($p)
1395 }
1396 } else {
1397 set level $k
1398 break
Paul Mackerras1db95b02005-05-09 04:08:39 +00001399 }
1400 }
Paul Mackerras1db95b02005-05-09 04:08:39 +00001401 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001402 if {$level < 0} {
1403 if {$todo != {}} {
1404 puts "ERROR: none of the pending commits can be done yet:"
1405 foreach p $todo {
Paul Mackerrasb490a992005-06-22 10:25:38 +10001406 puts " $p ($ncleft($p))"
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001407 }
1408 }
1409 return -1
1410 }
1411
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001412 return $level
1413}
1414
1415proc drawcommit {id} {
Paul Mackerras232475d2005-11-15 10:34:03 +11001416 global phase todo nchildren datemode nextupdate revlistorder
1417 global numcommits ncmupdate displayorder todo onscreen parents
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001418
1419 if {$phase != "incrdraw"} {
1420 set phase incrdraw
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001421 set displayorder {}
1422 set todo {}
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001423 initgraph
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001424 }
1425 if {$nchildren($id) == 0} {
1426 lappend todo $id
1427 set onscreen($id) 0
1428 }
Paul Mackerras232475d2005-11-15 10:34:03 +11001429 if {$revlistorder} {
1430 set level [lsearch -exact $todo $id]
1431 if {$level < 0} {
1432 error_popup "oops, $id isn't in todo"
1433 return
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001434 }
Paul Mackerras232475d2005-11-15 10:34:03 +11001435 lappend displayorder $id
1436 updatetodo $level 0
1437 } else {
1438 set level [decidenext 1]
1439 if {$level == {} || $id != [lindex $todo $level]} {
1440 return
1441 }
1442 while 1 {
1443 lappend displayorder [lindex $todo $level]
1444 if {[updatetodo $level $datemode]} {
1445 set level [decidenext 1]
1446 if {$level == {}} break
1447 }
1448 set id [lindex $todo $level]
1449 if {![info exists commitlisted($id)]} {
1450 break
1451 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001452 }
1453 }
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001454 drawmore 1
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001455}
1456
1457proc finishcommits {} {
1458 global phase
Paul Mackerras8a0a74a2005-06-27 13:38:29 +10001459 global canv mainfont ctext maincursor textcursor
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001460
1461 if {$phase != "incrdraw"} {
1462 $canv delete all
1463 $canv create text 3 3 -anchor nw -text "No commits selected" \
1464 -font $mainfont -tags textitems
1465 set phase {}
Paul Mackerras8a0a74a2005-06-27 13:38:29 +10001466 } else {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001467 drawrest
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001468 }
Paul Mackerrasea13cba2005-06-16 10:54:04 +00001469 . config -cursor $maincursor
Paul Mackerras94a2eed2005-08-07 15:27:57 +10001470 settextcursor $textcursor
1471}
1472
1473# Don't change the text pane cursor if it is currently the hand cursor,
1474# showing that we are over a sha1 ID link.
1475proc settextcursor {c} {
1476 global ctext curtextcursor
1477
1478 if {[$ctext cget -cursor] == $curtextcursor} {
1479 $ctext config -cursor $c
1480 }
1481 set curtextcursor $c
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001482}
1483
1484proc drawgraph {} {
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001485 global nextupdate startmsecs ncmupdate
1486 global displayorder onscreen
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001487
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001488 if {$displayorder == {}} return
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001489 set startmsecs [clock clicks -milliseconds]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08001490 set nextupdate [expr {$startmsecs + 100}]
Paul Mackerrasb6645502005-08-11 09:56:23 +10001491 set ncmupdate 1
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001492 initgraph
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001493 foreach id $displayorder {
1494 set onscreen($id) 0
1495 }
1496 drawmore 0
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001497}
1498
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001499proc drawrest {} {
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001500 global phase stopped redisplaying selectedline
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10001501 global datemode todo displayorder
Paul Mackerras466e4fd2005-08-10 22:50:28 +10001502 global numcommits ncmupdate
Paul Mackerras232475d2005-11-15 10:34:03 +11001503 global nextupdate startmsecs revlistorder
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001504
Paul Mackerrasf6e28692005-11-20 23:08:22 +11001505 set level [decidenext]
1506 if {$level >= 0} {
1507 set phase drawgraph
1508 while 1 {
1509 lappend displayorder [lindex $todo $level]
1510 set hard [updatetodo $level $datemode]
1511 if {$hard} {
1512 set level [decidenext]
1513 if {$level < 0} break
Paul Mackerrasa823a912005-06-21 10:01:38 +10001514 }
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001515 }
1516 }
Paul Mackerras232475d2005-11-15 10:34:03 +11001517 drawmore 0
Paul Mackerras1d10f362005-05-15 12:55:47 +00001518 set phase {}
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08001519 set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
Paul Mackerras84ba7342005-06-17 00:12:26 +00001520 #puts "overall $drawmsecs ms for $numcommits commits"
Paul Mackerras1d10f362005-05-15 12:55:47 +00001521 if {$redisplaying} {
1522 if {$stopped == 0 && [info exists selectedline]} {
Paul Mackerrasd6982062005-08-06 22:06:06 +10001523 selectline $selectedline 0
Paul Mackerras1d10f362005-05-15 12:55:47 +00001524 }
1525 if {$stopped == 1} {
1526 set stopped 0
1527 after idle drawgraph
1528 } else {
1529 set redisplaying 0
1530 }
1531 }
Paul Mackerras1db95b02005-05-09 04:08:39 +00001532}
1533
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001534proc findmatches {f} {
1535 global findtype foundstring foundstrlen
1536 if {$findtype == "Regexp"} {
1537 set matches [regexp -indices -all -inline $foundstring $f]
1538 } else {
1539 if {$findtype == "IgnCase"} {
1540 set str [string tolower $f]
1541 } else {
1542 set str $f
1543 }
1544 set matches {}
1545 set i 0
1546 while {[set j [string first $foundstring $str $i]] >= 0} {
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08001547 lappend matches [list $j [expr {$j+$foundstrlen-1}]]
1548 set i [expr {$j + $foundstrlen}]
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001549 }
1550 }
1551 return $matches
1552}
1553
Paul Mackerras98f350e2005-05-15 05:56:51 +00001554proc dofind {} {
1555 global findtype findloc findstring markedmatches commitinfo
1556 global numcommits lineid linehtag linentag linedtag
1557 global mainfont namefont canv canv2 canv3 selectedline
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00001558 global matchinglines foundstring foundstrlen
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001559
1560 stopfindproc
Paul Mackerras98f350e2005-05-15 05:56:51 +00001561 unmarkmatches
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001562 focus .
Paul Mackerras98f350e2005-05-15 05:56:51 +00001563 set matchinglines {}
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001564 if {$findloc == "Pickaxe"} {
1565 findpatches
1566 return
1567 }
Paul Mackerras98f350e2005-05-15 05:56:51 +00001568 if {$findtype == "IgnCase"} {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001569 set foundstring [string tolower $findstring]
Paul Mackerras98f350e2005-05-15 05:56:51 +00001570 } else {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001571 set foundstring $findstring
Paul Mackerras98f350e2005-05-15 05:56:51 +00001572 }
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001573 set foundstrlen [string length $findstring]
1574 if {$foundstrlen == 0} return
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001575 if {$findloc == "Files"} {
1576 findfiles
1577 return
1578 }
Paul Mackerras98f350e2005-05-15 05:56:51 +00001579 if {![info exists selectedline]} {
1580 set oldsel -1
1581 } else {
1582 set oldsel $selectedline
1583 }
1584 set didsel 0
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001585 set fldtypes {Headline Author Date Committer CDate Comment}
Paul Mackerras98f350e2005-05-15 05:56:51 +00001586 for {set l 0} {$l < $numcommits} {incr l} {
1587 set id $lineid($l)
1588 set info $commitinfo($id)
1589 set doesmatch 0
1590 foreach f $info ty $fldtypes {
1591 if {$findloc != "All fields" && $findloc != $ty} {
1592 continue
1593 }
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001594 set matches [findmatches $f]
Paul Mackerras98f350e2005-05-15 05:56:51 +00001595 if {$matches == {}} continue
1596 set doesmatch 1
1597 if {$ty == "Headline"} {
1598 markmatches $canv $l $f $linehtag($l) $matches $mainfont
1599 } elseif {$ty == "Author"} {
1600 markmatches $canv2 $l $f $linentag($l) $matches $namefont
1601 } elseif {$ty == "Date"} {
1602 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
1603 }
1604 }
1605 if {$doesmatch} {
1606 lappend matchinglines $l
1607 if {!$didsel && $l > $oldsel} {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001608 findselectline $l
Paul Mackerras98f350e2005-05-15 05:56:51 +00001609 set didsel 1
1610 }
1611 }
1612 }
1613 if {$matchinglines == {}} {
1614 bell
1615 } elseif {!$didsel} {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001616 findselectline [lindex $matchinglines 0]
1617 }
1618}
1619
1620proc findselectline {l} {
1621 global findloc commentend ctext
Paul Mackerrasd6982062005-08-06 22:06:06 +10001622 selectline $l 1
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001623 if {$findloc == "All fields" || $findloc == "Comments"} {
1624 # highlight the matches in the comments
1625 set f [$ctext get 1.0 $commentend]
1626 set matches [findmatches $f]
1627 foreach match $matches {
1628 set start [lindex $match 0]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08001629 set end [expr {[lindex $match 1] + 1}]
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001630 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
1631 }
Paul Mackerras98f350e2005-05-15 05:56:51 +00001632 }
1633}
1634
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001635proc findnext {restart} {
Paul Mackerras98f350e2005-05-15 05:56:51 +00001636 global matchinglines selectedline
1637 if {![info exists matchinglines]} {
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001638 if {$restart} {
1639 dofind
1640 }
Paul Mackerras98f350e2005-05-15 05:56:51 +00001641 return
1642 }
1643 if {![info exists selectedline]} return
1644 foreach l $matchinglines {
1645 if {$l > $selectedline} {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001646 findselectline $l
Paul Mackerras98f350e2005-05-15 05:56:51 +00001647 return
1648 }
1649 }
1650 bell
1651}
1652
1653proc findprev {} {
1654 global matchinglines selectedline
1655 if {![info exists matchinglines]} {
1656 dofind
1657 return
1658 }
1659 if {![info exists selectedline]} return
1660 set prev {}
1661 foreach l $matchinglines {
1662 if {$l >= $selectedline} break
1663 set prev $l
1664 }
1665 if {$prev != {}} {
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00001666 findselectline $prev
Paul Mackerras98f350e2005-05-15 05:56:51 +00001667 } else {
1668 bell
1669 }
1670}
1671
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001672proc findlocchange {name ix op} {
1673 global findloc findtype findtypemenu
1674 if {$findloc == "Pickaxe"} {
1675 set findtype Exact
1676 set state disabled
1677 } else {
1678 set state normal
1679 }
1680 $findtypemenu entryconf 1 -state $state
1681 $findtypemenu entryconf 2 -state $state
1682}
1683
1684proc stopfindproc {{done 0}} {
1685 global findprocpid findprocfile findids
1686 global ctext findoldcursor phase maincursor textcursor
1687 global findinprogress
1688
1689 catch {unset findids}
1690 if {[info exists findprocpid]} {
1691 if {!$done} {
1692 catch {exec kill $findprocpid}
1693 }
1694 catch {close $findprocfile}
1695 unset findprocpid
1696 }
1697 if {[info exists findinprogress]} {
1698 unset findinprogress
1699 if {$phase != "incrdraw"} {
1700 . config -cursor $maincursor
Paul Mackerras94a2eed2005-08-07 15:27:57 +10001701 settextcursor $textcursor
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001702 }
1703 }
1704}
1705
1706proc findpatches {} {
1707 global findstring selectedline numcommits
1708 global findprocpid findprocfile
1709 global finddidsel ctext lineid findinprogress
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001710 global findinsertpos
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001711
1712 if {$numcommits == 0} return
1713
1714 # make a list of all the ids to search, starting at the one
1715 # after the selected line (if any)
1716 if {[info exists selectedline]} {
1717 set l $selectedline
1718 } else {
1719 set l -1
1720 }
1721 set inputids {}
1722 for {set i 0} {$i < $numcommits} {incr i} {
1723 if {[incr l] >= $numcommits} {
1724 set l 0
1725 }
1726 append inputids $lineid($l) "\n"
1727 }
1728
1729 if {[catch {
1730 set f [open [list | git-diff-tree --stdin -s -r -S$findstring \
1731 << $inputids] r]
1732 } err]} {
1733 error_popup "Error starting search process: $err"
1734 return
1735 }
1736
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001737 set findinsertpos end
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001738 set findprocfile $f
1739 set findprocpid [pid $f]
1740 fconfigure $f -blocking 0
1741 fileevent $f readable readfindproc
1742 set finddidsel 0
1743 . config -cursor watch
Paul Mackerras94a2eed2005-08-07 15:27:57 +10001744 settextcursor watch
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001745 set findinprogress 1
1746}
1747
1748proc readfindproc {} {
1749 global findprocfile finddidsel
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001750 global idline matchinglines findinsertpos
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001751
1752 set n [gets $findprocfile line]
1753 if {$n < 0} {
1754 if {[eof $findprocfile]} {
1755 stopfindproc 1
1756 if {!$finddidsel} {
1757 bell
1758 }
1759 }
1760 return
1761 }
1762 if {![regexp {^[0-9a-f]{40}} $line id]} {
1763 error_popup "Can't parse git-diff-tree output: $line"
1764 stopfindproc
1765 return
1766 }
1767 if {![info exists idline($id)]} {
1768 puts stderr "spurious id: $id"
1769 return
1770 }
1771 set l $idline($id)
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001772 insertmatch $l $id
1773}
1774
1775proc insertmatch {l id} {
1776 global matchinglines findinsertpos finddidsel
1777
1778 if {$findinsertpos == "end"} {
1779 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
1780 set matchinglines [linsert $matchinglines 0 $l]
1781 set findinsertpos 1
1782 } else {
1783 lappend matchinglines $l
1784 }
1785 } else {
1786 set matchinglines [linsert $matchinglines $findinsertpos $l]
1787 incr findinsertpos
1788 }
1789 markheadline $l $id
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001790 if {!$finddidsel} {
1791 findselectline $l
1792 set finddidsel 1
1793 }
1794}
1795
1796proc findfiles {} {
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001797 global selectedline numcommits lineid ctext
1798 global ffileline finddidsel parents nparents
1799 global findinprogress findstartline findinsertpos
1800 global treediffs fdiffids fdiffsneeded fdiffpos
1801 global findmergefiles
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001802
1803 if {$numcommits == 0} return
1804
1805 if {[info exists selectedline]} {
1806 set l [expr {$selectedline + 1}]
1807 } else {
1808 set l 0
1809 }
1810 set ffileline $l
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001811 set findstartline $l
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001812 set diffsneeded {}
1813 set fdiffsneeded {}
1814 while 1 {
1815 set id $lineid($l)
1816 if {$findmergefiles || $nparents($id) == 1} {
1817 foreach p $parents($id) {
1818 if {![info exists treediffs([list $id $p])]} {
1819 append diffsneeded "$id $p\n"
1820 lappend fdiffsneeded [list $id $p]
1821 }
1822 }
1823 }
1824 if {[incr l] >= $numcommits} {
1825 set l 0
1826 }
1827 if {$l == $findstartline} break
1828 }
1829
1830 # start off a git-diff-tree process if needed
1831 if {$diffsneeded ne {}} {
1832 if {[catch {
1833 set df [open [list | git-diff-tree -r --stdin << $diffsneeded] r]
1834 } err ]} {
1835 error_popup "Error starting search process: $err"
1836 return
1837 }
1838 catch {unset fdiffids}
1839 set fdiffpos 0
1840 fconfigure $df -blocking 0
1841 fileevent $df readable [list readfilediffs $df]
1842 }
1843
1844 set finddidsel 0
1845 set findinsertpos end
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001846 set id $lineid($l)
1847 set p [lindex $parents($id) 0]
1848 . config -cursor watch
Paul Mackerras94a2eed2005-08-07 15:27:57 +10001849 settextcursor watch
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001850 set findinprogress 1
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001851 findcont [list $id $p]
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001852 update
1853}
1854
1855proc readfilediffs {df} {
1856 global findids fdiffids fdiffs
1857
1858 set n [gets $df line]
1859 if {$n < 0} {
1860 if {[eof $df]} {
1861 donefilediff
1862 if {[catch {close $df} err]} {
1863 stopfindproc
1864 bell
1865 error_popup "Error in git-diff-tree: $err"
1866 } elseif {[info exists findids]} {
1867 set ids $findids
1868 stopfindproc
1869 bell
1870 error_popup "Couldn't find diffs for {$ids}"
1871 }
1872 }
1873 return
1874 }
1875 if {[regexp {^([0-9a-f]{40}) \(from ([0-9a-f]{40})\)} $line match id p]} {
1876 # start of a new string of diffs
1877 donefilediff
1878 set fdiffids [list $id $p]
1879 set fdiffs {}
1880 } elseif {[string match ":*" $line]} {
1881 lappend fdiffs [lindex $line 5]
1882 }
1883}
1884
1885proc donefilediff {} {
1886 global fdiffids fdiffs treediffs findids
1887 global fdiffsneeded fdiffpos
1888
1889 if {[info exists fdiffids]} {
1890 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
1891 && $fdiffpos < [llength $fdiffsneeded]} {
1892 # git-diff-tree doesn't output anything for a commit
1893 # which doesn't change anything
1894 set nullids [lindex $fdiffsneeded $fdiffpos]
1895 set treediffs($nullids) {}
1896 if {[info exists findids] && $nullids eq $findids} {
1897 unset findids
1898 findcont $nullids
1899 }
1900 incr fdiffpos
1901 }
1902 incr fdiffpos
1903
1904 if {![info exists treediffs($fdiffids)]} {
1905 set treediffs($fdiffids) $fdiffs
1906 }
1907 if {[info exists findids] && $fdiffids eq $findids} {
1908 unset findids
1909 findcont $fdiffids
1910 }
1911 }
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001912}
1913
1914proc findcont {ids} {
Paul Mackerras3c461ff2005-07-20 09:13:46 -04001915 global findids treediffs parents nparents
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001916 global ffileline findstartline finddidsel
1917 global lineid numcommits matchinglines findinprogress
1918 global findmergefiles
1919
1920 set id [lindex $ids 0]
1921 set p [lindex $ids 1]
1922 set pi [lsearch -exact $parents($id) $p]
1923 set l $ffileline
1924 while 1 {
1925 if {$findmergefiles || $nparents($id) == 1} {
1926 if {![info exists treediffs($ids)]} {
1927 set findids $ids
1928 set ffileline $l
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001929 return
1930 }
1931 set doesmatch 0
1932 foreach f $treediffs($ids) {
1933 set x [findmatches $f]
1934 if {$x != {}} {
1935 set doesmatch 1
1936 break
1937 }
1938 }
1939 if {$doesmatch} {
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04001940 insertmatch $l $id
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001941 set pi $nparents($id)
1942 }
1943 } else {
1944 set pi $nparents($id)
1945 }
1946 if {[incr pi] >= $nparents($id)} {
1947 set pi 0
1948 if {[incr l] >= $numcommits} {
1949 set l 0
1950 }
1951 if {$l == $findstartline} break
1952 set id $lineid($l)
1953 }
1954 set p [lindex $parents($id) $pi]
1955 set ids [list $id $p]
1956 }
1957 stopfindproc
1958 if {!$finddidsel} {
1959 bell
1960 }
1961}
1962
1963# mark a commit as matching by putting a yellow background
1964# behind the headline
1965proc markheadline {l id} {
1966 global canv mainfont linehtag commitinfo
1967
1968 set bbox [$canv bbox $linehtag($l)]
1969 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
1970 $canv lower $t
1971}
1972
1973# mark the bits of a headline, author or date that match a find string
Paul Mackerras98f350e2005-05-15 05:56:51 +00001974proc markmatches {canv l str tag matches font} {
1975 set bbox [$canv bbox $tag]
1976 set x0 [lindex $bbox 0]
1977 set y0 [lindex $bbox 1]
1978 set y1 [lindex $bbox 3]
1979 foreach match $matches {
1980 set start [lindex $match 0]
1981 set end [lindex $match 1]
1982 if {$start > $end} continue
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08001983 set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
1984 set xlen [font measure $font [string range $str 0 [expr {$end}]]]
1985 set t [$canv create rect [expr {$x0+$xoff}] $y0 \
1986 [expr {$x0+$xlen+2}] $y1 \
Paul Mackerras98f350e2005-05-15 05:56:51 +00001987 -outline {} -tags matches -fill yellow]
1988 $canv lower $t
1989 }
1990}
1991
1992proc unmarkmatches {} {
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001993 global matchinglines findids
Paul Mackerras98f350e2005-05-15 05:56:51 +00001994 allcanvs delete matches
1995 catch {unset matchinglines}
Paul Mackerrasb74fd572005-07-16 07:46:13 -04001996 catch {unset findids}
Paul Mackerras98f350e2005-05-15 05:56:51 +00001997}
1998
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10001999proc selcanvline {w x y} {
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002000 global canv canvy0 ctext linespc
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002001 global lineid linehtag linentag linedtag rowtextx
Paul Mackerras1db95b02005-05-09 04:08:39 +00002002 set ymax [lindex [$canv cget -scrollregion] 3]
Paul Mackerrascfb45632005-05-31 12:14:42 +00002003 if {$ymax == {}} return
Paul Mackerras1db95b02005-05-09 04:08:39 +00002004 set yfrac [lindex [$canv yview] 0]
2005 set y [expr {$y + $yfrac * $ymax}]
2006 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
2007 if {$l < 0} {
2008 set l 0
2009 }
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002010 if {$w eq $canv} {
2011 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
2012 }
Paul Mackerras98f350e2005-05-15 05:56:51 +00002013 unmarkmatches
Paul Mackerrasd6982062005-08-06 22:06:06 +10002014 selectline $l 1
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002015}
2016
Linus Torvaldsb1ba39e2005-08-08 20:04:20 -07002017proc commit_descriptor {p} {
2018 global commitinfo
2019 set l "..."
2020 if {[info exists commitinfo($p)]} {
2021 set l [lindex $commitinfo($p) 0]
2022 }
2023 return "$p ($l)"
2024}
2025
Paul Mackerras106288c2005-08-19 23:11:39 +10002026# append some text to the ctext widget, and make any SHA1 ID
2027# that we know about be a clickable link.
2028proc appendwithlinks {text} {
2029 global ctext idline linknum
2030
2031 set start [$ctext index "end - 1c"]
2032 $ctext insert end $text
2033 $ctext insert end "\n"
2034 set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
2035 foreach l $links {
2036 set s [lindex $l 0]
2037 set e [lindex $l 1]
2038 set linkid [string range $text $s $e]
2039 if {![info exists idline($linkid)]} continue
2040 incr e
2041 $ctext tag add link "$start + $s c" "$start + $e c"
2042 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
2043 $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
2044 incr linknum
2045 }
2046 $ctext tag conf link -foreground blue -underline 1
2047 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
2048 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
2049}
2050
Paul Mackerrasd6982062005-08-06 22:06:06 +10002051proc selectline {l isnew} {
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002052 global canv canv2 canv3 ctext commitinfo selectedline
2053 global lineid linehtag linentag linedtag
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10002054 global canvy0 linespc parents nparents children
Paul Mackerras14c9dbd2005-07-16 21:53:55 -04002055 global cflist currentid sha1entry
Paul Mackerras106288c2005-08-19 23:11:39 +10002056 global commentend idtags idline linknum
Paul Mackerrasd6982062005-08-06 22:06:06 +10002057
Paul Mackerras84ba7342005-06-17 00:12:26 +00002058 $canv delete hover
Paul Mackerras9843c302005-08-30 10:57:11 +10002059 normalline
Paul Mackerras1db95b02005-05-09 04:08:39 +00002060 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002061 $canv delete secsel
2062 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
2063 -tags secsel -fill [$canv cget -selectbackground]]
2064 $canv lower $t
2065 $canv2 delete secsel
2066 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
2067 -tags secsel -fill [$canv2 cget -selectbackground]]
2068 $canv2 lower $t
2069 $canv3 delete secsel
2070 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
2071 -tags secsel -fill [$canv3 cget -selectbackground]]
2072 $canv3 lower $t
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002073 set y [expr {$canvy0 + $l * $linespc}]
Paul Mackerras17386062005-05-18 22:51:00 +00002074 set ymax [lindex [$canv cget -scrollregion] 3]
Paul Mackerras58422152005-05-19 10:56:42 +00002075 set ytop [expr {$y - $linespc - 1}]
2076 set ybot [expr {$y + $linespc + 1}]
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002077 set wnow [$canv yview]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08002078 set wtop [expr {[lindex $wnow 0] * $ymax}]
2079 set wbot [expr {[lindex $wnow 1] * $ymax}]
Paul Mackerras58422152005-05-19 10:56:42 +00002080 set wh [expr {$wbot - $wtop}]
2081 set newtop $wtop
Paul Mackerras17386062005-05-18 22:51:00 +00002082 if {$ytop < $wtop} {
Paul Mackerras58422152005-05-19 10:56:42 +00002083 if {$ybot < $wtop} {
2084 set newtop [expr {$y - $wh / 2.0}]
2085 } else {
2086 set newtop $ytop
2087 if {$newtop > $wtop - $linespc} {
2088 set newtop [expr {$wtop - $linespc}]
2089 }
Paul Mackerras17386062005-05-18 22:51:00 +00002090 }
Paul Mackerras58422152005-05-19 10:56:42 +00002091 } elseif {$ybot > $wbot} {
2092 if {$ytop > $wbot} {
2093 set newtop [expr {$y - $wh / 2.0}]
2094 } else {
2095 set newtop [expr {$ybot - $wh}]
2096 if {$newtop < $wtop + $linespc} {
2097 set newtop [expr {$wtop + $linespc}]
2098 }
Paul Mackerras17386062005-05-18 22:51:00 +00002099 }
Paul Mackerras58422152005-05-19 10:56:42 +00002100 }
2101 if {$newtop != $wtop} {
2102 if {$newtop < 0} {
2103 set newtop 0
2104 }
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08002105 allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002106 }
Paul Mackerrasd6982062005-08-06 22:06:06 +10002107
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002108 if {$isnew} {
2109 addtohistory [list selectline $l 0]
Paul Mackerrasd6982062005-08-06 22:06:06 +10002110 }
2111
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002112 set selectedline $l
2113
Paul Mackerras1db95b02005-05-09 04:08:39 +00002114 set id $lineid($l)
Paul Mackerras887fe3c2005-05-21 07:35:37 +00002115 set currentid $id
Paul Mackerras98f350e2005-05-15 05:56:51 +00002116 $sha1entry delete 0 end
2117 $sha1entry insert 0 $id
2118 $sha1entry selection from 0
2119 $sha1entry selection to end
Paul Mackerras98f350e2005-05-15 05:56:51 +00002120
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002121 $ctext conf -state normal
Paul Mackerras1db95b02005-05-09 04:08:39 +00002122 $ctext delete 0.0 end
Paul Mackerras106288c2005-08-19 23:11:39 +10002123 set linknum 0
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002124 $ctext mark set fmark.0 0.0
2125 $ctext mark gravity fmark.0 left
Paul Mackerras1db95b02005-05-09 04:08:39 +00002126 set info $commitinfo($id)
Paul Mackerras232475d2005-11-15 10:34:03 +11002127 set date [formatdate [lindex $info 2]]
2128 $ctext insert end "Author: [lindex $info 1] $date\n"
2129 set date [formatdate [lindex $info 4]]
2130 $ctext insert end "Committer: [lindex $info 3] $date\n"
Paul Mackerras887fe3c2005-05-21 07:35:37 +00002131 if {[info exists idtags($id)]} {
2132 $ctext insert end "Tags:"
2133 foreach tag $idtags($id) {
2134 $ctext insert end " $tag"
2135 }
2136 $ctext insert end "\n"
2137 }
Linus Torvalds8b192802005-08-07 13:58:56 -07002138
Linus Torvalds8b192802005-08-07 13:58:56 -07002139 set comment {}
Linus Torvaldsb1ba39e2005-08-08 20:04:20 -07002140 if {[info exists parents($id)]} {
2141 foreach p $parents($id) {
2142 append comment "Parent: [commit_descriptor $p]\n"
Linus Torvalds8b192802005-08-07 13:58:56 -07002143 }
Linus Torvaldsb1ba39e2005-08-08 20:04:20 -07002144 }
2145 if {[info exists children($id)]} {
2146 foreach c $children($id) {
2147 append comment "Child: [commit_descriptor $c]\n"
2148 }
Linus Torvalds8b192802005-08-07 13:58:56 -07002149 }
2150 append comment "\n"
2151 append comment [lindex $info 5]
Paul Mackerrasd6982062005-08-06 22:06:06 +10002152
2153 # make anything that looks like a SHA1 ID be a clickable link
Paul Mackerras106288c2005-08-19 23:11:39 +10002154 appendwithlinks $comment
Paul Mackerrasd6982062005-08-06 22:06:06 +10002155
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002156 $ctext tag delete Comments
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00002157 $ctext tag remove found 1.0 end
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002158 $ctext conf -state disabled
Paul Mackerrasdf3d83b2005-05-17 23:23:07 +00002159 set commentend [$ctext index "end - 1c"]
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002160
2161 $cflist delete 0 end
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002162 $cflist insert end "Comments"
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002163 if {$nparents($id) == 1} {
Paul Mackerrasd3272442005-11-28 20:41:56 +11002164 startdiff $id
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002165 } elseif {$nparents($id) > 1} {
2166 mergediff $id
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002167 }
2168}
2169
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002170proc selnextline {dir} {
2171 global selectedline
2172 if {![info exists selectedline]} return
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08002173 set l [expr {$selectedline + $dir}]
Paul Mackerras98f350e2005-05-15 05:56:51 +00002174 unmarkmatches
Paul Mackerrasd6982062005-08-06 22:06:06 +10002175 selectline $l 1
2176}
2177
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002178proc unselectline {} {
2179 global selectedline
2180
2181 catch {unset selectedline}
2182 allcanvs delete secsel
2183}
2184
2185proc addtohistory {cmd} {
2186 global history historyindex
2187
2188 if {$historyindex > 0
2189 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2190 return
2191 }
2192
2193 if {$historyindex < [llength $history]} {
2194 set history [lreplace $history $historyindex end $cmd]
2195 } else {
2196 lappend history $cmd
2197 }
2198 incr historyindex
2199 if {$historyindex > 1} {
2200 .ctop.top.bar.leftbut conf -state normal
2201 } else {
2202 .ctop.top.bar.leftbut conf -state disabled
2203 }
2204 .ctop.top.bar.rightbut conf -state disabled
2205}
2206
Paul Mackerrasd6982062005-08-06 22:06:06 +10002207proc goback {} {
2208 global history historyindex
2209
2210 if {$historyindex > 1} {
2211 incr historyindex -1
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002212 set cmd [lindex $history [expr {$historyindex - 1}]]
2213 eval $cmd
Paul Mackerrasd6982062005-08-06 22:06:06 +10002214 .ctop.top.bar.rightbut conf -state normal
2215 }
2216 if {$historyindex <= 1} {
2217 .ctop.top.bar.leftbut conf -state disabled
2218 }
2219}
2220
2221proc goforw {} {
2222 global history historyindex
2223
2224 if {$historyindex < [llength $history]} {
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002225 set cmd [lindex $history $historyindex]
Paul Mackerrasd6982062005-08-06 22:06:06 +10002226 incr historyindex
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002227 eval $cmd
Paul Mackerrasd6982062005-08-06 22:06:06 +10002228 .ctop.top.bar.leftbut conf -state normal
2229 }
2230 if {$historyindex >= [llength $history]} {
2231 .ctop.top.bar.rightbut conf -state disabled
2232 }
Paul Mackerras5ad588d2005-05-10 01:02:55 +00002233}
2234
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002235proc mergediff {id} {
2236 global parents diffmergeid diffmergegca mergefilelist diffpindex
Paul Mackerrase2ed4322005-07-17 03:39:44 -04002237
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002238 set diffmergeid $id
2239 set diffpindex -1
2240 set diffmergegca [findgca $parents($id)]
2241 if {[info exists mergefilelist($id)]} {
Paul Mackerras1115fb32005-07-31 21:35:21 +10002242 if {$mergefilelist($id) ne {}} {
2243 showmergediff
2244 }
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002245 } else {
2246 contmergediff {}
2247 }
2248}
2249
2250proc findgca {ids} {
2251 set gca {}
2252 foreach id $ids {
2253 if {$gca eq {}} {
2254 set gca $id
2255 } else {
2256 if {[catch {
2257 set gca [exec git-merge-base $gca $id]
2258 } err]} {
2259 return {}
2260 }
2261 }
2262 }
2263 return $gca
2264}
2265
2266proc contmergediff {ids} {
2267 global diffmergeid diffpindex parents nparents diffmergegca
Paul Mackerras1115fb32005-07-31 21:35:21 +10002268 global treediffs mergefilelist diffids treepending
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002269
2270 # diff the child against each of the parents, and diff
2271 # each of the parents against the GCA.
2272 while 1 {
Paul Mackerrasd3272442005-11-28 20:41:56 +11002273 if {[lindex $ids 1] == $diffmergeid && $diffmergegca ne {}} {
2274 set ids [list $diffmergegca [lindex $ids 0]]
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002275 } else {
2276 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2277 set p [lindex $parents($diffmergeid) $diffpindex]
Paul Mackerrasd3272442005-11-28 20:41:56 +11002278 set ids [list $p $diffmergeid]
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002279 }
2280 if {![info exists treediffs($ids)]} {
2281 set diffids $ids
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002282 if {![info exists treepending]} {
2283 gettreediffs $ids
2284 }
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002285 return
2286 }
2287 }
2288
2289 # If a file in some parent is different from the child and also
2290 # different from the GCA, then it's interesting.
2291 # If we don't have a GCA, then a file is interesting if it is
2292 # different from the child in all the parents.
2293 if {$diffmergegca ne {}} {
2294 set files {}
2295 foreach p $parents($diffmergeid) {
Paul Mackerrasd3272442005-11-28 20:41:56 +11002296 set gcadiffs $treediffs([list $diffmergegca $p])
2297 foreach f $treediffs([list $p $diffmergeid]) {
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002298 if {[lsearch -exact $files $f] < 0
2299 && [lsearch -exact $gcadiffs $f] >= 0} {
2300 lappend files $f
2301 }
2302 }
2303 }
2304 set files [lsort $files]
2305 } else {
2306 set p [lindex $parents($diffmergeid) 0]
2307 set files $treediffs([list $diffmergeid $p])
2308 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2309 set p [lindex $parents($diffmergeid) $i]
Paul Mackerrasd3272442005-11-28 20:41:56 +11002310 set df $treediffs([list $p $diffmergeid])
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002311 set nf {}
2312 foreach f $files {
2313 if {[lsearch -exact $df $f] >= 0} {
2314 lappend nf $f
2315 }
2316 }
2317 set files $nf
2318 }
2319 }
2320
2321 set mergefilelist($diffmergeid) $files
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002322 if {$files ne {}} {
2323 showmergediff
2324 }
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002325}
2326
2327proc showmergediff {} {
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002328 global cflist diffmergeid mergefilelist parents
Paul Mackerras1115fb32005-07-31 21:35:21 +10002329 global diffopts diffinhunk currentfile currenthunk filelines
2330 global diffblocked groupfilelast mergefds groupfilenum grouphunks
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002331
2332 set files $mergefilelist($diffmergeid)
2333 foreach f $files {
2334 $cflist insert end $f
2335 }
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002336 set env(GIT_DIFF_OPTS) $diffopts
2337 set flist {}
2338 catch {unset currentfile}
2339 catch {unset currenthunk}
2340 catch {unset filelines}
Paul Mackerras1115fb32005-07-31 21:35:21 +10002341 catch {unset groupfilenum}
2342 catch {unset grouphunks}
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002343 set groupfilelast -1
2344 foreach p $parents($diffmergeid) {
2345 set cmd [list | git-diff-tree -p $p $diffmergeid]
2346 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2347 if {[catch {set f [open $cmd r]} err]} {
2348 error_popup "Error getting diffs: $err"
2349 foreach f $flist {
2350 catch {close $f}
2351 }
2352 return
2353 }
2354 lappend flist $f
2355 set ids [list $diffmergeid $p]
2356 set mergefds($ids) $f
2357 set diffinhunk($ids) 0
2358 set diffblocked($ids) 0
2359 fconfigure $f -blocking 0
2360 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2361 }
2362}
2363
2364proc getmergediffline {f ids id} {
2365 global diffmergeid diffinhunk diffoldlines diffnewlines
2366 global currentfile currenthunk
2367 global diffoldstart diffnewstart diffoldlno diffnewlno
2368 global diffblocked mergefilelist
2369 global noldlines nnewlines difflcounts filelines
2370
2371 set n [gets $f line]
2372 if {$n < 0} {
2373 if {![eof $f]} return
2374 }
2375
2376 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2377 if {$n < 0} {
2378 close $f
2379 }
2380 return
2381 }
2382
2383 if {$diffinhunk($ids) != 0} {
2384 set fi $currentfile($ids)
2385 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2386 # continuing an existing hunk
2387 set line [string range $line 1 end]
2388 set p [lindex $ids 1]
2389 if {$match eq "-" || $match eq " "} {
2390 set filelines($p,$fi,$diffoldlno($ids)) $line
2391 incr diffoldlno($ids)
2392 }
2393 if {$match eq "+" || $match eq " "} {
2394 set filelines($id,$fi,$diffnewlno($ids)) $line
2395 incr diffnewlno($ids)
2396 }
2397 if {$match eq " "} {
2398 if {$diffinhunk($ids) == 2} {
2399 lappend difflcounts($ids) \
2400 [list $noldlines($ids) $nnewlines($ids)]
2401 set noldlines($ids) 0
2402 set diffinhunk($ids) 1
2403 }
2404 incr noldlines($ids)
2405 } elseif {$match eq "-" || $match eq "+"} {
2406 if {$diffinhunk($ids) == 1} {
2407 lappend difflcounts($ids) [list $noldlines($ids)]
2408 set noldlines($ids) 0
2409 set nnewlines($ids) 0
2410 set diffinhunk($ids) 2
2411 }
2412 if {$match eq "-"} {
2413 incr noldlines($ids)
2414 } else {
2415 incr nnewlines($ids)
2416 }
2417 }
2418 # and if it's \ No newline at end of line, then what?
2419 return
2420 }
2421 # end of a hunk
2422 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2423 lappend difflcounts($ids) [list $noldlines($ids)]
2424 } elseif {$diffinhunk($ids) == 2
2425 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2426 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2427 }
2428 set currenthunk($ids) [list $currentfile($ids) \
2429 $diffoldstart($ids) $diffnewstart($ids) \
2430 $diffoldlno($ids) $diffnewlno($ids) \
2431 $difflcounts($ids)]
2432 set diffinhunk($ids) 0
2433 # -1 = need to block, 0 = unblocked, 1 = is blocked
2434 set diffblocked($ids) -1
2435 processhunks
2436 if {$diffblocked($ids) == -1} {
2437 fileevent $f readable {}
2438 set diffblocked($ids) 1
2439 }
2440 }
2441
2442 if {$n < 0} {
2443 # eof
2444 if {!$diffblocked($ids)} {
2445 close $f
2446 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2447 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2448 processhunks
2449 }
2450 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2451 # start of a new file
2452 set currentfile($ids) \
2453 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2454 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2455 $line match f1l f1c f2l f2c rest]} {
2456 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2457 # start of a new hunk
2458 if {$f1l == 0 && $f1c == 0} {
2459 set f1l 1
2460 }
2461 if {$f2l == 0 && $f2c == 0} {
2462 set f2l 1
2463 }
2464 set diffinhunk($ids) 1
2465 set diffoldstart($ids) $f1l
2466 set diffnewstart($ids) $f2l
2467 set diffoldlno($ids) $f1l
2468 set diffnewlno($ids) $f2l
2469 set difflcounts($ids) {}
2470 set noldlines($ids) 0
2471 set nnewlines($ids) 0
2472 }
2473 }
2474}
2475
2476proc processhunks {} {
2477 global diffmergeid parents nparents currenthunk
2478 global mergefilelist diffblocked mergefds
2479 global grouphunks grouplinestart grouplineend groupfilenum
2480
2481 set nfiles [llength $mergefilelist($diffmergeid)]
2482 while 1 {
2483 set fi $nfiles
2484 set lno 0
2485 # look for the earliest hunk
2486 foreach p $parents($diffmergeid) {
2487 set ids [list $diffmergeid $p]
2488 if {![info exists currenthunk($ids)]} return
2489 set i [lindex $currenthunk($ids) 0]
2490 set l [lindex $currenthunk($ids) 2]
2491 if {$i < $fi || ($i == $fi && $l < $lno)} {
2492 set fi $i
2493 set lno $l
2494 set pi $p
2495 }
2496 }
2497
2498 if {$fi < $nfiles} {
2499 set ids [list $diffmergeid $pi]
2500 set hunk $currenthunk($ids)
2501 unset currenthunk($ids)
2502 if {$diffblocked($ids) > 0} {
2503 fileevent $mergefds($ids) readable \
2504 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2505 }
2506 set diffblocked($ids) 0
2507
2508 if {[info exists groupfilenum] && $groupfilenum == $fi
2509 && $lno <= $grouplineend} {
2510 # add this hunk to the pending group
2511 lappend grouphunks($pi) $hunk
2512 set endln [lindex $hunk 4]
2513 if {$endln > $grouplineend} {
2514 set grouplineend $endln
2515 }
2516 continue
2517 }
2518 }
2519
2520 # succeeding stuff doesn't belong in this group, so
2521 # process the group now
2522 if {[info exists groupfilenum]} {
2523 processgroup
2524 unset groupfilenum
2525 unset grouphunks
2526 }
2527
2528 if {$fi >= $nfiles} break
2529
2530 # start a new group
2531 set groupfilenum $fi
2532 set grouphunks($pi) [list $hunk]
2533 set grouplinestart $lno
2534 set grouplineend [lindex $hunk 4]
2535 }
2536}
2537
2538proc processgroup {} {
2539 global groupfilelast groupfilenum difffilestart
2540 global mergefilelist diffmergeid ctext filelines
2541 global parents diffmergeid diffoffset
2542 global grouphunks grouplinestart grouplineend nparents
2543 global mergemax
2544
2545 $ctext conf -state normal
2546 set id $diffmergeid
2547 set f $groupfilenum
2548 if {$groupfilelast != $f} {
2549 $ctext insert end "\n"
2550 set here [$ctext index "end - 1c"]
2551 set difffilestart($f) $here
2552 set mark fmark.[expr {$f + 1}]
2553 $ctext mark set $mark $here
2554 $ctext mark gravity $mark left
2555 set header [lindex $mergefilelist($id) $f]
2556 set l [expr {(78 - [string length $header]) / 2}]
2557 set pad [string range "----------------------------------------" 1 $l]
2558 $ctext insert end "$pad $header $pad\n" filesep
2559 set groupfilelast $f
2560 foreach p $parents($id) {
2561 set diffoffset($p) 0
2562 }
2563 }
2564
2565 $ctext insert end "@@" msep
2566 set nlines [expr {$grouplineend - $grouplinestart}]
2567 set events {}
2568 set pnum 0
2569 foreach p $parents($id) {
2570 set startline [expr {$grouplinestart + $diffoffset($p)}]
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002571 set ol $startline
2572 set nl $grouplinestart
2573 if {[info exists grouphunks($p)]} {
2574 foreach h $grouphunks($p) {
2575 set l [lindex $h 2]
2576 if {$nl < $l} {
2577 for {} {$nl < $l} {incr nl} {
2578 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2579 incr ol
2580 }
2581 }
2582 foreach chunk [lindex $h 5] {
2583 if {[llength $chunk] == 2} {
2584 set olc [lindex $chunk 0]
2585 set nlc [lindex $chunk 1]
2586 set nnl [expr {$nl + $nlc}]
2587 lappend events [list $nl $nnl $pnum $olc $nlc]
2588 incr ol $olc
2589 set nl $nnl
2590 } else {
2591 incr ol [lindex $chunk 0]
2592 incr nl [lindex $chunk 0]
2593 }
2594 }
2595 }
2596 }
2597 if {$nl < $grouplineend} {
2598 for {} {$nl < $grouplineend} {incr nl} {
2599 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2600 incr ol
2601 }
2602 }
2603 set nlines [expr {$ol - $startline}]
2604 $ctext insert end " -$startline,$nlines" msep
2605 incr pnum
2606 }
2607
2608 set nlines [expr {$grouplineend - $grouplinestart}]
2609 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2610
2611 set events [lsort -integer -index 0 $events]
2612 set nevents [llength $events]
2613 set nmerge $nparents($diffmergeid)
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002614 set l $grouplinestart
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002615 for {set i 0} {$i < $nevents} {set i $j} {
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002616 set nl [lindex $events $i 0]
2617 while {$l < $nl} {
2618 $ctext insert end " $filelines($id,$f,$l)\n"
2619 incr l
2620 }
2621 set e [lindex $events $i]
2622 set enl [lindex $e 1]
2623 set j $i
2624 set active {}
2625 while 1 {
2626 set pnum [lindex $e 2]
2627 set olc [lindex $e 3]
2628 set nlc [lindex $e 4]
2629 if {![info exists delta($pnum)]} {
2630 set delta($pnum) [expr {$olc - $nlc}]
2631 lappend active $pnum
2632 } else {
2633 incr delta($pnum) [expr {$olc - $nlc}]
2634 }
2635 if {[incr j] >= $nevents} break
2636 set e [lindex $events $j]
2637 if {[lindex $e 0] >= $enl} break
2638 if {[lindex $e 1] > $enl} {
2639 set enl [lindex $e 1]
2640 }
2641 }
2642 set nlc [expr {$enl - $l}]
2643 set ncol mresult
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002644 set bestpn -1
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002645 if {[llength $active] == $nmerge - 1} {
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002646 # no diff for one of the parents, i.e. it's identical
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002647 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2648 if {![info exists delta($pnum)]} {
2649 if {$pnum < $mergemax} {
2650 lappend ncol m$pnum
2651 } else {
2652 lappend ncol mmax
2653 }
2654 break
2655 }
2656 }
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002657 } elseif {[llength $active] == $nmerge} {
2658 # all parents are different, see if one is very similar
2659 set bestsim 30
2660 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2661 set sim [similarity $pnum $l $nlc $f \
2662 [lrange $events $i [expr {$j-1}]]]
2663 if {$sim > $bestsim} {
2664 set bestsim $sim
2665 set bestpn $pnum
2666 }
2667 }
2668 if {$bestpn >= 0} {
2669 lappend ncol m$bestpn
2670 }
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002671 }
2672 set pnum -1
2673 foreach p $parents($id) {
2674 incr pnum
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002675 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002676 set olc [expr {$nlc + $delta($pnum)}]
2677 set ol [expr {$l + $diffoffset($p)}]
2678 incr diffoffset($p) $delta($pnum)
2679 unset delta($pnum)
2680 for {} {$olc > 0} {incr olc -1} {
2681 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
2682 incr ol
2683 }
2684 }
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002685 set endl [expr {$l + $nlc}]
2686 if {$bestpn >= 0} {
2687 # show this pretty much as a normal diff
2688 set p [lindex $parents($id) $bestpn]
2689 set ol [expr {$l + $diffoffset($p)}]
2690 incr diffoffset($p) $delta($bestpn)
2691 unset delta($bestpn)
2692 for {set k $i} {$k < $j} {incr k} {
2693 set e [lindex $events $k]
2694 if {[lindex $e 2] != $bestpn} continue
2695 set nl [lindex $e 0]
2696 set ol [expr {$ol + $nl - $l}]
2697 for {} {$l < $nl} {incr l} {
2698 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2699 }
2700 set c [lindex $e 3]
2701 for {} {$c > 0} {incr c -1} {
2702 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
2703 incr ol
2704 }
2705 set nl [lindex $e 1]
2706 for {} {$l < $nl} {incr l} {
2707 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
2708 }
2709 }
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002710 }
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002711 for {} {$l < $endl} {incr l} {
2712 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2713 }
Paul Mackerras9d2a52e2005-07-27 22:15:47 -05002714 }
2715 while {$l < $grouplineend} {
2716 $ctext insert end " $filelines($id,$f,$l)\n"
2717 incr l
2718 }
2719 $ctext conf -state disabled
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002720}
2721
Paul Mackerrasc8a4acb2005-07-29 09:23:03 -05002722proc similarity {pnum l nlc f events} {
2723 global diffmergeid parents diffoffset filelines
2724
2725 set id $diffmergeid
2726 set p [lindex $parents($id) $pnum]
2727 set ol [expr {$l + $diffoffset($p)}]
2728 set endl [expr {$l + $nlc}]
2729 set same 0
2730 set diff 0
2731 foreach e $events {
2732 if {[lindex $e 2] != $pnum} continue
2733 set nl [lindex $e 0]
2734 set ol [expr {$ol + $nl - $l}]
2735 for {} {$l < $nl} {incr l} {
2736 incr same [string length $filelines($id,$f,$l)]
2737 incr same
2738 }
2739 set oc [lindex $e 3]
2740 for {} {$oc > 0} {incr oc -1} {
2741 incr diff [string length $filelines($p,$f,$ol)]
2742 incr diff
2743 incr ol
2744 }
2745 set nl [lindex $e 1]
2746 for {} {$l < $nl} {incr l} {
2747 incr diff [string length $filelines($id,$f,$l)]
2748 incr diff
2749 }
2750 }
2751 for {} {$l < $endl} {incr l} {
2752 incr same [string length $filelines($id,$f,$l)]
2753 incr same
2754 }
2755 if {$same == 0} {
2756 return 0
2757 }
2758 return [expr {200 * $same / (2 * $same + $diff)}]
2759}
2760
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002761proc startdiff {ids} {
2762 global treediffs diffids treepending diffmergeid
2763
2764 set diffids $ids
2765 catch {unset diffmergeid}
2766 if {![info exists treediffs($ids)]} {
2767 if {![info exists treepending]} {
2768 gettreediffs $ids
2769 }
2770 } else {
2771 addtocflist $ids
2772 }
2773}
2774
2775proc addtocflist {ids} {
2776 global treediffs cflist
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002777 foreach f $treediffs($ids) {
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002778 $cflist insert end $f
2779 }
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002780 getblobdiffs $ids
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002781}
2782
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002783proc gettreediffs {ids} {
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002784 global treediff parents treepending
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002785 set treepending $ids
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002786 set treediff {}
Paul Mackerrasd3272442005-11-28 20:41:56 +11002787 if [catch {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]}] return
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002788 fconfigure $gdtf -blocking 0
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002789 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002790}
2791
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002792proc gettreediffline {gdtf ids} {
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002793 global treediff treediffs treepending diffids diffmergeid
2794
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002795 set n [gets $gdtf line]
2796 if {$n < 0} {
2797 if {![eof $gdtf]} return
2798 close $gdtf
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002799 set treediffs($ids) $treediff
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002800 unset treepending
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002801 if {$ids != $diffids} {
2802 gettreediffs $diffids
2803 } else {
2804 if {[info exists diffmergeid]} {
2805 contmergediff $ids
Paul Mackerrasb74fd572005-07-16 07:46:13 -04002806 } else {
2807 addtocflist $ids
2808 }
2809 }
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002810 return
2811 }
Paul Mackerrasd4e95cb2005-06-01 00:02:13 +00002812 set file [lindex $line 5]
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002813 lappend treediff $file
Paul Mackerrasd2610d12005-05-11 00:45:38 +00002814}
2815
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002816proc getblobdiffs {ids} {
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002817 global diffopts blobdifffd diffids env curdifftag curtagstart
Paul Mackerras7eab2932005-07-20 12:25:54 -04002818 global difffilestart nextupdate diffinhdr treediffs
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002819
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002820 set env(GIT_DIFF_OPTS) $diffopts
Paul Mackerrasd3272442005-11-28 20:41:56 +11002821 set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids]
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002822 if {[catch {set bdf [open $cmd r]} err]} {
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002823 puts "error getting diffs: $err"
2824 return
2825 }
Paul Mackerras4f2c2642005-07-17 11:11:44 -04002826 set diffinhdr 0
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002827 fconfigure $bdf -blocking 0
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002828 set blobdifffd($ids) $bdf
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002829 set curdifftag Comments
2830 set curtagstart 0.0
Paul Mackerras3c461ff2005-07-20 09:13:46 -04002831 catch {unset difffilestart}
2832 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002833 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002834}
2835
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002836proc getblobdiffline {bdf ids} {
Paul Mackerras4f2c2642005-07-17 11:11:44 -04002837 global diffids blobdifffd ctext curdifftag curtagstart
Paul Mackerras7eab2932005-07-20 12:25:54 -04002838 global diffnexthead diffnextnote difffilestart
2839 global nextupdate diffinhdr treediffs
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002840
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002841 set n [gets $bdf line]
2842 if {$n < 0} {
2843 if {[eof $bdf]} {
2844 close $bdf
Paul Mackerrase2ed4322005-07-17 03:39:44 -04002845 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002846 $ctext tag add $curdifftag $curtagstart end
2847 }
2848 }
2849 return
2850 }
Paul Mackerrase2ed4322005-07-17 03:39:44 -04002851 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002852 return
2853 }
2854 $ctext conf -state normal
Paul Mackerras7eab2932005-07-20 12:25:54 -04002855 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002856 # start of a new file
2857 $ctext insert end "\n"
2858 $ctext tag add $curdifftag $curtagstart end
2859 set curtagstart [$ctext index "end - 1c"]
Paul Mackerras7eab2932005-07-20 12:25:54 -04002860 set header $newname
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002861 set here [$ctext index "end - 1c"]
Paul Mackerras7eab2932005-07-20 12:25:54 -04002862 set i [lsearch -exact $treediffs($diffids) $fname]
2863 if {$i >= 0} {
2864 set difffilestart($i) $here
2865 incr i
2866 $ctext mark set fmark.$i $here
2867 $ctext mark gravity fmark.$i left
2868 }
2869 if {$newname != $fname} {
2870 set i [lsearch -exact $treediffs($diffids) $newname]
2871 if {$i >= 0} {
2872 set difffilestart($i) $here
2873 incr i
2874 $ctext mark set fmark.$i $here
2875 $ctext mark gravity fmark.$i left
2876 }
2877 }
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002878 set curdifftag "f:$fname"
2879 $ctext tag delete $curdifftag
Paul Mackerras58422152005-05-19 10:56:42 +00002880 set l [expr {(78 - [string length $header]) / 2}]
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002881 set pad [string range "----------------------------------------" 1 $l]
Paul Mackerras58422152005-05-19 10:56:42 +00002882 $ctext insert end "$pad $header $pad\n" filesep
Paul Mackerras4f2c2642005-07-17 11:11:44 -04002883 set diffinhdr 1
2884 } elseif {[regexp {^(---|\+\+\+)} $line]} {
2885 set diffinhdr 0
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002886 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2887 $line match f1l f1c f2l f2c rest]} {
Paul Mackerras712fcc02005-11-30 09:28:16 +11002888 $ctext insert end "$line\n" hunksep
Paul Mackerras4f2c2642005-07-17 11:11:44 -04002889 set diffinhdr 0
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002890 } else {
2891 set x [string range $line 0 0]
2892 if {$x == "-" || $x == "+"} {
2893 set tag [expr {$x == "+"}]
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002894 $ctext insert end "$line\n" d$tag
2895 } elseif {$x == " "} {
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002896 $ctext insert end "$line\n"
Paul Mackerras4f2c2642005-07-17 11:11:44 -04002897 } elseif {$diffinhdr || $x == "\\"} {
Paul Mackerras58422152005-05-19 10:56:42 +00002898 # e.g. "\ No newline at end of file"
2899 $ctext insert end "$line\n" filesep
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002900 } else {
2901 # Something else we don't recognize
2902 if {$curdifftag != "Comments"} {
2903 $ctext insert end "\n"
2904 $ctext tag add $curdifftag $curtagstart end
2905 set curtagstart [$ctext index "end - 1c"]
2906 set curdifftag Comments
2907 }
2908 $ctext insert end "$line\n" filesep
2909 }
2910 }
2911 $ctext conf -state disabled
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002912 if {[clock clicks -milliseconds] >= $nextupdate} {
2913 incr nextupdate 100
2914 fileevent $bdf readable {}
2915 update
2916 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
2917 }
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002918}
2919
Paul Mackerras39ad8572005-05-19 12:35:53 +00002920proc nextfile {} {
2921 global difffilestart ctext
2922 set here [$ctext index @0,0]
2923 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
2924 if {[$ctext compare $difffilestart($i) > $here]} {
Paul Mackerras7eab2932005-07-20 12:25:54 -04002925 if {![info exists pos]
2926 || [$ctext compare $difffilestart($i) < $pos]} {
2927 set pos $difffilestart($i)
2928 }
Paul Mackerras39ad8572005-05-19 12:35:53 +00002929 }
2930 }
Paul Mackerras7eab2932005-07-20 12:25:54 -04002931 if {[info exists pos]} {
2932 $ctext yview $pos
2933 }
Paul Mackerras39ad8572005-05-19 12:35:53 +00002934}
2935
Paul Mackerrase5c2d852005-05-11 23:44:54 +00002936proc listboxsel {} {
Paul Mackerras7eab2932005-07-20 12:25:54 -04002937 global ctext cflist currentid
Paul Mackerras9a40c502005-05-12 23:46:16 +00002938 if {![info exists currentid]} return
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10002939 set sel [lsort [$cflist curselection]]
2940 if {$sel eq {}} return
2941 set first [lindex $sel 0]
2942 catch {$ctext yview fmark.$first}
Paul Mackerras1db95b02005-05-09 04:08:39 +00002943}
2944
Paul Mackerras1d10f362005-05-15 12:55:47 +00002945proc setcoords {} {
2946 global linespc charspc canvx0 canvy0 mainfont
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10002947 global xspc1 xspc2 lthickness
Paul Mackerras8d858d12005-08-05 09:52:16 +10002948
Paul Mackerras1d10f362005-05-15 12:55:47 +00002949 set linespc [font metrics $mainfont -linespace]
2950 set charspc [font measure $mainfont "m"]
Jeff Hobbs2ed49d52005-11-22 17:39:53 -08002951 set canvy0 [expr {3 + 0.5 * $linespc}]
2952 set canvx0 [expr {3 + 0.5 * $linespc}]
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10002953 set lthickness [expr {int($linespc / 9) + 1}]
Paul Mackerras8d858d12005-08-05 09:52:16 +10002954 set xspc1(0) $linespc
2955 set xspc2 $linespc
Paul Mackerras9a40c502005-05-12 23:46:16 +00002956}
Paul Mackerras1db95b02005-05-09 04:08:39 +00002957
Paul Mackerras1d10f362005-05-15 12:55:47 +00002958proc redisplay {} {
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002959 global stopped redisplaying phase
Paul Mackerras1d10f362005-05-15 12:55:47 +00002960 if {$stopped > 1} return
2961 if {$phase == "getcommits"} return
2962 set redisplaying 1
Paul Mackerras9ccbdfb2005-06-16 00:27:23 +00002963 if {$phase == "drawgraph" || $phase == "incrdraw"} {
Paul Mackerras1d10f362005-05-15 12:55:47 +00002964 set stopped 1
2965 } else {
2966 drawgraph
Paul Mackerras1db95b02005-05-09 04:08:39 +00002967 }
2968}
Paul Mackerras1d10f362005-05-15 12:55:47 +00002969
2970proc incrfont {inc} {
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10002971 global mainfont namefont textfont ctext canv phase
Paul Mackerrascfb45632005-05-31 12:14:42 +00002972 global stopped entries
Paul Mackerras1d10f362005-05-15 12:55:47 +00002973 unmarkmatches
2974 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
2975 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
2976 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
2977 setcoords
2978 $ctext conf -font $textfont
2979 $ctext tag conf filesep -font [concat $textfont bold]
Paul Mackerras887fe3c2005-05-21 07:35:37 +00002980 foreach e $entries {
2981 $e conf -font $mainfont
2982 }
Paul Mackerras1d10f362005-05-15 12:55:47 +00002983 if {$phase == "getcommits"} {
2984 $canv itemconf textitems -font $mainfont
2985 }
2986 redisplay
Paul Mackerras1db95b02005-05-09 04:08:39 +00002987}
Paul Mackerras1d10f362005-05-15 12:55:47 +00002988
Paul Mackerrasee3dc722005-06-25 16:37:13 +10002989proc clearsha1 {} {
2990 global sha1entry sha1string
2991 if {[string length $sha1string] == 40} {
2992 $sha1entry delete 0 end
2993 }
2994}
2995
Paul Mackerras887fe3c2005-05-21 07:35:37 +00002996proc sha1change {n1 n2 op} {
2997 global sha1string currentid sha1but
2998 if {$sha1string == {}
2999 || ([info exists currentid] && $sha1string == $currentid)} {
3000 set state disabled
3001 } else {
3002 set state normal
3003 }
3004 if {[$sha1but cget -state] == $state} return
3005 if {$state == "normal"} {
3006 $sha1but conf -state normal -relief raised -text "Goto: "
3007 } else {
3008 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3009 }
3010}
3011
3012proc gotocommit {} {
3013 global sha1string currentid idline tagids
Paul Mackerrasf3b8b3c2005-07-18 12:16:35 -04003014 global lineid numcommits
3015
Paul Mackerras887fe3c2005-05-21 07:35:37 +00003016 if {$sha1string == {}
3017 || ([info exists currentid] && $sha1string == $currentid)} return
3018 if {[info exists tagids($sha1string)]} {
3019 set id $tagids($sha1string)
3020 } else {
3021 set id [string tolower $sha1string]
Paul Mackerrasf3b8b3c2005-07-18 12:16:35 -04003022 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3023 set matches {}
3024 for {set l 0} {$l < $numcommits} {incr l} {
3025 if {[string match $id* $lineid($l)]} {
3026 lappend matches $lineid($l)
3027 }
3028 }
3029 if {$matches ne {}} {
3030 if {[llength $matches] > 1} {
3031 error_popup "Short SHA1 id $id is ambiguous"
3032 return
3033 }
3034 set id [lindex $matches 0]
3035 }
3036 }
Paul Mackerras887fe3c2005-05-21 07:35:37 +00003037 }
3038 if {[info exists idline($id)]} {
Paul Mackerrasd6982062005-08-06 22:06:06 +10003039 selectline $idline($id) 1
Paul Mackerras887fe3c2005-05-21 07:35:37 +00003040 return
3041 }
Paul Mackerrasf3b8b3c2005-07-18 12:16:35 -04003042 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
Paul Mackerras887fe3c2005-05-21 07:35:37 +00003043 set type "SHA1 id"
3044 } else {
3045 set type "Tag"
3046 }
3047 error_popup "$type $sha1string is not known"
3048}
3049
Paul Mackerras84ba7342005-06-17 00:12:26 +00003050proc lineenter {x y id} {
3051 global hoverx hovery hoverid hovertimer
3052 global commitinfo canv
3053
3054 if {![info exists commitinfo($id)]} return
3055 set hoverx $x
3056 set hovery $y
3057 set hoverid $id
3058 if {[info exists hovertimer]} {
3059 after cancel $hovertimer
3060 }
3061 set hovertimer [after 500 linehover]
3062 $canv delete hover
3063}
3064
3065proc linemotion {x y id} {
3066 global hoverx hovery hoverid hovertimer
3067
3068 if {[info exists hoverid] && $id == $hoverid} {
3069 set hoverx $x
3070 set hovery $y
3071 if {[info exists hovertimer]} {
3072 after cancel $hovertimer
3073 }
3074 set hovertimer [after 500 linehover]
3075 }
3076}
3077
3078proc lineleave {id} {
3079 global hoverid hovertimer canv
3080
3081 if {[info exists hoverid] && $id == $hoverid} {
3082 $canv delete hover
3083 if {[info exists hovertimer]} {
3084 after cancel $hovertimer
3085 unset hovertimer
3086 }
3087 unset hoverid
3088 }
3089}
3090
3091proc linehover {} {
3092 global hoverx hovery hoverid hovertimer
3093 global canv linespc lthickness
3094 global commitinfo mainfont
3095
3096 set text [lindex $commitinfo($hoverid) 0]
3097 set ymax [lindex [$canv cget -scrollregion] 3]
3098 if {$ymax == {}} return
3099 set yfrac [lindex [$canv yview] 0]
3100 set x [expr {$hoverx + 2 * $linespc}]
3101 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3102 set x0 [expr {$x - 2 * $lthickness}]
3103 set y0 [expr {$y - 2 * $lthickness}]
3104 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3105 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3106 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3107 -fill \#ffff80 -outline black -width 1 -tags hover]
3108 $canv raise $t
Frank Sorensone2464832005-10-30 02:06:46 -07003109 set t [$canv create text $x $y -anchor nw -text $text -tags hover -font $mainfont]
Paul Mackerras84ba7342005-06-17 00:12:26 +00003110 $canv raise $t
3111}
3112
Paul Mackerras9843c302005-08-30 10:57:11 +10003113proc clickisonarrow {id y} {
3114 global mainline mainlinearrow sidelines lthickness
3115
3116 set thresh [expr {2 * $lthickness + 6}]
3117 if {[info exists mainline($id)]} {
3118 if {$mainlinearrow($id) ne "none"} {
3119 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3120 return "up"
3121 }
3122 }
3123 }
3124 if {[info exists sidelines($id)]} {
3125 foreach ls $sidelines($id) {
3126 set coords [lindex $ls 0]
3127 set arrow [lindex $ls 2]
3128 if {$arrow eq "first" || $arrow eq "both"} {
3129 if {abs([lindex $coords 1] - $y) < $thresh} {
3130 return "up"
3131 }
3132 }
3133 if {$arrow eq "last" || $arrow eq "both"} {
3134 if {abs([lindex $coords end] - $y) < $thresh} {
3135 return "down"
3136 }
3137 }
3138 }
3139 }
3140 return {}
3141}
3142
3143proc arrowjump {id dirn y} {
Stefan-W. Hahne3fe5322005-11-05 20:55:29 +01003144 global mainline sidelines canv canv2 canv3
Paul Mackerras9843c302005-08-30 10:57:11 +10003145
3146 set yt {}
3147 if {$dirn eq "down"} {
3148 if {[info exists mainline($id)]} {
3149 set y1 [lindex $mainline($id) 1]
3150 if {$y1 > $y} {
3151 set yt $y1
3152 }
3153 }
3154 if {[info exists sidelines($id)]} {
3155 foreach ls $sidelines($id) {
3156 set y1 [lindex $ls 0 1]
3157 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3158 set yt $y1
3159 }
3160 }
3161 }
3162 } else {
3163 if {[info exists sidelines($id)]} {
3164 foreach ls $sidelines($id) {
3165 set y1 [lindex $ls 0 end]
3166 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3167 set yt $y1
3168 }
3169 }
3170 }
3171 }
3172 if {$yt eq {}} return
3173 set ymax [lindex [$canv cget -scrollregion] 3]
3174 if {$ymax eq {} || $ymax <= 0} return
3175 set view [$canv yview]
3176 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3177 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3178 if {$yfrac < 0} {
3179 set yfrac 0
3180 }
3181 $canv yview moveto $yfrac
Stefan-W. Hahne3fe5322005-11-05 20:55:29 +01003182 $canv2 yview moveto $yfrac
3183 $canv3 yview moveto $yfrac
Paul Mackerras9843c302005-08-30 10:57:11 +10003184}
3185
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003186proc lineclick {x y id isnew} {
Paul Mackerras9843c302005-08-30 10:57:11 +10003187 global ctext commitinfo children cflist canv thickerline
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003188
3189 unmarkmatches
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003190 unselectline
Paul Mackerras9843c302005-08-30 10:57:11 +10003191 normalline
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003192 $canv delete hover
Paul Mackerras9843c302005-08-30 10:57:11 +10003193 # draw this line thicker than normal
Paul Mackerras232475d2005-11-15 10:34:03 +11003194 drawlines $id 1 1
Paul Mackerras9843c302005-08-30 10:57:11 +10003195 set thickerline $id
3196 if {$isnew} {
3197 set ymax [lindex [$canv cget -scrollregion] 3]
3198 if {$ymax eq {}} return
3199 set yfrac [lindex [$canv yview] 0]
3200 set y [expr {$y + $yfrac * $ymax}]
3201 }
3202 set dirn [clickisonarrow $id $y]
3203 if {$dirn ne {}} {
3204 arrowjump $id $dirn $y
3205 return
3206 }
3207
3208 if {$isnew} {
3209 addtohistory [list lineclick $x $y $id 0]
3210 }
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003211 # fill the details pane with info about this line
3212 $ctext conf -state normal
3213 $ctext delete 0.0 end
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003214 $ctext tag conf link -foreground blue -underline 1
3215 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3216 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3217 $ctext insert end "Parent:\t"
3218 $ctext insert end $id [list link link0]
3219 $ctext tag bind link0 <1> [list selbyid $id]
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003220 set info $commitinfo($id)
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003221 $ctext insert end "\n\t[lindex $info 0]\n"
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003222 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
Paul Mackerras232475d2005-11-15 10:34:03 +11003223 set date [formatdate [lindex $info 2]]
3224 $ctext insert end "\tDate:\t$date\n"
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003225 if {[info exists children($id)]} {
3226 $ctext insert end "\nChildren:"
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003227 set i 0
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003228 foreach child $children($id) {
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003229 incr i
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003230 set info $commitinfo($child)
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003231 $ctext insert end "\n\t"
3232 $ctext insert end $child [list link link$i]
3233 $ctext tag bind link$i <1> [list selbyid $child]
3234 $ctext insert end "\n\t[lindex $info 0]"
3235 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
Paul Mackerras232475d2005-11-15 10:34:03 +11003236 set date [formatdate [lindex $info 2]]
3237 $ctext insert end "\n\tDate:\t$date\n"
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003238 }
3239 }
3240 $ctext conf -state disabled
3241
3242 $cflist delete 0 end
3243}
3244
Paul Mackerras9843c302005-08-30 10:57:11 +10003245proc normalline {} {
3246 global thickerline
3247 if {[info exists thickerline]} {
Paul Mackerras232475d2005-11-15 10:34:03 +11003248 drawlines $thickerline 0 1
Paul Mackerras9843c302005-08-30 10:57:11 +10003249 unset thickerline
3250 }
3251}
3252
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003253proc selbyid {id} {
3254 global idline
3255 if {[info exists idline($id)]} {
Paul Mackerrasd6982062005-08-06 22:06:06 +10003256 selectline $idline($id) 1
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003257 }
3258}
3259
3260proc mstime {} {
3261 global startmstime
3262 if {![info exists startmstime]} {
3263 set startmstime [clock clicks -milliseconds]
3264 }
3265 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3266}
3267
3268proc rowmenu {x y id} {
3269 global rowctxmenu idline selectedline rowmenuid
3270
3271 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3272 set state disabled
3273 } else {
3274 set state normal
3275 }
3276 $rowctxmenu entryconfigure 0 -state $state
3277 $rowctxmenu entryconfigure 1 -state $state
Paul Mackerras74daedb2005-06-27 19:27:32 +10003278 $rowctxmenu entryconfigure 2 -state $state
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003279 set rowmenuid $id
3280 tk_popup $rowctxmenu $x $y
3281}
3282
3283proc diffvssel {dirn} {
3284 global rowmenuid selectedline lineid
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003285
3286 if {![info exists selectedline]} return
3287 if {$dirn} {
3288 set oldid $lineid($selectedline)
3289 set newid $rowmenuid
3290 } else {
3291 set oldid $rowmenuid
3292 set newid $lineid($selectedline)
3293 }
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003294 addtohistory [list doseldiff $oldid $newid]
3295 doseldiff $oldid $newid
3296}
3297
3298proc doseldiff {oldid newid} {
3299 global ctext cflist
3300 global commitinfo
3301
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003302 $ctext conf -state normal
3303 $ctext delete 0.0 end
3304 $ctext mark set fmark.0 0.0
3305 $ctext mark gravity fmark.0 left
3306 $cflist delete 0 end
3307 $cflist insert end "Top"
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003308 $ctext insert end "From "
3309 $ctext tag conf link -foreground blue -underline 1
3310 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3311 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3312 $ctext tag bind link0 <1> [list selbyid $oldid]
3313 $ctext insert end $oldid [list link link0]
3314 $ctext insert end "\n "
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003315 $ctext insert end [lindex $commitinfo($oldid) 0]
Paul Mackerrasfa4da7b2005-08-08 09:47:22 +10003316 $ctext insert end "\n\nTo "
3317 $ctext tag bind link1 <1> [list selbyid $newid]
3318 $ctext insert end $newid [list link link1]
3319 $ctext insert end "\n "
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003320 $ctext insert end [lindex $commitinfo($newid) 0]
3321 $ctext insert end "\n"
3322 $ctext conf -state disabled
3323 $ctext tag delete Comments
3324 $ctext tag remove found 1.0 end
Paul Mackerrasd3272442005-11-28 20:41:56 +11003325 startdiff [list $oldid $newid]
Paul Mackerrasc8dfbcf2005-06-25 15:39:21 +10003326}
3327
Paul Mackerras74daedb2005-06-27 19:27:32 +10003328proc mkpatch {} {
3329 global rowmenuid currentid commitinfo patchtop patchnum
3330
3331 if {![info exists currentid]} return
3332 set oldid $currentid
3333 set oldhead [lindex $commitinfo($oldid) 0]
3334 set newid $rowmenuid
3335 set newhead [lindex $commitinfo($newid) 0]
3336 set top .patch
3337 set patchtop $top
3338 catch {destroy $top}
3339 toplevel $top
3340 label $top.title -text "Generate patch"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003341 grid $top.title - -pady 10
Paul Mackerras74daedb2005-06-27 19:27:32 +10003342 label $top.from -text "From:"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003343 entry $top.fromsha1 -width 40 -relief flat
Paul Mackerras74daedb2005-06-27 19:27:32 +10003344 $top.fromsha1 insert 0 $oldid
3345 $top.fromsha1 conf -state readonly
3346 grid $top.from $top.fromsha1 -sticky w
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003347 entry $top.fromhead -width 60 -relief flat
Paul Mackerras74daedb2005-06-27 19:27:32 +10003348 $top.fromhead insert 0 $oldhead
3349 $top.fromhead conf -state readonly
3350 grid x $top.fromhead -sticky w
3351 label $top.to -text "To:"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003352 entry $top.tosha1 -width 40 -relief flat
Paul Mackerras74daedb2005-06-27 19:27:32 +10003353 $top.tosha1 insert 0 $newid
3354 $top.tosha1 conf -state readonly
3355 grid $top.to $top.tosha1 -sticky w
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003356 entry $top.tohead -width 60 -relief flat
Paul Mackerras74daedb2005-06-27 19:27:32 +10003357 $top.tohead insert 0 $newhead
3358 $top.tohead conf -state readonly
3359 grid x $top.tohead -sticky w
3360 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
3361 grid $top.rev x -pady 10
3362 label $top.flab -text "Output file:"
3363 entry $top.fname -width 60
3364 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3365 incr patchnum
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003366 grid $top.flab $top.fname -sticky w
Paul Mackerras74daedb2005-06-27 19:27:32 +10003367 frame $top.buts
3368 button $top.buts.gen -text "Generate" -command mkpatchgo
3369 button $top.buts.can -text "Cancel" -command mkpatchcan
3370 grid $top.buts.gen $top.buts.can
3371 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3372 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3373 grid $top.buts - -pady 10 -sticky ew
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003374 focus $top.fname
Paul Mackerras74daedb2005-06-27 19:27:32 +10003375}
3376
3377proc mkpatchrev {} {
3378 global patchtop
3379
3380 set oldid [$patchtop.fromsha1 get]
3381 set oldhead [$patchtop.fromhead get]
3382 set newid [$patchtop.tosha1 get]
3383 set newhead [$patchtop.tohead get]
3384 foreach e [list fromsha1 fromhead tosha1 tohead] \
3385 v [list $newid $newhead $oldid $oldhead] {
3386 $patchtop.$e conf -state normal
3387 $patchtop.$e delete 0 end
3388 $patchtop.$e insert 0 $v
3389 $patchtop.$e conf -state readonly
3390 }
3391}
3392
3393proc mkpatchgo {} {
3394 global patchtop
3395
3396 set oldid [$patchtop.fromsha1 get]
3397 set newid [$patchtop.tosha1 get]
3398 set fname [$patchtop.fname get]
3399 if {[catch {exec git-diff-tree -p $oldid $newid >$fname &} err]} {
3400 error_popup "Error creating patch: $err"
3401 }
3402 catch {destroy $patchtop}
3403 unset patchtop
3404}
3405
3406proc mkpatchcan {} {
3407 global patchtop
3408
3409 catch {destroy $patchtop}
3410 unset patchtop
3411}
3412
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003413proc mktag {} {
3414 global rowmenuid mktagtop commitinfo
3415
3416 set top .maketag
3417 set mktagtop $top
3418 catch {destroy $top}
3419 toplevel $top
3420 label $top.title -text "Create tag"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003421 grid $top.title - -pady 10
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003422 label $top.id -text "ID:"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003423 entry $top.sha1 -width 40 -relief flat
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003424 $top.sha1 insert 0 $rowmenuid
3425 $top.sha1 conf -state readonly
3426 grid $top.id $top.sha1 -sticky w
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003427 entry $top.head -width 60 -relief flat
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003428 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3429 $top.head conf -state readonly
3430 grid x $top.head -sticky w
3431 label $top.tlab -text "Tag name:"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003432 entry $top.tag -width 60
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003433 grid $top.tlab $top.tag -sticky w
3434 frame $top.buts
3435 button $top.buts.gen -text "Create" -command mktaggo
3436 button $top.buts.can -text "Cancel" -command mktagcan
3437 grid $top.buts.gen $top.buts.can
3438 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3439 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3440 grid $top.buts - -pady 10 -sticky ew
3441 focus $top.tag
3442}
3443
3444proc domktag {} {
3445 global mktagtop env tagids idtags
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003446
3447 set id [$mktagtop.sha1 get]
3448 set tag [$mktagtop.tag get]
3449 if {$tag == {}} {
3450 error_popup "No tag name specified"
3451 return
3452 }
3453 if {[info exists tagids($tag)]} {
3454 error_popup "Tag \"$tag\" already exists"
3455 return
3456 }
3457 if {[catch {
Junio C Hamano73b6a6c2005-07-28 00:28:44 -07003458 set dir [gitdir]
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003459 set fname [file join $dir "refs/tags" $tag]
3460 set f [open $fname w]
3461 puts $f $id
3462 close $f
3463 } err]} {
3464 error_popup "Error creating tag: $err"
3465 return
3466 }
3467
3468 set tagids($tag) $id
3469 lappend idtags($id) $tag
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +10003470 redrawtags $id
3471}
3472
3473proc redrawtags {id} {
3474 global canv linehtag idline idpos selectedline
3475
3476 if {![info exists idline($id)]} return
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003477 $canv delete tag.$id
3478 set xt [eval drawtags $id $idpos($id)]
3479 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3480 if {[info exists selectedline] && $selectedline == $idline($id)} {
Paul Mackerrasd6982062005-08-06 22:06:06 +10003481 selectline $selectedline 0
Paul Mackerrasbdbfbe32005-06-27 22:56:40 +10003482 }
3483}
3484
3485proc mktagcan {} {
3486 global mktagtop
3487
3488 catch {destroy $mktagtop}
3489 unset mktagtop
3490}
3491
3492proc mktaggo {} {
3493 domktag
3494 mktagcan
3495}
3496
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003497proc writecommit {} {
3498 global rowmenuid wrcomtop commitinfo wrcomcmd
3499
3500 set top .writecommit
3501 set wrcomtop $top
3502 catch {destroy $top}
3503 toplevel $top
3504 label $top.title -text "Write commit to file"
3505 grid $top.title - -pady 10
3506 label $top.id -text "ID:"
3507 entry $top.sha1 -width 40 -relief flat
3508 $top.sha1 insert 0 $rowmenuid
3509 $top.sha1 conf -state readonly
3510 grid $top.id $top.sha1 -sticky w
3511 entry $top.head -width 60 -relief flat
3512 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3513 $top.head conf -state readonly
3514 grid x $top.head -sticky w
3515 label $top.clab -text "Command:"
3516 entry $top.cmd -width 60 -textvariable wrcomcmd
3517 grid $top.clab $top.cmd -sticky w -pady 10
3518 label $top.flab -text "Output file:"
3519 entry $top.fname -width 60
3520 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3521 grid $top.flab $top.fname -sticky w
3522 frame $top.buts
3523 button $top.buts.gen -text "Write" -command wrcomgo
3524 button $top.buts.can -text "Cancel" -command wrcomcan
3525 grid $top.buts.gen $top.buts.can
3526 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3527 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3528 grid $top.buts - -pady 10 -sticky ew
3529 focus $top.fname
3530}
3531
3532proc wrcomgo {} {
3533 global wrcomtop
3534
3535 set id [$wrcomtop.sha1 get]
3536 set cmd "echo $id | [$wrcomtop.cmd get]"
3537 set fname [$wrcomtop.fname get]
3538 if {[catch {exec sh -c $cmd >$fname &} err]} {
3539 error_popup "Error writing commit: $err"
3540 }
3541 catch {destroy $wrcomtop}
3542 unset wrcomtop
3543}
3544
3545proc wrcomcan {} {
3546 global wrcomtop
3547
3548 catch {destroy $wrcomtop}
3549 unset wrcomtop
3550}
3551
Paul Mackerrasf1d83ba2005-08-19 22:14:28 +10003552proc listrefs {id} {
3553 global idtags idheads idotherrefs
3554
3555 set x {}
3556 if {[info exists idtags($id)]} {
3557 set x $idtags($id)
3558 }
3559 set y {}
3560 if {[info exists idheads($id)]} {
3561 set y $idheads($id)
3562 }
3563 set z {}
3564 if {[info exists idotherrefs($id)]} {
3565 set z $idotherrefs($id)
3566 }
3567 return [list $x $y $z]
3568}
3569
3570proc rereadrefs {} {
3571 global idtags idheads idotherrefs
3572 global tagids headids otherrefids
3573
3574 set refids [concat [array names idtags] \
3575 [array names idheads] [array names idotherrefs]]
3576 foreach id $refids {
3577 if {![info exists ref($id)]} {
3578 set ref($id) [listrefs $id]
3579 }
3580 }
3581 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
3582 catch {unset $v}
3583 }
3584 readrefs
3585 set refids [lsort -unique [concat $refids [array names idtags] \
3586 [array names idheads] [array names idotherrefs]]]
3587 foreach id $refids {
3588 set v [listrefs $id]
3589 if {![info exists ref($id)] || $ref($id) != $v} {
3590 redrawtags $id
3591 }
3592 }
3593}
3594
Paul Mackerras106288c2005-08-19 23:11:39 +10003595proc showtag {tag isnew} {
3596 global ctext cflist tagcontents tagids linknum
3597
3598 if {$isnew} {
3599 addtohistory [list showtag $tag 0]
3600 }
3601 $ctext conf -state normal
3602 $ctext delete 0.0 end
3603 set linknum 0
3604 if {[info exists tagcontents($tag)]} {
3605 set text $tagcontents($tag)
3606 } else {
3607 set text "Tag: $tag\nId: $tagids($tag)"
3608 }
3609 appendwithlinks $text
3610 $ctext conf -state disabled
3611 $cflist delete 0 end
3612}
3613
Paul Mackerras1d10f362005-05-15 12:55:47 +00003614proc doquit {} {
3615 global stopped
3616 set stopped 100
3617 destroy .
3618}
3619
Paul Mackerras712fcc02005-11-30 09:28:16 +11003620proc doprefs {} {
3621 global maxwidth maxgraphpct diffopts findmergefiles
3622 global oldprefs prefstop
Paul Mackerras232475d2005-11-15 10:34:03 +11003623
Paul Mackerras712fcc02005-11-30 09:28:16 +11003624 set top .gitkprefs
3625 set prefstop $top
3626 if {[winfo exists $top]} {
3627 raise $top
3628 return
Paul Mackerras757f17b2005-11-21 09:56:07 +11003629 }
Paul Mackerras712fcc02005-11-30 09:28:16 +11003630 foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
3631 set oldprefs($v) [set $v]
Paul Mackerras232475d2005-11-15 10:34:03 +11003632 }
Paul Mackerras712fcc02005-11-30 09:28:16 +11003633 toplevel $top
3634 wm title $top "Gitk preferences"
3635 label $top.ldisp -text "Commit list display options"
3636 grid $top.ldisp - -sticky w -pady 10
3637 label $top.spacer -text " "
3638 label $top.maxwidthl -text "Maximum graph width (lines)" \
3639 -font optionfont
3640 spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
3641 grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
3642 label $top.maxpctl -text "Maximum graph width (% of pane)" \
3643 -font optionfont
3644 spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
3645 grid x $top.maxpctl $top.maxpct -sticky w
3646 checkbutton $top.findm -variable findmergefiles
3647 label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
3648 -font optionfont
3649 grid $top.findm $top.findml - -sticky w
3650 label $top.ddisp -text "Diff display options"
3651 grid $top.ddisp - -sticky w -pady 10
3652 label $top.diffoptl -text "Options for diff program" \
3653 -font optionfont
3654 entry $top.diffopt -width 20 -textvariable diffopts
3655 grid x $top.diffoptl $top.diffopt -sticky w
3656 frame $top.buts
3657 button $top.buts.ok -text "OK" -command prefsok
3658 button $top.buts.can -text "Cancel" -command prefscan
3659 grid $top.buts.ok $top.buts.can
3660 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3661 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3662 grid $top.buts - - -pady 10 -sticky ew
3663}
3664
3665proc prefscan {} {
3666 global maxwidth maxgraphpct diffopts findmergefiles
3667 global oldprefs prefstop
3668
3669 foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
3670 set $v $oldprefs($v)
3671 }
3672 catch {destroy $prefstop}
3673 unset prefstop
3674}
3675
3676proc prefsok {} {
3677 global maxwidth maxgraphpct
3678 global oldprefs prefstop
3679
3680 catch {destroy $prefstop}
3681 unset prefstop
3682 if {$maxwidth != $oldprefs(maxwidth)
3683 || $maxgraphpct != $oldprefs(maxgraphpct)} {
3684 redisplay
3685 }
3686}
3687
3688proc formatdate {d} {
3689 return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
Paul Mackerras232475d2005-11-15 10:34:03 +11003690}
3691
Paul Mackerras1d10f362005-05-15 12:55:47 +00003692# defaults...
3693set datemode 0
Paul Mackerras1d10f362005-05-15 12:55:47 +00003694set diffopts "-U 5 -p"
Paul Mackerras4a2139f2005-06-29 09:47:48 +10003695set wrcomcmd "git-diff-tree --stdin -p --pretty"
Junio C Hamano671bc152005-11-27 16:12:51 -08003696
3697set gitencoding ""
3698catch {
3699 set gitencoding [exec git-repo-config --get i18n.commitencoding]
3700}
3701if {$gitencoding == ""} {
3702 set gitencoding "utf-8"
3703}
Paul Mackerras1d10f362005-05-15 12:55:47 +00003704
3705set mainfont {Helvetica 9}
Paul Mackerras1d10f362005-05-15 12:55:47 +00003706set textfont {Courier 9}
Paul Mackerrasb74fd572005-07-16 07:46:13 -04003707set findmergefiles 0
Paul Mackerras8d858d12005-08-05 09:52:16 +10003708set maxgraphpct 50
Paul Mackerrasf6075eb2005-08-18 09:30:10 +10003709set maxwidth 16
Paul Mackerras232475d2005-11-15 10:34:03 +11003710set revlistorder 0
Paul Mackerras757f17b2005-11-21 09:56:07 +11003711set fastdate 0
Paul Mackerras1d10f362005-05-15 12:55:47 +00003712
3713set colors {green red blue magenta darkgrey brown orange}
Paul Mackerras1d10f362005-05-15 12:55:47 +00003714
3715catch {source ~/.gitk}
3716
Paul Mackerras17386062005-05-18 22:51:00 +00003717set namefont $mainfont
Paul Mackerras712fcc02005-11-30 09:28:16 +11003718
3719font create optionfont -family sans-serif -size -12
Paul Mackerras17386062005-05-18 22:51:00 +00003720
Paul Mackerras1d10f362005-05-15 12:55:47 +00003721set revtreeargs {}
3722foreach arg $argv {
3723 switch -regexp -- $arg {
3724 "^$" { }
Paul Mackerras1d10f362005-05-15 12:55:47 +00003725 "^-d" { set datemode 1 }
Paul Mackerras232475d2005-11-15 10:34:03 +11003726 "^-r" { set revlistorder 1 }
Paul Mackerras1d10f362005-05-15 12:55:47 +00003727 default {
3728 lappend revtreeargs $arg
3729 }
3730 }
3731}
3732
Paul Mackerrasd6982062005-08-06 22:06:06 +10003733set history {}
3734set historyindex 0
3735
Paul Mackerras1d10f362005-05-15 12:55:47 +00003736set stopped 0
3737set redisplaying 0
Paul Mackerras0fba86b2005-05-16 23:54:58 +00003738set stuffsaved 0
Paul Mackerras74daedb2005-06-27 19:27:32 +10003739set patchnum 0
Paul Mackerras1d10f362005-05-15 12:55:47 +00003740setcoords
3741makewindow
Paul Mackerras887fe3c2005-05-21 07:35:37 +00003742readrefs
Paul Mackerras1d10f362005-05-15 12:55:47 +00003743getcommits $revtreeargs