##// END OF EJS Templates
hgk: drop committer field from the UI...
Andrew Shadura -
r18801:c84cc0f3 default
parent child Browse files
Show More
@@ -1,4106 +1,4105
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 Committer 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 Committer 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 "Revision: [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 "Author: [lindex $info 1] [lindex $info 2]\n"
2479 $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
2480 if {[info exists idbookmarks($id)]} {
2479 if {[info exists idbookmarks($id)]} {
2481 $ctext insert end "Bookmarks:"
2480 $ctext insert end "Bookmarks:"
2482 foreach bookmark $idbookmarks($id) {
2481 foreach bookmark $idbookmarks($id) {
2483 $ctext insert end " $bookmark"
2482 $ctext insert end " $bookmark"
2484 }
2483 }
2485 $ctext insert end "\n"
2484 $ctext insert end "\n"
2486 }
2485 }
2487
2486
2488 if {[info exists idtags($id)]} {
2487 if {[info exists idtags($id)]} {
2489 $ctext insert end "Tags:"
2488 $ctext insert end "Tags:"
2490 foreach tag $idtags($id) {
2489 foreach tag $idtags($id) {
2491 $ctext insert end " $tag"
2490 $ctext insert end " $tag"
2492 }
2491 }
2493 $ctext insert end "\n"
2492 $ctext insert end "\n"
2494 }
2493 }
2495
2494
2496 set comment {}
2495 set comment {}
2497 if {[info exists parents($id)]} {
2496 if {[info exists parents($id)]} {
2498 foreach p $parents($id) {
2497 foreach p $parents($id) {
2499 append comment "Parent: [commit_descriptor $p]\n"
2498 append comment "Parent: [commit_descriptor $p]\n"
2500 }
2499 }
2501 }
2500 }
2502 if {[info exists children($id)]} {
2501 if {[info exists children($id)]} {
2503 foreach c $children($id) {
2502 foreach c $children($id) {
2504 append comment "Child: [commit_descriptor $c]\n"
2503 append comment "Child: [commit_descriptor $c]\n"
2505 }
2504 }
2506 }
2505 }
2507 append comment "\n"
2506 append comment "\n"
2508 append comment [lindex $info 5]
2507 append comment [lindex $info 5]
2509
2508
2510 # make anything that looks like a SHA1 ID be a clickable link
2509 # make anything that looks like a SHA1 ID be a clickable link
2511 appendwithlinks $comment
2510 appendwithlinks $comment
2512
2511
2513 $ctext tag delete Comments
2512 $ctext tag delete Comments
2514 $ctext tag remove found 1.0 end
2513 $ctext tag remove found 1.0 end
2515 $ctext conf -state disabled
2514 $ctext conf -state disabled
2516 set commentend [$ctext index "end - 1c"]
2515 set commentend [$ctext index "end - 1c"]
2517
2516
2518 $cflist delete 0 end
2517 $cflist delete 0 end
2519 $cflist insert end "Comments"
2518 $cflist insert end "Comments"
2520 if {$nparents($id) <= 1} {
2519 if {$nparents($id) <= 1} {
2521 set parent "null"
2520 set parent "null"
2522 if {$nparents($id) == 1} {
2521 if {$nparents($id) == 1} {
2523 set parent $parents($id)
2522 set parent $parents($id)
2524 }
2523 }
2525 startdiff [concat $id $parent]
2524 startdiff [concat $id $parent]
2526 } elseif {$nparents($id) > 1} {
2525 } elseif {$nparents($id) > 1} {
2527 mergediff $id
2526 mergediff $id
2528 }
2527 }
2529 }
2528 }
2530
2529
2531 proc selnextline {dir} {
2530 proc selnextline {dir} {
2532 global selectedline
2531 global selectedline
2533 if {![info exists selectedline]} return
2532 if {![info exists selectedline]} return
2534 set l [expr $selectedline + $dir]
2533 set l [expr $selectedline + $dir]
2535 unmarkmatches
2534 unmarkmatches
2536 selectline $l 1
2535 selectline $l 1
2537 }
2536 }
2538
2537
2539 proc unselectline {} {
2538 proc unselectline {} {
2540 global selectedline
2539 global selectedline
2541
2540
2542 catch {unset selectedline}
2541 catch {unset selectedline}
2543 allcanvs delete secsel
2542 allcanvs delete secsel
2544 }
2543 }
2545
2544
2546 proc addtohistory {cmd} {
2545 proc addtohistory {cmd} {
2547 global history historyindex
2546 global history historyindex
2548
2547
2549 if {$historyindex > 0
2548 if {$historyindex > 0
2550 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2549 && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
2551 return
2550 return
2552 }
2551 }
2553
2552
2554 if {$historyindex < [llength $history]} {
2553 if {$historyindex < [llength $history]} {
2555 set history [lreplace $history $historyindex end $cmd]
2554 set history [lreplace $history $historyindex end $cmd]
2556 } else {
2555 } else {
2557 lappend history $cmd
2556 lappend history $cmd
2558 }
2557 }
2559 incr historyindex
2558 incr historyindex
2560 if {$historyindex > 1} {
2559 if {$historyindex > 1} {
2561 .ctop.top.bar.leftbut conf -state normal
2560 .ctop.top.bar.leftbut conf -state normal
2562 } else {
2561 } else {
2563 .ctop.top.bar.leftbut conf -state disabled
2562 .ctop.top.bar.leftbut conf -state disabled
2564 }
2563 }
2565 .ctop.top.bar.rightbut conf -state disabled
2564 .ctop.top.bar.rightbut conf -state disabled
2566 }
2565 }
2567
2566
2568 proc goback {} {
2567 proc goback {} {
2569 global history historyindex
2568 global history historyindex
2570
2569
2571 if {$historyindex > 1} {
2570 if {$historyindex > 1} {
2572 incr historyindex -1
2571 incr historyindex -1
2573 set cmd [lindex $history [expr {$historyindex - 1}]]
2572 set cmd [lindex $history [expr {$historyindex - 1}]]
2574 eval $cmd
2573 eval $cmd
2575 .ctop.top.bar.rightbut conf -state normal
2574 .ctop.top.bar.rightbut conf -state normal
2576 }
2575 }
2577 if {$historyindex <= 1} {
2576 if {$historyindex <= 1} {
2578 .ctop.top.bar.leftbut conf -state disabled
2577 .ctop.top.bar.leftbut conf -state disabled
2579 }
2578 }
2580 }
2579 }
2581
2580
2582 proc goforw {} {
2581 proc goforw {} {
2583 global history historyindex
2582 global history historyindex
2584
2583
2585 if {$historyindex < [llength $history]} {
2584 if {$historyindex < [llength $history]} {
2586 set cmd [lindex $history $historyindex]
2585 set cmd [lindex $history $historyindex]
2587 incr historyindex
2586 incr historyindex
2588 eval $cmd
2587 eval $cmd
2589 .ctop.top.bar.leftbut conf -state normal
2588 .ctop.top.bar.leftbut conf -state normal
2590 }
2589 }
2591 if {$historyindex >= [llength $history]} {
2590 if {$historyindex >= [llength $history]} {
2592 .ctop.top.bar.rightbut conf -state disabled
2591 .ctop.top.bar.rightbut conf -state disabled
2593 }
2592 }
2594 }
2593 }
2595
2594
2596 proc mergediff {id} {
2595 proc mergediff {id} {
2597 global parents diffmergeid diffmergegca mergefilelist diffpindex
2596 global parents diffmergeid diffmergegca mergefilelist diffpindex
2598
2597
2599 set diffmergeid $id
2598 set diffmergeid $id
2600 set diffpindex -1
2599 set diffpindex -1
2601 set diffmergegca [findgca $parents($id)]
2600 set diffmergegca [findgca $parents($id)]
2602 if {[info exists mergefilelist($id)]} {
2601 if {[info exists mergefilelist($id)]} {
2603 if {$mergefilelist($id) ne {}} {
2602 if {$mergefilelist($id) ne {}} {
2604 showmergediff
2603 showmergediff
2605 }
2604 }
2606 } else {
2605 } else {
2607 contmergediff {}
2606 contmergediff {}
2608 }
2607 }
2609 }
2608 }
2610
2609
2611 proc findgca {ids} {
2610 proc findgca {ids} {
2612 global env
2611 global env
2613 set gca {}
2612 set gca {}
2614 foreach id $ids {
2613 foreach id $ids {
2615 if {$gca eq {}} {
2614 if {$gca eq {}} {
2616 set gca $id
2615 set gca $id
2617 } else {
2616 } else {
2618 if {[catch {
2617 if {[catch {
2619 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2618 set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id]
2620 } err]} {
2619 } err]} {
2621 return {}
2620 return {}
2622 }
2621 }
2623 }
2622 }
2624 }
2623 }
2625 return $gca
2624 return $gca
2626 }
2625 }
2627
2626
2628 proc contmergediff {ids} {
2627 proc contmergediff {ids} {
2629 global diffmergeid diffpindex parents nparents diffmergegca
2628 global diffmergeid diffpindex parents nparents diffmergegca
2630 global treediffs mergefilelist diffids treepending
2629 global treediffs mergefilelist diffids treepending
2631
2630
2632 # diff the child against each of the parents, and diff
2631 # diff the child against each of the parents, and diff
2633 # each of the parents against the GCA.
2632 # each of the parents against the GCA.
2634 while 1 {
2633 while 1 {
2635 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2634 if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
2636 set ids [list [lindex $ids 1] $diffmergegca]
2635 set ids [list [lindex $ids 1] $diffmergegca]
2637 } else {
2636 } else {
2638 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2637 if {[incr diffpindex] >= $nparents($diffmergeid)} break
2639 set p [lindex $parents($diffmergeid) $diffpindex]
2638 set p [lindex $parents($diffmergeid) $diffpindex]
2640 set ids [list $diffmergeid $p]
2639 set ids [list $diffmergeid $p]
2641 }
2640 }
2642 if {![info exists treediffs($ids)]} {
2641 if {![info exists treediffs($ids)]} {
2643 set diffids $ids
2642 set diffids $ids
2644 if {![info exists treepending]} {
2643 if {![info exists treepending]} {
2645 gettreediffs $ids
2644 gettreediffs $ids
2646 }
2645 }
2647 return
2646 return
2648 }
2647 }
2649 }
2648 }
2650
2649
2651 # If a file in some parent is different from the child and also
2650 # If a file in some parent is different from the child and also
2652 # different from the GCA, then it's interesting.
2651 # different from the GCA, then it's interesting.
2653 # If we don't have a GCA, then a file is interesting if it is
2652 # If we don't have a GCA, then a file is interesting if it is
2654 # different from the child in all the parents.
2653 # different from the child in all the parents.
2655 if {$diffmergegca ne {}} {
2654 if {$diffmergegca ne {}} {
2656 set files {}
2655 set files {}
2657 foreach p $parents($diffmergeid) {
2656 foreach p $parents($diffmergeid) {
2658 set gcadiffs $treediffs([list $p $diffmergegca])
2657 set gcadiffs $treediffs([list $p $diffmergegca])
2659 foreach f $treediffs([list $diffmergeid $p]) {
2658 foreach f $treediffs([list $diffmergeid $p]) {
2660 if {[lsearch -exact $files $f] < 0
2659 if {[lsearch -exact $files $f] < 0
2661 && [lsearch -exact $gcadiffs $f] >= 0} {
2660 && [lsearch -exact $gcadiffs $f] >= 0} {
2662 lappend files $f
2661 lappend files $f
2663 }
2662 }
2664 }
2663 }
2665 }
2664 }
2666 set files [lsort $files]
2665 set files [lsort $files]
2667 } else {
2666 } else {
2668 set p [lindex $parents($diffmergeid) 0]
2667 set p [lindex $parents($diffmergeid) 0]
2669 set files $treediffs([list $diffmergeid $p])
2668 set files $treediffs([list $diffmergeid $p])
2670 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2669 for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
2671 set p [lindex $parents($diffmergeid) $i]
2670 set p [lindex $parents($diffmergeid) $i]
2672 set df $treediffs([list $diffmergeid $p])
2671 set df $treediffs([list $diffmergeid $p])
2673 set nf {}
2672 set nf {}
2674 foreach f $files {
2673 foreach f $files {
2675 if {[lsearch -exact $df $f] >= 0} {
2674 if {[lsearch -exact $df $f] >= 0} {
2676 lappend nf $f
2675 lappend nf $f
2677 }
2676 }
2678 }
2677 }
2679 set files $nf
2678 set files $nf
2680 }
2679 }
2681 }
2680 }
2682
2681
2683 set mergefilelist($diffmergeid) $files
2682 set mergefilelist($diffmergeid) $files
2684 if {$files ne {}} {
2683 if {$files ne {}} {
2685 showmergediff
2684 showmergediff
2686 }
2685 }
2687 }
2686 }
2688
2687
2689 proc showmergediff {} {
2688 proc showmergediff {} {
2690 global cflist diffmergeid mergefilelist parents
2689 global cflist diffmergeid mergefilelist parents
2691 global diffopts diffinhunk currentfile currenthunk filelines
2690 global diffopts diffinhunk currentfile currenthunk filelines
2692 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2691 global diffblocked groupfilelast mergefds groupfilenum grouphunks
2693 global env
2692 global env
2694
2693
2695 set files $mergefilelist($diffmergeid)
2694 set files $mergefilelist($diffmergeid)
2696 foreach f $files {
2695 foreach f $files {
2697 $cflist insert end $f
2696 $cflist insert end $f
2698 }
2697 }
2699 set env(GIT_DIFF_OPTS) $diffopts
2698 set env(GIT_DIFF_OPTS) $diffopts
2700 set flist {}
2699 set flist {}
2701 catch {unset currentfile}
2700 catch {unset currentfile}
2702 catch {unset currenthunk}
2701 catch {unset currenthunk}
2703 catch {unset filelines}
2702 catch {unset filelines}
2704 catch {unset groupfilenum}
2703 catch {unset groupfilenum}
2705 catch {unset grouphunks}
2704 catch {unset grouphunks}
2706 set groupfilelast -1
2705 set groupfilelast -1
2707 foreach p $parents($diffmergeid) {
2706 foreach p $parents($diffmergeid) {
2708 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2707 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid]
2709 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2708 set cmd [concat $cmd $mergefilelist($diffmergeid)]
2710 if {[catch {set f [open $cmd r]} err]} {
2709 if {[catch {set f [open $cmd r]} err]} {
2711 error_popup "Error getting diffs: $err"
2710 error_popup "Error getting diffs: $err"
2712 foreach f $flist {
2711 foreach f $flist {
2713 catch {close $f}
2712 catch {close $f}
2714 }
2713 }
2715 return
2714 return
2716 }
2715 }
2717 lappend flist $f
2716 lappend flist $f
2718 set ids [list $diffmergeid $p]
2717 set ids [list $diffmergeid $p]
2719 set mergefds($ids) $f
2718 set mergefds($ids) $f
2720 set diffinhunk($ids) 0
2719 set diffinhunk($ids) 0
2721 set diffblocked($ids) 0
2720 set diffblocked($ids) 0
2722 fconfigure $f -blocking 0
2721 fconfigure $f -blocking 0
2723 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2722 fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
2724 }
2723 }
2725 }
2724 }
2726
2725
2727 proc getmergediffline {f ids id} {
2726 proc getmergediffline {f ids id} {
2728 global diffmergeid diffinhunk diffoldlines diffnewlines
2727 global diffmergeid diffinhunk diffoldlines diffnewlines
2729 global currentfile currenthunk
2728 global currentfile currenthunk
2730 global diffoldstart diffnewstart diffoldlno diffnewlno
2729 global diffoldstart diffnewstart diffoldlno diffnewlno
2731 global diffblocked mergefilelist
2730 global diffblocked mergefilelist
2732 global noldlines nnewlines difflcounts filelines
2731 global noldlines nnewlines difflcounts filelines
2733
2732
2734 set n [gets $f line]
2733 set n [gets $f line]
2735 if {$n < 0} {
2734 if {$n < 0} {
2736 if {![eof $f]} return
2735 if {![eof $f]} return
2737 }
2736 }
2738
2737
2739 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2738 if {!([info exists diffmergeid] && $diffmergeid == $id)} {
2740 if {$n < 0} {
2739 if {$n < 0} {
2741 close $f
2740 close $f
2742 }
2741 }
2743 return
2742 return
2744 }
2743 }
2745
2744
2746 if {$diffinhunk($ids) != 0} {
2745 if {$diffinhunk($ids) != 0} {
2747 set fi $currentfile($ids)
2746 set fi $currentfile($ids)
2748 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2747 if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
2749 # continuing an existing hunk
2748 # continuing an existing hunk
2750 set line [string range $line 1 end]
2749 set line [string range $line 1 end]
2751 set p [lindex $ids 1]
2750 set p [lindex $ids 1]
2752 if {$match eq "-" || $match eq " "} {
2751 if {$match eq "-" || $match eq " "} {
2753 set filelines($p,$fi,$diffoldlno($ids)) $line
2752 set filelines($p,$fi,$diffoldlno($ids)) $line
2754 incr diffoldlno($ids)
2753 incr diffoldlno($ids)
2755 }
2754 }
2756 if {$match eq "+" || $match eq " "} {
2755 if {$match eq "+" || $match eq " "} {
2757 set filelines($id,$fi,$diffnewlno($ids)) $line
2756 set filelines($id,$fi,$diffnewlno($ids)) $line
2758 incr diffnewlno($ids)
2757 incr diffnewlno($ids)
2759 }
2758 }
2760 if {$match eq " "} {
2759 if {$match eq " "} {
2761 if {$diffinhunk($ids) == 2} {
2760 if {$diffinhunk($ids) == 2} {
2762 lappend difflcounts($ids) \
2761 lappend difflcounts($ids) \
2763 [list $noldlines($ids) $nnewlines($ids)]
2762 [list $noldlines($ids) $nnewlines($ids)]
2764 set noldlines($ids) 0
2763 set noldlines($ids) 0
2765 set diffinhunk($ids) 1
2764 set diffinhunk($ids) 1
2766 }
2765 }
2767 incr noldlines($ids)
2766 incr noldlines($ids)
2768 } elseif {$match eq "-" || $match eq "+"} {
2767 } elseif {$match eq "-" || $match eq "+"} {
2769 if {$diffinhunk($ids) == 1} {
2768 if {$diffinhunk($ids) == 1} {
2770 lappend difflcounts($ids) [list $noldlines($ids)]
2769 lappend difflcounts($ids) [list $noldlines($ids)]
2771 set noldlines($ids) 0
2770 set noldlines($ids) 0
2772 set nnewlines($ids) 0
2771 set nnewlines($ids) 0
2773 set diffinhunk($ids) 2
2772 set diffinhunk($ids) 2
2774 }
2773 }
2775 if {$match eq "-"} {
2774 if {$match eq "-"} {
2776 incr noldlines($ids)
2775 incr noldlines($ids)
2777 } else {
2776 } else {
2778 incr nnewlines($ids)
2777 incr nnewlines($ids)
2779 }
2778 }
2780 }
2779 }
2781 # and if it's \ No newline at end of line, then what?
2780 # and if it's \ No newline at end of line, then what?
2782 return
2781 return
2783 }
2782 }
2784 # end of a hunk
2783 # end of a hunk
2785 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2784 if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
2786 lappend difflcounts($ids) [list $noldlines($ids)]
2785 lappend difflcounts($ids) [list $noldlines($ids)]
2787 } elseif {$diffinhunk($ids) == 2
2786 } elseif {$diffinhunk($ids) == 2
2788 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2787 && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
2789 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2788 lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
2790 }
2789 }
2791 set currenthunk($ids) [list $currentfile($ids) \
2790 set currenthunk($ids) [list $currentfile($ids) \
2792 $diffoldstart($ids) $diffnewstart($ids) \
2791 $diffoldstart($ids) $diffnewstart($ids) \
2793 $diffoldlno($ids) $diffnewlno($ids) \
2792 $diffoldlno($ids) $diffnewlno($ids) \
2794 $difflcounts($ids)]
2793 $difflcounts($ids)]
2795 set diffinhunk($ids) 0
2794 set diffinhunk($ids) 0
2796 # -1 = need to block, 0 = unblocked, 1 = is blocked
2795 # -1 = need to block, 0 = unblocked, 1 = is blocked
2797 set diffblocked($ids) -1
2796 set diffblocked($ids) -1
2798 processhunks
2797 processhunks
2799 if {$diffblocked($ids) == -1} {
2798 if {$diffblocked($ids) == -1} {
2800 fileevent $f readable {}
2799 fileevent $f readable {}
2801 set diffblocked($ids) 1
2800 set diffblocked($ids) 1
2802 }
2801 }
2803 }
2802 }
2804
2803
2805 if {$n < 0} {
2804 if {$n < 0} {
2806 # eof
2805 # eof
2807 if {!$diffblocked($ids)} {
2806 if {!$diffblocked($ids)} {
2808 close $f
2807 close $f
2809 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2808 set currentfile($ids) [llength $mergefilelist($diffmergeid)]
2810 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2809 set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
2811 processhunks
2810 processhunks
2812 }
2811 }
2813 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2812 } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
2814 # start of a new file
2813 # start of a new file
2815 set currentfile($ids) \
2814 set currentfile($ids) \
2816 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2815 [lsearch -exact $mergefilelist($diffmergeid) $fname]
2817 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2816 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
2818 $line match f1l f1c f2l f2c rest]} {
2817 $line match f1l f1c f2l f2c rest]} {
2819 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2818 if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
2820 # start of a new hunk
2819 # start of a new hunk
2821 if {$f1l == 0 && $f1c == 0} {
2820 if {$f1l == 0 && $f1c == 0} {
2822 set f1l 1
2821 set f1l 1
2823 }
2822 }
2824 if {$f2l == 0 && $f2c == 0} {
2823 if {$f2l == 0 && $f2c == 0} {
2825 set f2l 1
2824 set f2l 1
2826 }
2825 }
2827 set diffinhunk($ids) 1
2826 set diffinhunk($ids) 1
2828 set diffoldstart($ids) $f1l
2827 set diffoldstart($ids) $f1l
2829 set diffnewstart($ids) $f2l
2828 set diffnewstart($ids) $f2l
2830 set diffoldlno($ids) $f1l
2829 set diffoldlno($ids) $f1l
2831 set diffnewlno($ids) $f2l
2830 set diffnewlno($ids) $f2l
2832 set difflcounts($ids) {}
2831 set difflcounts($ids) {}
2833 set noldlines($ids) 0
2832 set noldlines($ids) 0
2834 set nnewlines($ids) 0
2833 set nnewlines($ids) 0
2835 }
2834 }
2836 }
2835 }
2837 }
2836 }
2838
2837
2839 proc processhunks {} {
2838 proc processhunks {} {
2840 global diffmergeid parents nparents currenthunk
2839 global diffmergeid parents nparents currenthunk
2841 global mergefilelist diffblocked mergefds
2840 global mergefilelist diffblocked mergefds
2842 global grouphunks grouplinestart grouplineend groupfilenum
2841 global grouphunks grouplinestart grouplineend groupfilenum
2843
2842
2844 set nfiles [llength $mergefilelist($diffmergeid)]
2843 set nfiles [llength $mergefilelist($diffmergeid)]
2845 while 1 {
2844 while 1 {
2846 set fi $nfiles
2845 set fi $nfiles
2847 set lno 0
2846 set lno 0
2848 # look for the earliest hunk
2847 # look for the earliest hunk
2849 foreach p $parents($diffmergeid) {
2848 foreach p $parents($diffmergeid) {
2850 set ids [list $diffmergeid $p]
2849 set ids [list $diffmergeid $p]
2851 if {![info exists currenthunk($ids)]} return
2850 if {![info exists currenthunk($ids)]} return
2852 set i [lindex $currenthunk($ids) 0]
2851 set i [lindex $currenthunk($ids) 0]
2853 set l [lindex $currenthunk($ids) 2]
2852 set l [lindex $currenthunk($ids) 2]
2854 if {$i < $fi || ($i == $fi && $l < $lno)} {
2853 if {$i < $fi || ($i == $fi && $l < $lno)} {
2855 set fi $i
2854 set fi $i
2856 set lno $l
2855 set lno $l
2857 set pi $p
2856 set pi $p
2858 }
2857 }
2859 }
2858 }
2860
2859
2861 if {$fi < $nfiles} {
2860 if {$fi < $nfiles} {
2862 set ids [list $diffmergeid $pi]
2861 set ids [list $diffmergeid $pi]
2863 set hunk $currenthunk($ids)
2862 set hunk $currenthunk($ids)
2864 unset currenthunk($ids)
2863 unset currenthunk($ids)
2865 if {$diffblocked($ids) > 0} {
2864 if {$diffblocked($ids) > 0} {
2866 fileevent $mergefds($ids) readable \
2865 fileevent $mergefds($ids) readable \
2867 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2866 [list getmergediffline $mergefds($ids) $ids $diffmergeid]
2868 }
2867 }
2869 set diffblocked($ids) 0
2868 set diffblocked($ids) 0
2870
2869
2871 if {[info exists groupfilenum] && $groupfilenum == $fi
2870 if {[info exists groupfilenum] && $groupfilenum == $fi
2872 && $lno <= $grouplineend} {
2871 && $lno <= $grouplineend} {
2873 # add this hunk to the pending group
2872 # add this hunk to the pending group
2874 lappend grouphunks($pi) $hunk
2873 lappend grouphunks($pi) $hunk
2875 set endln [lindex $hunk 4]
2874 set endln [lindex $hunk 4]
2876 if {$endln > $grouplineend} {
2875 if {$endln > $grouplineend} {
2877 set grouplineend $endln
2876 set grouplineend $endln
2878 }
2877 }
2879 continue
2878 continue
2880 }
2879 }
2881 }
2880 }
2882
2881
2883 # succeeding stuff doesn't belong in this group, so
2882 # succeeding stuff doesn't belong in this group, so
2884 # process the group now
2883 # process the group now
2885 if {[info exists groupfilenum]} {
2884 if {[info exists groupfilenum]} {
2886 processgroup
2885 processgroup
2887 unset groupfilenum
2886 unset groupfilenum
2888 unset grouphunks
2887 unset grouphunks
2889 }
2888 }
2890
2889
2891 if {$fi >= $nfiles} break
2890 if {$fi >= $nfiles} break
2892
2891
2893 # start a new group
2892 # start a new group
2894 set groupfilenum $fi
2893 set groupfilenum $fi
2895 set grouphunks($pi) [list $hunk]
2894 set grouphunks($pi) [list $hunk]
2896 set grouplinestart $lno
2895 set grouplinestart $lno
2897 set grouplineend [lindex $hunk 4]
2896 set grouplineend [lindex $hunk 4]
2898 }
2897 }
2899 }
2898 }
2900
2899
2901 proc processgroup {} {
2900 proc processgroup {} {
2902 global groupfilelast groupfilenum difffilestart
2901 global groupfilelast groupfilenum difffilestart
2903 global mergefilelist diffmergeid ctext filelines
2902 global mergefilelist diffmergeid ctext filelines
2904 global parents diffmergeid diffoffset
2903 global parents diffmergeid diffoffset
2905 global grouphunks grouplinestart grouplineend nparents
2904 global grouphunks grouplinestart grouplineend nparents
2906 global mergemax
2905 global mergemax
2907
2906
2908 $ctext conf -state normal
2907 $ctext conf -state normal
2909 set id $diffmergeid
2908 set id $diffmergeid
2910 set f $groupfilenum
2909 set f $groupfilenum
2911 if {$groupfilelast != $f} {
2910 if {$groupfilelast != $f} {
2912 $ctext insert end "\n"
2911 $ctext insert end "\n"
2913 set here [$ctext index "end - 1c"]
2912 set here [$ctext index "end - 1c"]
2914 set difffilestart($f) $here
2913 set difffilestart($f) $here
2915 set mark fmark.[expr {$f + 1}]
2914 set mark fmark.[expr {$f + 1}]
2916 $ctext mark set $mark $here
2915 $ctext mark set $mark $here
2917 $ctext mark gravity $mark left
2916 $ctext mark gravity $mark left
2918 set header [lindex $mergefilelist($id) $f]
2917 set header [lindex $mergefilelist($id) $f]
2919 set l [expr {(78 - [string length $header]) / 2}]
2918 set l [expr {(78 - [string length $header]) / 2}]
2920 set pad [string range "----------------------------------------" 1 $l]
2919 set pad [string range "----------------------------------------" 1 $l]
2921 $ctext insert end "$pad $header $pad\n" filesep
2920 $ctext insert end "$pad $header $pad\n" filesep
2922 set groupfilelast $f
2921 set groupfilelast $f
2923 foreach p $parents($id) {
2922 foreach p $parents($id) {
2924 set diffoffset($p) 0
2923 set diffoffset($p) 0
2925 }
2924 }
2926 }
2925 }
2927
2926
2928 $ctext insert end "@@" msep
2927 $ctext insert end "@@" msep
2929 set nlines [expr {$grouplineend - $grouplinestart}]
2928 set nlines [expr {$grouplineend - $grouplinestart}]
2930 set events {}
2929 set events {}
2931 set pnum 0
2930 set pnum 0
2932 foreach p $parents($id) {
2931 foreach p $parents($id) {
2933 set startline [expr {$grouplinestart + $diffoffset($p)}]
2932 set startline [expr {$grouplinestart + $diffoffset($p)}]
2934 set ol $startline
2933 set ol $startline
2935 set nl $grouplinestart
2934 set nl $grouplinestart
2936 if {[info exists grouphunks($p)]} {
2935 if {[info exists grouphunks($p)]} {
2937 foreach h $grouphunks($p) {
2936 foreach h $grouphunks($p) {
2938 set l [lindex $h 2]
2937 set l [lindex $h 2]
2939 if {$nl < $l} {
2938 if {$nl < $l} {
2940 for {} {$nl < $l} {incr nl} {
2939 for {} {$nl < $l} {incr nl} {
2941 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2940 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2942 incr ol
2941 incr ol
2943 }
2942 }
2944 }
2943 }
2945 foreach chunk [lindex $h 5] {
2944 foreach chunk [lindex $h 5] {
2946 if {[llength $chunk] == 2} {
2945 if {[llength $chunk] == 2} {
2947 set olc [lindex $chunk 0]
2946 set olc [lindex $chunk 0]
2948 set nlc [lindex $chunk 1]
2947 set nlc [lindex $chunk 1]
2949 set nnl [expr {$nl + $nlc}]
2948 set nnl [expr {$nl + $nlc}]
2950 lappend events [list $nl $nnl $pnum $olc $nlc]
2949 lappend events [list $nl $nnl $pnum $olc $nlc]
2951 incr ol $olc
2950 incr ol $olc
2952 set nl $nnl
2951 set nl $nnl
2953 } else {
2952 } else {
2954 incr ol [lindex $chunk 0]
2953 incr ol [lindex $chunk 0]
2955 incr nl [lindex $chunk 0]
2954 incr nl [lindex $chunk 0]
2956 }
2955 }
2957 }
2956 }
2958 }
2957 }
2959 }
2958 }
2960 if {$nl < $grouplineend} {
2959 if {$nl < $grouplineend} {
2961 for {} {$nl < $grouplineend} {incr nl} {
2960 for {} {$nl < $grouplineend} {incr nl} {
2962 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2961 set filelines($p,$f,$ol) $filelines($id,$f,$nl)
2963 incr ol
2962 incr ol
2964 }
2963 }
2965 }
2964 }
2966 set nlines [expr {$ol - $startline}]
2965 set nlines [expr {$ol - $startline}]
2967 $ctext insert end " -$startline,$nlines" msep
2966 $ctext insert end " -$startline,$nlines" msep
2968 incr pnum
2967 incr pnum
2969 }
2968 }
2970
2969
2971 set nlines [expr {$grouplineend - $grouplinestart}]
2970 set nlines [expr {$grouplineend - $grouplinestart}]
2972 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2971 $ctext insert end " +$grouplinestart,$nlines @@\n" msep
2973
2972
2974 set events [lsort -integer -index 0 $events]
2973 set events [lsort -integer -index 0 $events]
2975 set nevents [llength $events]
2974 set nevents [llength $events]
2976 set nmerge $nparents($diffmergeid)
2975 set nmerge $nparents($diffmergeid)
2977 set l $grouplinestart
2976 set l $grouplinestart
2978 for {set i 0} {$i < $nevents} {set i $j} {
2977 for {set i 0} {$i < $nevents} {set i $j} {
2979 set nl [lindex $events $i 0]
2978 set nl [lindex $events $i 0]
2980 while {$l < $nl} {
2979 while {$l < $nl} {
2981 $ctext insert end " $filelines($id,$f,$l)\n"
2980 $ctext insert end " $filelines($id,$f,$l)\n"
2982 incr l
2981 incr l
2983 }
2982 }
2984 set e [lindex $events $i]
2983 set e [lindex $events $i]
2985 set enl [lindex $e 1]
2984 set enl [lindex $e 1]
2986 set j $i
2985 set j $i
2987 set active {}
2986 set active {}
2988 while 1 {
2987 while 1 {
2989 set pnum [lindex $e 2]
2988 set pnum [lindex $e 2]
2990 set olc [lindex $e 3]
2989 set olc [lindex $e 3]
2991 set nlc [lindex $e 4]
2990 set nlc [lindex $e 4]
2992 if {![info exists delta($pnum)]} {
2991 if {![info exists delta($pnum)]} {
2993 set delta($pnum) [expr {$olc - $nlc}]
2992 set delta($pnum) [expr {$olc - $nlc}]
2994 lappend active $pnum
2993 lappend active $pnum
2995 } else {
2994 } else {
2996 incr delta($pnum) [expr {$olc - $nlc}]
2995 incr delta($pnum) [expr {$olc - $nlc}]
2997 }
2996 }
2998 if {[incr j] >= $nevents} break
2997 if {[incr j] >= $nevents} break
2999 set e [lindex $events $j]
2998 set e [lindex $events $j]
3000 if {[lindex $e 0] >= $enl} break
2999 if {[lindex $e 0] >= $enl} break
3001 if {[lindex $e 1] > $enl} {
3000 if {[lindex $e 1] > $enl} {
3002 set enl [lindex $e 1]
3001 set enl [lindex $e 1]
3003 }
3002 }
3004 }
3003 }
3005 set nlc [expr {$enl - $l}]
3004 set nlc [expr {$enl - $l}]
3006 set ncol mresult
3005 set ncol mresult
3007 set bestpn -1
3006 set bestpn -1
3008 if {[llength $active] == $nmerge - 1} {
3007 if {[llength $active] == $nmerge - 1} {
3009 # no diff for one of the parents, i.e. it's identical
3008 # no diff for one of the parents, i.e. it's identical
3010 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
3009 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
3011 if {![info exists delta($pnum)]} {
3010 if {![info exists delta($pnum)]} {
3012 if {$pnum < $mergemax} {
3011 if {$pnum < $mergemax} {
3013 lappend ncol m$pnum
3012 lappend ncol m$pnum
3014 } else {
3013 } else {
3015 lappend ncol mmax
3014 lappend ncol mmax
3016 }
3015 }
3017 break
3016 break
3018 }
3017 }
3019 }
3018 }
3020 } elseif {[llength $active] == $nmerge} {
3019 } elseif {[llength $active] == $nmerge} {
3021 # all parents are different, see if one is very similar
3020 # all parents are different, see if one is very similar
3022 set bestsim 30
3021 set bestsim 30
3023 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
3022 for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
3024 set sim [similarity $pnum $l $nlc $f \
3023 set sim [similarity $pnum $l $nlc $f \
3025 [lrange $events $i [expr {$j-1}]]]
3024 [lrange $events $i [expr {$j-1}]]]
3026 if {$sim > $bestsim} {
3025 if {$sim > $bestsim} {
3027 set bestsim $sim
3026 set bestsim $sim
3028 set bestpn $pnum
3027 set bestpn $pnum
3029 }
3028 }
3030 }
3029 }
3031 if {$bestpn >= 0} {
3030 if {$bestpn >= 0} {
3032 lappend ncol m$bestpn
3031 lappend ncol m$bestpn
3033 }
3032 }
3034 }
3033 }
3035 set pnum -1
3034 set pnum -1
3036 foreach p $parents($id) {
3035 foreach p $parents($id) {
3037 incr pnum
3036 incr pnum
3038 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
3037 if {![info exists delta($pnum)] || $pnum == $bestpn} continue
3039 set olc [expr {$nlc + $delta($pnum)}]
3038 set olc [expr {$nlc + $delta($pnum)}]
3040 set ol [expr {$l + $diffoffset($p)}]
3039 set ol [expr {$l + $diffoffset($p)}]
3041 incr diffoffset($p) $delta($pnum)
3040 incr diffoffset($p) $delta($pnum)
3042 unset delta($pnum)
3041 unset delta($pnum)
3043 for {} {$olc > 0} {incr olc -1} {
3042 for {} {$olc > 0} {incr olc -1} {
3044 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
3043 $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
3045 incr ol
3044 incr ol
3046 }
3045 }
3047 }
3046 }
3048 set endl [expr {$l + $nlc}]
3047 set endl [expr {$l + $nlc}]
3049 if {$bestpn >= 0} {
3048 if {$bestpn >= 0} {
3050 # show this pretty much as a normal diff
3049 # show this pretty much as a normal diff
3051 set p [lindex $parents($id) $bestpn]
3050 set p [lindex $parents($id) $bestpn]
3052 set ol [expr {$l + $diffoffset($p)}]
3051 set ol [expr {$l + $diffoffset($p)}]
3053 incr diffoffset($p) $delta($bestpn)
3052 incr diffoffset($p) $delta($bestpn)
3054 unset delta($bestpn)
3053 unset delta($bestpn)
3055 for {set k $i} {$k < $j} {incr k} {
3054 for {set k $i} {$k < $j} {incr k} {
3056 set e [lindex $events $k]
3055 set e [lindex $events $k]
3057 if {[lindex $e 2] != $bestpn} continue
3056 if {[lindex $e 2] != $bestpn} continue
3058 set nl [lindex $e 0]
3057 set nl [lindex $e 0]
3059 set ol [expr {$ol + $nl - $l}]
3058 set ol [expr {$ol + $nl - $l}]
3060 for {} {$l < $nl} {incr l} {
3059 for {} {$l < $nl} {incr l} {
3061 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
3060 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
3062 }
3061 }
3063 set c [lindex $e 3]
3062 set c [lindex $e 3]
3064 for {} {$c > 0} {incr c -1} {
3063 for {} {$c > 0} {incr c -1} {
3065 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
3064 $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn
3066 incr ol
3065 incr ol
3067 }
3066 }
3068 set nl [lindex $e 1]
3067 set nl [lindex $e 1]
3069 for {} {$l < $nl} {incr l} {
3068 for {} {$l < $nl} {incr l} {
3070 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
3069 $ctext insert end "+$filelines($id,$f,$l)\n" mresult
3071 }
3070 }
3072 }
3071 }
3073 }
3072 }
3074 for {} {$l < $endl} {incr l} {
3073 for {} {$l < $endl} {incr l} {
3075 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
3074 $ctext insert end "+$filelines($id,$f,$l)\n" $ncol
3076 }
3075 }
3077 }
3076 }
3078 while {$l < $grouplineend} {
3077 while {$l < $grouplineend} {
3079 $ctext insert end " $filelines($id,$f,$l)\n"
3078 $ctext insert end " $filelines($id,$f,$l)\n"
3080 incr l
3079 incr l
3081 }
3080 }
3082 $ctext conf -state disabled
3081 $ctext conf -state disabled
3083 }
3082 }
3084
3083
3085 proc similarity {pnum l nlc f events} {
3084 proc similarity {pnum l nlc f events} {
3086 global diffmergeid parents diffoffset filelines
3085 global diffmergeid parents diffoffset filelines
3087
3086
3088 set id $diffmergeid
3087 set id $diffmergeid
3089 set p [lindex $parents($id) $pnum]
3088 set p [lindex $parents($id) $pnum]
3090 set ol [expr {$l + $diffoffset($p)}]
3089 set ol [expr {$l + $diffoffset($p)}]
3091 set endl [expr {$l + $nlc}]
3090 set endl [expr {$l + $nlc}]
3092 set same 0
3091 set same 0
3093 set diff 0
3092 set diff 0
3094 foreach e $events {
3093 foreach e $events {
3095 if {[lindex $e 2] != $pnum} continue
3094 if {[lindex $e 2] != $pnum} continue
3096 set nl [lindex $e 0]
3095 set nl [lindex $e 0]
3097 set ol [expr {$ol + $nl - $l}]
3096 set ol [expr {$ol + $nl - $l}]
3098 for {} {$l < $nl} {incr l} {
3097 for {} {$l < $nl} {incr l} {
3099 incr same [string length $filelines($id,$f,$l)]
3098 incr same [string length $filelines($id,$f,$l)]
3100 incr same
3099 incr same
3101 }
3100 }
3102 set oc [lindex $e 3]
3101 set oc [lindex $e 3]
3103 for {} {$oc > 0} {incr oc -1} {
3102 for {} {$oc > 0} {incr oc -1} {
3104 incr diff [string length $filelines($p,$f,$ol)]
3103 incr diff [string length $filelines($p,$f,$ol)]
3105 incr diff
3104 incr diff
3106 incr ol
3105 incr ol
3107 }
3106 }
3108 set nl [lindex $e 1]
3107 set nl [lindex $e 1]
3109 for {} {$l < $nl} {incr l} {
3108 for {} {$l < $nl} {incr l} {
3110 incr diff [string length $filelines($id,$f,$l)]
3109 incr diff [string length $filelines($id,$f,$l)]
3111 incr diff
3110 incr diff
3112 }
3111 }
3113 }
3112 }
3114 for {} {$l < $endl} {incr l} {
3113 for {} {$l < $endl} {incr l} {
3115 incr same [string length $filelines($id,$f,$l)]
3114 incr same [string length $filelines($id,$f,$l)]
3116 incr same
3115 incr same
3117 }
3116 }
3118 if {$same == 0} {
3117 if {$same == 0} {
3119 return 0
3118 return 0
3120 }
3119 }
3121 return [expr {200 * $same / (2 * $same + $diff)}]
3120 return [expr {200 * $same / (2 * $same + $diff)}]
3122 }
3121 }
3123
3122
3124 proc startdiff {ids} {
3123 proc startdiff {ids} {
3125 global treediffs diffids treepending diffmergeid
3124 global treediffs diffids treepending diffmergeid
3126
3125
3127 set diffids $ids
3126 set diffids $ids
3128 catch {unset diffmergeid}
3127 catch {unset diffmergeid}
3129 if {![info exists treediffs($ids)]} {
3128 if {![info exists treediffs($ids)]} {
3130 if {![info exists treepending]} {
3129 if {![info exists treepending]} {
3131 gettreediffs $ids
3130 gettreediffs $ids
3132 }
3131 }
3133 } else {
3132 } else {
3134 addtocflist $ids
3133 addtocflist $ids
3135 }
3134 }
3136 }
3135 }
3137
3136
3138 proc addtocflist {ids} {
3137 proc addtocflist {ids} {
3139 global treediffs cflist
3138 global treediffs cflist
3140 foreach f $treediffs($ids) {
3139 foreach f $treediffs($ids) {
3141 $cflist insert end $f
3140 $cflist insert end $f
3142 }
3141 }
3143 getblobdiffs $ids
3142 getblobdiffs $ids
3144 }
3143 }
3145
3144
3146 proc gettreediffs {ids} {
3145 proc gettreediffs {ids} {
3147 global treediff parents treepending env
3146 global treediff parents treepending env
3148 set treepending $ids
3147 set treepending $ids
3149 set treediff {}
3148 set treediff {}
3150 set id [lindex $ids 0]
3149 set id [lindex $ids 0]
3151 set p [lindex $ids 1]
3150 set p [lindex $ids 1]
3152 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
3151 if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return
3153 fconfigure $gdtf -blocking 0
3152 fconfigure $gdtf -blocking 0
3154 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
3153 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
3155 }
3154 }
3156
3155
3157 proc gettreediffline {gdtf ids} {
3156 proc gettreediffline {gdtf ids} {
3158 global treediff treediffs treepending diffids diffmergeid
3157 global treediff treediffs treepending diffids diffmergeid
3159
3158
3160 set n [gets $gdtf line]
3159 set n [gets $gdtf line]
3161 if {$n < 0} {
3160 if {$n < 0} {
3162 if {![eof $gdtf]} return
3161 if {![eof $gdtf]} return
3163 close $gdtf
3162 close $gdtf
3164 set treediffs($ids) $treediff
3163 set treediffs($ids) $treediff
3165 unset treepending
3164 unset treepending
3166 if {$ids != $diffids} {
3165 if {$ids != $diffids} {
3167 gettreediffs $diffids
3166 gettreediffs $diffids
3168 } else {
3167 } else {
3169 if {[info exists diffmergeid]} {
3168 if {[info exists diffmergeid]} {
3170 contmergediff $ids
3169 contmergediff $ids
3171 } else {
3170 } else {
3172 addtocflist $ids
3171 addtocflist $ids
3173 }
3172 }
3174 }
3173 }
3175 return
3174 return
3176 }
3175 }
3177 set tab1 [expr [string first "\t" $line] + 1]
3176 set tab1 [expr [string first "\t" $line] + 1]
3178 set tab2 [expr [string first "\t" $line $tab1] - 1]
3177 set tab2 [expr [string first "\t" $line $tab1] - 1]
3179 set file [string range $line $tab1 $tab2]
3178 set file [string range $line $tab1 $tab2]
3180 lappend treediff $file
3179 lappend treediff $file
3181 }
3180 }
3182
3181
3183 proc getblobdiffs {ids} {
3182 proc getblobdiffs {ids} {
3184 global diffopts blobdifffd diffids env curdifftag curtagstart
3183 global diffopts blobdifffd diffids env curdifftag curtagstart
3185 global difffilestart nextupdate diffinhdr treediffs
3184 global difffilestart nextupdate diffinhdr treediffs
3186
3185
3187 set id [lindex $ids 0]
3186 set id [lindex $ids 0]
3188 set p [lindex $ids 1]
3187 set p [lindex $ids 1]
3189 set env(GIT_DIFF_OPTS) $diffopts
3188 set env(GIT_DIFF_OPTS) $diffopts
3190 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
3189 set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id]
3191 if {[catch {set bdf [open $cmd r]} err]} {
3190 if {[catch {set bdf [open $cmd r]} err]} {
3192 puts "error getting diffs: $err"
3191 puts "error getting diffs: $err"
3193 return
3192 return
3194 }
3193 }
3195 set diffinhdr 0
3194 set diffinhdr 0
3196 fconfigure $bdf -blocking 0
3195 fconfigure $bdf -blocking 0
3197 set blobdifffd($ids) $bdf
3196 set blobdifffd($ids) $bdf
3198 set curdifftag Comments
3197 set curdifftag Comments
3199 set curtagstart 0.0
3198 set curtagstart 0.0
3200 catch {unset difffilestart}
3199 catch {unset difffilestart}
3201 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
3200 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
3202 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
3201 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
3203 }
3202 }
3204
3203
3205 proc getblobdiffline {bdf ids} {
3204 proc getblobdiffline {bdf ids} {
3206 global diffids blobdifffd ctext curdifftag curtagstart
3205 global diffids blobdifffd ctext curdifftag curtagstart
3207 global diffnexthead diffnextnote difffilestart
3206 global diffnexthead diffnextnote difffilestart
3208 global nextupdate diffinhdr treediffs
3207 global nextupdate diffinhdr treediffs
3209 global gaudydiff
3208 global gaudydiff
3210
3209
3211 set n [gets $bdf line]
3210 set n [gets $bdf line]
3212 if {$n < 0} {
3211 if {$n < 0} {
3213 if {[eof $bdf]} {
3212 if {[eof $bdf]} {
3214 close $bdf
3213 close $bdf
3215 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
3214 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
3216 $ctext tag add $curdifftag $curtagstart end
3215 $ctext tag add $curdifftag $curtagstart end
3217 }
3216 }
3218 }
3217 }
3219 return
3218 return
3220 }
3219 }
3221 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
3220 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
3222 return
3221 return
3223 }
3222 }
3224 regsub -all "\r" $line "" line
3223 regsub -all "\r" $line "" line
3225 $ctext conf -state normal
3224 $ctext conf -state normal
3226 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
3225 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
3227 # start of a new file
3226 # start of a new file
3228 $ctext insert end "\n"
3227 $ctext insert end "\n"
3229 $ctext tag add $curdifftag $curtagstart end
3228 $ctext tag add $curdifftag $curtagstart end
3230 set curtagstart [$ctext index "end - 1c"]
3229 set curtagstart [$ctext index "end - 1c"]
3231 set header $newname
3230 set header $newname
3232 set here [$ctext index "end - 1c"]
3231 set here [$ctext index "end - 1c"]
3233 set i [lsearch -exact $treediffs($diffids) $fname]
3232 set i [lsearch -exact $treediffs($diffids) $fname]
3234 if {$i >= 0} {
3233 if {$i >= 0} {
3235 set difffilestart($i) $here
3234 set difffilestart($i) $here
3236 incr i
3235 incr i
3237 $ctext mark set fmark.$i $here
3236 $ctext mark set fmark.$i $here
3238 $ctext mark gravity fmark.$i left
3237 $ctext mark gravity fmark.$i left
3239 }
3238 }
3240 if {$newname != $fname} {
3239 if {$newname != $fname} {
3241 set i [lsearch -exact $treediffs($diffids) $newname]
3240 set i [lsearch -exact $treediffs($diffids) $newname]
3242 if {$i >= 0} {
3241 if {$i >= 0} {
3243 set difffilestart($i) $here
3242 set difffilestart($i) $here
3244 incr i
3243 incr i
3245 $ctext mark set fmark.$i $here
3244 $ctext mark set fmark.$i $here
3246 $ctext mark gravity fmark.$i left
3245 $ctext mark gravity fmark.$i left
3247 }
3246 }
3248 }
3247 }
3249 set curdifftag "f:$fname"
3248 set curdifftag "f:$fname"
3250 $ctext tag delete $curdifftag
3249 $ctext tag delete $curdifftag
3251 set l [expr {(78 - [string length $header]) / 2}]
3250 set l [expr {(78 - [string length $header]) / 2}]
3252 set pad [string range "----------------------------------------" 1 $l]
3251 set pad [string range "----------------------------------------" 1 $l]
3253 $ctext insert end "$pad $header $pad\n" filesep
3252 $ctext insert end "$pad $header $pad\n" filesep
3254 set diffinhdr 1
3253 set diffinhdr 1
3255 } elseif {[regexp {^(---|\+\+\+) } $line] && $diffinhdr} {
3254 } elseif {[regexp {^(---|\+\+\+) } $line] && $diffinhdr} {
3256 set diffinhdr 1
3255 set diffinhdr 1
3257 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
3256 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
3258 $line match f1l f1c f2l f2c rest]} {
3257 $line match f1l f1c f2l f2c rest]} {
3259 if {$gaudydiff} {
3258 if {$gaudydiff} {
3260 $ctext insert end "\t" hunksep
3259 $ctext insert end "\t" hunksep
3261 $ctext insert end " $f1l " d0 " $f2l " d1
3260 $ctext insert end " $f1l " d0 " $f2l " d1
3262 $ctext insert end " $rest \n" hunksep
3261 $ctext insert end " $rest \n" hunksep
3263 } else {
3262 } else {
3264 $ctext insert end "$line\n" hunksep
3263 $ctext insert end "$line\n" hunksep
3265 }
3264 }
3266 set diffinhdr 0
3265 set diffinhdr 0
3267 } else {
3266 } else {
3268 set x [string range $line 0 0]
3267 set x [string range $line 0 0]
3269 if {$x == "-" || $x == "+"} {
3268 if {$x == "-" || $x == "+"} {
3270 set tag [expr {$x == "+"}]
3269 set tag [expr {$x == "+"}]
3271 if {$gaudydiff} {
3270 if {$gaudydiff} {
3272 set line [string range $line 1 end]
3271 set line [string range $line 1 end]
3273 }
3272 }
3274 $ctext insert end "$line\n" d$tag
3273 $ctext insert end "$line\n" d$tag
3275 } elseif {$x == " "} {
3274 } elseif {$x == " "} {
3276 if {$gaudydiff} {
3275 if {$gaudydiff} {
3277 set line [string range $line 1 end]
3276 set line [string range $line 1 end]
3278 }
3277 }
3279 $ctext insert end "$line\n"
3278 $ctext insert end "$line\n"
3280 } elseif {$diffinhdr || $x == "\\"} {
3279 } elseif {$diffinhdr || $x == "\\"} {
3281 # e.g. "\ No newline at end of file"
3280 # e.g. "\ No newline at end of file"
3282 $ctext insert end "$line\n" filesep
3281 $ctext insert end "$line\n" filesep
3283 } elseif {$line != ""} {
3282 } elseif {$line != ""} {
3284 # Something else we don't recognize
3283 # Something else we don't recognize
3285 if {$curdifftag != "Comments"} {
3284 if {$curdifftag != "Comments"} {
3286 $ctext insert end "\n"
3285 $ctext insert end "\n"
3287 $ctext tag add $curdifftag $curtagstart end
3286 $ctext tag add $curdifftag $curtagstart end
3288 set curtagstart [$ctext index "end - 1c"]
3287 set curtagstart [$ctext index "end - 1c"]
3289 set curdifftag Comments
3288 set curdifftag Comments
3290 }
3289 }
3291 $ctext insert end "$line\n" filesep
3290 $ctext insert end "$line\n" filesep
3292 }
3291 }
3293 }
3292 }
3294 $ctext conf -state disabled
3293 $ctext conf -state disabled
3295 if {[clock clicks -milliseconds] >= $nextupdate} {
3294 if {[clock clicks -milliseconds] >= $nextupdate} {
3296 incr nextupdate 100
3295 incr nextupdate 100
3297 fileevent $bdf readable {}
3296 fileevent $bdf readable {}
3298 update
3297 update
3299 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3298 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
3300 }
3299 }
3301 }
3300 }
3302
3301
3303 proc nextfile {} {
3302 proc nextfile {} {
3304 global difffilestart ctext
3303 global difffilestart ctext
3305 set here [$ctext index @0,0]
3304 set here [$ctext index @0,0]
3306 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3305 for {set i 0} {[info exists difffilestart($i)]} {incr i} {
3307 if {[$ctext compare $difffilestart($i) > $here]} {
3306 if {[$ctext compare $difffilestart($i) > $here]} {
3308 if {![info exists pos]
3307 if {![info exists pos]
3309 || [$ctext compare $difffilestart($i) < $pos]} {
3308 || [$ctext compare $difffilestart($i) < $pos]} {
3310 set pos $difffilestart($i)
3309 set pos $difffilestart($i)
3311 }
3310 }
3312 }
3311 }
3313 }
3312 }
3314 if {[info exists pos]} {
3313 if {[info exists pos]} {
3315 $ctext yview $pos
3314 $ctext yview $pos
3316 }
3315 }
3317 }
3316 }
3318
3317
3319 proc listboxsel {} {
3318 proc listboxsel {} {
3320 global ctext cflist currentid
3319 global ctext cflist currentid
3321 if {![info exists currentid]} return
3320 if {![info exists currentid]} return
3322 set sel [lsort [$cflist curselection]]
3321 set sel [lsort [$cflist curselection]]
3323 if {$sel eq {}} return
3322 if {$sel eq {}} return
3324 set first [lindex $sel 0]
3323 set first [lindex $sel 0]
3325 catch {$ctext yview fmark.$first}
3324 catch {$ctext yview fmark.$first}
3326 }
3325 }
3327
3326
3328 proc setcoords {} {
3327 proc setcoords {} {
3329 global linespc charspc canvx0 canvy0 mainfont
3328 global linespc charspc canvx0 canvy0 mainfont
3330 global xspc1 xspc2 lthickness
3329 global xspc1 xspc2 lthickness
3331
3330
3332 set linespc [font metrics $mainfont -linespace]
3331 set linespc [font metrics $mainfont -linespace]
3333 set charspc [font measure $mainfont "m"]
3332 set charspc [font measure $mainfont "m"]
3334 set canvy0 [expr 3 + 0.5 * $linespc]
3333 set canvy0 [expr 3 + 0.5 * $linespc]
3335 set canvx0 [expr 3 + 0.5 * $linespc]
3334 set canvx0 [expr 3 + 0.5 * $linespc]
3336 set lthickness [expr {int($linespc / 9) + 1}]
3335 set lthickness [expr {int($linespc / 9) + 1}]
3337 set xspc1(0) $linespc
3336 set xspc1(0) $linespc
3338 set xspc2 $linespc
3337 set xspc2 $linespc
3339 }
3338 }
3340
3339
3341 proc redisplay {} {
3340 proc redisplay {} {
3342 global stopped redisplaying phase
3341 global stopped redisplaying phase
3343 if {$stopped > 1} return
3342 if {$stopped > 1} return
3344 if {$phase == "getcommits"} return
3343 if {$phase == "getcommits"} return
3345 set redisplaying 1
3344 set redisplaying 1
3346 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3345 if {$phase == "drawgraph" || $phase == "incrdraw"} {
3347 set stopped 1
3346 set stopped 1
3348 } else {
3347 } else {
3349 drawgraph
3348 drawgraph
3350 }
3349 }
3351 }
3350 }
3352
3351
3353 proc incrfont {inc} {
3352 proc incrfont {inc} {
3354 global mainfont namefont textfont ctext canv phase
3353 global mainfont namefont textfont ctext canv phase
3355 global stopped entries curidfont
3354 global stopped entries curidfont
3356 unmarkmatches
3355 unmarkmatches
3357 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3356 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
3358 set curidfont [lreplace $curidfont 1 1 [expr {[lindex $curidfont 1] + $inc}]]
3357 set curidfont [lreplace $curidfont 1 1 [expr {[lindex $curidfont 1] + $inc}]]
3359 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3358 set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
3360 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3359 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
3361 setcoords
3360 setcoords
3362 $ctext conf -font $textfont
3361 $ctext conf -font $textfont
3363 $ctext tag conf filesep -font [concat $textfont bold]
3362 $ctext tag conf filesep -font [concat $textfont bold]
3364 foreach e $entries {
3363 foreach e $entries {
3365 $e conf -font $mainfont
3364 $e conf -font $mainfont
3366 }
3365 }
3367 if {$phase == "getcommits"} {
3366 if {$phase == "getcommits"} {
3368 $canv itemconf textitems -font $mainfont
3367 $canv itemconf textitems -font $mainfont
3369 }
3368 }
3370 redisplay
3369 redisplay
3371 }
3370 }
3372
3371
3373 proc clearsha1 {} {
3372 proc clearsha1 {} {
3374 global sha1entry sha1string
3373 global sha1entry sha1string
3375 if {[string length $sha1string] == 40} {
3374 if {[string length $sha1string] == 40} {
3376 $sha1entry delete 0 end
3375 $sha1entry delete 0 end
3377 }
3376 }
3378 }
3377 }
3379
3378
3380 proc sha1change {n1 n2 op} {
3379 proc sha1change {n1 n2 op} {
3381 global sha1string currentid sha1but
3380 global sha1string currentid sha1but
3382 if {$sha1string == {}
3381 if {$sha1string == {}
3383 || ([info exists currentid] && $sha1string == $currentid)} {
3382 || ([info exists currentid] && $sha1string == $currentid)} {
3384 set state disabled
3383 set state disabled
3385 } else {
3384 } else {
3386 set state normal
3385 set state normal
3387 }
3386 }
3388 if {[$sha1but cget -state] == $state} return
3387 if {[$sha1but cget -state] == $state} return
3389 if {$state == "normal"} {
3388 if {$state == "normal"} {
3390 $sha1but conf -state normal -relief raised -text "Goto: "
3389 $sha1but conf -state normal -relief raised -text "Goto: "
3391 } else {
3390 } else {
3392 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3391 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
3393 }
3392 }
3394 }
3393 }
3395
3394
3396 proc gotocommit {} {
3395 proc gotocommit {} {
3397 global sha1string currentid idline tagids
3396 global sha1string currentid idline tagids
3398 global lineid numcommits
3397 global lineid numcommits
3399
3398
3400 if {$sha1string == {}
3399 if {$sha1string == {}
3401 || ([info exists currentid] && $sha1string == $currentid)} return
3400 || ([info exists currentid] && $sha1string == $currentid)} return
3402 if {[info exists tagids($sha1string)]} {
3401 if {[info exists tagids($sha1string)]} {
3403 set id $tagids($sha1string)
3402 set id $tagids($sha1string)
3404 } else {
3403 } else {
3405 set id [string tolower $sha1string]
3404 set id [string tolower $sha1string]
3406 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3405 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
3407 set matches {}
3406 set matches {}
3408 for {set l 0} {$l < $numcommits} {incr l} {
3407 for {set l 0} {$l < $numcommits} {incr l} {
3409 if {[string match $id* $lineid($l)]} {
3408 if {[string match $id* $lineid($l)]} {
3410 lappend matches $lineid($l)
3409 lappend matches $lineid($l)
3411 }
3410 }
3412 }
3411 }
3413 if {$matches ne {}} {
3412 if {$matches ne {}} {
3414 if {[llength $matches] > 1} {
3413 if {[llength $matches] > 1} {
3415 error_popup "Short SHA1 id $id is ambiguous"
3414 error_popup "Short SHA1 id $id is ambiguous"
3416 return
3415 return
3417 }
3416 }
3418 set id [lindex $matches 0]
3417 set id [lindex $matches 0]
3419 }
3418 }
3420 }
3419 }
3421 }
3420 }
3422 if {[info exists idline($id)]} {
3421 if {[info exists idline($id)]} {
3423 selectline $idline($id) 1
3422 selectline $idline($id) 1
3424 return
3423 return
3425 }
3424 }
3426 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3425 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
3427 set type "SHA1 id"
3426 set type "SHA1 id"
3428 } else {
3427 } else {
3429 set type "Tag"
3428 set type "Tag"
3430 }
3429 }
3431 error_popup "$type $sha1string is not known"
3430 error_popup "$type $sha1string is not known"
3432 }
3431 }
3433
3432
3434 proc lineenter {x y id} {
3433 proc lineenter {x y id} {
3435 global hoverx hovery hoverid hovertimer
3434 global hoverx hovery hoverid hovertimer
3436 global commitinfo canv
3435 global commitinfo canv
3437
3436
3438 if {![info exists commitinfo($id)]} return
3437 if {![info exists commitinfo($id)]} return
3439 set hoverx $x
3438 set hoverx $x
3440 set hovery $y
3439 set hovery $y
3441 set hoverid $id
3440 set hoverid $id
3442 if {[info exists hovertimer]} {
3441 if {[info exists hovertimer]} {
3443 after cancel $hovertimer
3442 after cancel $hovertimer
3444 }
3443 }
3445 set hovertimer [after 500 linehover]
3444 set hovertimer [after 500 linehover]
3446 $canv delete hover
3445 $canv delete hover
3447 }
3446 }
3448
3447
3449 proc linemotion {x y id} {
3448 proc linemotion {x y id} {
3450 global hoverx hovery hoverid hovertimer
3449 global hoverx hovery hoverid hovertimer
3451
3450
3452 if {[info exists hoverid] && $id == $hoverid} {
3451 if {[info exists hoverid] && $id == $hoverid} {
3453 set hoverx $x
3452 set hoverx $x
3454 set hovery $y
3453 set hovery $y
3455 if {[info exists hovertimer]} {
3454 if {[info exists hovertimer]} {
3456 after cancel $hovertimer
3455 after cancel $hovertimer
3457 }
3456 }
3458 set hovertimer [after 500 linehover]
3457 set hovertimer [after 500 linehover]
3459 }
3458 }
3460 }
3459 }
3461
3460
3462 proc lineleave {id} {
3461 proc lineleave {id} {
3463 global hoverid hovertimer canv
3462 global hoverid hovertimer canv
3464
3463
3465 if {[info exists hoverid] && $id == $hoverid} {
3464 if {[info exists hoverid] && $id == $hoverid} {
3466 $canv delete hover
3465 $canv delete hover
3467 if {[info exists hovertimer]} {
3466 if {[info exists hovertimer]} {
3468 after cancel $hovertimer
3467 after cancel $hovertimer
3469 unset hovertimer
3468 unset hovertimer
3470 }
3469 }
3471 unset hoverid
3470 unset hoverid
3472 }
3471 }
3473 }
3472 }
3474
3473
3475 proc linehover {} {
3474 proc linehover {} {
3476 global hoverx hovery hoverid hovertimer
3475 global hoverx hovery hoverid hovertimer
3477 global canv linespc lthickness
3476 global canv linespc lthickness
3478 global commitinfo mainfont
3477 global commitinfo mainfont
3479
3478
3480 set text [lindex $commitinfo($hoverid) 0]
3479 set text [lindex $commitinfo($hoverid) 0]
3481 set ymax [lindex [$canv cget -scrollregion] 3]
3480 set ymax [lindex [$canv cget -scrollregion] 3]
3482 if {$ymax == {}} return
3481 if {$ymax == {}} return
3483 set yfrac [lindex [$canv yview] 0]
3482 set yfrac [lindex [$canv yview] 0]
3484 set x [expr {$hoverx + 2 * $linespc}]
3483 set x [expr {$hoverx + 2 * $linespc}]
3485 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3484 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
3486 set x0 [expr {$x - 2 * $lthickness}]
3485 set x0 [expr {$x - 2 * $lthickness}]
3487 set y0 [expr {$y - 2 * $lthickness}]
3486 set y0 [expr {$y - 2 * $lthickness}]
3488 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3487 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
3489 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3488 set y1 [expr {$y + $linespc + 2 * $lthickness}]
3490 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3489 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
3491 -fill \#ffff80 -outline black -width 1 -tags hover]
3490 -fill \#ffff80 -outline black -width 1 -tags hover]
3492 $canv raise $t
3491 $canv raise $t
3493 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3492 set t [$canv create text $x $y -anchor nw -text $text -tags hover]
3494 $canv raise $t
3493 $canv raise $t
3495 }
3494 }
3496
3495
3497 proc clickisonarrow {id y} {
3496 proc clickisonarrow {id y} {
3498 global mainline mainlinearrow sidelines lthickness
3497 global mainline mainlinearrow sidelines lthickness
3499
3498
3500 set thresh [expr {2 * $lthickness + 6}]
3499 set thresh [expr {2 * $lthickness + 6}]
3501 if {[info exists mainline($id)]} {
3500 if {[info exists mainline($id)]} {
3502 if {$mainlinearrow($id) ne "none"} {
3501 if {$mainlinearrow($id) ne "none"} {
3503 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3502 if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
3504 return "up"
3503 return "up"
3505 }
3504 }
3506 }
3505 }
3507 }
3506 }
3508 if {[info exists sidelines($id)]} {
3507 if {[info exists sidelines($id)]} {
3509 foreach ls $sidelines($id) {
3508 foreach ls $sidelines($id) {
3510 set coords [lindex $ls 0]
3509 set coords [lindex $ls 0]
3511 set arrow [lindex $ls 2]
3510 set arrow [lindex $ls 2]
3512 if {$arrow eq "first" || $arrow eq "both"} {
3511 if {$arrow eq "first" || $arrow eq "both"} {
3513 if {abs([lindex $coords 1] - $y) < $thresh} {
3512 if {abs([lindex $coords 1] - $y) < $thresh} {
3514 return "up"
3513 return "up"
3515 }
3514 }
3516 }
3515 }
3517 if {$arrow eq "last" || $arrow eq "both"} {
3516 if {$arrow eq "last" || $arrow eq "both"} {
3518 if {abs([lindex $coords end] - $y) < $thresh} {
3517 if {abs([lindex $coords end] - $y) < $thresh} {
3519 return "down"
3518 return "down"
3520 }
3519 }
3521 }
3520 }
3522 }
3521 }
3523 }
3522 }
3524 return {}
3523 return {}
3525 }
3524 }
3526
3525
3527 proc arrowjump {id dirn y} {
3526 proc arrowjump {id dirn y} {
3528 global mainline sidelines canv
3527 global mainline sidelines canv
3529
3528
3530 set yt {}
3529 set yt {}
3531 if {$dirn eq "down"} {
3530 if {$dirn eq "down"} {
3532 if {[info exists mainline($id)]} {
3531 if {[info exists mainline($id)]} {
3533 set y1 [lindex $mainline($id) 1]
3532 set y1 [lindex $mainline($id) 1]
3534 if {$y1 > $y} {
3533 if {$y1 > $y} {
3535 set yt $y1
3534 set yt $y1
3536 }
3535 }
3537 }
3536 }
3538 if {[info exists sidelines($id)]} {
3537 if {[info exists sidelines($id)]} {
3539 foreach ls $sidelines($id) {
3538 foreach ls $sidelines($id) {
3540 set y1 [lindex $ls 0 1]
3539 set y1 [lindex $ls 0 1]
3541 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3540 if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
3542 set yt $y1
3541 set yt $y1
3543 }
3542 }
3544 }
3543 }
3545 }
3544 }
3546 } else {
3545 } else {
3547 if {[info exists sidelines($id)]} {
3546 if {[info exists sidelines($id)]} {
3548 foreach ls $sidelines($id) {
3547 foreach ls $sidelines($id) {
3549 set y1 [lindex $ls 0 end]
3548 set y1 [lindex $ls 0 end]
3550 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3549 if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
3551 set yt $y1
3550 set yt $y1
3552 }
3551 }
3553 }
3552 }
3554 }
3553 }
3555 }
3554 }
3556 if {$yt eq {}} return
3555 if {$yt eq {}} return
3557 set ymax [lindex [$canv cget -scrollregion] 3]
3556 set ymax [lindex [$canv cget -scrollregion] 3]
3558 if {$ymax eq {} || $ymax <= 0} return
3557 if {$ymax eq {} || $ymax <= 0} return
3559 set view [$canv yview]
3558 set view [$canv yview]
3560 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3559 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
3561 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3560 set yfrac [expr {$yt / $ymax - $yspan / 2}]
3562 if {$yfrac < 0} {
3561 if {$yfrac < 0} {
3563 set yfrac 0
3562 set yfrac 0
3564 }
3563 }
3565 $canv yview moveto $yfrac
3564 $canv yview moveto $yfrac
3566 }
3565 }
3567
3566
3568 proc lineclick {x y id isnew} {
3567 proc lineclick {x y id isnew} {
3569 global ctext commitinfo children cflist canv thickerline
3568 global ctext commitinfo children cflist canv thickerline
3570
3569
3571 unmarkmatches
3570 unmarkmatches
3572 unselectline
3571 unselectline
3573 normalline
3572 normalline
3574 $canv delete hover
3573 $canv delete hover
3575 # draw this line thicker than normal
3574 # draw this line thicker than normal
3576 drawlines $id 1
3575 drawlines $id 1
3577 set thickerline $id
3576 set thickerline $id
3578 if {$isnew} {
3577 if {$isnew} {
3579 set ymax [lindex [$canv cget -scrollregion] 3]
3578 set ymax [lindex [$canv cget -scrollregion] 3]
3580 if {$ymax eq {}} return
3579 if {$ymax eq {}} return
3581 set yfrac [lindex [$canv yview] 0]
3580 set yfrac [lindex [$canv yview] 0]
3582 set y [expr {$y + $yfrac * $ymax}]
3581 set y [expr {$y + $yfrac * $ymax}]
3583 }
3582 }
3584 set dirn [clickisonarrow $id $y]
3583 set dirn [clickisonarrow $id $y]
3585 if {$dirn ne {}} {
3584 if {$dirn ne {}} {
3586 arrowjump $id $dirn $y
3585 arrowjump $id $dirn $y
3587 return
3586 return
3588 }
3587 }
3589
3588
3590 if {$isnew} {
3589 if {$isnew} {
3591 addtohistory [list lineclick $x $y $id 0]
3590 addtohistory [list lineclick $x $y $id 0]
3592 }
3591 }
3593 # fill the details pane with info about this line
3592 # fill the details pane with info about this line
3594 $ctext conf -state normal
3593 $ctext conf -state normal
3595 $ctext delete 0.0 end
3594 $ctext delete 0.0 end
3596 $ctext tag conf link -foreground blue -underline 1
3595 $ctext tag conf link -foreground blue -underline 1
3597 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3596 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3598 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3597 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3599 $ctext insert end "Parent:\t"
3598 $ctext insert end "Parent:\t"
3600 $ctext insert end $id [list link link0]
3599 $ctext insert end $id [list link link0]
3601 $ctext tag bind link0 <1> [list selbyid $id]
3600 $ctext tag bind link0 <1> [list selbyid $id]
3602 set info $commitinfo($id)
3601 set info $commitinfo($id)
3603 $ctext insert end "\n\t[lindex $info 0]\n"
3602 $ctext insert end "\n\t[lindex $info 0]\n"
3604 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
3603 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
3605 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3604 $ctext insert end "\tDate:\t[lindex $info 2]\n"
3606 if {[info exists children($id)]} {
3605 if {[info exists children($id)]} {
3607 $ctext insert end "\nChildren:"
3606 $ctext insert end "\nChildren:"
3608 set i 0
3607 set i 0
3609 foreach child $children($id) {
3608 foreach child $children($id) {
3610 incr i
3609 incr i
3611 set info $commitinfo($child)
3610 set info $commitinfo($child)
3612 $ctext insert end "\n\t"
3611 $ctext insert end "\n\t"
3613 $ctext insert end $child [list link link$i]
3612 $ctext insert end $child [list link link$i]
3614 $ctext tag bind link$i <1> [list selbyid $child]
3613 $ctext tag bind link$i <1> [list selbyid $child]
3615 $ctext insert end "\n\t[lindex $info 0]"
3614 $ctext insert end "\n\t[lindex $info 0]"
3616 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
3615 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
3617 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3616 $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
3618 }
3617 }
3619 }
3618 }
3620 $ctext conf -state disabled
3619 $ctext conf -state disabled
3621
3620
3622 $cflist delete 0 end
3621 $cflist delete 0 end
3623 }
3622 }
3624
3623
3625 proc normalline {} {
3624 proc normalline {} {
3626 global thickerline
3625 global thickerline
3627 if {[info exists thickerline]} {
3626 if {[info exists thickerline]} {
3628 drawlines $thickerline 0
3627 drawlines $thickerline 0
3629 unset thickerline
3628 unset thickerline
3630 }
3629 }
3631 }
3630 }
3632
3631
3633 proc selbyid {id} {
3632 proc selbyid {id} {
3634 global idline
3633 global idline
3635 if {[info exists idline($id)]} {
3634 if {[info exists idline($id)]} {
3636 selectline $idline($id) 1
3635 selectline $idline($id) 1
3637 }
3636 }
3638 }
3637 }
3639
3638
3640 proc mstime {} {
3639 proc mstime {} {
3641 global startmstime
3640 global startmstime
3642 if {![info exists startmstime]} {
3641 if {![info exists startmstime]} {
3643 set startmstime [clock clicks -milliseconds]
3642 set startmstime [clock clicks -milliseconds]
3644 }
3643 }
3645 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3644 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
3646 }
3645 }
3647
3646
3648 proc rowmenu {x y id} {
3647 proc rowmenu {x y id} {
3649 global rowctxmenu idline selectedline rowmenuid hgvdiff
3648 global rowctxmenu idline selectedline rowmenuid hgvdiff
3650
3649
3651 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3650 if {![info exists selectedline] || $idline($id) eq $selectedline} {
3652 set state disabled
3651 set state disabled
3653 } else {
3652 } else {
3654 set state normal
3653 set state normal
3655 }
3654 }
3656 $rowctxmenu entryconfigure 0 -state $state
3655 $rowctxmenu entryconfigure 0 -state $state
3657 $rowctxmenu entryconfigure 1 -state $state
3656 $rowctxmenu entryconfigure 1 -state $state
3658 $rowctxmenu entryconfigure 2 -state $state
3657 $rowctxmenu entryconfigure 2 -state $state
3659 if { $hgvdiff ne "" } {
3658 if { $hgvdiff ne "" } {
3660 $rowctxmenu entryconfigure 6 -state $state
3659 $rowctxmenu entryconfigure 6 -state $state
3661 }
3660 }
3662 set rowmenuid $id
3661 set rowmenuid $id
3663 tk_popup $rowctxmenu $x $y
3662 tk_popup $rowctxmenu $x $y
3664 }
3663 }
3665
3664
3666 proc diffvssel {dirn} {
3665 proc diffvssel {dirn} {
3667 global rowmenuid selectedline lineid
3666 global rowmenuid selectedline lineid
3668
3667
3669 if {![info exists selectedline]} return
3668 if {![info exists selectedline]} return
3670 if {$dirn} {
3669 if {$dirn} {
3671 set oldid $lineid($selectedline)
3670 set oldid $lineid($selectedline)
3672 set newid $rowmenuid
3671 set newid $rowmenuid
3673 } else {
3672 } else {
3674 set oldid $rowmenuid
3673 set oldid $rowmenuid
3675 set newid $lineid($selectedline)
3674 set newid $lineid($selectedline)
3676 }
3675 }
3677 addtohistory [list doseldiff $oldid $newid]
3676 addtohistory [list doseldiff $oldid $newid]
3678 doseldiff $oldid $newid
3677 doseldiff $oldid $newid
3679 }
3678 }
3680
3679
3681 proc doseldiff {oldid newid} {
3680 proc doseldiff {oldid newid} {
3682 global ctext cflist
3681 global ctext cflist
3683 global commitinfo
3682 global commitinfo
3684
3683
3685 $ctext conf -state normal
3684 $ctext conf -state normal
3686 $ctext delete 0.0 end
3685 $ctext delete 0.0 end
3687 $ctext mark set fmark.0 0.0
3686 $ctext mark set fmark.0 0.0
3688 $ctext mark gravity fmark.0 left
3687 $ctext mark gravity fmark.0 left
3689 $cflist delete 0 end
3688 $cflist delete 0 end
3690 $cflist insert end "Top"
3689 $cflist insert end "Top"
3691 $ctext insert end "From "
3690 $ctext insert end "From "
3692 $ctext tag conf link -foreground blue -underline 1
3691 $ctext tag conf link -foreground blue -underline 1
3693 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3692 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3694 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3693 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3695 $ctext tag bind link0 <1> [list selbyid $oldid]
3694 $ctext tag bind link0 <1> [list selbyid $oldid]
3696 $ctext insert end $oldid [list link link0]
3695 $ctext insert end $oldid [list link link0]
3697 $ctext insert end "\n "
3696 $ctext insert end "\n "
3698 $ctext insert end [lindex $commitinfo($oldid) 0]
3697 $ctext insert end [lindex $commitinfo($oldid) 0]
3699 $ctext insert end "\n\nTo "
3698 $ctext insert end "\n\nTo "
3700 $ctext tag bind link1 <1> [list selbyid $newid]
3699 $ctext tag bind link1 <1> [list selbyid $newid]
3701 $ctext insert end $newid [list link link1]
3700 $ctext insert end $newid [list link link1]
3702 $ctext insert end "\n "
3701 $ctext insert end "\n "
3703 $ctext insert end [lindex $commitinfo($newid) 0]
3702 $ctext insert end [lindex $commitinfo($newid) 0]
3704 $ctext insert end "\n"
3703 $ctext insert end "\n"
3705 $ctext conf -state disabled
3704 $ctext conf -state disabled
3706 $ctext tag delete Comments
3705 $ctext tag delete Comments
3707 $ctext tag remove found 1.0 end
3706 $ctext tag remove found 1.0 end
3708 startdiff [list $newid $oldid]
3707 startdiff [list $newid $oldid]
3709 }
3708 }
3710
3709
3711 proc mkpatch {} {
3710 proc mkpatch {} {
3712 global rowmenuid currentid commitinfo patchtop patchnum
3711 global rowmenuid currentid commitinfo patchtop patchnum
3713
3712
3714 if {![info exists currentid]} return
3713 if {![info exists currentid]} return
3715 set oldid $currentid
3714 set oldid $currentid
3716 set oldhead [lindex $commitinfo($oldid) 0]
3715 set oldhead [lindex $commitinfo($oldid) 0]
3717 set newid $rowmenuid
3716 set newid $rowmenuid
3718 set newhead [lindex $commitinfo($newid) 0]
3717 set newhead [lindex $commitinfo($newid) 0]
3719 set top .patch
3718 set top .patch
3720 set patchtop $top
3719 set patchtop $top
3721 catch {destroy $top}
3720 catch {destroy $top}
3722 toplevel $top
3721 toplevel $top
3723 ttk::label $top.title -text "Generate patch"
3722 ttk::label $top.title -text "Generate patch"
3724 grid $top.title - -pady 10
3723 grid $top.title - -pady 10
3725 ttk::label $top.from -text "From:"
3724 ttk::label $top.from -text "From:"
3726 ttk::entry $top.fromsha1 -width 40
3725 ttk::entry $top.fromsha1 -width 40
3727 $top.fromsha1 insert 0 $oldid
3726 $top.fromsha1 insert 0 $oldid
3728 $top.fromsha1 conf -state readonly
3727 $top.fromsha1 conf -state readonly
3729 grid $top.from $top.fromsha1 -sticky w
3728 grid $top.from $top.fromsha1 -sticky w
3730 ttk::entry $top.fromhead -width 60
3729 ttk::entry $top.fromhead -width 60
3731 $top.fromhead insert 0 $oldhead
3730 $top.fromhead insert 0 $oldhead
3732 $top.fromhead conf -state readonly
3731 $top.fromhead conf -state readonly
3733 grid x $top.fromhead -sticky w
3732 grid x $top.fromhead -sticky w
3734 ttk::label $top.to -text "To:"
3733 ttk::label $top.to -text "To:"
3735 ttk::entry $top.tosha1 -width 40
3734 ttk::entry $top.tosha1 -width 40
3736 $top.tosha1 insert 0 $newid
3735 $top.tosha1 insert 0 $newid
3737 $top.tosha1 conf -state readonly
3736 $top.tosha1 conf -state readonly
3738 grid $top.to $top.tosha1 -sticky w
3737 grid $top.to $top.tosha1 -sticky w
3739 ttk::entry $top.tohead -width 60
3738 ttk::entry $top.tohead -width 60
3740 $top.tohead insert 0 $newhead
3739 $top.tohead insert 0 $newhead
3741 $top.tohead conf -state readonly
3740 $top.tohead conf -state readonly
3742 grid x $top.tohead -sticky w
3741 grid x $top.tohead -sticky w
3743 ttk::button $top.rev -text "Reverse" -command mkpatchrev
3742 ttk::button $top.rev -text "Reverse" -command mkpatchrev
3744 grid $top.rev x -pady 10
3743 grid $top.rev x -pady 10
3745 ttk::label $top.flab -text "Output file:"
3744 ttk::label $top.flab -text "Output file:"
3746 ttk::entry $top.fname -width 60
3745 ttk::entry $top.fname -width 60
3747 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3746 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
3748 incr patchnum
3747 incr patchnum
3749 grid $top.flab $top.fname -sticky w
3748 grid $top.flab $top.fname -sticky w
3750 ttk::frame $top.buts
3749 ttk::frame $top.buts
3751 ttk::button $top.buts.gen -text "Generate" -command mkpatchgo
3750 ttk::button $top.buts.gen -text "Generate" -command mkpatchgo
3752 ttk::button $top.buts.can -text "Cancel" -command mkpatchcan
3751 ttk::button $top.buts.can -text "Cancel" -command mkpatchcan
3753 grid $top.buts.gen $top.buts.can
3752 grid $top.buts.gen $top.buts.can
3754 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3753 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3755 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3754 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3756 grid $top.buts - -pady 10 -sticky ew
3755 grid $top.buts - -pady 10 -sticky ew
3757 focus $top.fname
3756 focus $top.fname
3758 }
3757 }
3759
3758
3760 proc mkpatchrev {} {
3759 proc mkpatchrev {} {
3761 global patchtop
3760 global patchtop
3762
3761
3763 set oldid [$patchtop.fromsha1 get]
3762 set oldid [$patchtop.fromsha1 get]
3764 set oldhead [$patchtop.fromhead get]
3763 set oldhead [$patchtop.fromhead get]
3765 set newid [$patchtop.tosha1 get]
3764 set newid [$patchtop.tosha1 get]
3766 set newhead [$patchtop.tohead get]
3765 set newhead [$patchtop.tohead get]
3767 foreach e [list fromsha1 fromhead tosha1 tohead] \
3766 foreach e [list fromsha1 fromhead tosha1 tohead] \
3768 v [list $newid $newhead $oldid $oldhead] {
3767 v [list $newid $newhead $oldid $oldhead] {
3769 $patchtop.$e conf -state normal
3768 $patchtop.$e conf -state normal
3770 $patchtop.$e delete 0 end
3769 $patchtop.$e delete 0 end
3771 $patchtop.$e insert 0 $v
3770 $patchtop.$e insert 0 $v
3772 $patchtop.$e conf -state readonly
3771 $patchtop.$e conf -state readonly
3773 }
3772 }
3774 }
3773 }
3775
3774
3776 proc mkpatchgo {} {
3775 proc mkpatchgo {} {
3777 global patchtop env
3776 global patchtop env
3778
3777
3779 set oldid [$patchtop.fromsha1 get]
3778 set oldid [$patchtop.fromsha1 get]
3780 set newid [$patchtop.tosha1 get]
3779 set newid [$patchtop.tosha1 get]
3781 set fname [$patchtop.fname get]
3780 set fname [$patchtop.fname get]
3782 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3781 if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} {
3783 error_popup "Error creating patch: $err"
3782 error_popup "Error creating patch: $err"
3784 }
3783 }
3785 catch {destroy $patchtop}
3784 catch {destroy $patchtop}
3786 unset patchtop
3785 unset patchtop
3787 }
3786 }
3788
3787
3789 proc mkpatchcan {} {
3788 proc mkpatchcan {} {
3790 global patchtop
3789 global patchtop
3791
3790
3792 catch {destroy $patchtop}
3791 catch {destroy $patchtop}
3793 unset patchtop
3792 unset patchtop
3794 }
3793 }
3795
3794
3796 proc mktag {} {
3795 proc mktag {} {
3797 global rowmenuid mktagtop commitinfo
3796 global rowmenuid mktagtop commitinfo
3798
3797
3799 set top .maketag
3798 set top .maketag
3800 set mktagtop $top
3799 set mktagtop $top
3801 catch {destroy $top}
3800 catch {destroy $top}
3802 toplevel $top
3801 toplevel $top
3803 ttk::label $top.title -text "Create tag"
3802 ttk::label $top.title -text "Create tag"
3804 grid $top.title - -pady 10
3803 grid $top.title - -pady 10
3805 ttk::label $top.id -text "ID:"
3804 ttk::label $top.id -text "ID:"
3806 ttk::entry $top.sha1 -width 40
3805 ttk::entry $top.sha1 -width 40
3807 $top.sha1 insert 0 $rowmenuid
3806 $top.sha1 insert 0 $rowmenuid
3808 $top.sha1 conf -state readonly
3807 $top.sha1 conf -state readonly
3809 grid $top.id $top.sha1 -sticky w
3808 grid $top.id $top.sha1 -sticky w
3810 ttk::entry $top.head -width 60
3809 ttk::entry $top.head -width 60
3811 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3810 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3812 $top.head conf -state readonly
3811 $top.head conf -state readonly
3813 grid x $top.head -sticky w
3812 grid x $top.head -sticky w
3814 ttk::label $top.tlab -text "Tag name:"
3813 ttk::label $top.tlab -text "Tag name:"
3815 ttk::entry $top.tag -width 60
3814 ttk::entry $top.tag -width 60
3816 grid $top.tlab $top.tag -sticky w
3815 grid $top.tlab $top.tag -sticky w
3817 ttk::frame $top.buts
3816 ttk::frame $top.buts
3818 ttk::button $top.buts.gen -text "Create" -command mktaggo
3817 ttk::button $top.buts.gen -text "Create" -command mktaggo
3819 ttk::button $top.buts.can -text "Cancel" -command mktagcan
3818 ttk::button $top.buts.can -text "Cancel" -command mktagcan
3820 grid $top.buts.gen $top.buts.can
3819 grid $top.buts.gen $top.buts.can
3821 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3820 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3822 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3821 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3823 grid $top.buts - -pady 10 -sticky ew
3822 grid $top.buts - -pady 10 -sticky ew
3824 focus $top.tag
3823 focus $top.tag
3825 }
3824 }
3826
3825
3827 proc domktag {} {
3826 proc domktag {} {
3828 global mktagtop env tagids idtags
3827 global mktagtop env tagids idtags
3829
3828
3830 set id [$mktagtop.sha1 get]
3829 set id [$mktagtop.sha1 get]
3831 set tag [$mktagtop.tag get]
3830 set tag [$mktagtop.tag get]
3832 if {$tag == {}} {
3831 if {$tag == {}} {
3833 error_popup "No tag name specified"
3832 error_popup "No tag name specified"
3834 return
3833 return
3835 }
3834 }
3836 if {[info exists tagids($tag)]} {
3835 if {[info exists tagids($tag)]} {
3837 error_popup "Tag \"$tag\" already exists"
3836 error_popup "Tag \"$tag\" already exists"
3838 return
3837 return
3839 }
3838 }
3840 if {[catch {
3839 if {[catch {
3841 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3840 set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag]
3842 } err]} {
3841 } err]} {
3843 error_popup "Error creating tag: $err"
3842 error_popup "Error creating tag: $err"
3844 return
3843 return
3845 }
3844 }
3846
3845
3847 set tagids($tag) $id
3846 set tagids($tag) $id
3848 lappend idtags($id) $tag
3847 lappend idtags($id) $tag
3849 redrawtags $id
3848 redrawtags $id
3850 }
3849 }
3851
3850
3852 proc redrawtags {id} {
3851 proc redrawtags {id} {
3853 global canv linehtag idline idpos selectedline
3852 global canv linehtag idline idpos selectedline
3854
3853
3855 if {![info exists idline($id)]} return
3854 if {![info exists idline($id)]} return
3856 $canv delete tag.$id
3855 $canv delete tag.$id
3857 set xt [eval drawtags $id $idpos($id)]
3856 set xt [eval drawtags $id $idpos($id)]
3858 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3857 $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
3859 if {[info exists selectedline] && $selectedline == $idline($id)} {
3858 if {[info exists selectedline] && $selectedline == $idline($id)} {
3860 selectline $selectedline 0
3859 selectline $selectedline 0
3861 }
3860 }
3862 }
3861 }
3863
3862
3864 proc mktagcan {} {
3863 proc mktagcan {} {
3865 global mktagtop
3864 global mktagtop
3866
3865
3867 catch {destroy $mktagtop}
3866 catch {destroy $mktagtop}
3868 unset mktagtop
3867 unset mktagtop
3869 }
3868 }
3870
3869
3871 proc mktaggo {} {
3870 proc mktaggo {} {
3872 domktag
3871 domktag
3873 mktagcan
3872 mktagcan
3874 }
3873 }
3875
3874
3876 proc writecommit {} {
3875 proc writecommit {} {
3877 global rowmenuid wrcomtop commitinfo wrcomcmd
3876 global rowmenuid wrcomtop commitinfo wrcomcmd
3878
3877
3879 set top .writecommit
3878 set top .writecommit
3880 set wrcomtop $top
3879 set wrcomtop $top
3881 catch {destroy $top}
3880 catch {destroy $top}
3882 toplevel $top
3881 toplevel $top
3883 ttk::label $top.title -text "Write commit to file"
3882 ttk::label $top.title -text "Write commit to file"
3884 grid $top.title - -pady 10
3883 grid $top.title - -pady 10
3885 ttk::label $top.id -text "ID:"
3884 ttk::label $top.id -text "ID:"
3886 ttk::entry $top.sha1 -width 40
3885 ttk::entry $top.sha1 -width 40
3887 $top.sha1 insert 0 $rowmenuid
3886 $top.sha1 insert 0 $rowmenuid
3888 $top.sha1 conf -state readonly
3887 $top.sha1 conf -state readonly
3889 grid $top.id $top.sha1 -sticky w
3888 grid $top.id $top.sha1 -sticky w
3890 ttk::entry $top.head -width 60
3889 ttk::entry $top.head -width 60
3891 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3890 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
3892 $top.head conf -state readonly
3891 $top.head conf -state readonly
3893 grid x $top.head -sticky w
3892 grid x $top.head -sticky w
3894 ttk::label $top.clab -text "Command:"
3893 ttk::label $top.clab -text "Command:"
3895 ttk::entry $top.cmd -width 60 -textvariable wrcomcmd
3894 ttk::entry $top.cmd -width 60 -textvariable wrcomcmd
3896 grid $top.clab $top.cmd -sticky w -pady 10
3895 grid $top.clab $top.cmd -sticky w -pady 10
3897 ttk::label $top.flab -text "Output file:"
3896 ttk::label $top.flab -text "Output file:"
3898 ttk::entry $top.fname -width 60
3897 ttk::entry $top.fname -width 60
3899 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3898 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
3900 grid $top.flab $top.fname -sticky w
3899 grid $top.flab $top.fname -sticky w
3901 ttk::frame $top.buts
3900 ttk::frame $top.buts
3902 ttk::button $top.buts.gen -text "Write" -command wrcomgo
3901 ttk::button $top.buts.gen -text "Write" -command wrcomgo
3903 ttk::button $top.buts.can -text "Cancel" -command wrcomcan
3902 ttk::button $top.buts.can -text "Cancel" -command wrcomcan
3904 grid $top.buts.gen $top.buts.can
3903 grid $top.buts.gen $top.buts.can
3905 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3904 grid columnconfigure $top.buts 0 -weight 1 -uniform a
3906 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3905 grid columnconfigure $top.buts 1 -weight 1 -uniform a
3907 grid $top.buts - -pady 10 -sticky ew
3906 grid $top.buts - -pady 10 -sticky ew
3908 focus $top.fname
3907 focus $top.fname
3909 }
3908 }
3910
3909
3911 proc wrcomgo {} {
3910 proc wrcomgo {} {
3912 global wrcomtop
3911 global wrcomtop
3913
3912
3914 set id [$wrcomtop.sha1 get]
3913 set id [$wrcomtop.sha1 get]
3915 set cmd "echo $id | [$wrcomtop.cmd get]"
3914 set cmd "echo $id | [$wrcomtop.cmd get]"
3916 set fname [$wrcomtop.fname get]
3915 set fname [$wrcomtop.fname get]
3917 if {[catch {exec sh -c $cmd > $fname &} err]} {
3916 if {[catch {exec sh -c $cmd > $fname &} err]} {
3918 error_popup "Error writing commit: $err"
3917 error_popup "Error writing commit: $err"
3919 }
3918 }
3920 catch {destroy $wrcomtop}
3919 catch {destroy $wrcomtop}
3921 unset wrcomtop
3920 unset wrcomtop
3922 }
3921 }
3923
3922
3924 proc wrcomcan {} {
3923 proc wrcomcan {} {
3925 global wrcomtop
3924 global wrcomtop
3926
3925
3927 catch {destroy $wrcomtop}
3926 catch {destroy $wrcomtop}
3928 unset wrcomtop
3927 unset wrcomtop
3929 }
3928 }
3930
3929
3931 proc listrefs {id} {
3930 proc listrefs {id} {
3932 global idtags idheads idotherrefs idbookmarks
3931 global idtags idheads idotherrefs idbookmarks
3933
3932
3934 set w {}
3933 set w {}
3935 if {[info exists idbookmarks($id)]} {
3934 if {[info exists idbookmarks($id)]} {
3936 set w $idbookmarks($id)
3935 set w $idbookmarks($id)
3937 }
3936 }
3938 set x {}
3937 set x {}
3939 if {[info exists idtags($id)]} {
3938 if {[info exists idtags($id)]} {
3940 set x $idtags($id)
3939 set x $idtags($id)
3941 }
3940 }
3942 set y {}
3941 set y {}
3943 if {[info exists idheads($id)]} {
3942 if {[info exists idheads($id)]} {
3944 set y $idheads($id)
3943 set y $idheads($id)
3945 }
3944 }
3946 set z {}
3945 set z {}
3947 if {[info exists idotherrefs($id)]} {
3946 if {[info exists idotherrefs($id)]} {
3948 set z $idotherrefs($id)
3947 set z $idotherrefs($id)
3949 }
3948 }
3950 return [list $w $x $y $z]
3949 return [list $w $x $y $z]
3951 }
3950 }
3952
3951
3953 proc rereadrefs {} {
3952 proc rereadrefs {} {
3954 global idbookmarks idtags idheads idotherrefs
3953 global idbookmarks idtags idheads idotherrefs
3955 global bookmarkids tagids headids otherrefids
3954 global bookmarkids tagids headids otherrefids
3956
3955
3957 set refids [concat [array names idtags] \
3956 set refids [concat [array names idtags] \
3958 [array names idheads] [array names idotherrefs] \
3957 [array names idheads] [array names idotherrefs] \
3959 [array names idbookmarks]]
3958 [array names idbookmarks]]
3960 foreach id $refids {
3959 foreach id $refids {
3961 if {![info exists ref($id)]} {
3960 if {![info exists ref($id)]} {
3962 set ref($id) [listrefs $id]
3961 set ref($id) [listrefs $id]
3963 }
3962 }
3964 }
3963 }
3965 foreach v {tagids idtags headids idheads otherrefids idotherrefs \
3964 foreach v {tagids idtags headids idheads otherrefids idotherrefs \
3966 bookmarkids idbookmarks} {
3965 bookmarkids idbookmarks} {
3967 catch {unset $v}
3966 catch {unset $v}
3968 }
3967 }
3969 readrefs
3968 readrefs
3970 set refids [lsort -unique [concat $refids [array names idtags] \
3969 set refids [lsort -unique [concat $refids [array names idtags] \
3971 [array names idheads] [array names idotherrefs] \
3970 [array names idheads] [array names idotherrefs] \
3972 [array names idbookmarks]]]
3971 [array names idbookmarks]]]
3973 foreach id $refids {
3972 foreach id $refids {
3974 set v [listrefs $id]
3973 set v [listrefs $id]
3975 if {![info exists ref($id)] || $ref($id) != $v} {
3974 if {![info exists ref($id)] || $ref($id) != $v} {
3976 redrawtags $id
3975 redrawtags $id
3977 }
3976 }
3978 }
3977 }
3979 }
3978 }
3980
3979
3981 proc vdiff {withparent} {
3980 proc vdiff {withparent} {
3982 global env rowmenuid selectedline lineid hgvdiff
3981 global env rowmenuid selectedline lineid hgvdiff
3983
3982
3984 if {![info exists rowmenuid]} return
3983 if {![info exists rowmenuid]} return
3985 set curid $rowmenuid
3984 set curid $rowmenuid
3986
3985
3987 if {$withparent} {
3986 if {$withparent} {
3988 set parents [exec $env(HG) --config ui.report_untrusted=false parents --rev $curid --template "{node}\n"]
3987 set parents [exec $env(HG) --config ui.report_untrusted=false parents --rev $curid --template "{node}\n"]
3989 set firstparent [lindex [split $parents "\n"] 0]
3988 set firstparent [lindex [split $parents "\n"] 0]
3990 set otherid $firstparent
3989 set otherid $firstparent
3991 } else {
3990 } else {
3992 if {![info exists selectedline]} return
3991 if {![info exists selectedline]} return
3993 set otherid $lineid($selectedline)
3992 set otherid $lineid($selectedline)
3994 }
3993 }
3995 set range "$otherid:$curid"
3994 set range "$otherid:$curid"
3996 if {[catch {exec $env(HG) --config ui.report_untrusted=false $hgvdiff -r $range} err]} {
3995 if {[catch {exec $env(HG) --config ui.report_untrusted=false $hgvdiff -r $range} err]} {
3997 # Ignore errors, this is just visualization
3996 # Ignore errors, this is just visualization
3998 }
3997 }
3999 }
3998 }
4000
3999
4001 proc showtag {tag isnew} {
4000 proc showtag {tag isnew} {
4002 global ctext cflist tagcontents tagids linknum
4001 global ctext cflist tagcontents tagids linknum
4003
4002
4004 if {$isnew} {
4003 if {$isnew} {
4005 addtohistory [list showtag $tag 0]
4004 addtohistory [list showtag $tag 0]
4006 }
4005 }
4007 $ctext conf -state normal
4006 $ctext conf -state normal
4008 $ctext delete 0.0 end
4007 $ctext delete 0.0 end
4009 set linknum 0
4008 set linknum 0
4010 if {[info exists tagcontents($tag)]} {
4009 if {[info exists tagcontents($tag)]} {
4011 set text $tagcontents($tag)
4010 set text $tagcontents($tag)
4012 } else {
4011 } else {
4013 set text "Tag: $tag\nId: $tagids($tag)"
4012 set text "Tag: $tag\nId: $tagids($tag)"
4014 }
4013 }
4015 appendwithlinks $text
4014 appendwithlinks $text
4016 $ctext conf -state disabled
4015 $ctext conf -state disabled
4017 $cflist delete 0 end
4016 $cflist delete 0 end
4018 }
4017 }
4019
4018
4020 proc doquit {} {
4019 proc doquit {} {
4021 global stopped
4020 global stopped
4022 set stopped 100
4021 set stopped 100
4023 destroy .
4022 destroy .
4024 }
4023 }
4025
4024
4026 proc getconfig {} {
4025 proc getconfig {} {
4027 global env
4026 global env
4028
4027
4029 set lines [exec $env(HG) debug-config]
4028 set lines [exec $env(HG) debug-config]
4030 regsub -all "\r\n" $lines "\n" config
4029 regsub -all "\r\n" $lines "\n" config
4031 set config {}
4030 set config {}
4032 foreach line [split $lines "\n"] {
4031 foreach line [split $lines "\n"] {
4033 regsub "^(k|v)=" $line "" line
4032 regsub "^(k|v)=" $line "" line
4034 lappend config $line
4033 lappend config $line
4035 }
4034 }
4036 return $config
4035 return $config
4037 }
4036 }
4038
4037
4039 # defaults...
4038 # defaults...
4040 set datemode 0
4039 set datemode 0
4041 set boldnames 0
4040 set boldnames 0
4042 set diffopts "-U 5 -p"
4041 set diffopts "-U 5 -p"
4043 set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty"
4042 set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty"
4044
4043
4045 set mainfont {Helvetica 9}
4044 set mainfont {Helvetica 9}
4046 set curidfont {}
4045 set curidfont {}
4047 set textfont {Courier 9}
4046 set textfont {Courier 9}
4048 set findmergefiles 0
4047 set findmergefiles 0
4049 set gaudydiff 0
4048 set gaudydiff 0
4050 set maxgraphpct 50
4049 set maxgraphpct 50
4051 set maxwidth 16
4050 set maxwidth 16
4052
4051
4053 set colors {green red blue magenta darkgrey brown orange}
4052 set colors {green red blue magenta darkgrey brown orange}
4054 set authorcolors {
4053 set authorcolors {
4055 black blue deeppink mediumorchid blue burlywood4 goldenrod slateblue red2 navy dimgrey
4054 black blue deeppink mediumorchid blue burlywood4 goldenrod slateblue red2 navy dimgrey
4056 }
4055 }
4057 set bgcolor white
4056 set bgcolor white
4058
4057
4059 # This color should probably be some system color (provided by tk),
4058 # This color should probably be some system color (provided by tk),
4060 # but as the bgcolor has always been set to white, I choose to ignore
4059 # but as the bgcolor has always been set to white, I choose to ignore
4061 set fgcolor black
4060 set fgcolor black
4062 set diffaddcolor "#00a000"
4061 set diffaddcolor "#00a000"
4063 set diffremcolor red
4062 set diffremcolor red
4064 set diffmerge1color red
4063 set diffmerge1color red
4065 set diffmerge2color blue
4064 set diffmerge2color blue
4066 set hunksepcolor blue
4065 set hunksepcolor blue
4067
4066
4068 catch {source ~/.hgk}
4067 catch {source ~/.hgk}
4069
4068
4070 if {$curidfont == ""} { # initialize late based on current mainfont
4069 if {$curidfont == ""} { # initialize late based on current mainfont
4071 set curidfont "$mainfont bold italic underline"
4070 set curidfont "$mainfont bold italic underline"
4072 }
4071 }
4073
4072
4074 set namefont $mainfont
4073 set namefont $mainfont
4075 if {$boldnames} {
4074 if {$boldnames} {
4076 lappend namefont bold
4075 lappend namefont bold
4077 }
4076 }
4078
4077
4079 set revtreeargs {}
4078 set revtreeargs {}
4080 foreach arg $argv {
4079 foreach arg $argv {
4081 switch -regexp -- $arg {
4080 switch -regexp -- $arg {
4082 "^$" { }
4081 "^$" { }
4083 "^-b" { set boldnames 1 }
4082 "^-b" { set boldnames 1 }
4084 "^-d" { set datemode 1 }
4083 "^-d" { set datemode 1 }
4085 default {
4084 default {
4086 lappend revtreeargs $arg
4085 lappend revtreeargs $arg
4087 }
4086 }
4088 }
4087 }
4089 }
4088 }
4090
4089
4091 set history {}
4090 set history {}
4092 set historyindex 0
4091 set historyindex 0
4093
4092
4094 set stopped 0
4093 set stopped 0
4095 set redisplaying 0
4094 set redisplaying 0
4096 set stuffsaved 0
4095 set stuffsaved 0
4097 set patchnum 0
4096 set patchnum 0
4098
4097
4099 array set config [getconfig]
4098 array set config [getconfig]
4100 set hgvdiff $config(vdiff)
4099 set hgvdiff $config(vdiff)
4101 setcoords
4100 setcoords
4102 makewindow
4101 makewindow
4103 readrefs
4102 readrefs
4104 set hgroot [exec $env(HG) root]
4103 set hgroot [exec $env(HG) root]
4105 wm title . "hgk $hgroot"
4104 wm title . "hgk $hgroot"
4106 getcommits $revtreeargs
4105 getcommits $revtreeargs
General Comments 0
You need to be logged in to leave comments. Login now