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