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