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