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