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