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