2 # Tcl ignores the next line -*- tcl -*- \
5 # Copyright (C) 2005-2006 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
)]} {
15 return [exec git rev-parse
--git-dir]
19 proc start_rev_list
{view
} {
20 global startmsecs nextupdate
21 global commfd leftover tclencoding datemode
22 global viewargs viewfiles commitidx
24 set startmsecs
[clock clicks
-milliseconds]
25 set nextupdate
[expr {$startmsecs + 100}]
26 set commitidx
($view) 0
27 set args
$viewargs($view)
28 if {$viewfiles($view) ne
{}} {
29 set args
[concat
$args "--" $viewfiles($view)]
31 set order
"--topo-order"
33 set order
"--date-order"
36 set fd
[open
[concat | git rev-list
--header $order \
37 --parents --boundary --default HEAD
$args] r
]
39 puts stderr
"Error executing git rev-list: $err"
43 set leftover
($view) {}
44 fconfigure
$fd -blocking 0 -translation lf
45 if {$tclencoding != {}} {
46 fconfigure
$fd -encoding $tclencoding
48 fileevent
$fd readable
[list getcommitlines
$fd $view]
52 proc stop_rev_list
{} {
55 if {![info exists commfd
($curview)]} return
56 set fd
$commfd($curview)
62 unset commfd
($curview)
66 global phase canv mainfont curview
70 start_rev_list
$curview
71 show_status
"Reading commits..."
74 proc getcommitlines
{fd view
} {
75 global commitlisted nextupdate
76 global leftover commfd
77 global displayorder commitidx commitrow commitdata
78 global parentlist childlist children curview hlview
79 global vparentlist vchildlist vdisporder vcmitlisted
81 set stuff
[read $fd 500000]
83 if {![eof
$fd]} return
87 # set it blocking so we wait for the process to terminate
88 fconfigure
$fd -blocking 1
89 if {[catch
{close
$fd} err
]} {
91 if {$view != $curview} {
92 set fv
" for the \"$viewname($view)\" view"
94 if {[string range
$err 0 4] == "usage"} {
95 set err
"Gitk: error reading commits$fv:\
96 bad arguments to git rev-list."
97 if {$viewname($view) eq
"Command line"} {
99 " (Note: arguments to gitk are passed to git rev-list\
100 to allow selection of commits to be displayed.)"
103 set err
"Error reading commits$fv: $err"
107 if {$view == $curview} {
108 after idle finishcommits
115 set i
[string first
"\0" $stuff $start]
117 append leftover
($view) [string range
$stuff $start end
]
121 set cmit
$leftover($view)
122 append cmit
[string range
$stuff 0 [expr {$i - 1}]]
123 set leftover
($view) {}
125 set cmit
[string range
$stuff $start [expr {$i - 1}]]
127 set start
[expr {$i + 1}]
128 set j
[string first
"\n" $cmit]
132 set ids
[string range
$cmit 0 [expr {$j - 1}]]
133 if {[string range
$ids 0 0] == "-"} {
135 set ids
[string range
$ids 1 end
]
139 if {[string length
$id] != 40} {
147 if {[string length
$shortcmit] > 80} {
148 set shortcmit
"[string range $shortcmit 0 80]..."
150 error_popup
"Can't parse git rev-list output: {$shortcmit}"
153 set id
[lindex
$ids 0]
155 set olds
[lrange
$ids 1 end
]
158 if {$i == 0 ||
[lsearch
-exact $olds $p] >= $i} {
159 lappend children
($view,$p) $id
166 if {![info exists children
($view,$id)]} {
167 set children
($view,$id) {}
169 set commitdata
($id) [string range
$cmit [expr {$j + 1}] end
]
170 set commitrow
($view,$id) $commitidx($view)
171 incr commitidx
($view)
172 if {$view == $curview} {
173 lappend parentlist
$olds
174 lappend childlist
$children($view,$id)
175 lappend displayorder
$id
176 lappend commitlisted
$listed
178 lappend vparentlist
($view) $olds
179 lappend vchildlist
($view) $children($view,$id)
180 lappend vdisporder
($view) $id
181 lappend vcmitlisted
($view) $listed
186 if {$view == $curview} {
187 while {[layoutmore
$nextupdate]} doupdate
188 } elseif
{[info exists hlview
] && $view == $hlview} {
192 if {[clock clicks
-milliseconds] >= $nextupdate} {
198 global commfd nextupdate numcommits
200 foreach v
[array names commfd
] {
201 fileevent
$commfd($v) readable
{}
204 set nextupdate
[expr {[clock clicks
-milliseconds] + 100}]
205 foreach v
[array names commfd
] {
207 fileevent
$fd readable
[list getcommitlines
$fd $v]
211 proc readcommit
{id
} {
212 if {[catch
{set contents
[exec git cat-file commit
$id]}]} return
213 parsecommit
$id $contents 0
216 proc updatecommits
{} {
217 global viewdata curview phase displayorder
218 global children commitrow selectedline thickerline
225 foreach id
$displayorder {
226 catch
{unset children
($n,$id)}
227 catch
{unset commitrow
($n,$id)}
230 catch
{unset selectedline
}
231 catch
{unset thickerline
}
232 catch
{unset viewdata
($n)}
239 proc parsecommit
{id contents listed
} {
240 global commitinfo cdate
249 set hdrend
[string first
"\n\n" $contents]
251 # should never happen...
252 set hdrend
[string length
$contents]
254 set header
[string range
$contents 0 [expr {$hdrend - 1}]]
255 set comment
[string range
$contents [expr {$hdrend + 2}] end
]
256 foreach line
[split $header "\n"] {
257 set tag
[lindex
$line 0]
258 if {$tag == "author"} {
259 set audate
[lindex
$line end-1
]
260 set auname
[lrange
$line 1 end-2
]
261 } elseif
{$tag == "committer"} {
262 set comdate
[lindex
$line end-1
]
263 set comname
[lrange
$line 1 end-2
]
267 # take the first line of the comment as the headline
268 set i
[string first
"\n" $comment]
270 set headline
[string trim
[string range
$comment 0 $i]]
272 set headline
$comment
275 # git rev-list indents the comment by 4 spaces;
276 # if we got this via git cat-file, add the indentation
278 foreach line
[split $comment "\n"] {
279 append newcomment
" "
280 append newcomment
$line
281 append newcomment
"\n"
283 set comment
$newcomment
285 if {$comdate != {}} {
286 set cdate
($id) $comdate
288 set commitinfo
($id) [list
$headline $auname $audate \
289 $comname $comdate $comment]
292 proc getcommit
{id
} {
293 global commitdata commitinfo
295 if {[info exists commitdata
($id)]} {
296 parsecommit
$id $commitdata($id) 1
299 if {![info exists commitinfo
($id)]} {
300 set commitinfo
($id) {"No commit information available"}
307 global tagids idtags headids idheads tagcontents
308 global otherrefids idotherrefs mainhead
310 foreach v
{tagids idtags headids idheads otherrefids idotherrefs
} {
313 set refd
[open
[list | git show-ref
] r
]
314 while {0 <= [set n
[gets
$refd line
]]} {
315 if {![regexp
{^
([0-9a-f]{40}) refs
/([^^
]*)$
} $line \
319 if {[regexp
{^remotes
/.
*/HEAD$
} $path match
]} {
322 if {![regexp
{^
(tags|heads
)/(.
*)$
} $path match
type name
]} {
326 if {[regexp
{^remotes
/} $path match
]} {
329 if {$type == "tags"} {
330 set tagids
($name) $id
331 lappend idtags
($id) $name
336 set commit
[exec git rev-parse
"$id^0"]
337 if {$commit != $id} {
338 set tagids
($name) $commit
339 lappend idtags
($commit) $name
343 set tagcontents
($name) [exec git cat-file tag
$id]
345 } elseif
{ $type == "heads" } {
346 set headids
($name) $id
347 lappend idheads
($id) $name
349 set otherrefids
($name) $id
350 lappend idotherrefs
($id) $name
356 set thehead
[exec git symbolic-ref HEAD
]
357 if {[string match
"refs/heads/*" $thehead]} {
358 set mainhead
[string range
$thehead 11 end
]
363 # update things for a head moved to a child of its previous location
364 proc movehead
{id name
} {
365 global headids idheads
367 removehead
$headids($name) $name
368 set headids
($name) $id
369 lappend idheads
($id) $name
372 # update things when a head has been removed
373 proc removehead
{id name
} {
374 global headids idheads
376 if {$idheads($id) eq
$name} {
379 set i
[lsearch
-exact $idheads($id) $name]
381 set idheads
($id) [lreplace
$idheads($id) $i $i]
387 proc show_error
{w top msg
} {
388 message
$w.m
-text $msg -justify center
-aspect 400
389 pack
$w.m
-side top
-fill x
-padx 20 -pady 20
390 button
$w.ok
-text OK
-command "destroy $top"
391 pack
$w.ok
-side bottom
-fill x
392 bind $top <Visibility
> "grab $top; focus $top"
393 bind $top <Key-Return
> "destroy $top"
397 proc error_popup msg
{
401 show_error
$w $w $msg
404 proc confirm_popup msg
{
410 message
$w.m
-text $msg -justify center
-aspect 400
411 pack
$w.m
-side top
-fill x
-padx 20 -pady 20
412 button
$w.ok
-text OK
-command "set confirm_ok 1; destroy $w"
413 pack
$w.ok
-side left
-fill x
414 button
$w.cancel
-text Cancel
-command "destroy $w"
415 pack
$w.cancel
-side right
-fill x
416 bind $w <Visibility
> "grab $w; focus $w"
422 global canv canv2 canv3 linespc charspc ctext cflist
423 global textfont mainfont uifont tabstop
424 global findtype findtypemenu findloc findstring fstring geometry
425 global entries sha1entry sha1string sha1but
426 global maincursor textcursor curtextcursor
427 global rowctxmenu mergemax wrapcomment
428 global highlight_files gdttype
429 global searchstring sstring
430 global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
434 .bar add cascade
-label "File" -menu .bar.
file
435 .bar configure
-font $uifont
437 .bar.
file add
command -label "Update" -command updatecommits
438 .bar.
file add
command -label "Reread references" -command rereadrefs
439 .bar.
file add
command -label "Quit" -command doquit
440 .bar.
file configure
-font $uifont
442 .bar add cascade
-label "Edit" -menu .bar.edit
443 .bar.edit add
command -label "Preferences" -command doprefs
444 .bar.edit configure
-font $uifont
446 menu .bar.view
-font $uifont
447 .bar add cascade
-label "View" -menu .bar.view
448 .bar.view add
command -label "New view..." -command {newview
0}
449 .bar.view add
command -label "Edit view..." -command editview \
451 .bar.view add
command -label "Delete view" -command delview
-state disabled
452 .bar.view add separator
453 .bar.view add radiobutton
-label "All files" -command {showview
0} \
454 -variable selectedview
-value 0
457 .bar add cascade
-label "Help" -menu .bar.
help
458 .bar.
help add
command -label "About gitk" -command about
459 .bar.
help add
command -label "Key bindings" -command keys
460 .bar.
help configure
-font $uifont
461 . configure
-menu .bar
463 # the gui has upper and lower half, parts of a paned window.
464 panedwindow .ctop
-orient vertical
466 # possibly use assumed geometry
467 if {![info exists geometry
(pwsash0
)]} {
468 set geometry
(topheight
) [expr {15 * $linespc}]
469 set geometry
(topwidth
) [expr {80 * $charspc}]
470 set geometry
(botheight
) [expr {15 * $linespc}]
471 set geometry
(botwidth
) [expr {50 * $charspc}]
472 set geometry
(pwsash0
) "[expr {40 * $charspc}] 2"
473 set geometry
(pwsash1
) "[expr {60 * $charspc}] 2"
476 # the upper half will have a paned window, a scroll bar to the right, and some stuff below
477 frame .tf
-height $geometry(topheight
) -width $geometry(topwidth
)
479 panedwindow .tf.histframe.pwclist
-orient horizontal
-sashpad 0 -handlesize 4
481 # create three canvases
482 set cscroll .tf.histframe.csb
483 set canv .tf.histframe.pwclist.canv
485 -selectbackground $selectbgcolor \
486 -background $bgcolor -bd 0 \
487 -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
488 .tf.histframe.pwclist add
$canv
489 set canv2 .tf.histframe.pwclist.canv2
491 -selectbackground $selectbgcolor \
492 -background $bgcolor -bd 0 -yscrollincr $linespc
493 .tf.histframe.pwclist add
$canv2
494 set canv3 .tf.histframe.pwclist.canv3
496 -selectbackground $selectbgcolor \
497 -background $bgcolor -bd 0 -yscrollincr $linespc
498 .tf.histframe.pwclist add
$canv3
499 eval .tf.histframe.pwclist sash place
0 $geometry(pwsash0
)
500 eval .tf.histframe.pwclist sash place
1 $geometry(pwsash1
)
502 # a scroll bar to rule them
503 scrollbar
$cscroll -command {allcanvs yview
} -highlightthickness 0
504 pack
$cscroll -side right
-fill y
505 bind .tf.histframe.pwclist
<Configure
> {resizeclistpanes
%W
%w
}
506 lappend bglist
$canv $canv2 $canv3
507 pack .tf.histframe.pwclist
-fill both
-expand 1 -side left
509 # we have two button bars at bottom of top frame. Bar 1
511 frame .tf.lbar
-height 15
513 set sha1entry .tf.bar.sha1
514 set entries
$sha1entry
515 set sha1but .tf.bar.sha1label
516 button
$sha1but -text "SHA1 ID: " -state disabled
-relief flat \
517 -command gotocommit
-width 8 -font $uifont
518 $sha1but conf
-disabledforeground [$sha1but cget
-foreground]
519 pack .tf.bar.sha1label
-side left
520 entry
$sha1entry -width 40 -font $textfont -textvariable sha1string
521 trace add variable sha1string
write sha1change
522 pack
$sha1entry -side left
-pady 2
524 image create bitmap bm-left
-data {
525 #define left_width 16
526 #define left_height 16
527 static unsigned char left_bits
[] = {
528 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
529 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
530 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
532 image create bitmap bm-right
-data {
533 #define right_width 16
534 #define right_height 16
535 static unsigned char right_bits
[] = {
536 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
537 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
538 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
540 button .tf.bar.leftbut
-image bm-left
-command goback \
541 -state disabled
-width 26
542 pack .tf.bar.leftbut
-side left
-fill y
543 button .tf.bar.rightbut
-image bm-right
-command goforw \
544 -state disabled
-width 26
545 pack .tf.bar.rightbut
-side left
-fill y
547 button .tf.bar.findbut
-text "Find" -command dofind
-font $uifont
548 pack .tf.bar.findbut
-side left
550 set fstring .tf.bar.findstring
551 lappend entries
$fstring
552 entry
$fstring -width 30 -font $textfont -textvariable findstring
553 trace add variable findstring
write find_change
554 pack
$fstring -side left
-expand 1 -fill x
-in .tf.bar
556 set findtypemenu
[tk_optionMenu .tf.bar.findtype \
557 findtype Exact IgnCase Regexp
]
558 trace add variable findtype
write find_change
559 .tf.bar.findtype configure
-font $uifont
560 .tf.bar.findtype.menu configure
-font $uifont
561 set findloc
"All fields"
562 tk_optionMenu .tf.bar.findloc findloc
"All fields" Headline \
563 Comments Author Committer
564 trace add variable findloc
write find_change
565 .tf.bar.findloc configure
-font $uifont
566 .tf.bar.findloc.menu configure
-font $uifont
567 pack .tf.bar.findloc
-side right
568 pack .tf.bar.findtype
-side right
570 # build up the bottom bar of upper window
571 label .tf.lbar.flabel
-text "Highlight: Commits " \
573 pack .tf.lbar.flabel
-side left
-fill y
574 set gdttype
"touching paths:"
575 set gm
[tk_optionMenu .tf.lbar.gdttype gdttype
"touching paths:" \
576 "adding/removing string:"]
577 trace add variable gdttype
write hfiles_change
578 $gm conf
-font $uifont
579 .tf.lbar.gdttype conf
-font $uifont
580 pack .tf.lbar.gdttype
-side left
-fill y
581 entry .tf.lbar.fent
-width 25 -font $textfont \
582 -textvariable highlight_files
583 trace add variable highlight_files
write hfiles_change
584 lappend entries .tf.lbar.fent
585 pack .tf.lbar.fent
-side left
-fill x
-expand 1
586 label .tf.lbar.vlabel
-text " OR in view" -font $uifont
587 pack .tf.lbar.vlabel
-side left
-fill y
588 global viewhlmenu selectedhlview
589 set viewhlmenu
[tk_optionMenu .tf.lbar.vhl selectedhlview None
]
590 $viewhlmenu entryconf None
-command delvhighlight
591 $viewhlmenu conf
-font $uifont
592 .tf.lbar.vhl conf
-font $uifont
593 pack .tf.lbar.vhl
-side left
-fill y
594 label .tf.lbar.rlabel
-text " OR " -font $uifont
595 pack .tf.lbar.rlabel
-side left
-fill y
596 global highlight_related
597 set m
[tk_optionMenu .tf.lbar.relm highlight_related None \
598 "Descendent" "Not descendent" "Ancestor" "Not ancestor"]
599 $m conf
-font $uifont
600 .tf.lbar.relm conf
-font $uifont
601 trace add variable highlight_related
write vrel_change
602 pack .tf.lbar.relm
-side left
-fill y
604 # Finish putting the upper half of the viewer together
605 pack .tf.lbar
-in .tf
-side bottom
-fill x
606 pack .tf.bar
-in .tf
-side bottom
-fill x
607 pack .tf.histframe
-fill both
-side top
-expand 1
609 .ctop paneconfigure .tf
-height $geometry(topheight
)
610 .ctop paneconfigure .tf
-width $geometry(topwidth
)
612 # now build up the bottom
613 panedwindow .pwbottom
-orient horizontal
615 # lower left, a text box over search bar, scroll bar to the right
616 # if we know window height, then that will set the lower text height, otherwise
617 # we set lower text height which will drive window height
618 if {[info exists geometry
(main
)]} {
619 frame .bleft
-width $geometry(botwidth
)
621 frame .bleft
-width $geometry(botwidth
) -height $geometry(botheight
)
626 button .bleft.top.search
-text "Search" -command dosearch \
628 pack .bleft.top.search
-side left
-padx 5
629 set sstring .bleft.top.sstring
630 entry
$sstring -width 20 -font $textfont -textvariable searchstring
631 lappend entries
$sstring
632 trace add variable searchstring
write incrsearch
633 pack
$sstring -side left
-expand 1 -fill x
634 radiobutton .bleft.mid.
diff -text "Diff" \
635 -command changediffdisp
-variable diffelide
-value {0 0}
636 radiobutton .bleft.mid.old
-text "Old version" \
637 -command changediffdisp
-variable diffelide
-value {0 1}
638 radiobutton .bleft.mid.new
-text "New version" \
639 -command changediffdisp
-variable diffelide
-value {1 0}
640 pack .bleft.mid.
diff .bleft.mid.old .bleft.mid.new
-side left
641 set ctext .bleft.ctext
642 text
$ctext -background $bgcolor -foreground $fgcolor \
643 -tabs "[expr {$tabstop * $charspc}]" \
644 -state disabled
-font $textfont \
645 -yscrollcommand scrolltext
-wrap none
646 scrollbar .bleft.sb
-command "$ctext yview"
647 pack .bleft.top
-side top
-fill x
648 pack .bleft.mid
-side top
-fill x
649 pack .bleft.sb
-side right
-fill y
650 pack
$ctext -side left
-fill both
-expand 1
651 lappend bglist
$ctext
652 lappend fglist
$ctext
654 $ctext tag conf comment
-wrap $wrapcomment
655 $ctext tag conf filesep
-font [concat
$textfont bold
] -back "#aaaaaa"
656 $ctext tag conf hunksep
-fore [lindex
$diffcolors 2]
657 $ctext tag conf d0
-fore [lindex
$diffcolors 0]
658 $ctext tag conf d1
-fore [lindex
$diffcolors 1]
659 $ctext tag conf m0
-fore red
660 $ctext tag conf m1
-fore blue
661 $ctext tag conf m2
-fore green
662 $ctext tag conf m3
-fore purple
663 $ctext tag conf
m4 -fore brown
664 $ctext tag conf m5
-fore "#009090"
665 $ctext tag conf m6
-fore magenta
666 $ctext tag conf m7
-fore "#808000"
667 $ctext tag conf m8
-fore "#009000"
668 $ctext tag conf m9
-fore "#ff0080"
669 $ctext tag conf m10
-fore cyan
670 $ctext tag conf m11
-fore "#b07070"
671 $ctext tag conf m12
-fore "#70b0f0"
672 $ctext tag conf m13
-fore "#70f0b0"
673 $ctext tag conf m14
-fore "#f0b070"
674 $ctext tag conf m15
-fore "#ff70b0"
675 $ctext tag conf mmax
-fore darkgrey
677 $ctext tag conf mresult
-font [concat
$textfont bold
]
678 $ctext tag conf msep
-font [concat
$textfont bold
]
679 $ctext tag conf found
-back yellow
682 .pwbottom paneconfigure .bleft
-width $geometry(botwidth
)
687 radiobutton .bright.mode.
patch -text "Patch" \
688 -command reselectline
-variable cmitmode
-value "patch"
689 .bright.mode.
patch configure
-font $uifont
690 radiobutton .bright.mode.tree
-text "Tree" \
691 -command reselectline
-variable cmitmode
-value "tree"
692 .bright.mode.tree configure
-font $uifont
693 grid .bright.mode.
patch .bright.mode.tree
-sticky ew
694 pack .bright.mode
-side top
-fill x
695 set cflist .bright.cfiles
696 set indent
[font measure
$mainfont "nn"]
698 -selectbackground $selectbgcolor \
699 -background $bgcolor -foreground $fgcolor \
701 -tabs [list
$indent [expr {2 * $indent}]] \
702 -yscrollcommand ".bright.sb set" \
703 -cursor [. cget
-cursor] \
704 -spacing1 1 -spacing3 1
705 lappend bglist
$cflist
706 lappend fglist
$cflist
707 scrollbar .bright.sb
-command "$cflist yview"
708 pack .bright.sb
-side right
-fill y
709 pack
$cflist -side left
-fill both
-expand 1
710 $cflist tag configure highlight \
711 -background [$cflist cget
-selectbackground]
712 $cflist tag configure bold
-font [concat
$mainfont bold
]
714 .pwbottom add .bright
717 # restore window position if known
718 if {[info exists geometry
(main
)]} {
719 wm geometry .
"$geometry(main)"
722 bind .pwbottom
<Configure
> {resizecdetpanes
%W
%w
}
723 pack .ctop
-fill both
-expand 1
724 bindall
<1> {selcanvline
%W
%x
%y
}
725 #bindall <B1-Motion> {selcanvline %W %x %y}
726 bindall
<ButtonRelease-4
> "allcanvs yview scroll -5 units"
727 bindall
<ButtonRelease-5
> "allcanvs yview scroll 5 units"
728 bindall
<2> "canvscan mark %W %x %y"
729 bindall
<B2-Motion
> "canvscan dragto %W %x %y"
730 bindkey
<Home
> selfirstline
731 bindkey
<End
> sellastline
732 bind .
<Key-Up
> "selnextline -1"
733 bind .
<Key-Down
> "selnextline 1"
734 bind .
<Shift-Key-Up
> "next_highlight -1"
735 bind .
<Shift-Key-Down
> "next_highlight 1"
736 bindkey
<Key-Right
> "goforw"
737 bindkey
<Key-Left
> "goback"
738 bind .
<Key-Prior
> "selnextpage -1"
739 bind .
<Key-Next
> "selnextpage 1"
740 bind .
<Control-Home
> "allcanvs yview moveto 0.0"
741 bind .
<Control-End
> "allcanvs yview moveto 1.0"
742 bind .
<Control-Key-Up
> "allcanvs yview scroll -1 units"
743 bind .
<Control-Key-Down
> "allcanvs yview scroll 1 units"
744 bind .
<Control-Key-Prior
> "allcanvs yview scroll -1 pages"
745 bind .
<Control-Key-Next
> "allcanvs yview scroll 1 pages"
746 bindkey
<Key-Delete
> "$ctext yview scroll -1 pages"
747 bindkey
<Key-BackSpace
> "$ctext yview scroll -1 pages"
748 bindkey
<Key-space
> "$ctext yview scroll 1 pages"
749 bindkey p
"selnextline -1"
750 bindkey n
"selnextline 1"
753 bindkey i
"selnextline -1"
754 bindkey k
"selnextline 1"
757 bindkey b
"$ctext yview scroll -1 pages"
758 bindkey d
"$ctext yview scroll 18 units"
759 bindkey u
"$ctext yview scroll -18 units"
760 bindkey
/ {findnext
1}
761 bindkey
<Key-Return
> {findnext
0}
764 bindkey
<F5
> updatecommits
765 bind .
<Control-q
> doquit
766 bind .
<Control-f
> dofind
767 bind .
<Control-g
> {findnext
0}
768 bind .
<Control-r
> dosearchback
769 bind .
<Control-s
> dosearch
770 bind .
<Control-equal
> {incrfont
1}
771 bind .
<Control-KP_Add
> {incrfont
1}
772 bind .
<Control-minus
> {incrfont
-1}
773 bind .
<Control-KP_Subtract
> {incrfont
-1}
774 wm protocol . WM_DELETE_WINDOW doquit
775 bind .
<Button-1
> "click %W"
776 bind $fstring <Key-Return
> dofind
777 bind $sha1entry <Key-Return
> gotocommit
778 bind $sha1entry <<PasteSelection>> clearsha1
779 bind $cflist <1> {sel_flist %W %x %y; break}
780 bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
781 bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
783 set maincursor [. cget -cursor]
784 set textcursor [$ctext cget -cursor]
785 set curtextcursor $textcursor
787 set rowctxmenu .rowctxmenu
788 menu $rowctxmenu -tearoff 0
789 $rowctxmenu add command -label "Diff this -> selected" \
790 -command {diffvssel 0}
791 $rowctxmenu add command -label "Diff selected -> this" \
792 -command {diffvssel 1}
793 $rowctxmenu add command -label "Make patch" -command mkpatch
794 $rowctxmenu add command -label "Create tag" -command mktag
795 $rowctxmenu add command -label "Write commit to file" -command writecommit
796 $rowctxmenu add command -label "Create new branch" -command mkbranch
797 $rowctxmenu add command -label "Cherry-pick this commit" \
800 set headctxmenu .headctxmenu
801 menu $headctxmenu -tearoff 0
802 $headctxmenu add command -label "Check out this branch" \
804 $headctxmenu add command -label "Remove this branch" \
808 # mouse-2 makes all windows scan vertically, but only the one
809 # the cursor is in scans horizontally
810 proc canvscan {op w x y} {
811 global canv canv2 canv3
812 foreach c [list $canv $canv2 $canv3] {
821 proc scrollcanv {cscroll f0 f1} {
827 # when we make a key binding for the toplevel, make sure
828 # it doesn't get triggered when that key is pressed in the
829 # find string entry widget.
830 proc bindkey {ev script} {
833 set escript [bind Entry $ev]
834 if {$escript == {}} {
835 set escript [bind Entry <Key>]
838 bind $e $ev "$escript; break"
842 # set the focus back to the toplevel for any click outside
853 global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop
854 global stuffsaved findmergefiles maxgraphpct
855 global maxwidth showneartags
856 global viewname viewfiles viewargs viewperm nextviewnum
857 global cmitmode wrapcomment
858 global colors bgcolor fgcolor diffcolors selectbgcolor
860 if {$stuffsaved} return
861 if {![winfo viewable .]} return
863 set f [open "~/.gitk-new" w]
864 puts $f [list set mainfont $mainfont]
865 puts $f [list set textfont $textfont]
866 puts $f [list set uifont $uifont]
867 puts $f [list set tabstop $tabstop]
868 puts $f [list set findmergefiles $findmergefiles]
869 puts $f [list set maxgraphpct $maxgraphpct]
870 puts $f [list set maxwidth $maxwidth]
871 puts $f [list set cmitmode $cmitmode]
872 puts $f [list set wrapcomment $wrapcomment]
873 puts $f [list set showneartags $showneartags]
874 puts $f [list set bgcolor $bgcolor]
875 puts $f [list set fgcolor $fgcolor]
876 puts $f [list set colors $colors]
877 puts $f [list set diffcolors $diffcolors]
878 puts $f [list set selectbgcolor $selectbgcolor]
880 puts $f "set geometry(main) [wm geometry .]"
881 puts $f "set geometry(topwidth) [winfo width .tf]"
882 puts $f "set geometry(topheight) [winfo height .tf]"
883 puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\""
884 puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sash coord 1]\""
885 puts $f "set geometry(botwidth) [winfo width .bleft]"
886 puts $f "set geometry(botheight) [winfo height .bleft]"
888 puts -nonewline $f "set permviews {"
889 for {set v 0} {$v < $nextviewnum} {incr v} {
891 puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v)]}"
896 file rename -force "~/.gitk-new" "~/.gitk"
901 proc resizeclistpanes {win w} {
903 if {[info exists oldwidth($win)]} {
904 set s0 [$win sash coord 0]
905 set s1 [$win sash coord 1]
907 set sash0 [expr {int($w/2 - 2)}]
908 set sash1 [expr {int($w*5/6 - 2)}]
910 set factor [expr {1.0 * $w / $oldwidth($win)}]
911 set sash0 [expr {int($factor * [lindex $s0 0])}]
912 set sash1 [expr {int($factor * [lindex $s1 0])}]
916 if {$sash1 < $sash0 + 20} {
917 set sash1 [expr {$sash0 + 20}]
919 if {$sash1 > $w - 10} {
920 set sash1 [expr {$w - 10}]
921 if {$sash0 > $sash1 - 20} {
922 set sash0 [expr {$sash1 - 20}]
926 $win sash place 0 $sash0 [lindex $s0 1]
927 $win sash place 1 $sash1 [lindex $s1 1]
929 set oldwidth($win) $w
932 proc resizecdetpanes {win w} {
934 if {[info exists oldwidth($win)]} {
935 set s0 [$win sash coord 0]
937 set sash0 [expr {int($w*3/4 - 2)}]
939 set factor [expr {1.0 * $w / $oldwidth($win)}]
940 set sash0 [expr {int($factor * [lindex $s0 0])}]
944 if {$sash0 > $w - 15} {
945 set sash0 [expr {$w - 15}]
948 $win sash place 0 $sash0 [lindex $s0 1]
950 set oldwidth($win) $w
954 global canv canv2 canv3
960 proc bindall {event action} {
961 global canv canv2 canv3
962 bind $canv $event $action
963 bind $canv2 $event $action
964 bind $canv3 $event $action
970 if {[winfo exists $w]} {
975 wm title $w "About gitk"
977 Gitk - a commit viewer for git
979 Copyright © 2005-2006 Paul Mackerras
981 Use and redistribute under the terms of the GNU General Public License} \
982 -justify center -aspect 400 -border 2 -bg white -relief groove
983 pack $w.m -side top -fill x -padx 2 -pady 2
984 $w.m configure -font $uifont
985 button $w.ok -text Close -command "destroy $w" -default active
986 pack $w.ok -side bottom
987 $w.ok configure -font $uifont
988 bind $w <Visibility> "focus $w.ok"
989 bind $w <Key-Escape> "destroy $w"
990 bind $w <Key-Return> "destroy $w"
996 if {[winfo exists $w]} {
1001 wm title $w "Gitk key bindings"
1002 message $w.m -text {
1006 <Home> Move to first commit
1007 <End> Move to last commit
1008 <Up>, p, i Move up one commit
1009 <Down>, n, k Move down one commit
1010 <Left>, z, j Go back in history list
1011 <Right>, x, l Go forward in history list
1012 <PageUp> Move up one page in commit list
1013 <PageDown> Move down one page in commit list
1014 <Ctrl-Home> Scroll to top of commit list
1015 <Ctrl-End> Scroll to bottom of commit list
1016 <Ctrl-Up> Scroll commit list up one line
1017 <Ctrl-Down> Scroll commit list down one line
1018 <Ctrl-PageUp> Scroll commit list up one page
1019 <Ctrl-PageDown> Scroll commit list down one page
1020 <Shift-Up> Move to previous highlighted line
1021 <Shift-Down> Move to next highlighted line
1022 <Delete>, b Scroll diff view up one page
1023 <Backspace> Scroll diff view up one page
1024 <Space> Scroll diff view down one page
1025 u Scroll diff view up 18 lines
1026 d Scroll diff view down 18 lines
1028 <Ctrl-G> Move to next find hit
1029 <Return> Move to next find hit
1030 / Move to next find hit, or redo find
1031 ? Move to previous find hit
1032 f Scroll diff view to next file
1033 <Ctrl-S> Search for next hit in diff view
1034 <Ctrl-R> Search for previous hit in diff view
1035 <Ctrl-KP+> Increase font size
1036 <Ctrl-plus> Increase font size
1037 <Ctrl-KP-> Decrease font size
1038 <Ctrl-minus> Decrease font size
1041 -justify left -bg white -border 2 -relief groove
1042 pack $w.m -side top -fill both -padx 2 -pady 2
1043 $w.m configure -font $uifont
1044 button $w.ok -text Close -command "destroy $w" -default active
1045 pack $w.ok -side bottom
1046 $w.ok configure -font $uifont
1047 bind $w <Visibility> "focus $w.ok"
1048 bind $w <Key-Escape> "destroy $w"
1049 bind $w <Key-Return> "destroy $w"
1052 # Procedures for manipulating the file list window at the
1053 # bottom right of the overall window.
1055 proc treeview {w l openlevs} {
1056 global treecontents treediropen treeheight treeparent treeindex
1066 set treecontents() {}
1067 $w conf -state normal
1069 while {[string range $f 0 $prefixend] ne $prefix} {
1070 if {$lev <= $openlevs} {
1071 $w mark set e:$treeindex($prefix) "end -1c"
1072 $w mark gravity e:$treeindex($prefix) left
1074 set treeheight($prefix) $ht
1075 incr ht [lindex $htstack end]
1076 set htstack [lreplace $htstack end end]
1077 set prefixend [lindex $prefendstack end]
1078 set prefendstack [lreplace $prefendstack end end]
1079 set prefix [string range $prefix 0 $prefixend]
1082 set tail [string range $f [expr {$prefixend+1}] end]
1083 while {[set slash [string first "/" $tail]] >= 0} {
1086 lappend prefendstack $prefixend
1087 incr prefixend [expr {$slash + 1}]
1088 set d [string range $tail 0 $slash]
1089 lappend treecontents($prefix) $d
1090 set oldprefix $prefix
1092 set treecontents($prefix) {}
1093 set treeindex($prefix) [incr ix]
1094 set treeparent($prefix) $oldprefix
1095 set tail [string range $tail [expr {$slash+1}] end]
1096 if {$lev <= $openlevs} {
1098 set treediropen($prefix) [expr {$lev < $openlevs}]
1099 set bm [expr {$lev == $openlevs? "tri-rt": "tri-dn"}]
1100 $w mark set d:$ix "end -1c"
1101 $w mark gravity d:$ix left
1103 for {set i 0} {$i < $lev} {incr i} {append str "\t"}
1105 $w image create end -align center -image $bm -padx 1 \
1107 $w insert end $d [highlight_tag $prefix]
1108 $w mark set s:$ix "end -1c"
1109 $w mark gravity s:$ix left
1114 if {$lev <= $openlevs} {
1117 for {set i 0} {$i < $lev} {incr i} {append str "\t"}
1119 $w insert end $tail [highlight_tag $f]
1121 lappend treecontents($prefix) $tail
1124 while {$htstack ne {}} {
1125 set treeheight($prefix) $ht
1126 incr ht [lindex $htstack end]
1127 set htstack [lreplace $htstack end end]
1129 $w conf -state disabled
1132 proc linetoelt {l} {
1133 global treeheight treecontents
1138 foreach e $treecontents($prefix) {
1143 if {[string index $e end] eq "/"} {
1144 set n $treeheight($prefix$e)
1156 proc highlight_tree {y prefix} {
1157 global treeheight treecontents cflist
1159 foreach e $treecontents($prefix) {
1161 if {[highlight_tag $path] ne {}} {
1162 $cflist tag add bold $y.0 "$y.0 lineend"
1165 if {[string index $e end] eq "/" && $treeheight($path) > 1} {
1166 set y [highlight_tree $y $path]
1172 proc treeclosedir {w dir} {
1173 global treediropen treeheight treeparent treeindex
1175 set ix $treeindex($dir)
1176 $w conf -state normal
1177 $w delete s:$ix e:$ix
1178 set treediropen($dir) 0
1179 $w image configure a:$ix -image tri-rt
1180 $w conf -state disabled
1181 set n [expr {1 - $treeheight($dir)}]
1182 while {$dir ne {}} {
1183 incr treeheight($dir) $n
1184 set dir $treeparent($dir)
1188 proc treeopendir {w dir} {
1189 global treediropen treeheight treeparent treecontents treeindex
1191 set ix $treeindex($dir)
1192 $w conf -state normal
1193 $w image configure a:$ix -image tri-dn
1194 $w mark set e:$ix s:$ix
1195 $w mark gravity e:$ix right
1198 set n [llength $treecontents($dir)]
1199 for {set x $dir} {$x ne {}} {set x $treeparent($x)} {
1202 incr treeheight($x) $n
1204 foreach e $treecontents($dir) {
1206 if {[string index $e end] eq "/"} {
1207 set iy $treeindex($de)
1208 $w mark set d:$iy e:$ix
1209 $w mark gravity d:$iy left
1210 $w insert e:$ix $str
1211 set treediropen($de) 0
1212 $w image create e:$ix -align center -image tri-rt -padx 1 \
1214 $w insert e:$ix $e [highlight_tag $de]
1215 $w mark set s:$iy e:$ix
1216 $w mark gravity s:$iy left
1217 set treeheight($de) 1
1219 $w insert e:$ix $str
1220 $w insert e:$ix $e [highlight_tag $de]
1223 $w mark gravity e:$ix left
1224 $w conf -state disabled
1225 set treediropen($dir) 1
1226 set top [lindex [split [$w index @0,0] .] 0]
1227 set ht [$w cget -height]
1228 set l [lindex [split [$w index s:$ix] .] 0]
1231 } elseif {$l + $n + 1 > $top + $ht} {
1232 set top [expr {$l + $n + 2 - $ht}]
1240 proc treeclick {w x y} {
1241 global treediropen cmitmode ctext cflist cflist_top
1243 if {$cmitmode ne "tree"} return
1244 if {![info exists cflist_top]} return
1245 set l [lindex [split [$w index "@$x,$y"] "."] 0]
1246 $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend"
1247 $cflist tag add highlight $l.0 "$l.0 lineend"
1253 set e [linetoelt $l]
1254 if {[string index $e end] ne "/"} {
1256 } elseif {$treediropen($e)} {
1263 proc setfilelist {id} {
1264 global treefilelist cflist
1266 treeview $cflist $treefilelist($id) 0
1269 image create bitmap tri-rt -background black -foreground blue -data {
1270 #define tri-rt_width 13
1271 #define tri-rt_height 13
1272 static unsigned char tri-rt_bits[] = {
1273 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x70, 0x00, 0xf0, 0x00,
1274 0xf0, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x30, 0x00, 0x10, 0x00, 0x00, 0x00,
1277 #define tri-rt-mask_width 13
1278 #define tri-rt-mask_height 13
1279 static unsigned char tri-rt-mask_bits[] = {
1280 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00, 0xf8, 0x01,
1281 0xf8, 0x03, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00,
1284 image create bitmap tri-dn -background black -foreground blue -data {
1285 #define tri-dn_width 13
1286 #define tri-dn_height 13
1287 static unsigned char tri-dn_bits[] = {
1288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xf8, 0x03,
1289 0xf0, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1292 #define tri-dn-mask_width 13
1293 #define tri-dn-mask_height 13
1294 static unsigned char tri-dn-mask_bits[] = {
1295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0xfe, 0x0f, 0xfc, 0x07,
1296 0xf8, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1300 proc init_flist {first} {
1301 global cflist cflist_top selectedline difffilestart
1303 $cflist conf -state normal
1304 $cflist delete 0.0 end
1306 $cflist insert end $first
1308 $cflist tag add highlight 1.0 "1.0 lineend"
1310 catch {unset cflist_top}
1312 $cflist conf -state disabled
1313 set difffilestart {}
1316 proc highlight_tag {f} {
1317 global highlight_paths
1319 foreach p $highlight_paths {
1320 if {[string match $p $f]} {
1327 proc highlight_filelist {} {
1328 global cmitmode cflist
1330 $cflist conf -state normal
1331 if {$cmitmode ne "tree"} {
1332 set end [lindex [split [$cflist index end] .] 0]
1333 for {set l 2} {$l < $end} {incr l} {
1334 set line [$cflist get $l.0 "$l.0 lineend"]
1335 if {[highlight_tag $line] ne {}} {
1336 $cflist tag add bold $l.0 "$l.0 lineend"
1342 $cflist conf -state disabled
1345 proc unhighlight_filelist {} {
1348 $cflist conf -state normal
1349 $cflist tag remove bold 1.0 end
1350 $cflist conf -state disabled
1353 proc add_flist {fl} {
1356 $cflist conf -state normal
1358 $cflist insert end "\n"
1359 $cflist insert end $f [highlight_tag $f]
1361 $cflist conf -state disabled
1364 proc sel_flist {w x y} {
1365 global ctext difffilestart cflist cflist_top cmitmode
1367 if {$cmitmode eq "tree"} return
1368 if {![info exists cflist_top]} return
1369 set l [lindex [split [$w index "@$x,$y"] "."] 0]
1370 $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend"
1371 $cflist tag add highlight $l.0 "$l.0 lineend"
1376 catch {$ctext yview [lindex $difffilestart [expr {$l - 2}]]}
1380 # Functions for adding and removing shell-type quoting
1382 proc shellquote {str} {
1383 if {![string match "*\['\"\\ \t]*" $str]} {
1386 if {![string match "*\['\"\\]*" $str]} {
1389 if {![string match "*'*" $str]} {
1392 return "\"[string map {\" \\\" \\ \\\\} $str]\""
1395 proc shellarglist {l} {
1401 append str [shellquote $a]
1406 proc shelldequote {str} {
1411 if {![regexp -start $used -indices "\['\"\\\\ \t]" $str first]} {
1412 append ret [string range $str $used end]
1413 set used [string length $str]
1416 set first [lindex $first 0]
1417 set ch [string index $str $first]
1418 if {$first > $used} {
1419 append ret [string range $str $used [expr {$first - 1}]]
1422 if {$ch eq " " || $ch eq "\t"} break
1425 set first [string first "'" $str $used]
1427 error "unmatched single-quote"
1429 append ret [string range $str $used [expr {$first - 1}]]
1434 if {$used >= [string length $str]} {
1435 error "trailing backslash"
1437 append ret [string index $str $used]
1442 if {![regexp -start $used -indices "\[\"\\\\]" $str first]} {
1443 error "unmatched double-quote"
1445 set first [lindex $first 0]
1446 set ch [string index $str $first]
1447 if {$first > $used} {
1448 append ret [string range $str $used [expr {$first - 1}]]
1451 if {$ch eq "\""} break
1453 append ret [string index $str $used]
1457 return [list $used $ret]
1460 proc shellsplit {str} {
1463 set str [string trimleft $str]
1464 if {$str eq {}} break
1465 set dq [shelldequote $str]
1466 set n [lindex $dq 0]
1467 set word [lindex $dq 1]
1468 set str [string range $str $n end]
1474 # Code to implement multiple views
1476 proc newview {ishighlight} {
1477 global nextviewnum newviewname newviewperm uifont newishighlight
1478 global newviewargs revtreeargs
1480 set newishighlight $ishighlight
1482 if {[winfo exists $top]} {
1486 set newviewname($nextviewnum) "View $nextviewnum"
1487 set newviewperm($nextviewnum) 0
1488 set newviewargs($nextviewnum) [shellarglist $revtreeargs]
1489 vieweditor $top $nextviewnum "Gitk view definition"
1494 global viewname viewperm newviewname newviewperm
1495 global viewargs newviewargs
1497 set top .gitkvedit-$curview
1498 if {[winfo exists $top]} {
1502 set newviewname($curview) $viewname($curview)
1503 set newviewperm($curview) $viewperm($curview)
1504 set newviewargs($curview) [shellarglist $viewargs($curview)]
1505 vieweditor $top $curview "Gitk: edit view $viewname($curview)"
1508 proc vieweditor {top n title} {
1509 global newviewname newviewperm viewfiles
1513 wm title $top $title
1514 label $top.nl -text "Name" -font $uifont
1515 entry $top.name -width 20 -textvariable newviewname($n) -font $uifont
1516 grid $top.nl $top.name -sticky w -pady 5
1517 checkbutton $top.perm -text "Remember this view" -variable newviewperm($n) \
1519 grid $top.perm - -pady 5 -sticky w
1520 message $top.al -aspect 1000 -font $uifont \
1521 -text "Commits to include (arguments to git rev-list):"
1522 grid $top.al - -sticky w -pady 5
1523 entry $top.args -width 50 -textvariable newviewargs($n) \
1524 -background white -font $uifont
1525 grid $top.args - -sticky ew -padx 5
1526 message $top.l -aspect 1000 -font $uifont \
1527 -text "Enter files and directories to include, one per line:"
1528 grid $top.l - -sticky w
1529 text $top.t -width 40 -height 10 -background white -font $uifont
1530 if {[info exists viewfiles($n)]} {
1531 foreach f $viewfiles($n) {
1532 $top.t insert end $f
1533 $top.t insert end "\n"
1535 $top.t delete {end - 1c} end
1536 $top.t mark set insert 0.0
1538 grid $top.t - -sticky ew -padx 5
1540 button $top.buts.ok -text "OK" -command [list newviewok $top $n] \
1542 button $top.buts.can -text "Cancel" -command [list destroy $top] \
1544 grid $top.buts.ok $top.buts.can
1545 grid columnconfigure $top.buts 0 -weight 1 -uniform a
1546 grid columnconfigure $top.buts 1 -weight 1 -uniform a
1547 grid $top.buts - -pady 10 -sticky ew
1551 proc doviewmenu {m first cmd op argv} {
1552 set nmenu [$m index end]
1553 for {set i $first} {$i <= $nmenu} {incr i} {
1554 if {[$m entrycget $i -command] eq $cmd} {
1555 eval $m $op $i $argv
1561 proc allviewmenus {n op args} {
1564 doviewmenu .bar.view 5 [list showview $n] $op $args
1565 doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args
1568 proc newviewok {top n} {
1569 global nextviewnum newviewperm newviewname newishighlight
1570 global viewname viewfiles viewperm selectedview curview
1571 global viewargs newviewargs viewhlmenu
1574 set newargs [shellsplit $newviewargs($n)]
1576 error_popup "Error in commit selection arguments: $err"
1582 foreach f [split [$top.t get 0.0 end] "\n"] {
1583 set ft [string trim $f]
1588 if {![info exists viewfiles($n)]} {
1589 # creating a new view
1591 set viewname($n) $newviewname($n)
1592 set viewperm($n) $newviewperm($n)
1593 set viewfiles($n) $files
1594 set viewargs($n) $newargs
1596 if {!$newishighlight} {
1597 after idle showview $n
1599 after idle addvhighlight $n
1602 # editing an existing view
1603 set viewperm($n) $newviewperm($n)
1604 if {$newviewname($n) ne $viewname($n)} {
1605 set viewname($n) $newviewname($n)
1606 doviewmenu .bar.view 5 [list showview $n] \
1607 entryconf [list -label $viewname($n)]
1608 doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
1609 entryconf [list -label $viewname($n) -value $viewname($n)]
1611 if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} {
1612 set viewfiles($n) $files
1613 set viewargs($n) $newargs
1614 if {$curview == $n} {
1615 after idle updatecommits
1619 catch {destroy $top}
1623 global curview viewdata viewperm hlview selectedhlview
1625 if {$curview == 0} return
1626 if {[info exists hlview] && $hlview == $curview} {
1627 set selectedhlview None
1630 allviewmenus $curview delete
1631 set viewdata($curview) {}
1632 set viewperm($curview) 0
1636 proc addviewmenu {n} {
1637 global viewname viewhlmenu
1639 .bar.view add radiobutton -label $viewname($n) \
1640 -command [list showview $n] -variable selectedview -value $n
1641 $viewhlmenu add radiobutton -label $viewname($n) \
1642 -command [list addvhighlight $n] -variable selectedhlview
1645 proc flatten {var} {
1649 foreach i [array names $var] {
1650 lappend ret $i [set $var\($i\)]
1655 proc unflatten {var l} {
1665 global curview viewdata viewfiles
1666 global displayorder parentlist childlist rowidlist rowoffsets
1667 global colormap rowtextx commitrow nextcolor canvxmax
1668 global numcommits rowrangelist commitlisted idrowranges
1669 global selectedline currentid canv canvy0
1670 global matchinglines treediffs
1671 global pending_select phase
1672 global commitidx rowlaidout rowoptim linesegends
1673 global commfd nextupdate
1675 global vparentlist vchildlist vdisporder vcmitlisted
1676 global hlview selectedhlview
1678 if {$n == $curview} return
1680 if {[info exists selectedline]} {
1681 set selid $currentid
1682 set y [yc $selectedline]
1683 set ymax [lindex [$canv cget -scrollregion] 3]
1684 set span [$canv yview]
1685 set ytop [expr {[lindex $span 0] * $ymax}]
1686 set ybot [expr {[lindex $span 1] * $ymax}]
1687 if {$ytop < $y && $y < $ybot} {
1688 set yscreen [expr {$y - $ytop}]
1690 set yscreen [expr {($ybot - $ytop) / 2}]
1696 if {$curview >= 0} {
1697 set vparentlist($curview) $parentlist
1698 set vchildlist($curview) $childlist
1699 set vdisporder($curview) $displayorder
1700 set vcmitlisted($curview) $commitlisted
1702 set viewdata($curview) \
1703 [list $phase $rowidlist $rowoffsets $rowrangelist \
1704 [flatten idrowranges] [flatten idinlist] \
1705 $rowlaidout $rowoptim $numcommits $linesegends]
1706 } elseif {![info exists viewdata($curview)]
1707 || [lindex $viewdata($curview) 0] ne {}} {
1708 set viewdata($curview) \
1709 [list {} $rowidlist $rowoffsets $rowrangelist]
1712 catch {unset matchinglines}
1713 catch {unset treediffs}
1715 if {[info exists hlview] && $hlview == $n} {
1717 set selectedhlview None
1722 .bar.view entryconf Edit* -state [expr {$n == 0? "disabled": "normal"}]
1723 .bar.view entryconf Delete* -state [expr {$n == 0? "disabled": "normal"}]
1725 if {![info exists viewdata($n)]} {
1726 set pending_select $selid
1732 set phase [lindex $v 0]
1733 set displayorder $vdisporder($n)
1734 set parentlist $vparentlist($n)
1735 set childlist $vchildlist($n)
1736 set commitlisted $vcmitlisted($n)
1737 set rowidlist [lindex $v 1]
1738 set rowoffsets [lindex $v 2]
1739 set rowrangelist [lindex $v 3]
1741 set numcommits [llength $displayorder]
1742 catch {unset idrowranges}
1744 unflatten idrowranges [lindex $v 4]
1745 unflatten idinlist [lindex $v 5]
1746 set rowlaidout [lindex $v 6]
1747 set rowoptim [lindex $v 7]
1748 set numcommits [lindex $v 8]
1749 set linesegends [lindex $v 9]
1752 catch {unset colormap}
1753 catch {unset rowtextx}
1755 set canvxmax [$canv cget -width]
1761 if {$selid ne {} && [info exists commitrow($n,$selid)]} {
1762 set row $commitrow($n,$selid)
1763 # try to get the selected row in the same position on the screen
1764 set ymax [lindex [$canv cget -scrollregion] 3]
1765 set ytop [expr {[yc $row] - $yscreen}]
1769 set yf [expr {$ytop * 1.0 / $ymax}]
1771 allcanvs yview moveto $yf
1775 if {$phase eq "getcommits"} {
1776 show_status "Reading commits..."
1778 if {[info exists commfd($n)]} {
1783 } elseif {$numcommits == 0} {
1784 show_status "No commits selected"
1788 # Stuff relating to the highlighting facility
1790 proc ishighlighted {row} {
1791 global vhighlights fhighlights nhighlights rhighlights
1793 if {[info exists nhighlights($row)] && $nhighlights($row) > 0} {
1794 return $nhighlights($row)
1796 if {[info exists vhighlights($row)] && $vhighlights($row) > 0} {
1797 return $vhighlights($row)
1799 if {[info exists fhighlights($row)] && $fhighlights($row) > 0} {
1800 return $fhighlights($row)
1802 if {[info exists rhighlights($row)] && $rhighlights($row) > 0} {
1803 return $rhighlights($row)
1808 proc bolden {row font} {
1809 global canv linehtag selectedline boldrows
1811 lappend boldrows $row
1812 $canv itemconf $linehtag($row) -font $font
1813 if {[info exists selectedline] && $row == $selectedline} {
1815 set t [eval $canv create rect [$canv bbox $linehtag($row)] \
1816 -outline {{}} -tags secsel \
1817 -fill [$canv cget -selectbackground]]
1822 proc bolden_name {row font} {
1823 global canv2 linentag selectedline boldnamerows
1825 lappend boldnamerows $row
1826 $canv2 itemconf $linentag($row) -font $font
1827 if {[info exists selectedline] && $row == $selectedline} {
1828 $canv2 delete secsel
1829 set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \
1830 -outline {{}} -tags secsel \
1831 -fill [$canv2 cget -selectbackground]]
1837 global mainfont boldrows
1840 foreach row $boldrows {
1841 if {![ishighlighted $row]} {
1842 bolden $row $mainfont
1844 lappend stillbold $row
1847 set boldrows $stillbold
1850 proc addvhighlight {n} {
1851 global hlview curview viewdata vhl_done vhighlights commitidx
1853 if {[info exists hlview]} {
1857 if {$n != $curview && ![info exists viewdata($n)]} {
1858 set viewdata($n) [list getcommits {{}} {{}} {} {} {} 0 0 0 {}]
1859 set vparentlist($n) {}
1860 set vchildlist($n) {}
1861 set vdisporder($n) {}
1862 set vcmitlisted($n) {}
1865 set vhl_done $commitidx($hlview)
1866 if {$vhl_done > 0} {
1871 proc delvhighlight {} {
1872 global hlview vhighlights
1874 if {![info exists hlview]} return
1876 catch {unset vhighlights}
1880 proc vhighlightmore {} {
1881 global hlview vhl_done commitidx vhighlights
1882 global displayorder vdisporder curview mainfont
1884 set font [concat $mainfont bold]
1885 set max $commitidx($hlview)
1886 if {$hlview == $curview} {
1887 set disp $displayorder
1889 set disp $vdisporder($hlview)
1891 set vr [visiblerows]
1892 set r0 [lindex $vr 0]
1893 set r1 [lindex $vr 1]
1894 for {set i $vhl_done} {$i < $max} {incr i} {
1895 set id [lindex $disp $i]
1896 if {[info exists commitrow($curview,$id)]} {
1897 set row $commitrow($curview,$id)
1898 if {$r0 <= $row && $row <= $r1} {
1899 if {![highlighted $row]} {
1902 set vhighlights($row) 1
1909 proc askvhighlight {row id} {
1910 global hlview vhighlights commitrow iddrawn mainfont
1912 if {[info exists commitrow($hlview,$id)]} {
1913 if {[info exists iddrawn($id)] && ![ishighlighted $row]} {
1914 bolden $row [concat $mainfont bold]
1916 set vhighlights($row) 1
1918 set vhighlights($row) 0
1922 proc hfiles_change {name ix op} {
1923 global highlight_files filehighlight fhighlights fh_serial
1924 global mainfont highlight_paths
1926 if {[info exists filehighlight]} {
1927 # delete previous highlights
1928 catch {close $filehighlight}
1930 catch {unset fhighlights}
1932 unhighlight_filelist
1934 set highlight_paths {}
1935 after cancel do_file_hl $fh_serial
1937 if {$highlight_files ne {}} {
1938 after 300 do_file_hl $fh_serial
1942 proc makepatterns {l} {
1945 set ee [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} $e]
1946 if {[string index $ee end] eq "/"} {
1956 proc do_file_hl {serial} {
1957 global highlight_files filehighlight highlight_paths gdttype fhl_list
1959 if {$gdttype eq "touching paths:"} {
1960 if {[catch {set paths [shellsplit $highlight_files]}]} return
1961 set highlight_paths [makepatterns $paths]
1963 set gdtargs [concat -- $paths]
1965 set gdtargs [list "-S$highlight_files"]
1967 set cmd [concat | git diff-tree -r -s --stdin $gdtargs]
1968 set filehighlight [open $cmd r+]
1969 fconfigure $filehighlight -blocking 0
1970 fileevent $filehighlight readable readfhighlight
1976 proc flushhighlights {} {
1977 global filehighlight fhl_list
1979 if {[info exists filehighlight]} {
1981 puts $filehighlight ""
1982 flush $filehighlight
1986 proc askfilehighlight {row id} {
1987 global filehighlight fhighlights fhl_list
1989 lappend fhl_list $id
1990 set fhighlights($row) -1
1991 puts $filehighlight $id
1994 proc readfhighlight {} {
1995 global filehighlight fhighlights commitrow curview mainfont iddrawn
1998 while {[gets $filehighlight line] >= 0} {
1999 set line [string trim $line]
2000 set i [lsearch -exact $fhl_list $line]
2001 if {$i < 0} continue
2002 for {set j 0} {$j < $i} {incr j} {
2003 set id [lindex $fhl_list $j]
2004 if {[info exists commitrow($curview,$id)]} {
2005 set fhighlights($commitrow($curview,$id)) 0
2008 set fhl_list [lrange $fhl_list [expr {$i+1}] end]
2009 if {$line eq {}} continue
2010 if {![info exists commitrow($curview,$line)]} continue
2011 set row $commitrow($curview,$line)
2012 if {[info exists iddrawn($line)] && ![ishighlighted $row]} {
2013 bolden $row [concat $mainfont bold]
2015 set fhighlights($row) 1
2017 if {[eof $filehighlight]} {
2019 puts "oops, git diff-tree died"
2020 catch {close $filehighlight}
2026 proc find_change {name ix op} {
2027 global nhighlights mainfont boldnamerows
2028 global findstring findpattern findtype
2030 # delete previous highlights, if any
2031 foreach row $boldnamerows {
2032 bolden_name $row $mainfont
2035 catch {unset nhighlights}
2037 if {$findtype ne "Regexp"} {
2038 set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
2040 set findpattern "*$e*"
2045 proc askfindhighlight {row id} {
2046 global nhighlights commitinfo iddrawn mainfont
2047 global findstring findtype findloc findpattern
2049 if {![info exists commitinfo($id)]} {
2052 set info $commitinfo($id)
2054 set fldtypes {Headline Author Date Committer CDate Comments}
2055 foreach f $info ty $fldtypes {
2056 if {$findloc ne "All fields" && $findloc ne $ty} {
2059 if {$findtype eq "Regexp"} {
2060 set doesmatch [regexp $findstring $f]
2061 } elseif {$findtype eq "IgnCase"} {
2062 set doesmatch [string match -nocase $findpattern $f]
2064 set doesmatch [string match $findpattern $f]
2067 if {$ty eq "Author"} {
2074 if {[info exists iddrawn($id)]} {
2075 if {$isbold && ![ishighlighted $row]} {
2076 bolden $row [concat $mainfont bold]
2079 bolden_name $row [concat $mainfont bold]
2082 set nhighlights($row) $isbold
2085 proc vrel_change {name ix op} {
2086 global highlight_related
2089 if {$highlight_related ne "None"} {
2090 after idle drawvisible
2094 # prepare for testing whether commits are descendents or ancestors of a
2095 proc rhighlight_sel {a} {
2096 global descendent desc_todo ancestor anc_todo
2097 global highlight_related rhighlights
2099 catch {unset descendent}
2100 set desc_todo [list $a]
2101 catch {unset ancestor}
2102 set anc_todo [list $a]
2103 if {$highlight_related ne "None"} {
2105 after idle drawvisible
2109 proc rhighlight_none {} {
2112 catch {unset rhighlights}
2116 proc is_descendent {a} {
2117 global curview children commitrow descendent desc_todo
2120 set la $commitrow($v,$a)
2124 for {set i 0} {$i < [llength $todo]} {incr i} {
2125 set do [lindex $todo $i]
2126 if {$commitrow($v,$do) < $la} {
2127 lappend leftover $do
2130 foreach nk $children($v,$do) {
2131 if {![info exists descendent($nk)]} {
2132 set descendent($nk) 1
2140 set desc_todo [concat $leftover [lrange $todo [expr {$i+1}] end]]
2144 set descendent($a) 0
2145 set desc_todo $leftover
2148 proc is_ancestor {a} {
2149 global curview parentlist commitrow ancestor anc_todo
2152 set la $commitrow($v,$a)
2156 for {set i 0} {$i < [llength $todo]} {incr i} {
2157 set do [lindex $todo $i]
2158 if {![info exists commitrow($v,$do)] || $commitrow($v,$do) > $la} {
2159 lappend leftover $do
2162 foreach np [lindex $parentlist $commitrow($v,$do)] {
2163 if {![info exists ancestor($np)]} {
2172 set anc_todo [concat $leftover [lrange $todo [expr {$i+1}] end]]
2177 set anc_todo $leftover
2180 proc askrelhighlight {row id} {
2181 global descendent highlight_related iddrawn mainfont rhighlights
2182 global selectedline ancestor
2184 if {![info exists selectedline]} return
2186 if {$highlight_related eq "Descendent" ||
2187 $highlight_related eq "Not descendent"} {
2188 if {![info exists descendent($id)]} {
2191 if {$descendent($id) == ($highlight_related eq "Descendent")} {
2194 } elseif {$highlight_related eq "Ancestor" ||
2195 $highlight_related eq "Not ancestor"} {
2196 if {![info exists ancestor($id)]} {
2199 if {$ancestor($id) == ($highlight_related eq "Ancestor")} {
2203 if {[info exists iddrawn($id)]} {
2204 if {$isbold && ![ishighlighted $row]} {
2205 bolden $row [concat $mainfont bold]
2208 set rhighlights($row) $isbold
2211 proc next_hlcont {} {
2212 global fhl_row fhl_dirn displayorder numcommits
2213 global vhighlights fhighlights nhighlights rhighlights
2214 global hlview filehighlight findstring highlight_related
2216 if {![info exists fhl_dirn] || $fhl_dirn == 0} return
2219 if {$row < 0 || $row >= $numcommits} {
2224 set id [lindex $displayorder $row]
2225 if {[info exists hlview]} {
2226 if {![info exists vhighlights($row)]} {
2227 askvhighlight $row $id
2229 if {$vhighlights($row) > 0} break
2231 if {$findstring ne {}} {
2232 if {![info exists nhighlights($row)]} {
2233 askfindhighlight $row $id
2235 if {$nhighlights($row) > 0} break
2237 if {$highlight_related ne "None"} {
2238 if {![info exists rhighlights($row)]} {
2239 askrelhighlight $row $id
2241 if {$rhighlights($row) > 0} break
2243 if {[info exists filehighlight]} {
2244 if {![info exists fhighlights($row)]} {
2245 # ask for a few more while we're at it...
2247 for {set n 0} {$n < 100} {incr n} {
2248 if {![info exists fhighlights($r)]} {
2249 askfilehighlight $r [lindex $displayorder $r]
2252 if {$r < 0 || $r >= $numcommits} break
2256 if {$fhighlights($row) < 0} {
2260 if {$fhighlights($row) > 0} break
2268 proc next_highlight {dirn} {
2269 global selectedline fhl_row fhl_dirn
2270 global hlview filehighlight findstring highlight_related
2272 if {![info exists selectedline]} return
2273 if {!([info exists hlview] || $findstring ne {} ||
2274 $highlight_related ne "None" || [info exists filehighlight])} return
2275 set fhl_row [expr {$selectedline + $dirn}]
2280 proc cancel_next_highlight {} {
2286 # Graph layout functions
2288 proc shortids {ids} {
2291 if {[llength $id] > 1} {
2292 lappend res [shortids $id]
2293 } elseif {[regexp {^[0-9a-f]{40}$} $id]} {
2294 lappend res [string range $id 0 7]
2302 proc incrange {l x o} {
2305 set e [lindex $l $x]
2307 lset l $x [expr {$e + $o}]
2316 for {} {$n > 0} {incr n -1} {
2322 proc usedinrange {id l1 l2} {
2323 global children commitrow childlist curview
2325 if {[info exists commitrow($curview,$id)]} {
2326 set r $commitrow($curview,$id)
2327 if {$l1 <= $r && $r <= $l2} {
2328 return [expr {$r - $l1 + 1}]
2330 set kids [lindex $childlist $r]
2332 set kids $children($curview,$id)
2335 set r $commitrow($curview,$c)
2336 if {$l1 <= $r && $r <= $l2} {
2337 return [expr {$r - $l1 + 1}]
2343 proc sanity {row {full 0}} {
2344 global rowidlist rowoffsets
2347 set ids [lindex $rowidlist $row]
2350 if {$id eq {}} continue
2351 if {$col < [llength $ids] - 1 &&
2352 [lsearch -exact -start [expr {$col+1}] $ids $id] >= 0} {
2353 puts "oops: [shortids $id] repeated in row $row col $col: {[shortids [lindex $rowidlist $row]]}"
2355 set o [lindex $rowoffsets $row $col]
2361 if {[lindex $rowidlist $y $x] != $id} {
2362 puts "oops: rowoffsets wrong at row [expr {$y+1}] col [expr {$x-$o}]"
2363 puts " id=[shortids $id] check started at row $row"
2364 for {set i $row} {$i >= $y} {incr i -1} {
2365 puts " row $i ids={[shortids [lindex $rowidlist $i]]} offs={[lindex $rowoffsets $i]}"
2370 set o [lindex $rowoffsets $y $x]
2375 proc makeuparrow {oid x y z} {
2376 global rowidlist rowoffsets uparrowlen idrowranges
2378 for {set i 1} {$i < $uparrowlen && $y > 1} {incr i} {
2381 set off0 [lindex $rowoffsets $y]
2382 for {set x0 $x} {1} {incr x0} {
2383 if {$x0 >= [llength $off0]} {
2384 set x0 [llength [lindex $rowoffsets [expr {$y-1}]]]
2387 set z [lindex $off0 $x0]
2393 set z [expr {$x0 - $x}]
2394 lset rowidlist $y [linsert [lindex $rowidlist $y] $x $oid]
2395 lset rowoffsets $y [linsert [lindex $rowoffsets $y] $x $z]
2397 set tmp [lreplace [lindex $rowoffsets $y] $x $x {}]
2398 lset rowoffsets $y [incrange $tmp [expr {$x+1}] -1]
2399 lappend idrowranges($oid) $y
2402 proc initlayout {} {
2403 global rowidlist rowoffsets displayorder commitlisted
2404 global rowlaidout rowoptim
2405 global idinlist rowchk rowrangelist idrowranges
2406 global numcommits canvxmax canv
2408 global parentlist childlist children
2409 global colormap rowtextx
2421 catch {unset idinlist}
2422 catch {unset rowchk}
2425 set canvxmax [$canv cget -width]
2426 catch {unset colormap}
2427 catch {unset rowtextx}
2428 catch {unset idrowranges}
2432 proc setcanvscroll {} {
2433 global canv canv2 canv3 numcommits linespc canvxmax canvy0
2435 set ymax [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]
2436 $canv conf -scrollregion [list 0 0 $canvxmax $ymax]
2437 $canv2 conf -scrollregion [list 0 0 0 $ymax]
2438 $canv3 conf -scrollregion [list 0 0 0 $ymax]
2441 proc visiblerows {} {
2442 global canv numcommits linespc
2444 set ymax [lindex [$canv cget -scrollregion] 3]
2445 if {$ymax eq {} || $ymax == 0} return
2447 set y0 [expr {int([lindex $f 0] * $ymax)}]
2448 set r0 [expr {int(($y0 - 3) / $linespc) - 1}]
2452 set y1 [expr {int([lindex $f 1] * $ymax)}]
2453 set r1 [expr {int(($y1 - 3) / $linespc) + 1}]
2454 if {$r1 >= $numcommits} {
2455 set r1 [expr {$numcommits - 1}]
2457 return [list $r0 $r1]
2460 proc layoutmore {tmax} {
2461 global rowlaidout rowoptim commitidx numcommits optim_delay
2462 global uparrowlen curview
2465 if {$rowoptim - $optim_delay > $numcommits} {
2466 showstuff [expr {$rowoptim - $optim_delay}]
2467 } elseif {$rowlaidout - $uparrowlen - 1 > $rowoptim} {
2468 set nr [expr {$rowlaidout - $uparrowlen - 1 - $rowoptim}]
2472 optimize_rows $rowoptim 0 [expr {$rowoptim + $nr}]
2474 } elseif {$commitidx($curview) > $rowlaidout} {
2475 set nr [expr {$commitidx($curview) - $rowlaidout}]
2476 # may need to increase this threshold if uparrowlen or
2477 # mingaplen are increased...
2482 set rowlaidout [layoutrows $row [expr {$row + $nr}] 0]
2483 if {$rowlaidout == $row} {
2489 if {$tmax ne {} && [clock clicks -milliseconds] >= $tmax} {
2495 proc showstuff {canshow} {
2496 global numcommits commitrow pending_select selectedline
2497 global linesegends idrowranges idrangedrawn curview
2499 if {$numcommits == 0} {
2501 set phase "incrdraw"
2505 set numcommits $canshow
2507 set rows [visiblerows]
2508 set r0 [lindex $rows 0]
2509 set r1 [lindex $rows 1]
2511 for {set r $row} {$r < $canshow} {incr r} {
2512 foreach id [lindex $linesegends [expr {$r+1}]] {
2514 foreach {s e} [rowranges $id] {
2516 if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
2517 && ![info exists idrangedrawn($id,$i)]} {
2519 set idrangedrawn($id,$i) 1
2524 if {$canshow > $r1} {
2527 while {$row < $canshow} {
2531 if {[info exists pending_select] &&
2532 [info exists commitrow($curview,$pending_select)] &&
2533 $commitrow($curview,$pending_select) < $numcommits} {
2534 selectline $commitrow($curview,$pending_select) 1
2536 if {![info exists selectedline] && ![info exists pending_select]} {
2541 proc layoutrows {row endrow last} {
2542 global rowidlist rowoffsets displayorder
2543 global uparrowlen downarrowlen maxwidth mingaplen
2544 global childlist parentlist
2545 global idrowranges linesegends
2546 global commitidx curview
2547 global idinlist rowchk rowrangelist
2549 set idlist [lindex $rowidlist $row]
2550 set offs [lindex $rowoffsets $row]
2551 while {$row < $endrow} {
2552 set id [lindex $displayorder $row]
2555 foreach p [lindex $parentlist $row] {
2556 if {![info exists idinlist($p)]} {
2558 } elseif {!$idinlist($p)} {
2563 set nev [expr {[llength $idlist] + [llength $newolds]
2564 + [llength $oldolds] - $maxwidth + 1}]
2567 $row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
2568 for {set x [llength $idlist]} {[incr x -1] >= 0} {} {
2569 set i [lindex $idlist $x]
2570 if {![info exists rowchk($i)] || $row >= $rowchk($i)} {
2571 set r [usedinrange $i [expr {$row - $downarrowlen}] \
2572 [expr {$row + $uparrowlen + $mingaplen}]]
2574 set idlist [lreplace $idlist $x $x]
2575 set offs [lreplace $offs $x $x]
2576 set offs [incrange $offs $x 1]
2578 set rm1 [expr {$row - 1}]
2580 lappend idrowranges($i) $rm1
2581 if {[incr nev -1] <= 0} break
2584 set rowchk($id) [expr {$row + $r}]
2587 lset rowidlist $row $idlist
2588 lset rowoffsets $row $offs
2590 lappend linesegends $lse
2591 set col [lsearch -exact $idlist $id]
2593 set col [llength $idlist]
2595 lset rowidlist $row $idlist
2597 if {[lindex $childlist $row] ne {}} {
2598 set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
2602 lset rowoffsets $row $offs
2604 makeuparrow $id $col $row $z
2610 if {[info exists idrowranges($id)]} {
2611 set ranges $idrowranges($id)
2613 unset idrowranges($id)
2615 lappend rowrangelist $ranges
2617 set offs [ntimes [llength $idlist] 0]
2618 set l [llength $newolds]
2619 set idlist [eval lreplace \$idlist $col $col $newolds]
2622 set offs [lrange $offs 0 [expr {$col - 1}]]
2623 foreach x $newolds {
2628 set tmp [expr {[llength $idlist] - [llength $offs]}]
2630 set offs [concat $offs [ntimes $tmp $o]]
2635 foreach i $newolds {
2637 set idrowranges($i) $row
2640 foreach oid $oldolds {
2641 set idinlist($oid) 1
2642 set idlist [linsert $idlist $col $oid]
2643 set offs [linsert $offs $col $o]
2644 makeuparrow $oid $col $row $o
2647 lappend rowidlist $idlist
2648 lappend rowoffsets $offs
2653 proc addextraid {id row} {
2654 global displayorder commitrow commitinfo
2655 global commitidx commitlisted
2656 global parentlist childlist children curview
2658 incr commitidx($curview)
2659 lappend displayorder $id
2660 lappend commitlisted 0
2661 lappend parentlist {}
2662 set commitrow($curview,$id) $row
2664 if {![info exists commitinfo($id)]} {
2665 set commitinfo($id) {"No commit information available"}
2667 if {![info exists children($curview,$id)]} {
2668 set children($curview,$id) {}
2670 lappend childlist $children($curview,$id)
2673 proc layouttail {} {
2674 global rowidlist rowoffsets idinlist commitidx curview
2675 global idrowranges rowrangelist
2677 set row $commitidx($curview)
2678 set idlist [lindex $rowidlist $row]
2679 while {$idlist ne {}} {
2680 set col [expr {[llength $idlist] - 1}]
2681 set id [lindex $idlist $col]
2684 lappend idrowranges($id) $row
2685 lappend rowrangelist $idrowranges($id)
2686 unset idrowranges($id)
2688 set offs [ntimes $col 0]
2689 set idlist [lreplace $idlist $col $col]
2690 lappend rowidlist $idlist
2691 lappend rowoffsets $offs
2694 foreach id [array names idinlist] {
2696 lset rowidlist $row [list $id]
2697 lset rowoffsets $row 0
2698 makeuparrow $id 0 $row 0
2699 lappend idrowranges($id) $row
2700 lappend rowrangelist $idrowranges($id)
2701 unset idrowranges($id)
2703 lappend rowidlist {}
2704 lappend rowoffsets {}
2708 proc insert_pad {row col npad} {
2709 global rowidlist rowoffsets
2711 set pad [ntimes $npad {}]
2712 lset rowidlist $row [eval linsert [list [lindex $rowidlist $row]] $col $pad]
2713 set tmp [eval linsert [list [lindex $rowoffsets $row]] $col $pad]
2714 lset rowoffsets $row [incrange $tmp [expr {$col + $npad}] [expr {-$npad}]]
2717 proc optimize_rows {row col endrow} {
2718 global rowidlist rowoffsets idrowranges displayorder
2720 for {} {$row < $endrow} {incr row} {
2721 set idlist [lindex $rowidlist $row]
2722 set offs [lindex $rowoffsets $row]
2724 for {} {$col < [llength $offs]} {incr col} {
2725 if {[lindex $idlist $col] eq {}} {
2729 set z [lindex $offs $col]
2730 if {$z eq {}} continue
2732 set x0 [expr {$col + $z}]
2733 set y0 [expr {$row - 1}]
2734 set z0 [lindex $rowoffsets $y0 $x0]
2736 set id [lindex $idlist $col]
2737 set ranges [rowranges $id]
2738 if {$ranges ne {} && $y0 > [lindex $ranges 0]} {
2742 if {$z < -1 || ($z < 0 && $isarrow)} {
2743 set npad [expr {-1 - $z + $isarrow}]
2744 set offs [incrange $offs $col $npad]
2745 insert_pad $y0 $x0 $npad
2747 optimize_rows $y0 $x0 $row
2749 set z [lindex $offs $col]
2750 set x0 [expr {$col + $z}]
2751 set z0 [lindex $rowoffsets $y0 $x0]
2752 } elseif {$z > 1 || ($z > 0 && $isarrow)} {
2753 set npad [expr {$z - 1 + $isarrow}]
2754 set y1 [expr {$row + 1}]
2755 set offs2 [lindex $rowoffsets $y1]
2759 if {$z eq {} || $x1 + $z < $col} continue
2760 if {$x1 + $z > $col} {
2763 lset rowoffsets $y1 [incrange $offs2 $x1 $npad]
2766 set pad [ntimes $npad {}]
2767 set idlist [eval linsert \$idlist $col $pad]
2768 set tmp [eval linsert \$offs $col $pad]
2770 set offs [incrange $tmp $col [expr {-$npad}]]
2771 set z [lindex $offs $col]
2774 if {$z0 eq {} && !$isarrow} {
2775 # this line links to its first child on row $row-2
2776 set rm2 [expr {$row - 2}]
2777 set id [lindex $displayorder $rm2]
2778 set xc [lsearch -exact [lindex $rowidlist $rm2] $id]
2780 set z0 [expr {$xc - $x0}]
2783 if {$z0 ne {} && $z < 0 && $z0 > 0} {
2784 insert_pad $y0 $x0 1
2785 set offs [incrange $offs $col 1]
2786 optimize_rows $y0 [expr {$x0 + 1}] $row
2791 for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
2792 set o [lindex $offs $col]
2794 # check if this is the link to the first child
2795 set id [lindex $idlist $col]
2796 set ranges [rowranges $id]
2797 if {$ranges ne {} && $row == [lindex $ranges 0]} {
2798 # it is, work out offset to child
2799 set y0 [expr {$row - 1}]
2800 set id [lindex $displayorder $y0]
2801 set x0 [lsearch -exact [lindex $rowidlist $y0] $id]
2803 set o [expr {$x0 - $col}]
2807 if {$o eq {} || $o <= 0} break
2809 if {$o ne {} && [incr col] < [llength $idlist]} {
2810 set y1 [expr {$row + 1}]
2811 set offs2 [lindex $rowoffsets $y1]
2815 if {$z eq {} || $x1 + $z < $col} continue
2816 lset rowoffsets $y1 [incrange $offs2 $x1 1]
2819 set idlist [linsert $idlist $col {}]
2820 set tmp [linsert $offs $col {}]
2822 set offs [incrange $tmp $col -1]
2825 lset rowidlist $row $idlist
2826 lset rowoffsets $row $offs
2832 global canvx0 linespc
2833 return [expr {$canvx0 + $col * $linespc}]
2837 global canvy0 linespc
2838 return [expr {$canvy0 + $row * $linespc}]
2841 proc linewidth {id} {
2842 global thickerline lthickness
2845 if {[info exists thickerline] && $id eq $thickerline} {
2846 set wid [expr {2 * $lthickness}]
2851 proc rowranges {id} {
2852 global phase idrowranges commitrow rowlaidout rowrangelist curview
2856 ([info exists commitrow($curview,$id)]
2857 && $commitrow($curview,$id) < $rowlaidout)} {
2858 set ranges [lindex $rowrangelist $commitrow($curview,$id)]
2859 } elseif {[info exists idrowranges($id)]} {
2860 set ranges $idrowranges($id)
2865 proc drawlineseg {id i} {
2866 global rowoffsets rowidlist
2868 global canv colormap linespc
2869 global numcommits commitrow curview
2871 set ranges [rowranges $id]
2873 if {[info exists commitrow($curview,$id)]
2874 && $commitrow($curview,$id) < $numcommits} {
2875 set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
2879 set startrow [lindex $ranges [expr {2 * $i}]]
2880 set row [lindex $ranges [expr {2 * $i + 1}]]
2881 if {$startrow == $row} return
2884 set col [lsearch -exact [lindex $rowidlist $row] $id]
2886 puts "oops: drawline: id $id not on row $row"
2892 set o [lindex $rowoffsets $row $col]
2895 # changing direction
2896 set x [xc $row $col]
2898 lappend coords $x $y
2904 set x [xc $row $col]
2906 lappend coords $x $y
2908 # draw the link to the first child as part of this line
2910 set child [lindex $displayorder $row]
2911 set ccol [lsearch -exact [lindex $rowidlist $row] $child]
2913 set x [xc $row $ccol]
2915 if {$ccol < $col - 1} {
2916 lappend coords [xc $row [expr {$col - 1}]] [yc $row]
2917 } elseif {$ccol > $col + 1} {
2918 lappend coords [xc $row [expr {$col + 1}]] [yc $row]
2920 lappend coords $x $y
2923 if {[llength $coords] < 4} return
2925 # This line has an arrow at the lower end: check if the arrow is
2926 # on a diagonal segment, and if so, work around the Tk 8.4
2927 # refusal to draw arrows on diagonal lines.
2928 set x0 [lindex $coords 0]
2929 set x1 [lindex $coords 2]
2931 set y0 [lindex $coords 1]
2932 set y1 [lindex $coords 3]
2933 if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
2934 # we have a nearby vertical segment, just trim off the diag bit
2935 set coords [lrange $coords 2 end]
2937 set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
2938 set xi [expr {$x0 - $slope * $linespc / 2}]
2939 set yi [expr {$y0 - $linespc / 2}]
2940 set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
2944 set arrow [expr {2 * ($i > 0) + $downarrow}]
2945 set arrow [lindex {none first last both} $arrow]
2946 set t [$canv create line $coords -width [linewidth $id] \
2947 -fill $colormap($id) -tags lines.$id -arrow $arrow]
2952 proc drawparentlinks {id row col olds} {
2953 global rowidlist canv colormap
2955 set row2 [expr {$row + 1}]
2956 set x [xc $row $col]
2959 set ids [lindex $rowidlist $row2]
2960 # rmx = right-most X coord used
2963 set i [lsearch -exact $ids $p]
2965 puts "oops, parent $p of $id not in list"
2968 set x2 [xc $row2 $i]
2972 set ranges [rowranges $p]
2973 if {$ranges ne {} && $row2 == [lindex $ranges 0]
2974 && $row2 < [lindex $ranges 1]} {
2975 # drawlineseg will do this one for us
2979 # should handle duplicated parents here...
2980 set coords [list $x $y]
2981 if {$i < $col - 1} {
2982 lappend coords [xc $row [expr {$i + 1}]] $y
2983 } elseif {$i > $col + 1} {
2984 lappend coords [xc $row [expr {$i - 1}]] $y
2986 lappend coords $x2 $y2
2987 set t [$canv create line $coords -width [linewidth $p] \
2988 -fill $colormap($p) -tags lines.$p]
2995 proc drawlines {id} {
2996 global colormap canv
2998 global children iddrawn commitrow rowidlist curview
3000 $canv delete lines.$id
3001 set nr [expr {[llength [rowranges $id]] / 2}]
3002 for {set i 0} {$i < $nr} {incr i} {
3003 if {[info exists idrangedrawn($id,$i)]} {
3007 foreach child $children($curview,$id) {
3008 if {[info exists iddrawn($child)]} {
3009 set row $commitrow($curview,$child)
3010 set col [lsearch -exact [lindex $rowidlist $row] $child]
3012 drawparentlinks $child $row $col [list $id]
3018 proc drawcmittext {id row col rmx} {
3019 global linespc canv canv2 canv3 canvy0 fgcolor
3020 global commitlisted commitinfo rowidlist
3021 global rowtextx idpos idtags idheads idotherrefs
3022 global linehtag linentag linedtag
3023 global mainfont canvxmax boldrows boldnamerows fgcolor
3025 set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
3026 set x [xc $row $col]
3028 set orad [expr {$linespc / 3}]
3029 set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
3030 [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
3031 -fill $ofill -outline $fgcolor -width 1 -tags circle]
3033 $canv bind $t <1> {selcanvline {} %x %y}
3034 set xt [xc $row [llength [lindex $rowidlist $row]]]
3038 set rowtextx($row) $xt
3039 set idpos($id) [list $x $xt $y]
3040 if {[info exists idtags($id)] || [info exists idheads($id)]
3041 || [info exists idotherrefs($id)]} {
3042 set xt [drawtags $id $x $xt $y]
3044 set headline [lindex $commitinfo($id) 0]
3045 set name [lindex $commitinfo($id) 1]
3046 set date [lindex $commitinfo($id) 2]
3047 set date [formatdate $date]
3050 set isbold [ishighlighted $row]
3052 lappend boldrows $row
3055 lappend boldnamerows $row
3059 set linehtag($row) [$canv create text $xt $y -anchor w -fill $fgcolor \
3060 -text $headline -font $font -tags text]
3061 $canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id"
3062 set linentag($row) [$canv2 create text 3 $y -anchor w -fill $fgcolor \
3063 -text $name -font $nfont -tags text]
3064 set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \
3065 -text $date -font $mainfont -tags text]
3066 set xr [expr {$xt + [font measure $mainfont $headline]}]
3067 if {$xr > $canvxmax} {
3073 proc drawcmitrow {row} {
3074 global displayorder rowidlist
3075 global idrangedrawn iddrawn
3076 global commitinfo parentlist numcommits
3077 global filehighlight fhighlights findstring nhighlights
3078 global hlview vhighlights
3079 global highlight_related rhighlights
3081 if {$row >= $numcommits} return
3082 foreach id [lindex $rowidlist $row] {
3083 if {$id eq {}} continue
3085 foreach {s e} [rowranges $id] {
3087 if {$row < $s} continue
3090 if {$e < $numcommits && ![info exists idrangedrawn($id,$i)]} {
3092 set idrangedrawn($id,$i) 1
3099 set id [lindex $displayorder $row]
3100 if {[info exists hlview] && ![info exists vhighlights($row)]} {
3101 askvhighlight $row $id
3103 if {[info exists filehighlight] && ![info exists fhighlights($row)]} {
3104 askfilehighlight $row $id
3106 if {$findstring ne {} && ![info exists nhighlights($row)]} {
3107 askfindhighlight $row $id
3109 if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
3110 askrelhighlight $row $id
3112 if {[info exists iddrawn($id)]} return
3113 set col [lsearch -exact [lindex $rowidlist $row] $id]
3115 puts "oops, row $row id $id not in list"
3118 if {![info exists commitinfo($id)]} {
3122 set olds [lindex $parentlist $row]
3124 set rmx [drawparentlinks $id $row $col $olds]
3128 drawcmittext $id $row $col $rmx
3132 proc drawfrac {f0 f1} {
3133 global numcommits canv
3136 set ymax [lindex [$canv cget -scrollregion] 3]
3137 if {$ymax eq {} || $ymax == 0} return
3138 set y0 [expr {int($f0 * $ymax)}]
3139 set row [expr {int(($y0 - 3) / $linespc) - 1}]
3143 set y1 [expr {int($f1 * $ymax)}]
3144 set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
3145 if {$endrow >= $numcommits} {
3146 set endrow [expr {$numcommits - 1}]
3148 for {} {$row <= $endrow} {incr row} {
3153 proc drawvisible {} {
3155 eval drawfrac [$canv yview]
3158 proc clear_display {} {
3159 global iddrawn idrangedrawn
3160 global vhighlights fhighlights nhighlights rhighlights
3163 catch {unset iddrawn}
3164 catch {unset idrangedrawn}
3165 catch {unset vhighlights}
3166 catch {unset fhighlights}
3167 catch {unset nhighlights}
3168 catch {unset rhighlights}
3171 proc findcrossings {id} {
3172 global rowidlist parentlist numcommits rowoffsets displayorder
3176 foreach {s e} [rowranges $id] {
3177 if {$e >= $numcommits} {
3178 set e [expr {$numcommits - 1}]
3180 if {$e <= $s} continue
3181 set x [lsearch -exact [lindex $rowidlist $e] $id]
3183 puts "findcrossings: oops, no [shortids $id] in row $e"
3186 for {set row $e} {[incr row -1] >= $s} {} {
3187 set olds [lindex $parentlist $row]
3188 set kid [lindex $displayorder $row]
3189 set kidx [lsearch -exact [lindex $rowidlist $row] $kid]
3190 if {$kidx < 0} continue
3191 set nextrow [lindex $rowidlist [expr {$row + 1}]]
3193 set px [lsearch -exact $nextrow $p]
3194 if {$px < 0} continue
3195 if {($kidx < $x && $x < $px) || ($px < $x && $x < $kidx)} {
3196 if {[lsearch -exact $ccross $p] >= 0} continue
3197 if {$x == $px + ($kidx < $px? -1: 1)} {
3199 } elseif {[lsearch -exact $cross $p] < 0} {
3204 set inc [lindex $rowoffsets $row $x]
3205 if {$inc eq {}} break
3209 return [concat $ccross {{}} $cross]
3212 proc assigncolor {id} {
3213 global colormap colors nextcolor
3214 global commitrow parentlist children children curview
3216 if {[info exists colormap($id)]} return
3217 set ncolors [llength $colors]
3218 if {[info exists children($curview,$id)]} {
3219 set kids $children($curview,$id)
3223 if {[llength $kids] == 1} {
3224 set child [lindex $kids 0]
3225 if {[info exists colormap($child)]
3226 && [llength [lindex $parentlist $commitrow($curview,$child)]] == 1} {
3227 set colormap($id) $colormap($child)
3233 foreach x [findcrossings $id] {
3235 # delimiter between corner crossings and other crossings
3236 if {[llength $badcolors] >= $ncolors - 1} break
3237 set origbad $badcolors
3239 if {[info exists colormap($x)]
3240 && [lsearch -exact $badcolors $colormap($x)] < 0} {
3241 lappend badcolors $colormap($x)
3244 if {[llength $badcolors] >= $ncolors} {
3245 set badcolors $origbad
3247 set origbad $badcolors
3248 if {[llength $badcolors] < $ncolors - 1} {
3249 foreach child $kids {
3250 if {[info exists colormap($child)]
3251 && [lsearch -exact $badcolors $colormap($child)] < 0} {
3252 lappend badcolors $colormap($child)
3254 foreach p [lindex $parentlist $commitrow($curview,$child)] {
3255 if {[info exists colormap($p)]
3256 && [lsearch -exact $badcolors $colormap($p)] < 0} {
3257 lappend badcolors $colormap($p)
3261 if {[llength $badcolors] >= $ncolors} {
3262 set badcolors $origbad
3265 for {set i 0} {$i <= $ncolors} {incr i} {
3266 set c [lindex $colors $nextcolor]
3267 if {[incr nextcolor] >= $ncolors} {
3270 if {[lsearch -exact $badcolors $c]} break
3272 set colormap($id) $c
3275 proc bindline {t id} {
3278 $canv bind $t <Enter> "lineenter %x %y $id"
3279 $canv bind $t <Motion> "linemotion %x %y $id"
3280 $canv bind $t <Leave> "lineleave $id"
3281 $canv bind $t <Button-1> "lineclick %x %y $id 1"
3284 proc drawtags {id x xt y1} {
3285 global idtags idheads idotherrefs mainhead
3286 global linespc lthickness
3287 global canv mainfont commitrow rowtextx curview fgcolor bgcolor
3292 if {[info exists idtags($id)]} {
3293 set marks $idtags($id)
3294 set ntags [llength $marks]
3296 if {[info exists idheads($id)]} {
3297 set marks [concat $marks $idheads($id)]
3298 set nheads [llength $idheads($id)]
3300 if {[info exists idotherrefs($id)]} {
3301 set marks [concat $marks $idotherrefs($id)]
3307 set delta [expr {int(0.5 * ($linespc - $lthickness))}]
3308 set yt [expr {$y1 - 0.5 * $linespc}]
3309 set yb [expr {$yt + $linespc - 1}]
3313 foreach tag $marks {
3315 if {$i >= $ntags && $i < $ntags + $nheads && $tag eq $mainhead} {
3316 set wid [font measure [concat $mainfont bold] $tag]
3318 set wid [font measure $mainfont $tag]
3322 set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}]
3324 set t [$canv create line $x $y1 [lindex $xvals end] $y1 \
3325 -width $lthickness -fill black -tags tag.$id]
3327 foreach tag $marks x $xvals wid $wvals {
3328 set xl [expr {$x + $delta}]
3329 set xr [expr {$x + $delta + $wid + $lthickness}]
3331 if {[incr ntags -1] >= 0} {
3333 set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
3334 $xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
3335 -width 1 -outline black -fill yellow -tags tag.$id]
3336 $canv bind $t <1> [list showtag $tag 1]
3337 set rowtextx($commitrow($curview,$id)) [expr {$xr + $linespc}]
3339 # draw a head or other ref
3340 if {[incr nheads -1] >= 0} {
3342 if {$tag eq $mainhead} {
3348 set xl [expr {$xl - $delta/2}]
3349 $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
3350 -width 1 -outline black -fill $col -tags tag.$id
3351 if {[regexp {^(remotes/.*/|remotes/)} $tag match remoteprefix]} {
3352 set rwid [font measure $mainfont $remoteprefix]
3353 set xi [expr {$x + 1}]
3354 set yti [expr {$yt + 1}]
3355 set xri [expr {$x + $rwid}]
3356 $canv create polygon $xi $yti $xri $yti $xri $yb $xi $yb \
3357 -width 0 -fill "#ffddaa" -tags tag.$id
3360 set t [$canv create text $xl $y1 -anchor w -text $tag -fill $fgcolor \
3361 -font $font -tags [list tag.$id text]]
3363 $canv bind $t <1> [list showtag $tag 1]
3364 } elseif {$nheads >= 0} {
3365 $canv bind $t <Button-3> [list headmenu %X %Y $id $tag]
3371 proc xcoord {i level ln} {
3372 global canvx0 xspc1 xspc2
3374 set x [expr {$canvx0 + $i * $xspc1($ln)}]
3375 if {$i > 0 && $i == $level} {
3376 set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}]
3377 } elseif {$i > $level} {
3378 set x [expr {$x + $xspc2 - $xspc1($ln)}]
3383 proc show_status {msg} {
3384 global canv mainfont fgcolor
3387 $canv create text 3 3 -anchor nw -text $msg -font $mainfont \
3388 -tags text -fill $fgcolor
3391 proc finishcommits {} {
3392 global commitidx phase curview
3393 global pending_select
3395 if {$commitidx($curview) > 0} {
3398 show_status "No commits selected"
3401 catch {unset pending_select}
3404 # Insert a new commit as the child of the commit on row $row.
3405 # The new commit will be displayed on row $row and the commits
3406 # on that row and below will move down one row.
3407 proc insertrow {row newcmit} {
3408 global displayorder parentlist childlist commitlisted
3409 global commitrow curview rowidlist rowoffsets numcommits
3410 global rowrangelist idrowranges rowlaidout rowoptim numcommits
3411 global linesegends selectedline
3413 if {$row >= $numcommits} {
3414 puts "oops, inserting new row $row but only have $numcommits rows"
3417 set p [lindex $displayorder $row]
3418 set displayorder [linsert $displayorder $row $newcmit]
3419 set parentlist [linsert $parentlist $row $p]
3420 set kids [lindex $childlist $row]
3421 lappend kids $newcmit
3422 lset childlist $row $kids
3423 set childlist [linsert $childlist $row {}]
3424 set commitlisted [linsert $commitlisted $row 1]
3425 set l [llength $displayorder]
3426 for {set r $row} {$r < $l} {incr r} {
3427 set id [lindex $displayorder $r]
3428 set commitrow($curview,$id) $r
3431 set idlist [lindex $rowidlist $row]
3432 set offs [lindex $rowoffsets $row]
3435 if {$x eq {} || ($x eq $p && [llength $kids] == 1)} {
3441 if {[llength $kids] == 1} {
3442 set col [lsearch -exact $idlist $p]
3443 lset idlist $col $newcmit
3445 set col [llength $idlist]
3446 lappend idlist $newcmit
3448 lset rowoffsets $row $offs
3450 set rowidlist [linsert $rowidlist $row $idlist]
3451 set rowoffsets [linsert $rowoffsets [expr {$row+1}] $newoffs]
3453 set rowrangelist [linsert $rowrangelist $row {}]
3454 set l [llength $rowrangelist]
3455 for {set r 0} {$r < $l} {incr r} {
3456 set ranges [lindex $rowrangelist $r]
3457 if {$ranges ne {} && [lindex $ranges end] >= $row} {
3461 lappend newranges [expr {$x + 1}]
3463 lappend newranges $x
3466 lset rowrangelist $r $newranges
3469 if {[llength $kids] > 1} {
3470 set rp1 [expr {$row + 1}]
3471 set ranges [lindex $rowrangelist $rp1]
3472 if {$ranges eq {}} {
3473 set ranges [list $row $rp1]
3474 } elseif {[lindex $ranges end-1] == $rp1} {
3475 lset ranges end-1 $row
3477 lset rowrangelist $rp1 $ranges
3479 foreach id [array names idrowranges] {
3480 set ranges $idrowranges($id)
3481 if {$ranges ne {} && [lindex $ranges end] >= $row} {
3485 lappend newranges [expr {$x + 1}]
3487 lappend newranges $x
3490 set idrowranges($id) $newranges
3494 set linesegends [linsert $linesegends $row {}]
3500 if {[info exists selectedline] && $selectedline >= $row} {
3506 # Don't change the text pane cursor if it is currently the hand cursor,
3507 # showing that we are over a sha1 ID link.
3508 proc settextcursor {c} {
3509 global ctext curtextcursor
3511 if {[$ctext cget -cursor] == $curtextcursor} {
3512 $ctext config -cursor $c
3514 set curtextcursor $c
3517 proc nowbusy {what} {
3520 if {[array names isbusy] eq {}} {
3521 . config -cursor watch
3527 proc notbusy {what} {
3528 global isbusy maincursor textcursor
3530 catch {unset isbusy($what)}
3531 if {[array names isbusy] eq {}} {
3532 . config -cursor $maincursor
3533 settextcursor $textcursor
3539 global rowlaidout commitidx curview
3540 global pending_select
3543 layoutrows $rowlaidout $commitidx($curview) 1
3545 optimize_rows $row 0 $commitidx($curview)
3546 showstuff $commitidx($curview)
3547 if {[info exists pending_select]} {
3551 set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
3553 #puts "overall $drawmsecs ms for $numcommits commits"
3556 proc findmatches {f} {
3557 global findtype foundstring foundstrlen
3558 if {$findtype == "Regexp"} {
3559 set matches [regexp -indices -all -inline $foundstring $f]
3561 if {$findtype == "IgnCase"} {
3562 set str [string tolower $f]
3568 while {[set j [string first $foundstring $str $i]] >= 0} {
3569 lappend matches [list $j [expr {$j+$foundstrlen-1}]]
3570 set i [expr {$j + $foundstrlen}]
3577 global findtype findloc findstring markedmatches commitinfo
3578 global numcommits displayorder linehtag linentag linedtag
3579 global mainfont canv canv2 canv3 selectedline
3580 global matchinglines foundstring foundstrlen matchstring
3585 cancel_next_highlight
3587 set matchinglines {}
3588 if {$findtype == "IgnCase"} {
3589 set foundstring [string tolower $findstring]
3591 set foundstring $findstring
3593 set foundstrlen [string length $findstring]
3594 if {$foundstrlen == 0} return
3595 regsub -all {[*?\[\\]} $foundstring {\\&} matchstring
3596 set matchstring "*$matchstring*"
3597 if {![info exists selectedline]} {
3600 set oldsel $selectedline
3603 set fldtypes {Headline Author Date Committer CDate Comments}
3605 foreach id $displayorder {
3606 set d $commitdata($id)
3608 if {$findtype == "Regexp"} {
3609 set doesmatch [regexp $foundstring $d]
3610 } elseif {$findtype == "IgnCase"} {
3611 set doesmatch [string match -nocase $matchstring $d]
3613 set doesmatch [string match $matchstring $d]
3615 if {!$doesmatch} continue
3616 if {![info exists commitinfo($id)]} {
3619 set info $commitinfo($id)
3621 foreach f $info ty $fldtypes {
3622 if {$findloc != "All fields" && $findloc != $ty} {
3625 set matches [findmatches $f]
3626 if {$matches == {}} continue
3628 if {$ty == "Headline"} {
3630 markmatches $canv $l $f $linehtag($l) $matches $mainfont
3631 } elseif {$ty == "Author"} {
3633 markmatches $canv2 $l $f $linentag($l) $matches $mainfont
3634 } elseif {$ty == "Date"} {
3636 markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
3640 lappend matchinglines $l
3641 if {!$didsel && $l > $oldsel} {
3647 if {$matchinglines == {}} {
3649 } elseif {!$didsel} {
3650 findselectline [lindex $matchinglines 0]
3654 proc findselectline {l} {
3655 global findloc commentend ctext
3657 if {$findloc == "All fields" || $findloc == "Comments"} {
3658 # highlight the matches in the comments
3659 set f [$ctext get 1.0 $commentend]
3660 set matches [findmatches $f]
3661 foreach match $matches {
3662 set start [lindex $match 0]
3663 set end [expr {[lindex $match 1] + 1}]
3664 $ctext tag add found "1.0 + $start c" "1.0 + $end c"
3669 proc findnext {restart} {
3670 global matchinglines selectedline
3671 if {![info exists matchinglines]} {
3677 if {![info exists selectedline]} return
3678 foreach l $matchinglines {
3679 if {$l > $selectedline} {
3688 global matchinglines selectedline
3689 if {![info exists matchinglines]} {
3693 if {![info exists selectedline]} return
3695 foreach l $matchinglines {
3696 if {$l >= $selectedline} break
3700 findselectline $prev
3706 proc stopfindproc {{done 0}} {
3707 global findprocpid findprocfile findids
3708 global ctext findoldcursor phase maincursor textcursor
3709 global findinprogress
3711 catch {unset findids}
3712 if {[info exists findprocpid]} {
3714 catch {exec kill $findprocpid}
3716 catch {close $findprocfile}
3719 catch {unset findinprogress}
3723 # mark a commit as matching by putting a yellow background
3724 # behind the headline
3725 proc markheadline {l id} {
3726 global canv mainfont linehtag
3729 set bbox [$canv bbox $linehtag($l)]
3730 set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
3734 # mark the bits of a headline, author or date that match a find string
3735 proc markmatches {canv l str tag matches font} {
3736 set bbox [$canv bbox $tag]
3737 set x0 [lindex $bbox 0]
3738 set y0 [lindex $bbox 1]
3739 set y1 [lindex $bbox 3]
3740 foreach match $matches {
3741 set start [lindex $match 0]
3742 set end [lindex $match 1]
3743 if {$start > $end} continue
3744 set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
3745 set xlen [font measure $font [string range $str 0 [expr {$end}]]]
3746 set t [$canv create rect [expr {$x0+$xoff}] $y0 \
3747 [expr {$x0+$xlen+2}] $y1 \
3748 -outline {} -tags matches -fill yellow]
3753 proc unmarkmatches {} {
3754 global matchinglines findids
3755 allcanvs delete matches
3756 catch {unset matchinglines}
3757 catch {unset findids}
3760 proc selcanvline {w x y} {
3761 global canv canvy0 ctext linespc
3763 set ymax [lindex [$canv cget -scrollregion] 3]
3764 if {$ymax == {}} return
3765 set yfrac [lindex [$canv yview] 0]
3766 set y [expr {$y + $yfrac * $ymax}]
3767 set l [expr {int(($y - $canvy0) / $linespc + 0.5)}]
3772 if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
3778 proc commit_descriptor {p} {
3780 if {![info exists commitinfo($p)]} {
3784 if {[llength $commitinfo($p)] > 1} {
3785 set l [lindex $commitinfo($p) 0]
3790 # append some text to the ctext widget, and make any SHA1 ID
3791 # that we know about be a clickable link.
3792 proc appendwithlinks {text tags} {
3793 global ctext commitrow linknum curview
3795 set start [$ctext index "end - 1c"]
3796 $ctext insert end $text $tags
3797 set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
3801 set linkid [string range $text $s $e]
3802 if {![info exists commitrow($curview,$linkid)]} continue
3804 $ctext tag add link "$start + $s c" "$start + $e c"
3805 $ctext tag add link$linknum "$start + $s c" "$start + $e c"
3806 $ctext tag bind link$linknum <1> \
3807 [list selectline $commitrow($curview,$linkid) 1]
3810 $ctext tag conf link -foreground blue -underline 1
3811 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
3812 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
3815 proc viewnextline {dir} {
3819 set ymax [lindex [$canv cget -scrollregion] 3]
3820 set wnow [$canv yview]
3821 set wtop [expr {[lindex $wnow 0] * $ymax}]
3822 set newtop [expr {$wtop + $dir * $linespc}]
3825 } elseif {$newtop > $ymax} {
3828 allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
3831 # add a list of tag or branch names at position pos
3832 # returns the number of names inserted
3833 proc appendrefs {pos ids var} {
3834 global ctext commitrow linknum curview $var
3836 if {[catch {$ctext index $pos}]} {
3839 $ctext conf -state normal
3840 $ctext delete $pos "$pos lineend"
3843 foreach tag [set $var\($id\)] {
3844 lappend tags [list $tag $id]
3847 set tags [lsort -index 0 -decreasing $tags]
3850 set id [lindex $ti 1]
3853 $ctext tag delete $lk
3854 $ctext insert $pos $sep
3855 $ctext insert $pos [lindex $ti 0] $lk
3856 if {[info exists commitrow($curview,$id)]} {
3857 $ctext tag conf $lk -foreground blue
3858 $ctext tag bind $lk <1> \
3859 [list selectline $commitrow($curview,$id) 1]
3860 $ctext tag conf $lk -underline 1
3861 $ctext tag bind $lk <Enter> { %W configure -cursor hand2 }
3862 $ctext tag bind $lk <Leave> { %W configure -cursor $curtextcursor }
3866 $ctext conf -state disabled
3867 return [llength $tags]
3870 # called when we have finished computing the nearby tags
3871 proc dispneartags {delay} {
3872 global selectedline currentid showneartags tagphase
3874 if {![info exists selectedline] || !$showneartags} return
3875 after cancel dispnexttag
3877 after 200 dispnexttag
3880 after idle dispnexttag
3885 proc dispnexttag {} {
3886 global selectedline currentid showneartags tagphase ctext
3888 if {![info exists selectedline] || !$showneartags} return
3889 switch -- $tagphase {
3891 set dtags [desctags $currentid]
3893 appendrefs precedes $dtags idtags
3897 set atags [anctags $currentid]
3899 appendrefs follows $atags idtags
3903 set dheads [descheads $currentid]
3904 if {$dheads ne {}} {
3905 if {[appendrefs branch $dheads idheads] > 1
3906 && [$ctext get "branch -3c"] eq "h"} {
3907 # turn "Branch" into "Branches"
3908 $ctext conf -state normal
3909 $ctext insert "branch -2c" "es"
3910 $ctext conf -state disabled
3915 if {[incr tagphase] <= 2} {
3916 after idle dispnexttag
3920 proc selectline {l isnew} {
3921 global canv canv2 canv3 ctext commitinfo selectedline
3922 global displayorder linehtag linentag linedtag
3923 global canvy0 linespc parentlist childlist
3924 global currentid sha1entry
3925 global commentend idtags linknum
3926 global mergemax numcommits pending_select
3927 global cmitmode showneartags allcommits
3929 catch {unset pending_select}
3932 cancel_next_highlight
3933 if {$l < 0 || $l >= $numcommits} return
3934 set y [expr {$canvy0 + $l * $linespc}]
3935 set ymax [lindex [$canv cget -scrollregion] 3]
3936 set ytop [expr {$y - $linespc - 1}]
3937 set ybot [expr {$y + $linespc + 1}]
3938 set wnow [$canv yview]
3939 set wtop [expr {[lindex $wnow 0] * $ymax}]
3940 set wbot [expr {[lindex $wnow 1] * $ymax}]
3941 set wh [expr {$wbot - $wtop}]
3943 if {$ytop < $wtop} {
3944 if {$ybot < $wtop} {
3945 set newtop [expr {$y - $wh / 2.0}]
3948 if {$newtop > $wtop - $linespc} {
3949 set newtop [expr {$wtop - $linespc}]
3952 } elseif {$ybot > $wbot} {
3953 if {$ytop > $wbot} {
3954 set newtop [expr {$y - $wh / 2.0}]
3956 set newtop [expr {$ybot - $wh}]
3957 if {$newtop < $wtop + $linespc} {
3958 set newtop [expr {$wtop + $linespc}]
3962 if {$newtop != $wtop} {
3966 allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
3970 if {![info exists linehtag($l)]} return
3972 set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
3973 -tags secsel -fill [$canv cget -selectbackground]]
3975 $canv2 delete secsel
3976 set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \
3977 -tags secsel -fill [$canv2 cget -selectbackground]]
3979 $canv3 delete secsel
3980 set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \
3981 -tags secsel -fill [$canv3 cget -selectbackground]]
3985 addtohistory [list selectline $l 0]
3990 set id [lindex $displayorder $l]
3992 $sha1entry delete 0 end
3993 $sha1entry insert 0 $id
3994 $sha1entry selection from 0
3995 $sha1entry selection to end
3998 $ctext conf -state normal
4001 set info $commitinfo($id)
4002 set date [formatdate [lindex $info 2]]
4003 $ctext insert end "Author: [lindex $info 1] $date\n"
4004 set date [formatdate [lindex $info 4]]
4005 $ctext insert end "Committer: [lindex $info 3] $date\n"
4006 if {[info exists idtags($id)]} {
4007 $ctext insert end "Tags:"
4008 foreach tag $idtags($id) {
4009 $ctext insert end " $tag"
4011 $ctext insert end "\n"
4015 set olds [lindex $parentlist $l]
4016 if {[llength $olds] > 1} {
4019 if {$np >= $mergemax} {
4024 $ctext insert end "Parent: " $tag
4025 appendwithlinks [commit_descriptor $p] {}
4030 append headers "Parent: [commit_descriptor $p]"
4034 foreach c [lindex $childlist $l] {
4035 append headers "Child: [commit_descriptor $c]"
4038 # make anything that looks like a SHA1 ID be a clickable link
4039 appendwithlinks $headers {}
4040 if {$showneartags} {
4041 if {![info exists allcommits]} {
4044 $ctext insert end "Branch: "
4045 $ctext mark set branch "end -1c"
4046 $ctext mark gravity branch left
4047 $ctext insert end "\nFollows: "
4048 $ctext mark set follows "end -1c"
4049 $ctext mark gravity follows left
4050 $ctext insert end "\nPrecedes: "
4051 $ctext mark set precedes "end -1c"
4052 $ctext mark gravity precedes left
4053 $ctext insert end "\n"
4056 $ctext insert end "\n"
4057 appendwithlinks [lindex $info 5] {comment}
4059 $ctext tag delete Comments
4060 $ctext tag remove found 1.0 end
4061 $ctext conf -state disabled
4062 set commentend [$ctext index "end - 1c"]
4064 init_flist "Comments"
4065 if {$cmitmode eq "tree"} {
4067 } elseif {[llength $olds] <= 1} {
4074 proc selfirstline {} {
4079 proc sellastline {} {
4082 set l [expr {$numcommits - 1}]
4086 proc selnextline {dir} {
4088 if {![info exists selectedline]} return
4089 set l [expr {$selectedline + $dir}]
4094 proc selnextpage {dir} {
4095 global canv linespc selectedline numcommits
4097 set lpp [expr {([winfo height $canv] - 2) / $linespc}]
4101 allcanvs yview scroll [expr {$dir * $lpp}] units
4103 if {![info exists selectedline]} return
4104 set l [expr {$selectedline + $dir * $lpp}]
4107 } elseif {$l >= $numcommits} {
4108 set l [expr $numcommits - 1]
4114 proc unselectline {} {
4115 global selectedline currentid
4117 catch {unset selectedline}
4118 catch {unset currentid}
4119 allcanvs delete secsel
4121 cancel_next_highlight
4124 proc reselectline {} {
4127 if {[info exists selectedline]} {
4128 selectline $selectedline 0
4132 proc addtohistory {cmd} {
4133 global history historyindex curview
4135 set elt [list $curview $cmd]
4136 if {$historyindex > 0
4137 && [lindex $history [expr {$historyindex - 1}]] == $elt} {
4141 if {$historyindex < [llength $history]} {
4142 set history [lreplace $history $historyindex end $elt]
4144 lappend history $elt
4147 if {$historyindex > 1} {
4148 .tf.bar.leftbut conf -state normal
4150 .tf.bar.leftbut conf -state disabled
4152 .tf.bar.rightbut conf -state disabled
4158 set view [lindex $elt 0]
4159 set cmd [lindex $elt 1]
4160 if {$curview != $view} {
4167 global history historyindex
4169 if {$historyindex > 1} {
4170 incr historyindex -1
4171 godo [lindex $history [expr {$historyindex - 1}]]
4172 .tf.bar.rightbut conf -state normal
4174 if {$historyindex <= 1} {
4175 .tf.bar.leftbut conf -state disabled
4180 global history historyindex
4182 if {$historyindex < [llength $history]} {
4183 set cmd [lindex $history $historyindex]
4186 .tf.bar.leftbut conf -state normal
4188 if {$historyindex >= [llength $history]} {
4189 .tf.bar.rightbut conf -state disabled
4194 global treefilelist treeidlist diffids diffmergeid treepending
4197 catch {unset diffmergeid}
4198 if {![info exists treefilelist($id)]} {
4199 if {![info exists treepending]} {
4200 if {[catch {set gtf [open [concat | git ls-tree -r $id] r]}]} {
4204 set treefilelist($id) {}
4205 set treeidlist($id) {}
4206 fconfigure $gtf -blocking 0
4207 fileevent $gtf readable [list gettreeline $gtf $id]
4214 proc gettreeline {gtf id} {
4215 global treefilelist treeidlist treepending cmitmode diffids
4217 while {[gets $gtf line] >= 0} {
4218 if {[lindex $line 1] ne "blob"} continue
4219 set sha1 [lindex $line 2]
4220 set fname [lindex $line 3]
4221 lappend treefilelist($id) $fname
4222 lappend treeidlist($id) $sha1
4224 if {![eof $gtf]} return
4227 if {$cmitmode ne "tree"} {
4228 if {![info exists diffmergeid]} {
4229 gettreediffs $diffids
4231 } elseif {$id ne $diffids} {
4239 global treefilelist treeidlist diffids
4240 global ctext commentend
4242 set i [lsearch -exact $treefilelist($diffids) $f]
4244 puts "oops, $f not in list for id $diffids"
4247 set blob [lindex $treeidlist($diffids) $i]
4248 if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
4249 puts "oops, error reading blob $blob: $err"
4252 fconfigure $bf -blocking 0
4253 fileevent $bf readable [list getblobline $bf $diffids]
4254 $ctext config -state normal
4255 clear_ctext $commentend
4256 $ctext insert end "\n"
4257 $ctext insert end "$f\n" filesep
4258 $ctext config -state disabled
4259 $ctext yview $commentend
4262 proc getblobline {bf id} {
4263 global diffids cmitmode ctext
4265 if {$id ne $diffids || $cmitmode ne "tree"} {
4269 $ctext config -state normal
4270 while {[gets $bf line] >= 0} {
4271 $ctext insert end "$line\n"
4274 # delete last newline
4275 $ctext delete "end - 2c" "end - 1c"
4278 $ctext config -state disabled
4281 proc mergediff {id l} {
4282 global diffmergeid diffopts mdifffd
4288 # this doesn't seem to actually affect anything...
4289 set env(GIT_DIFF_OPTS) $diffopts
4290 set cmd [concat | git diff-tree --no-commit-id --cc $id]
4291 if {[catch {set mdf [open $cmd r]} err]} {
4292 error_popup "Error getting merge diffs: $err"
4295 fconfigure $mdf -blocking 0
4296 set mdifffd($id) $mdf
4297 set np [llength [lindex $parentlist $l]]
4298 fileevent $mdf readable [list getmergediffline $mdf $id $np]
4299 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
4302 proc getmergediffline {mdf id np} {
4303 global diffmergeid ctext cflist nextupdate mergemax
4304 global difffilestart mdifffd
4306 set n [gets $mdf line]
4313 if {![info exists diffmergeid] || $id != $diffmergeid
4314 || $mdf != $mdifffd($id)} {
4317 $ctext conf -state normal
4318 if {[regexp {^diff --cc (.*)} $line match fname]} {
4319 # start of a new file
4320 $ctext insert end "\n"
4321 set here [$ctext index "end - 1c"]
4322 lappend difffilestart $here
4323 add_flist [list $fname]
4324 set l [expr {(78 - [string length $fname]) / 2}]
4325 set pad [string range "----------------------------------------" 1 $l]
4326 $ctext insert end "$pad $fname $pad\n" filesep
4327 } elseif {[regexp {^@@} $line]} {
4328 $ctext insert end "$line\n" hunksep
4329 } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
4332 # parse the prefix - one ' ', '-' or '+' for each parent
4337 for {set j 0} {$j < $np} {incr j} {
4338 set c [string range $line $j $j]
4341 } elseif {$c == "-"} {
4343 } elseif {$c == "+"} {
4352 if {!$isbad && $minuses ne {} && $pluses eq {}} {
4353 # line doesn't appear in result, parents in $minuses have the line
4354 set num [lindex $minuses 0]
4355 } elseif {!$isbad && $pluses ne {} && $minuses eq {}} {
4356 # line appears in result, parents in $pluses don't have the line
4357 lappend tags mresult
4358 set num [lindex $spaces 0]
4361 if {$num >= $mergemax} {
4366 $ctext insert end "$line\n" $tags
4368 $ctext conf -state disabled
4369 if {[clock clicks -milliseconds] >= $nextupdate} {
4371 fileevent $mdf readable {}
4373 fileevent $mdf readable [list getmergediffline $mdf $id $np]
4377 proc startdiff {ids} {
4378 global treediffs diffids treepending diffmergeid
4381 catch {unset diffmergeid}
4382 if {![info exists treediffs($ids)]} {
4383 if {![info exists treepending]} {
4391 proc addtocflist {ids} {
4392 global treediffs cflist
4393 add_flist $treediffs($ids)
4397 proc gettreediffs {ids} {
4398 global treediff treepending
4399 set treepending $ids
4402 {set gdtf [open [concat | git diff-tree --no-commit-id -r $ids] r]} \
4404 fconfigure $gdtf -blocking 0
4405 fileevent $gdtf readable [list gettreediffline $gdtf $ids]
4408 proc gettreediffline {gdtf ids} {
4409 global treediff treediffs treepending diffids diffmergeid
4412 set n [gets $gdtf line]
4414 if {![eof $gdtf]} return
4416 set treediffs($ids) $treediff
4418 if {$cmitmode eq "tree"} {
4420 } elseif {$ids != $diffids} {
4421 if {![info exists diffmergeid]} {
4422 gettreediffs $diffids
4429 set file [lindex $line 5]
4430 lappend treediff $file
4433 proc getblobdiffs {ids} {
4434 global diffopts blobdifffd diffids env curdifftag curtagstart
4435 global nextupdate diffinhdr treediffs
4437 set env(GIT_DIFF_OPTS) $diffopts
4438 set cmd [concat | git diff-tree --no-commit-id -r -p -C $ids]
4439 if {[catch {set bdf [open $cmd r]} err]} {
4440 puts "error getting diffs: $err"
4444 fconfigure $bdf -blocking 0
4445 set blobdifffd($ids) $bdf
4446 set curdifftag Comments
4448 fileevent $bdf readable [list getblobdiffline $bdf $diffids]
4449 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
4452 proc setinlist {var i val} {
4455 while {[llength [set $var]] < $i} {
4458 if {[llength [set $var]] == $i} {
4465 proc getblobdiffline {bdf ids} {
4466 global diffids blobdifffd ctext curdifftag curtagstart
4467 global diffnexthead diffnextnote difffilestart
4468 global nextupdate diffinhdr treediffs
4470 set n [gets $bdf line]
4474 if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
4475 $ctext tag add $curdifftag $curtagstart end
4480 if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
4483 $ctext conf -state normal
4484 if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
4485 # start of a new file
4486 $ctext insert end "\n"
4487 $ctext tag add $curdifftag $curtagstart end
4488 set here [$ctext index "end - 1c"]
4489 set curtagstart $here
4491 set i [lsearch -exact $treediffs($ids) $fname]
4493 setinlist difffilestart $i $here
4495 if {$newname ne $fname} {
4496 set i [lsearch -exact $treediffs($ids) $newname]
4498 setinlist difffilestart $i $here
4501 set curdifftag "f:$fname"
4502 $ctext tag delete $curdifftag
4503 set l [expr {(78 - [string length $header]) / 2}]
4504 set pad [string range "----------------------------------------" 1 $l]
4505 $ctext insert end "$pad $header $pad\n" filesep
4507 } elseif {$diffinhdr && [string compare -length 3 $line "---"] == 0} {
4509 } elseif {$diffinhdr && [string compare -length 3 $line "+++"] == 0} {
4511 } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
4512 $line match f1l f1c f2l f2c rest]} {
4513 $ctext insert end "$line\n" hunksep
4516 set x [string range $line 0 0]
4517 if {$x == "-" || $x == "+"} {
4518 set tag [expr {$x == "+"}]
4519 $ctext insert end "$line\n" d$tag
4520 } elseif {$x == " "} {
4521 $ctext insert end "$line\n"
4522 } elseif {$diffinhdr || $x == "\\"} {
4523 # e.g. "\ No newline at end of file"
4524 $ctext insert end "$line\n" filesep
4526 # Something else we don't recognize
4527 if {$curdifftag != "Comments"} {
4528 $ctext insert end "\n"
4529 $ctext tag add $curdifftag $curtagstart end
4530 set curtagstart [$ctext index "end - 1c"]
4531 set curdifftag Comments
4533 $ctext insert end "$line\n" filesep
4536 $ctext conf -state disabled
4537 if {[clock clicks -milliseconds] >= $nextupdate} {
4539 fileevent $bdf readable {}
4541 fileevent $bdf readable "getblobdiffline $bdf {$ids}"
4545 proc changediffdisp {} {
4546 global ctext diffelide
4548 $ctext tag conf d0 -elide [lindex $diffelide 0]
4549 $ctext tag conf d1 -elide [lindex $diffelide 1]
4553 global difffilestart ctext
4554 set prev [lindex $difffilestart 0]
4555 set here [$ctext index @0,0]
4556 foreach loc $difffilestart {
4557 if {[$ctext compare $loc >= $here]} {
4567 global difffilestart ctext
4568 set here [$ctext index @0,0]
4569 foreach loc $difffilestart {
4570 if {[$ctext compare $loc > $here]} {
4577 proc clear_ctext {{first 1.0}} {
4578 global ctext smarktop smarkbot
4580 set l [lindex [split $first .] 0]
4581 if {![info exists smarktop] || [$ctext compare $first < $smarktop.0]} {
4584 if {![info exists smarkbot] || [$ctext compare $first < $smarkbot.0]} {
4587 $ctext delete $first end
4590 proc incrsearch {name ix op} {
4591 global ctext searchstring searchdirn
4593 $ctext tag remove found 1.0 end
4594 if {[catch {$ctext index anchor}]} {
4595 # no anchor set, use start of selection, or of visible area
4596 set sel [$ctext tag ranges sel]
4598 $ctext mark set anchor [lindex $sel 0]
4599 } elseif {$searchdirn eq "-forwards"} {
4600 $ctext mark set anchor @0,0
4602 $ctext mark set anchor @0,[winfo height $ctext]
4605 if {$searchstring ne {}} {
4606 set here [$ctext search $searchdirn -- $searchstring anchor]
4615 global sstring ctext searchstring searchdirn
4618 $sstring icursor end
4619 set searchdirn -forwards
4620 if {$searchstring ne {}} {
4621 set sel [$ctext tag ranges sel]
4623 set start "[lindex $sel 0] + 1c"
4624 } elseif {[catch {set start [$ctext index anchor]}]} {
4627 set match [$ctext search -count mlen -- $searchstring $start]
4628 $ctext tag remove sel 1.0 end
4634 set mend "$match + $mlen c"
4635 $ctext tag add sel $match $mend
4636 $ctext mark unset anchor
4640 proc dosearchback {} {
4641 global sstring ctext searchstring searchdirn
4644 $sstring icursor end
4645 set searchdirn -backwards
4646 if {$searchstring ne {}} {
4647 set sel [$ctext tag ranges sel]
4649 set start [lindex $sel 0]
4650 } elseif {[catch {set start [$ctext index anchor]}]} {
4651 set start @0,[winfo height $ctext]
4653 set match [$ctext search -backwards -count ml -- $searchstring $start]
4654 $ctext tag remove sel 1.0 end
4660 set mend "$match + $ml c"
4661 $ctext tag add sel $match $mend
4662 $ctext mark unset anchor
4666 proc searchmark {first last} {
4667 global ctext searchstring
4671 set match [$ctext search -count mlen -- $searchstring $mend $last.end]
4672 if {$match eq {}} break
4673 set mend "$match + $mlen c"
4674 $ctext tag add found $match $mend
4678 proc searchmarkvisible {doall} {
4679 global ctext smarktop smarkbot
4681 set topline [lindex [split [$ctext index @0,0] .] 0]
4682 set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0]
4683 if {$doall || $botline < $smarktop || $topline > $smarkbot} {
4684 # no overlap with previous
4685 searchmark $topline $botline
4686 set smarktop $topline
4687 set smarkbot $botline
4689 if {$topline < $smarktop} {
4690 searchmark $topline [expr {$smarktop-1}]
4691 set smarktop $topline
4693 if {$botline > $smarkbot} {
4694 searchmark [expr {$smarkbot+1}] $botline
4695 set smarkbot $botline
4700 proc scrolltext {f0 f1} {
4703 .bleft.sb set $f0 $f1
4704 if {$searchstring ne {}} {
4710 global linespc charspc canvx0 canvy0 mainfont
4711 global xspc1 xspc2 lthickness
4713 set linespc [font metrics $mainfont -linespace]
4714 set charspc [font measure $mainfont "m"]
4715 set canvy0 [expr {int(3 + 0.5 * $linespc)}]
4716 set canvx0 [expr {int(3 + 0.5 * $linespc)}]
4717 set lthickness [expr {int($linespc / 9) + 1}]
4718 set xspc1(0) $linespc
4726 set ymax [lindex [$canv cget -scrollregion] 3]
4727 if {$ymax eq {} || $ymax == 0} return
4728 set span [$canv yview]
4731 allcanvs yview moveto [lindex $span 0]
4733 if {[info exists selectedline]} {
4734 selectline $selectedline 0
4735 allcanvs yview moveto [lindex $span 0]
4739 proc incrfont {inc} {
4740 global mainfont textfont ctext canv phase cflist
4741 global charspc tabstop
4742 global stopped entries
4744 set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
4745 set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
4747 $ctext conf -font $textfont -tabs "[expr {$tabstop * $charspc}]"
4748 $cflist conf -font $textfont
4749 $ctext tag conf filesep -font [concat $textfont bold]
4750 foreach e $entries {
4751 $e conf -font $mainfont
4753 if {$phase eq "getcommits"} {
4754 $canv itemconf textitems -font $mainfont
4760 global sha1entry sha1string
4761 if {[string length $sha1string] == 40} {
4762 $sha1entry delete 0 end
4766 proc sha1change {n1 n2 op} {
4767 global sha1string currentid sha1but
4768 if {$sha1string == {}
4769 || ([info exists currentid] && $sha1string == $currentid)} {
4774 if {[$sha1but cget -state] == $state} return
4775 if {$state == "normal"} {
4776 $sha1but conf -state normal -relief raised -text "Goto: "
4778 $sha1but conf -state disabled -relief flat -text "SHA1 ID: "
4782 proc gotocommit {} {
4783 global sha1string currentid commitrow tagids headids
4784 global displayorder numcommits curview
4786 if {$sha1string == {}
4787 || ([info exists currentid] && $sha1string == $currentid)} return
4788 if {[info exists tagids($sha1string)]} {
4789 set id $tagids($sha1string)
4790 } elseif {[info exists headids($sha1string)]} {
4791 set id $headids($sha1string)
4793 set id [string tolower $sha1string]
4794 if {[regexp {^[0-9a-f]{4,39}$} $id]} {
4796 foreach i $displayorder {
4797 if {[string match $id* $i]} {
4801 if {$matches ne {}} {
4802 if {[llength $matches] > 1} {
4803 error_popup "Short SHA1 id $id is ambiguous"
4806 set id [lindex $matches 0]
4810 if {[info exists commitrow($curview,$id)]} {
4811 selectline $commitrow($curview,$id) 1
4814 if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
4819 error_popup "$type $sha1string is not known"
4822 proc lineenter {x y id} {
4823 global hoverx hovery hoverid hovertimer
4824 global commitinfo canv
4826 if {![info exists commitinfo($id)] && ![getcommit $id]} return
4830 if {[info exists hovertimer]} {
4831 after cancel $hovertimer
4833 set hovertimer [after 500 linehover]
4837 proc linemotion {x y id} {
4838 global hoverx hovery hoverid hovertimer
4840 if {[info exists hoverid] && $id == $hoverid} {
4843 if {[info exists hovertimer]} {
4844 after cancel $hovertimer
4846 set hovertimer [after 500 linehover]
4850 proc lineleave {id} {
4851 global hoverid hovertimer canv
4853 if {[info exists hoverid] && $id == $hoverid} {
4855 if {[info exists hovertimer]} {
4856 after cancel $hovertimer
4864 global hoverx hovery hoverid hovertimer
4865 global canv linespc lthickness
4866 global commitinfo mainfont
4868 set text [lindex $commitinfo($hoverid) 0]
4869 set ymax [lindex [$canv cget -scrollregion] 3]
4870 if {$ymax == {}} return
4871 set yfrac [lindex [$canv yview] 0]
4872 set x [expr {$hoverx + 2 * $linespc}]
4873 set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}]
4874 set x0 [expr {$x - 2 * $lthickness}]
4875 set y0 [expr {$y - 2 * $lthickness}]
4876 set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}]
4877 set y1 [expr {$y + $linespc + 2 * $lthickness}]
4878 set t [$canv create rectangle $x0 $y0 $x1 $y1 \
4879 -fill \#ffff80 -outline black -width 1 -tags hover]
4881 set t [$canv create text $x $y -anchor nw -text $text -tags hover \
4886 proc clickisonarrow {id y} {
4889 set ranges [rowranges $id]
4890 set thresh [expr {2 * $lthickness + 6}]
4891 set n [expr {[llength $ranges] - 1}]
4892 for {set i 1} {$i < $n} {incr i} {
4893 set row [lindex $ranges $i]
4894 if {abs([yc $row] - $y) < $thresh} {
4901 proc arrowjump {id n y} {
4904 # 1 <-> 2, 3 <-> 4, etc...
4905 set n [expr {(($n - 1) ^ 1) + 1}]
4906 set row [lindex [rowranges $id] $n]
4908 set ymax [lindex [$canv cget -scrollregion] 3]
4909 if {$ymax eq {} || $ymax <= 0} return
4910 set view [$canv yview]
4911 set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
4912 set yfrac [expr {$yt / $ymax - $yspan / 2}]
4916 allcanvs yview moveto $yfrac
4919 proc lineclick {x y id isnew} {
4920 global ctext commitinfo children canv thickerline curview
4922 if {![info exists commitinfo($id)] && ![getcommit $id]} return
4927 # draw this line thicker than normal
4931 set ymax [lindex [$canv cget -scrollregion] 3]
4932 if {$ymax eq {}} return
4933 set yfrac [lindex [$canv yview] 0]
4934 set y [expr {$y + $yfrac * $ymax}]
4936 set dirn [clickisonarrow $id $y]
4938 arrowjump $id $dirn $y
4943 addtohistory [list lineclick $x $y $id 0]
4945 # fill the details pane with info about this line
4946 $ctext conf -state normal
4948 $ctext tag conf link -foreground blue -underline 1
4949 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
4950 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
4951 $ctext insert end "Parent:\t"
4952 $ctext insert end $id [list link link0]
4953 $ctext tag bind link0 <1> [list selbyid $id]
4954 set info $commitinfo($id)
4955 $ctext insert end "\n\t[lindex $info 0]\n"
4956 $ctext insert end "\tAuthor:\t[lindex $info 1]\n"
4957 set date [formatdate [lindex $info 2]]
4958 $ctext insert end "\tDate:\t$date\n"
4959 set kids $children($curview,$id)
4961 $ctext insert end "\nChildren:"
4963 foreach child $kids {
4965 if {![info exists commitinfo($child)] && ![getcommit $child]} continue
4966 set info $commitinfo($child)
4967 $ctext insert end "\n\t"
4968 $ctext insert end $child [list link link$i]
4969 $ctext tag bind link$i <1> [list selbyid $child]
4970 $ctext insert end "\n\t[lindex $info 0]"
4971 $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
4972 set date [formatdate [lindex $info 2]]
4973 $ctext insert end "\n\tDate:\t$date\n"
4976 $ctext conf -state disabled
4980 proc normalline {} {
4982 if {[info exists thickerline]} {
4990 global commitrow curview
4991 if {[info exists commitrow($curview,$id)]} {
4992 selectline $commitrow($curview,$id) 1
4998 if {![info exists startmstime]} {
4999 set startmstime [clock clicks -milliseconds]
5001 return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]]
5004 proc rowmenu {x y id} {
5005 global rowctxmenu commitrow selectedline rowmenuid curview
5007 if {![info exists selectedline]
5008 || $commitrow($curview,$id) eq $selectedline} {
5013 $rowctxmenu entryconfigure "Diff this*" -state $state
5014 $rowctxmenu entryconfigure "Diff selected*" -state $state
5015 $rowctxmenu entryconfigure "Make patch" -state $state
5017 tk_popup $rowctxmenu $x $y
5020 proc diffvssel {dirn} {
5021 global rowmenuid selectedline displayorder
5023 if {![info exists selectedline]} return
5025 set oldid [lindex $displayorder $selectedline]
5026 set newid $rowmenuid
5028 set oldid $rowmenuid
5029 set newid [lindex $displayorder $selectedline]
5031 addtohistory [list doseldiff $oldid $newid]
5032 doseldiff $oldid $newid
5035 proc doseldiff {oldid newid} {
5039 $ctext conf -state normal
5042 $ctext insert end "From "
5043 $ctext tag conf link -foreground blue -underline 1
5044 $ctext tag bind link <Enter> { %W configure -cursor hand2 }
5045 $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
5046 $ctext tag bind link0 <1> [list selbyid $oldid]
5047 $ctext insert end $oldid [list link link0]
5048 $ctext insert end "\n "
5049 $ctext insert end [lindex $commitinfo($oldid) 0]
5050 $ctext insert end "\n\nTo "
5051 $ctext tag bind link1 <1> [list selbyid $newid]
5052 $ctext insert end $newid [list link link1]
5053 $ctext insert end "\n "
5054 $ctext insert end [lindex $commitinfo($newid) 0]
5055 $ctext insert end "\n"
5056 $ctext conf -state disabled
5057 $ctext tag delete Comments
5058 $ctext tag remove found 1.0 end
5059 startdiff [list $oldid $newid]
5063 global rowmenuid currentid commitinfo patchtop patchnum
5065 if {![info exists currentid]} return
5066 set oldid $currentid
5067 set oldhead [lindex $commitinfo($oldid) 0]
5068 set newid $rowmenuid
5069 set newhead [lindex $commitinfo($newid) 0]
5072 catch {destroy $top}
5074 label $top.title -text "Generate patch"
5075 grid $top.title - -pady 10
5076 label $top.from -text "From:"
5077 entry $top.fromsha1 -width 40 -relief flat
5078 $top.fromsha1 insert 0 $oldid
5079 $top.fromsha1 conf -state readonly
5080 grid $top.from $top.fromsha1 -sticky w
5081 entry $top.fromhead -width 60 -relief flat
5082 $top.fromhead insert 0 $oldhead
5083 $top.fromhead conf -state readonly
5084 grid x $top.fromhead -sticky w
5085 label $top.to -text "To:"
5086 entry $top.tosha1 -width 40 -relief flat
5087 $top.tosha1 insert 0 $newid
5088 $top.tosha1 conf -state readonly
5089 grid $top.to $top.tosha1 -sticky w
5090 entry $top.tohead -width 60 -relief flat
5091 $top.tohead insert 0 $newhead
5092 $top.tohead conf -state readonly
5093 grid x $top.tohead -sticky w
5094 button $top.rev -text "Reverse" -command mkpatchrev -padx 5
5095 grid $top.rev x -pady 10
5096 label $top.flab -text "Output file:"
5097 entry $top.fname -width 60
5098 $top.fname insert 0 [file normalize "patch$patchnum.patch"]
5100 grid $top.flab $top.fname -sticky w
5102 button $top.buts.gen -text "Generate" -command mkpatchgo
5103 button $top.buts.can -text "Cancel" -command mkpatchcan
5104 grid $top.buts.gen $top.buts.can
5105 grid columnconfigure $top.buts 0 -weight 1 -uniform a
5106 grid columnconfigure $top.buts 1 -weight 1 -uniform a
5107 grid $top.buts - -pady 10 -sticky ew
5111 proc mkpatchrev {} {
5114 set oldid [$patchtop.fromsha1 get]
5115 set oldhead [$patchtop.fromhead get]
5116 set newid [$patchtop.tosha1 get]
5117 set newhead [$patchtop.tohead get]
5118 foreach e [list fromsha1 fromhead tosha1 tohead] \
5119 v [list $newid $newhead $oldid $oldhead] {
5120 $patchtop.$e conf -state normal
5121 $patchtop.$e delete 0 end
5122 $patchtop.$e insert 0 $v
5123 $patchtop.$e conf -state readonly
5130 set oldid [$patchtop.fromsha1 get]
5131 set newid [$patchtop.tosha1 get]
5132 set fname [$patchtop.fname get]
5133 if {[catch {exec git diff-tree -p $oldid $newid >$fname &} err]} {
5134 error_popup "Error creating patch: $err"
5136 catch {destroy $patchtop}
5140 proc mkpatchcan {} {
5143 catch {destroy $patchtop}
5148 global rowmenuid mktagtop commitinfo
5152 catch {destroy $top}
5154 label $top.title -text "Create tag"
5155 grid $top.title - -pady 10
5156 label $top.id -text "ID:"
5157 entry $top.sha1 -width 40 -relief flat
5158 $top.sha1 insert 0 $rowmenuid
5159 $top.sha1 conf -state readonly
5160 grid $top.id $top.sha1 -sticky w
5161 entry $top.head -width 60 -relief flat
5162 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
5163 $top.head conf -state readonly
5164 grid x $top.head -sticky w
5165 label $top.tlab -text "Tag name:"
5166 entry $top.tag -width 60
5167 grid $top.tlab $top.tag -sticky w
5169 button $top.buts.gen -text "Create" -command mktaggo
5170 button $top.buts.can -text "Cancel" -command mktagcan
5171 grid $top.buts.gen $top.buts.can
5172 grid columnconfigure $top.buts 0 -weight 1 -uniform a
5173 grid columnconfigure $top.buts 1 -weight 1 -uniform a
5174 grid $top.buts - -pady 10 -sticky ew
5179 global mktagtop env tagids idtags
5181 set id [$mktagtop.sha1 get]
5182 set tag [$mktagtop.tag get]
5184 error_popup "No tag name specified"
5187 if {[info exists tagids($tag)]} {
5188 error_popup "Tag \"$tag\" already exists"
5193 set fname [file join $dir "refs/tags" $tag]
5194 set f [open $fname w]
5198 error_popup "Error creating tag: $err"
5202 set tagids($tag) $id
5203 lappend idtags($id) $tag
5208 proc redrawtags {id} {
5209 global canv linehtag commitrow idpos selectedline curview
5210 global mainfont canvxmax
5212 if {![info exists commitrow($curview,$id)]} return
5213 drawcmitrow $commitrow($curview,$id)
5214 $canv delete tag.$id
5215 set xt [eval drawtags $id $idpos($id)]
5216 $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2]
5217 set text [$canv itemcget $linehtag($commitrow($curview,$id)) -text]
5218 set xr [expr {$xt + [font measure $mainfont $text]}]
5219 if {$xr > $canvxmax} {
5223 if {[info exists selectedline]
5224 && $selectedline == $commitrow($curview,$id)} {
5225 selectline $selectedline 0
5232 catch {destroy $mktagtop}
5241 proc writecommit {} {
5242 global rowmenuid wrcomtop commitinfo wrcomcmd
5244 set top .writecommit
5246 catch {destroy $top}
5248 label $top.title -text "Write commit to file"
5249 grid $top.title - -pady 10
5250 label $top.id -text "ID:"
5251 entry $top.sha1 -width 40 -relief flat
5252 $top.sha1 insert 0 $rowmenuid
5253 $top.sha1 conf -state readonly
5254 grid $top.id $top.sha1 -sticky w
5255 entry $top.head -width 60 -relief flat
5256 $top.head insert 0 [lindex $commitinfo($rowmenuid) 0]
5257 $top.head conf -state readonly
5258 grid x $top.head -sticky w
5259 label $top.clab -text "Command:"
5260 entry $top.cmd -width 60 -textvariable wrcomcmd
5261 grid $top.clab $top.cmd -sticky w -pady 10
5262 label $top.flab -text "Output file:"
5263 entry $top.fname -width 60
5264 $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"]
5265 grid $top.flab $top.fname -sticky w
5267 button $top.buts.gen -text "Write" -command wrcomgo
5268 button $top.buts.can -text "Cancel" -command wrcomcan
5269 grid $top.buts.gen $top.buts.can
5270 grid columnconfigure $top.buts 0 -weight 1 -uniform a
5271 grid columnconfigure $top.buts 1 -weight 1 -uniform a
5272 grid $top.buts - -pady 10 -sticky ew
5279 set id [$wrcomtop.sha1 get]
5280 set cmd "echo $id | [$wrcomtop.cmd get]"
5281 set fname [$wrcomtop.fname get]
5282 if {[catch {exec sh -c $cmd >$fname &} err]} {
5283 error_popup "Error writing commit: $err"
5285 catch {destroy $wrcomtop}
5292 catch {destroy $wrcomtop}
5297 global rowmenuid mkbrtop
5300 catch {destroy $top}
5302 label $top.title -text "Create new branch"
5303 grid $top.title - -pady 10
5304 label $top.id -text "ID:"
5305 entry $top.sha1 -width 40 -relief flat
5306 $top.sha1 insert 0 $rowmenuid
5307 $top.sha1 conf -state readonly
5308 grid $top.id $top.sha1 -sticky w
5309 label $top.nlab -text "Name:"
5310 entry $top.name -width 40
5311 grid $top.nlab $top.name -sticky w
5313 button $top.buts.go -text "Create" -command [list mkbrgo $top]
5314 button $top.buts.can -text "Cancel" -command "catch {destroy $top}"
5315 grid $top.buts.go $top.buts.can
5316 grid columnconfigure $top.buts 0 -weight 1 -uniform a
5317 grid columnconfigure $top.buts 1 -weight 1 -uniform a
5318 grid $top.buts - -pady 10 -sticky ew
5323 global headids idheads
5325 set name [$top.name get]
5326 set id [$top.sha1 get]
5328 error_popup "Please specify a name for the new branch"
5331 catch {destroy $top}
5335 exec git branch $name $id
5340 set headids($name) $id
5341 lappend idheads($id) $name
5349 proc cherrypick {} {
5350 global rowmenuid curview commitrow
5353 set oldhead [exec git rev-parse HEAD]
5354 set dheads [descheads $rowmenuid]
5355 if {$dheads ne {} && [lsearch -exact $dheads $oldhead] >= 0} {
5356 set ok [confirm_popup "Commit [string range $rowmenuid 0 7] is already\
5357 included in branch $mainhead -- really re-apply it?"]
5362 # Unfortunately git-cherry-pick writes stuff to stderr even when
5363 # no error occurs, and exec takes that as an indication of error...
5364 if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} {
5369 set newhead [exec git rev-parse HEAD]
5370 if {$newhead eq $oldhead} {
5372 error_popup "No changes committed"
5375 addnewchild $newhead $oldhead
5376 if {[info exists commitrow($curview,$oldhead)]} {
5377 insertrow $commitrow($curview,$oldhead) $newhead
5378 if {$mainhead ne {}} {
5379 movehead $newhead $mainhead
5380 movedhead $newhead $mainhead
5388 # context menu for a head
5389 proc headmenu {x y id head} {
5390 global headmenuid headmenuhead headctxmenu
5393 set headmenuhead $head
5394 tk_popup $headctxmenu $x $y
5398 global headmenuid headmenuhead mainhead headids
5400 # check the tree is clean first??
5401 set oldmainhead $mainhead
5405 exec git checkout -q $headmenuhead
5411 set mainhead $headmenuhead
5412 if {[info exists headids($oldmainhead)]} {
5413 redrawtags $headids($oldmainhead)
5415 redrawtags $headmenuid
5420 global headmenuid headmenuhead mainhead
5421 global headids idheads
5423 set head $headmenuhead
5425 if {$head eq $mainhead} {
5426 error_popup "Cannot delete the currently checked-out branch"
5429 set dheads [descheads $id]
5430 if {$dheads eq $headids($head)} {
5431 # the stuff on this branch isn't on any other branch
5432 if {![confirm_popup "The commits on branch $head aren't on any other\
5433 branch.\nReally delete branch $head?"]} return
5437 if {[catch {exec git branch -D $head} err]} {
5442 removehead $id $head
5443 removedhead $id $head
5449 # Stuff for finding nearby tags
5450 proc getallcommits {} {
5451 global allcommits allids nbmp nextarc seeds
5461 # Called when the graph might have changed
5462 proc regetallcommits {} {
5463 global allcommits seeds
5465 set cmd [concat | git rev-list --all --parents]
5469 set fd [open $cmd r]
5470 fconfigure $fd -blocking 0
5476 proc restartgetall {fd} {
5477 fileevent $fd readable [list getallclines $fd]
5480 # Since most commits have 1 parent and 1 child, we group strings of
5481 # such commits into "arcs" joining branch/merge points (BMPs), which
5482 # are commits that either don't have 1 parent or don't have 1 child.
5484 # arcnos(id) - incoming arcs for BMP, arc we're on for other nodes
5485 # arcout(id) - outgoing arcs for BMP
5486 # arcids(a) - list of IDs on arc including end but not start
5487 # arcstart(a) - BMP ID at start of arc
5488 # arcend(a) - BMP ID at end of arc
5489 # growing(a) - arc a is still growing
5490 # arctags(a) - IDs out of arcids (excluding end) that have tags
5491 # archeads(a) - IDs out of arcids (excluding end) that have heads
5492 # The start of an arc is at the descendent end, so "incoming" means
5493 # coming from descendents, and "outgoing" means going towards ancestors.
5495 proc getallclines {fd} {
5496 global allids allparents allchildren idtags nextarc nbmp
5497 global arcnos arcids arctags arcout arcend arcstart archeads growing
5498 global seeds allcommits allcstart
5500 if {![info exists allcstart]} {
5501 set allcstart [clock clicks -milliseconds]
5504 while {[gets $fd line] >= 0} {
5505 set id [lindex $line 0]
5506 if {[info exists allparents($id)]} {
5511 set olds [lrange $line 1 end]
5512 set allparents($id) $olds
5513 if {![info exists allchildren($id)]} {
5514 set allchildren($id) {}
5519 if {[llength $olds] == 1 && [llength $a] == 1} {
5520 lappend arcids($a) $id
5521 if {[info exists idtags($id)]} {
5522 lappend arctags($a) $id
5524 if {[info exists idheads($id)]} {
5525 lappend archeads($a) $id
5527 if {[info exists allparents($olds)]} {
5528 # seen parent already
5529 if {![info exists arcout($olds)]} {
5532 lappend arcids($a) $olds
5533 set arcend($a) $olds
5536 lappend allchildren($olds) $id
5537 lappend arcnos($olds) $a
5542 foreach a $arcnos($id) {
5543 lappend arcids($a) $id
5550 lappend allchildren($p) $id
5551 set a [incr nextarc]
5552 set arcstart($a) $id
5559 if {[info exists allparents($p)]} {
5560 # seen it already, may need to make a new branch
5561 if {![info exists arcout($p)]} {
5564 lappend arcids($a) $p
5568 lappend arcnos($p) $a
5571 if {[incr nid] >= 50} {
5573 if {[clock clicks -milliseconds] - $allcstart >= 50} {
5574 fileevent $fd readable {}
5575 after idle restartgetall $fd
5581 if {![eof $fd]} return
5583 if {[incr allcommits -1] == 0} {
5589 proc recalcarc {a} {
5590 global arctags archeads arcids idtags idheads
5594 foreach id [lrange $arcids($a) 0 end-1] {
5595 if {[info exists idtags($id)]} {
5598 if {[info exists idheads($id)]} {
5603 set archeads($a) $ah
5607 global arcnos arcids nextarc nbmp arctags archeads idtags idheads
5608 global arcstart arcend arcout allparents growing
5611 if {[llength $a] != 1} {
5612 puts "oops splitarc called but [llength $a] arcs already"
5616 set i [lsearch -exact $arcids($a) $p]
5618 puts "oops splitarc $p not in arc $a"
5621 set na [incr nextarc]
5622 if {[info exists arcend($a)]} {
5623 set arcend($na) $arcend($a)
5625 set l [lindex $allparents([lindex $arcids($a) end]) 0]
5626 set j [lsearch -exact $arcnos($l) $a]
5627 set arcnos($l) [lreplace $arcnos($l) $j $j $na]
5629 set tail [lrange $arcids($a) [expr {$i+1}] end]
5630 set arcids($a) [lrange $arcids($a) 0 $i]
5632 set arcstart($na) $p
5634 set arcids($na) $tail
5635 if {[info exists growing($a)]} {
5642 if {[llength $arcnos($id)] == 1} {
5645 set j [lsearch -exact $arcnos($id) $a]
5646 set arcnos($id) [lreplace $arcnos($id) $j $j $na]
5650 # reconstruct tags and heads lists
5651 if {$arctags($a) ne {} || $archeads($a) ne {}} {
5656 set archeads($na) {}
5660 # Update things for a new commit added that is a child of one
5661 # existing commit. Used when cherry-picking.
5662 proc addnewchild {id p} {
5663 global allids allparents allchildren idtags nextarc nbmp
5664 global arcnos arcids arctags arcout arcend arcstart archeads growing
5668 set allparents($id) [list $p]
5669 set allchildren($id) {}
5673 lappend allchildren($p) $id
5674 set a [incr nextarc]
5675 set arcstart($a) $id
5678 set arcids($a) [list $p]
5680 if {![info exists arcout($p)]} {
5683 lappend arcnos($p) $a
5684 set arcout($id) [list $a]
5687 # Returns 1 if a is an ancestor of b, -1 if b is an ancestor of a,
5688 # or 0 if neither is true.
5689 proc anc_or_desc {a b} {
5690 global arcout arcstart arcend arcnos cached_isanc
5692 if {$arcnos($a) eq $arcnos($b)} {
5693 # Both are on the same arc(s); either both are the same BMP,
5694 # or if one is not a BMP, the other is also not a BMP or is
5695 # the BMP at end of the arc (and it only has 1 incoming arc).
5699 # assert {[llength $arcnos($a)] == 1}
5700 set arc [lindex $arcnos($a) 0]
5701 set i [lsearch -exact $arcids($arc) $a]
5702 set j [lsearch -exact $arcids($arc) $b]
5703 if {$i < 0 || $i > $j} {
5710 if {![info exists arcout($a)]} {
5711 set arc [lindex $arcnos($a) 0]
5712 if {[info exists arcend($arc)]} {
5713 set aend $arcend($arc)
5717 set a $arcstart($arc)
5721 if {![info exists arcout($b)]} {
5722 set arc [lindex $arcnos($b) 0]
5723 if {[info exists arcend($arc)]} {
5724 set bend $arcend($arc)
5728 set b $arcstart($arc)
5738 if {[info exists cached_isanc($a,$bend)]} {
5739 if {$cached_isanc($a,$bend)} {
5743 if {[info exists cached_isanc($b,$aend)]} {
5744 if {$cached_isanc($b,$aend)} {
5747 if {[info exists cached_isanc($a,$bend)]} {
5752 set todo [list $a $b]
5755 for {set i 0} {$i < [llength $todo]} {incr i} {
5756 set x [lindex $todo $i]
5757 if {$anc($x) eq {}} {
5760 foreach arc $arcnos($x) {
5761 set xd $arcstart($arc)
5763 set cached_isanc($a,$bend) 1
5764 set cached_isanc($b,$aend) 0
5766 } elseif {$xd eq $aend} {
5767 set cached_isanc($b,$aend) 1
5768 set cached_isanc($a,$bend) 0
5771 if {![info exists anc($xd)]} {
5772 set anc($xd) $anc($x)
5774 } elseif {$anc($xd) ne $anc($x)} {
5779 set cached_isanc($a,$bend) 0
5780 set cached_isanc($b,$aend) 0
5784 # This identifies whether $desc has an ancestor that is
5785 # a growing tip of the graph and which is not an ancestor of $anc
5786 # and returns 0 if so and 1 if not.
5787 # If we subsequently discover a tag on such a growing tip, and that
5788 # turns out to be a descendent of $anc (which it could, since we
5789 # don't necessarily see children before parents), then $desc
5790 # isn't a good choice to display as a descendent tag of
5791 # $anc (since it is the descendent of another tag which is
5792 # a descendent of $anc). Similarly, $anc isn't a good choice to
5793 # display as a ancestor tag of $desc.
5795 proc is_certain {desc anc} {
5796 global arcnos arcout arcstart arcend growing problems
5799 if {[llength $arcnos($anc)] == 1} {
5800 # tags on the same arc are certain
5801 if {$arcnos($desc) eq $arcnos($anc)} {
5804 if {![info exists arcout($anc)]} {
5805 # if $anc is partway along an arc, use the start of the arc instead
5806 set a [lindex $arcnos($anc) 0]
5807 set anc $arcstart($a)
5810 if {[llength $arcnos($desc)] > 1 || [info exists arcout($desc)]} {
5813 set a [lindex $arcnos($desc) 0]
5819 set anclist [list $x]
5823 for {set i 0} {$i < [llength $anclist] && ($nnh > 0 || $ngrowanc > 0)} {incr i} {
5824 set x [lindex $anclist $i]
5829 foreach a $arcout($x) {
5830 if {[info exists growing($a)]} {
5831 if {![info exists growanc($x)] && $dl($x)} {
5837 if {[info exists dl($y)]} {
5841 if {![info exists done($y)]} {
5844 if {[info exists growanc($x)]} {
5848 for {set k 0} {$k < [llength $xl]} {incr k} {
5849 set z [lindex $xl $k]
5850 foreach c $arcout($z) {
5851 if {[info exists arcend($c)]} {
5853 if {[info exists dl($v)] && $dl($v)} {
5855 if {![info exists done($v)]} {
5858 if {[info exists growanc($v)]} {
5868 } elseif {$y eq $anc || !$dl($x)} {
5879 foreach x [array names growanc] {
5887 proc validate_arctags {a} {
5888 global arctags idtags
5892 foreach id $arctags($a) {
5894 if {![info exists idtags($id)]} {
5895 set na [lreplace $na $i $i]
5902 proc validate_archeads {a} {
5903 global archeads idheads
5906 set na $archeads($a)
5907 foreach id $archeads($a) {
5909 if {![info exists idheads($id)]} {
5910 set na [lreplace $na $i $i]
5914 set archeads($a) $na
5917 # Return the list of IDs that have tags that are descendents of id,
5918 # ignoring IDs that are descendents of IDs already reported.
5919 proc desctags {id} {
5920 global arcnos arcstart arcids arctags idtags allparents
5921 global growing cached_dtags
5923 if {![info exists allparents($id)]} {
5926 set t1 [clock clicks -milliseconds]
5928 if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
5929 # part-way along an arc; check that arc first
5930 set a [lindex $arcnos($id) 0]
5931 if {$arctags($a) ne {}} {
5933 set i [lsearch -exact $arcids($a) $id]
5935 foreach t $arctags($a) {
5936 set j [lsearch -exact $arcids($a) $t]
5944 set id $arcstart($a)
5945 if {[info exists idtags($id)]} {
5949 if {[info exists cached_dtags($id)]} {
5950 return $cached_dtags($id)
5957 for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
5958 set id [lindex $todo $i]
5960 set ta [info exists hastaggedancestor($id)]
5964 # ignore tags on starting node
5965 if {!$ta && $i > 0} {
5966 if {[info exists idtags($id)]} {
5969 } elseif {[info exists cached_dtags($id)]} {
5970 set tagloc($id) $cached_dtags($id)
5974 foreach a $arcnos($id) {
5976 if {!$ta && $arctags($a) ne {}} {
5978 if {$arctags($a) ne {}} {
5979 lappend tagloc($id) [lindex $arctags($a) end]
5982 if {$ta || $arctags($a) ne {}} {
5983 set tomark [list $d]
5984 for {set j 0} {$j < [llength $tomark]} {incr j} {
5985 set dd [lindex $tomark $j]
5986 if {![info exists hastaggedancestor($dd)]} {
5987 if {[info exists done($dd)]} {
5988 foreach b $arcnos($dd) {
5989 lappend tomark $arcstart($b)
5991 if {[info exists tagloc($dd)]} {
5994 } elseif {[info exists queued($dd)]} {
5997 set hastaggedancestor($dd) 1
6001 if {![info exists queued($d)]} {
6004 if {![info exists hastaggedancestor($d)]} {
6011 foreach id [array names tagloc] {
6012 if {![info exists hastaggedancestor($id)]} {
6013 foreach t $tagloc($id) {
6014 if {[lsearch -exact $tags $t] < 0} {
6020 set t2 [clock clicks -milliseconds]
6023 # remove tags that are descendents of other tags
6024 for {set i 0} {$i < [llength $tags]} {incr i} {
6025 set a [lindex $tags $i]
6026 for {set j 0} {$j < $i} {incr j} {
6027 set b [lindex $tags $j]
6028 set r [anc_or_desc $a $b]
6030 set tags [lreplace $tags $j $j]
6033 } elseif {$r == -1} {
6034 set tags [lreplace $tags $i $i]
6041 if {[array names growing] ne {}} {
6042 # graph isn't finished, need to check if any tag could get
6043 # eclipsed by another tag coming later. Simply ignore any
6044 # tags that could later get eclipsed.
6047 if {[is_certain $t $origid]} {
6051 if {$tags eq $ctags} {
6052 set cached_dtags($origid) $tags
6057 set cached_dtags($origid) $tags
6059 set t3 [clock clicks -milliseconds]
6060 if {0 && $t3 - $t1 >= 100} {
6061 puts "iterating descendents ($loopix/[llength $todo] nodes) took\
6062 [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
6068 global arcnos arcids arcout arcend arctags idtags allparents
6069 global growing cached_atags
6071 if {![info exists allparents($id)]} {
6074 set t1 [clock clicks -milliseconds]
6076 if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
6077 # part-way along an arc; check that arc first
6078 set a [lindex $arcnos($id) 0]
6079 if {$arctags($a) ne {}} {
6081 set i [lsearch -exact $arcids($a) $id]
6082 foreach t $arctags($a) {
6083 set j [lsearch -exact $arcids($a) $t]
6089 if {![info exists arcend($a)]} {
6093 if {[info exists idtags($id)]} {
6097 if {[info exists cached_atags($id)]} {
6098 return $cached_atags($id)
6106 for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
6107 set id [lindex $todo $i]
6109 set td [info exists hastaggeddescendent($id)]
6113 # ignore tags on starting node
6114 if {!$td && $i > 0} {
6115 if {[info exists idtags($id)]} {
6118 } elseif {[info exists cached_atags($id)]} {
6119 set tagloc($id) $cached_atags($id)
6123 foreach a $arcout($id) {
6124 if {!$td && $arctags($a) ne {}} {
6126 if {$arctags($a) ne {}} {
6127 lappend tagloc($id) [lindex $arctags($a) 0]
6130 if {![info exists arcend($a)]} continue
6132 if {$td || $arctags($a) ne {}} {
6133 set tomark [list $d]
6134 for {set j 0} {$j < [llength $tomark]} {incr j} {
6135 set dd [lindex $tomark $j]
6136 if {![info exists hastaggeddescendent($dd)]} {
6137 if {[info exists done($dd)]} {
6138 foreach b $arcout($dd) {
6139 if {[info exists arcend($b)]} {
6140 lappend tomark $arcend($b)
6143 if {[info exists tagloc($dd)]} {
6146 } elseif {[info exists queued($dd)]} {
6149 set hastaggeddescendent($dd) 1
6153 if {![info exists queued($d)]} {
6156 if {![info exists hastaggeddescendent($d)]} {
6162 set t2 [clock clicks -milliseconds]
6165 foreach id [array names tagloc] {
6166 if {![info exists hastaggeddescendent($id)]} {
6167 foreach t $tagloc($id) {
6168 if {[lsearch -exact $tags $t] < 0} {
6175 # remove tags that are ancestors of other tags
6176 for {set i 0} {$i < [llength $tags]} {incr i} {
6177 set a [lindex $tags $i]
6178 for {set j 0} {$j < $i} {incr j} {
6179 set b [lindex $tags $j]
6180 set r [anc_or_desc $a $b]
6182 set tags [lreplace $tags $j $j]
6185 } elseif {$r == 1} {
6186 set tags [lreplace $tags $i $i]
6193 if {[array names growing] ne {}} {
6194 # graph isn't finished, need to check if any tag could get
6195 # eclipsed by another tag coming later. Simply ignore any
6196 # tags that could later get eclipsed.
6199 if {[is_certain $origid $t]} {
6203 if {$tags eq $ctags} {
6204 set cached_atags($origid) $tags
6209 set cached_atags($origid) $tags
6211 set t3 [clock clicks -milliseconds]
6212 if {0 && $t3 - $t1 >= 100} {
6213 puts "iterating ancestors ($loopix/[llength $todo] nodes) took\
6214 [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
6219 # Return the list of IDs that have heads that are descendents of id,
6220 # including id itself if it has a head.
6221 proc descheads {id} {
6222 global arcnos arcstart arcids archeads idheads cached_dheads
6225 if {![info exists allparents($id)]} {
6229 if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
6230 # part-way along an arc; check it first
6231 set a [lindex $arcnos($id) 0]
6232 if {$archeads($a) ne {}} {
6233 validate_archeads $a
6234 set i [lsearch -exact $arcids($a) $id]
6235 foreach t $archeads($a) {
6236 set j [lsearch -exact $arcids($a) $t]
6241 set id $arcstart($a)
6246 for {set i 0} {$i < [llength $todo]} {incr i} {
6247 set id [lindex $todo $i]
6248 if {[info exists cached_dheads($id)]} {
6249 set ret [concat $ret $cached_dheads($id)]
6251 if {[info exists idheads($id)]} {
6254 foreach a $arcnos($id) {
6255 if {$archeads($a) ne {}} {
6256 set ret [concat $ret $archeads($a)]
6259 if {![info exists seen($d)]} {
6266 set ret [lsort -unique $ret]
6267 set cached_dheads($origid) $ret
6270 proc addedtag {id} {
6271 global arcnos arcout cached_dtags cached_atags
6273 if {![info exists arcnos($id)]} return
6274 if {![info exists arcout($id)]} {
6275 recalcarc [lindex $arcnos($id) 0]
6277 catch {unset cached_dtags}
6278 catch {unset cached_atags}
6281 proc addedhead {hid head} {
6282 global arcnos arcout cached_dheads
6284 if {![info exists arcnos($hid)]} return
6285 if {![info exists arcout($hid)]} {
6286 recalcarc [lindex $arcnos($hid) 0]
6288 catch {unset cached_dheads}
6291 proc removedhead {hid head} {
6292 global cached_dheads
6294 catch {unset cached_dheads}
6297 proc movedhead {hid head} {
6298 global arcnos arcout cached_dheads
6300 if {![info exists arcnos($hid)]} return
6301 if {![info exists arcout($hid)]} {
6302 recalcarc [lindex $arcnos($hid) 0]
6304 catch {unset cached_dheads}
6307 proc changedrefs {} {
6308 global cached_dheads cached_dtags cached_atags
6309 global arctags archeads arcnos arcout idheads idtags
6311 foreach id [concat [array names idheads] [array names idtags]] {
6312 if {[info exists arcnos($id)] && ![info exists arcout($id)]} {
6313 set a [lindex $arcnos($id) 0]
6314 if {![info exists donearc($a)]} {
6320 catch {unset cached_dtags}
6321 catch {unset cached_atags}
6322 catch {unset cached_dheads}
6325 proc rereadrefs {} {
6326 global idtags idheads idotherrefs mainhead
6328 set refids [concat [array names idtags] \
6329 [array names idheads] [array names idotherrefs]]
6330 foreach id $refids {
6331 if {![info exists ref($id)]} {
6332 set ref($id) [listrefs $id]
6335 set oldmainhead $mainhead
6338 set refids [lsort -unique [concat $refids [array names idtags] \
6339 [array names idheads] [array names idotherrefs]]]
6340 foreach id $refids {
6341 set v [listrefs $id]
6342 if {![info exists ref($id)] || $ref($id) != $v ||
6343 ($id eq $oldmainhead && $id ne $mainhead) ||
6344 ($id eq $mainhead && $id ne $oldmainhead)} {
6350 proc listrefs {id} {
6351 global idtags idheads idotherrefs
6354 if {[info exists idtags($id)]} {
6358 if {[info exists idheads($id)]} {
6362 if {[info exists idotherrefs($id)]} {
6363 set z $idotherrefs($id)
6365 return [list $x $y $z]
6368 proc showtag {tag isnew} {
6369 global ctext tagcontents tagids linknum
6372 addtohistory [list showtag $tag 0]
6374 $ctext conf -state normal
6377 if {[info exists tagcontents($tag)]} {
6378 set text $tagcontents($tag)
6380 set text "Tag: $tag\nId: $tagids($tag)"
6382 appendwithlinks $text {}
6383 $ctext conf -state disabled
6395 global maxwidth maxgraphpct diffopts
6396 global oldprefs prefstop showneartags
6397 global bgcolor fgcolor ctext diffcolors selectbgcolor
6398 global uifont tabstop
6402 if {[winfo exists $top]} {
6406 foreach v {maxwidth maxgraphpct diffopts showneartags} {
6407 set oldprefs($v) [set $v]
6410 wm title $top "Gitk preferences"
6411 label $top.ldisp -text "Commit list display options"
6412 $top.ldisp configure -font $uifont
6413 grid $top.ldisp - -sticky w -pady 10
6414 label $top.spacer -text " "
6415 label $top.maxwidthl -text "Maximum graph width (lines)" \
6417 spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
6418 grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
6419 label $top.maxpctl -text "Maximum graph width (% of pane)" \
6421 spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
6422 grid x $top.maxpctl $top.maxpct -sticky w
6424 label $top.ddisp -text "Diff display options"
6425 $top.ddisp configure -font $uifont
6426 grid $top.ddisp - -sticky w -pady 10
6427 label $top.diffoptl -text "Options for diff program" \
6429 entry $top.diffopt -width 20 -textvariable diffopts
6430 grid x $top.diffoptl $top.diffopt -sticky w
6432 label $top.ntag.l -text "Display nearby tags" -font optionfont
6433 checkbutton $top.ntag.b -variable showneartags
6434 pack $top.ntag.b $top.ntag.l -side left
6435 grid x $top.ntag -sticky w
6436 label $top.tabstopl -text "tabstop" -font optionfont
6437 entry $top.tabstop -width 10 -textvariable tabstop
6438 grid x $top.tabstopl $top.tabstop -sticky w
6440 label $top.cdisp -text "Colors: press to choose"
6441 $top.cdisp configure -font $uifont
6442 grid $top.cdisp - -sticky w -pady 10
6443 label $top.bg -padx 40 -relief sunk -background $bgcolor
6444 button $top.bgbut -text "Background" -font optionfont \
6445 -command [list choosecolor bgcolor 0 $top.bg background setbg]
6446 grid x $top.bgbut $top.bg -sticky w
6447 label $top.fg -padx 40 -relief sunk -background $fgcolor
6448 button $top.fgbut -text "Foreground" -font optionfont \
6449 -command [list choosecolor fgcolor 0 $top.fg foreground setfg]
6450 grid x $top.fgbut $top.fg -sticky w
6451 label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
6452 button $top.diffoldbut -text "Diff: old lines" -font optionfont \
6453 -command [list choosecolor diffcolors 0 $top.diffold "diff old lines" \
6454 [list $ctext tag conf d0 -foreground]]
6455 grid x $top.diffoldbut $top.diffold -sticky w
6456 label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
6457 button $top.diffnewbut -text "Diff: new lines" -font optionfont \
6458 -command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
6459 [list $ctext tag conf d1 -foreground]]
6460 grid x $top.diffnewbut $top.diffnew -sticky w
6461 label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
6462 button $top.hunksepbut -text "Diff: hunk header" -font optionfont \
6463 -command [list choosecolor diffcolors 2 $top.hunksep \
6464 "diff hunk header" \
6465 [list $ctext tag conf hunksep -foreground]]
6466 grid x $top.hunksepbut $top.hunksep -sticky w
6467 label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
6468 button $top.selbgbut -text "Select bg" -font optionfont \
6469 -command [list choosecolor selectbgcolor 0 $top.bg background setselbg]
6470 grid x $top.selbgbut $top.selbgsep -sticky w
6473 button $top.buts.ok -text "OK" -command prefsok -default active
6474 $top.buts.ok configure -font $uifont
6475 button $top.buts.can -text "Cancel" -command prefscan -default normal
6476 $top.buts.can configure -font $uifont
6477 grid $top.buts.ok $top.buts.can
6478 grid columnconfigure $top.buts 0 -weight 1 -uniform a
6479 grid columnconfigure $top.buts 1 -weight 1 -uniform a
6480 grid $top.buts - - -pady 10 -sticky ew
6481 bind $top <Visibility> "focus $top.buts.ok"
6484 proc choosecolor {v vi w x cmd} {
6487 set c [tk_chooseColor -initialcolor [lindex [set $v] $vi] \
6488 -title "Gitk: choose color for $x"]
6489 if {$c eq {}} return
6490 $w conf -background $c
6496 global bglist cflist
6498 $w configure -selectbackground $c
6500 $cflist tag configure highlight \
6501 -background [$cflist cget -selectbackground]
6502 allcanvs itemconf secsel -fill $c
6509 $w conf -background $c
6517 $w conf -foreground $c
6519 allcanvs itemconf text -fill $c
6520 $canv itemconf circle -outline $c
6524 global maxwidth maxgraphpct diffopts
6525 global oldprefs prefstop showneartags
6527 foreach v {maxwidth maxgraphpct diffopts showneartags} {
6528 set $v $oldprefs($v)
6530 catch {destroy $prefstop}
6535 global maxwidth maxgraphpct
6536 global oldprefs prefstop showneartags
6537 global charspc ctext tabstop
6539 catch {destroy $prefstop}
6541 $ctext configure -tabs "[expr {$tabstop * $charspc}]"
6542 if {$maxwidth != $oldprefs(maxwidth)
6543 || $maxgraphpct != $oldprefs(maxgraphpct)} {
6545 } elseif {$showneartags != $oldprefs(showneartags)} {
6550 proc formatdate {d} {
6551 return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
6554 # This list of encoding names and aliases is distilled from
6555 # http://www.iana.org/assignments/character-sets.
6556 # Not all of them are supported by Tcl.
6557 set encoding_aliases {
6558 { ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
6559 ISO646-US US-ASCII us IBM367 cp367 csASCII }
6560 { ISO-10646-UTF-1 csISO10646UTF1 }
6561 { ISO_646.basic:1983 ref csISO646basic1983 }
6562 { INVARIANT csINVARIANT }
6563 { ISO_646.irv:1983 iso-ir-2 irv csISO2IntlRefVersion }
6564 { BS_4730 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom }
6565 { NATS-SEFI iso-ir-8-1 csNATSSEFI }
6566 { NATS-SEFI-ADD iso-ir-8-2 csNATSSEFIADD }
6567 { NATS-DANO iso-ir-9-1 csNATSDANO }
6568 { NATS-DANO-ADD iso-ir-9-2 csNATSDANOADD }
6569 { SEN_850200_B iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish }
6570 { SEN_850200_C iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames }
6571 { KS_C_5601-1987 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987 }
6572 { ISO-2022-KR csISO2022KR }
6574 { ISO-2022-JP csISO2022JP }
6575 { ISO-2022-JP-2 csISO2022JP2 }
6576 { JIS_C6220-1969-jp JIS_C6220-1969 iso-ir-13 katakana x0201-7
6578 { JIS_C6220-1969-ro iso-ir-14 jp ISO646-JP csISO14JISC6220ro }
6579 { IT iso-ir-15 ISO646-IT csISO15Italian }
6580 { PT iso-ir-16 ISO646-PT csISO16Portuguese }
6581 { ES iso-ir-17 ISO646-ES csISO17Spanish }
6582 { greek7-old iso-ir-18 csISO18Greek7Old }
6583 { latin-greek iso-ir-19 csISO19LatinGreek }
6584 { DIN_66003 iso-ir-21 de ISO646-DE csISO21German }
6585 { NF_Z_62-010_(1973) iso-ir-25 ISO646-FR1 csISO25French }
6586 { Latin-greek-1 iso-ir-27 csISO27LatinGreek1 }
6587 { ISO_5427 iso-ir-37 csISO5427Cyrillic }
6588 { JIS_C6226-1978 iso-ir-42 csISO42JISC62261978 }
6589 { BS_viewdata iso-ir-47 csISO47BSViewdata }
6590 { INIS iso-ir-49 csISO49INIS }
6591 { INIS-8 iso-ir-50 csISO50INIS8 }
6592 { INIS-cyrillic iso-ir-51 csISO51INISCyrillic }
6593 { ISO_5427:1981 iso-ir-54 ISO5427Cyrillic1981 }
6594 { ISO_5428:1980 iso-ir-55 csISO5428Greek }
6595 { GB_1988-80 iso-ir-57 cn ISO646-CN csISO57GB1988 }
6596 { GB_2312-80 iso-ir-58 chinese csISO58GB231280 }
6597 { NS_4551-1 iso-ir-60 ISO646-NO no csISO60DanishNorwegian
6599 { NS_4551-2 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2 }
6600 { NF_Z_62-010 iso-ir-69 ISO646-FR fr csISO69French }
6601 { videotex-suppl iso-ir-70 csISO70VideotexSupp1 }
6602 { PT2 iso-ir-84 ISO646-PT2 csISO84Portuguese2 }
6603 { ES2 iso-ir-85 ISO646-ES2 csISO85Spanish2 }
6604 { MSZ_7795.3 iso-ir-86 ISO646-HU hu csISO86Hungarian }
6605 { JIS_C6226-1983 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208 }
6606 { greek7 iso-ir-88 csISO88Greek7 }
6607 { ASMO_449 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449 }
6608 { iso-ir-90 csISO90 }
6609 { JIS_C6229-1984-a iso-ir-91 jp-ocr-a csISO91JISC62291984a }
6610 { JIS_C6229-1984-b iso-ir-92 ISO646-JP-OCR-B jp-ocr-b
6611 csISO92JISC62991984b }
6612 { JIS_C6229-1984-b-add iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd }
6613 { JIS_C6229-1984-hand iso-ir-94 jp-ocr-hand csISO94JIS62291984hand }
6614 { JIS_C6229-1984-hand-add iso-ir-95 jp-ocr-hand-add
6615 csISO95JIS62291984handadd }
6616 { JIS_C6229-1984-kana iso-ir-96 csISO96JISC62291984kana }
6617 { ISO_2033-1983 iso-ir-98 e13b csISO2033 }
6618 { ANSI_X3.110-1983 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS }
6619 { ISO_8859-1:1987 iso-ir-100 ISO_8859-1 ISO-8859-1 latin1 l1 IBM819
6621 { ISO_8859-2:1987 iso-ir-101 ISO_8859-2 ISO-8859-2 latin2 l2 csISOLatin2 }
6622 { T.61-7bit iso-ir-102 csISO102T617bit }
6623 { T.61-8bit T.61 iso-ir-103 csISO103T618bit }
6624 { ISO_8859-3:1988 iso-ir-109 ISO_8859-3 ISO-8859-3 latin3 l3 csISOLatin3 }
6625 { ISO_8859-4:1988 iso-ir-110 ISO_8859-4 ISO-8859-4 latin4 l4 csISOLatin4 }
6626 { ECMA-cyrillic iso-ir-111 KOI8-E csISO111ECMACyrillic }
6627 { CSA_Z243.4-1985-1 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1 }
6628 { CSA_Z243.4-1985-2 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2 }
6629 { CSA_Z243.4-1985-gr iso-ir-123 csISO123CSAZ24341985gr }
6630 { ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ISO-8859-6 ECMA-114 ASMO-708
6631 arabic csISOLatinArabic }
6632 { ISO_8859-6-E csISO88596E ISO-8859-6-E }
6633 { ISO_8859-6-I csISO88596I ISO-8859-6-I }
6634 { ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ISO-8859-7 ELOT_928 ECMA-118
6635 greek greek8 csISOLatinGreek }
6636 { T.101-G2 iso-ir-128 csISO128T101G2 }
6637 { ISO_8859-8:1988 iso-ir-138 ISO_8859-8 ISO-8859-8 hebrew
6639 { ISO_8859-8-E csISO88598E ISO-8859-8-E }
6640 { ISO_8859-8-I csISO88598I ISO-8859-8-I }
6641 { CSN_369103 iso-ir-139 csISO139CSN369103 }
6642 { JUS_I.B1.002 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002 }
6643 { ISO_6937-2-add iso-ir-142 csISOTextComm }
6644 { IEC_P27-1 iso-ir-143 csISO143IECP271 }
6645 { ISO_8859-5:1988 iso-ir-144 ISO_8859-5 ISO-8859-5 cyrillic
6646 csISOLatinCyrillic }
6647 { JUS_I.B1.003-serb iso-ir-146 serbian csISO146Serbian }
6648 { JUS_I.B1.003-mac macedonian iso-ir-147 csISO147Macedonian }
6649 { ISO_8859-9:1989 iso-ir-148 ISO_8859-9 ISO-8859-9 latin5 l5 csISOLatin5 }
6650 { greek-ccitt iso-ir-150 csISO150 csISO150GreekCCITT }
6651 { NC_NC00-10:81 cuba iso-ir-151 ISO646-CU csISO151Cuba }
6652 { ISO_6937-2-25 iso-ir-152 csISO6937Add }
6653 { GOST_19768-74 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874 }
6654 { ISO_8859-supp iso-ir-154 latin1-2-5 csISO8859Supp }
6655 { ISO_10367-box iso-ir-155 csISO10367Box }
6656 { ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 }
6657 { latin-lap lap iso-ir-158 csISO158Lap }
6658 { JIS_X0212-1990 x0212 iso-ir-159 csISO159JISX02121990 }
6659 { DS_2089 DS2089 ISO646-DK dk csISO646Danish }
6662 { JIS_X0201 X0201 csHalfWidthKatakana }
6663 { KSC5636 ISO646-KR csKSC5636 }
6664 { ISO-10646-UCS-2 csUnicode }
6665 { ISO-10646-UCS-4 csUCS4 }
6666 { DEC-MCS dec csDECMCS }
6667 { hp-roman8 roman8 r8 csHPRoman8 }
6668 { macintosh mac csMacintosh }
6669 { IBM037 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl
6671 { IBM038 EBCDIC-INT cp038 csIBM038 }
6672 { IBM273 CP273 csIBM273 }
6673 { IBM274 EBCDIC-BE CP274 csIBM274 }
6674 { IBM275 EBCDIC-BR cp275 csIBM275 }
6675 { IBM277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 }
6676 { IBM278 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 }
6677 { IBM280 CP280 ebcdic-cp-it csIBM280 }
6678 { IBM281 EBCDIC-JP-E cp281 csIBM281 }
6679 { IBM284 CP284 ebcdic-cp-es csIBM284 }
6680 { IBM285 CP285 ebcdic-cp-gb csIBM285 }
6681 { IBM290 cp290 EBCDIC-JP-kana csIBM290 }
6682 { IBM297 cp297 ebcdic-cp-fr csIBM297 }
6683 { IBM420 cp420 ebcdic-cp-ar1 csIBM420 }
6684 { IBM423 cp423 ebcdic-cp-gr csIBM423 }
6685 { IBM424 cp424 ebcdic-cp-he csIBM424 }
6686 { IBM437 cp437 437 csPC8CodePage437 }
6687 { IBM500 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500 }
6688 { IBM775 cp775 csPC775Baltic }
6689 { IBM850 cp850 850 csPC850Multilingual }
6690 { IBM851 cp851 851 csIBM851 }
6691 { IBM852 cp852 852 csPCp852 }
6692 { IBM855 cp855 855 csIBM855 }
6693 { IBM857 cp857 857 csIBM857 }
6694 { IBM860 cp860 860 csIBM860 }
6695 { IBM861 cp861 861 cp-is csIBM861 }
6696 { IBM862 cp862 862 csPC862LatinHebrew }
6697 { IBM863 cp863 863 csIBM863 }
6698 { IBM864 cp864 csIBM864 }
6699 { IBM865 cp865 865 csIBM865 }
6700 { IBM866 cp866 866 csIBM866 }
6701 { IBM868 CP868 cp-ar csIBM868 }
6702 { IBM869 cp869 869 cp-gr csIBM869 }
6703 { IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 }
6704 { IBM871 CP871 ebcdic-cp-is csIBM871 }
6705 { IBM880 cp880 EBCDIC-Cyrillic csIBM880 }
6706 { IBM891 cp891 csIBM891 }
6707 { IBM903 cp903 csIBM903 }
6708 { IBM904 cp904 904 csIBBM904 }
6709 { IBM905 CP905 ebcdic-cp-tr csIBM905 }
6710 { IBM918 CP918 ebcdic-cp-ar2 csIBM918 }
6711 { IBM1026 CP1026 csIBM1026 }
6712 { EBCDIC-AT-DE csIBMEBCDICATDE }
6713 { EBCDIC-AT-DE-A csEBCDICATDEA }
6714 { EBCDIC-CA-FR csEBCDICCAFR }
6715 { EBCDIC-DK-NO csEBCDICDKNO }
6716 { EBCDIC-DK-NO-A csEBCDICDKNOA }
6717 { EBCDIC-FI-SE csEBCDICFISE }
6718 { EBCDIC-FI-SE-A csEBCDICFISEA }
6719 { EBCDIC-FR csEBCDICFR }
6720 { EBCDIC-IT csEBCDICIT }
6721 { EBCDIC-PT csEBCDICPT }
6722 { EBCDIC-ES csEBCDICES }
6723 { EBCDIC-ES-A csEBCDICESA }
6724 { EBCDIC-ES-S csEBCDICESS }
6725 { EBCDIC-UK csEBCDICUK }
6726 { EBCDIC-US csEBCDICUS }
6727 { UNKNOWN-8BIT csUnknown8BiT }
6728 { MNEMONIC csMnemonic }
6733 { IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro }
6734 { IBM00924 CCSID00924 CP00924 ebcdic-Latin9--euro }
6735 { IBM01140 CCSID01140 CP01140 ebcdic-us-37+euro }
6736 { IBM01141 CCSID01141 CP01141 ebcdic-de-273+euro }
6737 { IBM01142 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro }
6738 { IBM01143 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro }
6739 { IBM01144 CCSID01144 CP01144 ebcdic-it-280+euro }
6740 { IBM01145 CCSID01145 CP01145 ebcdic-es-284+euro }
6741 { IBM01146 CCSID01146 CP01146 ebcdic-gb-285+euro }
6742 { IBM01147 CCSID01147 CP01147 ebcdic-fr-297+euro }
6743 { IBM01148 CCSID01148 CP01148 ebcdic-international-500+euro }
6744 { IBM01149 CCSID01149 CP01149 ebcdic-is-871+euro }
6745 { IBM1047 IBM-1047 }
6746 { PTCP154 csPTCP154 PT154 CP154 Cyrillic-Asian }
6747 { Amiga-1251 Ami1251 Amiga1251 Ami-1251 }
6748 { UNICODE-1-1 csUnicode11 }
6751 { UNICODE-1-1-UTF-7 csUnicode11UTF7 }
6752 { ISO-8859-14 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic
6754 { ISO-8859-15 ISO_8859-15 Latin-9 }
6755 { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
6756 { GBK CP936 MS936 windows-936 }
6757 { JIS_Encoding csJISEncoding }
6758 { Shift_JIS MS_Kanji csShiftJIS }
6759 { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
6761 { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
6762 { ISO-10646-UCS-Basic csUnicodeASCII }
6763 { ISO-10646-Unicode-Latin1 csUnicodeLatin1 ISO-10646 }
6764 { ISO-Unicode-IBM-1261 csUnicodeIBM1261 }
6765 { ISO-Unicode-IBM-1268 csUnicodeIBM1268 }
6766 { ISO-Unicode-IBM-1276 csUnicodeIBM1276 }
6767 { ISO-Unicode-IBM-1264 csUnicodeIBM1264 }
6768 { ISO-Unicode-IBM-1265 csUnicodeIBM1265 }
6769 { ISO-8859-1-Windows-3.0-Latin-1 csWindows30Latin1 }
6770 { ISO-8859-1-Windows-3.1-Latin-1 csWindows31Latin1 }
6771 { ISO-8859-2-Windows-Latin-2 csWindows31Latin2 }
6772 { ISO-8859-9-Windows-Latin-5 csWindows31Latin5 }
6773 { Adobe-Standard-Encoding csAdobeStandardEncoding }
6774 { Ventura-US csVenturaUS }
6775 { Ventura-International csVenturaInternational }
6776 { PC8-Danish-Norwegian csPC8DanishNorwegian }
6777 { PC8-Turkish csPC8Turkish }
6778 { IBM-Symbols csIBMSymbols }
6779 { IBM-Thai csIBMThai }
6780 { HP-Legal csHPLegal }
6781 { HP-Pi-font csHPPiFont }
6782 { HP-Math8 csHPMath8 }
6783 { Adobe-Symbol-Encoding csHPPSMath }
6784 { HP-DeskTop csHPDesktop }
6785 { Ventura-Math csVenturaMath }
6786 { Microsoft-Publishing csMicrosoftPublishing }
6787 { Windows-31J csWindows31J }
6792 proc tcl_encoding {enc} {
6793 global encoding_aliases
6794 set names [encoding names]
6795 set lcnames [string tolower $names]
6796 set enc [string tolower $enc]
6797 set i [lsearch -exact $lcnames $enc]
6799 # look for "isonnn" instead of "iso-nnn" or "iso_nnn"
6800 if {[regsub {^iso[-_]} $enc iso encx]} {
6801 set i [lsearch -exact $lcnames $encx]
6805 foreach l $encoding_aliases {
6806 set ll [string tolower $l]
6807 if {[lsearch -exact $ll $enc] < 0} continue
6808 # look through the aliases for one that tcl knows about
6810 set i [lsearch -exact $lcnames $e]
6812 if {[regsub {^iso[-_]} $e iso ex]} {
6813 set i [lsearch -exact $lcnames $ex]
6822 return [lindex $names $i]
6829 set diffopts "-U 5 -p"
6830 set wrcomcmd "git diff-tree --stdin -p --pretty"
6834 set gitencoding [exec git config --get i18n.commitencoding]
6836 if {$gitencoding == ""} {
6837 set gitencoding "utf-8"
6839 set tclencoding [tcl_encoding $gitencoding]
6840 if {$tclencoding == {}} {
6841 puts stderr "Warning: encoding $gitencoding is not supported by Tcl/Tk"
6844 set mainfont {Helvetica 9}
6845 set textfont {Courier 9}
6846 set uifont {Helvetica 9 bold}
6848 set findmergefiles 0
6856 set cmitmode "patch"
6857 set wrapcomment "none"
6860 set colors {green red blue magenta darkgrey brown orange}
6863 set diffcolors {red "#00a000" blue}
6864 set selectbgcolor gray85
6866 catch {source ~/.gitk}
6868 font create optionfont -family sans-serif -size -12
6872 switch -regexp -- $arg {
6874 "^-d" { set datemode 1 }
6876 lappend revtreeargs $arg
6881 # check that we can find a .git directory somewhere...
6883 if {![file isdirectory $gitdir]} {
6884 show_error {} . "Cannot find the git directory \"$gitdir\"."
6888 set cmdline_files {}
6889 set i [lsearch -exact $revtreeargs "--"]
6891 set cmdline_files [lrange $revtreeargs [expr {$i + 1}] end]
6892 set revtreeargs [lrange $revtreeargs 0 [expr {$i - 1}]]
6893 } elseif {$revtreeargs ne {}} {
6895 set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
6896 set cmdline_files [split $f "\n"]
6897 set n [llength $cmdline_files]
6898 set revtreeargs [lrange $revtreeargs 0 end-$n]
6900 # unfortunately we get both stdout and stderr in $err,
6901 # so look for "fatal:".
6902 set i [string first "fatal:" $err]
6904 set err [string range $err [expr {$i + 6}] end]
6906 show_error {} . "Bad arguments to gitk:\n$err"
6915 set highlight_paths {}
6916 set searchdirn -forwards
6926 set selectedhlview None
6937 wm title . "[file tail $argv0]: [file tail [pwd]]"
6940 if {$cmdline_files ne {} || $revtreeargs ne {}} {
6941 # create a view for the files/dirs specified on the command line
6945 set viewname(1) "Command line"
6946 set viewfiles(1) $cmdline_files
6947 set viewargs(1) $revtreeargs
6950 .bar.view entryconf Edit* -state normal
6951 .bar.view entryconf Delete* -state normal
6954 if {[info exists permviews]} {
6955 foreach v $permviews {
6958 set viewname($n) [lindex $v 0]
6959 set viewfiles($n) [lindex $v 1]
6960 set viewargs($n) [lindex $v 2]