2 # Tcl ignores the next line -*- tcl -*- \
5 # Copyright (C) 2005 Paul Mackerras. All rights reserved.
6 # This program is free software; it may be used, copied, modified
7 # and distributed under the terms of the GNU General Public Licence,
8 # either version 2, or (at your option) any later version.
12 if {[info exists env
(GIT_DIR
)]} {
19 proc start_rev_list
{view
} {
20 global startmsecs nextupdate ncmupdate
21 global commfd leftover tclencoding datemode
22 global viewargs viewfiles commitidx
24 set startmsecs
[clock clicks
-milliseconds]
25 set nextupdate
[expr {$startmsecs + 100}]
27 set commitidx
($view) 0
28 set args
$viewargs($view)
29 if {$viewfiles($view) ne
{}} {
30 set args
[concat
$args "--" $viewfiles($view)]
32 set order
"--topo-order"
34 set order
"--date-order"
37 set fd
[open
[concat | git-rev-list
--header $order \
38 --parents --boundary --default HEAD
$args] r
]
40 puts stderr
"Error executing git-rev-list: $err"
44 set leftover
($view) {}
45 fconfigure
$fd -blocking 0 -translation lf
46 if {$tclencoding != {}} {
47 fconfigure
$fd -encoding $tclencoding
49 fileevent
$fd readable
[list getcommitlines
$fd $view]
53 proc stop_rev_list
{} {
56 if {![info exists commfd
($curview)]} return
57 set fd
$commfd($curview)
63 unset commfd
($curview)
67 global phase canv mainfont curview
71 start_rev_list
$curview
72 show_status
"Reading commits..."
75 proc getcommitlines
{fd view
} {
76 global commitlisted nextupdate
77 global leftover commfd
78 global displayorder commitidx commitrow commitdata
79 global parentlist childlist children curview hlview
80 global vparentlist vchildlist vdisporder vcmitlisted
84 if {![eof
$fd]} return
88 # set it blocking so we wait for the process to terminate
89 fconfigure
$fd -blocking 1
90 if {[catch
{close
$fd} err
]} {
92 if {$view != $curview} {
93 set fv
" for the \"$viewname($view)\" view"
95 if {[string range
$err 0 4] == "usage"} {
96 set err
"Gitk: error reading commits$fv:\
97 bad arguments to git-rev-list."
98 if {$viewname($view) eq
"Command line"} {
100 " (Note: arguments to gitk are passed to git-rev-list\
101 to allow selection of commits to be displayed.)"
104 set err
"Error reading commits$fv: $err"
108 if {$view == $curview} {
109 after idle finishcommits
116 set i
[string first
"\0" $stuff $start]
118 append leftover
($view) [string range
$stuff $start end
]
122 set cmit
$leftover($view)
123 append cmit
[string range
$stuff 0 [expr {$i - 1}]]
124 set leftover
($view) {}
126 set cmit
[string range
$stuff $start [expr {$i - 1}]]
128 set start
[expr {$i + 1}]
129 set j
[string first
"\n" $cmit]
133 set ids
[string range
$cmit 0 [expr {$j - 1}]]
134 if {[string range
$ids 0 0] == "-"} {
136 set ids
[string range
$ids 1 end
]
140 if {[string length
$id] != 40} {
148 if {[string length
$shortcmit] > 80} {
149 set shortcmit
"[string range $shortcmit 0 80]..."
151 error_popup
"Can't parse git-rev-list output: {$shortcmit}"
154 set id
[lindex
$ids 0]
156 set olds
[lrange
$ids 1 end
]
159 if {$i == 0 ||
[lsearch
-exact $olds $p] >= $i} {
160 lappend children
($view,$p) $id
167 if {![info exists children
($view,$id)]} {
168 set children
($view,$id) {}
170 set commitdata
($id) [string range
$cmit [expr {$j + 1}] end
]
171 set commitrow
($view,$id) $commitidx($view)
172 incr commitidx
($view)
173 if {$view == $curview} {
174 lappend parentlist
$olds
175 lappend childlist
$children($view,$id)
176 lappend displayorder
$id
177 lappend commitlisted
$listed
179 lappend vparentlist
($view) $olds
180 lappend vchildlist
($view) $children($view,$id)
181 lappend vdisporder
($view) $id
182 lappend vcmitlisted
($view) $listed
187 if {$view == $curview} {
189 } elseif
{[info exists hlview
] && $view == $hlview} {
193 if {[clock clicks
-milliseconds] >= $nextupdate} {
199 global commfd nextupdate numcommits ncmupdate
201 foreach v
[array names commfd
] {
202 fileevent
$commfd($v) readable
{}
205 set nextupdate
[expr {[clock clicks
-milliseconds] + 100}]
206 if {$numcommits < 100} {
207 set ncmupdate
[expr {$numcommits + 1}]
208 } elseif
{$numcommits < 10000} {
209 set ncmupdate
[expr {$numcommits + 10}]
211 set ncmupdate
[expr {$numcommits + 100}]
213 foreach v
[array names commfd
] {
215 fileevent
$fd readable
[list getcommitlines
$fd $v]
219 proc readcommit
{id
} {
220 if {[catch
{set contents
[exec git-cat-file commit
$id]}]} return
221 parsecommit
$id $contents 0
224 proc updatecommits
{} {
225 global viewdata curview phase displayorder
226 global children commitrow selectedline thickerline
233 foreach id
$displayorder {
234 catch
{unset children
($n,$id)}
235 catch
{unset commitrow
($n,$id)}
238 catch
{unset selectedline
}
239 catch
{unset thickerline
}
240 catch
{unset viewdata
($n)}
245 proc parsecommit
{id contents listed
} {
246 global commitinfo cdate
255 set hdrend
[string first
"\n\n" $contents]
257 # should never happen...
258 set hdrend
[string length
$contents]
260 set header
[string range
$contents 0 [expr {$hdrend - 1}]]
261 set comment
[string range
$contents [expr {$hdrend + 2}] end
]
262 foreach line
[split $header "\n"] {
263 set tag
[lindex
$line 0]
264 if {$tag == "author"} {
265 set audate
[lindex
$line end-1
]
266 set auname
[lrange
$line 1 end-2
]
267 } elseif
{$tag == "committer"} {
268 set comdate
[lindex
$line end-1
]
269 set comname
[lrange
$line 1 end-2
]
273 # take the first line of the comment as the headline
274 set i
[string first
"\n" $comment]
276 set headline
[string trim
[string range
$comment 0 $i]]
278 set headline
$comment
281 # git-rev-list indents the comment by 4 spaces;
282 # if we got this via git-cat-file, add the indentation
284 foreach line
[split $comment "\n"] {
285 append newcomment
" "
286 append newcomment
$line
287 append newcomment
"\n"
289 set comment
$newcomment
291 if {$comdate != {}} {
292 set cdate
($id) $comdate
294 set commitinfo
($id) [list
$headline $auname $audate \
295 $comname $comdate $comment]
298 proc getcommit
{id
} {
299 global commitdata commitinfo
301 if {[info exists commitdata
($id)]} {
302 parsecommit
$id $commitdata($id) 1
305 if {![info exists commitinfo
($id)]} {
306 set commitinfo
($id) {"No commit information available"}
313 global tagids idtags headids idheads tagcontents
314 global otherrefids idotherrefs
316 foreach v
{tagids idtags headids idheads otherrefids idotherrefs
} {
319 set refd
[open
[list | git ls-remote
[gitdir
]] r
]
320 while {0 <= [set n
[gets
$refd line
]]} {
321 if {![regexp
{^
([0-9a-f]{40}) refs
/([^^
]*)$
} $line \
325 if {[regexp
{^remotes
/.
*/HEAD$
} $path match
]} {
328 if {![regexp
{^
(tags|heads
)/(.
*)$
} $path match
type name
]} {
332 if {[regexp
{^remotes
/} $path match
]} {
335 if {$type == "tags"} {
336 set tagids
($name) $id
337 lappend idtags
($id) $name
342 set commit
[exec git-rev-parse
"$id^0"]
343 if {"$commit" != "$id"} {
344 set tagids
($name) $commit
345 lappend idtags
($commit) $name
349 set tagcontents
($name) [exec git-cat-file tag
"$id"]
351 } elseif
{ $type == "heads" } {
352 set headids
($name) $id
353 lappend idheads
($id) $name
355 set otherrefids
($name) $id
356 lappend idotherrefs
($id) $name
362 proc show_error
{w msg
} {
363 message
$w.m
-text $msg -justify center
-aspect 400
364 pack
$w.m
-side top
-fill x
-padx 20 -pady 20
365 button
$w.ok
-text OK
-command "destroy $w"
366 pack
$w.ok
-side bottom
-fill x
367 bind $w <Visibility
> "grab $w; focus $w"
368 bind $w <Key-Return
> "destroy $w"
372 proc error_popup msg
{
380 global canv canv2 canv3 linespc charspc ctext cflist
381 global textfont mainfont uifont
382 global findtype findtypemenu findloc findstring fstring geometry
383 global entries sha1entry sha1string sha1but
384 global maincursor textcursor curtextcursor
385 global rowctxmenu mergemax
386 global highlight_files highlight_names
387 global searchstring sstring
390 .bar add cascade
-label "File" -menu .bar.
file
391 .bar configure
-font $uifont
393 .bar.
file add
command -label "Update" -command updatecommits
394 .bar.
file add
command -label "Reread references" -command rereadrefs
395 .bar.
file add
command -label "Quit" -command doquit
396 .bar.
file configure
-font $uifont
398 .bar add cascade
-label "Edit" -menu .bar.edit
399 .bar.edit add
command -label "Preferences" -command doprefs
400 .bar.edit configure
-font $uifont
402 menu .bar.view
-font $uifont
403 .bar add cascade
-label "View" -menu .bar.view
404 .bar.view add
command -label "New view..." -command {newview
0}
405 .bar.view add
command -label "Edit view..." -command editview \
407 .bar.view add
command -label "Delete view" -command delview
-state disabled
408 .bar.view add separator
409 .bar.view add radiobutton
-label "All files" -command {showview
0} \
410 -variable selectedview
-value 0
413 .bar add cascade
-label "Help" -menu .bar.
help
414 .bar.
help add
command -label "About gitk" -command about
415 .bar.
help add
command -label "Key bindings" -command keys
416 .bar.
help configure
-font $uifont
417 . configure
-menu .bar
419 if {![info exists geometry
(canv1
)]} {
420 set geometry
(canv1
) [expr {45 * $charspc}]
421 set geometry
(canv2
) [expr {30 * $charspc}]
422 set geometry
(canv3
) [expr {15 * $charspc}]
423 set geometry
(canvh
) [expr {25 * $linespc + 4}]
424 set geometry
(ctextw
) 80
425 set geometry
(ctexth
) 30
426 set geometry
(cflistw
) 30
428 panedwindow .ctop
-orient vertical
429 if {[info exists geometry
(width
)]} {
430 .ctop conf
-width $geometry(width
) -height $geometry(height
)
431 set texth
[expr {$geometry(height
) - $geometry(canvh
) - 56}]
432 set geometry
(ctexth
) [expr {($texth - 8) /
433 [font metrics
$textfont -linespace]}]
438 pack .ctop.top.lbar
-side bottom
-fill x
439 pack .ctop.top.bar
-side bottom
-fill x
440 set cscroll .ctop.top.csb
441 scrollbar
$cscroll -command {allcanvs yview
} -highlightthickness 0
442 pack
$cscroll -side right
-fill y
443 panedwindow .ctop.top.clist
-orient horizontal
-sashpad 0 -handlesize 4
444 pack .ctop.top.clist
-side top
-fill both
-expand 1
446 set canv .ctop.top.clist.canv
447 canvas
$canv -height $geometry(canvh
) -width $geometry(canv1
) \
449 -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
450 .ctop.top.clist add
$canv
451 set canv2 .ctop.top.clist.canv2
452 canvas
$canv2 -height $geometry(canvh
) -width $geometry(canv2
) \
453 -bg white
-bd 0 -yscrollincr $linespc
454 .ctop.top.clist add
$canv2
455 set canv3 .ctop.top.clist.canv3
456 canvas
$canv3 -height $geometry(canvh
) -width $geometry(canv3
) \
457 -bg white
-bd 0 -yscrollincr $linespc
458 .ctop.top.clist add
$canv3
459 bind .ctop.top.clist
<Configure
> {resizeclistpanes
%W
%w
}
461 set sha1entry .ctop.top.bar.sha1
462 set entries
$sha1entry
463 set sha1but .ctop.top.bar.sha1label
464 button
$sha1but -text "SHA1 ID: " -state disabled
-relief flat \
465 -command gotocommit
-width 8 -font $uifont
466 $sha1but conf
-disabledforeground [$sha1but cget
-foreground]
467 pack .ctop.top.bar.sha1label
-side left
468 entry
$sha1entry -width 40 -font $textfont -textvariable sha1string
469 trace add variable sha1string
write sha1change
470 pack
$sha1entry -side left
-pady 2
472 image create bitmap bm-left
-data {
473 #define left_width 16
474 #define left_height 16
475 static unsigned char left_bits
[] = {
476 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
477 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
478 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
480 image create bitmap bm-right
-data {
481 #define right_width 16
482 #define right_height 16
483 static unsigned char right_bits
[] = {
484 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
485 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
486 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
488 button .ctop.top.bar.leftbut
-image bm-left
-command goback \
489 -state disabled
-width 26
490 pack .ctop.top.bar.leftbut
-side left
-fill y
491 button .ctop.top.bar.rightbut
-image bm-right
-command goforw \
492 -state disabled
-width 26
493 pack .ctop.top.bar.rightbut
-side left
-fill y
495 button .ctop.top.bar.findbut
-text "Find" -command dofind
-font $uifont
496 pack .ctop.top.bar.findbut
-side left
498 set fstring .ctop.top.bar.findstring
499 lappend entries
$fstring
500 entry
$fstring -width 30 -font $textfont -textvariable findstring
501 pack
$fstring -side left
-expand 1 -fill x
503 set findtypemenu
[tk_optionMenu .ctop.top.bar.findtype \
504 findtype Exact IgnCase Regexp
]
505 .ctop.top.bar.findtype configure
-font $uifont
506 .ctop.top.bar.findtype.menu configure
-font $uifont
507 set findloc
"All fields"
508 tk_optionMenu .ctop.top.bar.findloc findloc
"All fields" Headline \
509 Comments Author Committer Files Pickaxe
510 .ctop.top.bar.findloc configure
-font $uifont
511 .ctop.top.bar.findloc.menu configure
-font $uifont
513 pack .ctop.top.bar.findloc
-side right
514 pack .ctop.top.bar.findtype
-side right
515 # for making sure type==Exact whenever loc==Pickaxe
516 trace add variable findloc
write findlocchange
518 label .ctop.top.lbar.flabel
-text "Highlight: Commits touching paths:" \
520 pack .ctop.top.lbar.flabel
-side left
-fill y
521 entry .ctop.top.lbar.fent
-width 25 -font $textfont \
522 -textvariable highlight_files
523 trace add variable highlight_files
write hfiles_change
524 lappend entries .ctop.top.lbar.fent
525 pack .ctop.top.lbar.fent
-side left
-fill x
-expand 1
526 label .ctop.top.lbar.vlabel
-text " OR in view" -font $uifont
527 pack .ctop.top.lbar.vlabel
-side left
-fill y
528 global viewhlmenu selectedhlview
529 set viewhlmenu
[tk_optionMenu .ctop.top.lbar.vhl selectedhlview None
]
530 $viewhlmenu entryconf
0 -command delvhighlight
531 $viewhlmenu conf
-font $uifont
532 .ctop.top.lbar.vhl conf
-font $uifont
533 pack .ctop.top.lbar.vhl
-side left
-fill y
534 label .ctop.top.lbar.alabel
-text " OR author/committer:" \
536 pack .ctop.top.lbar.alabel
-side left
-fill y
537 entry .ctop.top.lbar.aent
-width 20 -font $textfont \
538 -textvariable highlight_names
539 trace add variable highlight_names
write hnames_change
540 lappend entries .ctop.top.lbar.aent
541 pack .ctop.top.lbar.aent
-side right
-fill x
-expand 1
543 panedwindow .ctop.cdet
-orient horizontal
545 frame .ctop.cdet.left
546 frame .ctop.cdet.left.bot
547 pack .ctop.cdet.left.bot
-side bottom
-fill x
548 button .ctop.cdet.left.bot.search
-text "Search" -command dosearch \
550 pack .ctop.cdet.left.bot.search
-side left
-padx 5
551 set sstring .ctop.cdet.left.bot.sstring
552 entry
$sstring -width 20 -font $textfont -textvariable searchstring
553 lappend entries
$sstring
554 trace add variable searchstring
write incrsearch
555 pack
$sstring -side left
-expand 1 -fill x
556 set ctext .ctop.cdet.left.ctext
557 text
$ctext -bg white
-state disabled
-font $textfont \
558 -width $geometry(ctextw
) -height $geometry(ctexth
) \
559 -yscrollcommand scrolltext
-wrap none
560 scrollbar .ctop.cdet.left.sb
-command "$ctext yview"
561 pack .ctop.cdet.left.sb
-side right
-fill y
562 pack
$ctext -side left
-fill both
-expand 1
563 .ctop.cdet add .ctop.cdet.left
565 $ctext tag conf filesep
-font [concat
$textfont bold
] -back "#aaaaaa"
566 $ctext tag conf hunksep
-fore blue
567 $ctext tag conf d0
-fore red
568 $ctext tag conf d1
-fore "#00a000"
569 $ctext tag conf m0
-fore red
570 $ctext tag conf m1
-fore blue
571 $ctext tag conf m2
-fore green
572 $ctext tag conf m3
-fore purple
573 $ctext tag conf
m4 -fore brown
574 $ctext tag conf m5
-fore "#009090"
575 $ctext tag conf m6
-fore magenta
576 $ctext tag conf m7
-fore "#808000"
577 $ctext tag conf m8
-fore "#009000"
578 $ctext tag conf m9
-fore "#ff0080"
579 $ctext tag conf m10
-fore cyan
580 $ctext tag conf m11
-fore "#b07070"
581 $ctext tag conf m12
-fore "#70b0f0"
582 $ctext tag conf m13
-fore "#70f0b0"
583 $ctext tag conf m14
-fore "#f0b070"
584 $ctext tag conf m15
-fore "#ff70b0"
585 $ctext tag conf mmax
-fore darkgrey
587 $ctext tag conf mresult
-font [concat
$textfont bold
]
588 $ctext tag conf msep
-font [concat
$textfont bold
]
589 $ctext tag conf found
-back yellow
591 frame .ctop.cdet.right
592 frame .ctop.cdet.right.mode
593 radiobutton .ctop.cdet.right.mode.
patch -text "Patch" \
594 -command reselectline
-variable cmitmode
-value "patch"
595 radiobutton .ctop.cdet.right.mode.tree
-text "Tree" \
596 -command reselectline
-variable cmitmode
-value "tree"
597 grid .ctop.cdet.right.mode.
patch .ctop.cdet.right.mode.tree
-sticky ew
598 pack .ctop.cdet.right.mode
-side top
-fill x
599 set cflist .ctop.cdet.right.cfiles
600 set indent
[font measure
$mainfont "nn"]
601 text
$cflist -width $geometry(cflistw
) -background white
-font $mainfont \
602 -tabs [list
$indent [expr {2 * $indent}]] \
603 -yscrollcommand ".ctop.cdet.right.sb set" \
604 -cursor [. cget
-cursor] \
605 -spacing1 1 -spacing3 1
606 scrollbar .ctop.cdet.right.sb
-command "$cflist yview"
607 pack .ctop.cdet.right.sb
-side right
-fill y
608 pack
$cflist -side left
-fill both
-expand 1
609 $cflist tag configure highlight \
610 -background [$cflist cget
-selectbackground]
611 $cflist tag configure bold
-font [concat
$mainfont bold
]
612 .ctop.cdet add .ctop.cdet.right
613 bind .ctop.cdet
<Configure
> {resizecdetpanes
%W
%w
}
615 pack .ctop
-side top
-fill both
-expand 1
617 bindall
<1> {selcanvline
%W
%x
%y
}
618 #bindall <B1-Motion> {selcanvline %W %x %y}
619 bindall
<ButtonRelease-4
> "allcanvs yview scroll -5 units"
620 bindall
<ButtonRelease-5
> "allcanvs yview scroll 5 units"
621 bindall
<2> "canvscan mark %W %x %y"
622 bindall
<B2-Motion
> "canvscan dragto %W %x %y"
623 bindkey
<Home
> selfirstline
624 bindkey
<End
> sellastline
625 bind .
<Key-Up
> "selnextline -1"
626 bind .
<Key-Down
> "selnextline 1"
627 bindkey
<Key-Right
> "goforw"
628 bindkey
<Key-Left
> "goback"
629 bind .
<Key-Prior
> "selnextpage -1"
630 bind .
<Key-Next
> "selnextpage 1"
631 bind .
<Control-Home
> "allcanvs yview moveto 0.0"
632 bind .
<Control-End
> "allcanvs yview moveto 1.0"
633 bind .
<Control-Key-Up
> "allcanvs yview scroll -1 units"
634 bind .
<Control-Key-Down
> "allcanvs yview scroll 1 units"
635 bind .
<Control-Key-Prior
> "allcanvs yview scroll -1 pages"
636 bind .
<Control-Key-Next
> "allcanvs yview scroll 1 pages"
637 bindkey
<Key-Delete
> "$ctext yview scroll -1 pages"
638 bindkey
<Key-BackSpace
> "$ctext yview scroll -1 pages"
639 bindkey
<Key-space
> "$ctext yview scroll 1 pages"
640 bindkey p
"selnextline -1"
641 bindkey n
"selnextline 1"
644 bindkey i
"selnextline -1"
645 bindkey k
"selnextline 1"
648 bindkey b
"$ctext yview scroll -1 pages"
649 bindkey d
"$ctext yview scroll 18 units"
650 bindkey u
"$ctext yview scroll -18 units"
651 bindkey
/ {findnext
1}
652 bindkey
<Key-Return
> {findnext
0}
655 bind .
<Control-q
> doquit
656 bind .
<Control-f
> dofind
657 bind .
<Control-g
> {findnext
0}
658 bind .
<Control-r
> dosearchback
659 bind .
<Control-s
> dosearch
660 bind .
<Control-equal
> {incrfont
1}
661 bind .
<Control-KP_Add
> {incrfont
1}
662 bind .
<Control-minus
> {incrfont
-1}
663 bind .
<Control-KP_Subtract
> {incrfont
-1}
664 bind .
<Destroy
> {savestuff
%W
}
665 bind .
<Button-1
> "click %W"
666 bind $fstring <Key-Return
> dofind
667 bind $sha1entry <Key-Return
> gotocommit
668 bind $sha1entry <<PasteSelection>> clearsha1
669 bind $cflist <1> {sel_flist %W %x %y; break}
670 bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
671 bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
673 set maincursor [. cget -cursor]
674 set textcursor [$ctext cget -cursor]
675 set curtextcursor $textcursor
677 set rowctxmenu .rowctxmenu
678 menu $rowctxmenu -tearoff 0
679 $rowctxmenu add command -label "Diff this -> selected" \
680 -command {diffvssel 0}
681 $rowctxmenu add command -label "Diff selected -> this" \
682 -command {diffvssel 1}
683 $rowctxmenu add command -label "Make patch" -command mkpatch
684 $rowctxmenu add command -label "Create tag" -command mktag
685 $rowctxmenu add command -label "Write commit to file" -command writecommit
688 # mouse-2 makes all windows scan vertically, but only the one
689 # the cursor is in scans horizontally
690 proc canvscan {op w x y} {
691 global canv canv2 canv3
692 foreach c [list $canv $canv2 $canv3] {
701 proc scrollcanv {cscroll f0 f1} {
707 # when we make a key binding for the toplevel, make sure
708 # it doesn't get triggered when that key is pressed in the
709 # find string entry widget.
710 proc bindkey {ev script} {
713 set escript [bind Entry $ev]
714 if {$escript == {}} {
715 set escript [bind Entry <Key>]
718 bind $e $ev "$escript; break"
722 # set the focus back to the toplevel for any click outside
733 global canv canv2 canv3 ctext cflist mainfont textfont uifont
734 global stuffsaved findmergefiles maxgraphpct
736 global viewname viewfiles viewargs viewperm nextviewnum
739 if {$stuffsaved} return
740 if {![winfo viewable .]} return
742 set f [open "~/.gitk-new" w]
743 puts $f [list set mainfont $mainfont]
744 puts $f [list set textfont $textfont]
745 puts $f [list set uifont $uifont]
746 puts $f [list set findmergefiles $findmergefiles]
747 puts $f [list set maxgraphpct $maxgraphpct]
748 puts $f [list set maxwidth $maxwidth]
749 puts $f [list set cmitmode $cmitmode]
750 puts $f "set geometry(width) [winfo width .ctop]"
751 puts $f "set geometry(height) [winfo height .ctop]"
752 puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
753 puts $f "set geometry(canv2) [expr {[winfo width $canv2]-2}]"
754 puts $f "set geometry(canv3) [expr {[winfo width $canv3]-2}]"
755 puts $f "set geometry(canvh) [expr {[winfo height $canv]-2}]"
756 set wid [expr {([winfo width $ctext] - 8) \
757 / [font measure $textfont "0"]}]
758 puts $f "set geometry(ctextw) $wid"
759 set wid [expr {([winfo width $cflist] - 11) \
760 / [font measure [$cflist cget -font] "0"]}]
761 puts $f "set geometry(cflistw) $wid"
762 puts -nonewline $f "set permviews {"
763 for {set v 0} {$v < $nextviewnum} {incr v} {
765 puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v)]}"
770 file rename -force "~/.gitk-new" "~/.gitk"
775 proc resizeclistpanes {win w} {
777 if {[info exists oldwidth($win)]} {
778 set s0 [$win sash coord 0]
779 set s1 [$win sash coord 1]
781 set sash0 [expr {int($w/2 - 2)}]
782 set sash1 [expr {int($w*5/6 - 2)}]
784 set factor [expr {1.0 * $w / $oldwidth($win)}]
785 set sash0 [expr {int($factor * [lindex $s0 0])}]
786 set sash1 [expr {int($factor * [lindex $s1 0])}]
790 if {$sash1 < $sash0 + 20} {
791 set sash1 [expr {$sash0 + 20}]
793 if {$sash1 > $w - 10} {
794 set sash1 [expr {$w - 10}]
795 if {$sash0 > $sash1 - 20} {
796 set sash0 [expr {$sash1 - 20}]
800 $win sash place 0 $sash0 [lindex $s0 1]
801 $win sash place 1 $sash1 [lindex $s1 1]
803 set oldwidth($win) $w
806 proc resizecdetpanes {win w} {
808 if {[info exists oldwidth($win)]} {
809 set s0 [$win sash coord 0]
811 set sash0 [expr {int($w*3/4 - 2)}]
813 set factor [expr {1.0 * $w / $oldwidth($win)}]
814 set sash0 [expr {int($factor * [lindex $s0 0])}]
818 if {$sash0 > $w - 15} {
819 set sash0 [expr {$w - 15}]
822 $win sash place 0 $sash0 [lindex $s0 1]
824 set oldwidth($win) $w
828 global canv canv2 canv3
834 proc bindall {event action} {
835 global canv canv2 canv3
836 bind $canv $event $action
837 bind $canv2 $event $action
838 bind $canv3 $event $action
843 if {[winfo exists $w]} {
848 wm title $w "About gitk"
850 Gitk - a commit viewer for git
852 Copyright © 2005-2006 Paul Mackerras
854 Use and redistribute under the terms of the GNU General Public License} \
855 -justify center -aspect 400
856 pack $w.m -side top -fill x -padx 20 -pady 20
857 button $w.ok -text Close -command "destroy $w"
858 pack $w.ok -side bottom
863 if {[winfo exists $w]} {
868 wm title $w "Gitk key bindings"
873 <Home> Move to first commit
874 <End> Move to last commit
875 <Up>, p, i Move up one commit
876 <Down>, n, k Move down one commit
877 <Left>, z, j Go back in history list
878 <Right>, x, l Go forward in history list
879 <PageUp> Move up one page in commit list
880 <PageDown> Move down one page in commit list
881 <Ctrl-Home> Scroll to top of commit list
882 <Ctrl-End> Scroll to bottom of commit list
883 <Ctrl-Up> Scroll commit list up one line
884 <Ctrl-Down> Scroll commit list down one line
885 <Ctrl-PageUp> Scroll commit list up one page
886 <Ctrl-PageDown> Scroll commit list down one page
887 <Delete>, b Scroll diff view up one page
888 <Backspace> Scroll diff view up one page
889 <Space> Scroll diff view down one page
890 u Scroll diff view up 18 lines
891 d Scroll diff view down 18 lines
893 <Ctrl-G> Move to next find hit
894 <Ctrl-R> Move to previous find hit
895 <Return> Move to next find hit
896 / Move to next find hit, or redo find
897 ? Move to previous find hit
898 f Scroll diff view to next file
899 <Ctrl-KP+> Increase font size
900 <Ctrl-plus> Increase font size
901 <Ctrl-KP-> Decrease font size
902 <Ctrl-minus> Decrease font size
904 -justify left -bg white -border 2 -relief sunken
905 pack $w.m -side top -fill both
906 button $w.ok -text Close -command "destroy $w"
907 pack $w.ok -side bottom
910 # Procedures for manipulating the file list window at the
911 # bottom right of the overall window.
913 proc treeview {w l openlevs} {
914 global treecontents treediropen treeheight treeparent treeindex
924 set treecontents() {}
925 $w conf -state normal
927 while {[string range $f 0 $prefixend] ne $prefix} {
928 if {$lev <= $openlevs} {
929 $w mark set e:$treeindex($prefix) "end -1c"
930 $w mark gravity e:$treeindex($prefix) left
932 set treeheight($prefix) $ht
933 incr ht [lindex $htstack end]
934 set htstack [lreplace $htstack end end]
935 set prefixend [lindex $prefendstack end]
936 set prefendstack [lreplace $prefendstack end end]
937 set prefix [string range $prefix 0 $prefixend]
940 set tail [string range $f [expr {$prefixend+1}] end]
941 while {[set slash [string first "/" $tail]] >= 0} {
944 lappend prefendstack $prefixend
945 incr prefixend [expr {$slash + 1}]
946 set d [string range $tail 0 $slash]
947 lappend treecontents($prefix) $d
948 set oldprefix $prefix
950 set treecontents($prefix) {}
951 set treeindex($prefix) [incr ix]
952 set treeparent($prefix) $oldprefix
953 set tail [string range $tail [expr {$slash+1}] end]
954 if {$lev <= $openlevs} {
956 set treediropen($prefix) [expr {$lev < $openlevs}]
957 set bm [expr {$lev == $openlevs? "tri-rt": "tri-dn"}]
958 $w mark set d:$ix "end -1c"
959 $w mark gravity d:$ix left
961 for {set i 0} {$i < $lev} {incr i} {append str "\t"}
963 $w image create end -align center -image $bm -padx 1 \
965 $w insert end $d [highlight_tag $prefix]
966 $w mark set s:$ix "end -1c"
967 $w mark gravity s:$ix left
972 if {$lev <= $openlevs} {
975 for {set i 0} {$i < $lev} {incr i} {append str "\t"}
977 $w insert end $tail [highlight_tag $f]
979 lappend treecontents($prefix) $tail
982 while {$htstack ne {}} {
983 set treeheight($prefix) $ht
984 incr ht [lindex $htstack end]
985 set htstack [lreplace $htstack end end]
987 $w conf -state disabled
991 global treeheight treecontents
996 foreach e $treecontents($prefix) {
1001 if {[string index $e end] eq "/"} {
1002 set n $treeheight($prefix$e)
1014 proc highlight_tree {y prefix} {
1015 global treeheight treecontents cflist
1017 foreach e $treecontents($prefix) {
1019 if {[highlight_tag $path] ne {}} {
1020 $cflist tag add bold $y.0 "$y.0 lineend"
1023 if {[string index $e end] eq "/" && $treeheight($path) > 1} {
1024 set y [highlight_tree $y $path]
1030 proc treeclosedir {w dir} {
1031 global treediropen treeheight treeparent treeindex
1033 set ix $treeindex($dir)
1034 $w conf -state normal
1035 $w delete s:$ix e:$ix
1036 set treediropen($dir) 0
1037 $w image configure a:$ix -image tri-rt
1038 $w conf -state disabled
1039 set n [expr {1 - $treeheight($dir)}]
1040 while {$dir ne {}} {
1041 incr treeheight($dir) $n
1042 set dir $treeparent($dir)
1046 proc treeopendir {w dir} {
1047 global treediropen treeheight treeparent treecontents treeindex
1049 set ix $treeindex($dir)
1050 $w conf -state normal
1051 $w image configure a:$ix -image tri-dn
1052 $w mark set e:$ix s:$ix
1053 $w mark gravity e:$ix right
1056 set n [llength $treecontents($dir)]
1057 for {set x $dir} {$x ne {}} {set x $treeparent($x)} {
1060 incr treeheight($x) $n
1062 foreach e $treecontents($dir) {
1064 if {[string index $e end] eq "/"} {
1065 set iy $treeindex($de)
1066 $w mark set d:$iy e:$ix
1067 $w mark gravity d:$iy left
1068 $w insert e:$ix $str
1069 set treediropen($de) 0
1070 $w image create e:$ix -align center -image tri-rt -padx 1 \
1072 $w insert e:$ix $e [highlight_tag $de]
1073 $w mark set s:$iy e:$ix
1074 $w mark gravity s:$iy left
1075 set treeheight($de) 1
1077 $w insert e:$ix $str
1078 $w insert e:$ix $e [highlight_tag $de]
1081 $w mark gravity e:$ix left
1082 $w conf -state disabled
1083 set treediropen($dir) 1
1084 set top [lindex [split [$w index @0,0] .] 0]
1085 set ht [$w cget -height]
1086 set l [lindex [split [$w index s:$ix] .] 0]
1089 } elseif {$l + $n + 1 > $top + $ht} {
1090 set top [expr {$l + $n + 2 - $ht}]
1098 proc treeclick {w x y} {
1099 global treediropen cmitmode ctext cflist cflist_top
1101 if {$cmitmode ne "tree"} return
1102 if {![info exists cflist_top]} return
1103 set l [lindex [split [$w index "@$x,$y"] "."] 0]
1104 $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend"
1105 $cflist tag add highlight $l.0 "$l.0 lineend"
1111 set e [linetoelt $l]
1112 if {[string index $e end] ne "/"} {
1114 } elseif {$treediropen($e)} {
1121 proc setfilelist {id} {
1122 global treefilelist cflist
1124 treeview $cflist $treefilelist($id) 0
1127 image create bitmap tri-rt -background black -foreground blue -data {
1128 #define tri-rt_width 13
1129 #define tri-rt_height 13
1130 static unsigned char tri-rt_bits[] = {
1131 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x70, 0x00, 0xf0, 0x00,
1132 0xf0, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x30, 0x00, 0x10, 0x00, 0x00, 0x00,
1135 #define tri-rt-mask_width 13
1136 #define tri-rt-mask_height 13
1137 static unsigned char tri-rt-mask_bits[] = {
1138 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00, 0xf8, 0x01,
1139 0xf8, 0x03, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00,
1142 image create bitmap tri-dn -background black -foreground blue -data {
1143 #define tri-dn_width 13
1144 #define tri-dn_height 13
1145 static unsigned char tri-dn_bits[] = {
1146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xf8, 0x03,
1147 0xf0, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1150 #define tri-dn-mask_width 13
1151 #define tri-dn-mask_height 13
1152 static unsigned char tri-dn-mask_bits[] = {
1153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0xfe, 0x0f, 0xfc, 0x07,
1154 0xf8, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1158 proc init_flist {first} {
1159 global cflist cflist_top selectedline difffilestart
1161 $cflist conf -state normal
1162 $cflist delete 0.0 end
1164 $cflist insert end $first
1166 $cflist tag add highlight 1.0 "1.0 lineend"
1168 catch {unset cflist_top}
1170 $cflist conf -state disabled
1171 set difffilestart {}
1174 proc highlight_tag {f} {
1175 global highlight_paths
1177 foreach p $highlight_paths {
1178 if {[string match $p $f]} {
1185 proc highlight_filelist {} {
1186 global cmitmode cflist
1188 $cflist conf -state normal
1189 if {$cmitmode ne "tree"} {
1190 set end [lindex [split [$cflist index end] .] 0]
1191 for {set l 2} {$l < $end} {incr l} {
1192 set line [$cflist get $l.0 "$l.0 lineend"]
1193 if {[highlight_tag $line] ne {}} {
1194 $cflist tag add bold $l.0 "$l.0 lineend"
1200 $cflist conf -state disabled
1203 proc unhighlight_filelist {} {
1206 $cflist conf -state normal
1207 $cflist tag remove bold 1.0 end
1208 $cflist conf -state disabled
1211 proc add_flist {fl} {
1214 $cflist conf -state normal
1216 $cflist insert end "\n"
1217 $cflist insert end $f [highlight_tag $f]
1219 $cflist conf -state disabled
1222 proc sel_flist {w x y} {
1223 global ctext difffilestart cflist cflist_top cmitmode
1225 if {$cmitmode eq "tree"} return
1226 if {![info exists cflist_top]} return
1227 set l [lindex [split [$w index "@$x,$y"] "."] 0]
1228 $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend"
1229 $cflist tag add highlight $l.0 "$l.0 lineend"
1234 catch {$ctext yview [lindex $difffilestart [expr {$l - 2}]]}
1238 # Functions for adding and removing shell-type quoting
1240 proc shellquote {str} {
1241 if {![string match "*\['\"\\ \t]*" $str]} {
1244 if {![string match "*\['\"\\]*" $str]} {
1247 if {![string match "*'*" $str]} {
1250 return "\"[string map {\" \\\" \\ \\\\} $str]\""
1253 proc shellarglist {l} {
1259 append str [shellquote $a]
1264 proc shelldequote {str} {
1269 if {![regexp -start $used -indices "\['\"\\\\ \t]" $str first]} {
1270 append ret [string range $str $used end]
1271 set used [string length $str]
1274 set first [lindex $first 0]
1275 set ch [string index $str $first]
1276 if {$first > $used} {
1277 append ret [string range $str $used [expr {$first - 1}]]
1280 if {$ch eq " " || $ch eq "\t"} break
1283 set first [string first "'" $str $used]
1285 error "unmatched single-quote"
1287 append ret [string range $str $used [expr {$first - 1}]]
1292 if {$used >= [string length $str]} {
1293 error "trailing backslash"
1295 append ret [string index $str $used]
1300 if {![regexp -start $used -indices "\[\"\\\\]" $str first]} {
1301 error "unmatched double-quote"
1303 set first [lindex $first 0]
1304 set ch [string index $str $first]
1305 if {$first > $used} {
1306 append ret [string range $str $used [expr {$first - 1}]]
1309 if {$ch eq "\""} break
1311 append ret [string index $str $used]
1315 return [list $used $ret]
1318 proc shellsplit {str} {
1321 set str [string trimleft $str]
1322 if {$str eq {}} break
1323 set dq [shelldequote $str]
1324 set n [lindex $dq 0]
1325 set word [lindex $dq 1]
1326 set str [string range $str $n end]
1332 # Code to implement multiple views
1334 proc newview {ishighlight} {
1335 global nextviewnum newviewname newviewperm uifont newishighlight
1336 global newviewargs revtreeargs
1338 set newishighlight $ishighlight
1340 if {[winfo exists $top]} {
1344 set newviewname($nextviewnum) "View $nextviewnum"
1345 set newviewperm($nextviewnum) 0
1346 set newviewargs($nextviewnum) [shellarglist $revtreeargs]
1347 vieweditor $top $nextviewnum "Gitk view definition"
1352 global viewname viewperm newviewname newviewperm
1353 global viewargs newviewargs
1355 set top .gitkvedit-$curview
1356 if {[winfo exists $top]} {
1360 set newviewname($curview) $viewname($curview)
1361 set newviewperm($curview) $viewperm($curview)
1362 set newviewargs($curview) [shellarglist $viewargs($curview)]
1363 vieweditor $top $curview "Gitk: edit view $viewname($curview)"
1366 proc vieweditor {top n title} {
1367 global newviewname newviewperm viewfiles
1371 wm title $top $title
1372 label $top.nl -text "Name" -font $uifont
1373 entry $top.name -width 20 -textvariable newviewname($n)
1374 grid $top.nl $top.name -sticky w -pady 5
1375 checkbutton $top.perm -text "Remember this view" -variable newviewperm($n)
1376 grid $top.perm - -pady 5 -sticky w
1377 message $top.al -aspect 1000 -font $uifont \
1378 -text "Commits to include (arguments to git-rev-list):"
1379 grid $top.al - -sticky w -pady 5
1380 entry $top.args -width 50 -textvariable newviewargs($n) \
1382 grid $top.args - -sticky ew -padx 5
1383 message $top.l -aspect 1000 -font $uifont \
1384 -text "Enter files and directories to include, one per line:"
1385 grid $top.l - -sticky w
1386 text $top.t -width 40 -height 10 -background white
1387 if {[info exists viewfiles($n)]} {
1388 foreach f $viewfiles($n) {
1389 $top.t insert end $f
1390 $top.t insert end "\n"
1392 $top.t delete {end - 1c} end
1393 $top.t mark set insert 0.0
1395 grid $top.t - -sticky ew -padx 5
1397 button $top.buts.ok -text "OK" -command [list newviewok $top $n]
1398 button $top.buts.can -text "Cancel" -command [list destroy $top]
1399 grid $top.buts.ok $top.buts.can
1400 grid columnconfigure $top.buts 0 -weight 1 -uniform a
1401 grid columnconfigure $top.buts 1 -weight 1 -uniform a
1402 grid $top.buts - -pady 10 -sticky ew
1406 proc doviewmenu {m first cmd op argv} {
1407 set nmenu [$m index end]
1408 for {set i $first} {$i <= $nmenu} {incr i} {
1409 if {[$m entrycget $i -command] eq $cmd} {
1410 eval $m $op $i $argv
1416 proc allviewmenus {n op args} {
1419 doviewmenu .bar.view 7 [list showview $n] $op $args
1420 doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args
1423 proc newviewok {top n} {
1424 global nextviewnum newviewperm newviewname newishighlight
1425 global viewname viewfiles viewperm selectedview curview
1426 global viewargs newviewargs viewhlmenu
1429 set newargs [shellsplit $newviewargs($n)]
1431 error_popup "Error in commit selection arguments: $err"
1437 foreach f [split [$top.t get 0.0 end] "\n"] {
1438 set ft [string trim $f]
1443 if {![info exists viewfiles($n)]} {
1444 # creating a new view
1446 set viewname($n) $newviewname($n)
1447 set viewperm($n) $newviewperm($n)
1448 set viewfiles($n) $files
1449 set viewargs($n) $newargs
1451 if {!$newishighlight} {
1452 after idle showview $n
1454 after idle addvhighlight $n
1457 # editing an existing view
1458 set viewperm($n) $newviewperm($n)
1459 if {$newviewname($n) ne $viewname($n)} {
1460 set viewname($n) $newviewname($n)
1461 doviewmenu .bar.view 7 [list showview $n] \
1462 entryconf [list -label $viewname($n)]
1463 doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
1464 entryconf [list -label $viewname($n) -value $viewname($n)]
1466 if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} {
1467 set viewfiles($n) $files
1468 set viewargs($n) $newargs
1469 if {$curview == $n} {
1470 after idle updatecommits
1474 catch {destroy $top}
1478 global curview viewdata viewperm hlview selectedhlview
1480 if {$curview == 0} return
1481 if {[info exists hlview] && $hlview == $curview} {
1482 set selectedhlview None
1485 allviewmenus $curview delete
1486 set viewdata($curview) {}
1487 set viewperm($curview) 0
1491 proc addviewmenu {n} {
1492 global viewname viewhlmenu
1494 .bar.view add radiobutton -label $viewname($n) \
1495 -command [list showview $n] -variable selectedview -value $n
1496 $viewhlmenu add radiobutton -label $viewname($n) \
1497 -command [list addvhighlight $n] -variable selectedhlview
1500 proc flatten {var} {
1504 foreach i [array names $var] {
1505 lappend ret $i [set $var\($i\)]
1510 proc unflatten {var l} {
1520 global curview viewdata viewfiles
1521 global displayorder parentlist childlist rowidlist rowoffsets
1522 global colormap rowtextx commitrow nextcolor canvxmax
1523 global numcommits rowrangelist commitlisted idrowranges
1524 global selectedline currentid canv canvy0
1525 global matchinglines treediffs
1526 global pending_select phase
1527 global commitidx rowlaidout rowoptim linesegends
1528 global commfd nextupdate
1530 global vparentlist vchildlist vdisporder vcmitlisted
1531 global hlview selectedhlview
1533 if {$n == $curview} return
1535 if {[info exists selectedline]} {
1536 set selid $currentid
1537 set y [yc $selectedline]
1538 set ymax [lindex [$canv cget -scrollregion] 3]
1539 set span [$canv yview]
1540 set ytop [expr {[lindex $span 0] * $ymax}]
1541 set ybot [expr {[lindex $span 1] * $ymax}]
1542 if {$ytop < $y && $y < $ybot} {
1543 set yscreen [expr {$y - $ytop}]
1545 set yscreen [expr {($ybot - $ytop) / 2}]
1551 if {$curview >= 0} {
1552 set vparentlist($curview) $parentlist
1553 set vchildlist($curview) $childlist
1554 set vdisporder($curview) $displayorder
1555 set vcmitlisted($curview) $commitlisted
1557 set viewdata($curview) \
1558 [list $phase $rowidlist $rowoffsets $rowrangelist \
1559 [flatten idrowranges] [flatten idinlist] \
1560 $rowlaidout $rowoptim $numcommits $linesegends]
1561 } elseif {![info exists viewdata($curview)]
1562 || [lindex $viewdata($curview) 0] ne {}} {
1563 set viewdata($curview) \
1564 [list {} $rowidlist $rowoffsets $rowrangelist]
1567 catch {unset matchinglines}
1568 catch {unset treediffs}
1570 if {[info exists hlview] && $hlview == $n} {
1572 set selectedhlview None
1577 .bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}]
1578 .bar.view entryconf 3 -state [expr {$n == 0? "disabled": "normal"}]
1580 if {![info exists viewdata($n)]} {
1581 set pending_select $selid
1587 set phase [lindex $v 0]
1588 set displayorder $vdisporder($n)
1589 set parentlist $vparentlist($n)
1590 set childlist $vchildlist($n)
1591 set commitlisted $vcmitlisted($n)
1592 set rowidlist [lindex $v 1]
1593 set rowoffsets [lindex $v 2]
1594 set rowrangelist [lindex $v 3]
1596 set numcommits [llength $displayorder]
1597 catch {unset idrowranges}
1599 unflatten idrowranges [lindex $v 4]
1600 unflatten idinlist [lindex $v 5]
1601 set rowlaidout [lindex $v 6]
1602 set rowoptim [lindex $v 7]
1603 set numcommits [lindex $v 8]
1604 set linesegends [lindex $v 9]
1607 catch {unset colormap}
1608 catch {unset rowtextx}
1610 set canvxmax [$canv cget -width]
1616 if {$selid ne {} && [info exists commitrow($n,$selid)]} {
1617 set row $commitrow($n,$selid)
1618 # try to get the selected row in the same position on the screen
1619 set ymax [lindex [$canv cget -scrollregion] 3]
1620 set ytop [expr {[yc $row] - $yscreen}]
1624 set yf [expr {$ytop * 1.0 / $ymax}]
1626 allcanvs yview moveto $yf
1630 if {$phase eq "getcommits"} {
1631 show_status "Reading commits..."
1633 if {[info exists commfd($n)]} {
1638 } elseif {$numcommits == 0} {
1639 show_status "No commits selected"
1643 # Stuff relating to the highlighting facility
1645 proc ishighlighted {row} {
1646 global vhighlights fhighlights nhighlights
1648 if {[info exists nhighlights($row)] && $nhighlights($row) > 0} {
1649 return $nhighlights($row)
1651 if {[info exists vhighlights($row)] && $vhighlights($row) > 0} {
1652 return $vhighlights($row)
1654 if {[info exists fhighlights($row)] && $fhighlights($row) > 0} {
1655 return $fhighlights($row)
1660 proc bolden {row font} {
1661 global canv linehtag selectedline
1663 $canv itemconf $linehtag($row) -font $font
1664 if {$row == $selectedline} {
1666 set t [eval $canv create rect [$canv bbox $linehtag($row)] \
1667 -outline {{}} -tags secsel \
1668 -fill [$canv cget -selectbackground]]
1673 proc bolden_name {row font} {
1674 global canv2 linentag selectedline
1676 $canv2 itemconf $linentag($row) -font $font
1677 if {$row == $selectedline} {
1678 $canv2 delete secsel
1679 set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \
1680 -outline {{}} -tags secsel \
1681 -fill [$canv2 cget -selectbackground]]
1686 proc unbolden {rows} {
1690 if {![ishighlighted $row]} {
1691 bolden $row $mainfont
1696 proc addvhighlight {n} {
1697 global hlview curview viewdata vhl_done vhighlights commitidx
1699 if {[info exists hlview]} {
1703 if {$n != $curview && ![info exists viewdata($n)]} {
1704 set viewdata($n) [list getcommits {{}} {{}} {} {} {} 0 0 0 {}]
1705 set vparentlist($n) {}
1706 set vchildlist($n) {}
1707 set vdisporder($n) {}
1708 set vcmitlisted($n) {}
1711 set vhl_done $commitidx($hlview)
1712 if {$vhl_done > 0} {
1717 proc delvhighlight {} {
1718 global hlview vhighlights
1721 if {![info exists hlview]} return
1723 set rows [array names vhighlights]
1730 proc vhighlightmore {} {
1731 global hlview vhl_done commitidx vhighlights
1732 global displayorder vdisporder curview mainfont
1734 set font [concat $mainfont bold]
1735 set max $commitidx($hlview)
1736 if {$hlview == $curview} {
1737 set disp $displayorder
1739 set disp $vdisporder($hlview)
1741 set vr [visiblerows]
1742 set r0 [lindex $vr 0]
1743 set r1 [lindex $vr 1]
1744 for {set i $vhl_done} {$i < $max} {incr i} {
1745 set id [lindex $disp $i]
1746 if {[info exists commitrow($curview,$id)]} {
1747 set row $commitrow($curview,$id)
1748 if {$r0 <= $row && $row <= $r1} {
1749 if {![highlighted $row]} {
1752 set vhighlights($row) 1
1759 proc askvhighlight {row id} {
1760 global hlview vhighlights commitrow iddrawn mainfont
1762 if {[info exists commitrow($hlview,$id)]} {
1763 if {[info exists iddrawn($id)] && ![ishighlighted $row]} {
1764 bolden $row [concat $mainfont bold]
1766 set vhighlights($row) 1
1768 set vhighlights($row) 0
1772 proc hfiles_change {name ix op} {
1773 global highlight_files filehighlight fhighlights fh_serial
1774 global mainfont highlight_paths
1776 if {[info exists filehighlight]} {
1777 # delete previous highlights
1778 catch {close $filehighlight}
1780 set rows [array names fhighlights]
1785 unhighlight_filelist
1787 set highlight_paths {}
1788 after cancel do_file_hl $fh_serial
1790 if {$highlight_files ne {}} {
1791 after 300 do_file_hl $fh_serial
1795 proc makepatterns {l} {
1798 set ee [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} $e]
1799 if {[string index $ee end] eq "/"} {
1809 proc do_file_hl {serial} {
1810 global highlight_files filehighlight highlight_paths
1812 if {[catch {set paths [shellsplit $highlight_files]}]} return
1813 set highlight_paths [makepatterns $paths]
1815 set cmd [concat | git-diff-tree -r -s --stdin -- $paths]
1816 set filehighlight [open $cmd r+]
1817 fconfigure $filehighlight -blocking 0
1818 fileevent $filehighlight readable readfhighlight
1823 proc flushhighlights {} {
1824 global filehighlight
1826 if {[info exists filehighlight]} {
1827 puts $filehighlight ""
1828 flush $filehighlight
1832 proc askfilehighlight {row id} {
1833 global filehighlight fhighlights
1835 set fhighlights($row) 0
1836 puts $filehighlight $id
1839 proc readfhighlight {} {
1840 global filehighlight fhighlights commitrow curview mainfont iddrawn
1842 set n [gets $filehighlight line]
1844 if {[eof $filehighlight]} {
1846 puts "oops, git-diff-tree died"
1847 catch {close $filehighlight}
1852 set line [string trim $line]
1853 if {$line eq {}} return
1854 if {![info exists commitrow($curview,$line)]} return
1855 set row $commitrow($curview,$line)
1856 if {[info exists iddrawn($line)] && ![ishighlighted $row]} {
1857 bolden $row [concat $mainfont bold]
1859 set fhighlights($row) 1
1862 proc hnames_change {name ix op} {
1863 global highlight_names nhighlights nhl_names mainfont
1865 # delete previous highlights, if any
1866 set rows [array names nhighlights]
1869 if {$nhighlights($row) >= 2} {
1870 bolden_name $row $mainfont
1876 if {[catch {set nhl_names [shellsplit $highlight_names]}]} {
1883 proc asknamehighlight {row id} {
1884 global nhl_names nhighlights commitinfo iddrawn mainfont
1886 if {![info exists commitinfo($id)]} {
1890 set author [lindex $commitinfo($id) 1]
1891 set committer [lindex $commitinfo($id) 3]
1892 foreach name $nhl_names {
1893 set pattern "*$name*"
1894 if {[string match -nocase $pattern $author]} {
1898 if {!$isbold && [string match -nocase $pattern $committer]} {
1902 if {[info exists iddrawn($id)]} {
1903 if {$isbold && ![ishighlighted $row]} {
1904 bolden $row [concat $mainfont bold]
1907 bolden_name $row [concat $mainfont bold]
1910 set nhighlights($row) $isbold
1913 # Graph layout functions
1915 proc shortids {ids} {
1918 if {[llength $id] > 1} {
1919 lappend res [shortids $id]
1920 } elseif {[regexp {^[0-9a-f]{40}$} $id]} {
1921 lappend res [string range $id 0 7]
1929 proc incrange {l x o} {
1932 set e [lindex $l $x]
1934 lset l $x [expr {$e + $o}]
1943 for {} {$n > 0} {incr n -1} {
1949 proc usedinrange {id l1 l2} {
1950 global children commitrow childlist curview
1952 if {[info exists commitrow($curview,$id)]} {
1953 set r $commitrow($curview,$id)
1954 if {$l1 <= $r && $r <= $l2} {
1955 return [expr {$r - $l1 + 1}]
1957 set kids [lindex $childlist $r]
1959 set kids $children($curview,$id)
1962 set r $commitrow($curview,$c)
1963 if {$l1 <= $r && $r <= $l2} {
1964 return [expr {$r - $l1 + 1}]
1970 proc sanity {row {full 0}} {
1971 global rowidlist rowoffsets
1974 set ids [lindex $rowidlist $row]
1977 if {$id eq {}} continue
1978 if {$col < [llength $ids] - 1 &&
1979 [lsearch -exact -start [expr {$col+1}] $ids $id] >= 0} {
1980 puts "oops: [shortids $id] repeated in row $row col $col: {[shortids [lindex $rowidlist $row]]}"
1982 set o [lindex $rowoffsets $row $col]
1988 if {[lindex $rowidlist $y $x] != $id} {
1989 puts "oops: rowoffsets wrong at row [expr {$y+1}] col [expr {$x-$o}]"
1990 puts " id=[shortids $id] check started at row $row"
1991 for {set i $row} {$i >= $y} {incr i -1} {
1992 puts " row $i ids={[shortids [lindex $rowidlist $i]]} offs={[lindex $rowoffsets $i]}"
1997 set o [lindex $rowoffsets $y $x]
2002 proc makeuparrow {oid x y z} {
2003 global rowidlist rowoffsets uparrowlen idrowranges
2005 for {set i 1} {$i < $uparrowlen && $y > 1} {incr i} {
2008 set off0 [lindex $rowoffsets $y]
2009 for {set x0 $x} {1} {incr x0} {
2010 if {$x0 >= [llength $off0]} {
2011 set x0 [llength [lindex $rowoffsets [expr {$y-1}]]]
2014 set z [lindex $off0 $x0]
2020 set z [expr {$x0 - $x}]
2021 lset rowidlist $y [linsert [lindex $rowidlist $y] $x $oid]
2022 lset rowoffsets $y [linsert [lindex $rowoffsets $y] $x $z]
2024 set tmp [lreplace [lindex $rowoffsets $y] $x $x {}]
2025 lset rowoffsets $y [incrange $tmp [expr {$x+1}] -1]
2026 lappend idrowranges($oid) $y
2029 proc initlayout {} {
2030 global rowidlist rowoffsets displayorder commitlisted
2031 global rowlaidout rowoptim
2032 global idinlist rowchk rowrangelist idrowranges
2033 global numcommits canvxmax canv
2035 global parentlist childlist children
2036 global colormap rowtextx
2048 catch {unset idinlist}
2049 catch {unset rowchk}
2052 set canvxmax [$canv cget -width]
2053 catch {unset colormap}
2054 catch {unset rowtextx}
2055 catch {unset idrowranges}
2059 proc setcanvscroll {} {
2060 global canv canv2 canv3 numcommits linespc canvxmax canvy0
2062 set ymax [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]
2063 $canv conf -scrollregion [list 0 0 $canvxmax $ymax]
2064 $canv2 conf -scrollregion [list 0 0 0 $ymax]
2065 $canv3 conf -scrollregion [list 0 0 0 $ymax]
2068 proc visiblerows {} {
2069 global canv numcommits linespc
2071 set ymax [lindex [$canv cget -scrollregion] 3]
2072 if {$ymax eq {} || $ymax == 0} return
2074 set y0 [expr {int([lindex $f 0] * $ymax)}]
2075 set r0 [expr {int(($y0 - 3) / $linespc) - 1}]
2079 set y1 [expr {int([lindex $f 1] * $ymax)}]
2080 set r1 [expr {int(($y1 - 3) / $linespc) + 1}]
2081 if {$r1 >= $numcommits} {
2082 set r1 [expr {$numcommits - 1}]
2084 return [list $r0 $r1]
2087 proc layoutmore {} {
2088 global rowlaidout rowoptim commitidx numcommits optim_delay
2089 global uparrowlen curview
2092 set rowlaidout [layoutrows $row $commitidx($curview) 0]
2093 set orow [expr {$rowlaidout - $uparrowlen - 1}]
2094 if {$orow > $rowoptim} {
2095 optimize_rows $rowoptim 0 $orow
2098 set canshow [expr {$rowoptim - $optim_delay}]
2099 if {$canshow > $numcommits} {
2104 proc showstuff {canshow} {
2105 global numcommits commitrow pending_select selectedline
2106 global linesegends idrowranges idrangedrawn curview
2108 if {$numcommits == 0} {
2110 set phase "incrdraw"
2114 set numcommits $canshow
2116 set rows [visiblerows]
2117 set r0 [lindex $rows 0]
2118 set r1 [lindex $rows 1]
2120 for {set r $row} {$r < $canshow} {incr r} {
2121 foreach id [lindex $linesegends [expr {$r+1}]] {
2123 foreach {s e} [rowranges $id] {
2125 if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
2126 && ![info exists idrangedrawn($id,$i)]} {
2128 set idrangedrawn($id,$i) 1
2133 if {$canshow > $r1} {
2136 while {$row < $canshow} {
2140 if {[info exists pending_select] &&
2141 [info exists commitrow($curview,$pending_select)] &&
2142 $commitrow($curview,$pending_select) < $numcommits} {
2143 selectline $commitrow($curview,$pending_select) 1
2145 if {![info exists selectedline] && ![info exists pending_select]} {
2150 proc layoutrows {row endrow last} {
2151 global rowidlist rowoffsets displayorder
2152 global uparrowlen downarrowlen maxwidth mingaplen
2153 global childlist parentlist
2154 global idrowranges linesegends
2155 global commitidx curview
2156 global idinlist rowchk rowrangelist
2158 set idlist [lindex $rowidlist $row]
2159 set offs [lindex $rowoffsets $row]
2160 while {$row < $endrow} {
2161 set id [lindex $displayorder $row]
2164 foreach p [lindex $parentlist $row] {
2165 if {![info exists idinlist($p)]} {
2167 } elseif {!$idinlist($p)} {
2172 set nev [expr {[llength $idlist] + [llength $newolds]
2173 + [llength $oldolds] - $maxwidth + 1}]
2176 $row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
2177 for {set x [llength $idlist]} {[incr x -1] >= 0} {} {
2178 set i [lindex $idlist $x]
2179 if {![info exists rowchk($i)] || $row >= $rowchk($i)} {
2180 set r [usedinrange $i [expr {$row - $downarrowlen}] \
2181 [expr {$row + $uparrowlen + $mingaplen}]]
2183 set idlist [lreplace $idlist $x $x]
2184 set offs [lreplace $offs $x $x]
2185 set offs [incrange $offs $x 1]
2187 set rm1 [expr {$row - 1}]
2189 lappend idrowranges($i) $rm1
2190 if {[incr nev -1] <= 0} break
2193 set rowchk($id) [expr {$row + $r}]
2196 lset rowidlist $row $idlist
2197 lset rowoffsets $row $offs
2199 lappend linesegends $lse
2200 set col [lsearch -exact $idlist $id]
2202 set col [llength $idlist]
2204 lset rowidlist $row $idlist
2206 if {[lindex $childlist $row] ne {}} {
2207 set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
2211 lset rowoffsets $row $offs
2213 makeuparrow $id $col $row $z
2219 if {[info exists idrowranges($id)]} {
2220 set ranges $idrowranges($id)
2222 unset idrowranges($id)
2224 lappend rowrangelist $ranges
2226 set offs [ntimes [llength $idlist] 0]
2227 set l [llength $newolds]
2228 set idlist [eval lreplace \$idlist $col $col $newolds]
2231 set offs [lrange $offs 0 [expr {$col - 1}]]
2232 foreach x $newolds {
2237 set tmp [expr {[llength $idlist] - [llength $offs]}]
2239 set offs [concat $offs [ntimes $tmp $o]]
2244 foreach i $newolds {
2246 set idrowranges($i) $row
2249 foreach oid $oldolds {
2250 set idinlist($oid) 1
2251 set idlist [linsert $idlist $col $oid]
2252 set offs [linsert $offs $col $o]
2253 makeuparrow $oid $col $row $o
2256 lappend rowidlist $idlist
2257 lappend rowoffsets $offs
2262 proc addextraid {id row} {
2263 global displayorder commitrow commitinfo
2264 global commitidx commitlisted
2265 global parentlist childlist children curview
2267 incr commitidx($curview)
2268 lappend displayorder $id
2269 lappend commitlisted 0
2270 lappend parentlist {}
2271 set commitrow($curview,$id) $row
2273 if {![info exists commitinfo($id)]} {
2274 set commitinfo($id) {"No commit information available"}
2276 if {![info exists children($curview,$id)]} {
2277 set children($curview,$id) {}
2279 lappend childlist $children($curview,$id)
2282 proc layouttail {} {
2283 global rowidlist rowoffsets idinlist commitidx curview
2284 global idrowranges rowrangelist
2286 set row $commitidx($curview)
2287 set idlist [lindex $rowidlist $row]
2288 while {$idlist ne {}} {
2289 set col [expr {[llength $idlist] - 1}]
2290 set id [lindex $idlist $col]
2293 lappend idrowranges($id) $row
2294 lappend rowrangelist $idrowranges($id)
2295 unset idrowranges($id)
2297 set offs [ntimes $col 0]
2298 set idlist [lreplace $idlist $col $col]
2299 lappend rowidlist $idlist
2300 lappend rowoffsets $offs
2303 foreach id [array names idinlist] {
2305 lset rowidlist $row [list $id]
2306 lset rowoffsets $row 0
2307 makeuparrow $id 0 $row 0
2308 lappend idrowranges($id) $row
2309 lappend rowrangelist $idrowranges($id)
2310 unset idrowranges($id)
2312 lappend rowidlist {}
2313 lappend rowoffsets {}
2317 proc insert_pad {row col npad} {
2318 global rowidlist rowoffsets
2320 set pad [ntimes $npad {}]
2321 lset rowidlist $row [eval linsert [list [lindex $rowidlist $row]] $col $pad]
2322 set tmp [eval linsert [list [lindex $rowoffsets $row]] $col $pad]
2323 lset rowoffsets $row [incrange $tmp [expr {$col + $npad}] [expr {-$npad}]]
2326 proc optimize_rows {row col endrow} {
2327 global rowidlist rowoffsets idrowranges displayorder
2329 for {} {$row < $endrow} {incr row} {
2330 set idlist [lindex $rowidlist $row]
2331 set offs [lindex $rowoffsets $row]
2333 for {} {$col < [llength $offs]} {incr col} {
2334 if {[lindex $idlist $col] eq {}} {
2338 set z [lindex $offs $col]
2339 if {$z eq {}} continue
2341 set x0 [expr {$col + $z}]
2342 set y0 [expr {$row - 1}]
2343 set z0 [lindex $rowoffsets $y0 $x0]
2345 set id [lindex $idlist $col]
2346 set ranges [rowranges $id]
2347 if {$ranges ne {} && $y0 > [lindex $ranges 0]} {
2351 if {$z < -1 || ($z < 0 && $isarrow)} {
2352 set npad [expr {-1 - $z + $isarrow}]
2353 set offs [incrange $offs $col $npad]
2354 insert_pad $y0 $x0 $npad
2356 optimize_rows $y0 $x0 $row
2358 set z [lindex $offs $col]
2359 set x0 [expr {$col + $z}]
2360 set z0 [lindex $rowoffsets $y0 $x0]
2361 } elseif {$z > 1 || ($z > 0 && $isarrow)} {
2362 set npad [expr {$z - 1 + $isarrow}]
2363 set y1 [expr {$row + 1}]
2364 set offs2 [lindex $rowoffsets $y1]
2368 if {$z eq {} || $x1 + $z < $col} continue
2369 if {$x1 + $z > $col} {
2372 lset rowoffsets $y1 [incrange $offs2 $x1 $npad]
2375 set pad [ntimes $npad {}]
2376 set idlist [eval linsert \$idlist $col $pad]
2377 set tmp [eval linsert \$offs $col $pad]
2379 set offs [incrange $tmp $col [expr {-$npad}]]
2380 set z [lindex $offs $col]
2383 if {$z0 eq {} && !$isarrow} {
2384 # this line links to its first child on row $row-2
2385 set rm2 [expr {$row - 2}]
2386 set id [lindex $displayorder $rm2]
2387 set xc [lsearch -exact [lindex $rowidlist $rm2] $id]
2389 set z0 [expr {$xc - $x0}]
2392 if {$z0 ne {} && $z < 0 && $z0 > 0} {
2393 insert_pad $y0 $x0 1
2394 set offs [incrange $offs $col 1]
2395 optimize_rows $y0 [expr {$x0 + 1}] $row
2400 for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
2401 set o [lindex $offs $col]
2403 # check if this is the link to the first child
2404 set id [lindex $idlist $col]
2405 set ranges [rowranges $id]
2406 if {$ranges ne {} && $row == [lindex $ranges 0]} {
2407 # it is, work out offset to child
2408 set y0 [expr {$row - 1}]
2409 set id [lindex $displayorder $y0]
2410 set x0 [lsearch -exact [lindex $rowidlist $y0] $id]
2412 set o [expr {$x0 - $col}]
2416 if {$o eq {} || $o <= 0} break
2418 if {$o ne {} && [incr col] < [llength $idlist]} {
2419 set y1 [expr {$row + 1}]
2420 set offs2 [lindex $rowoffsets $y1]
2424 if {$z eq {} || $x1 + $z < $col} continue
2425 lset rowoffsets $y1 [incrange $offs2 $x1 1]
2428 set idlist [linsert $idlist $col {}]
2429 set tmp [linsert $offs $col {}]
2431 set offs [incrange $tmp $col -1]
2434 lset rowidlist $row $idlist
2435 lset rowoffsets $row $offs
2441 global canvx0 linespc
2442 return [expr {$canvx0 + $col * $linespc}]
2446 global canvy0 linespc
2447 return [expr {$canvy0 + $row * $linespc}]
2450 proc linewidth {id} {
2451 global thickerline lthickness
2454 if {[info exists thickerline] && $id eq $thickerline} {
2455 set wid [expr {2 * $lthickness}]
2460 proc rowranges {id} {
2461 global phase idrowranges commitrow rowlaidout rowrangelist curview
2465 ([info exists commitrow($curview,$id)]
2466 && $commitrow($curview,$id) < $rowlaidout)} {
2467 set ranges [lindex $rowrangelist $commitrow($curview,$id)]
2468 } elseif {[info exists idrowranges($id)]} {
2469 set ranges $idrowranges($id)
2474 proc drawlineseg {id i} {
2475 global rowoffsets rowidlist
2477 global canv colormap linespc
2478 global numcommits commitrow curview
2480 set ranges [rowranges $id]
2482 if {[info exists commitrow($curview,$id)]
2483 && $commitrow($curview,$id) < $numcommits} {
2484 set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
2488 set startrow [lindex $ranges [expr {2 * $i}]]
2489 set row [lindex $ranges [expr {2 * $i + 1}]]
2490 if {$startrow == $row} return
2493 set col [lsearch -exact [lindex $rowidlist $row] $id]
2495 puts "oops: drawline: id $id not on row $row"
2501 set o [lindex $rowoffsets $row $col]
2504 # changing direction
2505 set x [xc $row $col]
2507 lappend coords $x $y
2513 set x [xc $row $col]
2515 lappend coords $x $y
2517 # draw the link to the first child as part of this line
2519 set child [lindex $displayorder $row]
2520 set ccol [lsearch -exact [lindex $rowidlist $row] $child]
2522 set x [xc $row $ccol]
2524 if {$ccol < $col - 1} {
2525 lappend coords [xc $row [expr {$col - 1}]] [yc $row]
2526 } elseif {$ccol > $col + 1} {
2527 lappend coords [xc $row [expr {$col + 1}]] [yc $row]
2529 lappend coords $x $y
2532 if {[llength $coords] < 4} return
2534 # This line has an arrow at the lower end: check if the arrow is
2535 # on a diagonal segment, and if so, work around the Tk 8.4
2536 # refusal to draw arrows on diagonal lines.
2537 set x0 [lindex $coords 0]
2538 set x1 [lindex $coords 2]
2540 set y0 [lindex $coords 1]
2541 set y1 [lindex $coords 3]
2542 if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
2543 # we have a nearby vertical segment, just trim off the diag bit
2544 set coords [lrange $coords 2 end]
2546 set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
2547 set xi [expr {$x0 - $slope * $linespc / 2}]
2548 set yi [expr {$y0 - $linespc / 2}]
2549 set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
2553 set arrow [expr {2 * ($i > 0) + $downarrow}]
2554 set arrow [lindex {none first last both} $arrow]
2555 set t [$canv create line $coords -width [linewidth $id] \
2556 -fill $colormap($id) -tags lines.$id -arrow $arrow]
2561 proc drawparentlinks {id row col olds} {
2562 global rowidlist canv colormap
2564 set row2 [expr {$row + 1}]
2565 set x [xc $row $col]
2568 set ids [lindex $rowidlist $row2]
2569 # rmx = right-most X coord used
2572 set i [lsearch -exact $ids $p]
2574 puts "oops, parent $p of $id not in list"
2577 set x2 [xc $row2 $i]
2581 set ranges [rowranges $p]
2582 if {$ranges ne {} && $row2 == [lindex $ranges 0]
2583 && $row2 < [lindex $ranges 1]} {
2584 # drawlineseg will do this one for us
2588 # should handle duplicated parents here...
2589 set coords [list $x $y]
2590 if {$i < $col - 1} {
2591 lappend coords [xc $row [expr {$i + 1}]] $y
2592 } elseif {$i > $col + 1} {
2593 lappend coords [xc $row [expr {$i - 1}]] $y
2595 lappend coords $x2 $y2
2596 set t [$canv create line $coords -width [linewidth $p] \
2597 -fill $colormap($p) -tags lines.$p]
2604 proc drawlines {id} {
2605 global colormap canv
2607 global children iddrawn commitrow rowidlist curview
2609 $canv delete lines.$id
2610 set nr [expr {[llength [rowranges $id]] / 2}]
2611 for {set i 0} {$i < $nr} {incr i} {
2612 if {[info exists idrangedrawn($id,$i)]} {
2616 foreach child $children($curview,$id) {
2617 if {[info exists iddrawn($child)]} {
2618 set row $commitrow($curview,$child)
2619 set col [lsearch -exact [lindex $rowidlist $row] $child]
2621 drawparentlinks $child $row $col [list $id]
2627 proc drawcmittext {id row col rmx} {
2628 global linespc canv canv2 canv3 canvy0
2629 global commitlisted commitinfo rowidlist
2630 global rowtextx idpos idtags idheads idotherrefs
2631 global linehtag linentag linedtag
2632 global mainfont canvxmax
2634 set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
2635 set x [xc $row $col]
2637 set orad [expr {$linespc / 3}]
2638 set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
2639 [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
2640 -fill $ofill -outline black -width 1]
2642 $canv bind $t <1> {selcanvline {} %x %y}
2643 set xt [xc $row [llength [lindex $rowidlist $row]]]
2647 set rowtextx($row) $xt
2648 set idpos($id) [list $x $xt $y]
2649 if {[info exists idtags($id)] || [info exists idheads($id)]
2650 || [info exists idotherrefs($id)]} {
2651 set xt [drawtags $id $x $xt $y]
2653 set headline [lindex $commitinfo($id) 0]
2654 set name [lindex $commitinfo($id) 1]
2655 set date [lindex $commitinfo($id) 2]
2656 set date [formatdate $date]
2659 set isbold [ishighlighted $row]
2666 set linehtag($row) [$canv create text $xt $y -anchor w \
2667 -text $headline -font $font]
2668 $canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id"
2669 set linentag($row) [$canv2 create text 3 $y -anchor w \
2670 -text $name -font $nfont]
2671 set linedtag($row) [$canv3 create text 3 $y -anchor w \
2672 -text $date -font $mainfont]
2673 set xr [expr {$xt + [font measure $mainfont $headline]}]
2674 if {$xr > $canvxmax} {
2680 proc drawcmitrow {row} {
2681 global displayorder rowidlist
2682 global idrangedrawn iddrawn
2683 global commitinfo parentlist numcommits
2684 global filehighlight fhighlights nhl_names nhighlights
2685 global hlview vhighlights
2687 if {$row >= $numcommits} return
2688 foreach id [lindex $rowidlist $row] {
2689 if {$id eq {}} continue
2691 foreach {s e} [rowranges $id] {
2693 if {$row < $s} continue
2696 if {$e < $numcommits && ![info exists idrangedrawn($id,$i)]} {
2698 set idrangedrawn($id,$i) 1
2705 set id [lindex $displayorder $row]
2706 if {[info exists hlview] && ![info exists vhighlights($row)]} {
2707 askvhighlight $row $id
2709 if {[info exists filehighlight] && ![info exists fhighlights($row)]} {
2710 askfilehighlight $row $id
2712 if {$nhl_names ne {} && ![info exists nhighlights($row)]} {
2713 asknamehighlight $row $id
2715 if {[info exists iddrawn($id)]} return
2716 set col [lsearch -exact [lindex $rowidlist $row] $id]
2718 puts "oops, row $row id $id not in list"
2721 if {![info exists commitinfo($id)]} {
2725 set olds [lindex $parentlist $row]
2727 set rmx [drawparentlinks $id $row $col $olds]
2731 drawcmittext $id $row $col $rmx
2735 proc drawfrac {f0 f1} {
2736 global numcommits canv
2739 set ymax [lindex [$canv cget -scrollregion] 3]
2740 if {$ymax eq {} || $ymax == 0} return
2741 set y0 [expr {int($f0 * $ymax)}]
2742 set row [expr {int(($y0 - 3) / $linespc) - 1}]
2746 set y1 [expr {int($f1 * $ymax)}]
2747 set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
2748 if {$endrow >= $numcommits} {
2749 set endrow [expr {$numcommits - 1}]
2751 for {} {$row <= $endrow} {incr row} {
2756 proc drawvisible {} {
2758 eval drawfrac [$canv yview]
2761 proc clear_display {} {
2762 global iddrawn idrangedrawn
2763 global vhighlights fhighlights nhighlights
2766 catch {unset iddrawn}
2767 catch {unset idrangedrawn}
2768 catch {unset vhighlights}
2769 catch {unset fhighlights}
2770 catch {unset nhighlights}
2773 proc findcrossings {id} {
2774 global rowidlist parentlist numcommits rowoffsets displayorder
2778 foreach {s e} [rowranges $id] {
2779 if {$e >= $numcommits} {
2780 set e [expr {$numcommits - 1}]
2782 if {$e <= $s} continue
2783 set x [lsearch -exact [lindex $rowidlist $e] $id]
2785 puts "findcrossings: oops, no [shortids $id] in row $e"
2788 for {set row $e} {[incr row -1] >= $s} {} {
2789 set olds [lindex $parentlist $row]
2790 set kid [lindex $displayorder $row]
2791 set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
2792 if {$kidx < 0} continue
2793 set nextrow [lindex $rowidlist [expr {$row + 1}]]
2795 set px [lsearch -exact $nextrow $p]
2796 if {$px < 0} continue
2797 if {($kidx < $x && $x < $px) || ($px < $x && $x < $kidx)} {
2798 if {[lsearch -exact $ccross $p] >= 0} continue
2799 if {$x == $px + ($kidx < $px? -1: 1)} {
2801 } elseif {[lsearch -exact $cross $p] < 0} {
2806 set inc [lindex $rowoffsets $row $x]
2807 if {$inc eq {}} break
2811 return [concat $ccross {{}} $cross]
2814 proc assigncolor {id} {
2815 global colormap colors nextcolor
2816 global commitrow parentlist children children curview
2818 if {[info exists colormap($id)]} return
2819 set ncolors [llength $colors]
2820 if {[info exists children($curview,$id)]} {
2821 set kids $children($curview,$id)
2825 if {[llength $kids] == 1} {
2826 set child [lindex $kids 0]
2827 if {[info exists colormap($child)]
2828 && [llength [lindex $parentlist $commitrow($curview,$child)]] == 1} {
2829 set colormap($id) $colormap($child)
2835 foreach x [findcrossings $id] {
2837 # delimiter between corner crossings and other crossings
2838 if {[llength $badcolors] >= $ncolors - 1} break
2839 set origbad $badcolors
2841 if {[info exists colormap($x)]
2842 && [lsearch -exact $badcolors $colormap($x)] < 0} {
2843 lappend badcolors $colormap($x)
2846 if {[llength $badcolors] >= $ncolors} {
2847 set badcolors $origbad
2849 set origbad $badcolors
2850 if {[llength $badcolors] < $ncolors - 1} {
2851 foreach child $kids {
2852 if {[info exists colormap($child)]
2853 && [lsearch -exact $badcolors $colormap($child)] < 0} {
2854 lappend badcolors $colormap($child)
2856 foreach p [lindex $parentlist $commitrow($curview,$child)] {
2857 if {[info exists colormap($p)]
2858 && [lsearch -exact $badcolors $colormap($p)] < 0} {
2859 lappend badcolors $colormap($p)
2863 if {[llength $badcolors] >= $ncolors} {
2864 set badcolors $origbad
2867 for {set i 0} {$i <= $ncolors} {incr i} {
2868 set c [lindex $colors $nextcolor]
2869 if {[incr nextcolor] >= $ncolors} {
2872 if {[lsearch -exact $badcolors $c]} break
2874 set colormap($id) $c
2877 proc bindline {t id} {
2880 $canv bind $t <Enter> "lineenter %x %y $id"
2881 $canv bind $t <Motion> "linemotion %x %y $id"
2882 $canv bind $t <Leave> "lineleave $id"
2883 $canv bind $t <Button-1> "lineclick %x %y $id 1"
2886 proc drawtags {id x xt y1} {
2887 global idtags idheads idotherrefs
2888 global linespc lthickness
2889 global canv mainfont commitrow rowtextx curview
2894 if {[info exists idtags($id)]} {
2895 set marks $idtags($id)
2896 set ntags [llength $marks]
2898 if {[info exists idheads($id)]} {
2899 set marks [concat $marks $idheads($id)]
2900 set nheads [llength $idheads($id)]
2902 if {[info exists idotherrefs($id)]} {
2903 set marks [concat $marks $idotherrefs($id)]
2909 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
2910 set yt [expr {$y1 - 0.5 * $linespc}]
2911 set yb [expr {$yt + $linespc - 1}]
2914 foreach tag $marks {
2915 set wid [font measure $mainfont $tag]
2918 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
2920 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
2921 -width $lthickness -fill black -tags tag.$id]
2923 foreach tag $marks x $xvals wid $wvals {
2924 set xl [expr {$x + $delta}]
2925 set xr [expr {$x + $delta + $wid + $lthickness}]
2926 if {[incr ntags -1] >= 0} {
2928 set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
2929 $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
2930 -width 1 -outline black -fill yellow -tags tag.$id]
2931 $canv bind $t <1> [list showtag $tag 1]
2932 set rowtextx($commitrow($curview,$id)) [expr {$xr + $linespc}]
2934 # draw a head or other ref
2935 if {[incr nheads -1] >= 0} {
2940 set xl [expr {$xl - $delta/2}]
2941 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
2942 -width 1 -outline black -fill $col -tags tag.$id
2943 if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
2944 set rwid [font measure $mainfont $remoteprefix]
2945 set xi [expr {$x + 1}]
2946 set yti [expr {$yt + 1}]
2947 set xri [expr {$x + $rwid}]
2948 $canv create polygon $xi $yti $xri $yti $xri $yb $xi $yb \
2949 -width 0 -fill "#ffddaa" -tags tag.$id
2952 set t [$canv create text $xl $y1 -anchor w -text $tag \
2953 -font $mainfont -tags tag.$id]
2955 $canv bind $t <1> [list showtag $tag 1]
2961 proc xcoord {i level ln} {
2962 global canvx0 xspc1 xspc2
2964 set x [expr {$canvx0 + $i * $xspc1($ln)}]
2965 if {$i > 0 && $i == $level} {
2966 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
2967 } elseif {$i > $level} {
2968 set x [expr {$x + $xspc2 - $xspc1($ln)}]
2973 proc show_status {msg} {
2974 global canv mainfont
2977 $canv create text 3 3 -anchor nw -text $msg -font $mainfont -tags textitems
2980 proc finishcommits {} {
2981 global commitidx phase curview
2982 global canv mainfont ctext maincursor textcursor
2983 global findinprogress pending_select
2985 if {$commitidx($curview) > 0} {
2988 show_status "No commits selected"
2991 catch {unset pending_select}
2994 # Don't change the text pane cursor if it is currently the hand cursor,
2995 # showing that we are over a sha1 ID link.
2996 proc settextcursor {c} {
2997 global ctext curtextcursor
2999 if {[$ctext cget -cursor] == $curtextcursor} {
3000 $ctext config -cursor $c
3002 set curtextcursor $c
3005 proc nowbusy {what} {
3008 if {[array names isbusy] eq {}} {
3009 . config -cursor watch
3015 proc notbusy {what} {
3016 global isbusy maincursor textcursor
3018 catch {unset isbusy($what)}
3019 if {[array names isbusy] eq {}} {
3020 . config -cursor $maincursor
3021 settextcursor $textcursor
3028 global canvy0 numcommits linespc
3029 global rowlaidout commitidx curview
3030 global pending_select
3033 layoutrows $rowlaidout $commitidx($curview) 1
3035 optimize_rows $row 0 $commitidx($curview)
3036 showstuff $commitidx($curview)
3037 if {[info exists pending_select]} {
3041 set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
3042 #puts "overall $drawmsecs ms for $numcommits commits"
3045 proc findmatches {f} {
3046 global findtype foundstring foundstrlen
3047 if {$findtype == "Regexp"} {
3048 set matches [regexp -indices -all -inline $foundstring $f]
3050 if {$findtype == "IgnCase"} {
3051 set str [string tolower $f]
3057 while {[set j [string first $foundstring $str $i]] >= 0} {
3058 lappend matches [list $j [expr {$j+$foundstrlen-1}]]
3059 set i [expr {$j + $foundstrlen}]
3066 global findtype findloc findstring markedmatches commitinfo
3067 global numcommits displayorder linehtag linentag linedtag
3068 global mainfont canv canv2 canv3 selectedline
3069 global matchinglines foundstring foundstrlen matchstring
3075 set matchinglines {}
3076 if {$findloc == "Pickaxe"} {
3080 if {$findtype == "IgnCase"} {
3081 set foundstring [string tolower $findstring]
3083 set foundstring $findstring
3085 set foundstrlen [string length $findstring]
3086 if {$foundstrlen == 0} return
3087 regsub -all {[*?\[\\]} $foundstring {\\&} matchstring
3088 set matchstring "*$matchstring*"
3089 if {$findloc == "Files"} {
3093 if {![info exists selectedline]} {
3096 set oldsel $selectedline
3099 set fldtypes {Headline Author Date Committer CDate Comment}
3101 foreach id $displayorder {
3102 set d $commitdata($id)
3104 if {$findtype == "Regexp"} {
3105 set doesmatch [regexp $foundstring $d]
3106 } elseif {$findtype == "IgnCase"} {
3107 set doesmatch [string match -nocase $matchstring $d]
3109 set doesmatch [string match $matchstring $d]
3111 if {!$doesmatch} continue
3112 if {![info exists commitinfo($id)]} {
3115 set info $commitinfo($id)
3117 foreach f $info ty $fldtypes {
3118 if {$findloc != "All fields" && $findloc != $ty} {
3121 set matches [findmatches $f]
3122 if {$matches == {}} continue
3124 if {$ty == "Headline"} {
3126 markmatches $canv $l $f $linehtag($l) $matches $mainfont
3127 } elseif {$ty == "Author"} {
3129 markmatches $canv2 $l $f $linentag($l) $matches $mainfont
3130 } elseif {$ty == "Date"} {
3132 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
3136 lappend matchinglines $l
3137 if {!$didsel && $l > $oldsel} {
3143 if {$matchinglines == {}} {
3145 } elseif {!$didsel} {
3146 findselectline [lindex $matchinglines 0]
3150 proc findselectline {l} {
3151 global findloc commentend ctext
3153 if {$findloc == "All fields" || $findloc == "Comments"} {
3154 # highlight the matches in the comments
3155 set f [$ctext get 1.0 $commentend]
3156 set matches [findmatches $f]
3157 foreach match $matches {
3158 set start [lindex $match 0]
3159 set end [expr {[lindex $match 1] + 1}]
3160 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
3165 proc findnext {restart} {
3166 global matchinglines selectedline
3167 if {![info exists matchinglines]} {
3173 if {![info exists selectedline]} return
3174 foreach l $matchinglines {
3175 if {$l > $selectedline} {
3184 global matchinglines selectedline
3185 if {![info exists matchinglines]} {
3189 if {![info exists selectedline]} return
3191 foreach l $matchinglines {
3192 if {$l >= $selectedline} break
3196 findselectline $prev
3202 proc findlocchange {name ix op} {
3203 global findloc findtype findtypemenu
3204 if {$findloc == "Pickaxe"} {
3210 $findtypemenu entryconf 1 -state $state
3211 $findtypemenu entryconf 2 -state $state
3214 proc stopfindproc {{done 0}} {
3215 global findprocpid findprocfile findids
3216 global ctext findoldcursor phase maincursor textcursor
3217 global findinprogress
3219 catch {unset findids}
3220 if {[info exists findprocpid]} {
3222 catch {exec kill $findprocpid}
3224 catch {close $findprocfile}
3227 catch {unset findinprogress}
3231 proc findpatches {} {
3232 global findstring selectedline numcommits
3233 global findprocpid findprocfile
3234 global finddidsel ctext displayorder findinprogress
3235 global findinsertpos
3237 if {$numcommits == 0} return
3239 # make a list of all the ids to search, starting at the one
3240 # after the selected line (if any)
3241 if {[info exists selectedline]} {
3247 for {set i 0} {$i < $numcommits} {incr i} {
3248 if {[incr l] >= $numcommits} {
3251 append inputids [lindex $displayorder $l] "\n"
3255 set f [open [list | git-diff-tree --stdin -s -r -S$findstring \
3258 error_popup "Error starting search process: $err"
3262 set findinsertpos end
3264 set findprocpid [pid $f]
3265 fconfigure $f -blocking 0
3266 fileevent $f readable readfindproc
3269 set findinprogress 1
3272 proc readfindproc {} {
3273 global findprocfile finddidsel
3274 global commitrow matchinglines findinsertpos curview
3276 set n [gets $findprocfile line]
3278 if {[eof $findprocfile]} {
3286 if {![regexp {^[0-9a-f]{40}} $line id]} {
3287 error_popup "Can't parse git-diff-tree output: $line"
3291 if {![info exists commitrow($curview,$id)]} {
3292 puts stderr "spurious id: $id"
3295 set l $commitrow($curview,$id)
3299 proc insertmatch {l id} {
3300 global matchinglines findinsertpos finddidsel
3302 if {$findinsertpos == "end"} {
3303 if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
3304 set matchinglines [linsert $matchinglines 0 $l]
3307 lappend matchinglines $l
3310 set matchinglines [linsert $matchinglines $findinsertpos $l]
3321 global selectedline numcommits displayorder ctext
3322 global ffileline finddidsel parentlist
3323 global findinprogress findstartline findinsertpos
3324 global treediffs fdiffid fdiffsneeded fdiffpos
3325 global findmergefiles
3327 if {$numcommits == 0} return
3329 if {[info exists selectedline]} {
3330 set l [expr {$selectedline + 1}]
3335 set findstartline $l
3339 set id [lindex $displayorder $l]
3340 if {$findmergefiles || [llength [lindex $parentlist $l]] == 1} {
3341 if {![info exists treediffs($id)]} {
3342 append diffsneeded "$id\n"
3343 lappend fdiffsneeded $id
3346 if {[incr l] >= $numcommits} {
3349 if {$l == $findstartline} break
3352 # start off a git-diff-tree process if needed
3353 if {$diffsneeded ne {}} {
3355 set df [open [list | git-diff-tree -r --stdin << $diffsneeded] r]
3357 error_popup "Error starting search process: $err"
3360 catch {unset fdiffid}
3362 fconfigure $df -blocking 0
3363 fileevent $df readable [list readfilediffs $df]
3367 set findinsertpos end
3368 set id [lindex $displayorder $l]
3370 set findinprogress 1
3375 proc readfilediffs {df} {
3376 global findid fdiffid fdiffs
3378 set n [gets $df line]
3382 if {[catch {close $df} err]} {
3385 error_popup "Error in git-diff-tree: $err"
3386 } elseif {[info exists findid]} {
3390 error_popup "Couldn't find diffs for $id"
3395 if {[regexp {^([0-9a-f]{40})$} $line match id]} {
3396 # start of a new string of diffs
3400 } elseif {[string match ":*" $line]} {
3401 lappend fdiffs [lindex $line 5]
3405 proc donefilediff {} {
3406 global fdiffid fdiffs treediffs findid
3407 global fdiffsneeded fdiffpos
3409 if {[info exists fdiffid]} {
3410 while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffid
3411 && $fdiffpos < [llength $fdiffsneeded]} {
3412 # git-diff-tree doesn't output anything for a commit
3413 # which doesn't change anything
3414 set nullid [lindex $fdiffsneeded $fdiffpos]
3415 set treediffs($nullid) {}
3416 if {[info exists findid] && $nullid eq $findid} {
3424 if {![info exists treediffs($fdiffid)]} {
3425 set treediffs($fdiffid) $fdiffs
3427 if {[info exists findid] && $fdiffid eq $findid} {
3435 global findid treediffs parentlist
3436 global ffileline findstartline finddidsel
3437 global displayorder numcommits matchinglines findinprogress
3438 global findmergefiles
3442 set id [lindex $displayorder $l]
3443 if {$findmergefiles || [llength [lindex $parentlist $l]] == 1} {
3444 if {![info exists treediffs($id)]} {
3450 foreach f $treediffs($id) {
3451 set x [findmatches $f]
3461 if {[incr l] >= $numcommits} {
3464 if {$l == $findstartline} break
3472 # mark a commit as matching by putting a yellow background
3473 # behind the headline
3474 proc markheadline {l id} {
3475 global canv mainfont linehtag
3478 set bbox [$canv bbox $linehtag($l)]
3479 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
3483 # mark the bits of a headline, author or date that match a find string
3484 proc markmatches {canv l str tag matches font} {
3485 set bbox [$canv bbox $tag]
3486 set x0 [lindex $bbox 0]
3487 set y0 [lindex $bbox 1]
3488 set y1 [lindex $bbox 3]
3489 foreach match $matches {
3490 set start [lindex $match 0]
3491 set end [lindex $match 1]
3492 if {$start > $end} continue
3493 set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
3494 set xlen [font measure $font [string range $str 0 [expr {$end}]]]
3495 set t [$canv create rect [expr {$x0+$xoff}] $y0 \
3496 [expr {$x0+$xlen+2}] $y1 \
3497 -outline {} -tags matches -fill yellow]
3502 proc unmarkmatches {} {
3503 global matchinglines findids
3504 allcanvs delete matches
3505 catch {unset matchinglines}
3506 catch {unset findids}
3509 proc selcanvline {w x y} {
3510 global canv canvy0 ctext linespc
3512 set ymax [lindex [$canv cget -scrollregion] 3]
3513 if {$ymax == {}} return
3514 set yfrac [lindex [$canv yview] 0]
3515 set y [expr {$y + $yfrac * $ymax}]
3516 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
3521 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
3527 proc commit_descriptor {p} {
3529 if {![info exists commitinfo($p)]} {
3533 if {[llength $commitinfo($p)] > 1} {
3534 set l [lindex $commitinfo($p) 0]
3539 # append some text to the ctext widget, and make any SHA1 ID
3540 # that we know about be a clickable link.
3541 proc appendwithlinks {text} {
3542 global ctext commitrow linknum curview
3544 set start [$ctext index "end - 1c"]
3545 $ctext insert end $text
3546 $ctext insert end "\n"
3547 set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
3551 set linkid [string range $text $s $e]
3552 if {![info exists commitrow($curview,$linkid)]} continue
3554 $ctext tag add link "$start + $s c" "$start + $e c"
3555 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
3556 $ctext tag bind link$linknum <1> \
3557 [list selectline $commitrow($curview,$linkid) 1]
3560 $ctext tag conf link -foreground blue -underline 1
3561 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3562 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3565 proc viewnextline {dir} {
3569 set ymax [lindex [$canv cget -scrollregion] 3]
3570 set wnow [$canv yview]
3571 set wtop [expr {[lindex $wnow 0] * $ymax}]
3572 set newtop [expr {$wtop + $dir * $linespc}]
3575 } elseif {$newtop > $ymax} {
3578 allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
3581 proc selectline {l isnew} {
3582 global canv canv2 canv3 ctext commitinfo selectedline
3583 global displayorder linehtag linentag linedtag
3584 global canvy0 linespc parentlist childlist
3585 global currentid sha1entry
3586 global commentend idtags linknum
3587 global mergemax numcommits pending_select
3590 catch {unset pending_select}
3593 if {$l < 0 || $l >= $numcommits} return
3594 set y [expr {$canvy0 + $l * $linespc}]
3595 set ymax [lindex [$canv cget -scrollregion] 3]
3596 set ytop [expr {$y - $linespc - 1}]
3597 set ybot [expr {$y + $linespc + 1}]
3598 set wnow [$canv yview]
3599 set wtop [expr {[lindex $wnow 0] * $ymax}]
3600 set wbot [expr {[lindex $wnow 1] * $ymax}]
3601 set wh [expr {$wbot - $wtop}]
3603 if {$ytop < $wtop} {
3604 if {$ybot < $wtop} {
3605 set newtop [expr {$y - $wh / 2.0}]
3608 if {$newtop > $wtop - $linespc} {
3609 set newtop [expr {$wtop - $linespc}]
3612 } elseif {$ybot > $wbot} {
3613 if {$ytop > $wbot} {
3614 set newtop [expr {$y - $wh / 2.0}]
3616 set newtop [expr {$ybot - $wh}]
3617 if {$newtop < $wtop + $linespc} {
3618 set newtop [expr {$wtop + $linespc}]
3622 if {$newtop != $wtop} {
3626 allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
3630 if {![info exists linehtag($l)]} return
3632 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
3633 -tags secsel -fill [$canv cget -selectbackground]]
3635 $canv2 delete secsel
3636 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
3637 -tags secsel -fill [$canv2 cget -selectbackground]]
3639 $canv3 delete secsel
3640 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
3641 -tags secsel -fill [$canv3 cget -selectbackground]]
3645 addtohistory [list selectline $l 0]
3650 set id [lindex $displayorder $l]
3652 $sha1entry delete 0 end
3653 $sha1entry insert 0 $id
3654 $sha1entry selection from 0
3655 $sha1entry selection to end
3657 $ctext conf -state normal
3660 set info $commitinfo($id)
3661 set date [formatdate [lindex $info 2]]
3662 $ctext insert end "Author: [lindex $info 1] $date\n"
3663 set date [formatdate [lindex $info 4]]
3664 $ctext insert end "Committer: [lindex $info 3] $date\n"
3665 if {[info exists idtags($id)]} {
3666 $ctext insert end "Tags:"
3667 foreach tag $idtags($id) {
3668 $ctext insert end " $tag"
3670 $ctext insert end "\n"
3674 set olds [lindex $parentlist $l]
3675 if {[llength $olds] > 1} {
3678 if {$np >= $mergemax} {
3683 $ctext insert end "Parent: " $tag
3684 appendwithlinks [commit_descriptor $p]
3689 append comment "Parent: [commit_descriptor $p]\n"
3693 foreach c [lindex $childlist $l] {
3694 append comment "Child: [commit_descriptor $c]\n"
3697 append comment [lindex $info 5]
3699 # make anything that looks like a SHA1 ID be a clickable link
3700 appendwithlinks $comment
3702 $ctext tag delete Comments
3703 $ctext tag remove found 1.0 end
3704 $ctext conf -state disabled
3705 set commentend [$ctext index "end - 1c"]
3707 init_flist "Comments"
3708 if {$cmitmode eq "tree"} {
3710 } elseif {[llength $olds] <= 1} {
3717 proc selfirstline {} {
3722 proc sellastline {} {
3725 set l [expr {$numcommits - 1}]
3729 proc selnextline {dir} {
3731 if {![info exists selectedline]} return
3732 set l [expr {$selectedline + $dir}]
3737 proc selnextpage {dir} {
3738 global canv linespc selectedline numcommits
3740 set lpp [expr {([winfo height $canv] - 2) / $linespc}]
3744 allcanvs yview scroll [expr {$dir * $lpp}] units
3746 if {![info exists selectedline]} return
3747 set l [expr {$selectedline + $dir * $lpp}]
3750 } elseif {$l >= $numcommits} {
3751 set l [expr $numcommits - 1]
3757 proc unselectline {} {
3758 global selectedline currentid
3760 catch {unset selectedline}
3761 catch {unset currentid}
3762 allcanvs delete secsel
3765 proc reselectline {} {
3768 if {[info exists selectedline]} {
3769 selectline $selectedline 0
3773 proc addtohistory {cmd} {
3774 global history historyindex curview
3776 set elt [list $curview $cmd]
3777 if {$historyindex > 0
3778 && [lindex $history [expr {$historyindex - 1}]] == $elt} {
3782 if {$historyindex < [llength $history]} {
3783 set history [lreplace $history $historyindex end $elt]
3785 lappend history $elt
3788 if {$historyindex > 1} {
3789 .ctop.top.bar.leftbut conf -state normal
3791 .ctop.top.bar.leftbut conf -state disabled
3793 .ctop.top.bar.rightbut conf -state disabled
3799 set view [lindex $elt 0]
3800 set cmd [lindex $elt 1]
3801 if {$curview != $view} {
3808 global history historyindex
3810 if {$historyindex > 1} {
3811 incr historyindex -1
3812 godo [lindex $history [expr {$historyindex - 1}]]
3813 .ctop.top.bar.rightbut conf -state normal
3815 if {$historyindex <= 1} {
3816 .ctop.top.bar.leftbut conf -state disabled
3821 global history historyindex
3823 if {$historyindex < [llength $history]} {
3824 set cmd [lindex $history $historyindex]
3827 .ctop.top.bar.leftbut conf -state normal
3829 if {$historyindex >= [llength $history]} {
3830 .ctop.top.bar.rightbut conf -state disabled
3835 global treefilelist treeidlist diffids diffmergeid treepending
3838 catch {unset diffmergeid}
3839 if {![info exists treefilelist($id)]} {
3840 if {![info exists treepending]} {
3841 if {[catch {set gtf [open [concat | git-ls-tree -r $id] r]}]} {
3845 set treefilelist($id) {}
3846 set treeidlist($id) {}
3847 fconfigure $gtf -blocking 0
3848 fileevent $gtf readable [list gettreeline $gtf $id]
3855 proc gettreeline {gtf id} {
3856 global treefilelist treeidlist treepending cmitmode diffids
3858 while {[gets $gtf line] >= 0} {
3859 if {[lindex $line 1] ne "blob"} continue
3860 set sha1 [lindex $line 2]
3861 set fname [lindex $line 3]
3862 lappend treefilelist($id) $fname
3863 lappend treeidlist($id) $sha1
3865 if {![eof $gtf]} return
3868 if {$cmitmode ne "tree"} {
3869 if {![info exists diffmergeid]} {
3870 gettreediffs $diffids
3872 } elseif {$id ne $diffids} {
3880 global treefilelist treeidlist diffids
3881 global ctext commentend
3883 set i [lsearch -exact $treefilelist($diffids) $f]
3885 puts "oops, $f not in list for id $diffids"
3888 set blob [lindex $treeidlist($diffids) $i]
3889 if {[catch {set bf [open [concat | git-cat-file blob $blob] r]} err]} {
3890 puts "oops, error reading blob $blob: $err"
3893 fconfigure $bf -blocking 0
3894 fileevent $bf readable [list getblobline $bf $diffids]
3895 $ctext config -state normal
3896 clear_ctext $commentend
3897 $ctext insert end "\n"
3898 $ctext insert end "$f\n" filesep
3899 $ctext config -state disabled
3900 $ctext yview $commentend
3903 proc getblobline {bf id} {
3904 global diffids cmitmode ctext
3906 if {$id ne $diffids || $cmitmode ne "tree"} {
3910 $ctext config -state normal
3911 while {[gets $bf line] >= 0} {
3912 $ctext insert end "$line\n"
3915 # delete last newline
3916 $ctext delete "end - 2c" "end - 1c"
3919 $ctext config -state disabled
3922 proc mergediff {id l} {
3923 global diffmergeid diffopts mdifffd
3929 # this doesn't seem to actually affect anything...
3930 set env(GIT_DIFF_OPTS) $diffopts
3931 set cmd [concat | git-diff-tree --no-commit-id --cc $id]
3932 if {[catch {set mdf [open $cmd r]} err]} {
3933 error_popup "Error getting merge diffs: $err"
3936 fconfigure $mdf -blocking 0
3937 set mdifffd($id) $mdf
3938 set np [llength [lindex $parentlist $l]]
3939 fileevent $mdf readable [list getmergediffline $mdf $id $np]
3940 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
3943 proc getmergediffline {mdf id np} {
3944 global diffmergeid ctext cflist nextupdate mergemax
3945 global difffilestart mdifffd
3947 set n [gets $mdf line]
3954 if {![info exists diffmergeid] || $id != $diffmergeid
3955 || $mdf != $mdifffd($id)} {
3958 $ctext conf -state normal
3959 if {[regexp {^diff --cc (.*)} $line match fname]} {
3960 # start of a new file
3961 $ctext insert end "\n"
3962 set here [$ctext index "end - 1c"]
3963 lappend difffilestart $here
3964 add_flist [list $fname]
3965 set l [expr {(78 - [string length $fname]) / 2}]
3966 set pad [string range "----------------------------------------" 1 $l]
3967 $ctext insert end "$pad $fname $pad\n" filesep
3968 } elseif {[regexp {^@@} $line]} {
3969 $ctext insert end "$line\n" hunksep
3970 } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
3973 # parse the prefix - one ' ', '-' or '+' for each parent
3978 for {set j 0} {$j < $np} {incr j} {
3979 set c [string range $line $j $j]
3982 } elseif {$c == "-"} {
3984 } elseif {$c == "+"} {
3993 if {!$isbad && $minuses ne {} && $pluses eq {}} {
3994 # line doesn't appear in result, parents in $minuses have the line
3995 set num [lindex $minuses 0]
3996 } elseif {!$isbad && $pluses ne {} && $minuses eq {}} {
3997 # line appears in result, parents in $pluses don't have the line
3998 lappend tags mresult
3999 set num [lindex $spaces 0]
4002 if {$num >= $mergemax} {
4007 $ctext insert end "$line\n" $tags
4009 $ctext conf -state disabled
4010 if {[clock clicks -milliseconds] >= $nextupdate} {
4012 fileevent $mdf readable {}
4014 fileevent $mdf readable [list getmergediffline $mdf $id $np]
4018 proc startdiff {ids} {
4019 global treediffs diffids treepending diffmergeid
4022 catch {unset diffmergeid}
4023 if {![info exists treediffs($ids)]} {
4024 if {![info exists treepending]} {
4032 proc addtocflist {ids} {
4033 global treediffs cflist
4034 add_flist $treediffs($ids)
4038 proc gettreediffs {ids} {
4039 global treediff treepending
4040 set treepending $ids
4043 {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]} \
4045 fconfigure $gdtf -blocking 0
4046 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
4049 proc gettreediffline {gdtf ids} {
4050 global treediff treediffs treepending diffids diffmergeid
4053 set n [gets $gdtf line]
4055 if {![eof $gdtf]} return
4057 set treediffs($ids) $treediff
4059 if {$cmitmode eq "tree"} {
4061 } elseif {$ids != $diffids} {
4062 if {![info exists diffmergeid]} {
4063 gettreediffs $diffids
4070 set file [lindex $line 5]
4071 lappend treediff $file
4074 proc getblobdiffs {ids} {
4075 global diffopts blobdifffd diffids env curdifftag curtagstart
4076 global nextupdate diffinhdr treediffs
4078 set env(GIT_DIFF_OPTS) $diffopts
4079 set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids]
4080 if {[catch {set bdf [open $cmd r]} err]} {
4081 puts "error getting diffs: $err"
4085 fconfigure $bdf -blocking 0
4086 set blobdifffd($ids) $bdf
4087 set curdifftag Comments
4089 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
4090 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
4093 proc setinlist {var i val} {
4096 while {[llength [set $var]] < $i} {
4099 if {[llength [set $var]] == $i} {
4106 proc getblobdiffline {bdf ids} {
4107 global diffids blobdifffd ctext curdifftag curtagstart
4108 global diffnexthead diffnextnote difffilestart
4109 global nextupdate diffinhdr treediffs
4111 set n [gets $bdf line]
4115 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
4116 $ctext tag add $curdifftag $curtagstart end
4121 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
4124 $ctext conf -state normal
4125 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
4126 # start of a new file
4127 $ctext insert end "\n"
4128 $ctext tag add $curdifftag $curtagstart end
4129 set here [$ctext index "end - 1c"]
4130 set curtagstart $here
4132 set i [lsearch -exact $treediffs($ids) $fname]
4134 setinlist difffilestart $i $here
4136 if {$newname ne $fname} {
4137 set i [lsearch -exact $treediffs($ids) $newname]
4139 setinlist difffilestart $i $here
4142 set curdifftag "f:$fname"
4143 $ctext tag delete $curdifftag
4144 set l [expr {(78 - [string length $header]) / 2}]
4145 set pad [string range "----------------------------------------" 1 $l]
4146 $ctext insert end "$pad $header $pad\n" filesep
4148 } elseif {$diffinhdr && [string compare -length 3 $line "---"] == 0} {
4150 } elseif {$diffinhdr && [string compare -length 3 $line "+++"] == 0} {
4152 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
4153 $line match f1l f1c f2l f2c rest]} {
4154 $ctext insert end "$line\n" hunksep
4157 set x [string range $line 0 0]
4158 if {$x == "-" || $x == "+"} {
4159 set tag [expr {$x == "+"}]
4160 $ctext insert end "$line\n" d$tag
4161 } elseif {$x == " "} {
4162 $ctext insert end "$line\n"
4163 } elseif {$diffinhdr || $x == "\\"} {
4164 # e.g. "\ No newline at end of file"
4165 $ctext insert end "$line\n" filesep
4167 # Something else we don't recognize
4168 if {$curdifftag != "Comments"} {
4169 $ctext insert end "\n"
4170 $ctext tag add $curdifftag $curtagstart end
4171 set curtagstart [$ctext index "end - 1c"]
4172 set curdifftag Comments
4174 $ctext insert end "$line\n" filesep
4177 $ctext conf -state disabled
4178 if {[clock clicks -milliseconds] >= $nextupdate} {
4180 fileevent $bdf readable {}
4182 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
4187 global difffilestart ctext
4188 set here [$ctext index @0,0]
4189 foreach loc $difffilestart {
4190 if {[$ctext compare $loc > $here]} {
4196 proc clear_ctext {{first 1.0}} {
4197 global ctext smarktop smarkbot
4199 set l [lindex [split $first .] 0]
4200 if {![info exists smarktop] || [$ctext compare $first < $smarktop.0]} {
4203 if {![info exists smarkbot] || [$ctext compare $first < $smarkbot.0]} {
4206 $ctext delete $first end
4209 proc incrsearch {name ix op} {
4210 global ctext searchstring searchdirn
4212 $ctext tag remove found 1.0 end
4213 if {[catch {$ctext index anchor}]} {
4214 # no anchor set, use start of selection, or of visible area
4215 set sel [$ctext tag ranges sel]
4217 $ctext mark set anchor [lindex $sel 0]
4218 } elseif {$searchdirn eq "-forwards"} {
4219 $ctext mark set anchor @0,0
4221 $ctext mark set anchor @0,[winfo height $ctext]
4224 if {$searchstring ne {}} {
4225 set here [$ctext search $searchdirn -- $searchstring anchor]
4234 global sstring ctext searchstring searchdirn
4237 $sstring icursor end
4238 set searchdirn -forwards
4239 if {$searchstring ne {}} {
4240 set sel [$ctext tag ranges sel]
4242 set start "[lindex $sel 0] + 1c"
4243 } elseif {[catch {set start [$ctext index anchor]}]} {
4246 set match [$ctext search -count mlen -- $searchstring $start]
4247 $ctext tag remove sel 1.0 end
4253 set mend "$match + $mlen c"
4254 $ctext tag add sel $match $mend
4255 $ctext mark unset anchor
4259 proc dosearchback {} {
4260 global sstring ctext searchstring searchdirn
4263 $sstring icursor end
4264 set searchdirn -backwards
4265 if {$searchstring ne {}} {
4266 set sel [$ctext tag ranges sel]
4268 set start [lindex $sel 0]
4269 } elseif {[catch {set start [$ctext index anchor]}]} {
4270 set start @0,[winfo height $ctext]
4272 set match [$ctext search -backwards -count ml -- $searchstring $start]
4273 $ctext tag remove sel 1.0 end
4279 set mend "$match + $ml c"
4280 $ctext tag add sel $match $mend
4281 $ctext mark unset anchor
4285 proc searchmark {first last} {
4286 global ctext searchstring
4290 set match [$ctext search -count mlen -- $searchstring $mend $last.end]
4291 if {$match eq {}} break
4292 set mend "$match + $mlen c"
4293 $ctext tag add found $match $mend
4297 proc searchmarkvisible {doall} {
4298 global ctext smarktop smarkbot
4300 set topline [lindex [split [$ctext index @0,0] .] 0]
4301 set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0]
4302 if {$doall || $botline < $smarktop || $topline > $smarkbot} {
4303 # no overlap with previous
4304 searchmark $topline $botline
4305 set smarktop $topline
4306 set smarkbot $botline
4308 if {$topline < $smarktop} {
4309 searchmark $topline [expr {$smarktop-1}]
4310 set smarktop $topline
4312 if {$botline > $smarkbot} {
4313 searchmark [expr {$smarkbot+1}] $botline
4314 set smarkbot $botline
4319 proc scrolltext {f0 f1} {
4322 .ctop.cdet.left.sb set $f0 $f1
4323 if {$searchstring ne {}} {
4329 global linespc charspc canvx0 canvy0 mainfont
4330 global xspc1 xspc2 lthickness
4332 set linespc [font metrics $mainfont -linespace]
4333 set charspc [font measure $mainfont "m"]
4334 set canvy0 [expr {int(3 + 0.5 * $linespc)}]
4335 set canvx0 [expr {int(3 + 0.5 * $linespc)}]
4336 set lthickness [expr {int($linespc / 9) + 1}]
4337 set xspc1(0) $linespc
4345 set ymax [lindex [$canv cget -scrollregion] 3]
4346 if {$ymax eq {} || $ymax == 0} return
4347 set span [$canv yview]
4350 allcanvs yview moveto [lindex $span 0]
4352 if {[info exists selectedline]} {
4353 selectline $selectedline 0
4357 proc incrfont {inc} {
4358 global mainfont textfont ctext canv phase
4359 global stopped entries
4361 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
4362 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
4364 $ctext conf -font $textfont
4365 $ctext tag conf filesep -font [concat $textfont bold]
4366 foreach e $entries {
4367 $e conf -font $mainfont
4369 if {$phase eq "getcommits"} {
4370 $canv itemconf textitems -font $mainfont
4376 global sha1entry sha1string
4377 if {[string length $sha1string] == 40} {
4378 $sha1entry delete 0 end
4382 proc sha1change {n1 n2 op} {
4383 global sha1string currentid sha1but
4384 if {$sha1string == {}
4385 || ([info exists currentid] && $sha1string == $currentid)} {
4390 if {[$sha1but cget -state] == $state} return
4391 if {$state == "normal"} {
4392 $sha1but conf -state normal -relief raised -text "Goto: "
4394 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
4398 proc gotocommit {} {
4399 global sha1string currentid commitrow tagids headids
4400 global displayorder numcommits curview
4402 if {$sha1string == {}
4403 || ([info exists currentid] && $sha1string == $currentid)} return
4404 if {[info exists tagids($sha1string)]} {
4405 set id $tagids($sha1string)
4406 } elseif {[info exists headids($sha1string)]} {
4407 set id $headids($sha1string)
4409 set id [string tolower $sha1string]
4410 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
4412 foreach i $displayorder {
4413 if {[string match $id* $i]} {
4417 if {$matches ne {}} {
4418 if {[llength $matches] > 1} {
4419 error_popup "Short SHA1 id $id is ambiguous"
4422 set id [lindex $matches 0]
4426 if {[info exists commitrow($curview,$id)]} {
4427 selectline $commitrow($curview,$id) 1
4430 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
4435 error_popup "$type $sha1string is not known"
4438 proc lineenter {x y id} {
4439 global hoverx hovery hoverid hovertimer
4440 global commitinfo canv
4442 if {![info exists commitinfo($id)] && ![getcommit $id]} return
4446 if {[info exists hovertimer]} {
4447 after cancel $hovertimer
4449 set hovertimer [after 500 linehover]
4453 proc linemotion {x y id} {
4454 global hoverx hovery hoverid hovertimer
4456 if {[info exists hoverid] && $id == $hoverid} {
4459 if {[info exists hovertimer]} {
4460 after cancel $hovertimer
4462 set hovertimer [after 500 linehover]
4466 proc lineleave {id} {
4467 global hoverid hovertimer canv
4469 if {[info exists hoverid] && $id == $hoverid} {
4471 if {[info exists hovertimer]} {
4472 after cancel $hovertimer
4480 global hoverx hovery hoverid hovertimer
4481 global canv linespc lthickness
4482 global commitinfo mainfont
4484 set text [lindex $commitinfo($hoverid) 0]
4485 set ymax [lindex [$canv cget -scrollregion] 3]
4486 if {$ymax == {}} return
4487 set yfrac [lindex [$canv yview] 0]
4488 set x [expr {$hoverx + 2 * $linespc}]
4489 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
4490 set x0 [expr {$x - 2 * $lthickness}]
4491 set y0 [expr {$y - 2 * $lthickness}]
4492 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
4493 set y1 [expr {$y + $linespc + 2 * $lthickness}]
4494 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
4495 -fill \#ffff80 -outline black -width 1 -tags hover]
4497 set t [$canv create text $x $y -anchor nw -text $text -tags hover -font $mainfont]
4501 proc clickisonarrow {id y} {
4504 set ranges [rowranges $id]
4505 set thresh [expr {2 * $lthickness + 6}]
4506 set n [expr {[llength $ranges] - 1}]
4507 for {set i 1} {$i < $n} {incr i} {
4508 set row [lindex $ranges $i]
4509 if {abs([yc $row] - $y) < $thresh} {
4516 proc arrowjump {id n y} {
4519 # 1 <-> 2, 3 <-> 4, etc...
4520 set n [expr {(($n - 1) ^ 1) + 1}]
4521 set row [lindex [rowranges $id] $n]
4523 set ymax [lindex [$canv cget -scrollregion] 3]
4524 if {$ymax eq {} || $ymax <= 0} return
4525 set view [$canv yview]
4526 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
4527 set yfrac [expr {$yt / $ymax - $yspan / 2}]
4531 allcanvs yview moveto $yfrac
4534 proc lineclick {x y id isnew} {
4535 global ctext commitinfo children canv thickerline curview
4537 if {![info exists commitinfo($id)] && ![getcommit $id]} return
4542 # draw this line thicker than normal
4546 set ymax [lindex [$canv cget -scrollregion] 3]
4547 if {$ymax eq {}} return
4548 set yfrac [lindex [$canv yview] 0]
4549 set y [expr {$y + $yfrac * $ymax}]
4551 set dirn [clickisonarrow $id $y]
4553 arrowjump $id $dirn $y
4558 addtohistory [list lineclick $x $y $id 0]
4560 # fill the details pane with info about this line
4561 $ctext conf -state normal
4563 $ctext tag conf link -foreground blue -underline 1
4564 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
4565 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
4566 $ctext insert end "Parent:\t"
4567 $ctext insert end $id [list link link0]
4568 $ctext tag bind link0 <1> [list selbyid $id]
4569 set info $commitinfo($id)
4570 $ctext insert end "\n\t[lindex $info 0]\n"
4571 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
4572 set date [formatdate [lindex $info 2]]
4573 $ctext insert end "\tDate:\t$date\n"
4574 set kids $children($curview,$id)
4576 $ctext insert end "\nChildren:"
4578 foreach child $kids {
4580 if {![info exists commitinfo($child)] && ![getcommit $child]} continue
4581 set info $commitinfo($child)
4582 $ctext insert end "\n\t"
4583 $ctext insert end $child [list link link$i]
4584 $ctext tag bind link$i <1> [list selbyid $child]
4585 $ctext insert end "\n\t[lindex $info 0]"
4586 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
4587 set date [formatdate [lindex $info 2]]
4588 $ctext insert end "\n\tDate:\t$date\n"
4591 $ctext conf -state disabled
4595 proc normalline {} {
4597 if {[info exists thickerline]} {
4605 global commitrow curview
4606 if {[info exists commitrow($curview,$id)]} {
4607 selectline $commitrow($curview,$id) 1
4613 if {![info exists startmstime]} {
4614 set startmstime [clock clicks -milliseconds]
4616 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
4619 proc rowmenu {x y id} {
4620 global rowctxmenu commitrow selectedline rowmenuid curview
4622 if {![info exists selectedline]
4623 || $commitrow($curview,$id) eq $selectedline} {
4628 $rowctxmenu entryconfigure 0 -state $state
4629 $rowctxmenu entryconfigure 1 -state $state
4630 $rowctxmenu entryconfigure 2 -state $state
4632 tk_popup $rowctxmenu $x $y
4635 proc diffvssel {dirn} {
4636 global rowmenuid selectedline displayorder
4638 if {![info exists selectedline]} return
4640 set oldid [lindex $displayorder $selectedline]
4641 set newid $rowmenuid
4643 set oldid $rowmenuid
4644 set newid [lindex $displayorder $selectedline]
4646 addtohistory [list doseldiff $oldid $newid]
4647 doseldiff $oldid $newid
4650 proc doseldiff {oldid newid} {
4654 $ctext conf -state normal
4657 $ctext insert end "From "
4658 $ctext tag conf link -foreground blue -underline 1
4659 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
4660 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
4661 $ctext tag bind link0 <1> [list selbyid $oldid]
4662 $ctext insert end $oldid [list link link0]
4663 $ctext insert end "\n "
4664 $ctext insert end [lindex $commitinfo($oldid) 0]
4665 $ctext insert end "\n\nTo "
4666 $ctext tag bind link1 <1> [list selbyid $newid]
4667 $ctext insert end $newid [list link link1]
4668 $ctext insert end "\n "
4669 $ctext insert end [lindex $commitinfo($newid) 0]
4670 $ctext insert end "\n"
4671 $ctext conf -state disabled
4672 $ctext tag delete Comments
4673 $ctext tag remove found 1.0 end
4674 startdiff [list $oldid $newid]
4678 global rowmenuid currentid commitinfo patchtop patchnum
4680 if {![info exists currentid]} return
4681 set oldid $currentid
4682 set oldhead [lindex $commitinfo($oldid) 0]
4683 set newid $rowmenuid
4684 set newhead [lindex $commitinfo($newid) 0]
4687 catch {destroy $top}
4689 label $top.title -text "Generate patch"
4690 grid $top.title - -pady 10
4691 label $top.from -text "From:"
4692 entry $top.fromsha1 -width 40 -relief flat
4693 $top.fromsha1 insert 0 $oldid
4694 $top.fromsha1 conf -state readonly
4695 grid $top.from $top.fromsha1 -sticky w
4696 entry $top.fromhead -width 60 -relief flat
4697 $top.fromhead insert 0 $oldhead
4698 $top.fromhead conf -state readonly
4699 grid x $top.fromhead -sticky w
4700 label $top.to -text "To:"
4701 entry $top.tosha1 -width 40 -relief flat
4702 $top.tosha1 insert 0 $newid
4703 $top.tosha1 conf -state readonly
4704 grid $top.to $top.tosha1 -sticky w
4705 entry $top.tohead -width 60 -relief flat
4706 $top.tohead insert 0 $newhead
4707 $top.tohead conf -state readonly
4708 grid x $top.tohead -sticky w
4709 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
4710 grid $top.rev x -pady 10
4711 label $top.flab -text "Output file:"
4712 entry $top.fname -width 60
4713 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
4715 grid $top.flab $top.fname -sticky w
4717 button $top.buts.gen -text "Generate" -command mkpatchgo
4718 button $top.buts.can -text "Cancel" -command mkpatchcan
4719 grid $top.buts.gen $top.buts.can
4720 grid columnconfigure $top.buts 0 -weight 1 -uniform a
4721 grid columnconfigure $top.buts 1 -weight 1 -uniform a
4722 grid $top.buts - -pady 10 -sticky ew
4726 proc mkpatchrev {} {
4729 set oldid [$patchtop.fromsha1 get]
4730 set oldhead [$patchtop.fromhead get]
4731 set newid [$patchtop.tosha1 get]
4732 set newhead [$patchtop.tohead get]
4733 foreach e [list fromsha1 fromhead tosha1 tohead] \
4734 v [list $newid $newhead $oldid $oldhead] {
4735 $patchtop.$e conf -state normal
4736 $patchtop.$e delete 0 end
4737 $patchtop.$e insert 0 $v
4738 $patchtop.$e conf -state readonly
4745 set oldid [$patchtop.fromsha1 get]
4746 set newid [$patchtop.tosha1 get]
4747 set fname [$patchtop.fname get]
4748 if {[catch {exec git-diff-tree -p $oldid $newid >$fname &} err]} {
4749 error_popup "Error creating patch: $err"
4751 catch {destroy $patchtop}
4755 proc mkpatchcan {} {
4758 catch {destroy $patchtop}
4763 global rowmenuid mktagtop commitinfo
4767 catch {destroy $top}
4769 label $top.title -text "Create tag"
4770 grid $top.title - -pady 10
4771 label $top.id -text "ID:"
4772 entry $top.sha1 -width 40 -relief flat
4773 $top.sha1 insert 0 $rowmenuid
4774 $top.sha1 conf -state readonly
4775 grid $top.id $top.sha1 -sticky w
4776 entry $top.head -width 60 -relief flat
4777 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
4778 $top.head conf -state readonly
4779 grid x $top.head -sticky w
4780 label $top.tlab -text "Tag name:"
4781 entry $top.tag -width 60
4782 grid $top.tlab $top.tag -sticky w
4784 button $top.buts.gen -text "Create" -command mktaggo
4785 button $top.buts.can -text "Cancel" -command mktagcan
4786 grid $top.buts.gen $top.buts.can
4787 grid columnconfigure $top.buts 0 -weight 1 -uniform a
4788 grid columnconfigure $top.buts 1 -weight 1 -uniform a
4789 grid $top.buts - -pady 10 -sticky ew
4794 global mktagtop env tagids idtags
4796 set id [$mktagtop.sha1 get]
4797 set tag [$mktagtop.tag get]
4799 error_popup "No tag name specified"
4802 if {[info exists tagids($tag)]} {
4803 error_popup "Tag \"$tag\" already exists"
4808 set fname [file join $dir "refs/tags" $tag]
4809 set f [open $fname w]
4813 error_popup "Error creating tag: $err"
4817 set tagids($tag) $id
4818 lappend idtags($id) $tag
4822 proc redrawtags {id} {
4823 global canv linehtag commitrow idpos selectedline curview
4825 if {![info exists commitrow($curview,$id)]} return
4826 drawcmitrow $commitrow($curview,$id)
4827 $canv delete tag.$id
4828 set xt [eval drawtags $id $idpos($id)]
4829 $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2]
4830 if {[info exists selectedline]
4831 && $selectedline == $commitrow($curview,$id)} {
4832 selectline $selectedline 0
4839 catch {destroy $mktagtop}
4848 proc writecommit {} {
4849 global rowmenuid wrcomtop commitinfo wrcomcmd
4851 set top .writecommit
4853 catch {destroy $top}
4855 label $top.title -text "Write commit to file"
4856 grid $top.title - -pady 10
4857 label $top.id -text "ID:"
4858 entry $top.sha1 -width 40 -relief flat
4859 $top.sha1 insert 0 $rowmenuid
4860 $top.sha1 conf -state readonly
4861 grid $top.id $top.sha1 -sticky w
4862 entry $top.head -width 60 -relief flat
4863 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
4864 $top.head conf -state readonly
4865 grid x $top.head -sticky w
4866 label $top.clab -text "Command:"
4867 entry $top.cmd -width 60 -textvariable wrcomcmd
4868 grid $top.clab $top.cmd -sticky w -pady 10
4869 label $top.flab -text "Output file:"
4870 entry $top.fname -width 60
4871 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
4872 grid $top.flab $top.fname -sticky w
4874 button $top.buts.gen -text "Write" -command wrcomgo
4875 button $top.buts.can -text "Cancel" -command wrcomcan
4876 grid $top.buts.gen $top.buts.can
4877 grid columnconfigure $top.buts 0 -weight 1 -uniform a
4878 grid columnconfigure $top.buts 1 -weight 1 -uniform a
4879 grid $top.buts - -pady 10 -sticky ew
4886 set id [$wrcomtop.sha1 get]
4887 set cmd "echo $id | [$wrcomtop.cmd get]"
4888 set fname [$wrcomtop.fname get]
4889 if {[catch {exec sh -c $cmd >$fname &} err]} {
4890 error_popup "Error writing commit: $err"
4892 catch {destroy $wrcomtop}
4899 catch {destroy $wrcomtop}
4903 proc listrefs {id} {
4904 global idtags idheads idotherrefs
4907 if {[info exists idtags($id)]} {
4911 if {[info exists idheads($id)]} {
4915 if {[info exists idotherrefs($id)]} {
4916 set z $idotherrefs($id)
4918 return [list $x $y $z]
4921 proc rereadrefs {} {
4922 global idtags idheads idotherrefs
4924 set refids [concat [array names idtags] \
4925 [array names idheads] [array names idotherrefs]]
4926 foreach id $refids {
4927 if {![info exists ref($id)]} {
4928 set ref($id) [listrefs $id]
4932 set refids [lsort -unique [concat $refids [array names idtags] \
4933 [array names idheads] [array names idotherrefs]]]
4934 foreach id $refids {
4935 set v [listrefs $id]
4936 if {![info exists ref($id)] || $ref($id) != $v} {
4942 proc showtag {tag isnew} {
4943 global ctext tagcontents tagids linknum
4946 addtohistory [list showtag $tag 0]
4948 $ctext conf -state normal
4951 if {[info exists tagcontents($tag)]} {
4952 set text $tagcontents($tag)
4954 set text "Tag: $tag\nId: $tagids($tag)"
4956 appendwithlinks $text
4957 $ctext conf -state disabled
4968 global maxwidth maxgraphpct diffopts findmergefiles
4969 global oldprefs prefstop
4973 if {[winfo exists $top]} {
4977 foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
4978 set oldprefs($v) [set $v]
4981 wm title $top "Gitk preferences"
4982 label $top.ldisp -text "Commit list display options"
4983 grid $top.ldisp - -sticky w -pady 10
4984 label $top.spacer -text " "
4985 label $top.maxwidthl -text "Maximum graph width (lines)" \
4987 spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
4988 grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
4989 label $top.maxpctl -text "Maximum graph width (% of pane)" \
4991 spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
4992 grid x $top.maxpctl $top.maxpct -sticky w
4993 checkbutton $top.findm -variable findmergefiles
4994 label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
4996 grid $top.findm $top.findml - -sticky w
4997 label $top.ddisp -text "Diff display options"
4998 grid $top.ddisp - -sticky w -pady 10
4999 label $top.diffoptl -text "Options for diff program" \
5001 entry $top.diffopt -width 20 -textvariable diffopts
5002 grid x $top.diffoptl $top.diffopt -sticky w
5004 button $top.buts.ok -text "OK" -command prefsok
5005 button $top.buts.can -text "Cancel" -command prefscan
5006 grid $top.buts.ok $top.buts.can
5007 grid columnconfigure $top.buts 0 -weight 1 -uniform a
5008 grid columnconfigure $top.buts 1 -weight 1 -uniform a
5009 grid $top.buts - - -pady 10 -sticky ew
5013 global maxwidth maxgraphpct diffopts findmergefiles
5014 global oldprefs prefstop
5016 foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
5017 set $v $oldprefs($v)
5019 catch {destroy $prefstop}
5024 global maxwidth maxgraphpct
5025 global oldprefs prefstop
5027 catch {destroy $prefstop}
5029 if {$maxwidth != $oldprefs(maxwidth)
5030 || $maxgraphpct != $oldprefs(maxgraphpct)} {
5035 proc formatdate {d} {
5036 return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
5039 # This list of encoding names and aliases is distilled from
5040 # http://www.iana.org/assignments/character-sets.
5041 # Not all of them are supported by Tcl.
5042 set encoding_aliases {
5043 { ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
5044 ISO646-US US-ASCII us IBM367 cp367 csASCII }
5045 { ISO-10646-UTF-1 csISO10646UTF1 }
5046 { ISO_646.basic:1983 ref csISO646basic1983 }
5047 { INVARIANT csINVARIANT }
5048 { ISO_646.irv:1983 iso-ir-2 irv csISO2IntlRefVersion }
5049 { BS_4730 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom }
5050 { NATS-SEFI iso-ir-8-1 csNATSSEFI }
5051 { NATS-SEFI-ADD iso-ir-8-2 csNATSSEFIADD }
5052 { NATS-DANO iso-ir-9-1 csNATSDANO }
5053 { NATS-DANO-ADD iso-ir-9-2 csNATSDANOADD }
5054 { SEN_850200_B iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish }
5055 { SEN_850200_C iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames }
5056 { KS_C_5601-1987 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987 }
5057 { ISO-2022-KR csISO2022KR }
5059 { ISO-2022-JP csISO2022JP }
5060 { ISO-2022-JP-2 csISO2022JP2 }
5061 { JIS_C6220-1969-jp JIS_C6220-1969 iso-ir-13 katakana x0201-7
5063 { JIS_C6220-1969-ro iso-ir-14 jp ISO646-JP csISO14JISC6220ro }
5064 { IT iso-ir-15 ISO646-IT csISO15Italian }
5065 { PT iso-ir-16 ISO646-PT csISO16Portuguese }
5066 { ES iso-ir-17 ISO646-ES csISO17Spanish }
5067 { greek7-old iso-ir-18 csISO18Greek7Old }
5068 { latin-greek iso-ir-19 csISO19LatinGreek }
5069 { DIN_66003 iso-ir-21 de ISO646-DE csISO21German }
5070 { NF_Z_62-010_(1973) iso-ir-25 ISO646-FR1 csISO25French }
5071 { Latin-greek-1 iso-ir-27 csISO27LatinGreek1 }
5072 { ISO_5427 iso-ir-37 csISO5427Cyrillic }
5073 { JIS_C6226-1978 iso-ir-42 csISO42JISC62261978 }
5074 { BS_viewdata iso-ir-47 csISO47BSViewdata }
5075 { INIS iso-ir-49 csISO49INIS }
5076 { INIS-8 iso-ir-50 csISO50INIS8 }
5077 { INIS-cyrillic iso-ir-51 csISO51INISCyrillic }
5078 { ISO_5427:1981 iso-ir-54 ISO5427Cyrillic1981 }
5079 { ISO_5428:1980 iso-ir-55 csISO5428Greek }
5080 { GB_1988-80 iso-ir-57 cn ISO646-CN csISO57GB1988 }
5081 { GB_2312-80 iso-ir-58 chinese csISO58GB231280 }
5082 { NS_4551-1 iso-ir-60 ISO646-NO no csISO60DanishNorwegian
5084 { NS_4551-2 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2 }
5085 { NF_Z_62-010 iso-ir-69 ISO646-FR fr csISO69French }
5086 { videotex-suppl iso-ir-70 csISO70VideotexSupp1 }
5087 { PT2 iso-ir-84 ISO646-PT2 csISO84Portuguese2 }
5088 { ES2 iso-ir-85 ISO646-ES2 csISO85Spanish2 }
5089 { MSZ_7795.3 iso-ir-86 ISO646-HU hu csISO86Hungarian }
5090 { JIS_C6226-1983 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208 }
5091 { greek7 iso-ir-88 csISO88Greek7 }
5092 { ASMO_449 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449 }
5093 { iso-ir-90 csISO90 }
5094 { JIS_C6229-1984-a iso-ir-91 jp-ocr-a csISO91JISC62291984a }
5095 { JIS_C6229-1984-b iso-ir-92 ISO646-JP-OCR-B jp-ocr-b
5096 csISO92JISC62991984b }
5097 { JIS_C6229-1984-b-add iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd }
5098 { JIS_C6229-1984-hand iso-ir-94 jp-ocr-hand csISO94JIS62291984hand }
5099 { JIS_C6229-1984-hand-add iso-ir-95 jp-ocr-hand-add
5100 csISO95JIS62291984handadd }
5101 { JIS_C6229-1984-kana iso-ir-96 csISO96JISC62291984kana }
5102 { ISO_2033-1983 iso-ir-98 e13b csISO2033 }
5103 { ANSI_X3.110-1983 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS }
5104 { ISO_8859-1:1987 iso-ir-100 ISO_8859-1 ISO-8859-1 latin1 l1 IBM819
5106 { ISO_8859-2:1987 iso-ir-101 ISO_8859-2 ISO-8859-2 latin2 l2 csISOLatin2 }
5107 { T.61-7bit iso-ir-102 csISO102T617bit }
5108 { T.61-8bit T.61 iso-ir-103 csISO103T618bit }
5109 { ISO_8859-3:1988 iso-ir-109 ISO_8859-3 ISO-8859-3 latin3 l3 csISOLatin3 }
5110 { ISO_8859-4:1988 iso-ir-110 ISO_8859-4 ISO-8859-4 latin4 l4 csISOLatin4 }
5111 { ECMA-cyrillic iso-ir-111 KOI8-E csISO111ECMACyrillic }
5112 { CSA_Z243.4-1985-1 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1 }
5113 { CSA_Z243.4-1985-2 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2 }
5114 { CSA_Z243.4-1985-gr iso-ir-123 csISO123CSAZ24341985gr }
5115 { ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ISO-8859-6 ECMA-114 ASMO-708
5116 arabic csISOLatinArabic }
5117 { ISO_8859-6-E csISO88596E ISO-8859-6-E }
5118 { ISO_8859-6-I csISO88596I ISO-8859-6-I }
5119 { ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ISO-8859-7 ELOT_928 ECMA-118
5120 greek greek8 csISOLatinGreek }
5121 { T.101-G2 iso-ir-128 csISO128T101G2 }
5122 { ISO_8859-8:1988 iso-ir-138 ISO_8859-8 ISO-8859-8 hebrew
5124 { ISO_8859-8-E csISO88598E ISO-8859-8-E }
5125 { ISO_8859-8-I csISO88598I ISO-8859-8-I }
5126 { CSN_369103 iso-ir-139 csISO139CSN369103 }
5127 { JUS_I.B1.002 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002 }
5128 { ISO_6937-2-add iso-ir-142 csISOTextComm }
5129 { IEC_P27-1 iso-ir-143 csISO143IECP271 }
5130 { ISO_8859-5:1988 iso-ir-144 ISO_8859-5 ISO-8859-5 cyrillic
5131 csISOLatinCyrillic }
5132 { JUS_I.B1.003-serb iso-ir-146 serbian csISO146Serbian }
5133 { JUS_I.B1.003-mac macedonian iso-ir-147 csISO147Macedonian }
5134 { ISO_8859-9:1989 iso-ir-148 ISO_8859-9 ISO-8859-9 latin5 l5 csISOLatin5 }
5135 { greek-ccitt iso-ir-150 csISO150 csISO150GreekCCITT }
5136 { NC_NC00-10:81 cuba iso-ir-151 ISO646-CU csISO151Cuba }
5137 { ISO_6937-2-25 iso-ir-152 csISO6937Add }
5138 { GOST_19768-74 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874 }
5139 { ISO_8859-supp iso-ir-154 latin1-2-5 csISO8859Supp }
5140 { ISO_10367-box iso-ir-155 csISO10367Box }
5141 { ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 }
5142 { latin-lap lap iso-ir-158 csISO158Lap }
5143 { JIS_X0212-1990 x0212 iso-ir-159 csISO159JISX02121990 }
5144 { DS_2089 DS2089 ISO646-DK dk csISO646Danish }
5147 { JIS_X0201 X0201 csHalfWidthKatakana }
5148 { KSC5636 ISO646-KR csKSC5636 }
5149 { ISO-10646-UCS-2 csUnicode }
5150 { ISO-10646-UCS-4 csUCS4 }
5151 { DEC-MCS dec csDECMCS }
5152 { hp-roman8 roman8 r8 csHPRoman8 }
5153 { macintosh mac csMacintosh }
5154 { IBM037 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl
5156 { IBM038 EBCDIC-INT cp038 csIBM038 }
5157 { IBM273 CP273 csIBM273 }
5158 { IBM274 EBCDIC-BE CP274 csIBM274 }
5159 { IBM275 EBCDIC-BR cp275 csIBM275 }
5160 { IBM277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 }
5161 { IBM278 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 }
5162 { IBM280 CP280 ebcdic-cp-it csIBM280 }
5163 { IBM281 EBCDIC-JP-E cp281 csIBM281 }
5164 { IBM284 CP284 ebcdic-cp-es csIBM284 }
5165 { IBM285 CP285 ebcdic-cp-gb csIBM285 }
5166 { IBM290 cp290 EBCDIC-JP-kana csIBM290 }
5167 { IBM297 cp297 ebcdic-cp-fr csIBM297 }
5168 { IBM420 cp420 ebcdic-cp-ar1 csIBM420 }
5169 { IBM423 cp423 ebcdic-cp-gr csIBM423 }
5170 { IBM424 cp424 ebcdic-cp-he csIBM424 }
5171 { IBM437 cp437 437 csPC8CodePage437 }
5172 { IBM500 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500 }
5173 { IBM775 cp775 csPC775Baltic }
5174 { IBM850 cp850 850 csPC850Multilingual }
5175 { IBM851 cp851 851 csIBM851 }
5176 { IBM852 cp852 852 csPCp852 }
5177 { IBM855 cp855 855 csIBM855 }
5178 { IBM857 cp857 857 csIBM857 }
5179 { IBM860 cp860 860 csIBM860 }
5180 { IBM861 cp861 861 cp-is csIBM861 }
5181 { IBM862 cp862 862 csPC862LatinHebrew }
5182 { IBM863 cp863 863 csIBM863 }
5183 { IBM864 cp864 csIBM864 }
5184 { IBM865 cp865 865 csIBM865 }
5185 { IBM866 cp866 866 csIBM866 }
5186 { IBM868 CP868 cp-ar csIBM868 }
5187 { IBM869 cp869 869 cp-gr csIBM869 }
5188 { IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 }
5189 { IBM871 CP871 ebcdic-cp-is csIBM871 }
5190 { IBM880 cp880 EBCDIC-Cyrillic csIBM880 }
5191 { IBM891 cp891 csIBM891 }
5192 { IBM903 cp903 csIBM903 }
5193 { IBM904 cp904 904 csIBBM904 }
5194 { IBM905 CP905 ebcdic-cp-tr csIBM905 }
5195 { IBM918 CP918 ebcdic-cp-ar2 csIBM918 }
5196 { IBM1026 CP1026 csIBM1026 }
5197 { EBCDIC-AT-DE csIBMEBCDICATDE }
5198 { EBCDIC-AT-DE-A csEBCDICATDEA }
5199 { EBCDIC-CA-FR csEBCDICCAFR }
5200 { EBCDIC-DK-NO csEBCDICDKNO }
5201 { EBCDIC-DK-NO-A csEBCDICDKNOA }
5202 { EBCDIC-FI-SE csEBCDICFISE }
5203 { EBCDIC-FI-SE-A csEBCDICFISEA }
5204 { EBCDIC-FR csEBCDICFR }
5205 { EBCDIC-IT csEBCDICIT }
5206 { EBCDIC-PT csEBCDICPT }
5207 { EBCDIC-ES csEBCDICES }
5208 { EBCDIC-ES-A csEBCDICESA }
5209 { EBCDIC-ES-S csEBCDICESS }
5210 { EBCDIC-UK csEBCDICUK }
5211 { EBCDIC-US csEBCDICUS }
5212 { UNKNOWN-8BIT csUnknown8BiT }
5213 { MNEMONIC csMnemonic }
5218 { IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro }
5219 { IBM00924 CCSID00924 CP00924 ebcdic-Latin9--euro }
5220 { IBM01140 CCSID01140 CP01140 ebcdic-us-37+euro }
5221 { IBM01141 CCSID01141 CP01141 ebcdic-de-273+euro }
5222 { IBM01142 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro }
5223 { IBM01143 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro }
5224 { IBM01144 CCSID01144 CP01144 ebcdic-it-280+euro }
5225 { IBM01145 CCSID01145 CP01145 ebcdic-es-284+euro }
5226 { IBM01146 CCSID01146 CP01146 ebcdic-gb-285+euro }
5227 { IBM01147 CCSID01147 CP01147 ebcdic-fr-297+euro }
5228 { IBM01148 CCSID01148 CP01148 ebcdic-international-500+euro }
5229 { IBM01149 CCSID01149 CP01149 ebcdic-is-871+euro }
5230 { IBM1047 IBM-1047 }
5231 { PTCP154 csPTCP154 PT154 CP154 Cyrillic-Asian }
5232 { Amiga-1251 Ami1251 Amiga1251 Ami-1251 }
5233 { UNICODE-1-1 csUnicode11 }
5236 { UNICODE-1-1-UTF-7 csUnicode11UTF7 }
5237 { ISO-8859-14 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic
5239 { ISO-8859-15 ISO_8859-15 Latin-9 }
5240 { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
5241 { GBK CP936 MS936 windows-936 }
5242 { JIS_Encoding csJISEncoding }
5243 { Shift_JIS MS_Kanji csShiftJIS }
5244 { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
5246 { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
5247 { ISO-10646-UCS-Basic csUnicodeASCII }
5248 { ISO-10646-Unicode-Latin1 csUnicodeLatin1 ISO-10646 }
5249 { ISO-Unicode-IBM-1261 csUnicodeIBM1261 }
5250 { ISO-Unicode-IBM-1268 csUnicodeIBM1268 }
5251 { ISO-Unicode-IBM-1276 csUnicodeIBM1276 }
5252 { ISO-Unicode-IBM-1264 csUnicodeIBM1264 }
5253 { ISO-Unicode-IBM-1265 csUnicodeIBM1265 }
5254 { ISO-8859-1-Windows-3.0-Latin-1 csWindows30Latin1 }
5255 { ISO-8859-1-Windows-3.1-Latin-1 csWindows31Latin1 }
5256 { ISO-8859-2-Windows-Latin-2 csWindows31Latin2 }
5257 { ISO-8859-9-Windows-Latin-5 csWindows31Latin5 }
5258 { Adobe-Standard-Encoding csAdobeStandardEncoding }
5259 { Ventura-US csVenturaUS }
5260 { Ventura-International csVenturaInternational }
5261 { PC8-Danish-Norwegian csPC8DanishNorwegian }
5262 { PC8-Turkish csPC8Turkish }
5263 { IBM-Symbols csIBMSymbols }
5264 { IBM-Thai csIBMThai }
5265 { HP-Legal csHPLegal }
5266 { HP-Pi-font csHPPiFont }
5267 { HP-Math8 csHPMath8 }
5268 { Adobe-Symbol-Encoding csHPPSMath }
5269 { HP-DeskTop csHPDesktop }
5270 { Ventura-Math csVenturaMath }
5271 { Microsoft-Publishing csMicrosoftPublishing }
5272 { Windows-31J csWindows31J }
5277 proc tcl_encoding {enc} {
5278 global encoding_aliases
5279 set names [encoding names]
5280 set lcnames [string tolower $names]
5281 set enc [string tolower $enc]
5282 set i [lsearch -exact $lcnames $enc]
5284 # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
5285 if {[regsub {^iso[-_]} $enc iso encx]} {
5286 set i [lsearch -exact $lcnames $encx]
5290 foreach l $encoding_aliases {
5291 set ll [string tolower $l]
5292 if {[lsearch -exact $ll $enc] < 0} continue
5293 # look through the aliases for one that tcl knows about
5295 set i [lsearch -exact $lcnames $e]
5297 if {[regsub {^iso[-_]} $e iso ex]} {
5298 set i [lsearch -exact $lcnames $ex]
5307 return [lindex $names $i]
5314 set diffopts "-U 5 -p"
5315 set wrcomcmd "git-diff-tree --stdin -p --pretty"
5319 set gitencoding [exec git-repo-config --get i18n.commitencoding]
5321 if {$gitencoding == ""} {
5322 set gitencoding "utf-8"
5324 set tclencoding [tcl_encoding $gitencoding]
5325 if {$tclencoding == {}} {
5326 puts stderr "Warning: encoding $gitencoding is not supported by Tcl/Tk"
5329 set mainfont {Helvetica 9}
5330 set textfont {Courier 9}
5331 set uifont {Helvetica 9 bold}
5332 set findmergefiles 0
5340 set cmitmode "patch"
5342 set colors {green red blue magenta darkgrey brown orange}
5344 catch {source ~/.gitk}
5346 font create optionfont -family sans-serif -size -12
5350 switch -regexp -- $arg {
5352 "^-d" { set datemode 1 }
5354 lappend revtreeargs $arg
5359 # check that we can find a .git directory somewhere...
5361 if {![file isdirectory $gitdir]} {
5362 show_error . "Cannot find the git directory \"$gitdir\"."
5366 set cmdline_files {}
5367 set i [lsearch -exact $revtreeargs "--"]
5369 set cmdline_files [lrange $revtreeargs [expr {$i + 1}] end]
5370 set revtreeargs [lrange $revtreeargs 0 [expr {$i - 1}]]
5371 } elseif {$revtreeargs ne {}} {
5373 set f [eval exec git-rev-parse --no-revs --no-flags $revtreeargs]
5374 set cmdline_files [split $f "\n"]
5375 set n [llength $cmdline_files]
5376 set revtreeargs [lrange $revtreeargs 0 end-$n]
5378 # unfortunately we get both stdout and stderr in $err,
5379 # so look for "fatal:".
5380 set i [string first "fatal:" $err]
5382 set err [string range [expr {$i + 6}] end]
5384 show_error . "Bad arguments to gitk:\n$err"
5392 set highlight_names {}
5394 set highlight_paths {}
5395 set searchdirn -forwards
5402 set selectedhlview None
5415 if {$cmdline_files ne {} || $revtreeargs ne {}} {
5416 # create a view for the files/dirs specified on the command line
5420 set viewname(1) "Command line"
5421 set viewfiles(1) $cmdline_files
5422 set viewargs(1) $revtreeargs
5425 .bar.view entryconf 2 -state normal
5426 .bar.view entryconf 3 -state normal
5429 if {[info exists permviews]} {
5430 foreach v $permviews {
5433 set viewname($n) [lindex $v 0]
5434 set viewfiles($n) [lindex $v 1]
5435 set viewargs($n) [lindex $v 2]