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