##// END OF EJS Templates
hgk: add debug-config command to pass configuration options
Patrick Mezard -
r5393:c2ad1890 default
parent child Browse files
Show More
@@ -1,3769 +1,3782
1 #!/usr/bin/env wish
1 #!/usr/bin/env wish
2
2
3 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
3 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
4 # This program is free software; it may be used, copied, modified
4 # This program is free software; it may be used, copied, modified
5 # and distributed under the terms of the GNU General Public Licence,
5 # and distributed under the terms of the GNU General Public Licence,
6 # either version 2, or (at your option) any later version.
6 # either version 2, or (at your option) any later version.
7
7
8
8
9 # Modified version of Tip 171:
9 # Modified version of Tip 171:
10 # http://www.tcl.tk/cgi-bin/tct/tip/171.html
10 # http://www.tcl.tk/cgi-bin/tct/tip/171.html
11 #
11 #
12 # The in_mousewheel global was added to fix strange reentrancy issues.
12 # The in_mousewheel global was added to fix strange reentrancy issues.
13 # The whole snipped is activated only under windows, mouse wheel
13 # The whole snipped is activated only under windows, mouse wheel
14 # bindings working already under MacOSX and Linux.
14 # bindings working already under MacOSX and Linux.
15
15
16 if {[tk windowingsystem] eq "win32"} {
16 if {[tk windowingsystem] eq "win32"} {
17
17
18 set mw_classes [list Text Listbox Table TreeCtrl]
18 set mw_classes [list Text Listbox Table TreeCtrl]
19 foreach class $mw_classes { bind $class <MouseWheel> {} }
19 foreach class $mw_classes { bind $class <MouseWheel> {} }
20
20
21 set in_mousewheel 0
21 set in_mousewheel 0
22
22
23 proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
23 proc ::tk::MouseWheel {wFired X Y D {shifted 0}} {
24 global in_mousewheel
24 global in_mousewheel
25 if { $in_mousewheel != 0 } { return }
25 if { $in_mousewheel != 0 } { return }
26 # Set event to check based on call
26 # Set event to check based on call
27 set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
27 set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>"
28 # do not double-fire in case the class already has a binding
28 # do not double-fire in case the class already has a binding
29 if {[bind [winfo class $wFired] $evt] ne ""} { return }
29 if {[bind [winfo class $wFired] $evt] ne ""} { return }
30 # obtain the window the mouse is over
30 # obtain the window the mouse is over
31 set w [winfo containing $X $Y]
31 set w [winfo containing $X $Y]
32 # if we are outside the app, try and scroll the focus widget
32 # if we are outside the app, try and scroll the focus widget
33 if {![winfo exists $w]} { catch {set w [focus]} }
33 if {![winfo exists $w]} { catch {set w [focus]} }
34 if {[winfo exists $w]} {
34 if {[winfo exists $w]} {
35
35
36 if {[bind $w $evt] ne ""} {
36 if {[bind $w $evt] ne ""} {
37 # Awkward ... this widget has a MouseWheel binding, but to
37 # Awkward ... this widget has a MouseWheel binding, but to
38 # trigger successfully in it, we must give it focus.
38 # trigger successfully in it, we must give it focus.
39 catch {focus} old
39 catch {focus} old
40 if {$w ne $old} { focus $w }
40 if {$w ne $old} { focus $w }
41 set in_mousewheel 1
41 set in_mousewheel 1
42 event generate $w $evt -rootx $X -rooty $Y -delta $D
42 event generate $w $evt -rootx $X -rooty $Y -delta $D
43 set in_mousewheel 0
43 set in_mousewheel 0
44 if {$w ne $old} { focus $old }
44 if {$w ne $old} { focus $old }
45 return
45 return
46 }
46 }
47
47
48 # aqua and x11/win32 have different delta handling
48 # aqua and x11/win32 have different delta handling
49 if {[tk windowingsystem] ne "aqua"} {
49 if {[tk windowingsystem] ne "aqua"} {
50 set delta [expr {- ($D / 30)}]
50 set delta [expr {- ($D / 30)}]
51 } else {
51 } else {
52 set delta [expr {- ($D)}]
52 set delta [expr {- ($D)}]
53 }
53 }
54 # scrollbars have different call conventions
54 # scrollbars have different call conventions
55 if {[string match "*Scrollbar" [winfo class $w]]} {
55 if {[string match "*Scrollbar" [winfo class $w]]} {
56 catch {tk::ScrollByUnits $w \
56 catch {tk::ScrollByUnits $w \
57 [string index [$w cget -orient] 0] $delta}
57 [string index [$w cget -orient] 0] $delta}
58 } else {
58 } else {
59 set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
59 set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \
60 scroll $delta units]
60 scroll $delta units]
61 # Walking up to find the proper widget (handles cases like
61 # Walking up to find the proper widget (handles cases like
62 # embedded widgets in a canvas)
62 # embedded widgets in a canvas)
63 while {[catch $cmd] && [winfo toplevel $w] ne $w} {
63 while {[catch $cmd] && [winfo toplevel $w] ne $w} {
64 set w [winfo parent $w]
64 set w [winfo parent $w]
65 }
65 }
66 }
66 }
67 }
67 }
68 }
68 }
69
69
70 bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
70 bind all <MouseWheel> [list ::tk::MouseWheel %W %X %Y %D 0]
71
71
72 # end of win32 section
72 # end of win32 section
73 }
73 }
74
74
75
75
76 # Unify right mouse button handling.
76 # Unify right mouse button handling.
77 # See "mouse buttons on macintosh" thread on comp.lang.tcl
77 # See "mouse buttons on macintosh" thread on comp.lang.tcl
78 if {[tk windowingsystem] eq "aqua"} {
78 if {[tk windowingsystem] eq "aqua"} {
79 event add <<B3>> <Control-ButtonPress-1>
79 event add <<B3>> <Control-ButtonPress-1>
80 event add <<B3>> <Button-2>
80 event add <<B3>> <Button-2>
81 } else {
81 } else {
82 event add <<B3>> <Button-3>
82 event add <<B3>> <Button-3>
83 }
83 }
84
84
85 proc gitdir {} {
85 proc gitdir {} {
86 global env
86 global env
87 if {[info exists env(GIT_DIR)]} {
87 if {[info exists env(GIT_DIR)]} {
88 return $env(GIT_DIR)
88 return $env(GIT_DIR)
89 } else {
89 } else {
90 return ".hg"
90 return ".hg"
91 }
91 }
92 }
92 }
93
93
94 proc getcommits {rargs} {
94 proc getcommits {rargs} {
95 global commits commfd phase canv mainfont env
95 global commits commfd phase canv mainfont env
96 global startmsecs nextupdate ncmupdate
96 global startmsecs nextupdate ncmupdate
97 global ctext maincursor textcursor leftover
97 global ctext maincursor textcursor leftover
98
98
99 # check that we can find a .git directory somewhere...
99 # check that we can find a .git directory somewhere...
100 set gitdir [gitdir]
100 set gitdir [gitdir]
101 if {![file isdirectory $gitdir]} {
101 if {![file isdirectory $gitdir]} {
102 error_popup "Cannot find the git directory \"$gitdir\"."
102 error_popup "Cannot find the git directory \"$gitdir\"."
103 exit 1
103 exit 1
104 }
104 }
105 set commits {}
105 set commits {}
106 set phase getcommits
106 set phase getcommits
107 set startmsecs [clock clicks -milliseconds]
107 set startmsecs [clock clicks -milliseconds]
108 set nextupdate [expr $startmsecs + 100]
108 set nextupdate [expr $startmsecs + 100]
109 set ncmupdate 1
109 set ncmupdate 1
110 set limit 0
110 set limit 0
111 set revargs {}
111 set revargs {}
112 for {set i 0} {$i < [llength $rargs]} {incr i} {
112 for {set i 0} {$i < [llength $rargs]} {incr i} {
113 set opt [lindex $rargs $i]
113 set opt [lindex $rargs $i]
114 if {$opt == "--limit"} {
114 if {$opt == "--limit"} {
115 incr i
115 incr i
116 set limit [lindex $rargs $i]
116 set limit [lindex $rargs $i]
117 } else {
117 } else {
118 lappend revargs $opt
118 lappend revargs $opt
119 }
119 }
120 }
120 }
121 if [catch {
121 if [catch {
122 set parse_args [concat --default HEAD $revargs]
122 set parse_args [concat --default HEAD $revargs]
123 set parse_temp [eval exec {$env(HG)} --config ui.report_untrusted=false debug-rev-parse $parse_args]
123 set parse_temp [eval exec {$env(HG)} --config ui.report_untrusted=false debug-rev-parse $parse_args]
124 regsub -all "\r\n" $parse_temp "\n" parse_temp
124 regsub -all "\r\n" $parse_temp "\n" parse_temp
125 set parsed_args [split $parse_temp "\n"]
125 set parsed_args [split $parse_temp "\n"]
126 } err] {
126 } err] {
127 # if git-rev-parse failed for some reason...
127 # if git-rev-parse failed for some reason...
128 if {$rargs == {}} {
128 if {$rargs == {}} {
129 set revargs HEAD
129 set revargs HEAD
130 }
130 }
131 set parsed_args $revargs
131 set parsed_args $revargs
132 }
132 }
133 if {$limit > 0} {
133 if {$limit > 0} {
134 set parsed_args [concat -n $limit $parsed_args]
134 set parsed_args [concat -n $limit $parsed_args]
135 }
135 }
136 if [catch {
136 if [catch {
137 set commfd [open "|{$env(HG)} --config ui.report_untrusted=false debug-rev-list --header --topo-order --parents $parsed_args" r]
137 set commfd [open "|{$env(HG)} --config ui.report_untrusted=false debug-rev-list --header --topo-order --parents $parsed_args" r]
138 } err] {
138 } err] {
139 puts stderr "Error executing hg debug-rev-list: $err"
139 puts stderr "Error executing hg debug-rev-list: $err"
140 exit 1
140 exit 1
141 }
141 }
142 set leftover {}
142 set leftover {}
143 fconfigure $commfd -blocking 0 -translation lf
143 fconfigure $commfd -blocking 0 -translation lf
144 fileevent $commfd readable [list getcommitlines $commfd]
144 fileevent $commfd readable [list getcommitlines $commfd]
145 $canv delete all
145 $canv delete all
146 $canv create text 3 3 -anchor nw -text "Reading commits..." \
146 $canv create text 3 3 -anchor nw -text "Reading commits..." \
147 -font $mainfont -tags textitems
147 -font $mainfont -tags textitems
148 . config -cursor watch
148 . config -cursor watch
149 settextcursor watch
149 settextcursor watch
150 }
150 }
151
151
152 proc getcommitlines {commfd} {
152 proc getcommitlines {commfd} {
153 global commits parents cdate children
153 global commits parents cdate children
154 global commitlisted phase commitinfo nextupdate
154 global commitlisted phase commitinfo nextupdate
155 global stopped redisplaying leftover
155 global stopped redisplaying leftover
156
156
157 set stuff [read $commfd]
157 set stuff [read $commfd]
158 if {$stuff == {}} {
158 if {$stuff == {}} {
159 if {![eof $commfd]} return
159 if {![eof $commfd]} return
160 # set it blocking so we wait for the process to terminate
160 # set it blocking so we wait for the process to terminate
161 fconfigure $commfd -blocking 1
161 fconfigure $commfd -blocking 1
162 if {![catch {close $commfd} err]} {
162 if {![catch {close $commfd} err]} {
163 after idle finishcommits
163 after idle finishcommits
164 return
164 return
165 }
165 }
166 if {[string range $err 0 4] == "usage"} {
166 if {[string range $err 0 4] == "usage"} {
167 set err \
167 set err \
168 {Gitk: error reading commits: bad arguments to git-rev-list.
168 {Gitk: error reading commits: bad arguments to git-rev-list.
169 (Note: arguments to gitk are passed to git-rev-list
169 (Note: arguments to gitk are passed to git-rev-list
170 to allow selection of commits to be displayed.)}
170 to allow selection of commits to be displayed.)}
171 } else {
171 } else {
172 set err "Error reading commits: $err"
172 set err "Error reading commits: $err"
173 }
173 }
174 error_popup $err
174 error_popup $err
175 exit 1
175 exit 1
176 }
176 }
177 set start 0
177 set start 0
178 while 1 {
178 while 1 {
179 set i [string first "\0" $stuff $start]
179 set i [string first "\0" $stuff $start]
180 if {$i < 0} {
180 if {$i < 0} {
181 append leftover [string range $stuff $start end]
181 append leftover [string range $stuff $start end]
182 return
182 return
183 }
183 }
184 set cmit [string range $stuff $start [expr {$i - 1}]]
184 set cmit [string range $stuff $start [expr {$i - 1}]]
185 if {$start == 0} {
185 if {$start == 0} {
186 set cmit "$leftover$cmit"
186 set cmit "$leftover$cmit"
187 set leftover {}
187 set leftover {}
188 }
188 }
189 set start [expr {$i + 1}]
189 set start [expr {$i + 1}]
190 regsub -all "\r\n" $cmit "\n" cmit
190 regsub -all "\r\n" $cmit "\n" cmit
191 set j [string first "\n" $cmit]
191 set j [string first "\n" $cmit]
192 set ok 0
192 set ok 0
193 if {$j >= 0} {
193 if {$j >= 0} {
194 set ids [string range $cmit 0 [expr {$j - 1}]]
194 set ids [string range $cmit 0 [expr {$j - 1}]]
195 set ok 1
195 set ok 1
196 foreach id $ids {
196 foreach id $ids {
197 if {![regexp {^[0-9a-f]{12}$} $id]} {
197 if {![regexp {^[0-9a-f]{12}$} $id]} {
198 set ok 0
198 set ok 0
199 break
199 break
200 }
200 }
201 }
201 }
202 }
202 }
203 if {!$ok} {
203 if {!$ok} {
204 set shortcmit $cmit
204 set shortcmit $cmit
205 if {[string length $shortcmit] > 80} {
205 if {[string length $shortcmit] > 80} {
206 set shortcmit "[string range $shortcmit 0 80]..."
206 set shortcmit "[string range $shortcmit 0 80]..."
207 }
207 }
208 error_popup "Can't parse hg debug-rev-list output: {$shortcmit}"
208 error_popup "Can't parse hg debug-rev-list output: {$shortcmit}"
209 exit 1
209 exit 1
210 }
210 }
211 set id [lindex $ids 0]
211 set id [lindex $ids 0]
212 set olds [lrange $ids 1 end]
212 set olds [lrange $ids 1 end]
213 set cmit [string range $cmit [expr {$j + 1}] end]
213 set cmit [string range $cmit [expr {$j + 1}] end]
214 lappend commits $id
214 lappend commits $id
215 set commitlisted($id) 1
215 set commitlisted($id) 1
216 parsecommit $id $cmit 1 [lrange $ids 1 end]
216 parsecommit $id $cmit 1 [lrange $ids 1 end]
217 drawcommit $id
217 drawcommit $id
218 if {[clock clicks -milliseconds] >= $nextupdate} {
218 if {[clock clicks -milliseconds] >= $nextupdate} {
219 doupdate 1
219 doupdate 1
220 }
220 }
221 while {$redisplaying} {
221 while {$redisplaying} {
222 set redisplaying 0
222 set redisplaying 0
223 if {$stopped == 1} {
223 if {$stopped == 1} {
224 set stopped 0
224 set stopped 0
225 set phase "getcommits"
225 set phase "getcommits"
226 foreach id $commits {
226 foreach id $commits {
227 drawcommit $id
227 drawcommit $id
228 if {$stopped} break
228 if {$stopped} break
229 if {[clock clicks -milliseconds] >= $nextupdate} {
229 if {[clock clicks -milliseconds] >= $nextupdate} {
230 doupdate 1
230 doupdate 1
231 }
231 }
232 }
232 }
233 }
233 }
234 }
234 }
235 }
235 }
236 }
236 }
237
237
238 proc doupdate {reading} {
238 proc doupdate {reading} {
239 global commfd nextupdate numcommits ncmupdate
239 global commfd nextupdate numcommits ncmupdate
240
240
241 if {$reading} {
241 if {$reading} {
242 fileevent $commfd readable {}
242 fileevent $commfd readable {}
243 }
243 }
244 update
244 update
245 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
245 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
246 if {$numcommits < 100} {
246 if {$numcommits < 100} {
247 set ncmupdate [expr {$numcommits + 1}]
247 set ncmupdate [expr {$numcommits + 1}]
248 } elseif {$numcommits < 10000} {
248 } elseif {$numcommits < 10000} {
249 set ncmupdate [expr {$numcommits + 10}]
249 set ncmupdate [expr {$numcommits + 10}]
250 } else {
250 } else {
251 set ncmupdate [expr {$numcommits + 100}]
251 set ncmupdate [expr {$numcommits + 100}]
252 }
252 }
253 if {$reading} {
253 if {$reading} {
254 fileevent $commfd readable [list getcommitlines $commfd]
254 fileevent $commfd readable [list getcommitlines $commfd]
255 }
255 }
256 }
256 }
257
257
258 proc readcommit {id} {
258 proc readcommit {id} {
259 global env
259 global env
260 if [catch {set contents [exec $env(HG) --config ui.report_untrusted=false debug-cat-file commit $id]}] return
260 if [catch {set contents [exec $env(HG) --config ui.report_untrusted=false debug-cat-file commit $id]}] return
261 parsecommit $id $contents 0 {}
261 parsecommit $id $contents 0 {}
262 }
262 }
263
263
264 proc parsecommit {id contents listed olds} {
264 proc parsecommit {id contents listed olds} {
265 global commitinfo children nchildren parents nparents cdate ncleft
265 global commitinfo children nchildren parents nparents cdate ncleft
266
266
267 set inhdr 1
267 set inhdr 1
268 set comment {}
268 set comment {}
269 set headline {}
269 set headline {}
270 set auname {}
270 set auname {}
271 set audate {}
271 set audate {}
272 set comname {}
272 set comname {}
273 set comdate {}
273 set comdate {}
274 set rev {}
274 set rev {}
275 if {![info exists nchildren($id)]} {
275 if {![info exists nchildren($id)]} {
276 set children($id) {}
276 set children($id) {}
277 set nchildren($id) 0
277 set nchildren($id) 0
278 set ncleft($id) 0
278 set ncleft($id) 0
279 }
279 }
280 set parents($id) $olds
280 set parents($id) $olds
281 set nparents($id) [llength $olds]
281 set nparents($id) [llength $olds]
282 foreach p $olds {
282 foreach p $olds {
283 if {![info exists nchildren($p)]} {
283 if {![info exists nchildren($p)]} {
284 set children($p) [list $id]
284 set children($p) [list $id]
285 set nchildren($p) 1
285 set nchildren($p) 1
286 set ncleft($p) 1
286 set ncleft($p) 1
287 } elseif {[lsearch -exact $children($p) $id] < 0} {
287 } elseif {[lsearch -exact $children($p) $id] < 0} {
288 lappend children($p) $id
288 lappend children($p) $id
289 incr nchildren($p)
289 incr nchildren($p)
290 incr ncleft($p)
290 incr ncleft($p)
291 }
291 }
292 }
292 }
293 regsub -all "\r\n" $contents "\n" contents
293 regsub -all "\r\n" $contents "\n" contents
294 foreach line [split $contents "\n"] {
294 foreach line [split $contents "\n"] {
295 if {$inhdr} {
295 if {$inhdr} {
296 set line [split $line]
296 set line [split $line]
297 if {$line == {}} {
297 if {$line == {}} {
298 set inhdr 0
298 set inhdr 0
299 } else {
299 } else {
300 set tag [lindex $line 0]
300 set tag [lindex $line 0]
301 if {$tag == "author"} {
301 if {$tag == "author"} {
302 set x [expr {[llength $line] - 2}]
302 set x [expr {[llength $line] - 2}]
303 set audate [lindex $line $x]
303 set audate [lindex $line $x]
304 set auname [join [lrange $line 1 [expr {$x - 1}]]]
304 set auname [join [lrange $line 1 [expr {$x - 1}]]]
305 } elseif {$tag == "committer"} {
305 } elseif {$tag == "committer"} {
306 set x [expr {[llength $line] - 2}]
306 set x [expr {[llength $line] - 2}]
307 set comdate [lindex $line $x]
307 set comdate [lindex $line $x]
308 set comname [join [lrange $line 1 [expr {$x - 1}]]]
308 set comname [join [lrange $line 1 [expr {$x - 1}]]]
309 } elseif {$tag == "revision"} {
309 } elseif {$tag == "revision"} {
310 set rev [lindex $line 1]
310 set rev [lindex $line 1]
311 }
311 }
312 }
312 }
313 } else {
313 } else {
314 if {$comment == {}} {
314 if {$comment == {}} {
315 set headline [string trim $line]
315 set headline [string trim $line]
316 } else {
316 } else {
317 append comment "\n"
317 append comment "\n"
318 }
318 }
319 if {!$listed} {
319 if {!$listed} {
320 # git-rev-list indents the comment by 4 spaces;
320 # git-rev-list indents the comment by 4 spaces;
321 # if we got this via git-cat-file, add the indentation
321 # if we got this via git-cat-file, add the indentation
322 append comment " "
322 append comment " "
323 }
323 }
324 append comment $line
324 append comment $line
325 }
325 }
326 }
326 }
327 if {$audate != {}} {
327 if {$audate != {}} {
328 set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
328 set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
329 }
329 }
330 if {$comdate != {}} {
330 if {$comdate != {}} {
331 set cdate($id) $comdate
331 set cdate($id) $comdate
332 set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
332 set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
333 }
333 }
334 set commitinfo($id) [list $headline $auname $audate \
334 set commitinfo($id) [list $headline $auname $audate \
335 $comname $comdate $comment $rev]
335 $comname $comdate $comment $rev]
336 }
336 }
337
337
338 proc readrefs {} {
338 proc readrefs {} {
339 global tagids idtags headids idheads tagcontents env
339 global tagids idtags headids idheads tagcontents env
340
340
341 set tags [exec $env(HG) --config ui.report_untrusted=false tags]
341 set tags [exec $env(HG) --config ui.report_untrusted=false tags]
342 regsub -all "\r\n" $tags "\n" tags
342 regsub -all "\r\n" $tags "\n" tags
343 set lines [split $tags "\n"]
343 set lines [split $tags "\n"]
344 foreach f $lines {
344 foreach f $lines {
345 regexp {(\S+)$} $f full
345 regexp {(\S+)$} $f full
346 regsub {\s+(\S+)$} $f "" direct
346 regsub {\s+(\S+)$} $f "" direct
347 set sha [split $full ':']
347 set sha [split $full ':']
348 set tag [lindex $sha 1]
348 set tag [lindex $sha 1]
349 lappend tagids($direct) $tag
349 lappend tagids($direct) $tag
350 lappend idtags($tag) $direct
350 lappend idtags($tag) $direct
351 }
351 }
352 }
352 }
353
353
354 proc readotherrefs {base dname excl} {
354 proc readotherrefs {base dname excl} {
355 global otherrefids idotherrefs
355 global otherrefids idotherrefs
356
356
357 set git [gitdir]
357 set git [gitdir]
358 set files [glob -nocomplain -types f [file join $git $base *]]
358 set files [glob -nocomplain -types f [file join $git $base *]]
359 foreach f $files {
359 foreach f $files {
360 catch {
360 catch {
361 set fd [open $f r]
361 set fd [open $f r]
362 set line [read $fd 40]
362 set line [read $fd 40]
363 if {[regexp {^[0-9a-f]{12}} $line id]} {
363 if {[regexp {^[0-9a-f]{12}} $line id]} {
364 set name "$dname[file tail $f]"
364 set name "$dname[file tail $f]"
365 set otherrefids($name) $id
365 set otherrefids($name) $id
366 lappend idotherrefs($id) $name
366 lappend idotherrefs($id) $name
367 }
367 }
368 close $fd
368 close $fd
369 }
369 }
370 }
370 }
371 set dirs [glob -nocomplain -types d [file join $git $base *]]
371 set dirs [glob -nocomplain -types d [file join $git $base *]]
372 foreach d $dirs {
372 foreach d $dirs {
373 set dir [file tail $d]
373 set dir [file tail $d]
374 if {[lsearch -exact $excl $dir] >= 0} continue
374 if {[lsearch -exact $excl $dir] >= 0} continue
375 readotherrefs [file join $base $dir] "$dname$dir/" {}
375 readotherrefs [file join $base $dir] "$dname$dir/" {}
376 }
376 }
377 }
377 }
378
378
379 proc allcansmousewheel {delta} {
379 proc allcansmousewheel {delta} {
380 set delta [expr -5*(int($delta)/abs($delta))]
380 set delta [expr -5*(int($delta)/abs($delta))]
381 allcanvs yview scroll $delta units
381 allcanvs yview scroll $delta units
382 }
382 }
383
383
384 proc error_popup msg {
384 proc error_popup msg {
385 set w .error
385 set w .error
386 toplevel $w
386 toplevel $w
387 wm transient $w .
387 wm transient $w .
388 message $w.m -text $msg -justify center -aspect 400
388 message $w.m -text $msg -justify center -aspect 400
389 pack $w.m -side top -fill x -padx 20 -pady 20
389 pack $w.m -side top -fill x -padx 20 -pady 20
390 button $w.ok -text OK -command "destroy $w"
390 button $w.ok -text OK -command "destroy $w"
391 pack $w.ok -side bottom -fill x
391 pack $w.ok -side bottom -fill x
392 bind $w <Visibility> "grab $w; focus $w"
392 bind $w <Visibility> "grab $w; focus $w"
393 tkwait window $w
393 tkwait window $w
394 }
394 }
395
395
396 proc makewindow {} {
396 proc makewindow {} {
397 global canv canv2 canv3 linespc charspc ctext cflist textfont
397 global canv canv2 canv3 linespc charspc ctext cflist textfont
398 global findtype findtypemenu findloc findstring fstring geometry
398 global findtype findtypemenu findloc findstring fstring geometry
399 global entries sha1entry sha1string sha1but
399 global entries sha1entry sha1string sha1but
400 global maincursor textcursor curtextcursor
400 global maincursor textcursor curtextcursor
401 global rowctxmenu gaudydiff mergemax
401 global rowctxmenu gaudydiff mergemax
402
402
403 menu .bar
403 menu .bar
404 .bar add cascade -label "File" -menu .bar.file
404 .bar add cascade -label "File" -menu .bar.file
405 menu .bar.file
405 menu .bar.file
406 .bar.file add command -label "Reread references" -command rereadrefs
406 .bar.file add command -label "Reread references" -command rereadrefs
407 .bar.file add command -label "Quit" -command doquit
407 .bar.file add command -label "Quit" -command doquit
408 menu .bar.help
408 menu .bar.help
409 .bar add cascade -label "Help" -menu .bar.help
409 .bar add cascade -label "Help" -menu .bar.help
410 .bar.help add command -label "About gitk" -command about
410 .bar.help add command -label "About gitk" -command about
411 . configure -menu .bar
411 . configure -menu .bar
412
412
413 if {![info exists geometry(canv1)]} {
413 if {![info exists geometry(canv1)]} {
414 set geometry(canv1) [expr 45 * $charspc]
414 set geometry(canv1) [expr 45 * $charspc]
415 set geometry(canv2) [expr 30 * $charspc]
415 set geometry(canv2) [expr 30 * $charspc]
416 set geometry(canv3) [expr 15 * $charspc]
416 set geometry(canv3) [expr 15 * $charspc]
417 set geometry(canvh) [expr 25 * $linespc + 4]
417 set geometry(canvh) [expr 25 * $linespc + 4]
418 set geometry(ctextw) 80
418 set geometry(ctextw) 80
419 set geometry(ctexth) 30
419 set geometry(ctexth) 30
420 set geometry(cflistw) 30
420 set geometry(cflistw) 30
421 }
421 }
422 panedwindow .ctop -orient vertical
422 panedwindow .ctop -orient vertical
423 if {[info exists geometry(width)]} {
423 if {[info exists geometry(width)]} {
424 .ctop conf -width $geometry(width) -height $geometry(height)
424 .ctop conf -width $geometry(width) -height $geometry(height)
425 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
425 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
426 set geometry(ctexth) [expr {($texth - 8) /
426 set geometry(ctexth) [expr {($texth - 8) /
427 [font metrics $textfont -linespace]}]
427 [font metrics $textfont -linespace]}]
428 }
428 }
429 frame .ctop.top
429 frame .ctop.top
430 frame .ctop.top.bar
430 frame .ctop.top.bar
431 pack .ctop.top.bar -side bottom -fill x
431 pack .ctop.top.bar -side bottom -fill x
432 set cscroll .ctop.top.csb
432 set cscroll .ctop.top.csb
433 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
433 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
434 pack $cscroll -side right -fill y
434 pack $cscroll -side right -fill y
435 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
435 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
436 pack .ctop.top.clist -side top -fill both -expand 1
436 pack .ctop.top.clist -side top -fill both -expand 1
437 .ctop add .ctop.top
437 .ctop add .ctop.top
438 set canv .ctop.top.clist.canv
438 set canv .ctop.top.clist.canv
439 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
439 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
440 -bg white -bd 0 \
440 -bg white -bd 0 \
441 -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey
441 -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey
442 .ctop.top.clist add $canv
442 .ctop.top.clist add $canv
443 set canv2 .ctop.top.clist.canv2
443 set canv2 .ctop.top.clist.canv2
444 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
444 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
445 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
445 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
446 .ctop.top.clist add $canv2
446 .ctop.top.clist add $canv2
447 set canv3 .ctop.top.clist.canv3
447 set canv3 .ctop.top.clist.canv3
448 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
448 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
449 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
449 -bg white -bd 0 -yscrollincr $linespc -selectbackground grey
450 .ctop.top.clist add $canv3
450 .ctop.top.clist add $canv3
451 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
451 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
452
452
453 set sha1entry .ctop.top.bar.sha1
453 set sha1entry .ctop.top.bar.sha1
454 set entries $sha1entry
454 set entries $sha1entry
455 set sha1but .ctop.top.bar.sha1label
455 set sha1but .ctop.top.bar.sha1label
456 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
456 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
457 -command gotocommit -width 8
457 -command gotocommit -width 8
458 $sha1but conf -disabledforeground [$sha1but cget -foreground]
458 $sha1but conf -disabledforeground [$sha1but cget -foreground]
459 pack .ctop.top.bar.sha1label -side left
459 pack .ctop.top.bar.sha1label -side left
460 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
460 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
461 trace add variable sha1string write sha1change
461 trace add variable sha1string write sha1change
462 pack $sha1entry -side left -pady 2
462 pack $sha1entry -side left -pady 2
463
463
464 image create bitmap bm-left -data {
464 image create bitmap bm-left -data {
465 #define left_width 16
465 #define left_width 16
466 #define left_height 16
466 #define left_height 16
467 static unsigned char left_bits[] = {
467 static unsigned char left_bits[] = {
468 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
468 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
469 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
469 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
470 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
470 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
471 }
471 }
472 image create bitmap bm-right -data {
472 image create bitmap bm-right -data {
473 #define right_width 16
473 #define right_width 16
474 #define right_height 16
474 #define right_height 16
475 static unsigned char right_bits[] = {
475 static unsigned char right_bits[] = {
476 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
476 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
477 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
477 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
478 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
478 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
479 }
479 }
480 button .ctop.top.bar.leftbut -image bm-left -command goback \
480 button .ctop.top.bar.leftbut -image bm-left -command goback \
481 -state disabled -width 26
481 -state disabled -width 26
482 pack .ctop.top.bar.leftbut -side left -fill y
482 pack .ctop.top.bar.leftbut -side left -fill y
483 button .ctop.top.bar.rightbut -image bm-right -command goforw \
483 button .ctop.top.bar.rightbut -image bm-right -command goforw \
484 -state disabled -width 26
484 -state disabled -width 26
485 pack .ctop.top.bar.rightbut -side left -fill y
485 pack .ctop.top.bar.rightbut -side left -fill y
486
486
487 button .ctop.top.bar.findbut -text "Find" -command dofind
487 button .ctop.top.bar.findbut -text "Find" -command dofind
488 pack .ctop.top.bar.findbut -side left
488 pack .ctop.top.bar.findbut -side left
489 set findstring {}
489 set findstring {}
490 set fstring .ctop.top.bar.findstring
490 set fstring .ctop.top.bar.findstring
491 lappend entries $fstring
491 lappend entries $fstring
492 entry $fstring -width 30 -font $textfont -textvariable findstring
492 entry $fstring -width 30 -font $textfont -textvariable findstring
493 pack $fstring -side left -expand 1 -fill x
493 pack $fstring -side left -expand 1 -fill x
494 set findtype Exact
494 set findtype Exact
495 set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
495 set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
496 findtype Exact IgnCase Regexp]
496 findtype Exact IgnCase Regexp]
497 set findloc "All fields"
497 set findloc "All fields"
498 tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
498 tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
499 Comments Author Committer Files Pickaxe
499 Comments Author Committer Files Pickaxe
500 pack .ctop.top.bar.findloc -side right
500 pack .ctop.top.bar.findloc -side right
501 pack .ctop.top.bar.findtype -side right
501 pack .ctop.top.bar.findtype -side right
502 # for making sure type==Exact whenever loc==Pickaxe
502 # for making sure type==Exact whenever loc==Pickaxe
503 trace add variable findloc write findlocchange
503 trace add variable findloc write findlocchange
504
504
505 panedwindow .ctop.cdet -orient horizontal
505 panedwindow .ctop.cdet -orient horizontal
506 .ctop add .ctop.cdet
506 .ctop add .ctop.cdet
507 frame .ctop.cdet.left
507 frame .ctop.cdet.left
508 set ctext .ctop.cdet.left.ctext
508 set ctext .ctop.cdet.left.ctext
509 text $ctext -bg white -state disabled -font $textfont \
509 text $ctext -bg white -state disabled -font $textfont \
510 -width $geometry(ctextw) -height $geometry(ctexth) \
510 -width $geometry(ctextw) -height $geometry(ctexth) \
511 -yscrollcommand ".ctop.cdet.left.sb set" \
511 -yscrollcommand ".ctop.cdet.left.sb set" \
512 -xscrollcommand ".ctop.cdet.left.hb set" -wrap none
512 -xscrollcommand ".ctop.cdet.left.hb set" -wrap none
513 scrollbar .ctop.cdet.left.sb -command "$ctext yview"
513 scrollbar .ctop.cdet.left.sb -command "$ctext yview"
514 scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview"
514 scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview"
515 pack .ctop.cdet.left.sb -side right -fill y
515 pack .ctop.cdet.left.sb -side right -fill y
516 pack .ctop.cdet.left.hb -side bottom -fill x
516 pack .ctop.cdet.left.hb -side bottom -fill x
517 pack $ctext -side left -fill both -expand 1
517 pack $ctext -side left -fill both -expand 1
518 .ctop.cdet add .ctop.cdet.left
518 .ctop.cdet add .ctop.cdet.left
519
519
520 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
520 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
521 if {$gaudydiff} {
521 if {$gaudydiff} {
522 $ctext tag conf hunksep -back blue -fore white
522 $ctext tag conf hunksep -back blue -fore white
523 $ctext tag conf d0 -back "#ff8080"
523 $ctext tag conf d0 -back "#ff8080"
524 $ctext tag conf d1 -back green
524 $ctext tag conf d1 -back green
525 } else {
525 } else {
526 $ctext tag conf hunksep -fore blue
526 $ctext tag conf hunksep -fore blue
527 $ctext tag conf d0 -fore red
527 $ctext tag conf d0 -fore red
528 $ctext tag conf d1 -fore "#00a000"
528 $ctext tag conf d1 -fore "#00a000"
529 $ctext tag conf m0 -fore red
529 $ctext tag conf m0 -fore red
530 $ctext tag conf m1 -fore blue
530 $ctext tag conf m1 -fore blue
531 $ctext tag conf m2 -fore green
531 $ctext tag conf m2 -fore green
532 $ctext tag conf m3 -fore purple
532 $ctext tag conf m3 -fore purple
533 $ctext tag conf m4 -fore brown
533 $ctext tag conf m4 -fore brown
534 $ctext tag conf mmax -fore darkgrey
534 $ctext tag conf mmax -fore darkgrey
535 set mergemax 5
535 set mergemax 5
536 $ctext tag conf mresult -font [concat $textfont bold]
536 $ctext tag conf mresult -font [concat $textfont bold]
537 $ctext tag conf msep -font [concat $textfont bold]
537 $ctext tag conf msep -font [concat $textfont bold]
538 $ctext tag conf found -back yellow
538 $ctext tag conf found -back yellow
539 }
539 }
540
540
541 frame .ctop.cdet.right
541 frame .ctop.cdet.right
542 set cflist .ctop.cdet.right.cfiles
542 set cflist .ctop.cdet.right.cfiles
543 listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
543 listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
544 -yscrollcommand ".ctop.cdet.right.sb set"
544 -yscrollcommand ".ctop.cdet.right.sb set"
545 scrollbar .ctop.cdet.right.sb -command "$cflist yview"
545 scrollbar .ctop.cdet.right.sb -command "$cflist yview"
546 pack .ctop.cdet.right.sb -side right -fill y
546 pack .ctop.cdet.right.sb -side right -fill y
547 pack $cflist -side left -fill both -expand 1
547 pack $cflist -side left -fill both -expand 1
548 .ctop.cdet add .ctop.cdet.right
548 .ctop.cdet add .ctop.cdet.right
549 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
549 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
550
550
551 pack .ctop -side top -fill both -expand 1
551 pack .ctop -side top -fill both -expand 1
552
552
553 bindall <1> {selcanvline %W %x %y}
553 bindall <1> {selcanvline %W %x %y}
554 #bindall <B1-Motion> {selcanvline %W %x %y}
554 #bindall <B1-Motion> {selcanvline %W %x %y}
555 bindall <MouseWheel> "allcansmousewheel %D"
555 bindall <MouseWheel> "allcansmousewheel %D"
556 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
556 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
557 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
557 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
558 bindall <2> "allcanvs scan mark 0 %y"
558 bindall <2> "allcanvs scan mark 0 %y"
559 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
559 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
560 bind . <Key-Up> "selnextline -1"
560 bind . <Key-Up> "selnextline -1"
561 bind . <Key-Down> "selnextline 1"
561 bind . <Key-Down> "selnextline 1"
562 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
562 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
563 bind . <Key-Next> "allcanvs yview scroll 1 pages"
563 bind . <Key-Next> "allcanvs yview scroll 1 pages"
564 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
564 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
565 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
565 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
566 bindkey <Key-space> "$ctext yview scroll 1 pages"
566 bindkey <Key-space> "$ctext yview scroll 1 pages"
567 bindkey p "selnextline -1"
567 bindkey p "selnextline -1"
568 bindkey n "selnextline 1"
568 bindkey n "selnextline 1"
569 bindkey b "$ctext yview scroll -1 pages"
569 bindkey b "$ctext yview scroll -1 pages"
570 bindkey d "$ctext yview scroll 18 units"
570 bindkey d "$ctext yview scroll 18 units"
571 bindkey u "$ctext yview scroll -18 units"
571 bindkey u "$ctext yview scroll -18 units"
572 bindkey / {findnext 1}
572 bindkey / {findnext 1}
573 bindkey <Key-Return> {findnext 0}
573 bindkey <Key-Return> {findnext 0}
574 bindkey ? findprev
574 bindkey ? findprev
575 bindkey f nextfile
575 bindkey f nextfile
576 bind . <Control-q> doquit
576 bind . <Control-q> doquit
577 bind . <Control-w> doquit
577 bind . <Control-w> doquit
578 bind . <Control-f> dofind
578 bind . <Control-f> dofind
579 bind . <Control-g> {findnext 0}
579 bind . <Control-g> {findnext 0}
580 bind . <Control-r> findprev
580 bind . <Control-r> findprev
581 bind . <Control-equal> {incrfont 1}
581 bind . <Control-equal> {incrfont 1}
582 bind . <Control-KP_Add> {incrfont 1}
582 bind . <Control-KP_Add> {incrfont 1}
583 bind . <Control-minus> {incrfont -1}
583 bind . <Control-minus> {incrfont -1}
584 bind . <Control-KP_Subtract> {incrfont -1}
584 bind . <Control-KP_Subtract> {incrfont -1}
585 bind $cflist <<ListboxSelect>> listboxsel
585 bind $cflist <<ListboxSelect>> listboxsel
586 bind . <Destroy> {savestuff %W}
586 bind . <Destroy> {savestuff %W}
587 bind . <Button-1> "click %W"
587 bind . <Button-1> "click %W"
588 bind $fstring <Key-Return> dofind
588 bind $fstring <Key-Return> dofind
589 bind $sha1entry <Key-Return> gotocommit
589 bind $sha1entry <Key-Return> gotocommit
590 bind $sha1entry <<PasteSelection>> clearsha1
590 bind $sha1entry <<PasteSelection>> clearsha1
591
591
592 set maincursor [. cget -cursor]
592 set maincursor [. cget -cursor]
593 set textcursor [$ctext cget -cursor]
593 set textcursor [$ctext cget -cursor]
594 set curtextcursor $textcursor
594 set curtextcursor $textcursor
595
595
596 set rowctxmenu .rowctxmenu
596 set rowctxmenu .rowctxmenu
597 menu $rowctxmenu -tearoff 0
597 menu $rowctxmenu -tearoff 0
598 $rowctxmenu add command -label "Diff this -> selected" \
598 $rowctxmenu add command -label "Diff this -> selected" \
599 -command {diffvssel 0}
599 -command {diffvssel 0}
600 $rowctxmenu add command -label "Diff selected -> this" \
600 $rowctxmenu add command -label "Diff selected -> this" \
601 -command {diffvssel 1}
601 -command {diffvssel 1}
602 $rowctxmenu add command -label "Make patch" -command mkpatch
602 $rowctxmenu add command -label "Make patch" -command mkpatch
603 $rowctxmenu add command -label "Create tag" -command mktag
603 $rowctxmenu add command -label "Create tag" -command mktag
604 $rowctxmenu add command -label "Write commit to file" -command writecommit
604 $rowctxmenu add command -label "Write commit to file" -command writecommit
605 }
605 }
606
606
607 # when we make a key binding for the toplevel, make sure
607 # when we make a key binding for the toplevel, make sure
608 # it doesn't get triggered when that key is pressed in the
608 # it doesn't get triggered when that key is pressed in the
609 # find string entry widget.
609 # find string entry widget.
610 proc bindkey {ev script} {
610 proc bindkey {ev script} {
611 global entries
611 global entries
612 bind . $ev $script
612 bind . $ev $script
613 set escript [bind Entry $ev]
613 set escript [bind Entry $ev]
614 if {$escript == {}} {
614 if {$escript == {}} {
615 set escript [bind Entry <Key>]
615 set escript [bind Entry <Key>]
616 }
616 }
617 foreach e $entries {
617 foreach e $entries {
618 bind $e $ev "$escript; break"
618 bind $e $ev "$escript; break"
619 }
619 }
620 }
620 }
621
621
622 # set the focus back to the toplevel for any click outside
622 # set the focus back to the toplevel for any click outside
623 # the entry widgets
623 # the entry widgets
624 proc click {w} {
624 proc click {w} {
625 global entries
625 global entries
626 foreach e $entries {
626 foreach e $entries {
627 if {$w == $e} return
627 if {$w == $e} return
628 }
628 }
629 focus .
629 focus .
630 }
630 }
631
631
632 proc savestuff {w} {
632 proc savestuff {w} {
633 global canv canv2 canv3 ctext cflist mainfont textfont
633 global canv canv2 canv3 ctext cflist mainfont textfont
634 global stuffsaved findmergefiles gaudydiff maxgraphpct
634 global stuffsaved findmergefiles gaudydiff maxgraphpct
635 global maxwidth
635 global maxwidth
636
636
637 if {$stuffsaved} return
637 if {$stuffsaved} return
638 if {![winfo viewable .]} return
638 if {![winfo viewable .]} return
639 catch {
639 catch {
640 set f [open "~/.gitk-new" w]
640 set f [open "~/.gitk-new" w]
641 puts $f [list set mainfont $mainfont]
641 puts $f [list set mainfont $mainfont]
642 puts $f [list set textfont $textfont]
642 puts $f [list set textfont $textfont]
643 puts $f [list set findmergefiles $findmergefiles]
643 puts $f [list set findmergefiles $findmergefiles]
644 puts $f [list set gaudydiff $gaudydiff]
644 puts $f [list set gaudydiff $gaudydiff]
645 puts $f [list set maxgraphpct $maxgraphpct]
645 puts $f [list set maxgraphpct $maxgraphpct]
646 puts $f [list set maxwidth $maxwidth]
646 puts $f [list set maxwidth $maxwidth]
647 puts $f "set geometry(width) [winfo width .ctop]"
647 puts $f "set geometry(width) [winfo width .ctop]"
648 puts $f "set geometry(height) [winfo height .ctop]"
648 puts $f "set geometry(height) [winfo height .ctop]"
649 puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
649 puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
650 puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
650 puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
651 puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
651 puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
652 puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
652 puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
653 set wid [expr {([winfo width $ctext] - 8) \
653 set wid [expr {([winfo width $ctext] - 8) \
654 / [font measure $textfont "0"]}]
654 / [font measure $textfont "0"]}]
655 puts $f "set geometry(ctextw) $wid"
655 puts $f "set geometry(ctextw) $wid"
656 set wid [expr {([winfo width $cflist] - 11) \
656 set wid [expr {([winfo width $cflist] - 11) \
657 / [font measure [$cflist cget -font] "0"]}]
657 / [font measure [$cflist cget -font] "0"]}]
658 puts $f "set geometry(cflistw) $wid"
658 puts $f "set geometry(cflistw) $wid"
659 close $f
659 close $f
660 file rename -force "~/.gitk-new" "~/.gitk"
660 file rename -force "~/.gitk-new" "~/.gitk"
661 }
661 }
662 set stuffsaved 1
662 set stuffsaved 1
663 }
663 }
664
664
665 proc resizeclistpanes {win w} {
665 proc resizeclistpanes {win w} {
666 global oldwidth
666 global oldwidth
667 if [info exists oldwidth($win)] {
667 if [info exists oldwidth($win)] {
668 set s0 [$win sash coord 0]
668 set s0 [$win sash coord 0]
669 set s1 [$win sash coord 1]
669 set s1 [$win sash coord 1]
670 if {$w < 60} {
670 if {$w < 60} {
671 set sash0 [expr {int($w/2 - 2)}]
671 set sash0 [expr {int($w/2 - 2)}]
672 set sash1 [expr {int($w*5/6 - 2)}]
672 set sash1 [expr {int($w*5/6 - 2)}]
673 } else {
673 } else {
674 set factor [expr {1.0 * $w / $oldwidth($win)}]
674 set factor [expr {1.0 * $w / $oldwidth($win)}]
675 set sash0 [expr {int($factor * [lindex $s0 0])}]
675 set sash0 [expr {int($factor * [lindex $s0 0])}]
676 set sash1 [expr {int($factor * [lindex $s1 0])}]
676 set sash1 [expr {int($factor * [lindex $s1 0])}]
677 if {$sash0 < 30} {
677 if {$sash0 < 30} {
678 set sash0 30
678 set sash0 30
679 }
679 }
680 if {$sash1 < $sash0 + 20} {
680 if {$sash1 < $sash0 + 20} {
681 set sash1 [expr $sash0 + 20]
681 set sash1 [expr $sash0 + 20]
682 }
682 }
683 if {$sash1 > $w - 10} {
683 if {$sash1 > $w - 10} {
684 set sash1 [expr $w - 10]
684 set sash1 [expr $w - 10]
685 if {$sash0 > $sash1 - 20} {
685 if {$sash0 > $sash1 - 20} {
686 set sash0 [expr $sash1 - 20]
686 set sash0 [expr $sash1 - 20]
687 }
687 }
688 }
688 }
689 }
689 }
690 $win sash place 0 $sash0 [lindex $s0 1]
690 $win sash place 0 $sash0 [lindex $s0 1]
691 $win sash place 1 $sash1 [lindex $s1 1]
691 $win sash place 1 $sash1 [lindex $s1 1]
692 }
692 }
693 set oldwidth($win) $w
693 set oldwidth($win) $w
694 }
694 }
695
695
696 proc resizecdetpanes {win w} {
696 proc resizecdetpanes {win w} {
697 global oldwidth
697 global oldwidth
698 if [info exists oldwidth($win)] {
698 if [info exists oldwidth($win)] {
699 set s0 [$win sash coord 0]
699 set s0 [$win sash coord 0]
700 if {$w < 60} {
700 if {$w < 60} {
701 set sash0 [expr {int($w*3/4 - 2)}]
701 set sash0 [expr {int($w*3/4 - 2)}]
702 } else {
702 } else {
703 set factor [expr {1.0 * $w / $oldwidth($win)}]
703 set factor [expr {1.0 * $w / $oldwidth($win)}]
704 set sash0 [expr {int($factor * [lindex $s0 0])}]
704 set sash0 [expr {int($factor * [lindex $s0 0])}]
705 if {$sash0 < 45} {
705 if {$sash0 < 45} {
706 set sash0 45
706 set sash0 45
707 }
707 }
708 if {$sash0 > $w - 15} {
708 if {$sash0 > $w - 15} {
709 set sash0 [expr $w - 15]
709 set sash0 [expr $w - 15]
710 }
710 }
711 }
711 }
712 $win sash place 0 $sash0 [lindex $s0 1]
712 $win sash place 0 $sash0 [lindex $s0 1]
713 }
713 }
714 set oldwidth($win) $w
714 set oldwidth($win) $w
715 }
715 }
716
716
717 proc allcanvs args {
717 proc allcanvs args {
718 global canv canv2 canv3
718 global canv canv2 canv3
719 eval $canv $args
719 eval $canv $args
720 eval $canv2 $args
720 eval $canv2 $args
721 eval $canv3 $args
721 eval $canv3 $args
722 }
722 }
723
723
724 proc bindall {event action} {
724 proc bindall {event action} {
725 global canv canv2 canv3
725 global canv canv2 canv3
726 bind $canv $event $action
726 bind $canv $event $action
727 bind $canv2 $event $action
727 bind $canv2 $event $action
728 bind $canv3 $event $action
728 bind $canv3 $event $action
729 }
729 }
730
730
731 proc about {} {
731 proc about {} {
732 set w .about
732 set w .about
733 if {[winfo exists $w]} {
733 if {[winfo exists $w]} {
734 raise $w
734 raise $w
735 return
735 return
736 }
736 }
737 toplevel $w
737 toplevel $w
738 wm title $w "About gitk"
738 wm title $w "About gitk"
739 message $w.m -text {
739 message $w.m -text {
740 Gitk version 1.2
740 Gitk version 1.2
741
741
742 Copyright οΏ½ 2005 Paul Mackerras
742 Copyright οΏ½ 2005 Paul Mackerras
743
743
744 Use and redistribute under the terms of the GNU General Public License} \
744 Use and redistribute under the terms of the GNU General Public License} \
745 -justify center -aspect 400
745 -justify center -aspect 400
746 pack $w.m -side top -fill x -padx 20 -pady 20
746 pack $w.m -side top -fill x -padx 20 -pady 20
747 button $w.ok -text Close -command "destroy $w"
747 button $w.ok -text Close -command "destroy $w"
748 pack $w.ok -side bottom
748 pack $w.ok -side bottom
749 }
749 }
750
750
751 proc assigncolor {id} {
751 proc assigncolor {id} {
752 global commitinfo colormap commcolors colors nextcolor
752 global commitinfo colormap commcolors colors nextcolor
753 global parents nparents children nchildren
753 global parents nparents children nchildren
754 global cornercrossings crossings
754 global cornercrossings crossings
755
755
756 if [info exists colormap($id)] return
756 if [info exists colormap($id)] return
757 set ncolors [llength $colors]
757 set ncolors [llength $colors]
758 if {$nparents($id) <= 1 && $nchildren($id) == 1} {
758 if {$nparents($id) <= 1 && $nchildren($id) == 1} {
759 set child [lindex $children($id) 0]
759 set child [lindex $children($id) 0]
760 if {[info exists colormap($child)]
760 if {[info exists colormap($child)]
761 && $nparents($child) == 1} {
761 && $nparents($child) == 1} {
762 set colormap($id) $colormap($child)
762 set colormap($id) $colormap($child)
763 return
763 return
764 }
764 }
765 }
765 }
766 set badcolors {}
766 set badcolors {}
767 if {[info exists cornercrossings($id)]} {
767 if {[info exists cornercrossings($id)]} {
768 foreach x $cornercrossings($id) {
768 foreach x $cornercrossings($id) {
769 if {[info exists colormap($x)]
769 if {[info exists colormap($x)]
770 && [lsearch -exact $badcolors $colormap($x)] < 0} {
770 && [lsearch -exact $badcolors $colormap($x)] < 0} {
771 lappend badcolors $colormap($x)
771 lappend badcolors $colormap($x)
772 }
772 }
773 }
773 }
774 if {[llength $badcolors] >= $ncolors} {
774 if {[llength $badcolors] >= $ncolors} {
775 set badcolors {}
775 set badcolors {}
776 }
776 }
777 }
777 }
778 set origbad $badcolors
778 set origbad $badcolors
779 if {[llength $badcolors] < $ncolors - 1} {
779 if {[llength $badcolors] < $ncolors - 1} {
780 if {[info exists crossings($id)]} {
780 if {[info exists crossings($id)]} {
781 foreach x $crossings($id) {
781 foreach x $crossings($id) {
782 if {[info exists colormap($x)]
782 if {[info exists colormap($x)]
783 && [lsearch -exact $badcolors $colormap($x)] < 0} {
783 && [lsearch -exact $badcolors $colormap($x)] < 0} {
784 lappend badcolors $colormap($x)
784 lappend badcolors $colormap($x)
785 }
785 }
786 }
786 }
787 if {[llength $badcolors] >= $ncolors} {
787 if {[llength $badcolors] >= $ncolors} {
788 set badcolors $origbad
788 set badcolors $origbad
789 }
789 }
790 }
790 }
791 set origbad $badcolors
791 set origbad $badcolors
792 }
792 }
793 if {[llength $badcolors] < $ncolors - 1} {
793 if {[llength $badcolors] < $ncolors - 1} {
794 foreach child $children($id) {
794 foreach child $children($id) {
795 if {[info exists colormap($child)]
795 if {[info exists colormap($child)]
796 && [lsearch -exact $badcolors $colormap($child)] < 0} {
796 && [lsearch -exact $badcolors $colormap($child)] < 0} {
797 lappend badcolors $colormap($child)
797 lappend badcolors $colormap($child)
798 }
798 }
799 if {[info exists parents($child)]} {
799 if {[info exists parents($child)]} {
800 foreach p $parents($child) {
800 foreach p $parents($child) {
801 if {[info exists colormap($p)]
801 if {[info exists colormap($p)]
802 && [lsearch -exact $badcolors $colormap($p)] < 0} {
802 && [lsearch -exact $badcolors $colormap($p)] < 0} {
803 lappend badcolors $colormap($p)
803 lappend badcolors $colormap($p)
804 }
804 }
805 }
805 }
806 }
806 }
807 }
807 }
808 if {[llength $badcolors] >= $ncolors} {
808 if {[llength $badcolors] >= $ncolors} {
809 set badcolors $origbad
809 set badcolors $origbad
810 }
810 }
811 }
811 }
812 for {set i 0} {$i <= $ncolors} {incr i} {
812 for {set i 0} {$i <= $ncolors} {incr i} {
813 set c [lindex $colors $nextcolor]
813 set c [lindex $colors $nextcolor]
814 if {[incr nextcolor] >= $ncolors} {
814 if {[incr nextcolor] >= $ncolors} {
815 set nextcolor 0
815 set nextcolor 0
816 }
816 }
817 if {[lsearch -exact $badcolors $c]} break
817 if {[lsearch -exact $badcolors $c]} break
818 }
818 }
819 set colormap($id) $c
819 set colormap($id) $c
820 }
820 }
821
821
822 proc initgraph {} {
822 proc initgraph {} {
823 global canvy canvy0 lineno numcommits nextcolor linespc
823 global canvy canvy0 lineno numcommits nextcolor linespc
824 global mainline mainlinearrow sidelines
824 global mainline mainlinearrow sidelines
825 global nchildren ncleft
825 global nchildren ncleft
826 global displist nhyperspace
826 global displist nhyperspace
827
827
828 allcanvs delete all
828 allcanvs delete all
829 set nextcolor 0
829 set nextcolor 0
830 set canvy $canvy0
830 set canvy $canvy0
831 set lineno -1
831 set lineno -1
832 set numcommits 0
832 set numcommits 0
833 catch {unset mainline}
833 catch {unset mainline}
834 catch {unset mainlinearrow}
834 catch {unset mainlinearrow}
835 catch {unset sidelines}
835 catch {unset sidelines}
836 foreach id [array names nchildren] {
836 foreach id [array names nchildren] {
837 set ncleft($id) $nchildren($id)
837 set ncleft($id) $nchildren($id)
838 }
838 }
839 set displist {}
839 set displist {}
840 set nhyperspace 0
840 set nhyperspace 0
841 }
841 }
842
842
843 proc bindline {t id} {
843 proc bindline {t id} {
844 global canv
844 global canv
845
845
846 $canv bind $t <Enter> "lineenter %x %y $id"
846 $canv bind $t <Enter> "lineenter %x %y $id"
847 $canv bind $t <Motion> "linemotion %x %y $id"
847 $canv bind $t <Motion> "linemotion %x %y $id"
848 $canv bind $t <Leave> "lineleave $id"
848 $canv bind $t <Leave> "lineleave $id"
849 $canv bind $t <Button-1> "lineclick %x %y $id 1"
849 $canv bind $t <Button-1> "lineclick %x %y $id 1"
850 }
850 }
851
851
852 proc drawlines {id xtra} {
852 proc drawlines {id xtra} {
853 global mainline mainlinearrow sidelines lthickness colormap canv
853 global mainline mainlinearrow sidelines lthickness colormap canv
854
854
855 $canv delete lines.$id
855 $canv delete lines.$id
856 if {[info exists mainline($id)]} {
856 if {[info exists mainline($id)]} {
857 set t [$canv create line $mainline($id) \
857 set t [$canv create line $mainline($id) \
858 -width [expr {($xtra + 1) * $lthickness}] \
858 -width [expr {($xtra + 1) * $lthickness}] \
859 -fill $colormap($id) -tags lines.$id \
859 -fill $colormap($id) -tags lines.$id \
860 -arrow $mainlinearrow($id)]
860 -arrow $mainlinearrow($id)]
861 $canv lower $t
861 $canv lower $t
862 bindline $t $id
862 bindline $t $id
863 }
863 }
864 if {[info exists sidelines($id)]} {
864 if {[info exists sidelines($id)]} {
865 foreach ls $sidelines($id) {
865 foreach ls $sidelines($id) {
866 set coords [lindex $ls 0]
866 set coords [lindex $ls 0]
867 set thick [lindex $ls 1]
867 set thick [lindex $ls 1]
868 set arrow [lindex $ls 2]
868 set arrow [lindex $ls 2]
869 set t [$canv create line $coords -fill $colormap($id) \
869 set t [$canv create line $coords -fill $colormap($id) \
870 -width [expr {($thick + $xtra) * $lthickness}] \
870 -width [expr {($thick + $xtra) * $lthickness}] \
871 -arrow $arrow -tags lines.$id]
871 -arrow $arrow -tags lines.$id]
872 $canv lower $t
872 $canv lower $t
873 bindline $t $id
873 bindline $t $id
874 }
874 }
875 }
875 }
876 }
876 }
877
877
878 # level here is an index in displist
878 # level here is an index in displist
879 proc drawcommitline {level} {
879 proc drawcommitline {level} {
880 global parents children nparents displist
880 global parents children nparents displist
881 global canv canv2 canv3 mainfont namefont canvy linespc
881 global canv canv2 canv3 mainfont namefont canvy linespc
882 global lineid linehtag linentag linedtag commitinfo
882 global lineid linehtag linentag linedtag commitinfo
883 global colormap numcommits currentparents dupparents
883 global colormap numcommits currentparents dupparents
884 global idtags idline idheads idotherrefs
884 global idtags idline idheads idotherrefs
885 global lineno lthickness mainline mainlinearrow sidelines
885 global lineno lthickness mainline mainlinearrow sidelines
886 global commitlisted rowtextx idpos lastuse displist
886 global commitlisted rowtextx idpos lastuse displist
887 global oldnlines olddlevel olddisplist
887 global oldnlines olddlevel olddisplist
888
888
889 incr numcommits
889 incr numcommits
890 incr lineno
890 incr lineno
891 set id [lindex $displist $level]
891 set id [lindex $displist $level]
892 set lastuse($id) $lineno
892 set lastuse($id) $lineno
893 set lineid($lineno) $id
893 set lineid($lineno) $id
894 set idline($id) $lineno
894 set idline($id) $lineno
895 set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
895 set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
896 if {![info exists commitinfo($id)]} {
896 if {![info exists commitinfo($id)]} {
897 readcommit $id
897 readcommit $id
898 if {![info exists commitinfo($id)]} {
898 if {![info exists commitinfo($id)]} {
899 set commitinfo($id) {"No commit information available"}
899 set commitinfo($id) {"No commit information available"}
900 set nparents($id) 0
900 set nparents($id) 0
901 }
901 }
902 }
902 }
903 assigncolor $id
903 assigncolor $id
904 set currentparents {}
904 set currentparents {}
905 set dupparents {}
905 set dupparents {}
906 if {[info exists commitlisted($id)] && [info exists parents($id)]} {
906 if {[info exists commitlisted($id)] && [info exists parents($id)]} {
907 foreach p $parents($id) {
907 foreach p $parents($id) {
908 if {[lsearch -exact $currentparents $p] < 0} {
908 if {[lsearch -exact $currentparents $p] < 0} {
909 lappend currentparents $p
909 lappend currentparents $p
910 } else {
910 } else {
911 # remember that this parent was listed twice
911 # remember that this parent was listed twice
912 lappend dupparents $p
912 lappend dupparents $p
913 }
913 }
914 }
914 }
915 }
915 }
916 set x [xcoord $level $level $lineno]
916 set x [xcoord $level $level $lineno]
917 set y1 $canvy
917 set y1 $canvy
918 set canvy [expr $canvy + $linespc]
918 set canvy [expr $canvy + $linespc]
919 allcanvs conf -scrollregion \
919 allcanvs conf -scrollregion \
920 [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
920 [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
921 if {[info exists mainline($id)]} {
921 if {[info exists mainline($id)]} {
922 lappend mainline($id) $x $y1
922 lappend mainline($id) $x $y1
923 if {$mainlinearrow($id) ne "none"} {
923 if {$mainlinearrow($id) ne "none"} {
924 set mainline($id) [trimdiagstart $mainline($id)]
924 set mainline($id) [trimdiagstart $mainline($id)]
925 }
925 }
926 }
926 }
927 drawlines $id 0
927 drawlines $id 0
928 set orad [expr {$linespc / 3}]
928 set orad [expr {$linespc / 3}]
929 set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
929 set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
930 [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
930 [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
931 -fill $ofill -outline black -width 1]
931 -fill $ofill -outline black -width 1]
932 $canv raise $t
932 $canv raise $t
933 $canv bind $t <1> {selcanvline {} %x %y}
933 $canv bind $t <1> {selcanvline {} %x %y}
934 set xt [xcoord [llength $displist] $level $lineno]
934 set xt [xcoord [llength $displist] $level $lineno]
935 if {[llength $currentparents] > 2} {
935 if {[llength $currentparents] > 2} {
936 set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}]
936 set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}]
937 }
937 }
938 set rowtextx($lineno) $xt
938 set rowtextx($lineno) $xt
939 set idpos($id) [list $x $xt $y1]
939 set idpos($id) [list $x $xt $y1]
940 if {[info exists idtags($id)] || [info exists idheads($id)]
940 if {[info exists idtags($id)] || [info exists idheads($id)]
941 || [info exists idotherrefs($id)]} {
941 || [info exists idotherrefs($id)]} {
942 set xt [drawtags $id $x $xt $y1]
942 set xt [drawtags $id $x $xt $y1]
943 }
943 }
944 set headline [lindex $commitinfo($id) 0]
944 set headline [lindex $commitinfo($id) 0]
945 set name [lindex $commitinfo($id) 1]
945 set name [lindex $commitinfo($id) 1]
946 set date [lindex $commitinfo($id) 2]
946 set date [lindex $commitinfo($id) 2]
947 set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
947 set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
948 -text $headline -font $mainfont ]
948 -text $headline -font $mainfont ]
949 $canv bind $linehtag($lineno) <<B3>> "rowmenu %X %Y $id"
949 $canv bind $linehtag($lineno) <<B3>> "rowmenu %X %Y $id"
950 set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \
950 set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \
951 -text $name -font $namefont]
951 -text $name -font $namefont]
952 set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \
952 set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \
953 -text $date -font $mainfont]
953 -text $date -font $mainfont]
954
954
955 set olddlevel $level
955 set olddlevel $level
956 set olddisplist $displist
956 set olddisplist $displist
957 set oldnlines [llength $displist]
957 set oldnlines [llength $displist]
958 }
958 }
959
959
960 proc drawtags {id x xt y1} {
960 proc drawtags {id x xt y1} {
961 global idtags idheads idotherrefs
961 global idtags idheads idotherrefs
962 global linespc lthickness
962 global linespc lthickness
963 global canv mainfont idline rowtextx
963 global canv mainfont idline rowtextx
964
964
965 set marks {}
965 set marks {}
966 set ntags 0
966 set ntags 0
967 set nheads 0
967 set nheads 0
968 if {[info exists idtags($id)]} {
968 if {[info exists idtags($id)]} {
969 set marks $idtags($id)
969 set marks $idtags($id)
970 set ntags [llength $marks]
970 set ntags [llength $marks]
971 }
971 }
972 if {[info exists idheads($id)]} {
972 if {[info exists idheads($id)]} {
973 set marks [concat $marks $idheads($id)]
973 set marks [concat $marks $idheads($id)]
974 set nheads [llength $idheads($id)]
974 set nheads [llength $idheads($id)]
975 }
975 }
976 if {[info exists idotherrefs($id)]} {
976 if {[info exists idotherrefs($id)]} {
977 set marks [concat $marks $idotherrefs($id)]
977 set marks [concat $marks $idotherrefs($id)]
978 }
978 }
979 if {$marks eq {}} {
979 if {$marks eq {}} {
980 return $xt
980 return $xt
981 }
981 }
982
982
983 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
983 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
984 set yt [expr $y1 - 0.5 * $linespc]
984 set yt [expr $y1 - 0.5 * $linespc]
985 set yb [expr $yt + $linespc - 1]
985 set yb [expr $yt + $linespc - 1]
986 set xvals {}
986 set xvals {}
987 set wvals {}
987 set wvals {}
988 foreach tag $marks {
988 foreach tag $marks {
989 set wid [font measure $mainfont $tag]
989 set wid [font measure $mainfont $tag]
990 lappend xvals $xt
990 lappend xvals $xt
991 lappend wvals $wid
991 lappend wvals $wid
992 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
992 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
993 }
993 }
994 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
994 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
995 -width $lthickness -fill black -tags tag.$id]
995 -width $lthickness -fill black -tags tag.$id]
996 $canv lower $t
996 $canv lower $t
997 foreach tag $marks x $xvals wid $wvals {
997 foreach tag $marks x $xvals wid $wvals {
998 set xl [expr $x + $delta]
998 set xl [expr $x + $delta]
999 set xr [expr $x + $delta + $wid + $lthickness]
999 set xr [expr $x + $delta + $wid + $lthickness]
1000 if {[incr ntags -1] >= 0} {
1000 if {[incr ntags -1] >= 0} {
1001 # draw a tag
1001 # draw a tag
1002 set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
1002 set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
1003 $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
1003 $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
1004 -width 1 -outline black -fill yellow -tags tag.$id]
1004 -width 1 -outline black -fill yellow -tags tag.$id]
1005 $canv bind $t <1> [list showtag $tag 1]
1005 $canv bind $t <1> [list showtag $tag 1]
1006 set rowtextx($idline($id)) [expr {$xr + $linespc}]
1006 set rowtextx($idline($id)) [expr {$xr + $linespc}]
1007 } else {
1007 } else {
1008 # draw a head or other ref
1008 # draw a head or other ref
1009 if {[incr nheads -1] >= 0} {
1009 if {[incr nheads -1] >= 0} {
1010 set col green
1010 set col green
1011 } else {
1011 } else {
1012 set col "#ddddff"
1012 set col "#ddddff"
1013 }
1013 }
1014 set xl [expr $xl - $delta/2]
1014 set xl [expr $xl - $delta/2]
1015 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
1015 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
1016 -width 1 -outline black -fill $col -tags tag.$id
1016 -width 1 -outline black -fill $col -tags tag.$id
1017 }
1017 }
1018 set t [$canv create text $xl $y1 -anchor w -text $tag \
1018 set t [$canv create text $xl $y1 -anchor w -text $tag \
1019 -font $mainfont -tags tag.$id]
1019 -font $mainfont -tags tag.$id]
1020 if {$ntags >= 0} {
1020 if {$ntags >= 0} {
1021 $canv bind $t <1> [list showtag $tag 1]
1021 $canv bind $t <1> [list showtag $tag 1]
1022 }
1022 }
1023 }
1023 }
1024 return $xt
1024 return $xt
1025 }
1025 }
1026
1026
1027 proc notecrossings {id lo hi corner} {
1027 proc notecrossings {id lo hi corner} {
1028 global olddisplist crossings cornercrossings
1028 global olddisplist crossings cornercrossings
1029
1029
1030 for {set i $lo} {[incr i] < $hi} {} {
1030 for {set i $lo} {[incr i] < $hi} {} {
1031 set p [lindex $olddisplist $i]
1031 set p [lindex $olddisplist $i]
1032 if {$p == {}} continue
1032 if {$p == {}} continue
1033 if {$i == $corner} {
1033 if {$i == $corner} {
1034 if {![info exists cornercrossings($id)]
1034 if {![info exists cornercrossings($id)]
1035 || [lsearch -exact $cornercrossings($id) $p] < 0} {
1035 || [lsearch -exact $cornercrossings($id) $p] < 0} {
1036 lappend cornercrossings($id) $p
1036 lappend cornercrossings($id) $p
1037 }
1037 }
1038 if {![info exists cornercrossings($p)]
1038 if {![info exists cornercrossings($p)]
1039 || [lsearch -exact $cornercrossings($p) $id] < 0} {
1039 || [lsearch -exact $cornercrossings($p) $id] < 0} {
1040 lappend cornercrossings($p) $id
1040 lappend cornercrossings($p) $id
1041 }
1041 }
1042 } else {
1042 } else {
1043 if {![info exists crossings($id)]
1043 if {![info exists crossings($id)]
1044 || [lsearch -exact $crossings($id) $p] < 0} {
1044 || [lsearch -exact $crossings($id) $p] < 0} {
1045 lappend crossings($id) $p
1045 lappend crossings($id) $p
1046 }
1046 }
1047 if {![info exists crossings($p)]
1047 if {![info exists crossings($p)]
1048 || [lsearch -exact $crossings($p) $id] < 0} {
1048 || [lsearch -exact $crossings($p) $id] < 0} {
1049 lappend crossings($p) $id
1049 lappend crossings($p) $id
1050 }
1050 }
1051 }
1051 }
1052 }
1052 }
1053 }
1053 }
1054
1054
1055 proc xcoord {i level ln} {
1055 proc xcoord {i level ln} {
1056 global canvx0 xspc1 xspc2
1056 global canvx0 xspc1 xspc2
1057
1057
1058 set x [expr {$canvx0 + $i * $xspc1($ln)}]
1058 set x [expr {$canvx0 + $i * $xspc1($ln)}]
1059 if {$i > 0 && $i == $level} {
1059 if {$i > 0 && $i == $level} {
1060 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
1060 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
1061 } elseif {$i > $level} {
1061 } elseif {$i > $level} {
1062 set x [expr {$x + $xspc2 - $xspc1($ln)}]
1062 set x [expr {$x + $xspc2 - $xspc1($ln)}]
1063 }
1063 }
1064 return $x
1064 return $x
1065 }
1065 }
1066
1066
1067 # it seems Tk can't draw arrows on the end of diagonal line segments...
1067 # it seems Tk can't draw arrows on the end of diagonal line segments...
1068 proc trimdiagend {line} {
1068 proc trimdiagend {line} {
1069 while {[llength $line] > 4} {
1069 while {[llength $line] > 4} {
1070 set x1 [lindex $line end-3]
1070 set x1 [lindex $line end-3]
1071 set y1 [lindex $line end-2]
1071 set y1 [lindex $line end-2]
1072 set x2 [lindex $line end-1]
1072 set x2 [lindex $line end-1]
1073 set y2 [lindex $line end]
1073 set y2 [lindex $line end]
1074 if {($x1 == $x2) != ($y1 == $y2)} break
1074 if {($x1 == $x2) != ($y1 == $y2)} break
1075 set line [lreplace $line end-1 end]
1075 set line [lreplace $line end-1 end]
1076 }
1076 }
1077 return $line
1077 return $line
1078 }
1078 }
1079
1079
1080 proc trimdiagstart {line} {
1080 proc trimdiagstart {line} {
1081 while {[llength $line] > 4} {
1081 while {[llength $line] > 4} {
1082 set x1 [lindex $line 0]
1082 set x1 [lindex $line 0]
1083 set y1 [lindex $line 1]
1083 set y1 [lindex $line 1]
1084 set x2 [lindex $line 2]
1084 set x2 [lindex $line 2]
1085 set y2 [lindex $line 3]
1085 set y2 [lindex $line 3]
1086 if {($x1 == $x2) != ($y1 == $y2)} break
1086 if {($x1 == $x2) != ($y1 == $y2)} break
1087 set line [lreplace $line 0 1]
1087 set line [lreplace $line 0 1]
1088 }
1088 }
1089 return $line
1089 return $line
1090 }
1090 }
1091
1091
1092 proc drawslants {id needonscreen nohs} {
1092 proc drawslants {id needonscreen nohs} {
1093 global canv mainline mainlinearrow sidelines
1093 global canv mainline mainlinearrow sidelines
1094 global canvx0 canvy xspc1 xspc2 lthickness
1094 global canvx0 canvy xspc1 xspc2 lthickness
1095 global currentparents dupparents
1095 global currentparents dupparents
1096 global lthickness linespc canvy colormap lineno geometry
1096 global lthickness linespc canvy colormap lineno geometry
1097 global maxgraphpct maxwidth
1097 global maxgraphpct maxwidth
1098 global displist onscreen lastuse
1098 global displist onscreen lastuse
1099 global parents commitlisted
1099 global parents commitlisted
1100 global oldnlines olddlevel olddisplist
1100 global oldnlines olddlevel olddisplist
1101 global nhyperspace numcommits nnewparents
1101 global nhyperspace numcommits nnewparents
1102
1102
1103 if {$lineno < 0} {
1103 if {$lineno < 0} {
1104 lappend displist $id
1104 lappend displist $id
1105 set onscreen($id) 1
1105 set onscreen($id) 1
1106 return 0
1106 return 0
1107 }
1107 }
1108
1108
1109 set y1 [expr {$canvy - $linespc}]
1109 set y1 [expr {$canvy - $linespc}]
1110 set y2 $canvy
1110 set y2 $canvy
1111
1111
1112 # work out what we need to get back on screen
1112 # work out what we need to get back on screen
1113 set reins {}
1113 set reins {}
1114 if {$onscreen($id) < 0} {
1114 if {$onscreen($id) < 0} {
1115 # next to do isn't displayed, better get it on screen...
1115 # next to do isn't displayed, better get it on screen...
1116 lappend reins [list $id 0]
1116 lappend reins [list $id 0]
1117 }
1117 }
1118 # make sure all the previous commits's parents are on the screen
1118 # make sure all the previous commits's parents are on the screen
1119 foreach p $currentparents {
1119 foreach p $currentparents {
1120 if {$onscreen($p) < 0} {
1120 if {$onscreen($p) < 0} {
1121 lappend reins [list $p 0]
1121 lappend reins [list $p 0]
1122 }
1122 }
1123 }
1123 }
1124 # bring back anything requested by caller
1124 # bring back anything requested by caller
1125 if {$needonscreen ne {}} {
1125 if {$needonscreen ne {}} {
1126 lappend reins $needonscreen
1126 lappend reins $needonscreen
1127 }
1127 }
1128
1128
1129 # try the shortcut
1129 # try the shortcut
1130 if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} {
1130 if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} {
1131 set dlevel $olddlevel
1131 set dlevel $olddlevel
1132 set x [xcoord $dlevel $dlevel $lineno]
1132 set x [xcoord $dlevel $dlevel $lineno]
1133 set mainline($id) [list $x $y1]
1133 set mainline($id) [list $x $y1]
1134 set mainlinearrow($id) none
1134 set mainlinearrow($id) none
1135 set lastuse($id) $lineno
1135 set lastuse($id) $lineno
1136 set displist [lreplace $displist $dlevel $dlevel $id]
1136 set displist [lreplace $displist $dlevel $dlevel $id]
1137 set onscreen($id) 1
1137 set onscreen($id) 1
1138 set xspc1([expr {$lineno + 1}]) $xspc1($lineno)
1138 set xspc1([expr {$lineno + 1}]) $xspc1($lineno)
1139 return $dlevel
1139 return $dlevel
1140 }
1140 }
1141
1141
1142 # update displist
1142 # update displist
1143 set displist [lreplace $displist $olddlevel $olddlevel]
1143 set displist [lreplace $displist $olddlevel $olddlevel]
1144 set j $olddlevel
1144 set j $olddlevel
1145 foreach p $currentparents {
1145 foreach p $currentparents {
1146 set lastuse($p) $lineno
1146 set lastuse($p) $lineno
1147 if {$onscreen($p) == 0} {
1147 if {$onscreen($p) == 0} {
1148 set displist [linsert $displist $j $p]
1148 set displist [linsert $displist $j $p]
1149 set onscreen($p) 1
1149 set onscreen($p) 1
1150 incr j
1150 incr j
1151 }
1151 }
1152 }
1152 }
1153 if {$onscreen($id) == 0} {
1153 if {$onscreen($id) == 0} {
1154 lappend displist $id
1154 lappend displist $id
1155 set onscreen($id) 1
1155 set onscreen($id) 1
1156 }
1156 }
1157
1157
1158 # remove the null entry if present
1158 # remove the null entry if present
1159 set nullentry [lsearch -exact $displist {}]
1159 set nullentry [lsearch -exact $displist {}]
1160 if {$nullentry >= 0} {
1160 if {$nullentry >= 0} {
1161 set displist [lreplace $displist $nullentry $nullentry]
1161 set displist [lreplace $displist $nullentry $nullentry]
1162 }
1162 }
1163
1163
1164 # bring back the ones we need now (if we did it earlier
1164 # bring back the ones we need now (if we did it earlier
1165 # it would change displist and invalidate olddlevel)
1165 # it would change displist and invalidate olddlevel)
1166 foreach pi $reins {
1166 foreach pi $reins {
1167 # test again in case of duplicates in reins
1167 # test again in case of duplicates in reins
1168 set p [lindex $pi 0]
1168 set p [lindex $pi 0]
1169 if {$onscreen($p) < 0} {
1169 if {$onscreen($p) < 0} {
1170 set onscreen($p) 1
1170 set onscreen($p) 1
1171 set lastuse($p) $lineno
1171 set lastuse($p) $lineno
1172 set displist [linsert $displist [lindex $pi 1] $p]
1172 set displist [linsert $displist [lindex $pi 1] $p]
1173 incr nhyperspace -1
1173 incr nhyperspace -1
1174 }
1174 }
1175 }
1175 }
1176
1176
1177 set lastuse($id) $lineno
1177 set lastuse($id) $lineno
1178
1178
1179 # see if we need to make any lines jump off into hyperspace
1179 # see if we need to make any lines jump off into hyperspace
1180 set displ [llength $displist]
1180 set displ [llength $displist]
1181 if {$displ > $maxwidth} {
1181 if {$displ > $maxwidth} {
1182 set ages {}
1182 set ages {}
1183 foreach x $displist {
1183 foreach x $displist {
1184 lappend ages [list $lastuse($x) $x]
1184 lappend ages [list $lastuse($x) $x]
1185 }
1185 }
1186 set ages [lsort -integer -index 0 $ages]
1186 set ages [lsort -integer -index 0 $ages]
1187 set k 0
1187 set k 0
1188 while {$displ > $maxwidth} {
1188 while {$displ > $maxwidth} {
1189 set use [lindex $ages $k 0]
1189 set use [lindex $ages $k 0]
1190 set victim [lindex $ages $k 1]
1190 set victim [lindex $ages $k 1]
1191 if {$use >= $lineno - 5} break
1191 if {$use >= $lineno - 5} break
1192 incr k
1192 incr k
1193 if {[lsearch -exact $nohs $victim] >= 0} continue
1193 if {[lsearch -exact $nohs $victim] >= 0} continue
1194 set i [lsearch -exact $displist $victim]
1194 set i [lsearch -exact $displist $victim]
1195 set displist [lreplace $displist $i $i]
1195 set displist [lreplace $displist $i $i]
1196 set onscreen($victim) -1
1196 set onscreen($victim) -1
1197 incr nhyperspace
1197 incr nhyperspace
1198 incr displ -1
1198 incr displ -1
1199 if {$i < $nullentry} {
1199 if {$i < $nullentry} {
1200 incr nullentry -1
1200 incr nullentry -1
1201 }
1201 }
1202 set x [lindex $mainline($victim) end-1]
1202 set x [lindex $mainline($victim) end-1]
1203 lappend mainline($victim) $x $y1
1203 lappend mainline($victim) $x $y1
1204 set line [trimdiagend $mainline($victim)]
1204 set line [trimdiagend $mainline($victim)]
1205 set arrow "last"
1205 set arrow "last"
1206 if {$mainlinearrow($victim) ne "none"} {
1206 if {$mainlinearrow($victim) ne "none"} {
1207 set line [trimdiagstart $line]
1207 set line [trimdiagstart $line]
1208 set arrow "both"
1208 set arrow "both"
1209 }
1209 }
1210 lappend sidelines($victim) [list $line 1 $arrow]
1210 lappend sidelines($victim) [list $line 1 $arrow]
1211 unset mainline($victim)
1211 unset mainline($victim)
1212 }
1212 }
1213 }
1213 }
1214
1214
1215 set dlevel [lsearch -exact $displist $id]
1215 set dlevel [lsearch -exact $displist $id]
1216
1216
1217 # If we are reducing, put in a null entry
1217 # If we are reducing, put in a null entry
1218 if {$displ < $oldnlines} {
1218 if {$displ < $oldnlines} {
1219 # does the next line look like a merge?
1219 # does the next line look like a merge?
1220 # i.e. does it have > 1 new parent?
1220 # i.e. does it have > 1 new parent?
1221 if {$nnewparents($id) > 1} {
1221 if {$nnewparents($id) > 1} {
1222 set i [expr {$dlevel + 1}]
1222 set i [expr {$dlevel + 1}]
1223 } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} {
1223 } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} {
1224 set i $olddlevel
1224 set i $olddlevel
1225 if {$nullentry >= 0 && $nullentry < $i} {
1225 if {$nullentry >= 0 && $nullentry < $i} {
1226 incr i -1
1226 incr i -1
1227 }
1227 }
1228 } elseif {$nullentry >= 0} {
1228 } elseif {$nullentry >= 0} {
1229 set i $nullentry
1229 set i $nullentry
1230 while {$i < $displ
1230 while {$i < $displ
1231 && [lindex $olddisplist $i] == [lindex $displist $i]} {
1231 && [lindex $olddisplist $i] == [lindex $displist $i]} {
1232 incr i
1232 incr i
1233 }
1233 }
1234 } else {
1234 } else {
1235 set i $olddlevel
1235 set i $olddlevel
1236 if {$dlevel >= $i} {
1236 if {$dlevel >= $i} {
1237 incr i
1237 incr i
1238 }
1238 }
1239 }
1239 }
1240 if {$i < $displ} {
1240 if {$i < $displ} {
1241 set displist [linsert $displist $i {}]
1241 set displist [linsert $displist $i {}]
1242 incr displ
1242 incr displ
1243 if {$dlevel >= $i} {
1243 if {$dlevel >= $i} {
1244 incr dlevel
1244 incr dlevel
1245 }
1245 }
1246 }
1246 }
1247 }
1247 }
1248
1248
1249 # decide on the line spacing for the next line
1249 # decide on the line spacing for the next line
1250 set lj [expr {$lineno + 1}]
1250 set lj [expr {$lineno + 1}]
1251 set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}]
1251 set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}]
1252 if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} {
1252 if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} {
1253 set xspc1($lj) $xspc2
1253 set xspc1($lj) $xspc2
1254 } else {
1254 } else {
1255 set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}]
1255 set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}]
1256 if {$xspc1($lj) < $lthickness} {
1256 if {$xspc1($lj) < $lthickness} {
1257 set xspc1($lj) $lthickness
1257 set xspc1($lj) $lthickness
1258 }
1258 }
1259 }
1259 }
1260
1260
1261 foreach idi $reins {
1261 foreach idi $reins {
1262 set id [lindex $idi 0]
1262 set id [lindex $idi 0]
1263 set j [lsearch -exact $displist $id]
1263 set j [lsearch -exact $displist $id]
1264 set xj [xcoord $j $dlevel $lj]
1264 set xj [xcoord $j $dlevel $lj]
1265 set mainline($id) [list $xj $y2]
1265 set mainline($id) [list $xj $y2]
1266 set mainlinearrow($id) first
1266 set mainlinearrow($id) first
1267 }
1267 }
1268
1268
1269 set i -1
1269 set i -1
1270 foreach id $olddisplist {
1270 foreach id $olddisplist {
1271 incr i
1271 incr i
1272 if {$id == {}} continue
1272 if {$id == {}} continue
1273 if {$onscreen($id) <= 0} continue
1273 if {$onscreen($id) <= 0} continue
1274 set xi [xcoord $i $olddlevel $lineno]
1274 set xi [xcoord $i $olddlevel $lineno]
1275 if {$i == $olddlevel} {
1275 if {$i == $olddlevel} {
1276 foreach p $currentparents {
1276 foreach p $currentparents {
1277 set j [lsearch -exact $displist $p]
1277 set j [lsearch -exact $displist $p]
1278 set coords [list $xi $y1]
1278 set coords [list $xi $y1]
1279 set xj [xcoord $j $dlevel $lj]
1279 set xj [xcoord $j $dlevel $lj]
1280 if {$xj < $xi - $linespc} {
1280 if {$xj < $xi - $linespc} {
1281 lappend coords [expr {$xj + $linespc}] $y1
1281 lappend coords [expr {$xj + $linespc}] $y1
1282 notecrossings $p $j $i [expr {$j + 1}]
1282 notecrossings $p $j $i [expr {$j + 1}]
1283 } elseif {$xj > $xi + $linespc} {
1283 } elseif {$xj > $xi + $linespc} {
1284 lappend coords [expr {$xj - $linespc}] $y1
1284 lappend coords [expr {$xj - $linespc}] $y1
1285 notecrossings $p $i $j [expr {$j - 1}]
1285 notecrossings $p $i $j [expr {$j - 1}]
1286 }
1286 }
1287 if {[lsearch -exact $dupparents $p] >= 0} {
1287 if {[lsearch -exact $dupparents $p] >= 0} {
1288 # draw a double-width line to indicate the doubled parent
1288 # draw a double-width line to indicate the doubled parent
1289 lappend coords $xj $y2
1289 lappend coords $xj $y2
1290 lappend sidelines($p) [list $coords 2 none]
1290 lappend sidelines($p) [list $coords 2 none]
1291 if {![info exists mainline($p)]} {
1291 if {![info exists mainline($p)]} {
1292 set mainline($p) [list $xj $y2]
1292 set mainline($p) [list $xj $y2]
1293 set mainlinearrow($p) none
1293 set mainlinearrow($p) none
1294 }
1294 }
1295 } else {
1295 } else {
1296 # normal case, no parent duplicated
1296 # normal case, no parent duplicated
1297 set yb $y2
1297 set yb $y2
1298 set dx [expr {abs($xi - $xj)}]
1298 set dx [expr {abs($xi - $xj)}]
1299 if {0 && $dx < $linespc} {
1299 if {0 && $dx < $linespc} {
1300 set yb [expr {$y1 + $dx}]
1300 set yb [expr {$y1 + $dx}]
1301 }
1301 }
1302 if {![info exists mainline($p)]} {
1302 if {![info exists mainline($p)]} {
1303 if {$xi != $xj} {
1303 if {$xi != $xj} {
1304 lappend coords $xj $yb
1304 lappend coords $xj $yb
1305 }
1305 }
1306 set mainline($p) $coords
1306 set mainline($p) $coords
1307 set mainlinearrow($p) none
1307 set mainlinearrow($p) none
1308 } else {
1308 } else {
1309 lappend coords $xj $yb
1309 lappend coords $xj $yb
1310 if {$yb < $y2} {
1310 if {$yb < $y2} {
1311 lappend coords $xj $y2
1311 lappend coords $xj $y2
1312 }
1312 }
1313 lappend sidelines($p) [list $coords 1 none]
1313 lappend sidelines($p) [list $coords 1 none]
1314 }
1314 }
1315 }
1315 }
1316 }
1316 }
1317 } else {
1317 } else {
1318 set j $i
1318 set j $i
1319 if {[lindex $displist $i] != $id} {
1319 if {[lindex $displist $i] != $id} {
1320 set j [lsearch -exact $displist $id]
1320 set j [lsearch -exact $displist $id]
1321 }
1321 }
1322 if {$j != $i || $xspc1($lineno) != $xspc1($lj)
1322 if {$j != $i || $xspc1($lineno) != $xspc1($lj)
1323 || ($olddlevel < $i && $i < $dlevel)
1323 || ($olddlevel < $i && $i < $dlevel)
1324 || ($dlevel < $i && $i < $olddlevel)} {
1324 || ($dlevel < $i && $i < $olddlevel)} {
1325 set xj [xcoord $j $dlevel $lj]
1325 set xj [xcoord $j $dlevel $lj]
1326 lappend mainline($id) $xi $y1 $xj $y2
1326 lappend mainline($id) $xi $y1 $xj $y2
1327 }
1327 }
1328 }
1328 }
1329 }
1329 }
1330 return $dlevel
1330 return $dlevel
1331 }
1331 }
1332
1332
1333 # search for x in a list of lists
1333 # search for x in a list of lists
1334 proc llsearch {llist x} {
1334 proc llsearch {llist x} {
1335 set i 0
1335 set i 0
1336 foreach l $llist {
1336 foreach l $llist {
1337 if {$l == $x || [lsearch -exact $l $x] >= 0} {
1337 if {$l == $x || [lsearch -exact $l $x] >= 0} {
1338 return $i
1338 return $i
1339 }
1339 }
1340 incr i
1340 incr i
1341 }
1341 }
1342 return -1
1342 return -1
1343 }
1343 }
1344
1344
1345 proc drawmore {reading} {
1345 proc drawmore {reading} {
1346 global displayorder numcommits ncmupdate nextupdate
1346 global displayorder numcommits ncmupdate nextupdate
1347 global stopped nhyperspace parents commitlisted
1347 global stopped nhyperspace parents commitlisted
1348 global maxwidth onscreen displist currentparents olddlevel
1348 global maxwidth onscreen displist currentparents olddlevel
1349
1349
1350 set n [llength $displayorder]
1350 set n [llength $displayorder]
1351 while {$numcommits < $n} {
1351 while {$numcommits < $n} {
1352 set id [lindex $displayorder $numcommits]
1352 set id [lindex $displayorder $numcommits]
1353 set ctxend [expr {$numcommits + 10}]
1353 set ctxend [expr {$numcommits + 10}]
1354 if {!$reading && $ctxend > $n} {
1354 if {!$reading && $ctxend > $n} {
1355 set ctxend $n
1355 set ctxend $n
1356 }
1356 }
1357 set dlist {}
1357 set dlist {}
1358 if {$numcommits > 0} {
1358 if {$numcommits > 0} {
1359 set dlist [lreplace $displist $olddlevel $olddlevel]
1359 set dlist [lreplace $displist $olddlevel $olddlevel]
1360 set i $olddlevel
1360 set i $olddlevel
1361 foreach p $currentparents {
1361 foreach p $currentparents {
1362 if {$onscreen($p) == 0} {
1362 if {$onscreen($p) == 0} {
1363 set dlist [linsert $dlist $i $p]
1363 set dlist [linsert $dlist $i $p]
1364 incr i
1364 incr i
1365 }
1365 }
1366 }
1366 }
1367 }
1367 }
1368 set nohs {}
1368 set nohs {}
1369 set reins {}
1369 set reins {}
1370 set isfat [expr {[llength $dlist] > $maxwidth}]
1370 set isfat [expr {[llength $dlist] > $maxwidth}]
1371 if {$nhyperspace > 0 || $isfat} {
1371 if {$nhyperspace > 0 || $isfat} {
1372 if {$ctxend > $n} break
1372 if {$ctxend > $n} break
1373 # work out what to bring back and
1373 # work out what to bring back and
1374 # what we want to don't want to send into hyperspace
1374 # what we want to don't want to send into hyperspace
1375 set room 1
1375 set room 1
1376 for {set k $numcommits} {$k < $ctxend} {incr k} {
1376 for {set k $numcommits} {$k < $ctxend} {incr k} {
1377 set x [lindex $displayorder $k]
1377 set x [lindex $displayorder $k]
1378 set i [llsearch $dlist $x]
1378 set i [llsearch $dlist $x]
1379 if {$i < 0} {
1379 if {$i < 0} {
1380 set i [llength $dlist]
1380 set i [llength $dlist]
1381 lappend dlist $x
1381 lappend dlist $x
1382 }
1382 }
1383 if {[lsearch -exact $nohs $x] < 0} {
1383 if {[lsearch -exact $nohs $x] < 0} {
1384 lappend nohs $x
1384 lappend nohs $x
1385 }
1385 }
1386 if {$reins eq {} && $onscreen($x) < 0 && $room} {
1386 if {$reins eq {} && $onscreen($x) < 0 && $room} {
1387 set reins [list $x $i]
1387 set reins [list $x $i]
1388 }
1388 }
1389 set newp {}
1389 set newp {}
1390 if {[info exists commitlisted($x)]} {
1390 if {[info exists commitlisted($x)]} {
1391 set right 0
1391 set right 0
1392 foreach p $parents($x) {
1392 foreach p $parents($x) {
1393 if {[llsearch $dlist $p] < 0} {
1393 if {[llsearch $dlist $p] < 0} {
1394 lappend newp $p
1394 lappend newp $p
1395 if {[lsearch -exact $nohs $p] < 0} {
1395 if {[lsearch -exact $nohs $p] < 0} {
1396 lappend nohs $p
1396 lappend nohs $p
1397 }
1397 }
1398 if {$reins eq {} && $onscreen($p) < 0 && $room} {
1398 if {$reins eq {} && $onscreen($p) < 0 && $room} {
1399 set reins [list $p [expr {$i + $right}]]
1399 set reins [list $p [expr {$i + $right}]]
1400 }
1400 }
1401 }
1401 }
1402 set right 1
1402 set right 1
1403 }
1403 }
1404 }
1404 }
1405 set l [lindex $dlist $i]
1405 set l [lindex $dlist $i]
1406 if {[llength $l] == 1} {
1406 if {[llength $l] == 1} {
1407 set l $newp
1407 set l $newp
1408 } else {
1408 } else {
1409 set j [lsearch -exact $l $x]
1409 set j [lsearch -exact $l $x]
1410 set l [concat [lreplace $l $j $j] $newp]
1410 set l [concat [lreplace $l $j $j] $newp]
1411 }
1411 }
1412 set dlist [lreplace $dlist $i $i $l]
1412 set dlist [lreplace $dlist $i $i $l]
1413 if {$room && $isfat && [llength $newp] <= 1} {
1413 if {$room && $isfat && [llength $newp] <= 1} {
1414 set room 0
1414 set room 0
1415 }
1415 }
1416 }
1416 }
1417 }
1417 }
1418
1418
1419 set dlevel [drawslants $id $reins $nohs]
1419 set dlevel [drawslants $id $reins $nohs]
1420 drawcommitline $dlevel
1420 drawcommitline $dlevel
1421 if {[clock clicks -milliseconds] >= $nextupdate
1421 if {[clock clicks -milliseconds] >= $nextupdate
1422 && $numcommits >= $ncmupdate} {
1422 && $numcommits >= $ncmupdate} {
1423 doupdate $reading
1423 doupdate $reading
1424 if {$stopped} break
1424 if {$stopped} break
1425 }
1425 }
1426 }
1426 }
1427 }
1427 }
1428
1428
1429 # level here is an index in todo
1429 # level here is an index in todo
1430 proc updatetodo {level noshortcut} {
1430 proc updatetodo {level noshortcut} {
1431 global ncleft todo nnewparents
1431 global ncleft todo nnewparents
1432 global commitlisted parents onscreen
1432 global commitlisted parents onscreen
1433
1433
1434 set id [lindex $todo $level]
1434 set id [lindex $todo $level]
1435 set olds {}
1435 set olds {}
1436 if {[info exists commitlisted($id)]} {
1436 if {[info exists commitlisted($id)]} {
1437 foreach p $parents($id) {
1437 foreach p $parents($id) {
1438 if {[lsearch -exact $olds $p] < 0} {
1438 if {[lsearch -exact $olds $p] < 0} {
1439 lappend olds $p
1439 lappend olds $p
1440 }
1440 }
1441 }
1441 }
1442 }
1442 }
1443 if {!$noshortcut && [llength $olds] == 1} {
1443 if {!$noshortcut && [llength $olds] == 1} {
1444 set p [lindex $olds 0]
1444 set p [lindex $olds 0]
1445 if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} {
1445 if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} {
1446 set ncleft($p) 0
1446 set ncleft($p) 0
1447 set todo [lreplace $todo $level $level $p]
1447 set todo [lreplace $todo $level $level $p]
1448 set onscreen($p) 0
1448 set onscreen($p) 0
1449 set nnewparents($id) 1
1449 set nnewparents($id) 1
1450 return 0
1450 return 0
1451 }
1451 }
1452 }
1452 }
1453
1453
1454 set todo [lreplace $todo $level $level]
1454 set todo [lreplace $todo $level $level]
1455 set i $level
1455 set i $level
1456 set n 0
1456 set n 0
1457 foreach p $olds {
1457 foreach p $olds {
1458 incr ncleft($p) -1
1458 incr ncleft($p) -1
1459 set k [lsearch -exact $todo $p]
1459 set k [lsearch -exact $todo $p]
1460 if {$k < 0} {
1460 if {$k < 0} {
1461 set todo [linsert $todo $i $p]
1461 set todo [linsert $todo $i $p]
1462 set onscreen($p) 0
1462 set onscreen($p) 0
1463 incr i
1463 incr i
1464 incr n
1464 incr n
1465 }
1465 }
1466 }
1466 }
1467 set nnewparents($id) $n
1467 set nnewparents($id) $n
1468
1468
1469 return 1
1469 return 1
1470 }
1470 }
1471
1471
1472 proc decidenext {{noread 0}} {
1472 proc decidenext {{noread 0}} {
1473 global ncleft todo
1473 global ncleft todo
1474 global datemode cdate
1474 global datemode cdate
1475 global commitinfo
1475 global commitinfo
1476
1476
1477 # choose which one to do next time around
1477 # choose which one to do next time around
1478 set todol [llength $todo]
1478 set todol [llength $todo]
1479 set level -1
1479 set level -1
1480 set latest {}
1480 set latest {}
1481 for {set k $todol} {[incr k -1] >= 0} {} {
1481 for {set k $todol} {[incr k -1] >= 0} {} {
1482 set p [lindex $todo $k]
1482 set p [lindex $todo $k]
1483 if {$ncleft($p) == 0} {
1483 if {$ncleft($p) == 0} {
1484 if {$datemode} {
1484 if {$datemode} {
1485 if {![info exists commitinfo($p)]} {
1485 if {![info exists commitinfo($p)]} {
1486 if {$noread} {
1486 if {$noread} {
1487 return {}
1487 return {}
1488 }
1488 }
1489 readcommit $p
1489 readcommit $p
1490 }
1490 }
1491 if {$latest == {} || $cdate($p) > $latest} {
1491 if {$latest == {} || $cdate($p) > $latest} {
1492 set level $k
1492 set level $k
1493 set latest $cdate($p)
1493 set latest $cdate($p)
1494 }
1494 }
1495 } else {
1495 } else {
1496 set level $k
1496 set level $k
1497 break
1497 break
1498 }
1498 }
1499 }
1499 }
1500 }
1500 }
1501 if {$level < 0} {
1501 if {$level < 0} {
1502 if {$todo != {}} {
1502 if {$todo != {}} {
1503 puts "ERROR: none of the pending commits can be done yet:"
1503 puts "ERROR: none of the pending commits can be done yet:"
1504 foreach p $todo {
1504 foreach p $todo {
1505 puts " $p ($ncleft($p))"
1505 puts " $p ($ncleft($p))"
1506 }
1506 }
1507 }
1507 }
1508 return -1
1508 return -1
1509 }
1509 }
1510
1510
1511 return $level
1511 return $level
1512 }
1512 }
1513
1513
1514 proc drawcommit {id} {
1514 proc drawcommit {id} {
1515 global phase todo nchildren datemode nextupdate
1515 global phase todo nchildren datemode nextupdate
1516 global numcommits ncmupdate displayorder todo onscreen
1516 global numcommits ncmupdate displayorder todo onscreen
1517
1517
1518 if {$phase != "incrdraw"} {
1518 if {$phase != "incrdraw"} {
1519 set phase incrdraw
1519 set phase incrdraw
1520 set displayorder {}
1520 set displayorder {}
1521 set todo {}
1521 set todo {}
1522 initgraph
1522 initgraph
1523 }
1523 }
1524 if {$nchildren($id) == 0} {
1524 if {$nchildren($id) == 0} {
1525 lappend todo $id
1525 lappend todo $id
1526 set onscreen($id) 0
1526 set onscreen($id) 0
1527 }
1527 }
1528 set level [decidenext 1]
1528 set level [decidenext 1]
1529 if {$level == {} || $id != [lindex $todo $level]} {
1529 if {$level == {} || $id != [lindex $todo $level]} {
1530 return
1530 return
1531 }
1531 }
1532 while 1 {
1532 while 1 {
1533 lappend displayorder [lindex $todo $level]
1533 lappend displayorder [lindex $todo $level]
1534 if {[updatetodo $level $datemode]} {
1534 if {[updatetodo $level $datemode]} {
1535 set level [decidenext 1]
1535 set level [decidenext 1]
1536 if {$level == {}} break
1536 if {$level == {}} break
1537 }
1537 }
1538 set id [lindex $todo $level]
1538 set id [lindex $todo $level]
1539 if {![info exists commitlisted($id)]} {
1539 if {![info exists commitlisted($id)]} {
1540 break
1540 break
1541 }
1541 }
1542 }
1542 }
1543 drawmore 1
1543 drawmore 1
1544 }
1544 }
1545
1545
1546 proc finishcommits {} {
1546 proc finishcommits {} {
1547 global phase
1547 global phase
1548 global canv mainfont ctext maincursor textcursor
1548 global canv mainfont ctext maincursor textcursor
1549
1549
1550 if {$phase != "incrdraw"} {
1550 if {$phase != "incrdraw"} {
1551 $canv delete all
1551 $canv delete all
1552 $canv create text 3 3 -anchor nw -text "No commits selected" \
1552 $canv create text 3 3 -anchor nw -text "No commits selected" \
1553 -font $mainfont -tags textitems
1553 -font $mainfont -tags textitems
1554 set phase {}
1554 set phase {}
1555 } else {
1555 } else {
1556 drawrest
1556 drawrest
1557 }
1557 }
1558 . config -cursor $maincursor
1558 . config -cursor $maincursor
1559 settextcursor $textcursor
1559 settextcursor $textcursor
1560 }
1560 }
1561
1561
1562 # Don't change the text pane cursor if it is currently the hand cursor,
1562 # Don't change the text pane cursor if it is currently the hand cursor,
1563 # showing that we are over a sha1 ID link.
1563 # showing that we are over a sha1 ID link.
1564 proc settextcursor {c} {
1564 proc settextcursor {c} {
1565 global ctext curtextcursor
1565 global ctext curtextcursor
1566
1566
1567 if {[$ctext cget -cursor] == $curtextcursor} {
1567 if {[$ctext cget -cursor] == $curtextcursor} {
1568 $ctext config -cursor $c
1568 $ctext config -cursor $c
1569 }
1569 }
1570 set curtextcursor $c
1570 set curtextcursor $c
1571 }
1571 }
1572
1572
1573 proc drawgraph {} {
1573 proc drawgraph {} {
1574 global nextupdate startmsecs ncmupdate
1574 global nextupdate startmsecs ncmupdate
1575 global displayorder onscreen
1575 global displayorder onscreen
1576
1576
1577 if {$displayorder == {}} return
1577 if {$displayorder == {}} return
1578 set startmsecs [clock clicks -milliseconds]
1578 set startmsecs [clock clicks -milliseconds]
1579 set nextupdate [expr $startmsecs + 100]
1579 set nextupdate [expr $startmsecs + 100]
1580 set ncmupdate 1
1580 set ncmupdate 1
1581 initgraph
1581 initgraph
1582 foreach id $displayorder {
1582 foreach id $displayorder {
1583 set onscreen($id) 0
1583 set onscreen($id) 0
1584 }
1584 }
1585 drawmore 0
1585 drawmore 0
1586 }
1586 }
1587
1587
1588 proc drawrest {} {
1588 proc drawrest {} {
1589 global phase stopped redisplaying selectedline
1589 global phase stopped redisplaying selectedline
1590 global datemode todo displayorder
1590 global datemode todo displayorder
1591 global numcommits ncmupdate
1591 global numcommits ncmupdate
1592 global nextupdate startmsecs
1592 global nextupdate startmsecs
1593
1593
1594 set level [decidenext]
1594 set level [decidenext]
1595 if {$level >= 0} {
1595 if {$level >= 0} {
1596 set phase drawgraph
1596 set phase drawgraph
1597 while 1 {
1597 while 1 {
1598 lappend displayorder [lindex $todo $level]
1598 lappend displayorder [lindex $todo $level]
1599 set hard [updatetodo $level $datemode]
1599 set hard [updatetodo $level $datemode]
1600 if {$hard} {
1600 if {$hard} {
1601 set level [decidenext]
1601 set level [decidenext]
1602 if {$level < 0} break
1602 if {$level < 0} break
1603 }
1603 }
1604 }
1604 }
1605 drawmore 0
1605 drawmore 0
1606 }
1606 }
1607 set phase {}
1607 set phase {}
1608 set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
1608 set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
1609 #puts "overall $drawmsecs ms for $numcommits commits"
1609 #puts "overall $drawmsecs ms for $numcommits commits"
1610 if {$redisplaying} {
1610 if {$redisplaying} {
1611 if {$stopped == 0 && [info exists selectedline]} {
1611 if {$stopped == 0 && [info exists selectedline]} {
1612 selectline $selectedline 0
1612 selectline $selectedline 0
1613 }
1613 }
1614 if {$stopped == 1} {
1614 if {$stopped == 1} {
1615 set stopped 0
1615 set stopped 0
1616 after idle drawgraph
1616 after idle drawgraph
1617 } else {
1617 } else {
1618 set redisplaying 0
1618 set redisplaying 0
1619 }
1619 }
1620 }
1620 }
1621 }
1621 }
1622
1622
1623 proc findmatches {f} {
1623 proc findmatches {f} {
1624 global findtype foundstring foundstrlen
1624 global findtype foundstring foundstrlen
1625 if {$findtype == "Regexp"} {
1625 if {$findtype == "Regexp"} {
1626 set matches [regexp -indices -all -inline $foundstring $f]
1626 set matches [regexp -indices -all -inline $foundstring $f]
1627 } else {
1627 } else {
1628 if {$findtype == "IgnCase"} {
1628 if {$findtype == "IgnCase"} {
1629 set str [string tolower $f]
1629 set str [string tolower $f]
1630 } else {
1630 } else {
1631 set str $f
1631 set str $f
1632 }
1632 }
1633 set matches {}
1633 set matches {}
1634 set i 0
1634 set i 0
1635 while {[set j [string first $foundstring $str $i]] >= 0} {
1635 while {[set j [string first $foundstring $str $i]] >= 0} {
1636 lappend matches [list $j [expr $j+$foundstrlen-1]]
1636 lappend matches [list $j [expr $j+$foundstrlen-1]]
1637 set i [expr $j + $foundstrlen]
1637 set i [expr $j + $foundstrlen]
1638 }
1638 }
1639 }
1639 }
1640 return $matches
1640 return $matches
1641 }
1641 }
1642
1642
1643 proc dofind {} {
1643 proc dofind {} {
1644 global findtype findloc findstring markedmatches commitinfo
1644 global findtype findloc findstring markedmatches commitinfo
1645 global numcommits lineid linehtag linentag linedtag
1645 global numcommits lineid linehtag linentag linedtag
1646 global mainfont namefont canv canv2 canv3 selectedline
1646 global mainfont namefont canv canv2 canv3 selectedline
1647 global matchinglines foundstring foundstrlen
1647 global matchinglines foundstring foundstrlen
1648
1648
1649 stopfindproc
1649 stopfindproc
1650 unmarkmatches
1650 unmarkmatches
1651 focus .
1651 focus .
1652 set matchinglines {}
1652 set matchinglines {}
1653 if {$findloc == "Pickaxe"} {
1653 if {$findloc == "Pickaxe"} {
1654 findpatches
1654 findpatches
1655 return
1655 return
1656 }
1656 }
1657 if {$findtype == "IgnCase"} {
1657 if {$findtype == "IgnCase"} {
1658 set foundstring [string tolower $findstring]
1658 set foundstring [string tolower $findstring]
1659 } else {
1659 } else {
1660 set foundstring $findstring
1660 set foundstring $findstring
1661 }
1661 }
1662 set foundstrlen [string length $findstring]
1662 set foundstrlen [string length $findstring]
1663 if {$foundstrlen == 0} return
1663 if {$foundstrlen == 0} return
1664 if {$findloc == "Files"} {
1664 if {$findloc == "Files"} {
1665 findfiles
1665 findfiles
1666 return
1666 return
1667 }
1667 }
1668 if {![info exists selectedline]} {
1668 if {![info exists selectedline]} {
1669 set oldsel -1
1669 set oldsel -1
1670 } else {
1670 } else {
1671 set oldsel $selectedline
1671 set oldsel $selectedline
1672 }
1672 }
1673 set didsel 0
1673 set didsel 0
1674 set fldtypes {Headline Author Date Committer CDate Comment}
1674 set fldtypes {Headline Author Date Committer CDate Comment}
1675 for {set l 0} {$l < $numcommits} {incr l} {
1675 for {set l 0} {$l < $numcommits} {incr l} {
1676 set id $lineid($l)
1676 set id $lineid($l)
1677 set info $commitinfo($id)
1677 set info $commitinfo($id)
1678 set doesmatch 0
1678 set doesmatch 0
1679 foreach f $info ty $fldtypes {
1679 foreach f $info ty $fldtypes {
1680 if {$findloc != "All fields" && $findloc != $ty} {
1680 if {$findloc != "All fields" && $findloc != $ty} {
1681 continue
1681 continue
1682 }
1682 }
1683 set matches [findmatches $f]
1683 set matches [findmatches $f]
1684 if {$matches == {}} continue
1684 if {$matches == {}} continue
1685 set doesmatch 1
1685 set doesmatch 1
1686 if {$ty == "Headline"} {
1686 if {$ty == "Headline"} {
1687 markmatches $canv $l $f $linehtag($l) $matches $mainfont
1687 markmatches $canv $l $f $linehtag($l) $matches $mainfont
1688 } elseif {$ty == "Author"} {
1688 } elseif {$ty == "Author"} {
1689 markmatches $canv2 $l $f $linentag($l) $matches $namefont
1689 markmatches $canv2 $l $f $linentag($l) $matches $namefont
1690 } elseif {$ty == "Date"} {
1690 } elseif {$ty == "Date"} {
1691 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
1691 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
1692 }
1692 }
1693 }
1693 }
1694 if {$doesmatch} {
1694 if {$doesmatch} {
1695 lappend matchinglines $l
1695 lappend matchinglines $l
1696 if {!$didsel && $l > $oldsel} {
1696 if {!$didsel && $l > $oldsel} {
1697 findselectline $l
1697 findselectline $l
1698 set didsel 1
1698 set didsel 1
1699 }
1699 }
1700 }
1700 }
1701 }
1701 }
1702 if {$matchinglines == {}} {
1702 if {$matchinglines == {}} {
1703 bell
1703 bell
1704 } elseif {!$didsel} {
1704 } elseif {!$didsel} {
1705 findselectline [lindex $matchinglines 0]
1705 findselectline [lindex $matchinglines 0]
1706 }
1706 }
1707 }
1707 }
1708
1708
1709 proc findselectline {l} {
1709 proc findselectline {l} {
1710 global findloc commentend ctext
1710 global findloc commentend ctext
1711 selectline $l 1
1711 selectline $l 1
1712 if {$findloc == "All fields" || $findloc == "Comments"} {
1712 if {$findloc == "All fields" || $findloc == "Comments"} {
1713 # highlight the matches in the comments
1713 # highlight the matches in the comments
1714 set f [$ctext get 1.0 $commentend]
1714 set f [$ctext get 1.0 $commentend]
1715 set matches [findmatches $f]
1715 set matches [findmatches $f]
1716 foreach match $matches {
1716 foreach match $matches {
1717 set start [lindex $match 0]
1717 set start [lindex $match 0]
1718 set end [expr [lindex $match 1] + 1]
1718 set end [expr [lindex $match 1] + 1]
1719 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
1719 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
1720 }
1720 }
1721 }
1721 }
1722 }
1722 }
1723
1723
1724 proc findnext {restart} {
1724 proc findnext {restart} {
1725 global matchinglines selectedline
1725 global matchinglines selectedline
1726 if {![info exists matchinglines]} {
1726 if {![info exists matchinglines]} {
1727 if {$restart} {
1727 if {$restart} {
1728 dofind
1728 dofind
1729 }
1729 }
1730 return
1730 return
1731 }
1731 }
1732 if {![info exists selectedline]} return
1732 if {![info exists selectedline]} return
1733 foreach l $matchinglines {
1733 foreach l $matchinglines {
1734 if {$l > $selectedline} {
1734 if {$l > $selectedline} {
1735 findselectline $l
1735 findselectline $l
1736 return
1736 return
1737 }
1737 }
1738 }
1738 }
1739 bell
1739 bell
1740 }
1740 }
1741
1741
1742 proc findprev {} {
1742 proc findprev {} {
1743 global matchinglines selectedline
1743 global matchinglines selectedline
1744 if {![info exists matchinglines]} {
1744 if {![info exists matchinglines]} {
1745 dofind
1745 dofind
1746 return
1746 return
1747 }
1747 }
1748 if {![info exists selectedline]} return
1748 if {![info exists selectedline]} return
1749 set prev {}
1749 set prev {}
1750 foreach l $matchinglines {
1750 foreach l $matchinglines {
1751 if {$l >= $selectedline} break
1751 if {$l >= $selectedline} break
1752 set prev $l
1752 set prev $l
1753 }
1753 }
1754 if {$prev != {}} {
1754 if {$prev != {}} {
1755 findselectline $prev
1755 findselectline $prev
1756 } else {
1756 } else {
1757 bell
1757 bell
1758 }
1758 }
1759 }
1759 }
1760
1760
1761 proc findlocchange {name ix op} {
1761 proc findlocchange {name ix op} {
1762 global findloc findtype findtypemenu
1762 global findloc findtype findtypemenu
1763 if {$findloc == "Pickaxe"} {
1763 if {$findloc == "Pickaxe"} {
1764 set findtype Exact
1764 set findtype Exact
1765 set state disabled
1765 set state disabled
1766 } else {
1766 } else {
1767 set state normal
1767 set state normal
1768 }
1768 }
1769 $findtypemenu entryconf 1 -state $state
1769 $findtypemenu entryconf 1 -state $state
1770 $findtypemenu entryconf 2 -state $state
1770 $findtypemenu entryconf 2 -state $state
1771 }
1771 }
1772
1772
1773 proc stopfindproc {{done 0}} {
1773 proc stopfindproc {{done 0}} {
1774 global findprocpid findprocfile findids
1774 global findprocpid findprocfile findids
1775 global ctext findoldcursor phase maincursor textcursor
1775 global ctext findoldcursor phase maincursor textcursor
1776 global findinprogress
1776 global findinprogress
1777
1777
1778 catch {unset findids}
1778 catch {unset findids}
1779 if {[info exists findprocpid]} {
1779 if {[info exists findprocpid]} {
1780 if {!$done} {
1780 if {!$done} {
1781 catch {exec kill $findprocpid}
1781 catch {exec kill $findprocpid}
1782 }
1782 }
1783 catch {close $findprocfile}
1783 catch {close $findprocfile}
1784 unset findprocpid
1784 unset findprocpid
1785 }
1785 }
1786 if {[info exists findinprogress]} {
1786 if {[info exists findinprogress]} {
1787 unset findinprogress
1787 unset findinprogress
1788 if {$phase != "incrdraw"} {
1788 if {$phase != "incrdraw"} {
1789 . config -cursor $maincursor
1789 . config -cursor $maincursor
1790 settextcursor $textcursor
1790 settextcursor $textcursor
1791 }
1791 }
1792 }
1792 }
1793 }
1793 }
1794
1794
1795 proc findpatches {} {
1795 proc findpatches {} {
1796 global findstring selectedline numcommits
1796 global findstring selectedline numcommits
1797 global findprocpid findprocfile
1797 global findprocpid findprocfile
1798 global finddidsel ctext lineid findinprogress
1798 global finddidsel ctext lineid findinprogress
1799 global findinsertpos
1799 global findinsertpos
1800 global env
1800 global env
1801
1801
1802 if {$numcommits == 0} return
1802 if {$numcommits == 0} return
1803
1803
1804 # make a list of all the ids to search, starting at the one
1804 # make a list of all the ids to search, starting at the one
1805 # after the selected line (if any)
1805 # after the selected line (if any)
1806 if {[info exists selectedline]} {
1806 if {[info exists selectedline]} {
1807 set l $selectedline
1807 set l $selectedline
1808 } else {
1808 } else {
1809 set l -1
1809 set l -1
1810 }
1810 }
1811 set inputids {}
1811 set inputids {}
1812 for {set i 0} {$i < $numcommits} {incr i} {
1812 for {set i 0} {$i < $numcommits} {incr i} {
1813 if {[incr l] >= $numcommits} {
1813 if {[incr l] >= $numcommits} {
1814 set l 0
1814 set l 0
1815 }
1815 }
1816 append inputids $lineid($l) "\n"
1816 append inputids $lineid($l) "\n"
1817 }
1817 }
1818
1818
1819 if {[catch {
1819 if {[catch {
1820 set f [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree --stdin -s -r -S$findstring << $inputids] r]
1820 set f [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree --stdin -s -r -S$findstring << $inputids] r]
1821 } err]} {
1821 } err]} {
1822 error_popup "Error starting search process: $err"
1822 error_popup "Error starting search process: $err"
1823 return
1823 return
1824 }
1824 }
1825
1825
1826 set findinsertpos end
1826 set findinsertpos end
1827 set findprocfile $f
1827 set findprocfile $f
1828 set findprocpid [pid $f]
1828 set findprocpid [pid $f]
1829 fconfigure $f -blocking 0
1829 fconfigure $f -blocking 0
1830 fileevent $f readable readfindproc
1830 fileevent $f readable readfindproc
1831 set finddidsel 0
1831 set finddidsel 0
1832 . config -cursor watch
1832 . config -cursor watch
1833 settextcursor watch
1833 settextcursor watch
1834 set findinprogress 1
1834 set findinprogress 1
1835 }
1835 }
1836
1836
1837 proc readfindproc {} {
1837 proc readfindproc {} {
1838 global findprocfile finddidsel
1838 global findprocfile finddidsel
1839 global idline matchinglines findinsertpos
1839 global idline matchinglines findinsertpos
1840
1840
1841 set n [gets $findprocfile line]
1841 set n [gets $findprocfile line]
1842 if {$n < 0} {
1842 if {$n < 0} {
1843 if {[eof $findprocfile]} {
1843 if {[eof $findprocfile]} {
1844 stopfindproc 1
1844 stopfindproc 1
1845 if {!$finddidsel} {
1845 if {!$finddidsel} {
1846 bell
1846 bell
1847 }
1847 }
1848 }
1848 }
1849 return
1849 return
1850 }
1850 }
1851 if {![regexp {^[0-9a-f]{12}} $line id]} {
1851 if {![regexp {^[0-9a-f]{12}} $line id]} {
1852 error_popup "Can't parse git-diff-tree output: $line"
1852 error_popup "Can't parse git-diff-tree output: $line"
1853 stopfindproc
1853 stopfindproc
1854 return
1854 return
1855 }
1855 }
1856 if {![info exists idline($id)]} {
1856 if {![info exists idline($id)]} {
1857 puts stderr "spurious id: $id"
1857 puts stderr "spurious id: $id"
1858 return
1858 return
1859 }
1859 }
1860 set l $idline($id)
1860 set l $idline($id)
1861 insertmatch $l $id
1861 insertmatch $l $id
1862 }
1862 }
1863
1863
1864 proc insertmatch {l id} {
1864 proc insertmatch {l id} {
1865 global matchinglines findinsertpos finddidsel
1865 global matchinglines findinsertpos finddidsel
1866
1866
1867 if {$findinsertpos == "end"} {
1867 if {$findinsertpos == "end"} {
1868 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
1868 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
1869 set matchinglines [linsert $matchinglines 0 $l]
1869 set matchinglines [linsert $matchinglines 0 $l]
1870 set findinsertpos 1
1870 set findinsertpos 1
1871 } else {
1871 } else {
1872 lappend matchinglines $l
1872 lappend matchinglines $l
1873 }
1873 }
1874 } else {
1874 } else {
1875 set matchinglines [linsert $matchinglines $findinsertpos $l]
1875 set matchinglines [linsert $matchinglines $findinsertpos $l]
1876 incr findinsertpos
1876 incr findinsertpos
1877 }
1877 }
1878 markheadline $l $id
1878 markheadline $l $id
1879 if {!$finddidsel} {
1879 if {!$finddidsel} {
1880 findselectline $l
1880 findselectline $l
1881 set finddidsel 1
1881 set finddidsel 1
1882 }
1882 }
1883 }
1883 }
1884
1884
1885 proc findfiles {} {
1885 proc findfiles {} {
1886 global selectedline numcommits lineid ctext
1886 global selectedline numcommits lineid ctext
1887 global ffileline finddidsel parents nparents
1887 global ffileline finddidsel parents nparents
1888 global findinprogress findstartline findinsertpos
1888 global findinprogress findstartline findinsertpos
1889 global treediffs fdiffids fdiffsneeded fdiffpos
1889 global treediffs fdiffids fdiffsneeded fdiffpos
1890 global findmergefiles
1890 global findmergefiles
1891 global env
1891 global env
1892
1892
1893 if {$numcommits == 0} return
1893 if {$numcommits == 0} return
1894
1894
1895 if {[info exists selectedline]} {
1895 if {[info exists selectedline]} {
1896 set l [expr {$selectedline + 1}]
1896 set l [expr {$selectedline + 1}]
1897 } else {
1897 } else {
1898 set l 0
1898 set l 0
1899 }
1899 }
1900 set ffileline $l
1900 set ffileline $l
1901 set findstartline $l
1901 set findstartline $l
1902 set diffsneeded {}
1902 set diffsneeded {}
1903 set fdiffsneeded {}
1903 set fdiffsneeded {}
1904 while 1 {
1904 while 1 {
1905 set id $lineid($l)
1905 set id $lineid($l)
1906 if {$findmergefiles || $nparents($id) == 1} {
1906 if {$findmergefiles || $nparents($id) == 1} {
1907 foreach p $parents($id) {
1907 foreach p $parents($id) {
1908 if {![info exists treediffs([list $id $p])]} {
1908 if {![info exists treediffs([list $id $p])]} {
1909 append diffsneeded "$id $p\n"
1909 append diffsneeded "$id $p\n"
1910 lappend fdiffsneeded [list $id $p]
1910 lappend fdiffsneeded [list $id $p]
1911 }
1911 }
1912 }
1912 }
1913 }
1913 }
1914 if {[incr l] >= $numcommits} {
1914 if {[incr l] >= $numcommits} {
1915 set l 0
1915 set l 0
1916 }
1916 }
1917 if {$l == $findstartline} break
1917 if {$l == $findstartline} break
1918 }
1918 }
1919
1919
1920 # start off a git-diff-tree process if needed
1920 # start off a git-diff-tree process if needed
1921 if {$diffsneeded ne {}} {
1921 if {$diffsneeded ne {}} {
1922 if {[catch {
1922 if {[catch {
1923 set df [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r --stdin << $diffsneeded] r]
1923 set df [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r --stdin << $diffsneeded] r]
1924 } err ]} {
1924 } err ]} {
1925 error_popup "Error starting search process: $err"
1925 error_popup "Error starting search process: $err"
1926 return
1926 return
1927 }
1927 }
1928 catch {unset fdiffids}
1928 catch {unset fdiffids}
1929 set fdiffpos 0
1929 set fdiffpos 0
1930 fconfigure $df -blocking 0
1930 fconfigure $df -blocking 0
1931 fileevent $df readable [list readfilediffs $df]
1931 fileevent $df readable [list readfilediffs $df]
1932 }
1932 }
1933
1933
1934 set finddidsel 0
1934 set finddidsel 0
1935 set findinsertpos end
1935 set findinsertpos end
1936 set id $lineid($l)
1936 set id $lineid($l)
1937 set p [lindex $parents($id) 0]
1937 set p [lindex $parents($id) 0]
1938 . config -cursor watch
1938 . config -cursor watch
1939 settextcursor watch
1939 settextcursor watch
1940 set findinprogress 1
1940 set findinprogress 1
1941 findcont [list $id $p]
1941 findcont [list $id $p]
1942 update
1942 update
1943 }
1943 }
1944
1944
1945 proc readfilediffs {df} {
1945 proc readfilediffs {df} {
1946 global findids fdiffids fdiffs
1946 global findids fdiffids fdiffs
1947
1947
1948 set n [gets $df line]
1948 set n [gets $df line]
1949 if {$n < 0} {
1949 if {$n < 0} {
1950 if {[eof $df]} {
1950 if {[eof $df]} {
1951 donefilediff
1951 donefilediff
1952 if {[catch {close $df} err]} {
1952 if {[catch {close $df} err]} {
1953 stopfindproc
1953 stopfindproc
1954 bell
1954 bell
1955 error_popup "Error in hg debug-diff-tree: $err"
1955 error_popup "Error in hg debug-diff-tree: $err"
1956 } elseif {[info exists findids]} {
1956 } elseif {[info exists findids]} {
1957 set ids $findids
1957 set ids $findids
1958 stopfindproc
1958 stopfindproc
1959 bell
1959 bell
1960 error_popup "Couldn't find diffs for {$ids}"
1960 error_popup "Couldn't find diffs for {$ids}"
1961 }
1961 }
1962 }
1962 }
1963 return
1963 return
1964 }
1964 }
1965 if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} {
1965 if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} {
1966 # start of a new string of diffs
1966 # start of a new string of diffs
1967 donefilediff
1967 donefilediff
1968 set fdiffids [list $id $p]
1968 set fdiffids [list $id $p]
1969 set fdiffs {}
1969 set fdiffs {}
1970 } elseif {[string match ":*" $line]} {
1970 } elseif {[string match ":*" $line]} {
1971 lappend fdiffs [lindex $line 5]
1971 lappend fdiffs [lindex $line 5]
1972 }
1972 }
1973 }
1973 }
1974
1974
1975 proc donefilediff {} {
1975 proc donefilediff {} {
1976 global fdiffids fdiffs treediffs findids
1976 global fdiffids fdiffs treediffs findids
1977 global fdiffsneeded fdiffpos
1977 global fdiffsneeded fdiffpos
1978
1978
1979 if {[info exists fdiffids]} {
1979 if {[info exists fdiffids]} {
1980 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
1980 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
1981 && $fdiffpos < [llength $fdiffsneeded]} {
1981 && $fdiffpos < [llength $fdiffsneeded]} {
1982 # git-diff-tree doesn't output anything for a commit
1982 # git-diff-tree doesn't output anything for a commit
1983 # which doesn't change anything
1983 # which doesn't change anything
1984 set nullids [lindex $fdiffsneeded $fdiffpos]
1984 set nullids [lindex $fdiffsneeded $fdiffpos]
1985 set treediffs($nullids) {}
1985 set treediffs($nullids) {}
1986 if {[info exists findids] && $nullids eq $findids} {
1986 if {[info exists findids] && $nullids eq $findids} {
1987 unset findids
1987 unset findids
1988 findcont $nullids
1988 findcont $nullids
1989 }
1989 }
1990 incr fdiffpos
1990 incr fdiffpos
1991 }
1991 }
1992 incr fdiffpos
1992 incr fdiffpos
1993
1993
1994 if {![info exists treediffs($fdiffids)]} {
1994 if {![info exists treediffs($fdiffids)]} {
1995 set treediffs($fdiffids) $fdiffs
1995 set treediffs($fdiffids) $fdiffs
1996 }
1996 }
1997 if {[info exists findids] && $fdiffids eq $findids} {
1997 if {[info exists findids] && $fdiffids eq $findids} {
1998 unset findids
1998 unset findids
1999 findcont $fdiffids
1999 findcont $fdiffids
2000 }
2000 }
2001 }
2001 }
2002 }
2002 }
2003
2003
2004 proc findcont {ids} {
2004 proc findcont {ids} {
2005 global findids treediffs parents nparents
2005 global findids treediffs parents nparents
2006 global ffileline findstartline finddidsel
2006 global ffileline findstartline finddidsel
2007 global lineid numcommits matchinglines findinprogress
2007 global lineid numcommits matchinglines findinprogress
2008 global findmergefiles
2008 global findmergefiles
2009
2009
2010 set id [lindex $ids 0]
2010 set id [lindex $ids 0]
2011 set p [lindex $ids 1]
2011 set p [lindex $ids 1]
2012 set pi [lsearch -exact $parents($id) $p]
2012 set pi [lsearch -exact $parents($id) $p]
2013 set l $ffileline
2013 set l $ffileline
2014 while 1 {
2014 while 1 {
2015 if {$findmergefiles || $nparents($id) == 1} {
2015 if {$findmergefiles || $nparents($id) == 1} {
2016 if {![info exists treediffs($ids)]} {
2016 if {![info exists treediffs($ids)]} {
2017 set findids $ids
2017 set findids $ids
2018 set ffileline $l
2018 set ffileline $l
2019 return
2019 return
2020 }
2020 }
2021 set doesmatch 0
2021 set doesmatch 0
2022 foreach f $treediffs($ids) {
2022 foreach f $treediffs($ids) {
2023 set x [findmatches $f]
2023 set x [findmatches $f]
2024 if {$x != {}} {
2024 if {$x != {}} {
2025 set doesmatch 1
2025 set doesmatch 1
2026 break
2026 break
2027 }
2027 }
2028 }
2028 }
2029 if {$doesmatch} {
2029 if {$doesmatch} {
2030 insertmatch $l $id
2030 insertmatch $l $id
2031 set pi $nparents($id)
2031 set pi $nparents($id)
2032 }
2032 }
2033 } else {
2033 } else {
2034 set pi $nparents($id)
2034 set pi $nparents($id)
2035 }
2035 }
2036 if {[incr pi] >= $nparents($id)} {
2036 if {[incr pi] >= $nparents($id)} {
2037 set pi 0
2037 set pi 0
2038 if {[incr l] >= $numcommits} {
2038 if {[incr l] >= $numcommits} {
2039 set l 0
2039 set l 0
2040 }
2040 }
2041 if {$l == $findstartline} break
2041 if {$l == $findstartline} break
2042 set id $lineid($l)
2042 set id $lineid($l)
2043 }
2043 }
2044 set p [lindex $parents($id) $pi]
2044 set p [lindex $parents($id) $pi]
2045 set ids [list $id $p]
2045 set ids [list $id $p]
2046 }
2046 }
2047 stopfindproc
2047 stopfindproc
2048 if {!$finddidsel} {
2048 if {!$finddidsel} {
2049 bell
2049 bell
2050 }
2050 }
2051 }
2051 }
2052
2052
2053 # mark a commit as matching by putting a yellow background
2053 # mark a commit as matching by putting a yellow background
2054 # behind the headline
2054 # behind the headline
2055 proc markheadline {l id} {
2055 proc markheadline {l id} {
2056 global canv mainfont linehtag commitinfo
2056 global canv mainfont linehtag commitinfo
2057
2057
2058 set bbox [$canv bbox $linehtag($l)]
2058 set bbox [$canv bbox $linehtag($l)]
2059 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
2059 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
2060 $canv lower $t
2060 $canv lower $t
2061 }
2061 }
2062
2062
2063 # mark the bits of a headline, author or date that match a find string
2063 # mark the bits of a headline, author or date that match a find string
2064 proc markmatches {canv l str tag matches font} {
2064 proc markmatches {canv l str tag matches font} {
2065 set bbox [$canv bbox $tag]
2065 set bbox [$canv bbox $tag]
2066 set x0 [lindex $bbox 0]
2066 set x0 [lindex $bbox 0]
2067 set y0 [lindex $bbox 1]
2067 set y0 [lindex $bbox 1]
2068 set y1 [lindex $bbox 3]
2068 set y1 [lindex $bbox 3]
2069 foreach match $matches {
2069 foreach match $matches {
2070 set start [lindex $match 0]
2070 set start [lindex $match 0]
2071 set end [lindex $match 1]
2071 set end [lindex $match 1]
2072 if {$start > $end} continue
2072 if {$start > $end} continue
2073 set xoff [font measure $font [string range $str 0 [expr $start-1]]]
2073 set xoff [font measure $font [string range $str 0 [expr $start-1]]]
2074 set xlen [font measure $font [string range $str 0 [expr $end]]]
2074 set xlen [font measure $font [string range $str 0 [expr $end]]]
2075 set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
2075 set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
2076 -outline {} -tags matches -fill yellow]
2076 -outline {} -tags matches -fill yellow]
2077 $canv lower $t
2077 $canv lower $t
2078 }
2078 }
2079 }
2079 }
2080
2080
2081 proc unmarkmatches {} {
2081 proc unmarkmatches {} {
2082 global matchinglines findids
2082 global matchinglines findids
2083 allcanvs delete matches
2083 allcanvs delete matches
2084 catch {unset matchinglines}
2084 catch {unset matchinglines}
2085 catch {unset findids}
2085 catch {unset findids}
2086 }
2086 }
2087
2087
2088 proc selcanvline {w x y} {
2088 proc selcanvline {w x y} {
2089 global canv canvy0 ctext linespc
2089 global canv canvy0 ctext linespc
2090 global lineid linehtag linentag linedtag rowtextx
2090 global lineid linehtag linentag linedtag rowtextx
2091 set ymax [lindex [$canv cget -scrollregion] 3]
2091 set ymax [lindex [$canv cget -scrollregion] 3]
2092 if {$ymax == {}} return
2092 if {$ymax == {}} return
2093 set yfrac [lindex [$canv yview] 0]
2093 set yfrac [lindex [$canv yview] 0]
2094 set y [expr {$y + $yfrac * $ymax}]
2094 set y [expr {$y + $yfrac * $ymax}]
2095 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
2095 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
2096 if {$l < 0} {
2096 if {$l < 0} {
2097 set l 0
2097 set l 0
2098 }
2098 }
2099 if {$w eq $canv} {
2099 if {$w eq $canv} {
2100 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
2100 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
2101 }
2101 }
2102 unmarkmatches
2102 unmarkmatches
2103 selectline $l 1
2103 selectline $l 1
2104 }
2104 }
2105
2105
2106 proc commit_descriptor {p} {
2106 proc commit_descriptor {p} {
2107 global commitinfo
2107 global commitinfo
2108 set l "..."
2108 set l "..."
2109 if {[info exists commitinfo($p)]} {
2109 if {[info exists commitinfo($p)]} {
2110 set l [lindex $commitinfo($p) 0]
2110 set l [lindex $commitinfo($p) 0]
2111 set r [lindex $commitinfo($p) 6]
2111 set r [lindex $commitinfo($p) 6]
2112 }
2112 }
2113 return "$r:$p ($l)"
2113 return "$r:$p ($l)"
2114 }
2114 }
2115
2115
2116 # append some text to the ctext widget, and make any SHA1 ID
2116 # append some text to the ctext widget, and make any SHA1 ID
2117 # that we know about be a clickable link.
2117 # that we know about be a clickable link.
2118 proc appendwithlinks {text} {
2118 proc appendwithlinks {text} {
2119 global ctext idline linknum
2119 global ctext idline linknum
2120
2120
2121 set start [$ctext index "end - 1c"]
2121 set start [$ctext index "end - 1c"]
2122 $ctext insert end $text
2122 $ctext insert end $text
2123 $ctext insert end "\n"
2123 $ctext insert end "\n"
2124 set links [regexp -indices -all -inline {[0-9a-f]{12}} $text]
2124 set links [regexp -indices -all -inline {[0-9a-f]{12}} $text]
2125 foreach l $links {
2125 foreach l $links {
2126 set s [lindex $l 0]
2126 set s [lindex $l 0]
2127 set e [lindex $l 1]
2127 set e [lindex $l 1]
2128 set linkid [string range $text $s $e]
2128 set linkid [string range $text $s $e]
2129 if {![info exists idline($linkid)]} continue
2129 if {![info exists idline($linkid)]} continue
2130 incr e
2130 incr e
2131 $ctext tag add link "$start + $s c" "$start + $e c"
2131 $ctext tag add link "$start + $s c" "$start + $e c"
2132 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
2132 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
2133 $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
2133 $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
2134 incr linknum
2134 incr linknum
2135 }
2135 }
2136 $ctext tag conf link -foreground blue -underline 1
2136 $ctext tag conf link -foreground blue -underline 1
2137 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
2137 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
2138 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
2138 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
2139 }
2139 }
2140
2140
2141 proc selectline {l isnew} {
2141 proc selectline {l isnew} {
2142 global canv canv2 canv3 ctext commitinfo selectedline
2142 global canv canv2 canv3 ctext commitinfo selectedline
2143 global lineid linehtag linentag linedtag
2143 global lineid linehtag linentag linedtag
2144 global canvy0 linespc parents nparents children
2144 global canvy0 linespc parents nparents children
2145 global cflist currentid sha1entry
2145 global cflist currentid sha1entry
2146 global commentend idtags idline linknum
2146 global commentend idtags idline linknum
2147
2147
2148 $canv delete hover
2148 $canv delete hover
2149 normalline
2149 normalline
2150 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
2150 if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
2151 $canv delete secsel
2151 $canv delete secsel
2152 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
2152 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
2153 -tags secsel -fill [$canv cget -selectbackground]]
2153 -tags secsel -fill [$canv cget -selectbackground]]
2154 $canv lower $t
2154 $canv lower $t
2155 $canv2 delete secsel
2155 $canv2 delete secsel
2156 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
2156 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
2157 -tags secsel -fill [$canv2 cget -selectbackground]]
2157 -tags secsel -fill [$canv2 cget -selectbackground]]
2158 $canv2 lower $t
2158 $canv2 lower $t
2159 $canv3 delete secsel
2159 $canv3 delete secsel
2160 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
2160 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
2161 -tags secsel -fill [$canv3 cget -selectbackground]]
2161 -tags secsel -fill [$canv3 cget -selectbackground]]
2162 $canv3 lower $t
2162 $canv3 lower $t
2163 set y [expr {$canvy0 + $l * $linespc}]
2163 set y [expr {$canvy0 + $l * $linespc}]
2164 set ymax [lindex [$canv cget -scrollregion] 3]
2164 set ymax [lindex [$canv cget -scrollregion] 3]
2165 set ytop [expr {$y - $linespc - 1}]
2165 set ytop [expr {$y - $linespc - 1}]
2166 set ybot [expr {$y + $linespc + 1}]
2166 set ybot [expr {$y + $linespc + 1}]
2167 set wnow [$canv yview]
2167 set wnow [$canv yview]
2168 set wtop [expr [lindex $wnow 0] * $ymax]
2168 set wtop [expr [lindex $wnow 0] * $ymax]
2169 set wbot [expr [lindex $wnow 1] * $ymax]
2169 set wbot [expr [lindex $wnow 1] * $ymax]
2170 set wh [expr {$wbot - $wtop}]
2170 set wh [expr {$wbot - $wtop}]
2171 set newtop $wtop
2171 set newtop $wtop
2172 if {$ytop < $wtop} {
2172 if {$ytop < $wtop} {
2173 if {$ybot < $wtop} {
2173 if {$ybot < $wtop} {
2174 set newtop [expr {$y - $wh / 2.0}]
2174 set newtop [expr {$y - $wh / 2.0}]
2175 } else {
2175 } else {
2176 set newtop $ytop
2176 set newtop $ytop
2177 if {$newtop > $wtop - $linespc} {
2177 if {$newtop > $wtop - $linespc} {
2178 set newtop [expr {$wtop - $linespc}]
2178 set newtop [expr {$wtop - $linespc}]
2179 }
2179 }
2180 }
2180 }
2181 } elseif {$ybot > $wbot} {
2181 } elseif {$ybot > $wbot} {
2182 if {$ytop > $wbot} {
2182 if {$ytop > $wbot} {
2183 set newtop [expr {$y - $wh / 2.0}]
2183 set newtop [expr {$y - $wh / 2.0}]
2184 } else {
2184 } else {
2185 set newtop [expr {$ybot - $wh}]
2185 set newtop [expr {$ybot - $wh}]
2186 if {$newtop < $wtop + $linespc} {
2186 if {$newtop < $wtop + $linespc} {
2187 set newtop [expr {$wtop + $linespc}]
2187 set newtop [expr {$wtop + $linespc}]
2188 }
2188 }
2189 }
2189 }
2190 }
2190 }
2191 if {$newtop != $wtop} {
2191 if {$newtop != $wtop} {
2192 if {$newtop < 0} {
2192 if {$newtop < 0} {
2193 set newtop 0
2193 set newtop 0
2194 }
2194 }
2195 allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
2195 allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
2196 }
2196 }
2197
2197
2198 if {$isnew} {
2198 if {$isnew} {
2199 addtohistory [list selectline $l 0]
2199 addtohistory [list selectline $l 0]
2200 }
2200 }
2201
2201
2202 set selectedline $l
2202 set selectedline $l
2203
2203
2204 set id $lineid($l)
2204 set id $lineid($l)
2205 set currentid $id
2205 set currentid $id
2206 $sha1entry delete 0 end
2206 $sha1entry delete 0 end
2207 $sha1entry insert 0 $id
2207 $sha1entry insert 0 $id
2208 $sha1entry selection from 0
2208 $sha1entry selection from 0
2209 $sha1entry selection to end
2209 $sha1entry selection to end
2210
2210
2211 $ctext conf -state normal
2211 $ctext conf -state normal
2212 $ctext delete 0.0 end
2212 $ctext delete 0.0 end
2213 set linknum 0
2213 set linknum 0
2214 $ctext mark set fmark.0 0.0
2214 $ctext mark set fmark.0 0.0
2215 $ctext mark gravity fmark.0 left
2215 $ctext mark gravity fmark.0 left
2216 set info $commitinfo($id)
2216 set info $commitinfo($id)
2217 $ctext insert end "Revision: [lindex $info 6]\n"
2217 $ctext insert end "Revision: [lindex $info 6]\n"
2218 $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n"
2218 $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n"
2219 $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
2219 $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
2220 if {[info exists idtags($id)]} {
2220 if {[info exists idtags($id)]} {
2221 $ctext insert end "Tags:"
2221 $ctext insert end "Tags:"
2222 foreach tag $idtags($id) {
2222 foreach tag $idtags($id) {
2223 $ctext insert end " $tag"
2223 $ctext insert end " $tag"
2224 }
2224 }
2225 $ctext insert end "\n"
2225 $ctext insert end "\n"
2226 }
2226 }
2227
2227
2228 set comment {}
2228 set comment {}
2229 if {[info exists parents($id)]} {
2229 if {[info exists parents($id)]} {
2230 foreach p $parents($id) {
2230 foreach p $parents($id) {
2231 append comment "Parent: [commit_descriptor $p]\n"
2231 append comment "Parent: [commit_descriptor $p]\n"
2232 }
2232 }
2233 }
2233 }
2234 if {[info exists children($id)]} {
2234 if {[info exists children($id)]} {
2235 foreach c $children($id) {
2235 foreach c $children($id) {
2236 append comment "Child: [commit_descriptor $c]\n"
2236 append comment "Child: [commit_descriptor $c]\n"
2237 }
2237 }
2238 }
2238 }
2239 append comment "\n"
2239 append comment "\n"
2240 append comment [lindex $info 5]
2240 append comment [lindex $info 5]
2241
2241
2242 # make anything that looks like a SHA1 ID be a clickable link
2242 # make anything that looks like a SHA1 ID be a clickable link
2243 appendwithlinks $comment
2243 appendwithlinks $comment
2244
2244
2245 $ctext tag delete Comments
2245 $ctext tag delete Comments
2246 $ctext tag remove found 1.0 end
2246 $ctext tag remove found 1.0 end
2247 $ctext conf -state disabled
2247 $ctext conf -state disabled
2248 set commentend [$ctext index "end - 1c"]
2248 set commentend [$ctext index "end - 1c"]
2249
2249
2250 $cflist delete 0 end
2250 $cflist delete 0 end
2251 $cflist insert end "Comments"
2251 $cflist insert end "Comments"
2252 if {$nparents($id) == 1} {
2252 if {$nparents($id) == 1} {
2253 startdiff [concat $id $parents($id)]
2253 startdiff [concat $id $parents($id)]
2254 } elseif {$nparents($id) > 1} {
2254 } elseif {$nparents($id) > 1} {
2255 mergediff $id
2255 mergediff $id
2256 }
2256 }
2257 }
2257 }
2258
2258
2259 proc selnextline {dir} {
2259 proc selnextline {dir} {
2260 global selectedline
2260 global selectedline
2261 if {![info exists selectedline]} return
2261 if {![info exists selectedline]} return
2262 set l [expr $selectedline + $dir]
2262 set l [expr $selectedline + $dir]
2263 unmarkmatches
2263 unmarkmatches
2264 selectline $l 1
2264 selectline $l 1
2265 }
2265 }
2266
2266
2267 proc unselectline {} {
2267 proc unselectline {} {
2268 global selectedline
2268 global selectedline
2269
2269
2270 catch {unset selectedline}
2270 catch {unset selectedline}
2271 allcanvs delete secsel
2271 allcanvs delete secsel
2272 }
2272 }
2273
2273
2274 proc addtohistory {cmd} {
2274 proc addtohistory {cmd} {
2275 global history historyindex
2275 global history historyindex
2276
2276
2277 if {$historyindex > 0
2277 if {$historyindex > 0
2278 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2278 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2279 return
2279 return
2280 }
2280 }
2281
2281
2282 if {$historyindex < [llength $history]} {
2282 if {$historyindex < [llength $history]} {
2283 set history [lreplace $history $historyindex end $cmd]
2283 set history [lreplace $history $historyindex end $cmd]
2284 } else {
2284 } else {
2285 lappend history $cmd
2285 lappend history $cmd
2286 }
2286 }
2287 incr historyindex
2287 incr historyindex
2288 if {$historyindex > 1} {
2288 if {$historyindex > 1} {
2289 .ctop.top.bar.leftbut conf -state normal
2289 .ctop.top.bar.leftbut conf -state normal
2290 } else {
2290 } else {
2291 .ctop.top.bar.leftbut conf -state disabled
2291 .ctop.top.bar.leftbut conf -state disabled
2292 }
2292 }
2293 .ctop.top.bar.rightbut conf -state disabled
2293 .ctop.top.bar.rightbut conf -state disabled
2294 }
2294 }
2295
2295
2296 proc goback {} {
2296 proc goback {} {
2297 global history historyindex
2297 global history historyindex
2298
2298
2299 if {$historyindex > 1} {
2299 if {$historyindex > 1} {
2300 incr historyindex -1
2300 incr historyindex -1
2301 set cmd [lindex $history [expr {$historyindex - 1}]]
2301 set cmd [lindex $history [expr {$historyindex - 1}]]
2302 eval $cmd
2302 eval $cmd
2303 .ctop.top.bar.rightbut conf -state normal
2303 .ctop.top.bar.rightbut conf -state normal
2304 }
2304 }
2305 if {$historyindex <= 1} {
2305 if {$historyindex <= 1} {
2306 .ctop.top.bar.leftbut conf -state disabled
2306 .ctop.top.bar.leftbut conf -state disabled
2307 }
2307 }
2308 }
2308 }
2309
2309
2310 proc goforw {} {
2310 proc goforw {} {
2311 global history historyindex
2311 global history historyindex
2312
2312
2313 if {$historyindex < [llength $history]} {
2313 if {$historyindex < [llength $history]} {
2314 set cmd [lindex $history $historyindex]
2314 set cmd [lindex $history $historyindex]
2315 incr historyindex
2315 incr historyindex
2316 eval $cmd
2316 eval $cmd
2317 .ctop.top.bar.leftbut conf -state normal
2317 .ctop.top.bar.leftbut conf -state normal
2318 }
2318 }
2319 if {$historyindex >= [llength $history]} {
2319 if {$historyindex >= [llength $history]} {
2320 .ctop.top.bar.rightbut conf -state disabled
2320 .ctop.top.bar.rightbut conf -state disabled
2321 }
2321 }
2322 }
2322 }
2323
2323
2324 proc mergediff {id} {
2324 proc mergediff {id} {
2325 global parents diffmergeid diffmergegca mergefilelist diffpindex
2325 global parents diffmergeid diffmergegca mergefilelist diffpindex
2326
2326
2327 set diffmergeid $id
2327 set diffmergeid $id
2328 set diffpindex -1
2328 set diffpindex -1
2329 set diffmergegca [findgca $parents($id)]
2329 set diffmergegca [findgca $parents($id)]
2330 if {[info exists mergefilelist($id)]} {
2330 if {[info exists mergefilelist($id)]} {
2331 if {$mergefilelist($id) ne {}} {
2331 if {$mergefilelist($id) ne {}} {
2332 showmergediff
2332 showmergediff
2333 }
2333 }
2334 } else {
2334 } else {
2335 contmergediff {}
2335 contmergediff {}
2336 }
2336 }
2337 }
2337 }
2338
2338
2339 proc findgca {ids} {
2339 proc findgca {ids} {
2340 global env
2340 global env
2341 set gca {}
2341 set gca {}
2342 foreach id $ids {
2342 foreach id $ids {
2343 if {$gca eq {}} {
2343 if {$gca eq {}} {
2344 set gca $id
2344 set gca $id
2345 } else {
2345 } else {
2346 if {[catch {
2346 if {[catch {
2347 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2347 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2348 } err]} {
2348 } err]} {
2349 return {}
2349 return {}
2350 }
2350 }
2351 }
2351 }
2352 }
2352 }
2353 return $gca
2353 return $gca
2354 }
2354 }
2355
2355
2356 proc contmergediff {ids} {
2356 proc contmergediff {ids} {
2357 global diffmergeid diffpindex parents nparents diffmergegca
2357 global diffmergeid diffpindex parents nparents diffmergegca
2358 global treediffs mergefilelist diffids treepending
2358 global treediffs mergefilelist diffids treepending
2359
2359
2360 # diff the child against each of the parents, and diff
2360 # diff the child against each of the parents, and diff
2361 # each of the parents against the GCA.
2361 # each of the parents against the GCA.
2362 while 1 {
2362 while 1 {
2363 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2363 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2364 set ids [list [lindex $ids 1] $diffmergegca]
2364 set ids [list [lindex $ids 1] $diffmergegca]
2365 } else {
2365 } else {
2366 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2366 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2367 set p [lindex $parents($diffmergeid) $diffpindex]
2367 set p [lindex $parents($diffmergeid) $diffpindex]
2368 set ids [list $diffmergeid $p]
2368 set ids [list $diffmergeid $p]
2369 }
2369 }
2370 if {![info exists treediffs($ids)]} {
2370 if {![info exists treediffs($ids)]} {
2371 set diffids $ids
2371 set diffids $ids
2372 if {![info exists treepending]} {
2372 if {![info exists treepending]} {
2373 gettreediffs $ids
2373 gettreediffs $ids
2374 }
2374 }
2375 return
2375 return
2376 }
2376 }
2377 }
2377 }
2378
2378
2379 # If a file in some parent is different from the child and also
2379 # If a file in some parent is different from the child and also
2380 # different from the GCA, then it's interesting.
2380 # different from the GCA, then it's interesting.
2381 # If we don't have a GCA, then a file is interesting if it is
2381 # If we don't have a GCA, then a file is interesting if it is
2382 # different from the child in all the parents.
2382 # different from the child in all the parents.
2383 if {$diffmergegca ne {}} {
2383 if {$diffmergegca ne {}} {
2384 set files {}
2384 set files {}
2385 foreach p $parents($diffmergeid) {
2385 foreach p $parents($diffmergeid) {
2386 set gcadiffs $treediffs([list $p $diffmergegca])
2386 set gcadiffs $treediffs([list $p $diffmergegca])
2387 foreach f $treediffs([list $diffmergeid $p]) {
2387 foreach f $treediffs([list $diffmergeid $p]) {
2388 if {[lsearch -exact $files $f] < 0
2388 if {[lsearch -exact $files $f] < 0
2389 && [lsearch -exact $gcadiffs $f] >= 0} {
2389 && [lsearch -exact $gcadiffs $f] >= 0} {
2390 lappend files $f
2390 lappend files $f
2391 }
2391 }
2392 }
2392 }
2393 }
2393 }
2394 set files [lsort $files]
2394 set files [lsort $files]
2395 } else {
2395 } else {
2396 set p [lindex $parents($diffmergeid) 0]
2396 set p [lindex $parents($diffmergeid) 0]
2397 set files $treediffs([list $diffmergeid $p])
2397 set files $treediffs([list $diffmergeid $p])
2398 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2398 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2399 set p [lindex $parents($diffmergeid) $i]
2399 set p [lindex $parents($diffmergeid) $i]
2400 set df $treediffs([list $diffmergeid $p])
2400 set df $treediffs([list $diffmergeid $p])
2401 set nf {}
2401 set nf {}
2402 foreach f $files {
2402 foreach f $files {
2403 if {[lsearch -exact $df $f] >= 0} {
2403 if {[lsearch -exact $df $f] >= 0} {
2404 lappend nf $f
2404 lappend nf $f
2405 }
2405 }
2406 }
2406 }
2407 set files $nf
2407 set files $nf
2408 }
2408 }
2409 }
2409 }
2410
2410
2411 set mergefilelist($diffmergeid) $files
2411 set mergefilelist($diffmergeid) $files
2412 if {$files ne {}} {
2412 if {$files ne {}} {
2413 showmergediff
2413 showmergediff
2414 }
2414 }
2415 }
2415 }
2416
2416
2417 proc showmergediff {} {
2417 proc showmergediff {} {
2418 global cflist diffmergeid mergefilelist parents
2418 global cflist diffmergeid mergefilelist parents
2419 global diffopts diffinhunk currentfile currenthunk filelines
2419 global diffopts diffinhunk currentfile currenthunk filelines
2420 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2420 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2421 global env
2421 global env
2422
2422
2423 set files $mergefilelist($diffmergeid)
2423 set files $mergefilelist($diffmergeid)
2424 foreach f $files {
2424 foreach f $files {
2425 $cflist insert end $f
2425 $cflist insert end $f
2426 }
2426 }
2427 set env(GIT_DIFF_OPTS) $diffopts
2427 set env(GIT_DIFF_OPTS) $diffopts
2428 set flist {}
2428 set flist {}
2429 catch {unset currentfile}
2429 catch {unset currentfile}
2430 catch {unset currenthunk}
2430 catch {unset currenthunk}
2431 catch {unset filelines}
2431 catch {unset filelines}
2432 catch {unset groupfilenum}
2432 catch {unset groupfilenum}
2433 catch {unset grouphunks}
2433 catch {unset grouphunks}
2434 set groupfilelast -1
2434 set groupfilelast -1
2435 foreach p $parents($diffmergeid) {
2435 foreach p $parents($diffmergeid) {
2436 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2436 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2437 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2437 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2438 if {[catch {set f [open $cmd r]} err]} {
2438 if {[catch {set f [open $cmd r]} err]} {
2439 error_popup "Error getting diffs: $err"
2439 error_popup "Error getting diffs: $err"
2440 foreach f $flist {
2440 foreach f $flist {
2441 catch {close $f}
2441 catch {close $f}
2442 }
2442 }
2443 return
2443 return
2444 }
2444 }
2445 lappend flist $f
2445 lappend flist $f
2446 set ids [list $diffmergeid $p]
2446 set ids [list $diffmergeid $p]
2447 set mergefds($ids) $f
2447 set mergefds($ids) $f
2448 set diffinhunk($ids) 0
2448 set diffinhunk($ids) 0
2449 set diffblocked($ids) 0
2449 set diffblocked($ids) 0
2450 fconfigure $f -blocking 0
2450 fconfigure $f -blocking 0
2451 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2451 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2452 }
2452 }
2453 }
2453 }
2454
2454
2455 proc getmergediffline {f ids id} {
2455 proc getmergediffline {f ids id} {
2456 global diffmergeid diffinhunk diffoldlines diffnewlines
2456 global diffmergeid diffinhunk diffoldlines diffnewlines
2457 global currentfile currenthunk
2457 global currentfile currenthunk
2458 global diffoldstart diffnewstart diffoldlno diffnewlno
2458 global diffoldstart diffnewstart diffoldlno diffnewlno
2459 global diffblocked mergefilelist
2459 global diffblocked mergefilelist
2460 global noldlines nnewlines difflcounts filelines
2460 global noldlines nnewlines difflcounts filelines
2461
2461
2462 set n [gets $f line]
2462 set n [gets $f line]
2463 if {$n < 0} {
2463 if {$n < 0} {
2464 if {![eof $f]} return
2464 if {![eof $f]} return
2465 }
2465 }
2466
2466
2467 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2467 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2468 if {$n < 0} {
2468 if {$n < 0} {
2469 close $f
2469 close $f
2470 }
2470 }
2471 return
2471 return
2472 }
2472 }
2473
2473
2474 if {$diffinhunk($ids) != 0} {
2474 if {$diffinhunk($ids) != 0} {
2475 set fi $currentfile($ids)
2475 set fi $currentfile($ids)
2476 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2476 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2477 # continuing an existing hunk
2477 # continuing an existing hunk
2478 set line [string range $line 1 end]
2478 set line [string range $line 1 end]
2479 set p [lindex $ids 1]
2479 set p [lindex $ids 1]
2480 if {$match eq "-" || $match eq " "} {
2480 if {$match eq "-" || $match eq " "} {
2481 set filelines($p,$fi,$diffoldlno($ids)) $line
2481 set filelines($p,$fi,$diffoldlno($ids)) $line
2482 incr diffoldlno($ids)
2482 incr diffoldlno($ids)
2483 }
2483 }
2484 if {$match eq "+" || $match eq " "} {
2484 if {$match eq "+" || $match eq " "} {
2485 set filelines($id,$fi,$diffnewlno($ids)) $line
2485 set filelines($id,$fi,$diffnewlno($ids)) $line
2486 incr diffnewlno($ids)
2486 incr diffnewlno($ids)
2487 }
2487 }
2488 if {$match eq " "} {
2488 if {$match eq " "} {
2489 if {$diffinhunk($ids) == 2} {
2489 if {$diffinhunk($ids) == 2} {
2490 lappend difflcounts($ids) \
2490 lappend difflcounts($ids) \
2491 [list $noldlines($ids) $nnewlines($ids)]
2491 [list $noldlines($ids) $nnewlines($ids)]
2492 set noldlines($ids) 0
2492 set noldlines($ids) 0
2493 set diffinhunk($ids) 1
2493 set diffinhunk($ids) 1
2494 }
2494 }
2495 incr noldlines($ids)
2495 incr noldlines($ids)
2496 } elseif {$match eq "-" || $match eq "+"} {
2496 } elseif {$match eq "-" || $match eq "+"} {
2497 if {$diffinhunk($ids) == 1} {
2497 if {$diffinhunk($ids) == 1} {
2498 lappend difflcounts($ids) [list $noldlines($ids)]
2498 lappend difflcounts($ids) [list $noldlines($ids)]
2499 set noldlines($ids) 0
2499 set noldlines($ids) 0
2500 set nnewlines($ids) 0
2500 set nnewlines($ids) 0
2501 set diffinhunk($ids) 2
2501 set diffinhunk($ids) 2
2502 }
2502 }
2503 if {$match eq "-"} {
2503 if {$match eq "-"} {
2504 incr noldlines($ids)
2504 incr noldlines($ids)
2505 } else {
2505 } else {
2506 incr nnewlines($ids)
2506 incr nnewlines($ids)
2507 }
2507 }
2508 }
2508 }
2509 # and if it's \ No newline at end of line, then what?
2509 # and if it's \ No newline at end of line, then what?
2510 return
2510 return
2511 }
2511 }
2512 # end of a hunk
2512 # end of a hunk
2513 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2513 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2514 lappend difflcounts($ids) [list $noldlines($ids)]
2514 lappend difflcounts($ids) [list $noldlines($ids)]
2515 } elseif {$diffinhunk($ids) == 2
2515 } elseif {$diffinhunk($ids) == 2
2516 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2516 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2517 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2517 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2518 }
2518 }
2519 set currenthunk($ids) [list $currentfile($ids) \
2519 set currenthunk($ids) [list $currentfile($ids) \
2520 $diffoldstart($ids) $diffnewstart($ids) \
2520 $diffoldstart($ids) $diffnewstart($ids) \
2521 $diffoldlno($ids) $diffnewlno($ids) \
2521 $diffoldlno($ids) $diffnewlno($ids) \
2522 $difflcounts($ids)]
2522 $difflcounts($ids)]
2523 set diffinhunk($ids) 0
2523 set diffinhunk($ids) 0
2524 # -1 = need to block, 0 = unblocked, 1 = is blocked
2524 # -1 = need to block, 0 = unblocked, 1 = is blocked
2525 set diffblocked($ids) -1
2525 set diffblocked($ids) -1
2526 processhunks
2526 processhunks
2527 if {$diffblocked($ids) == -1} {
2527 if {$diffblocked($ids) == -1} {
2528 fileevent $f readable {}
2528 fileevent $f readable {}
2529 set diffblocked($ids) 1
2529 set diffblocked($ids) 1
2530 }
2530 }
2531 }
2531 }
2532
2532
2533 if {$n < 0} {
2533 if {$n < 0} {
2534 # eof
2534 # eof
2535 if {!$diffblocked($ids)} {
2535 if {!$diffblocked($ids)} {
2536 close $f
2536 close $f
2537 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2537 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2538 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2538 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2539 processhunks
2539 processhunks
2540 }
2540 }
2541 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2541 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2542 # start of a new file
2542 # start of a new file
2543 set currentfile($ids) \
2543 set currentfile($ids) \
2544 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2544 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2545 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2545 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2546 $line match f1l f1c f2l f2c rest]} {
2546 $line match f1l f1c f2l f2c rest]} {
2547 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2547 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2548 # start of a new hunk
2548 # start of a new hunk
2549 if {$f1l == 0 && $f1c == 0} {
2549 if {$f1l == 0 && $f1c == 0} {
2550 set f1l 1
2550 set f1l 1
2551 }
2551 }
2552 if {$f2l == 0 && $f2c == 0} {
2552 if {$f2l == 0 && $f2c == 0} {
2553 set f2l 1
2553 set f2l 1
2554 }
2554 }
2555 set diffinhunk($ids) 1
2555 set diffinhunk($ids) 1
2556 set diffoldstart($ids) $f1l
2556 set diffoldstart($ids) $f1l
2557 set diffnewstart($ids) $f2l
2557 set diffnewstart($ids) $f2l
2558 set diffoldlno($ids) $f1l
2558 set diffoldlno($ids) $f1l
2559 set diffnewlno($ids) $f2l
2559 set diffnewlno($ids) $f2l
2560 set difflcounts($ids) {}
2560 set difflcounts($ids) {}
2561 set noldlines($ids) 0
2561 set noldlines($ids) 0
2562 set nnewlines($ids) 0
2562 set nnewlines($ids) 0
2563 }
2563 }
2564 }
2564 }
2565 }
2565 }
2566
2566
2567 proc processhunks {} {
2567 proc processhunks {} {
2568 global diffmergeid parents nparents currenthunk
2568 global diffmergeid parents nparents currenthunk
2569 global mergefilelist diffblocked mergefds
2569 global mergefilelist diffblocked mergefds
2570 global grouphunks grouplinestart grouplineend groupfilenum
2570 global grouphunks grouplinestart grouplineend groupfilenum
2571
2571
2572 set nfiles [llength $mergefilelist($diffmergeid)]
2572 set nfiles [llength $mergefilelist($diffmergeid)]
2573 while 1 {
2573 while 1 {
2574 set fi $nfiles
2574 set fi $nfiles
2575 set lno 0
2575 set lno 0
2576 # look for the earliest hunk
2576 # look for the earliest hunk
2577 foreach p $parents($diffmergeid) {
2577 foreach p $parents($diffmergeid) {
2578 set ids [list $diffmergeid $p]
2578 set ids [list $diffmergeid $p]
2579 if {![info exists currenthunk($ids)]} return
2579 if {![info exists currenthunk($ids)]} return
2580 set i [lindex $currenthunk($ids) 0]
2580 set i [lindex $currenthunk($ids) 0]
2581 set l [lindex $currenthunk($ids) 2]
2581 set l [lindex $currenthunk($ids) 2]
2582 if {$i < $fi || ($i == $fi && $l < $lno)} {
2582 if {$i < $fi || ($i == $fi && $l < $lno)} {
2583 set fi $i
2583 set fi $i
2584 set lno $l
2584 set lno $l
2585 set pi $p
2585 set pi $p
2586 }
2586 }
2587 }
2587 }
2588
2588
2589 if {$fi < $nfiles} {
2589 if {$fi < $nfiles} {
2590 set ids [list $diffmergeid $pi]
2590 set ids [list $diffmergeid $pi]
2591 set hunk $currenthunk($ids)
2591 set hunk $currenthunk($ids)
2592 unset currenthunk($ids)
2592 unset currenthunk($ids)
2593 if {$diffblocked($ids) > 0} {
2593 if {$diffblocked($ids) > 0} {
2594 fileevent $mergefds($ids) readable \
2594 fileevent $mergefds($ids) readable \
2595 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2595 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2596 }
2596 }
2597 set diffblocked($ids) 0
2597 set diffblocked($ids) 0
2598
2598
2599 if {[info exists groupfilenum] && $groupfilenum == $fi
2599 if {[info exists groupfilenum] && $groupfilenum == $fi
2600 && $lno <= $grouplineend} {
2600 && $lno <= $grouplineend} {
2601 # add this hunk to the pending group
2601 # add this hunk to the pending group
2602 lappend grouphunks($pi) $hunk
2602 lappend grouphunks($pi) $hunk
2603 set endln [lindex $hunk 4]
2603 set endln [lindex $hunk 4]
2604 if {$endln > $grouplineend} {
2604 if {$endln > $grouplineend} {
2605 set grouplineend $endln
2605 set grouplineend $endln
2606 }
2606 }
2607 continue
2607 continue
2608 }
2608 }
2609 }
2609 }
2610
2610
2611 # succeeding stuff doesn't belong in this group, so
2611 # succeeding stuff doesn't belong in this group, so
2612 # process the group now
2612 # process the group now
2613 if {[info exists groupfilenum]} {
2613 if {[info exists groupfilenum]} {
2614 processgroup
2614 processgroup
2615 unset groupfilenum
2615 unset groupfilenum
2616 unset grouphunks
2616 unset grouphunks
2617 }
2617 }
2618
2618
2619 if {$fi >= $nfiles} break
2619 if {$fi >= $nfiles} break
2620
2620
2621 # start a new group
2621 # start a new group
2622 set groupfilenum $fi
2622 set groupfilenum $fi
2623 set grouphunks($pi) [list $hunk]
2623 set grouphunks($pi) [list $hunk]
2624 set grouplinestart $lno
2624 set grouplinestart $lno
2625 set grouplineend [lindex $hunk 4]
2625 set grouplineend [lindex $hunk 4]
2626 }
2626 }
2627 }
2627 }
2628
2628
2629 proc processgroup {} {
2629 proc processgroup {} {
2630 global groupfilelast groupfilenum difffilestart
2630 global groupfilelast groupfilenum difffilestart
2631 global mergefilelist diffmergeid ctext filelines
2631 global mergefilelist diffmergeid ctext filelines
2632 global parents diffmergeid diffoffset
2632 global parents diffmergeid diffoffset
2633 global grouphunks grouplinestart grouplineend nparents
2633 global grouphunks grouplinestart grouplineend nparents
2634 global mergemax
2634 global mergemax
2635
2635
2636 $ctext conf -state normal
2636 $ctext conf -state normal
2637 set id $diffmergeid
2637 set id $diffmergeid
2638 set f $groupfilenum
2638 set f $groupfilenum
2639 if {$groupfilelast != $f} {
2639 if {$groupfilelast != $f} {
2640 $ctext insert end "\n"
2640 $ctext insert end "\n"
2641 set here [$ctext index "end - 1c"]
2641 set here [$ctext index "end - 1c"]
2642 set difffilestart($f) $here
2642 set difffilestart($f) $here
2643 set mark fmark.[expr {$f + 1}]
2643 set mark fmark.[expr {$f + 1}]
2644 $ctext mark set $mark $here
2644 $ctext mark set $mark $here
2645 $ctext mark gravity $mark left
2645 $ctext mark gravity $mark left
2646 set header [lindex $mergefilelist($id) $f]
2646 set header [lindex $mergefilelist($id) $f]
2647 set l [expr {(78 - [string length $header]) / 2}]
2647 set l [expr {(78 - [string length $header]) / 2}]
2648 set pad [string range "----------------------------------------" 1 $l]
2648 set pad [string range "----------------------------------------" 1 $l]
2649 $ctext insert end "$pad $header $pad\n" filesep
2649 $ctext insert end "$pad $header $pad\n" filesep
2650 set groupfilelast $f
2650 set groupfilelast $f
2651 foreach p $parents($id) {
2651 foreach p $parents($id) {
2652 set diffoffset($p) 0
2652 set diffoffset($p) 0
2653 }
2653 }
2654 }
2654 }
2655
2655
2656 $ctext insert end "@@" msep
2656 $ctext insert end "@@" msep
2657 set nlines [expr {$grouplineend - $grouplinestart}]
2657 set nlines [expr {$grouplineend - $grouplinestart}]
2658 set events {}
2658 set events {}
2659 set pnum 0
2659 set pnum 0
2660 foreach p $parents($id) {
2660 foreach p $parents($id) {
2661 set startline [expr {$grouplinestart + $diffoffset($p)}]
2661 set startline [expr {$grouplinestart + $diffoffset($p)}]
2662 set ol $startline
2662 set ol $startline
2663 set nl $grouplinestart
2663 set nl $grouplinestart
2664 if {[info exists grouphunks($p)]} {
2664 if {[info exists grouphunks($p)]} {
2665 foreach h $grouphunks($p) {
2665 foreach h $grouphunks($p) {
2666 set l [lindex $h 2]
2666 set l [lindex $h 2]
2667 if {$nl < $l} {
2667 if {$nl < $l} {
2668 for {} {$nl < $l} {incr nl} {
2668 for {} {$nl < $l} {incr nl} {
2669 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2669 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2670 incr ol
2670 incr ol
2671 }
2671 }
2672 }
2672 }
2673 foreach chunk [lindex $h 5] {
2673 foreach chunk [lindex $h 5] {
2674 if {[llength $chunk] == 2} {
2674 if {[llength $chunk] == 2} {
2675 set olc [lindex $chunk 0]
2675 set olc [lindex $chunk 0]
2676 set nlc [lindex $chunk 1]
2676 set nlc [lindex $chunk 1]
2677 set nnl [expr {$nl + $nlc}]
2677 set nnl [expr {$nl + $nlc}]
2678 lappend events [list $nl $nnl $pnum $olc $nlc]
2678 lappend events [list $nl $nnl $pnum $olc $nlc]
2679 incr ol $olc
2679 incr ol $olc
2680 set nl $nnl
2680 set nl $nnl
2681 } else {
2681 } else {
2682 incr ol [lindex $chunk 0]
2682 incr ol [lindex $chunk 0]
2683 incr nl [lindex $chunk 0]
2683 incr nl [lindex $chunk 0]
2684 }
2684 }
2685 }
2685 }
2686 }
2686 }
2687 }
2687 }
2688 if {$nl < $grouplineend} {
2688 if {$nl < $grouplineend} {
2689 for {} {$nl < $grouplineend} {incr nl} {
2689 for {} {$nl < $grouplineend} {incr nl} {
2690 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2690 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2691 incr ol
2691 incr ol
2692 }
2692 }
2693 }
2693 }
2694 set nlines [expr {$ol - $startline}]
2694 set nlines [expr {$ol - $startline}]
2695 $ctext insert end " -$startline,$nlines" msep
2695 $ctext insert end " -$startline,$nlines" msep
2696 incr pnum
2696 incr pnum
2697 }
2697 }
2698
2698
2699 set nlines [expr {$grouplineend - $grouplinestart}]
2699 set nlines [expr {$grouplineend - $grouplinestart}]
2700 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2700 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2701
2701
2702 set events [lsort -integer -index 0 $events]
2702 set events [lsort -integer -index 0 $events]
2703 set nevents [llength $events]
2703 set nevents [llength $events]
2704 set nmerge $nparents($diffmergeid)
2704 set nmerge $nparents($diffmergeid)
2705 set l $grouplinestart
2705 set l $grouplinestart
2706 for {set i 0} {$i < $nevents} {set i $j} {
2706 for {set i 0} {$i < $nevents} {set i $j} {
2707 set nl [lindex $events $i 0]
2707 set nl [lindex $events $i 0]
2708 while {$l < $nl} {
2708 while {$l < $nl} {
2709 $ctext insert end " $filelines($id,$f,$l)\n"
2709 $ctext insert end " $filelines($id,$f,$l)\n"
2710 incr l
2710 incr l
2711 }
2711 }
2712 set e [lindex $events $i]
2712 set e [lindex $events $i]
2713 set enl [lindex $e 1]
2713 set enl [lindex $e 1]
2714 set j $i
2714 set j $i
2715 set active {}
2715 set active {}
2716 while 1 {
2716 while 1 {
2717 set pnum [lindex $e 2]
2717 set pnum [lindex $e 2]
2718 set olc [lindex $e 3]
2718 set olc [lindex $e 3]
2719 set nlc [lindex $e 4]
2719 set nlc [lindex $e 4]
2720 if {![info exists delta($pnum)]} {
2720 if {![info exists delta($pnum)]} {
2721 set delta($pnum) [expr {$olc - $nlc}]
2721 set delta($pnum) [expr {$olc - $nlc}]
2722 lappend active $pnum
2722 lappend active $pnum
2723 } else {
2723 } else {
2724 incr delta($pnum) [expr {$olc - $nlc}]
2724 incr delta($pnum) [expr {$olc - $nlc}]
2725 }
2725 }
2726 if {[incr j] >= $nevents} break
2726 if {[incr j] >= $nevents} break
2727 set e [lindex $events $j]
2727 set e [lindex $events $j]
2728 if {[lindex $e 0] >= $enl} break
2728 if {[lindex $e 0] >= $enl} break
2729 if {[lindex $e 1] > $enl} {
2729 if {[lindex $e 1] > $enl} {
2730 set enl [lindex $e 1]
2730 set enl [lindex $e 1]
2731 }
2731 }
2732 }
2732 }
2733 set nlc [expr {$enl - $l}]
2733 set nlc [expr {$enl - $l}]
2734 set ncol mresult
2734 set ncol mresult
2735 set bestpn -1
2735 set bestpn -1
2736 if {[llength $active] == $nmerge - 1} {
2736 if {[llength $active] == $nmerge - 1} {
2737 # no diff for one of the parents, i.e. it's identical
2737 # no diff for one of the parents, i.e. it's identical
2738 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2738 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2739 if {![info exists delta($pnum)]} {
2739 if {![info exists delta($pnum)]} {
2740 if {$pnum < $mergemax} {
2740 if {$pnum < $mergemax} {
2741 lappend ncol m$pnum
2741 lappend ncol m$pnum
2742 } else {
2742 } else {
2743 lappend ncol mmax
2743 lappend ncol mmax
2744 }
2744 }
2745 break
2745 break
2746 }
2746 }
2747 }
2747 }
2748 } elseif {[llength $active] == $nmerge} {
2748 } elseif {[llength $active] == $nmerge} {
2749 # all parents are different, see if one is very similar
2749 # all parents are different, see if one is very similar
2750 set bestsim 30
2750 set bestsim 30
2751 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2751 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
2752 set sim [similarity $pnum $l $nlc $f \
2752 set sim [similarity $pnum $l $nlc $f \
2753 [lrange $events $i [expr {$j-1}]]]
2753 [lrange $events $i [expr {$j-1}]]]
2754 if {$sim > $bestsim} {
2754 if {$sim > $bestsim} {
2755 set bestsim $sim
2755 set bestsim $sim
2756 set bestpn $pnum
2756 set bestpn $pnum
2757 }
2757 }
2758 }
2758 }
2759 if {$bestpn >= 0} {
2759 if {$bestpn >= 0} {
2760 lappend ncol m$bestpn
2760 lappend ncol m$bestpn
2761 }
2761 }
2762 }
2762 }
2763 set pnum -1
2763 set pnum -1
2764 foreach p $parents($id) {
2764 foreach p $parents($id) {
2765 incr pnum
2765 incr pnum
2766 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
2766 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
2767 set olc [expr {$nlc + $delta($pnum)}]
2767 set olc [expr {$nlc + $delta($pnum)}]
2768 set ol [expr {$l + $diffoffset($p)}]
2768 set ol [expr {$l + $diffoffset($p)}]
2769 incr diffoffset($p) $delta($pnum)
2769 incr diffoffset($p) $delta($pnum)
2770 unset delta($pnum)
2770 unset delta($pnum)
2771 for {} {$olc > 0} {incr olc -1} {
2771 for {} {$olc > 0} {incr olc -1} {
2772 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
2772 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
2773 incr ol
2773 incr ol
2774 }
2774 }
2775 }
2775 }
2776 set endl [expr {$l + $nlc}]
2776 set endl [expr {$l + $nlc}]
2777 if {$bestpn >= 0} {
2777 if {$bestpn >= 0} {
2778 # show this pretty much as a normal diff
2778 # show this pretty much as a normal diff
2779 set p [lindex $parents($id) $bestpn]
2779 set p [lindex $parents($id) $bestpn]
2780 set ol [expr {$l + $diffoffset($p)}]
2780 set ol [expr {$l + $diffoffset($p)}]
2781 incr diffoffset($p) $delta($bestpn)
2781 incr diffoffset($p) $delta($bestpn)
2782 unset delta($bestpn)
2782 unset delta($bestpn)
2783 for {set k $i} {$k < $j} {incr k} {
2783 for {set k $i} {$k < $j} {incr k} {
2784 set e [lindex $events $k]
2784 set e [lindex $events $k]
2785 if {[lindex $e 2] != $bestpn} continue
2785 if {[lindex $e 2] != $bestpn} continue
2786 set nl [lindex $e 0]
2786 set nl [lindex $e 0]
2787 set ol [expr {$ol + $nl - $l}]
2787 set ol [expr {$ol + $nl - $l}]
2788 for {} {$l < $nl} {incr l} {
2788 for {} {$l < $nl} {incr l} {
2789 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2789 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2790 }
2790 }
2791 set c [lindex $e 3]
2791 set c [lindex $e 3]
2792 for {} {$c > 0} {incr c -1} {
2792 for {} {$c > 0} {incr c -1} {
2793 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
2793 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
2794 incr ol
2794 incr ol
2795 }
2795 }
2796 set nl [lindex $e 1]
2796 set nl [lindex $e 1]
2797 for {} {$l < $nl} {incr l} {
2797 for {} {$l < $nl} {incr l} {
2798 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
2798 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
2799 }
2799 }
2800 }
2800 }
2801 }
2801 }
2802 for {} {$l < $endl} {incr l} {
2802 for {} {$l < $endl} {incr l} {
2803 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2803 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
2804 }
2804 }
2805 }
2805 }
2806 while {$l < $grouplineend} {
2806 while {$l < $grouplineend} {
2807 $ctext insert end " $filelines($id,$f,$l)\n"
2807 $ctext insert end " $filelines($id,$f,$l)\n"
2808 incr l
2808 incr l
2809 }
2809 }
2810 $ctext conf -state disabled
2810 $ctext conf -state disabled
2811 }
2811 }
2812
2812
2813 proc similarity {pnum l nlc f events} {
2813 proc similarity {pnum l nlc f events} {
2814 global diffmergeid parents diffoffset filelines
2814 global diffmergeid parents diffoffset filelines
2815
2815
2816 set id $diffmergeid
2816 set id $diffmergeid
2817 set p [lindex $parents($id) $pnum]
2817 set p [lindex $parents($id) $pnum]
2818 set ol [expr {$l + $diffoffset($p)}]
2818 set ol [expr {$l + $diffoffset($p)}]
2819 set endl [expr {$l + $nlc}]
2819 set endl [expr {$l + $nlc}]
2820 set same 0
2820 set same 0
2821 set diff 0
2821 set diff 0
2822 foreach e $events {
2822 foreach e $events {
2823 if {[lindex $e 2] != $pnum} continue
2823 if {[lindex $e 2] != $pnum} continue
2824 set nl [lindex $e 0]
2824 set nl [lindex $e 0]
2825 set ol [expr {$ol + $nl - $l}]
2825 set ol [expr {$ol + $nl - $l}]
2826 for {} {$l < $nl} {incr l} {
2826 for {} {$l < $nl} {incr l} {
2827 incr same [string length $filelines($id,$f,$l)]
2827 incr same [string length $filelines($id,$f,$l)]
2828 incr same
2828 incr same
2829 }
2829 }
2830 set oc [lindex $e 3]
2830 set oc [lindex $e 3]
2831 for {} {$oc > 0} {incr oc -1} {
2831 for {} {$oc > 0} {incr oc -1} {
2832 incr diff [string length $filelines($p,$f,$ol)]
2832 incr diff [string length $filelines($p,$f,$ol)]
2833 incr diff
2833 incr diff
2834 incr ol
2834 incr ol
2835 }
2835 }
2836 set nl [lindex $e 1]
2836 set nl [lindex $e 1]
2837 for {} {$l < $nl} {incr l} {
2837 for {} {$l < $nl} {incr l} {
2838 incr diff [string length $filelines($id,$f,$l)]
2838 incr diff [string length $filelines($id,$f,$l)]
2839 incr diff
2839 incr diff
2840 }
2840 }
2841 }
2841 }
2842 for {} {$l < $endl} {incr l} {
2842 for {} {$l < $endl} {incr l} {
2843 incr same [string length $filelines($id,$f,$l)]
2843 incr same [string length $filelines($id,$f,$l)]
2844 incr same
2844 incr same
2845 }
2845 }
2846 if {$same == 0} {
2846 if {$same == 0} {
2847 return 0
2847 return 0
2848 }
2848 }
2849 return [expr {200 * $same / (2 * $same + $diff)}]
2849 return [expr {200 * $same / (2 * $same + $diff)}]
2850 }
2850 }
2851
2851
2852 proc startdiff {ids} {
2852 proc startdiff {ids} {
2853 global treediffs diffids treepending diffmergeid
2853 global treediffs diffids treepending diffmergeid
2854
2854
2855 set diffids $ids
2855 set diffids $ids
2856 catch {unset diffmergeid}
2856 catch {unset diffmergeid}
2857 if {![info exists treediffs($ids)]} {
2857 if {![info exists treediffs($ids)]} {
2858 if {![info exists treepending]} {
2858 if {![info exists treepending]} {
2859 gettreediffs $ids
2859 gettreediffs $ids
2860 }
2860 }
2861 } else {
2861 } else {
2862 addtocflist $ids
2862 addtocflist $ids
2863 }
2863 }
2864 }
2864 }
2865
2865
2866 proc addtocflist {ids} {
2866 proc addtocflist {ids} {
2867 global treediffs cflist
2867 global treediffs cflist
2868 foreach f $treediffs($ids) {
2868 foreach f $treediffs($ids) {
2869 $cflist insert end $f
2869 $cflist insert end $f
2870 }
2870 }
2871 getblobdiffs $ids
2871 getblobdiffs $ids
2872 }
2872 }
2873
2873
2874 proc gettreediffs {ids} {
2874 proc gettreediffs {ids} {
2875 global treediff parents treepending env
2875 global treediff parents treepending env
2876 set treepending $ids
2876 set treepending $ids
2877 set treediff {}
2877 set treediff {}
2878 set id [lindex $ids 0]
2878 set id [lindex $ids 0]
2879 set p [lindex $ids 1]
2879 set p [lindex $ids 1]
2880 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
2880 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
2881 fconfigure $gdtf -blocking 0
2881 fconfigure $gdtf -blocking 0
2882 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
2882 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
2883 }
2883 }
2884
2884
2885 proc gettreediffline {gdtf ids} {
2885 proc gettreediffline {gdtf ids} {
2886 global treediff treediffs treepending diffids diffmergeid
2886 global treediff treediffs treepending diffids diffmergeid
2887
2887
2888 set n [gets $gdtf line]
2888 set n [gets $gdtf line]
2889 if {$n < 0} {
2889 if {$n < 0} {
2890 if {![eof $gdtf]} return
2890 if {![eof $gdtf]} return
2891 close $gdtf
2891 close $gdtf
2892 set treediffs($ids) $treediff
2892 set treediffs($ids) $treediff
2893 unset treepending
2893 unset treepending
2894 if {$ids != $diffids} {
2894 if {$ids != $diffids} {
2895 gettreediffs $diffids
2895 gettreediffs $diffids
2896 } else {
2896 } else {
2897 if {[info exists diffmergeid]} {
2897 if {[info exists diffmergeid]} {
2898 contmergediff $ids
2898 contmergediff $ids
2899 } else {
2899 } else {
2900 addtocflist $ids
2900 addtocflist $ids
2901 }
2901 }
2902 }
2902 }
2903 return
2903 return
2904 }
2904 }
2905 set tab1 [expr [string first "\t" $line] + 1]
2905 set tab1 [expr [string first "\t" $line] + 1]
2906 set tab2 [expr [string first "\t" $line $tab1] - 1]
2906 set tab2 [expr [string first "\t" $line $tab1] - 1]
2907 set file [string range $line $tab1 $tab2]
2907 set file [string range $line $tab1 $tab2]
2908 lappend treediff $file
2908 lappend treediff $file
2909 }
2909 }
2910
2910
2911 proc getblobdiffs {ids} {
2911 proc getblobdiffs {ids} {
2912 global diffopts blobdifffd diffids env curdifftag curtagstart
2912 global diffopts blobdifffd diffids env curdifftag curtagstart
2913 global difffilestart nextupdate diffinhdr treediffs
2913 global difffilestart nextupdate diffinhdr treediffs
2914
2914
2915 set id [lindex $ids 0]
2915 set id [lindex $ids 0]
2916 set p [lindex $ids 1]
2916 set p [lindex $ids 1]
2917 set env(GIT_DIFF_OPTS) $diffopts
2917 set env(GIT_DIFF_OPTS) $diffopts
2918 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
2918 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
2919 if {[catch {set bdf [open $cmd r]} err]} {
2919 if {[catch {set bdf [open $cmd r]} err]} {
2920 puts "error getting diffs: $err"
2920 puts "error getting diffs: $err"
2921 return
2921 return
2922 }
2922 }
2923 set diffinhdr 0
2923 set diffinhdr 0
2924 fconfigure $bdf -blocking 0
2924 fconfigure $bdf -blocking 0
2925 set blobdifffd($ids) $bdf
2925 set blobdifffd($ids) $bdf
2926 set curdifftag Comments
2926 set curdifftag Comments
2927 set curtagstart 0.0
2927 set curtagstart 0.0
2928 catch {unset difffilestart}
2928 catch {unset difffilestart}
2929 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
2929 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
2930 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
2930 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
2931 }
2931 }
2932
2932
2933 proc getblobdiffline {bdf ids} {
2933 proc getblobdiffline {bdf ids} {
2934 global diffids blobdifffd ctext curdifftag curtagstart
2934 global diffids blobdifffd ctext curdifftag curtagstart
2935 global diffnexthead diffnextnote difffilestart
2935 global diffnexthead diffnextnote difffilestart
2936 global nextupdate diffinhdr treediffs
2936 global nextupdate diffinhdr treediffs
2937 global gaudydiff
2937 global gaudydiff
2938
2938
2939 set n [gets $bdf line]
2939 set n [gets $bdf line]
2940 if {$n < 0} {
2940 if {$n < 0} {
2941 if {[eof $bdf]} {
2941 if {[eof $bdf]} {
2942 close $bdf
2942 close $bdf
2943 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
2943 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
2944 $ctext tag add $curdifftag $curtagstart end
2944 $ctext tag add $curdifftag $curtagstart end
2945 }
2945 }
2946 }
2946 }
2947 return
2947 return
2948 }
2948 }
2949 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
2949 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
2950 return
2950 return
2951 }
2951 }
2952 regsub -all "\r" $line "" line
2952 regsub -all "\r" $line "" line
2953 $ctext conf -state normal
2953 $ctext conf -state normal
2954 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
2954 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
2955 # start of a new file
2955 # start of a new file
2956 $ctext insert end "\n"
2956 $ctext insert end "\n"
2957 $ctext tag add $curdifftag $curtagstart end
2957 $ctext tag add $curdifftag $curtagstart end
2958 set curtagstart [$ctext index "end - 1c"]
2958 set curtagstart [$ctext index "end - 1c"]
2959 set header $newname
2959 set header $newname
2960 set here [$ctext index "end - 1c"]
2960 set here [$ctext index "end - 1c"]
2961 set i [lsearch -exact $treediffs($diffids) $fname]
2961 set i [lsearch -exact $treediffs($diffids) $fname]
2962 if {$i >= 0} {
2962 if {$i >= 0} {
2963 set difffilestart($i) $here
2963 set difffilestart($i) $here
2964 incr i
2964 incr i
2965 $ctext mark set fmark.$i $here
2965 $ctext mark set fmark.$i $here
2966 $ctext mark gravity fmark.$i left
2966 $ctext mark gravity fmark.$i left
2967 }
2967 }
2968 if {$newname != $fname} {
2968 if {$newname != $fname} {
2969 set i [lsearch -exact $treediffs($diffids) $newname]
2969 set i [lsearch -exact $treediffs($diffids) $newname]
2970 if {$i >= 0} {
2970 if {$i >= 0} {
2971 set difffilestart($i) $here
2971 set difffilestart($i) $here
2972 incr i
2972 incr i
2973 $ctext mark set fmark.$i $here
2973 $ctext mark set fmark.$i $here
2974 $ctext mark gravity fmark.$i left
2974 $ctext mark gravity fmark.$i left
2975 }
2975 }
2976 }
2976 }
2977 set curdifftag "f:$fname"
2977 set curdifftag "f:$fname"
2978 $ctext tag delete $curdifftag
2978 $ctext tag delete $curdifftag
2979 set l [expr {(78 - [string length $header]) / 2}]
2979 set l [expr {(78 - [string length $header]) / 2}]
2980 set pad [string range "----------------------------------------" 1 $l]
2980 set pad [string range "----------------------------------------" 1 $l]
2981 $ctext insert end "$pad $header $pad\n" filesep
2981 $ctext insert end "$pad $header $pad\n" filesep
2982 set diffinhdr 1
2982 set diffinhdr 1
2983 } elseif {[regexp {^(---|\+\+\+)} $line]} {
2983 } elseif {[regexp {^(---|\+\+\+)} $line]} {
2984 set diffinhdr 0
2984 set diffinhdr 0
2985 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2985 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2986 $line match f1l f1c f2l f2c rest]} {
2986 $line match f1l f1c f2l f2c rest]} {
2987 if {$gaudydiff} {
2987 if {$gaudydiff} {
2988 $ctext insert end "\t" hunksep
2988 $ctext insert end "\t" hunksep
2989 $ctext insert end " $f1l " d0 " $f2l " d1
2989 $ctext insert end " $f1l " d0 " $f2l " d1
2990 $ctext insert end " $rest \n" hunksep
2990 $ctext insert end " $rest \n" hunksep
2991 } else {
2991 } else {
2992 $ctext insert end "$line\n" hunksep
2992 $ctext insert end "$line\n" hunksep
2993 }
2993 }
2994 set diffinhdr 0
2994 set diffinhdr 0
2995 } else {
2995 } else {
2996 set x [string range $line 0 0]
2996 set x [string range $line 0 0]
2997 if {$x == "-" || $x == "+"} {
2997 if {$x == "-" || $x == "+"} {
2998 set tag [expr {$x == "+"}]
2998 set tag [expr {$x == "+"}]
2999 if {$gaudydiff} {
2999 if {$gaudydiff} {
3000 set line [string range $line 1 end]
3000 set line [string range $line 1 end]
3001 }
3001 }
3002 $ctext insert end "$line\n" d$tag
3002 $ctext insert end "$line\n" d$tag
3003 } elseif {$x == " "} {
3003 } elseif {$x == " "} {
3004 if {$gaudydiff} {
3004 if {$gaudydiff} {
3005 set line [string range $line 1 end]
3005 set line [string range $line 1 end]
3006 }
3006 }
3007 $ctext insert end "$line\n"
3007 $ctext insert end "$line\n"
3008 } elseif {$diffinhdr || $x == "\\"} {
3008 } elseif {$diffinhdr || $x == "\\"} {
3009 # e.g. "\ No newline at end of file"
3009 # e.g. "\ No newline at end of file"
3010 $ctext insert end "$line\n" filesep
3010 $ctext insert end "$line\n" filesep
3011 } elseif {$line != ""} {
3011 } elseif {$line != ""} {
3012 # Something else we don't recognize
3012 # Something else we don't recognize
3013 if {$curdifftag != "Comments"} {
3013 if {$curdifftag != "Comments"} {
3014 $ctext insert end "\n"
3014 $ctext insert end "\n"
3015 $ctext tag add $curdifftag $curtagstart end
3015 $ctext tag add $curdifftag $curtagstart end
3016 set curtagstart [$ctext index "end - 1c"]
3016 set curtagstart [$ctext index "end - 1c"]
3017 set curdifftag Comments
3017 set curdifftag Comments
3018 }
3018 }
3019 $ctext insert end "$line\n" filesep
3019 $ctext insert end "$line\n" filesep
3020 }
3020 }
3021 }
3021 }
3022 $ctext conf -state disabled
3022 $ctext conf -state disabled
3023 if {[clock clicks -milliseconds] >= $nextupdate} {
3023 if {[clock clicks -milliseconds] >= $nextupdate} {
3024 incr nextupdate 100
3024 incr nextupdate 100
3025 fileevent $bdf readable {}
3025 fileevent $bdf readable {}
3026 update
3026 update
3027 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3027 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3028 }
3028 }
3029 }
3029 }
3030
3030
3031 proc nextfile {} {
3031 proc nextfile {} {
3032 global difffilestart ctext
3032 global difffilestart ctext
3033 set here [$ctext index @0,0]
3033 set here [$ctext index @0,0]
3034 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3034 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3035 if {[$ctext compare $difffilestart($i) > $here]} {
3035 if {[$ctext compare $difffilestart($i) > $here]} {
3036 if {![info exists pos]
3036 if {![info exists pos]
3037 || [$ctext compare $difffilestart($i) < $pos]} {
3037 || [$ctext compare $difffilestart($i) < $pos]} {
3038 set pos $difffilestart($i)
3038 set pos $difffilestart($i)
3039 }
3039 }
3040 }
3040 }
3041 }
3041 }
3042 if {[info exists pos]} {
3042 if {[info exists pos]} {
3043 $ctext yview $pos
3043 $ctext yview $pos
3044 }
3044 }
3045 }
3045 }
3046
3046
3047 proc listboxsel {} {
3047 proc listboxsel {} {
3048 global ctext cflist currentid
3048 global ctext cflist currentid
3049 if {![info exists currentid]} return
3049 if {![info exists currentid]} return
3050 set sel [lsort [$cflist curselection]]
3050 set sel [lsort [$cflist curselection]]
3051 if {$sel eq {}} return
3051 if {$sel eq {}} return
3052 set first [lindex $sel 0]
3052 set first [lindex $sel 0]
3053 catch {$ctext yview fmark.$first}
3053 catch {$ctext yview fmark.$first}
3054 }
3054 }
3055
3055
3056 proc setcoords {} {
3056 proc setcoords {} {
3057 global linespc charspc canvx0 canvy0 mainfont
3057 global linespc charspc canvx0 canvy0 mainfont
3058 global xspc1 xspc2 lthickness
3058 global xspc1 xspc2 lthickness
3059
3059
3060 set linespc [font metrics $mainfont -linespace]
3060 set linespc [font metrics $mainfont -linespace]
3061 set charspc [font measure $mainfont "m"]
3061 set charspc [font measure $mainfont "m"]
3062 set canvy0 [expr 3 + 0.5 * $linespc]
3062 set canvy0 [expr 3 + 0.5 * $linespc]
3063 set canvx0 [expr 3 + 0.5 * $linespc]
3063 set canvx0 [expr 3 + 0.5 * $linespc]
3064 set lthickness [expr {int($linespc / 9) + 1}]
3064 set lthickness [expr {int($linespc / 9) + 1}]
3065 set xspc1(0) $linespc
3065 set xspc1(0) $linespc
3066 set xspc2 $linespc
3066 set xspc2 $linespc
3067 }
3067 }
3068
3068
3069 proc redisplay {} {
3069 proc redisplay {} {
3070 global stopped redisplaying phase
3070 global stopped redisplaying phase
3071 if {$stopped > 1} return
3071 if {$stopped > 1} return
3072 if {$phase == "getcommits"} return
3072 if {$phase == "getcommits"} return
3073 set redisplaying 1
3073 set redisplaying 1
3074 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3074 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3075 set stopped 1
3075 set stopped 1
3076 } else {
3076 } else {
3077 drawgraph
3077 drawgraph
3078 }
3078 }
3079 }
3079 }
3080
3080
3081 proc incrfont {inc} {
3081 proc incrfont {inc} {
3082 global mainfont namefont textfont ctext canv phase
3082 global mainfont namefont textfont ctext canv phase
3083 global stopped entries
3083 global stopped entries
3084 unmarkmatches
3084 unmarkmatches
3085 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3085 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3086 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3086 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3087 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3087 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3088 setcoords
3088 setcoords
3089 $ctext conf -font $textfont
3089 $ctext conf -font $textfont
3090 $ctext tag conf filesep -font [concat $textfont bold]
3090 $ctext tag conf filesep -font [concat $textfont bold]
3091 foreach e $entries {
3091 foreach e $entries {
3092 $e conf -font $mainfont
3092 $e conf -font $mainfont
3093 }
3093 }
3094 if {$phase == "getcommits"} {
3094 if {$phase == "getcommits"} {
3095 $canv itemconf textitems -font $mainfont
3095 $canv itemconf textitems -font $mainfont
3096 }
3096 }
3097 redisplay
3097 redisplay
3098 }
3098 }
3099
3099
3100 proc clearsha1 {} {
3100 proc clearsha1 {} {
3101 global sha1entry sha1string
3101 global sha1entry sha1string
3102 if {[string length $sha1string] == 40} {
3102 if {[string length $sha1string] == 40} {
3103 $sha1entry delete 0 end
3103 $sha1entry delete 0 end
3104 }
3104 }
3105 }
3105 }
3106
3106
3107 proc sha1change {n1 n2 op} {
3107 proc sha1change {n1 n2 op} {
3108 global sha1string currentid sha1but
3108 global sha1string currentid sha1but
3109 if {$sha1string == {}
3109 if {$sha1string == {}
3110 || ([info exists currentid] && $sha1string == $currentid)} {
3110 || ([info exists currentid] && $sha1string == $currentid)} {
3111 set state disabled
3111 set state disabled
3112 } else {
3112 } else {
3113 set state normal
3113 set state normal
3114 }
3114 }
3115 if {[$sha1but cget -state] == $state} return
3115 if {[$sha1but cget -state] == $state} return
3116 if {$state == "normal"} {
3116 if {$state == "normal"} {
3117 $sha1but conf -state normal -relief raised -text "Goto: "
3117 $sha1but conf -state normal -relief raised -text "Goto: "
3118 } else {
3118 } else {
3119 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3119 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3120 }
3120 }
3121 }
3121 }
3122
3122
3123 proc gotocommit {} {
3123 proc gotocommit {} {
3124 global sha1string currentid idline tagids
3124 global sha1string currentid idline tagids
3125 global lineid numcommits
3125 global lineid numcommits
3126
3126
3127 if {$sha1string == {}
3127 if {$sha1string == {}
3128 || ([info exists currentid] && $sha1string == $currentid)} return
3128 || ([info exists currentid] && $sha1string == $currentid)} return
3129 if {[info exists tagids($sha1string)]} {
3129 if {[info exists tagids($sha1string)]} {
3130 set id $tagids($sha1string)
3130 set id $tagids($sha1string)
3131 } else {
3131 } else {
3132 set id [string tolower $sha1string]
3132 set id [string tolower $sha1string]
3133 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3133 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3134 set matches {}
3134 set matches {}
3135 for {set l 0} {$l < $numcommits} {incr l} {
3135 for {set l 0} {$l < $numcommits} {incr l} {
3136 if {[string match $id* $lineid($l)]} {
3136 if {[string match $id* $lineid($l)]} {
3137 lappend matches $lineid($l)
3137 lappend matches $lineid($l)
3138 }
3138 }
3139 }
3139 }
3140 if {$matches ne {}} {
3140 if {$matches ne {}} {
3141 if {[llength $matches] > 1} {
3141 if {[llength $matches] > 1} {
3142 error_popup "Short SHA1 id $id is ambiguous"
3142 error_popup "Short SHA1 id $id is ambiguous"
3143 return
3143 return
3144 }
3144 }
3145 set id [lindex $matches 0]
3145 set id [lindex $matches 0]
3146 }
3146 }
3147 }
3147 }
3148 }
3148 }
3149 if {[info exists idline($id)]} {
3149 if {[info exists idline($id)]} {
3150 selectline $idline($id) 1
3150 selectline $idline($id) 1
3151 return
3151 return
3152 }
3152 }
3153 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3153 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3154 set type "SHA1 id"
3154 set type "SHA1 id"
3155 } else {
3155 } else {
3156 set type "Tag"
3156 set type "Tag"
3157 }
3157 }
3158 error_popup "$type $sha1string is not known"
3158 error_popup "$type $sha1string is not known"
3159 }
3159 }
3160
3160
3161 proc lineenter {x y id} {
3161 proc lineenter {x y id} {
3162 global hoverx hovery hoverid hovertimer
3162 global hoverx hovery hoverid hovertimer
3163 global commitinfo canv
3163 global commitinfo canv
3164
3164
3165 if {![info exists commitinfo($id)]} return
3165 if {![info exists commitinfo($id)]} return
3166 set hoverx $x
3166 set hoverx $x
3167 set hovery $y
3167 set hovery $y
3168 set hoverid $id
3168 set hoverid $id
3169 if {[info exists hovertimer]} {
3169 if {[info exists hovertimer]} {
3170 after cancel $hovertimer
3170 after cancel $hovertimer
3171 }
3171 }
3172 set hovertimer [after 500 linehover]
3172 set hovertimer [after 500 linehover]
3173 $canv delete hover
3173 $canv delete hover
3174 }
3174 }
3175
3175
3176 proc linemotion {x y id} {
3176 proc linemotion {x y id} {
3177 global hoverx hovery hoverid hovertimer
3177 global hoverx hovery hoverid hovertimer
3178
3178
3179 if {[info exists hoverid] && $id == $hoverid} {
3179 if {[info exists hoverid] && $id == $hoverid} {
3180 set hoverx $x
3180 set hoverx $x
3181 set hovery $y
3181 set hovery $y
3182 if {[info exists hovertimer]} {
3182 if {[info exists hovertimer]} {
3183 after cancel $hovertimer
3183 after cancel $hovertimer
3184 }
3184 }
3185 set hovertimer [after 500 linehover]
3185 set hovertimer [after 500 linehover]
3186 }
3186 }
3187 }
3187 }
3188
3188
3189 proc lineleave {id} {
3189 proc lineleave {id} {
3190 global hoverid hovertimer canv
3190 global hoverid hovertimer canv
3191
3191
3192 if {[info exists hoverid] && $id == $hoverid} {
3192 if {[info exists hoverid] && $id == $hoverid} {
3193 $canv delete hover
3193 $canv delete hover
3194 if {[info exists hovertimer]} {
3194 if {[info exists hovertimer]} {
3195 after cancel $hovertimer
3195 after cancel $hovertimer
3196 unset hovertimer
3196 unset hovertimer
3197 }
3197 }
3198 unset hoverid
3198 unset hoverid
3199 }
3199 }
3200 }
3200 }
3201
3201
3202 proc linehover {} {
3202 proc linehover {} {
3203 global hoverx hovery hoverid hovertimer
3203 global hoverx hovery hoverid hovertimer
3204 global canv linespc lthickness
3204 global canv linespc lthickness
3205 global commitinfo mainfont
3205 global commitinfo mainfont
3206
3206
3207 set text [lindex $commitinfo($hoverid) 0]
3207 set text [lindex $commitinfo($hoverid) 0]
3208 set ymax [lindex [$canv cget -scrollregion] 3]
3208 set ymax [lindex [$canv cget -scrollregion] 3]
3209 if {$ymax == {}} return
3209 if {$ymax == {}} return
3210 set yfrac [lindex [$canv yview] 0]
3210 set yfrac [lindex [$canv yview] 0]
3211 set x [expr {$hoverx + 2 * $linespc}]
3211 set x [expr {$hoverx + 2 * $linespc}]
3212 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3212 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3213 set x0 [expr {$x - 2 * $lthickness}]
3213 set x0 [expr {$x - 2 * $lthickness}]
3214 set y0 [expr {$y - 2 * $lthickness}]
3214 set y0 [expr {$y - 2 * $lthickness}]
3215 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3215 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3216 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3216 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3217 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3217 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3218 -fill \#ffff80 -outline black -width 1 -tags hover]
3218 -fill \#ffff80 -outline black -width 1 -tags hover]
3219 $canv raise $t
3219 $canv raise $t
3220 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3220 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3221 $canv raise $t
3221 $canv raise $t
3222 }
3222 }
3223
3223
3224 proc clickisonarrow {id y} {
3224 proc clickisonarrow {id y} {
3225 global mainline mainlinearrow sidelines lthickness
3225 global mainline mainlinearrow sidelines lthickness
3226
3226
3227 set thresh [expr {2 * $lthickness + 6}]
3227 set thresh [expr {2 * $lthickness + 6}]
3228 if {[info exists mainline($id)]} {
3228 if {[info exists mainline($id)]} {
3229 if {$mainlinearrow($id) ne "none"} {
3229 if {$mainlinearrow($id) ne "none"} {
3230 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3230 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3231 return "up"
3231 return "up"
3232 }
3232 }
3233 }
3233 }
3234 }
3234 }
3235 if {[info exists sidelines($id)]} {
3235 if {[info exists sidelines($id)]} {
3236 foreach ls $sidelines($id) {
3236 foreach ls $sidelines($id) {
3237 set coords [lindex $ls 0]
3237 set coords [lindex $ls 0]
3238 set arrow [lindex $ls 2]
3238 set arrow [lindex $ls 2]
3239 if {$arrow eq "first" || $arrow eq "both"} {
3239 if {$arrow eq "first" || $arrow eq "both"} {
3240 if {abs([lindex $coords 1] - $y) < $thresh} {
3240 if {abs([lindex $coords 1] - $y) < $thresh} {
3241 return "up"
3241 return "up"
3242 }
3242 }
3243 }
3243 }
3244 if {$arrow eq "last" || $arrow eq "both"} {
3244 if {$arrow eq "last" || $arrow eq "both"} {
3245 if {abs([lindex $coords end] - $y) < $thresh} {
3245 if {abs([lindex $coords end] - $y) < $thresh} {
3246 return "down"
3246 return "down"
3247 }
3247 }
3248 }
3248 }
3249 }
3249 }
3250 }
3250 }
3251 return {}
3251 return {}
3252 }
3252 }
3253
3253
3254 proc arrowjump {id dirn y} {
3254 proc arrowjump {id dirn y} {
3255 global mainline sidelines canv
3255 global mainline sidelines canv
3256
3256
3257 set yt {}
3257 set yt {}
3258 if {$dirn eq "down"} {
3258 if {$dirn eq "down"} {
3259 if {[info exists mainline($id)]} {
3259 if {[info exists mainline($id)]} {
3260 set y1 [lindex $mainline($id) 1]
3260 set y1 [lindex $mainline($id) 1]
3261 if {$y1 > $y} {
3261 if {$y1 > $y} {
3262 set yt $y1
3262 set yt $y1
3263 }
3263 }
3264 }
3264 }
3265 if {[info exists sidelines($id)]} {
3265 if {[info exists sidelines($id)]} {
3266 foreach ls $sidelines($id) {
3266 foreach ls $sidelines($id) {
3267 set y1 [lindex $ls 0 1]
3267 set y1 [lindex $ls 0 1]
3268 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3268 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3269 set yt $y1
3269 set yt $y1
3270 }
3270 }
3271 }
3271 }
3272 }
3272 }
3273 } else {
3273 } else {
3274 if {[info exists sidelines($id)]} {
3274 if {[info exists sidelines($id)]} {
3275 foreach ls $sidelines($id) {
3275 foreach ls $sidelines($id) {
3276 set y1 [lindex $ls 0 end]
3276 set y1 [lindex $ls 0 end]
3277 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3277 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3278 set yt $y1
3278 set yt $y1
3279 }
3279 }
3280 }
3280 }
3281 }
3281 }
3282 }
3282 }
3283 if {$yt eq {}} return
3283 if {$yt eq {}} return
3284 set ymax [lindex [$canv cget -scrollregion] 3]
3284 set ymax [lindex [$canv cget -scrollregion] 3]
3285 if {$ymax eq {} || $ymax <= 0} return
3285 if {$ymax eq {} || $ymax <= 0} return
3286 set view [$canv yview]
3286 set view [$canv yview]
3287 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3287 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3288 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3288 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3289 if {$yfrac < 0} {
3289 if {$yfrac < 0} {
3290 set yfrac 0
3290 set yfrac 0
3291 }
3291 }
3292 $canv yview moveto $yfrac
3292 $canv yview moveto $yfrac
3293 }
3293 }
3294
3294
3295 proc lineclick {x y id isnew} {
3295 proc lineclick {x y id isnew} {
3296 global ctext commitinfo children cflist canv thickerline
3296 global ctext commitinfo children cflist canv thickerline
3297
3297
3298 unmarkmatches
3298 unmarkmatches
3299 unselectline
3299 unselectline
3300 normalline
3300 normalline
3301 $canv delete hover
3301 $canv delete hover
3302 # draw this line thicker than normal
3302 # draw this line thicker than normal
3303 drawlines $id 1
3303 drawlines $id 1
3304 set thickerline $id
3304 set thickerline $id
3305 if {$isnew} {
3305 if {$isnew} {
3306 set ymax [lindex [$canv cget -scrollregion] 3]
3306 set ymax [lindex [$canv cget -scrollregion] 3]
3307 if {$ymax eq {}} return
3307 if {$ymax eq {}} return
3308 set yfrac [lindex [$canv yview] 0]
3308 set yfrac [lindex [$canv yview] 0]
3309 set y [expr {$y + $yfrac * $ymax}]
3309 set y [expr {$y + $yfrac * $ymax}]
3310 }
3310 }
3311 set dirn [clickisonarrow $id $y]
3311 set dirn [clickisonarrow $id $y]
3312 if {$dirn ne {}} {
3312 if {$dirn ne {}} {
3313 arrowjump $id $dirn $y
3313 arrowjump $id $dirn $y
3314 return
3314 return
3315 }
3315 }
3316
3316
3317 if {$isnew} {
3317 if {$isnew} {
3318 addtohistory [list lineclick $x $y $id 0]
3318 addtohistory [list lineclick $x $y $id 0]
3319 }
3319 }
3320 # fill the details pane with info about this line
3320 # fill the details pane with info about this line
3321 $ctext conf -state normal
3321 $ctext conf -state normal
3322 $ctext delete 0.0 end
3322 $ctext delete 0.0 end
3323 $ctext tag conf link -foreground blue -underline 1
3323 $ctext tag conf link -foreground blue -underline 1
3324 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3324 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3325 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3325 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3326 $ctext insert end "Parent:\t"
3326 $ctext insert end "Parent:\t"
3327 $ctext insert end $id [list link link0]
3327 $ctext insert end $id [list link link0]
3328 $ctext tag bind link0 <1> [list selbyid $id]
3328 $ctext tag bind link0 <1> [list selbyid $id]
3329 set info $commitinfo($id)
3329 set info $commitinfo($id)
3330 $ctext insert end "\n\t[lindex $info 0]\n"
3330 $ctext insert end "\n\t[lindex $info 0]\n"
3331 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
3331 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
3332 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3332 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3333 if {[info exists children($id)]} {
3333 if {[info exists children($id)]} {
3334 $ctext insert end "\nChildren:"
3334 $ctext insert end "\nChildren:"
3335 set i 0
3335 set i 0
3336 foreach child $children($id) {
3336 foreach child $children($id) {
3337 incr i
3337 incr i
3338 set info $commitinfo($child)
3338 set info $commitinfo($child)
3339 $ctext insert end "\n\t"
3339 $ctext insert end "\n\t"
3340 $ctext insert end $child [list link link$i]
3340 $ctext insert end $child [list link link$i]
3341 $ctext tag bind link$i <1> [list selbyid $child]
3341 $ctext tag bind link$i <1> [list selbyid $child]
3342 $ctext insert end "\n\t[lindex $info 0]"
3342 $ctext insert end "\n\t[lindex $info 0]"
3343 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
3343 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
3344 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3344 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3345 }
3345 }
3346 }
3346 }
3347 $ctext conf -state disabled
3347 $ctext conf -state disabled
3348
3348
3349 $cflist delete 0 end
3349 $cflist delete 0 end
3350 }
3350 }
3351
3351
3352 proc normalline {} {
3352 proc normalline {} {
3353 global thickerline
3353 global thickerline
3354 if {[info exists thickerline]} {
3354 if {[info exists thickerline]} {
3355 drawlines $thickerline 0
3355 drawlines $thickerline 0
3356 unset thickerline
3356 unset thickerline
3357 }
3357 }
3358 }
3358 }
3359
3359
3360 proc selbyid {id} {
3360 proc selbyid {id} {
3361 global idline
3361 global idline
3362 if {[info exists idline($id)]} {
3362 if {[info exists idline($id)]} {
3363 selectline $idline($id) 1
3363 selectline $idline($id) 1
3364 }
3364 }
3365 }
3365 }
3366
3366
3367 proc mstime {} {
3367 proc mstime {} {
3368 global startmstime
3368 global startmstime
3369 if {![info exists startmstime]} {
3369 if {![info exists startmstime]} {
3370 set startmstime [clock clicks -milliseconds]
3370 set startmstime [clock clicks -milliseconds]
3371 }
3371 }
3372 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3372 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3373 }
3373 }
3374
3374
3375 proc rowmenu {x y id} {
3375 proc rowmenu {x y id} {
3376 global rowctxmenu idline selectedline rowmenuid
3376 global rowctxmenu idline selectedline rowmenuid
3377
3377
3378 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3378 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3379 set state disabled
3379 set state disabled
3380 } else {
3380 } else {
3381 set state normal
3381 set state normal
3382 }
3382 }
3383 $rowctxmenu entryconfigure 0 -state $state
3383 $rowctxmenu entryconfigure 0 -state $state
3384 $rowctxmenu entryconfigure 1 -state $state
3384 $rowctxmenu entryconfigure 1 -state $state
3385 $rowctxmenu entryconfigure 2 -state $state
3385 $rowctxmenu entryconfigure 2 -state $state
3386 set rowmenuid $id
3386 set rowmenuid $id
3387 tk_popup $rowctxmenu $x $y
3387 tk_popup $rowctxmenu $x $y
3388 }
3388 }
3389
3389
3390 proc diffvssel {dirn} {
3390 proc diffvssel {dirn} {
3391 global rowmenuid selectedline lineid
3391 global rowmenuid selectedline lineid
3392
3392
3393 if {![info exists selectedline]} return
3393 if {![info exists selectedline]} return
3394 if {$dirn} {
3394 if {$dirn} {
3395 set oldid $lineid($selectedline)
3395 set oldid $lineid($selectedline)
3396 set newid $rowmenuid
3396 set newid $rowmenuid
3397 } else {
3397 } else {
3398 set oldid $rowmenuid
3398 set oldid $rowmenuid
3399 set newid $lineid($selectedline)
3399 set newid $lineid($selectedline)
3400 }
3400 }
3401 addtohistory [list doseldiff $oldid $newid]
3401 addtohistory [list doseldiff $oldid $newid]
3402 doseldiff $oldid $newid
3402 doseldiff $oldid $newid
3403 }
3403 }
3404
3404
3405 proc doseldiff {oldid newid} {
3405 proc doseldiff {oldid newid} {
3406 global ctext cflist
3406 global ctext cflist
3407 global commitinfo
3407 global commitinfo
3408
3408
3409 $ctext conf -state normal
3409 $ctext conf -state normal
3410 $ctext delete 0.0 end
3410 $ctext delete 0.0 end
3411 $ctext mark set fmark.0 0.0
3411 $ctext mark set fmark.0 0.0
3412 $ctext mark gravity fmark.0 left
3412 $ctext mark gravity fmark.0 left
3413 $cflist delete 0 end
3413 $cflist delete 0 end
3414 $cflist insert end "Top"
3414 $cflist insert end "Top"
3415 $ctext insert end "From "
3415 $ctext insert end "From "
3416 $ctext tag conf link -foreground blue -underline 1
3416 $ctext tag conf link -foreground blue -underline 1
3417 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3417 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3418 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3418 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3419 $ctext tag bind link0 <1> [list selbyid $oldid]
3419 $ctext tag bind link0 <1> [list selbyid $oldid]
3420 $ctext insert end $oldid [list link link0]
3420 $ctext insert end $oldid [list link link0]
3421 $ctext insert end "\n "
3421 $ctext insert end "\n "
3422 $ctext insert end [lindex $commitinfo($oldid) 0]
3422 $ctext insert end [lindex $commitinfo($oldid) 0]
3423 $ctext insert end "\n\nTo "
3423 $ctext insert end "\n\nTo "
3424 $ctext tag bind link1 <1> [list selbyid $newid]
3424 $ctext tag bind link1 <1> [list selbyid $newid]
3425 $ctext insert end $newid [list link link1]
3425 $ctext insert end $newid [list link link1]
3426 $ctext insert end "\n "
3426 $ctext insert end "\n "
3427 $ctext insert end [lindex $commitinfo($newid) 0]
3427 $ctext insert end [lindex $commitinfo($newid) 0]
3428 $ctext insert end "\n"
3428 $ctext insert end "\n"
3429 $ctext conf -state disabled
3429 $ctext conf -state disabled
3430 $ctext tag delete Comments
3430 $ctext tag delete Comments
3431 $ctext tag remove found 1.0 end
3431 $ctext tag remove found 1.0 end
3432 startdiff [list $newid $oldid]
3432 startdiff [list $newid $oldid]
3433 }
3433 }
3434
3434
3435 proc mkpatch {} {
3435 proc mkpatch {} {
3436 global rowmenuid currentid commitinfo patchtop patchnum
3436 global rowmenuid currentid commitinfo patchtop patchnum
3437
3437
3438 if {![info exists currentid]} return
3438 if {![info exists currentid]} return
3439 set oldid $currentid
3439 set oldid $currentid
3440 set oldhead [lindex $commitinfo($oldid) 0]
3440 set oldhead [lindex $commitinfo($oldid) 0]
3441 set newid $rowmenuid
3441 set newid $rowmenuid
3442 set newhead [lindex $commitinfo($newid) 0]
3442 set newhead [lindex $commitinfo($newid) 0]
3443 set top .patch
3443 set top .patch
3444 set patchtop $top
3444 set patchtop $top
3445 catch {destroy $top}
3445 catch {destroy $top}
3446 toplevel $top
3446 toplevel $top
3447 label $top.title -text "Generate patch"
3447 label $top.title -text "Generate patch"
3448 grid $top.title - -pady 10
3448 grid $top.title - -pady 10
3449 label $top.from -text "From:"
3449 label $top.from -text "From:"
3450 entry $top.fromsha1 -width 40 -relief flat
3450 entry $top.fromsha1 -width 40 -relief flat
3451 $top.fromsha1 insert 0 $oldid
3451 $top.fromsha1 insert 0 $oldid
3452 $top.fromsha1 conf -state readonly
3452 $top.fromsha1 conf -state readonly
3453 grid $top.from $top.fromsha1 -sticky w
3453 grid $top.from $top.fromsha1 -sticky w
3454 entry $top.fromhead -width 60 -relief flat
3454 entry $top.fromhead -width 60 -relief flat
3455 $top.fromhead insert 0 $oldhead
3455 $top.fromhead insert 0 $oldhead
3456 $top.fromhead conf -state readonly
3456 $top.fromhead conf -state readonly
3457 grid x $top.fromhead -sticky w
3457 grid x $top.fromhead -sticky w
3458 label $top.to -text "To:"
3458 label $top.to -text "To:"
3459 entry $top.tosha1 -width 40 -relief flat
3459 entry $top.tosha1 -width 40 -relief flat
3460 $top.tosha1 insert 0 $newid
3460 $top.tosha1 insert 0 $newid
3461 $top.tosha1 conf -state readonly
3461 $top.tosha1 conf -state readonly
3462 grid $top.to $top.tosha1 -sticky w
3462 grid $top.to $top.tosha1 -sticky w
3463 entry $top.tohead -width 60 -relief flat
3463 entry $top.tohead -width 60 -relief flat
3464 $top.tohead insert 0 $newhead
3464 $top.tohead insert 0 $newhead
3465 $top.tohead conf -state readonly
3465 $top.tohead conf -state readonly
3466 grid x $top.tohead -sticky w
3466 grid x $top.tohead -sticky w
3467 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
3467 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
3468 grid $top.rev x -pady 10
3468 grid $top.rev x -pady 10
3469 label $top.flab -text "Output file:"
3469 label $top.flab -text "Output file:"
3470 entry $top.fname -width 60
3470 entry $top.fname -width 60
3471 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3471 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3472 incr patchnum
3472 incr patchnum
3473 grid $top.flab $top.fname -sticky w
3473 grid $top.flab $top.fname -sticky w
3474 frame $top.buts
3474 frame $top.buts
3475 button $top.buts.gen -text "Generate" -command mkpatchgo
3475 button $top.buts.gen -text "Generate" -command mkpatchgo
3476 button $top.buts.can -text "Cancel" -command mkpatchcan
3476 button $top.buts.can -text "Cancel" -command mkpatchcan
3477 grid $top.buts.gen $top.buts.can
3477 grid $top.buts.gen $top.buts.can
3478 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3478 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3479 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3479 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3480 grid $top.buts - -pady 10 -sticky ew
3480 grid $top.buts - -pady 10 -sticky ew
3481 focus $top.fname
3481 focus $top.fname
3482 }
3482 }
3483
3483
3484 proc mkpatchrev {} {
3484 proc mkpatchrev {} {
3485 global patchtop
3485 global patchtop
3486
3486
3487 set oldid [$patchtop.fromsha1 get]
3487 set oldid [$patchtop.fromsha1 get]
3488 set oldhead [$patchtop.fromhead get]
3488 set oldhead [$patchtop.fromhead get]
3489 set newid [$patchtop.tosha1 get]
3489 set newid [$patchtop.tosha1 get]
3490 set newhead [$patchtop.tohead get]
3490 set newhead [$patchtop.tohead get]
3491 foreach e [list fromsha1 fromhead tosha1 tohead] \
3491 foreach e [list fromsha1 fromhead tosha1 tohead] \
3492 v [list $newid $newhead $oldid $oldhead] {
3492 v [list $newid $newhead $oldid $oldhead] {
3493 $patchtop.$e conf -state normal
3493 $patchtop.$e conf -state normal
3494 $patchtop.$e delete 0 end
3494 $patchtop.$e delete 0 end
3495 $patchtop.$e insert 0 $v
3495 $patchtop.$e insert 0 $v
3496 $patchtop.$e conf -state readonly
3496 $patchtop.$e conf -state readonly
3497 }
3497 }
3498 }
3498 }
3499
3499
3500 proc mkpatchgo {} {
3500 proc mkpatchgo {} {
3501 global patchtop env
3501 global patchtop env
3502
3502
3503 set oldid [$patchtop.fromsha1 get]
3503 set oldid [$patchtop.fromsha1 get]
3504 set newid [$patchtop.tosha1 get]
3504 set newid [$patchtop.tosha1 get]
3505 set fname [$patchtop.fname get]
3505 set fname [$patchtop.fname get]
3506 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3506 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3507 error_popup "Error creating patch: $err"
3507 error_popup "Error creating patch: $err"
3508 }
3508 }
3509 catch {destroy $patchtop}
3509 catch {destroy $patchtop}
3510 unset patchtop
3510 unset patchtop
3511 }
3511 }
3512
3512
3513 proc mkpatchcan {} {
3513 proc mkpatchcan {} {
3514 global patchtop
3514 global patchtop
3515
3515
3516 catch {destroy $patchtop}
3516 catch {destroy $patchtop}
3517 unset patchtop
3517 unset patchtop
3518 }
3518 }
3519
3519
3520 proc mktag {} {
3520 proc mktag {} {
3521 global rowmenuid mktagtop commitinfo
3521 global rowmenuid mktagtop commitinfo
3522
3522
3523 set top .maketag
3523 set top .maketag
3524 set mktagtop $top
3524 set mktagtop $top
3525 catch {destroy $top}
3525 catch {destroy $top}
3526 toplevel $top
3526 toplevel $top
3527 label $top.title -text "Create tag"
3527 label $top.title -text "Create tag"
3528 grid $top.title - -pady 10
3528 grid $top.title - -pady 10
3529 label $top.id -text "ID:"
3529 label $top.id -text "ID:"
3530 entry $top.sha1 -width 40 -relief flat
3530 entry $top.sha1 -width 40 -relief flat
3531 $top.sha1 insert 0 $rowmenuid
3531 $top.sha1 insert 0 $rowmenuid
3532 $top.sha1 conf -state readonly
3532 $top.sha1 conf -state readonly
3533 grid $top.id $top.sha1 -sticky w
3533 grid $top.id $top.sha1 -sticky w
3534 entry $top.head -width 60 -relief flat
3534 entry $top.head -width 60 -relief flat
3535 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3535 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3536 $top.head conf -state readonly
3536 $top.head conf -state readonly
3537 grid x $top.head -sticky w
3537 grid x $top.head -sticky w
3538 label $top.tlab -text "Tag name:"
3538 label $top.tlab -text "Tag name:"
3539 entry $top.tag -width 60
3539 entry $top.tag -width 60
3540 grid $top.tlab $top.tag -sticky w
3540 grid $top.tlab $top.tag -sticky w
3541 frame $top.buts
3541 frame $top.buts
3542 button $top.buts.gen -text "Create" -command mktaggo
3542 button $top.buts.gen -text "Create" -command mktaggo
3543 button $top.buts.can -text "Cancel" -command mktagcan
3543 button $top.buts.can -text "Cancel" -command mktagcan
3544 grid $top.buts.gen $top.buts.can
3544 grid $top.buts.gen $top.buts.can
3545 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3545 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3546 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3546 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3547 grid $top.buts - -pady 10 -sticky ew
3547 grid $top.buts - -pady 10 -sticky ew
3548 focus $top.tag
3548 focus $top.tag
3549 }
3549 }
3550
3550
3551 proc domktag {} {
3551 proc domktag {} {
3552 global mktagtop env tagids idtags
3552 global mktagtop env tagids idtags
3553
3553
3554 set id [$mktagtop.sha1 get]
3554 set id [$mktagtop.sha1 get]
3555 set tag [$mktagtop.tag get]
3555 set tag [$mktagtop.tag get]
3556 if {$tag == {}} {
3556 if {$tag == {}} {
3557 error_popup "No tag name specified"
3557 error_popup "No tag name specified"
3558 return
3558 return
3559 }
3559 }
3560 if {[info exists tagids($tag)]} {
3560 if {[info exists tagids($tag)]} {
3561 error_popup "Tag \"$tag\" already exists"
3561 error_popup "Tag \"$tag\" already exists"
3562 return
3562 return
3563 }
3563 }
3564 if {[catch {
3564 if {[catch {
3565 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3565 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3566 } err]} {
3566 } err]} {
3567 error_popup "Error creating tag: $err"
3567 error_popup "Error creating tag: $err"
3568 return
3568 return
3569 }
3569 }
3570
3570
3571 set tagids($tag) $id
3571 set tagids($tag) $id
3572 lappend idtags($id) $tag
3572 lappend idtags($id) $tag
3573 redrawtags $id
3573 redrawtags $id
3574 }
3574 }
3575
3575
3576 proc redrawtags {id} {
3576 proc redrawtags {id} {
3577 global canv linehtag idline idpos selectedline
3577 global canv linehtag idline idpos selectedline
3578
3578
3579 if {![info exists idline($id)]} return
3579 if {![info exists idline($id)]} return
3580 $canv delete tag.$id
3580 $canv delete tag.$id
3581 set xt [eval drawtags $id $idpos($id)]
3581 set xt [eval drawtags $id $idpos($id)]
3582 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3582 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3583 if {[info exists selectedline] && $selectedline == $idline($id)} {
3583 if {[info exists selectedline] && $selectedline == $idline($id)} {
3584 selectline $selectedline 0
3584 selectline $selectedline 0
3585 }
3585 }
3586 }
3586 }
3587
3587
3588 proc mktagcan {} {
3588 proc mktagcan {} {
3589 global mktagtop
3589 global mktagtop
3590
3590
3591 catch {destroy $mktagtop}
3591 catch {destroy $mktagtop}
3592 unset mktagtop
3592 unset mktagtop
3593 }
3593 }
3594
3594
3595 proc mktaggo {} {
3595 proc mktaggo {} {
3596 domktag
3596 domktag
3597 mktagcan
3597 mktagcan
3598 }
3598 }
3599
3599
3600 proc writecommit {} {
3600 proc writecommit {} {
3601 global rowmenuid wrcomtop commitinfo wrcomcmd
3601 global rowmenuid wrcomtop commitinfo wrcomcmd
3602
3602
3603 set top .writecommit
3603 set top .writecommit
3604 set wrcomtop $top
3604 set wrcomtop $top
3605 catch {destroy $top}
3605 catch {destroy $top}
3606 toplevel $top
3606 toplevel $top
3607 label $top.title -text "Write commit to file"
3607 label $top.title -text "Write commit to file"
3608 grid $top.title - -pady 10
3608 grid $top.title - -pady 10
3609 label $top.id -text "ID:"
3609 label $top.id -text "ID:"
3610 entry $top.sha1 -width 40 -relief flat
3610 entry $top.sha1 -width 40 -relief flat
3611 $top.sha1 insert 0 $rowmenuid
3611 $top.sha1 insert 0 $rowmenuid
3612 $top.sha1 conf -state readonly
3612 $top.sha1 conf -state readonly
3613 grid $top.id $top.sha1 -sticky w
3613 grid $top.id $top.sha1 -sticky w
3614 entry $top.head -width 60 -relief flat
3614 entry $top.head -width 60 -relief flat
3615 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3615 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3616 $top.head conf -state readonly
3616 $top.head conf -state readonly
3617 grid x $top.head -sticky w
3617 grid x $top.head -sticky w
3618 label $top.clab -text "Command:"
3618 label $top.clab -text "Command:"
3619 entry $top.cmd -width 60 -textvariable wrcomcmd
3619 entry $top.cmd -width 60 -textvariable wrcomcmd
3620 grid $top.clab $top.cmd -sticky w -pady 10
3620 grid $top.clab $top.cmd -sticky w -pady 10
3621 label $top.flab -text "Output file:"
3621 label $top.flab -text "Output file:"
3622 entry $top.fname -width 60
3622 entry $top.fname -width 60
3623 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3623 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3624 grid $top.flab $top.fname -sticky w
3624 grid $top.flab $top.fname -sticky w
3625 frame $top.buts
3625 frame $top.buts
3626 button $top.buts.gen -text "Write" -command wrcomgo
3626 button $top.buts.gen -text "Write" -command wrcomgo
3627 button $top.buts.can -text "Cancel" -command wrcomcan
3627 button $top.buts.can -text "Cancel" -command wrcomcan
3628 grid $top.buts.gen $top.buts.can
3628 grid $top.buts.gen $top.buts.can
3629 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3629 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3630 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3630 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3631 grid $top.buts - -pady 10 -sticky ew
3631 grid $top.buts - -pady 10 -sticky ew
3632 focus $top.fname
3632 focus $top.fname
3633 }
3633 }
3634
3634
3635 proc wrcomgo {} {
3635 proc wrcomgo {} {
3636 global wrcomtop
3636 global wrcomtop
3637
3637
3638 set id [$wrcomtop.sha1 get]
3638 set id [$wrcomtop.sha1 get]
3639 set cmd "echo $id | [$wrcomtop.cmd get]"
3639 set cmd "echo $id | [$wrcomtop.cmd get]"
3640 set fname [$wrcomtop.fname get]
3640 set fname [$wrcomtop.fname get]
3641 if {[catch {exec sh -c $cmd > $fname &} err]} {
3641 if {[catch {exec sh -c $cmd > $fname &} err]} {
3642 error_popup "Error writing commit: $err"
3642 error_popup "Error writing commit: $err"
3643 }
3643 }
3644 catch {destroy $wrcomtop}
3644 catch {destroy $wrcomtop}
3645 unset wrcomtop
3645 unset wrcomtop
3646 }
3646 }
3647
3647
3648 proc wrcomcan {} {
3648 proc wrcomcan {} {
3649 global wrcomtop
3649 global wrcomtop
3650
3650
3651 catch {destroy $wrcomtop}
3651 catch {destroy $wrcomtop}
3652 unset wrcomtop
3652 unset wrcomtop
3653 }
3653 }
3654
3654
3655 proc listrefs {id} {
3655 proc listrefs {id} {
3656 global idtags idheads idotherrefs
3656 global idtags idheads idotherrefs
3657
3657
3658 set x {}
3658 set x {}
3659 if {[info exists idtags($id)]} {
3659 if {[info exists idtags($id)]} {
3660 set x $idtags($id)
3660 set x $idtags($id)
3661 }
3661 }
3662 set y {}
3662 set y {}
3663 if {[info exists idheads($id)]} {
3663 if {[info exists idheads($id)]} {
3664 set y $idheads($id)
3664 set y $idheads($id)
3665 }
3665 }
3666 set z {}
3666 set z {}
3667 if {[info exists idotherrefs($id)]} {
3667 if {[info exists idotherrefs($id)]} {
3668 set z $idotherrefs($id)
3668 set z $idotherrefs($id)
3669 }
3669 }
3670 return [list $x $y $z]
3670 return [list $x $y $z]
3671 }
3671 }
3672
3672
3673 proc rereadrefs {} {
3673 proc rereadrefs {} {
3674 global idtags idheads idotherrefs
3674 global idtags idheads idotherrefs
3675 global tagids headids otherrefids
3675 global tagids headids otherrefids
3676
3676
3677 set refids [concat [array names idtags] \
3677 set refids [concat [array names idtags] \
3678 [array names idheads] [array names idotherrefs]]
3678 [array names idheads] [array names idotherrefs]]
3679 foreach id $refids {
3679 foreach id $refids {
3680 if {![info exists ref($id)]} {
3680 if {![info exists ref($id)]} {
3681 set ref($id) [listrefs $id]
3681 set ref($id) [listrefs $id]
3682 }
3682 }
3683 }
3683 }
3684 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
3684 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
3685 catch {unset $v}
3685 catch {unset $v}
3686 }
3686 }
3687 readrefs
3687 readrefs
3688 set refids [lsort -unique [concat $refids [array names idtags] \
3688 set refids [lsort -unique [concat $refids [array names idtags] \
3689 [array names idheads] [array names idotherrefs]]]
3689 [array names idheads] [array names idotherrefs]]]
3690 foreach id $refids {
3690 foreach id $refids {
3691 set v [listrefs $id]
3691 set v [listrefs $id]
3692 if {![info exists ref($id)] || $ref($id) != $v} {
3692 if {![info exists ref($id)] || $ref($id) != $v} {
3693 redrawtags $id
3693 redrawtags $id
3694 }
3694 }
3695 }
3695 }
3696 }
3696 }
3697
3697
3698 proc showtag {tag isnew} {
3698 proc showtag {tag isnew} {
3699 global ctext cflist tagcontents tagids linknum
3699 global ctext cflist tagcontents tagids linknum
3700
3700
3701 if {$isnew} {
3701 if {$isnew} {
3702 addtohistory [list showtag $tag 0]
3702 addtohistory [list showtag $tag 0]
3703 }
3703 }
3704 $ctext conf -state normal
3704 $ctext conf -state normal
3705 $ctext delete 0.0 end
3705 $ctext delete 0.0 end
3706 set linknum 0
3706 set linknum 0
3707 if {[info exists tagcontents($tag)]} {
3707 if {[info exists tagcontents($tag)]} {
3708 set text $tagcontents($tag)
3708 set text $tagcontents($tag)
3709 } else {
3709 } else {
3710 set text "Tag: $tag\nId: $tagids($tag)"
3710 set text "Tag: $tag\nId: $tagids($tag)"
3711 }
3711 }
3712 appendwithlinks $text
3712 appendwithlinks $text
3713 $ctext conf -state disabled
3713 $ctext conf -state disabled
3714 $cflist delete 0 end
3714 $cflist delete 0 end
3715 }
3715 }
3716
3716
3717 proc doquit {} {
3717 proc doquit {} {
3718 global stopped
3718 global stopped
3719 set stopped 100
3719 set stopped 100
3720 destroy .
3720 destroy .
3721 }
3721 }
3722
3722
3723 proc getconfig {} {
3724 global env
3725
3726 set lines [exec $env(HG) debug-config]
3727 regsub -all "\r\n" $lines "\n" config
3728 set config {}
3729 foreach line [split $lines "\n"] {
3730 regsub "^(k|v)=" $line "" line
3731 lappend config $line
3732 }
3733 return $config
3734 }
3735
3723 # defaults...
3736 # defaults...
3724 set datemode 0
3737 set datemode 0
3725 set boldnames 0
3738 set boldnames 0
3726 set diffopts "-U 5 -p"
3739 set diffopts "-U 5 -p"
3727 set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty"
3740 set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty"
3728
3741
3729 set mainfont {Helvetica 9}
3742 set mainfont {Helvetica 9}
3730 set textfont {Courier 9}
3743 set textfont {Courier 9}
3731 set findmergefiles 0
3744 set findmergefiles 0
3732 set gaudydiff 0
3745 set gaudydiff 0
3733 set maxgraphpct 50
3746 set maxgraphpct 50
3734 set maxwidth 16
3747 set maxwidth 16
3735
3748
3736 set colors {green red blue magenta darkgrey brown orange}
3749 set colors {green red blue magenta darkgrey brown orange}
3737
3750
3738 catch {source ~/.gitk}
3751 catch {source ~/.gitk}
3739
3752
3740 set namefont $mainfont
3753 set namefont $mainfont
3741 if {$boldnames} {
3754 if {$boldnames} {
3742 lappend namefont bold
3755 lappend namefont bold
3743 }
3756 }
3744
3757
3745 set revtreeargs {}
3758 set revtreeargs {}
3746 foreach arg $argv {
3759 foreach arg $argv {
3747 switch -regexp -- $arg {
3760 switch -regexp -- $arg {
3748 "^$" { }
3761 "^$" { }
3749 "^-b" { set boldnames 1 }
3762 "^-b" { set boldnames 1 }
3750 "^-d" { set datemode 1 }
3763 "^-d" { set datemode 1 }
3751 default {
3764 default {
3752 lappend revtreeargs $arg
3765 lappend revtreeargs $arg
3753 }
3766 }
3754 }
3767 }
3755 }
3768 }
3756
3769
3757 set history {}
3770 set history {}
3758 set historyindex 0
3771 set historyindex 0
3759
3772
3760 set stopped 0
3773 set stopped 0
3761 set redisplaying 0
3774 set redisplaying 0
3762 set stuffsaved 0
3775 set stuffsaved 0
3763 set patchnum 0
3776 set patchnum 0
3764 setcoords
3777 setcoords
3765 makewindow
3778 makewindow
3766 readrefs
3779 readrefs
3767 set hgroot [exec $env(HG) root]
3780 set hgroot [exec $env(HG) root]
3768 wm title . "hgk $hgroot"
3781 wm title . "hgk $hgroot"
3769 getcommits $revtreeargs
3782 getcommits $revtreeargs
@@ -1,308 +1,318
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import sys, os
8 import sys, os
9 from mercurial import hg, fancyopts, commands, ui, util, patch, revlog
9 from mercurial import hg, fancyopts, commands, ui, util, patch, revlog
10
10
11 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
11 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
12 """diff trees from two commits"""
12 """diff trees from two commits"""
13 def __difftree(repo, node1, node2, files=[]):
13 def __difftree(repo, node1, node2, files=[]):
14 assert node2 is not None
14 assert node2 is not None
15 mmap = repo.changectx(node1).manifest()
15 mmap = repo.changectx(node1).manifest()
16 mmap2 = repo.changectx(node2).manifest()
16 mmap2 = repo.changectx(node2).manifest()
17 status = repo.status(node1, node2, files=files)[:5]
17 status = repo.status(node1, node2, files=files)[:5]
18 modified, added, removed, deleted, unknown = status
18 modified, added, removed, deleted, unknown = status
19
19
20 empty = hg.short(hg.nullid)
20 empty = hg.short(hg.nullid)
21
21
22 for f in modified:
22 for f in modified:
23 # TODO get file permissions
23 # TODO get file permissions
24 print ":100664 100664 %s %s M\t%s\t%s" % (hg.short(mmap[f]),
24 print ":100664 100664 %s %s M\t%s\t%s" % (hg.short(mmap[f]),
25 hg.short(mmap2[f]),
25 hg.short(mmap2[f]),
26 f, f)
26 f, f)
27 for f in added:
27 for f in added:
28 print ":000000 100664 %s %s N\t%s\t%s" % (empty,
28 print ":000000 100664 %s %s N\t%s\t%s" % (empty,
29 hg.short(mmap2[f]),
29 hg.short(mmap2[f]),
30 f, f)
30 f, f)
31 for f in removed:
31 for f in removed:
32 print ":100664 000000 %s %s D\t%s\t%s" % (hg.short(mmap[f]),
32 print ":100664 000000 %s %s D\t%s\t%s" % (hg.short(mmap[f]),
33 empty,
33 empty,
34 f, f)
34 f, f)
35 ##
35 ##
36
36
37 while True:
37 while True:
38 if opts['stdin']:
38 if opts['stdin']:
39 try:
39 try:
40 line = raw_input().split(' ')
40 line = raw_input().split(' ')
41 node1 = line[0]
41 node1 = line[0]
42 if len(line) > 1:
42 if len(line) > 1:
43 node2 = line[1]
43 node2 = line[1]
44 else:
44 else:
45 node2 = None
45 node2 = None
46 except EOFError:
46 except EOFError:
47 break
47 break
48 node1 = repo.lookup(node1)
48 node1 = repo.lookup(node1)
49 if node2:
49 if node2:
50 node2 = repo.lookup(node2)
50 node2 = repo.lookup(node2)
51 else:
51 else:
52 node2 = node1
52 node2 = node1
53 node1 = repo.changelog.parents(node1)[0]
53 node1 = repo.changelog.parents(node1)[0]
54 if opts['patch']:
54 if opts['patch']:
55 if opts['pretty']:
55 if opts['pretty']:
56 catcommit(repo, node2, "")
56 catcommit(repo, node2, "")
57 patch.diff(repo, node1, node2,
57 patch.diff(repo, node1, node2,
58 files=files,
58 files=files,
59 opts=patch.diffopts(ui, {'git': True}))
59 opts=patch.diffopts(ui, {'git': True}))
60 else:
60 else:
61 __difftree(repo, node1, node2, files=files)
61 __difftree(repo, node1, node2, files=files)
62 if not opts['stdin']:
62 if not opts['stdin']:
63 break
63 break
64
64
65 def catcommit(repo, n, prefix, ctx=None):
65 def catcommit(repo, n, prefix, ctx=None):
66 nlprefix = '\n' + prefix;
66 nlprefix = '\n' + prefix;
67 if ctx is None:
67 if ctx is None:
68 ctx = repo.changectx(n)
68 ctx = repo.changectx(n)
69 (p1, p2) = ctx.parents()
69 (p1, p2) = ctx.parents()
70 print "tree %s" % (hg.short(ctx.changeset()[0])) # use ctx.node() instead ??
70 print "tree %s" % (hg.short(ctx.changeset()[0])) # use ctx.node() instead ??
71 if p1: print "parent %s" % (hg.short(p1.node()))
71 if p1: print "parent %s" % (hg.short(p1.node()))
72 if p2: print "parent %s" % (hg.short(p2.node()))
72 if p2: print "parent %s" % (hg.short(p2.node()))
73 date = ctx.date()
73 date = ctx.date()
74 description = ctx.description().replace("\0", "")
74 description = ctx.description().replace("\0", "")
75 lines = description.splitlines()
75 lines = description.splitlines()
76 if lines and lines[-1].startswith('committer:'):
76 if lines and lines[-1].startswith('committer:'):
77 committer = lines[-1].split(': ')[1].rstrip()
77 committer = lines[-1].split(': ')[1].rstrip()
78 else:
78 else:
79 committer = ctx.user()
79 committer = ctx.user()
80
80
81 print "author %s %s %s" % (ctx.user(), int(date[0]), date[1])
81 print "author %s %s %s" % (ctx.user(), int(date[0]), date[1])
82 print "committer %s %s %s" % (committer, int(date[0]), date[1])
82 print "committer %s %s %s" % (committer, int(date[0]), date[1])
83 print "revision %d" % ctx.rev()
83 print "revision %d" % ctx.rev()
84 print ""
84 print ""
85 if prefix != "":
85 if prefix != "":
86 print "%s%s" % (prefix, description.replace('\n', nlprefix).strip())
86 print "%s%s" % (prefix, description.replace('\n', nlprefix).strip())
87 else:
87 else:
88 print description
88 print description
89 if prefix:
89 if prefix:
90 sys.stdout.write('\0')
90 sys.stdout.write('\0')
91
91
92 def base(ui, repo, node1, node2):
92 def base(ui, repo, node1, node2):
93 """Output common ancestor information"""
93 """Output common ancestor information"""
94 node1 = repo.lookup(node1)
94 node1 = repo.lookup(node1)
95 node2 = repo.lookup(node2)
95 node2 = repo.lookup(node2)
96 n = repo.changelog.ancestor(node1, node2)
96 n = repo.changelog.ancestor(node1, node2)
97 print hg.short(n)
97 print hg.short(n)
98
98
99 def catfile(ui, repo, type=None, r=None, **opts):
99 def catfile(ui, repo, type=None, r=None, **opts):
100 """cat a specific revision"""
100 """cat a specific revision"""
101 # in stdin mode, every line except the commit is prefixed with two
101 # in stdin mode, every line except the commit is prefixed with two
102 # spaces. This way the our caller can find the commit without magic
102 # spaces. This way the our caller can find the commit without magic
103 # strings
103 # strings
104 #
104 #
105 prefix = ""
105 prefix = ""
106 if opts['stdin']:
106 if opts['stdin']:
107 try:
107 try:
108 (type, r) = raw_input().split(' ');
108 (type, r) = raw_input().split(' ');
109 prefix = " "
109 prefix = " "
110 except EOFError:
110 except EOFError:
111 return
111 return
112
112
113 else:
113 else:
114 if not type or not r:
114 if not type or not r:
115 ui.warn("cat-file: type or revision not supplied\n")
115 ui.warn("cat-file: type or revision not supplied\n")
116 commands.help_(ui, 'cat-file')
116 commands.help_(ui, 'cat-file')
117
117
118 while r:
118 while r:
119 if type != "commit":
119 if type != "commit":
120 sys.stderr.write("aborting hg cat-file only understands commits\n")
120 sys.stderr.write("aborting hg cat-file only understands commits\n")
121 sys.exit(1);
121 sys.exit(1);
122 n = repo.lookup(r)
122 n = repo.lookup(r)
123 catcommit(repo, n, prefix)
123 catcommit(repo, n, prefix)
124 if opts['stdin']:
124 if opts['stdin']:
125 try:
125 try:
126 (type, r) = raw_input().split(' ');
126 (type, r) = raw_input().split(' ');
127 except EOFError:
127 except EOFError:
128 break
128 break
129 else:
129 else:
130 break
130 break
131
131
132 # git rev-tree is a confusing thing. You can supply a number of
132 # git rev-tree is a confusing thing. You can supply a number of
133 # commit sha1s on the command line, and it walks the commit history
133 # commit sha1s on the command line, and it walks the commit history
134 # telling you which commits are reachable from the supplied ones via
134 # telling you which commits are reachable from the supplied ones via
135 # a bitmask based on arg position.
135 # a bitmask based on arg position.
136 # you can specify a commit to stop at by starting the sha1 with ^
136 # you can specify a commit to stop at by starting the sha1 with ^
137 def revtree(args, repo, full="tree", maxnr=0, parents=False):
137 def revtree(args, repo, full="tree", maxnr=0, parents=False):
138 def chlogwalk():
138 def chlogwalk():
139 count = repo.changelog.count()
139 count = repo.changelog.count()
140 i = count
140 i = count
141 l = [0] * 100
141 l = [0] * 100
142 chunk = 100
142 chunk = 100
143 while True:
143 while True:
144 if chunk > i:
144 if chunk > i:
145 chunk = i
145 chunk = i
146 i = 0
146 i = 0
147 else:
147 else:
148 i -= chunk
148 i -= chunk
149
149
150 for x in xrange(0, chunk):
150 for x in xrange(0, chunk):
151 if i + x >= count:
151 if i + x >= count:
152 l[chunk - x:] = [0] * (chunk - x)
152 l[chunk - x:] = [0] * (chunk - x)
153 break
153 break
154 if full != None:
154 if full != None:
155 l[x] = repo.changectx(i + x)
155 l[x] = repo.changectx(i + x)
156 l[x].changeset() # force reading
156 l[x].changeset() # force reading
157 else:
157 else:
158 l[x] = 1
158 l[x] = 1
159 for x in xrange(chunk-1, -1, -1):
159 for x in xrange(chunk-1, -1, -1):
160 if l[x] != 0:
160 if l[x] != 0:
161 yield (i + x, full != None and l[x] or None)
161 yield (i + x, full != None and l[x] or None)
162 if i == 0:
162 if i == 0:
163 break
163 break
164
164
165 # calculate and return the reachability bitmask for sha
165 # calculate and return the reachability bitmask for sha
166 def is_reachable(ar, reachable, sha):
166 def is_reachable(ar, reachable, sha):
167 if len(ar) == 0:
167 if len(ar) == 0:
168 return 1
168 return 1
169 mask = 0
169 mask = 0
170 for i in xrange(len(ar)):
170 for i in xrange(len(ar)):
171 if sha in reachable[i]:
171 if sha in reachable[i]:
172 mask |= 1 << i
172 mask |= 1 << i
173
173
174 return mask
174 return mask
175
175
176 reachable = []
176 reachable = []
177 stop_sha1 = []
177 stop_sha1 = []
178 want_sha1 = []
178 want_sha1 = []
179 count = 0
179 count = 0
180
180
181 # figure out which commits they are asking for and which ones they
181 # figure out which commits they are asking for and which ones they
182 # want us to stop on
182 # want us to stop on
183 for i in xrange(len(args)):
183 for i in xrange(len(args)):
184 if args[i].startswith('^'):
184 if args[i].startswith('^'):
185 s = repo.lookup(args[i][1:])
185 s = repo.lookup(args[i][1:])
186 stop_sha1.append(s)
186 stop_sha1.append(s)
187 want_sha1.append(s)
187 want_sha1.append(s)
188 elif args[i] != 'HEAD':
188 elif args[i] != 'HEAD':
189 want_sha1.append(repo.lookup(args[i]))
189 want_sha1.append(repo.lookup(args[i]))
190
190
191 # calculate the graph for the supplied commits
191 # calculate the graph for the supplied commits
192 for i in xrange(len(want_sha1)):
192 for i in xrange(len(want_sha1)):
193 reachable.append({});
193 reachable.append({});
194 n = want_sha1[i];
194 n = want_sha1[i];
195 visit = [n];
195 visit = [n];
196 reachable[i][n] = 1
196 reachable[i][n] = 1
197 while visit:
197 while visit:
198 n = visit.pop(0)
198 n = visit.pop(0)
199 if n in stop_sha1:
199 if n in stop_sha1:
200 continue
200 continue
201 for p in repo.changelog.parents(n):
201 for p in repo.changelog.parents(n):
202 if p not in reachable[i]:
202 if p not in reachable[i]:
203 reachable[i][p] = 1
203 reachable[i][p] = 1
204 visit.append(p)
204 visit.append(p)
205 if p in stop_sha1:
205 if p in stop_sha1:
206 continue
206 continue
207
207
208 # walk the repository looking for commits that are in our
208 # walk the repository looking for commits that are in our
209 # reachability graph
209 # reachability graph
210 for i, ctx in chlogwalk():
210 for i, ctx in chlogwalk():
211 n = repo.changelog.node(i)
211 n = repo.changelog.node(i)
212 mask = is_reachable(want_sha1, reachable, n)
212 mask = is_reachable(want_sha1, reachable, n)
213 if mask:
213 if mask:
214 parentstr = ""
214 parentstr = ""
215 if parents:
215 if parents:
216 pp = repo.changelog.parents(n)
216 pp = repo.changelog.parents(n)
217 if pp[0] != hg.nullid:
217 if pp[0] != hg.nullid:
218 parentstr += " " + hg.short(pp[0])
218 parentstr += " " + hg.short(pp[0])
219 if pp[1] != hg.nullid:
219 if pp[1] != hg.nullid:
220 parentstr += " " + hg.short(pp[1])
220 parentstr += " " + hg.short(pp[1])
221 if not full:
221 if not full:
222 print hg.short(n) + parentstr
222 print hg.short(n) + parentstr
223 elif full == "commit":
223 elif full == "commit":
224 print hg.short(n) + parentstr
224 print hg.short(n) + parentstr
225 catcommit(repo, n, ' ', ctx)
225 catcommit(repo, n, ' ', ctx)
226 else:
226 else:
227 (p1, p2) = repo.changelog.parents(n)
227 (p1, p2) = repo.changelog.parents(n)
228 (h, h1, h2) = map(hg.short, (n, p1, p2))
228 (h, h1, h2) = map(hg.short, (n, p1, p2))
229 (i1, i2) = map(repo.changelog.rev, (p1, p2))
229 (i1, i2) = map(repo.changelog.rev, (p1, p2))
230
230
231 date = ctx.date()[0]
231 date = ctx.date()[0]
232 print "%s %s:%s" % (date, h, mask),
232 print "%s %s:%s" % (date, h, mask),
233 mask = is_reachable(want_sha1, reachable, p1)
233 mask = is_reachable(want_sha1, reachable, p1)
234 if i1 != hg.nullrev and mask > 0:
234 if i1 != hg.nullrev and mask > 0:
235 print "%s:%s " % (h1, mask),
235 print "%s:%s " % (h1, mask),
236 mask = is_reachable(want_sha1, reachable, p2)
236 mask = is_reachable(want_sha1, reachable, p2)
237 if i2 != hg.nullrev and mask > 0:
237 if i2 != hg.nullrev and mask > 0:
238 print "%s:%s " % (h2, mask),
238 print "%s:%s " % (h2, mask),
239 print ""
239 print ""
240 if maxnr and count >= maxnr:
240 if maxnr and count >= maxnr:
241 break
241 break
242 count += 1
242 count += 1
243
243
244 def revparse(ui, repo, *revs, **opts):
244 def revparse(ui, repo, *revs, **opts):
245 """Parse given revisions"""
245 """Parse given revisions"""
246 def revstr(rev):
246 def revstr(rev):
247 if rev == 'HEAD':
247 if rev == 'HEAD':
248 rev = 'tip'
248 rev = 'tip'
249 return revlog.hex(repo.lookup(rev))
249 return revlog.hex(repo.lookup(rev))
250
250
251 for r in revs:
251 for r in revs:
252 revrange = r.split(':', 1)
252 revrange = r.split(':', 1)
253 ui.write('%s\n' % revstr(revrange[0]))
253 ui.write('%s\n' % revstr(revrange[0]))
254 if len(revrange) == 2:
254 if len(revrange) == 2:
255 ui.write('^%s\n' % revstr(revrange[1]))
255 ui.write('^%s\n' % revstr(revrange[1]))
256
256
257 # git rev-list tries to order things by date, and has the ability to stop
257 # git rev-list tries to order things by date, and has the ability to stop
258 # at a given commit without walking the whole repo. TODO add the stop
258 # at a given commit without walking the whole repo. TODO add the stop
259 # parameter
259 # parameter
260 def revlist(ui, repo, *revs, **opts):
260 def revlist(ui, repo, *revs, **opts):
261 """print revisions"""
261 """print revisions"""
262 if opts['header']:
262 if opts['header']:
263 full = "commit"
263 full = "commit"
264 else:
264 else:
265 full = None
265 full = None
266 copy = [x for x in revs]
266 copy = [x for x in revs]
267 revtree(copy, repo, full, opts['max_count'], opts['parents'])
267 revtree(copy, repo, full, opts['max_count'], opts['parents'])
268
268
269 def config(ui, repo, **opts):
270 """print extension options"""
271 def writeopt(name, value):
272 ui.write('k=%s\nv=%s\n' % (name, value))
273
274 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
275
276
269 def view(ui, repo, *etc, **opts):
277 def view(ui, repo, *etc, **opts):
270 "start interactive history viewer"
278 "start interactive history viewer"
271 os.chdir(repo.root)
279 os.chdir(repo.root)
272 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
280 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
273 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
281 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
274 ui.debug("running %s\n" % cmd)
282 ui.debug("running %s\n" % cmd)
275 util.system(cmd)
283 util.system(cmd)
276
284
277 cmdtable = {
285 cmdtable = {
278 "^view":
286 "^view":
279 (view,
287 (view,
280 [('l', 'limit', '', 'limit number of changes displayed')],
288 [('l', 'limit', '', 'limit number of changes displayed')],
281 'hg view [-l LIMIT] [REVRANGE]'),
289 'hg view [-l LIMIT] [REVRANGE]'),
282 "debug-diff-tree":
290 "debug-diff-tree":
283 (difftree,
291 (difftree,
284 [('p', 'patch', None, 'generate patch'),
292 [('p', 'patch', None, 'generate patch'),
285 ('r', 'recursive', None, 'recursive'),
293 ('r', 'recursive', None, 'recursive'),
286 ('P', 'pretty', None, 'pretty'),
294 ('P', 'pretty', None, 'pretty'),
287 ('s', 'stdin', None, 'stdin'),
295 ('s', 'stdin', None, 'stdin'),
288 ('C', 'copy', None, 'detect copies'),
296 ('C', 'copy', None, 'detect copies'),
289 ('S', 'search', "", 'search')],
297 ('S', 'search', "", 'search')],
290 'hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...'),
298 'hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...'),
291 "debug-cat-file":
299 "debug-cat-file":
292 (catfile,
300 (catfile,
293 [('s', 'stdin', None, 'stdin')],
301 [('s', 'stdin', None, 'stdin')],
294 'hg debug-cat-file [OPTION]... TYPE FILE'),
302 'hg debug-cat-file [OPTION]... TYPE FILE'),
303 "debug-config":
304 (config, [], 'hg debug-config'),
295 "debug-merge-base":
305 "debug-merge-base":
296 (base, [], 'hg debug-merge-base node node'),
306 (base, [], 'hg debug-merge-base node node'),
297 "debug-rev-parse":
307 "debug-rev-parse":
298 (revparse,
308 (revparse,
299 [('', 'default', '', 'ignored')],
309 [('', 'default', '', 'ignored')],
300 'hg debug-rev-parse REV'),
310 'hg debug-rev-parse REV'),
301 "debug-rev-list":
311 "debug-rev-list":
302 (revlist,
312 (revlist,
303 [('H', 'header', None, 'header'),
313 [('H', 'header', None, 'header'),
304 ('t', 'topo-order', None, 'topo-order'),
314 ('t', 'topo-order', None, 'topo-order'),
305 ('p', 'parents', None, 'parents'),
315 ('p', 'parents', None, 'parents'),
306 ('n', 'max-count', 0, 'max-count')],
316 ('n', 'max-count', 0, 'max-count')],
307 'hg debug-rev-list [options] revs'),
317 'hg debug-rev-list [options] revs'),
308 }
318 }
General Comments 0
You need to be logged in to leave comments. Login now