hgk
1448 lines
| 39.1 KiB
| text/plain
|
TextLexer
/ contrib / hgk
mpm@selenic.com
|
r267 | #!/bin/sh | ||
# Tcl ignores the next line -*- tcl -*- \ | ||||
exec wish "$0" -- "${1+$@}" | ||||
# Copyright (C) 2005 Paul Mackerras. All rights reserved. | ||||
# This program is free software; it may be used, copied, modified | ||||
# and distributed under the terms of the GNU General Public Licence, | ||||
# either version 2, or (at your option) any later version. | ||||
# CVS $Revision: 1.20 $ | ||||
proc readfullcommits {rargs} { | ||||
global commits commfd phase canv mainfont curcommit allcommitstate | ||||
if {$rargs == {}} { | ||||
set rargs HEAD | ||||
} | ||||
set commits {} | ||||
set curcommit {} | ||||
set allcommitstate none | ||||
set phase getcommits | ||||
if [catch {set commfd [open "|hgit rev-list -c $rargs" r]} err] { | ||||
puts stderr "Error executing hgit rev-list: $err" | ||||
exit 1 | ||||
} | ||||
fconfigure $commfd -blocking 0 | ||||
fileevent $commfd readable "getallcommitline $commfd" | ||||
$canv delete all | ||||
$canv create text 3 3 -anchor nw -text "Reading all commits..." \ | ||||
-font $mainfont -tags textitems | ||||
} | ||||
proc getcommitline {commfd} { | ||||
global commits parents cdate nparents children nchildren | ||||
set n [gets $commfd line] | ||||
if {$n < 0} { | ||||
if {![eof $commfd]} return | ||||
# this works around what is apparently a bug in Tcl... | ||||
fconfigure $commfd -blocking 1 | ||||
if {![catch {close $commfd} err]} { | ||||
after idle readallcommits | ||||
return | ||||
} | ||||
if {[string range $err 0 4] == "usage"} { | ||||
set err "\ | ||||
Gitk: error reading commits: bad arguments to hgit rev-list.\n\ | ||||
(Note: arguments to gitk are passed to hgit rev-list\ | ||||
to allow selection of commits to be displayed.)" | ||||
} else { | ||||
set err "Error reading commits: $err" | ||||
} | ||||
error_popup $err | ||||
exit 1 | ||||
} | ||||
if {![regexp {^[0-9a-f]{40}$} $line]} { | ||||
error_popup "Can't parse hgit rev-tree output: {$line}" | ||||
exit 1 | ||||
} | ||||
lappend commits $line | ||||
} | ||||
proc readallcommits {} { | ||||
global commits | ||||
foreach id $commits { | ||||
readcommit $id | ||||
update | ||||
} | ||||
drawgraph | ||||
} | ||||
proc readonecommit {id contents} { | ||||
global commitinfo children nchildren parents nparents cdate | ||||
set inhdr 1 | ||||
set comment {} | ||||
set headline {} | ||||
set auname {} | ||||
set audate {} | ||||
set comname {} | ||||
set comdate {} | ||||
if {![info exists nchildren($id)]} { | ||||
set children($id) {} | ||||
set nchildren($id) 0 | ||||
} | ||||
set parents($id) {} | ||||
set nparents($id) 0 | ||||
foreach line [split $contents "\n"] { | ||||
if {$inhdr} { | ||||
if {$line == {}} { | ||||
set inhdr 0 | ||||
} else { | ||||
set tag [lindex $line 0] | ||||
if {$tag == "parent"} { | ||||
set p [lindex $line 1] | ||||
if {![info exists nchildren($p)]} { | ||||
set children($p) {} | ||||
set nchildren($p) 0 | ||||
} | ||||
lappend parents($id) $p | ||||
incr nparents($id) | ||||
if {[lsearch -exact $children($p) $id] < 0} { | ||||
lappend children($p) $id | ||||
incr nchildren($p) | ||||
} | ||||
} elseif {$tag == "author"} { | ||||
set x [expr {[llength $line] - 2}] | ||||
set audate [lindex $line $x] | ||||
set auname [lrange $line 1 [expr {$x - 1}]] | ||||
} elseif {$tag == "committer"} { | ||||
set x [expr {[llength $line] - 2}] | ||||
set comdate [lindex $line $x] | ||||
set comname [lrange $line 1 [expr {$x - 1}]] | ||||
} | ||||
} | ||||
} else { | ||||
if {$comment == {}} { | ||||
set headline $line | ||||
} else { | ||||
append comment "\n" | ||||
} | ||||
append comment $line | ||||
} | ||||
} | ||||
if {$audate != {}} { | ||||
set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"] | ||||
} | ||||
if {$comdate != {}} { | ||||
set cdate($id) $comdate | ||||
set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] | ||||
} | ||||
set commitinfo($id) [list $headline $auname $audate \ | ||||
$comname $comdate $comment] | ||||
} | ||||
proc getallcommitline {commfd} { | ||||
global commits allcommitstate curcommit curcommitid | ||||
set n [gets $commfd line] | ||||
set s "\n" | ||||
if {$n < 0} { | ||||
if {![eof $commfd]} return | ||||
# this works around what is apparently a bug in Tcl... | ||||
fconfigure $commfd -blocking 1 | ||||
if {![catch {close $commfd} err]} { | ||||
mpm@selenic.com
|
r283 | if {$allcommitstate == "indent"} { | ||
readonecommit $curcommitid $curcommit | ||||
} | ||||
mpm@selenic.com
|
r267 | after idle drawgraph | ||
return | ||||
} | ||||
if {[string range $err 0 4] == "usage"} { | ||||
set err "\ | ||||
Gitk: error reading commits: bad arguments to hgit rev-list.\n\ | ||||
(Note: arguments to gitk are passed to hgit rev-list\ | ||||
to allow selection of commits to be displayed.)" | ||||
} else { | ||||
set err "Error reading commits: $err" | ||||
} | ||||
error_popup $err | ||||
exit 1 | ||||
} | ||||
if {[string range $line 0 1] != " "} { | ||||
if {$allcommitstate == "indent"} { | ||||
readonecommit $curcommitid $curcommit | ||||
} | ||||
if {$allcommitstate == "start"} { | ||||
set curcommit $curcommit$line$s | ||||
set allcommitstate "indent" | ||||
} else { | ||||
set curcommitid $line | ||||
set curcommit {} | ||||
set allcommitstate "start" | ||||
lappend commits $line | ||||
} | ||||
} else { | ||||
set d [string range $line 2 end] | ||||
set curcommit $curcommit$d$s | ||||
} | ||||
} | ||||
proc getcommits {rargs} { | ||||
global commits commfd phase canv mainfont | ||||
if {$rargs == {}} { | ||||
set rargs HEAD | ||||
} | ||||
set commits {} | ||||
set phase getcommits | ||||
if [catch {set commfd [open "|hgit rev-list $rargs" r]} err] { | ||||
puts stderr "Error executing hgit rev-list: $err" | ||||
exit 1 | ||||
} | ||||
fconfigure $commfd -blocking 0 | ||||
fileevent $commfd readable "getcommitline $commfd" | ||||
$canv delete all | ||||
$canv create text 3 3 -anchor nw -text "Reading commits..." \ | ||||
-font $mainfont -tags textitems | ||||
} | ||||
proc readcommit {id} { | ||||
global commitinfo children nchildren parents nparents cdate | ||||
set inhdr 1 | ||||
set comment {} | ||||
set headline {} | ||||
set auname {} | ||||
set audate {} | ||||
set comname {} | ||||
set comdate {} | ||||
if {![info exists nchildren($id)]} { | ||||
set children($id) {} | ||||
set nchildren($id) 0 | ||||
} | ||||
set parents($id) {} | ||||
set nparents($id) 0 | ||||
if [catch {set contents [exec hgit cat-file commit $id]}] return | ||||
readonecommit $id $contents | ||||
} | ||||
proc readrefs {} { | ||||
global tagids idtags | ||||
set tags [glob -nocomplain -types f .git/refs/tags/*] | ||||
foreach f $tags { | ||||
catch { | ||||
set fd [open $f r] | ||||
set line [read $fd] | ||||
if {[regexp {^[0-9a-f]{40}} $line id]} { | ||||
set contents [split [exec hgit cat-file tag $id] "\n"] | ||||
set obj {} | ||||
set type {} | ||||
set tag {} | ||||
foreach l $contents { | ||||
if {$l == {}} break | ||||
switch -- [lindex $l 0] { | ||||
"object" {set obj [lindex $l 1]} | ||||
"type" {set type [lindex $l 1]} | ||||
"tag" {set tag [string range $l 4 end]} | ||||
} | ||||
} | ||||
if {$obj != {} && $type == "commit" && $tag != {}} { | ||||
set tagids($tag) $obj | ||||
lappend idtags($obj) $tag | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
proc error_popup msg { | ||||
set w .error | ||||
toplevel $w | ||||
wm transient $w . | ||||
message $w.m -text $msg -justify center -aspect 400 | ||||
pack $w.m -side top -fill x -padx 20 -pady 20 | ||||
button $w.ok -text OK -command "destroy $w" | ||||
pack $w.ok -side bottom -fill x | ||||
bind $w <Visibility> "grab $w; focus $w" | ||||
tkwait window $w | ||||
} | ||||
proc makewindow {} { | ||||
global canv canv2 canv3 linespc charspc ctext cflist textfont | ||||
global findtype findloc findstring fstring geometry | ||||
global entries sha1entry sha1string sha1but | ||||
menu .bar | ||||
.bar add cascade -label "File" -menu .bar.file | ||||
menu .bar.file | ||||
.bar.file add command -label "Quit" -command doquit | ||||
menu .bar.help | ||||
.bar add cascade -label "Help" -menu .bar.help | ||||
.bar.help add command -label "About gitk" -command about | ||||
. configure -menu .bar | ||||
if {![info exists geometry(canv1)]} { | ||||
set geometry(canv1) [expr 45 * $charspc] | ||||
set geometry(canv2) [expr 30 * $charspc] | ||||
set geometry(canv3) [expr 15 * $charspc] | ||||
set geometry(canvh) [expr 25 * $linespc + 4] | ||||
set geometry(ctextw) 80 | ||||
set geometry(ctexth) 30 | ||||
set geometry(cflistw) 30 | ||||
} | ||||
panedwindow .ctop -orient vertical | ||||
if {[info exists geometry(width)]} { | ||||
.ctop conf -width $geometry(width) -height $geometry(height) | ||||
set texth [expr {$geometry(height) - $geometry(canvh) - 56}] | ||||
set geometry(ctexth) [expr {($texth - 8) / | ||||
[font metrics $textfont -linespace]}] | ||||
} | ||||
frame .ctop.top | ||||
frame .ctop.top.bar | ||||
pack .ctop.top.bar -side bottom -fill x | ||||
set cscroll .ctop.top.csb | ||||
scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 | ||||
pack $cscroll -side right -fill y | ||||
panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4 | ||||
pack .ctop.top.clist -side top -fill both -expand 1 | ||||
.ctop add .ctop.top | ||||
set canv .ctop.top.clist.canv | ||||
canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ | ||||
-bg white -bd 0 \ | ||||
-yscrollincr $linespc -yscrollcommand "$cscroll set" | ||||
.ctop.top.clist add $canv | ||||
set canv2 .ctop.top.clist.canv2 | ||||
canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ | ||||
-bg white -bd 0 -yscrollincr $linespc | ||||
.ctop.top.clist add $canv2 | ||||
set canv3 .ctop.top.clist.canv3 | ||||
canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \ | ||||
-bg white -bd 0 -yscrollincr $linespc | ||||
.ctop.top.clist add $canv3 | ||||
bind .ctop.top.clist <Configure> {resizeclistpanes %W %w} | ||||
set sha1entry .ctop.top.bar.sha1 | ||||
set entries $sha1entry | ||||
set sha1but .ctop.top.bar.sha1label | ||||
button $sha1but -text "SHA1 ID: " -state disabled -relief flat \ | ||||
-command gotocommit -width 8 | ||||
$sha1but conf -disabledforeground [$sha1but cget -foreground] | ||||
pack .ctop.top.bar.sha1label -side left | ||||
entry $sha1entry -width 40 -font $textfont -textvariable sha1string | ||||
trace add variable sha1string write sha1change | ||||
pack $sha1entry -side left -pady 2 | ||||
button .ctop.top.bar.findbut -text "Find" -command dofind | ||||
pack .ctop.top.bar.findbut -side left | ||||
set findstring {} | ||||
set fstring .ctop.top.bar.findstring | ||||
lappend entries $fstring | ||||
entry $fstring -width 30 -font $textfont -textvariable findstring | ||||
pack $fstring -side left -expand 1 -fill x | ||||
set findtype Exact | ||||
tk_optionMenu .ctop.top.bar.findtype findtype Exact IgnCase Regexp | ||||
set findloc "All fields" | ||||
tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \ | ||||
Comments Author Committer | ||||
pack .ctop.top.bar.findloc -side right | ||||
pack .ctop.top.bar.findtype -side right | ||||
panedwindow .ctop.cdet -orient horizontal | ||||
.ctop add .ctop.cdet | ||||
frame .ctop.cdet.left | ||||
set ctext .ctop.cdet.left.ctext | ||||
text $ctext -bg white -state disabled -font $textfont \ | ||||
-width $geometry(ctextw) -height $geometry(ctexth) \ | ||||
-yscrollcommand ".ctop.cdet.left.sb set" | ||||
scrollbar .ctop.cdet.left.sb -command "$ctext yview" | ||||
pack .ctop.cdet.left.sb -side right -fill y | ||||
pack $ctext -side left -fill both -expand 1 | ||||
.ctop.cdet add .ctop.cdet.left | ||||
$ctext tag conf filesep -font [concat $textfont bold] | ||||
$ctext tag conf hunksep -back blue -fore white | ||||
$ctext tag conf d0 -back "#ff8080" | ||||
$ctext tag conf d1 -back green | ||||
$ctext tag conf found -back yellow | ||||
frame .ctop.cdet.right | ||||
set cflist .ctop.cdet.right.cfiles | ||||
listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \ | ||||
-yscrollcommand ".ctop.cdet.right.sb set" | ||||
scrollbar .ctop.cdet.right.sb -command "$cflist yview" | ||||
pack .ctop.cdet.right.sb -side right -fill y | ||||
pack $cflist -side left -fill both -expand 1 | ||||
.ctop.cdet add .ctop.cdet.right | ||||
bind .ctop.cdet <Configure> {resizecdetpanes %W %w} | ||||
pack .ctop -side top -fill both -expand 1 | ||||
bindall <1> {selcanvline %x %y} | ||||
bindall <B1-Motion> {selcanvline %x %y} | ||||
bindall <ButtonRelease-4> "allcanvs yview scroll -5 units" | ||||
bindall <ButtonRelease-5> "allcanvs yview scroll 5 units" | ||||
bindall <2> "allcanvs scan mark 0 %y" | ||||
bindall <B2-Motion> "allcanvs scan dragto 0 %y" | ||||
bind . <Key-Up> "selnextline -1" | ||||
bind . <Key-Down> "selnextline 1" | ||||
bind . <Key-Prior> "allcanvs yview scroll -1 pages" | ||||
bind . <Key-Next> "allcanvs yview scroll 1 pages" | ||||
bindkey <Key-Delete> "$ctext yview scroll -1 pages" | ||||
bindkey <Key-BackSpace> "$ctext yview scroll -1 pages" | ||||
bindkey <Key-space> "$ctext yview scroll 1 pages" | ||||
bindkey p "selnextline -1" | ||||
bindkey n "selnextline 1" | ||||
bindkey b "$ctext yview scroll -1 pages" | ||||
bindkey d "$ctext yview scroll 18 units" | ||||
bindkey u "$ctext yview scroll -18 units" | ||||
bindkey / findnext | ||||
bindkey ? findprev | ||||
bindkey f nextfile | ||||
bind . <Control-q> doquit | ||||
bind . <Control-f> dofind | ||||
bind . <Control-g> findnext | ||||
bind . <Control-r> findprev | ||||
bind . <Control-equal> {incrfont 1} | ||||
bind . <Control-KP_Add> {incrfont 1} | ||||
bind . <Control-minus> {incrfont -1} | ||||
bind . <Control-KP_Subtract> {incrfont -1} | ||||
bind $cflist <<ListboxSelect>> listboxsel | ||||
bind . <Destroy> {savestuff %W} | ||||
bind . <Button-1> "click %W" | ||||
bind $fstring <Key-Return> dofind | ||||
bind $sha1entry <Key-Return> gotocommit | ||||
} | ||||
# when we make a key binding for the toplevel, make sure | ||||
# it doesn't get triggered when that key is pressed in the | ||||
# find string entry widget. | ||||
proc bindkey {ev script} { | ||||
global entries | ||||
bind . $ev $script | ||||
set escript [bind Entry $ev] | ||||
if {$escript == {}} { | ||||
set escript [bind Entry <Key>] | ||||
} | ||||
foreach e $entries { | ||||
bind $e $ev "$escript; break" | ||||
} | ||||
} | ||||
# set the focus back to the toplevel for any click outside | ||||
# the entry widgets | ||||
proc click {w} { | ||||
global entries | ||||
foreach e $entries { | ||||
if {$w == $e} return | ||||
} | ||||
focus . | ||||
} | ||||
proc savestuff {w} { | ||||
global canv canv2 canv3 ctext cflist mainfont textfont | ||||
global stuffsaved | ||||
if {$stuffsaved} return | ||||
if {![winfo viewable .]} return | ||||
catch { | ||||
set f [open "~/.gitk-new" w] | ||||
puts $f "set mainfont {$mainfont}" | ||||
puts $f "set textfont {$textfont}" | ||||
puts $f "set geometry(width) [winfo width .ctop]" | ||||
puts $f "set geometry(height) [winfo height .ctop]" | ||||
puts $f "set geometry(canv1) [expr [winfo width $canv]-2]" | ||||
puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]" | ||||
puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]" | ||||
puts $f "set geometry(canvh) [expr [winfo height $canv]-2]" | ||||
set wid [expr {([winfo width $ctext] - 8) \ | ||||
/ [font measure $textfont "0"]}] | ||||
puts $f "set geometry(ctextw) $wid" | ||||
set wid [expr {([winfo width $cflist] - 11) \ | ||||
/ [font measure [$cflist cget -font] "0"]}] | ||||
puts $f "set geometry(cflistw) $wid" | ||||
close $f | ||||
file rename -force "~/.gitk-new" "~/.gitk" | ||||
} | ||||
set stuffsaved 1 | ||||
} | ||||
proc resizeclistpanes {win w} { | ||||
global oldwidth | ||||
if [info exists oldwidth($win)] { | ||||
set s0 [$win sash coord 0] | ||||
set s1 [$win sash coord 1] | ||||
if {$w < 60} { | ||||
set sash0 [expr {int($w/2 - 2)}] | ||||
set sash1 [expr {int($w*5/6 - 2)}] | ||||
} else { | ||||
set factor [expr {1.0 * $w / $oldwidth($win)}] | ||||
set sash0 [expr {int($factor * [lindex $s0 0])}] | ||||
set sash1 [expr {int($factor * [lindex $s1 0])}] | ||||
if {$sash0 < 30} { | ||||
set sash0 30 | ||||
} | ||||
if {$sash1 < $sash0 + 20} { | ||||
set sash1 [expr $sash0 + 20] | ||||
} | ||||
if {$sash1 > $w - 10} { | ||||
set sash1 [expr $w - 10] | ||||
if {$sash0 > $sash1 - 20} { | ||||
set sash0 [expr $sash1 - 20] | ||||
} | ||||
} | ||||
} | ||||
$win sash place 0 $sash0 [lindex $s0 1] | ||||
$win sash place 1 $sash1 [lindex $s1 1] | ||||
} | ||||
set oldwidth($win) $w | ||||
} | ||||
proc resizecdetpanes {win w} { | ||||
global oldwidth | ||||
if [info exists oldwidth($win)] { | ||||
set s0 [$win sash coord 0] | ||||
if {$w < 60} { | ||||
set sash0 [expr {int($w*3/4 - 2)}] | ||||
} else { | ||||
set factor [expr {1.0 * $w / $oldwidth($win)}] | ||||
set sash0 [expr {int($factor * [lindex $s0 0])}] | ||||
if {$sash0 < 45} { | ||||
set sash0 45 | ||||
} | ||||
if {$sash0 > $w - 15} { | ||||
set sash0 [expr $w - 15] | ||||
} | ||||
} | ||||
$win sash place 0 $sash0 [lindex $s0 1] | ||||
} | ||||
set oldwidth($win) $w | ||||
} | ||||
proc allcanvs args { | ||||
global canv canv2 canv3 | ||||
eval $canv $args | ||||
eval $canv2 $args | ||||
eval $canv3 $args | ||||
} | ||||
proc bindall {event action} { | ||||
global canv canv2 canv3 | ||||
bind $canv $event $action | ||||
bind $canv2 $event $action | ||||
bind $canv3 $event $action | ||||
} | ||||
proc about {} { | ||||
set w .about | ||||
if {[winfo exists $w]} { | ||||
raise $w | ||||
return | ||||
} | ||||
toplevel $w | ||||
wm title $w "About gitk" | ||||
message $w.m -text { | ||||
Gitk version 1.1 | ||||
Copyright � 2005 Paul Mackerras | ||||
Use and redistribute under the terms of the GNU General Public License | ||||
(CVS $Revision: 1.20 $)} \ | ||||
-justify center -aspect 400 | ||||
pack $w.m -side top -fill x -padx 20 -pady 20 | ||||
button $w.ok -text Close -command "destroy $w" | ||||
pack $w.ok -side bottom | ||||
} | ||||
proc truncatetofit {str width font} { | ||||
if {[font measure $font $str] <= $width} { | ||||
return $str | ||||
} | ||||
set best 0 | ||||
set bad [string length $str] | ||||
set tmp $str | ||||
while {$best < $bad - 1} { | ||||
set try [expr {int(($best + $bad) / 2)}] | ||||
set tmp "[string range $str 0 [expr $try-1]]..." | ||||
if {[font measure $font $tmp] <= $width} { | ||||
set best $try | ||||
} else { | ||||
set bad $try | ||||
} | ||||
} | ||||
return $tmp | ||||
} | ||||
proc assigncolor {id} { | ||||
global commitinfo colormap commcolors colors nextcolor | ||||
global colorbycommitter | ||||
global parents nparents children nchildren | ||||
if [info exists colormap($id)] return | ||||
set ncolors [llength $colors] | ||||
if {$colorbycommitter} { | ||||
if {![info exists commitinfo($id)]} { | ||||
readcommit $id | ||||
} | ||||
set comm [lindex $commitinfo($id) 3] | ||||
if {![info exists commcolors($comm)]} { | ||||
set commcolors($comm) [lindex $colors $nextcolor] | ||||
if {[incr nextcolor] >= $ncolors} { | ||||
set nextcolor 0 | ||||
} | ||||
} | ||||
set colormap($id) $commcolors($comm) | ||||
} else { | ||||
if {$nparents($id) == 1 && $nchildren($id) == 1} { | ||||
set child [lindex $children($id) 0] | ||||
if {[info exists colormap($child)] | ||||
&& $nparents($child) == 1} { | ||||
set colormap($id) $colormap($child) | ||||
return | ||||
} | ||||
} | ||||
set badcolors {} | ||||
foreach child $children($id) { | ||||
if {[info exists colormap($child)] | ||||
&& [lsearch -exact $badcolors $colormap($child)] < 0} { | ||||
lappend badcolors $colormap($child) | ||||
} | ||||
if {[info exists parents($child)]} { | ||||
foreach p $parents($child) { | ||||
if {[info exists colormap($p)] | ||||
&& [lsearch -exact $badcolors $colormap($p)] < 0} { | ||||
lappend badcolors $colormap($p) | ||||
} | ||||
} | ||||
} | ||||
} | ||||
if {[llength $badcolors] >= $ncolors} { | ||||
set badcolors {} | ||||
} | ||||
for {set i 0} {$i <= $ncolors} {incr i} { | ||||
set c [lindex $colors $nextcolor] | ||||
if {[incr nextcolor] >= $ncolors} { | ||||
set nextcolor 0 | ||||
} | ||||
if {[lsearch -exact $badcolors $c]} break | ||||
} | ||||
set colormap($id) $c | ||||
} | ||||
} | ||||
proc drawgraph {} { | ||||
global parents children nparents nchildren commits | ||||
global canv canv2 canv3 mainfont namefont canvx0 canvy0 canvy linespc | ||||
global datemode cdate | ||||
global lineid linehtag linentag linedtag commitinfo | ||||
global nextcolor colormap numcommits | ||||
global stopped phase redisplaying selectedline idtags idline | ||||
allcanvs delete all | ||||
set start {} | ||||
foreach id [array names nchildren] { | ||||
if {$nchildren($id) == 0} { | ||||
lappend start $id | ||||
} | ||||
set ncleft($id) $nchildren($id) | ||||
if {![info exists nparents($id)]} { | ||||
set nparents($id) 0 | ||||
} | ||||
} | ||||
if {$start == {}} { | ||||
error_popup "Gitk: ERROR: No starting commits found" | ||||
exit 1 | ||||
} | ||||
set nextcolor 0 | ||||
foreach id $start { | ||||
assigncolor $id | ||||
} | ||||
set todo $start | ||||
set level [expr [llength $todo] - 1] | ||||
set y2 $canvy0 | ||||
set nullentry -1 | ||||
set lineno -1 | ||||
set numcommits 0 | ||||
set phase drawgraph | ||||
set lthickness [expr {($linespc / 9) + 1}] | ||||
while 1 { | ||||
set canvy $y2 | ||||
allcanvs conf -scrollregion \ | ||||
[list 0 0 0 [expr $canvy + 0.5 * $linespc + 2]] | ||||
update | ||||
if {$stopped} break | ||||
incr numcommits | ||||
incr lineno | ||||
set nlines [llength $todo] | ||||
set id [lindex $todo $level] | ||||
set lineid($lineno) $id | ||||
set idline($id) $lineno | ||||
set actualparents {} | ||||
set ofill white | ||||
if {[info exists parents($id)]} { | ||||
foreach p $parents($id) { | ||||
if {[info exists ncleft($p)]} { | ||||
incr ncleft($p) -1 | ||||
if {![info exists commitinfo($p)]} { | ||||
readcommit $p | ||||
if {![info exists commitinfo($p)]} continue | ||||
} | ||||
lappend actualparents $p | ||||
set ofill blue | ||||
} | ||||
} | ||||
} | ||||
if {![info exists commitinfo($id)]} { | ||||
readcommit $id | ||||
if {![info exists commitinfo($id)]} { | ||||
set commitinfo($id) {"No commit information available"} | ||||
} | ||||
} | ||||
set x [expr $canvx0 + $level * $linespc] | ||||
set y2 [expr $canvy + $linespc] | ||||
if {[info exists linestarty($level)] && $linestarty($level) < $canvy} { | ||||
set t [$canv create line $x $linestarty($level) $x $canvy \ | ||||
-width $lthickness -fill $colormap($id)] | ||||
$canv lower $t | ||||
} | ||||
set linestarty($level) $canvy | ||||
set orad [expr {$linespc / 3}] | ||||
set t [$canv create oval [expr $x - $orad] [expr $canvy - $orad] \ | ||||
[expr $x + $orad - 1] [expr $canvy + $orad - 1] \ | ||||
-fill $ofill -outline black -width 1] | ||||
$canv raise $t | ||||
set xt [expr $canvx0 + $nlines * $linespc] | ||||
if {$nparents($id) > 2} { | ||||
set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] | ||||
} | ||||
if {[info exists idtags($id)] && $idtags($id) != {}} { | ||||
set delta [expr {int(0.5 * ($linespc - $lthickness))}] | ||||
set yt [expr $canvy - 0.5 * $linespc] | ||||
set yb [expr $yt + $linespc - 1] | ||||
set xvals {} | ||||
set wvals {} | ||||
foreach tag $idtags($id) { | ||||
set wid [font measure $mainfont $tag] | ||||
lappend xvals $xt | ||||
lappend wvals $wid | ||||
set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}] | ||||
} | ||||
set t [$canv create line $x $canvy [lindex $xvals end] $canvy \ | ||||
-width $lthickness -fill black] | ||||
$canv lower $t | ||||
foreach tag $idtags($id) x $xvals wid $wvals { | ||||
set xl [expr $x + $delta] | ||||
set xr [expr $x + $delta + $wid + $lthickness] | ||||
$canv create polygon $x [expr $yt + $delta] $xl $yt\ | ||||
$xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ | ||||
-width 1 -outline black -fill yellow | ||||
$canv create text $xl $canvy -anchor w -text $tag \ | ||||
-font $mainfont | ||||
} | ||||
} | ||||
set headline [lindex $commitinfo($id) 0] | ||||
set name [lindex $commitinfo($id) 1] | ||||
set date [lindex $commitinfo($id) 2] | ||||
set linehtag($lineno) [$canv create text $xt $canvy -anchor w \ | ||||
-text $headline -font $mainfont ] | ||||
set linentag($lineno) [$canv2 create text 3 $canvy -anchor w \ | ||||
-text $name -font $namefont] | ||||
set linedtag($lineno) [$canv3 create text 3 $canvy -anchor w \ | ||||
-text $date -font $mainfont] | ||||
if {!$datemode && [llength $actualparents] == 1} { | ||||
set p [lindex $actualparents 0] | ||||
if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { | ||||
assigncolor $p | ||||
set todo [lreplace $todo $level $level $p] | ||||
continue | ||||
} | ||||
} | ||||
set oldtodo $todo | ||||
set oldlevel $level | ||||
set lines {} | ||||
for {set i 0} {$i < $nlines} {incr i} { | ||||
if {[lindex $todo $i] == {}} continue | ||||
if {[info exists linestarty($i)]} { | ||||
set oldstarty($i) $linestarty($i) | ||||
unset linestarty($i) | ||||
} | ||||
if {$i != $level} { | ||||
lappend lines [list $i [lindex $todo $i]] | ||||
} | ||||
} | ||||
if {$nullentry >= 0} { | ||||
set todo [lreplace $todo $nullentry $nullentry] | ||||
if {$nullentry < $level} { | ||||
incr level -1 | ||||
} | ||||
} | ||||
set todo [lreplace $todo $level $level] | ||||
if {$nullentry > $level} { | ||||
incr nullentry -1 | ||||
} | ||||
set i $level | ||||
foreach p $actualparents { | ||||
set k [lsearch -exact $todo $p] | ||||
if {$k < 0} { | ||||
assigncolor $p | ||||
set todo [linsert $todo $i $p] | ||||
if {$nullentry >= $i} { | ||||
incr nullentry | ||||
} | ||||
incr i | ||||
} | ||||
lappend lines [list $oldlevel $p] | ||||
} | ||||
# choose which one to do next time around | ||||
set todol [llength $todo] | ||||
set level -1 | ||||
set latest {} | ||||
for {set k $todol} {[incr k -1] >= 0} {} { | ||||
set p [lindex $todo $k] | ||||
if {$p == {}} continue | ||||
if {$ncleft($p) == 0} { | ||||
if {$datemode} { | ||||
if {$latest == {} || $cdate($p) > $latest} { | ||||
set level $k | ||||
set latest $cdate($p) | ||||
} | ||||
} else { | ||||
set level $k | ||||
break | ||||
} | ||||
} | ||||
} | ||||
if {$level < 0} { | ||||
if {$todo != {}} { | ||||
puts "ERROR: none of the pending commits can be done yet:" | ||||
foreach p $todo { | ||||
puts " $p" | ||||
} | ||||
} | ||||
break | ||||
} | ||||
# If we are reducing, put in a null entry | ||||
if {$todol < $nlines} { | ||||
if {$nullentry >= 0} { | ||||
set i $nullentry | ||||
while {$i < $todol | ||||
&& [lindex $oldtodo $i] == [lindex $todo $i]} { | ||||
incr i | ||||
} | ||||
} else { | ||||
set i $oldlevel | ||||
if {$level >= $i} { | ||||
incr i | ||||
} | ||||
} | ||||
if {$i >= $todol} { | ||||
set nullentry -1 | ||||
} else { | ||||
set nullentry $i | ||||
set todo [linsert $todo $nullentry {}] | ||||
if {$level >= $i} { | ||||
incr level | ||||
} | ||||
} | ||||
} else { | ||||
set nullentry -1 | ||||
} | ||||
foreach l $lines { | ||||
set i [lindex $l 0] | ||||
set dst [lindex $l 1] | ||||
set j [lsearch -exact $todo $dst] | ||||
if {$i == $j} { | ||||
if {[info exists oldstarty($i)]} { | ||||
set linestarty($i) $oldstarty($i) | ||||
} | ||||
continue | ||||
} | ||||
set xi [expr {$canvx0 + $i * $linespc}] | ||||
set xj [expr {$canvx0 + $j * $linespc}] | ||||
set coords {} | ||||
if {[info exists oldstarty($i)] && $oldstarty($i) < $canvy} { | ||||
lappend coords $xi $oldstarty($i) | ||||
} | ||||
lappend coords $xi $canvy | ||||
if {$j < $i - 1} { | ||||
lappend coords [expr $xj + $linespc] $canvy | ||||
} elseif {$j > $i + 1} { | ||||
lappend coords [expr $xj - $linespc] $canvy | ||||
} | ||||
lappend coords $xj $y2 | ||||
set t [$canv create line $coords -width $lthickness \ | ||||
-fill $colormap($dst)] | ||||
$canv lower $t | ||||
if {![info exists linestarty($j)]} { | ||||
set linestarty($j) $y2 | ||||
} | ||||
} | ||||
} | ||||
set phase {} | ||||
if {$redisplaying} { | ||||
if {$stopped == 0 && [info exists selectedline]} { | ||||
selectline $selectedline | ||||
} | ||||
if {$stopped == 1} { | ||||
set stopped 0 | ||||
after idle drawgraph | ||||
} else { | ||||
set redisplaying 0 | ||||
} | ||||
} | ||||
} | ||||
proc findmatches {f} { | ||||
global findtype foundstring foundstrlen | ||||
if {$findtype == "Regexp"} { | ||||
set matches [regexp -indices -all -inline $foundstring $f] | ||||
} else { | ||||
if {$findtype == "IgnCase"} { | ||||
set str [string tolower $f] | ||||
} else { | ||||
set str $f | ||||
} | ||||
set matches {} | ||||
set i 0 | ||||
while {[set j [string first $foundstring $str $i]] >= 0} { | ||||
lappend matches [list $j [expr $j+$foundstrlen-1]] | ||||
set i [expr $j + $foundstrlen] | ||||
} | ||||
} | ||||
return $matches | ||||
} | ||||
proc dofind {} { | ||||
global findtype findloc findstring markedmatches commitinfo | ||||
global numcommits lineid linehtag linentag linedtag | ||||
global mainfont namefont canv canv2 canv3 selectedline | ||||
global matchinglines foundstring foundstrlen idtags | ||||
unmarkmatches | ||||
focus . | ||||
set matchinglines {} | ||||
set fldtypes {Headline Author Date Committer CDate Comment} | ||||
if {$findtype == "IgnCase"} { | ||||
set foundstring [string tolower $findstring] | ||||
} else { | ||||
set foundstring $findstring | ||||
} | ||||
set foundstrlen [string length $findstring] | ||||
if {$foundstrlen == 0} return | ||||
if {![info exists selectedline]} { | ||||
set oldsel -1 | ||||
} else { | ||||
set oldsel $selectedline | ||||
} | ||||
set didsel 0 | ||||
for {set l 0} {$l < $numcommits} {incr l} { | ||||
set id $lineid($l) | ||||
set info $commitinfo($id) | ||||
set doesmatch 0 | ||||
foreach f $info ty $fldtypes { | ||||
if {$findloc != "All fields" && $findloc != $ty} { | ||||
continue | ||||
} | ||||
set matches [findmatches $f] | ||||
if {$matches == {}} continue | ||||
set doesmatch 1 | ||||
if {$ty == "Headline"} { | ||||
markmatches $canv $l $f $linehtag($l) $matches $mainfont | ||||
} elseif {$ty == "Author"} { | ||||
markmatches $canv2 $l $f $linentag($l) $matches $namefont | ||||
} elseif {$ty == "Date"} { | ||||
markmatches $canv3 $l $f $linedtag($l) $matches $mainfont | ||||
} | ||||
} | ||||
if {$doesmatch} { | ||||
lappend matchinglines $l | ||||
if {!$didsel && $l > $oldsel} { | ||||
findselectline $l | ||||
set didsel 1 | ||||
} | ||||
} | ||||
} | ||||
if {$matchinglines == {}} { | ||||
bell | ||||
} elseif {!$didsel} { | ||||
findselectline [lindex $matchinglines 0] | ||||
} | ||||
} | ||||
proc findselectline {l} { | ||||
global findloc commentend ctext | ||||
selectline $l | ||||
if {$findloc == "All fields" || $findloc == "Comments"} { | ||||
# highlight the matches in the comments | ||||
set f [$ctext get 1.0 $commentend] | ||||
set matches [findmatches $f] | ||||
foreach match $matches { | ||||
set start [lindex $match 0] | ||||
set end [expr [lindex $match 1] + 1] | ||||
$ctext tag add found "1.0 + $start c" "1.0 + $end c" | ||||
} | ||||
} | ||||
} | ||||
proc findnext {} { | ||||
global matchinglines selectedline | ||||
if {![info exists matchinglines]} { | ||||
dofind | ||||
return | ||||
} | ||||
if {![info exists selectedline]} return | ||||
foreach l $matchinglines { | ||||
if {$l > $selectedline} { | ||||
findselectline $l | ||||
return | ||||
} | ||||
} | ||||
bell | ||||
} | ||||
proc findprev {} { | ||||
global matchinglines selectedline | ||||
if {![info exists matchinglines]} { | ||||
dofind | ||||
return | ||||
} | ||||
if {![info exists selectedline]} return | ||||
set prev {} | ||||
foreach l $matchinglines { | ||||
if {$l >= $selectedline} break | ||||
set prev $l | ||||
} | ||||
if {$prev != {}} { | ||||
findselectline $prev | ||||
} else { | ||||
bell | ||||
} | ||||
} | ||||
proc markmatches {canv l str tag matches font} { | ||||
set bbox [$canv bbox $tag] | ||||
set x0 [lindex $bbox 0] | ||||
set y0 [lindex $bbox 1] | ||||
set y1 [lindex $bbox 3] | ||||
foreach match $matches { | ||||
set start [lindex $match 0] | ||||
set end [lindex $match 1] | ||||
if {$start > $end} continue | ||||
set xoff [font measure $font [string range $str 0 [expr $start-1]]] | ||||
set xlen [font measure $font [string range $str 0 [expr $end]]] | ||||
set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \ | ||||
-outline {} -tags matches -fill yellow] | ||||
$canv lower $t | ||||
} | ||||
} | ||||
proc unmarkmatches {} { | ||||
global matchinglines | ||||
allcanvs delete matches | ||||
catch {unset matchinglines} | ||||
} | ||||
proc selcanvline {x y} { | ||||
global canv canvy0 ctext linespc selectedline | ||||
global lineid linehtag linentag linedtag | ||||
set ymax [lindex [$canv cget -scrollregion] 3] | ||||
if {$ymax == {}} return | ||||
set yfrac [lindex [$canv yview] 0] | ||||
set y [expr {$y + $yfrac * $ymax}] | ||||
set l [expr {int(($y - $canvy0) / $linespc + 0.5)}] | ||||
if {$l < 0} { | ||||
set l 0 | ||||
} | ||||
if {[info exists selectedline] && $selectedline == $l} return | ||||
unmarkmatches | ||||
selectline $l | ||||
} | ||||
proc selectline {l} { | ||||
global canv canv2 canv3 ctext commitinfo selectedline | ||||
global lineid linehtag linentag linedtag | ||||
global canvy0 linespc nparents treepending | ||||
global cflist treediffs currentid sha1entry | ||||
global commentend seenfile numcommits idtags | ||||
if {![info exists lineid($l)] || ![info exists linehtag($l)]} return | ||||
$canv delete secsel | ||||
set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ | ||||
-tags secsel -fill [$canv cget -selectbackground]] | ||||
$canv lower $t | ||||
$canv2 delete secsel | ||||
set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ | ||||
-tags secsel -fill [$canv2 cget -selectbackground]] | ||||
$canv2 lower $t | ||||
$canv3 delete secsel | ||||
set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ | ||||
-tags secsel -fill [$canv3 cget -selectbackground]] | ||||
$canv3 lower $t | ||||
set y [expr {$canvy0 + $l * $linespc}] | ||||
set ymax [lindex [$canv cget -scrollregion] 3] | ||||
set ytop [expr {$y - $linespc - 1}] | ||||
set ybot [expr {$y + $linespc + 1}] | ||||
set wnow [$canv yview] | ||||
set wtop [expr [lindex $wnow 0] * $ymax] | ||||
set wbot [expr [lindex $wnow 1] * $ymax] | ||||
set wh [expr {$wbot - $wtop}] | ||||
set newtop $wtop | ||||
if {$ytop < $wtop} { | ||||
if {$ybot < $wtop} { | ||||
set newtop [expr {$y - $wh / 2.0}] | ||||
} else { | ||||
set newtop $ytop | ||||
if {$newtop > $wtop - $linespc} { | ||||
set newtop [expr {$wtop - $linespc}] | ||||
} | ||||
} | ||||
} elseif {$ybot > $wbot} { | ||||
if {$ytop > $wbot} { | ||||
set newtop [expr {$y - $wh / 2.0}] | ||||
} else { | ||||
set newtop [expr {$ybot - $wh}] | ||||
if {$newtop < $wtop + $linespc} { | ||||
set newtop [expr {$wtop + $linespc}] | ||||
} | ||||
} | ||||
} | ||||
if {$newtop != $wtop} { | ||||
if {$newtop < 0} { | ||||
set newtop 0 | ||||
} | ||||
allcanvs yview moveto [expr $newtop * 1.0 / $ymax] | ||||
} | ||||
set selectedline $l | ||||
set id $lineid($l) | ||||
set currentid $id | ||||
$sha1entry delete 0 end | ||||
$sha1entry insert 0 $id | ||||
$sha1entry selection from 0 | ||||
$sha1entry selection to end | ||||
$ctext conf -state normal | ||||
$ctext delete 0.0 end | ||||
set info $commitinfo($id) | ||||
$ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" | ||||
$ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" | ||||
if {[info exists idtags($id)]} { | ||||
$ctext insert end "Tags:" | ||||
foreach tag $idtags($id) { | ||||
$ctext insert end " $tag" | ||||
} | ||||
$ctext insert end "\n" | ||||
} | ||||
$ctext insert end "\n" | ||||
$ctext insert end [lindex $info 5] | ||||
$ctext insert end "\n" | ||||
$ctext tag delete Comments | ||||
$ctext tag remove found 1.0 end | ||||
$ctext conf -state disabled | ||||
set commentend [$ctext index "end - 1c"] | ||||
$cflist delete 0 end | ||||
if {$nparents($id) == 1} { | ||||
if {![info exists treediffs($id)]} { | ||||
if {![info exists treepending]} { | ||||
gettreediffs $id | ||||
} | ||||
} else { | ||||
addtocflist $id | ||||
} | ||||
} | ||||
catch {unset seenfile} | ||||
} | ||||
proc selnextline {dir} { | ||||
global selectedline | ||||
if {![info exists selectedline]} return | ||||
set l [expr $selectedline + $dir] | ||||
unmarkmatches | ||||
selectline $l | ||||
} | ||||
proc addtocflist {id} { | ||||
global currentid treediffs cflist treepending | ||||
if {$id != $currentid} { | ||||
gettreediffs $currentid | ||||
return | ||||
} | ||||
$cflist insert end "All files" | ||||
foreach f $treediffs($currentid) { | ||||
$cflist insert end $f | ||||
} | ||||
getblobdiffs $id | ||||
} | ||||
proc gettreediffs {id} { | ||||
global treediffs parents treepending | ||||
set treepending $id | ||||
set treediffs($id) {} | ||||
set p [lindex $parents($id) 0] | ||||
if [catch {set gdtf [open "|hgit diff-tree -r $p $id" r]}] return | ||||
fconfigure $gdtf -blocking 0 | ||||
fileevent $gdtf readable "gettreediffline $gdtf $id" | ||||
} | ||||
proc gettreediffline {gdtf id} { | ||||
global treediffs treepending | ||||
set n [gets $gdtf line] | ||||
if {$n < 0} { | ||||
if {![eof $gdtf]} return | ||||
close $gdtf | ||||
unset treepending | ||||
addtocflist $id | ||||
return | ||||
} | ||||
set file [lindex $line 5] | ||||
lappend treediffs($id) $file | ||||
} | ||||
proc getblobdiffs {id} { | ||||
global parents diffopts blobdifffd env curdifftag curtagstart | ||||
global diffindex difffilestart | ||||
set p [lindex $parents($id) 0] | ||||
set env(GIT_DIFF_OPTS) $diffopts | ||||
if [catch {set bdf [open "|hgit diff-tree -r -p $p $id" r]} err] { | ||||
puts "error getting diffs: $err" | ||||
return | ||||
} | ||||
fconfigure $bdf -blocking 0 | ||||
set blobdifffd($id) $bdf | ||||
set curdifftag Comments | ||||
set curtagstart 0.0 | ||||
set diffindex 0 | ||||
catch {unset difffilestart} | ||||
fileevent $bdf readable "getblobdiffline $bdf $id" | ||||
} | ||||
proc getblobdiffline {bdf id} { | ||||
global currentid blobdifffd ctext curdifftag curtagstart seenfile | ||||
global diffnexthead diffnextnote diffindex difffilestart | ||||
set n [gets $bdf line] | ||||
if {$n < 0} { | ||||
if {[eof $bdf]} { | ||||
close $bdf | ||||
if {$id == $currentid && $bdf == $blobdifffd($id)} { | ||||
$ctext tag add $curdifftag $curtagstart end | ||||
set seenfile($curdifftag) 1 | ||||
} | ||||
} | ||||
return | ||||
} | ||||
if {$id != $currentid || $bdf != $blobdifffd($id)} { | ||||
return | ||||
} | ||||
$ctext conf -state normal | ||||
mpm@selenic.com
|
r274 | if {[regexp {^---[ \t]+([^/])*/([^\t]*)} $line match s0 fname]} { | ||
mpm@selenic.com
|
r267 | # start of a new file | ||
$ctext insert end "\n" | ||||
$ctext tag add $curdifftag $curtagstart end | ||||
set seenfile($curdifftag) 1 | ||||
set curtagstart [$ctext index "end - 1c"] | ||||
set header $fname | ||||
if {[info exists diffnexthead]} { | ||||
set fname $diffnexthead | ||||
set header "$diffnexthead ($diffnextnote)" | ||||
unset diffnexthead | ||||
} | ||||
set difffilestart($diffindex) [$ctext index "end - 1c"] | ||||
incr diffindex | ||||
set curdifftag "f:$fname" | ||||
$ctext tag delete $curdifftag | ||||
set l [expr {(78 - [string length $header]) / 2}] | ||||
set pad [string range "----------------------------------------" 1 $l] | ||||
$ctext insert end "$pad $header $pad\n" filesep | ||||
} elseif {[string range $line 0 2] == "+++"} { | ||||
# no need to do anything with this | ||||
} elseif {[regexp {^Created: (.*) \((mode: *[0-7]*)\)} $line match fn m]} { | ||||
set diffnexthead $fn | ||||
set diffnextnote "created, mode $m" | ||||
} elseif {[string range $line 0 8] == "Deleted: "} { | ||||
set diffnexthead [string range $line 9 end] | ||||
set diffnextnote "deleted" | ||||
} elseif {[regexp {^diff --git a/(.*) b/} $line match fn]} { | ||||
# save the filename in case the next thing is "new file mode ..." | ||||
set diffnexthead $fn | ||||
set diffnextnote "modified" | ||||
} elseif {[regexp {^new file mode ([0-7]+)} $line match m]} { | ||||
set diffnextnote "new file, mode $m" | ||||
} elseif {[string range $line 0 11] == "deleted file"} { | ||||
set diffnextnote "deleted" | ||||
} elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \ | ||||
$line match f1l f1c f2l f2c rest]} { | ||||
$ctext insert end "\t" hunksep | ||||
$ctext insert end " $f1l " d0 " $f2l " d1 | ||||
$ctext insert end " $rest \n" hunksep | ||||
} else { | ||||
set x [string range $line 0 0] | ||||
if {$x == "-" || $x == "+"} { | ||||
set tag [expr {$x == "+"}] | ||||
set line [string range $line 1 end] | ||||
$ctext insert end "$line\n" d$tag | ||||
} elseif {$x == " "} { | ||||
set line [string range $line 1 end] | ||||
$ctext insert end "$line\n" | ||||
} elseif {$x == "\\"} { | ||||
# e.g. "\ No newline at end of file" | ||||
$ctext insert end "$line\n" filesep | ||||
} else { | ||||
# Something else we don't recognize | ||||
if {$curdifftag != "Comments"} { | ||||
$ctext insert end "\n" | ||||
$ctext tag add $curdifftag $curtagstart end | ||||
set seenfile($curdifftag) 1 | ||||
set curtagstart [$ctext index "end - 1c"] | ||||
set curdifftag Comments | ||||
} | ||||
$ctext insert end "$line\n" filesep | ||||
} | ||||
} | ||||
$ctext conf -state disabled | ||||
} | ||||
proc nextfile {} { | ||||
global difffilestart ctext | ||||
set here [$ctext index @0,0] | ||||
for {set i 0} {[info exists difffilestart($i)]} {incr i} { | ||||
if {[$ctext compare $difffilestart($i) > $here]} { | ||||
$ctext yview $difffilestart($i) | ||||
break | ||||
} | ||||
} | ||||
} | ||||
proc listboxsel {} { | ||||
global ctext cflist currentid treediffs seenfile | ||||
if {![info exists currentid]} return | ||||
set sel [$cflist curselection] | ||||
if {$sel == {} || [lsearch -exact $sel 0] >= 0} { | ||||
# show everything | ||||
$ctext tag conf Comments -elide 0 | ||||
foreach f $treediffs($currentid) { | ||||
if [info exists seenfile(f:$f)] { | ||||
$ctext tag conf "f:$f" -elide 0 | ||||
} | ||||
} | ||||
} else { | ||||
# just show selected files | ||||
$ctext tag conf Comments -elide 1 | ||||
set i 1 | ||||
foreach f $treediffs($currentid) { | ||||
set elide [expr {[lsearch -exact $sel $i] < 0}] | ||||
if [info exists seenfile(f:$f)] { | ||||
$ctext tag conf "f:$f" -elide $elide | ||||
} | ||||
incr i | ||||
} | ||||
} | ||||
} | ||||
proc setcoords {} { | ||||
global linespc charspc canvx0 canvy0 mainfont | ||||
set linespc [font metrics $mainfont -linespace] | ||||
set charspc [font measure $mainfont "m"] | ||||
set canvy0 [expr 3 + 0.5 * $linespc] | ||||
set canvx0 [expr 3 + 0.5 * $linespc] | ||||
} | ||||
proc redisplay {} { | ||||
global selectedline stopped redisplaying phase | ||||
if {$stopped > 1} return | ||||
if {$phase == "getcommits"} return | ||||
set redisplaying 1 | ||||
if {$phase == "drawgraph"} { | ||||
set stopped 1 | ||||
} else { | ||||
drawgraph | ||||
} | ||||
} | ||||
proc incrfont {inc} { | ||||
global mainfont namefont textfont selectedline ctext canv phase | ||||
global stopped entries | ||||
unmarkmatches | ||||
set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] | ||||
set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]] | ||||
set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] | ||||
setcoords | ||||
$ctext conf -font $textfont | ||||
$ctext tag conf filesep -font [concat $textfont bold] | ||||
foreach e $entries { | ||||
$e conf -font $mainfont | ||||
} | ||||
if {$phase == "getcommits"} { | ||||
$canv itemconf textitems -font $mainfont | ||||
} | ||||
redisplay | ||||
} | ||||
proc sha1change {n1 n2 op} { | ||||
global sha1string currentid sha1but | ||||
if {$sha1string == {} | ||||
|| ([info exists currentid] && $sha1string == $currentid)} { | ||||
set state disabled | ||||
} else { | ||||
set state normal | ||||
} | ||||
if {[$sha1but cget -state] == $state} return | ||||
if {$state == "normal"} { | ||||
$sha1but conf -state normal -relief raised -text "Goto: " | ||||
} else { | ||||
$sha1but conf -state disabled -relief flat -text "SHA1 ID: " | ||||
} | ||||
} | ||||
proc gotocommit {} { | ||||
global sha1string currentid idline tagids | ||||
if {$sha1string == {} | ||||
|| ([info exists currentid] && $sha1string == $currentid)} return | ||||
if {[info exists tagids($sha1string)]} { | ||||
set id $tagids($sha1string) | ||||
} else { | ||||
set id [string tolower $sha1string] | ||||
} | ||||
if {[info exists idline($id)]} { | ||||
selectline $idline($id) | ||||
return | ||||
} | ||||
if {[regexp {^[0-9a-fA-F]{40}$} $sha1string]} { | ||||
set type "SHA1 id" | ||||
} else { | ||||
set type "Tag" | ||||
} | ||||
error_popup "$type $sha1string is not known" | ||||
} | ||||
proc doquit {} { | ||||
global stopped | ||||
set stopped 100 | ||||
destroy . | ||||
} | ||||
# defaults... | ||||
set datemode 0 | ||||
set boldnames 0 | ||||
set diffopts "-U 5 -p" | ||||
set mainfont {Helvetica 9} | ||||
set textfont {Courier 9} | ||||
set colors {green red blue magenta darkgrey brown orange} | ||||
set colorbycommitter false | ||||
catch {source ~/.gitk} | ||||
set namefont $mainfont | ||||
if {$boldnames} { | ||||
lappend namefont bold | ||||
} | ||||
set revtreeargs {} | ||||
foreach arg $argv { | ||||
switch -regexp -- $arg { | ||||
"^$" { } | ||||
"^-b" { set boldnames 1 } | ||||
"^-c" { set colorbycommitter 1 } | ||||
"^-d" { set datemode 1 } | ||||
default { | ||||
lappend revtreeargs $arg | ||||
} | ||||
} | ||||
} | ||||
set stopped 0 | ||||
set redisplaying 0 | ||||
set stuffsaved 0 | ||||
setcoords | ||||
makewindow | ||||
readrefs | ||||
readfullcommits $revtreeargs | ||||