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