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