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