}
if {[catch {
set commfd [open [concat | git-rev-list --header $order \
- --parents $rlargs] r]
+ --parents --boundary $rlargs] r]
} err]} {
puts stderr "Error executing git-rev-list: $err"
exit 1
global commitlisted nextupdate
global leftover
global displayorder commitidx commitrow commitdata
+ global parentlist childlist children
set stuff [read $commfd]
if {$stuff == {}} {
set start [expr {$i + 1}]
set j [string first "\n" $cmit]
set ok 0
+ set listed 1
if {$j >= 0} {
set ids [string range $cmit 0 [expr {$j - 1}]]
+ if {[string range $ids 0 0] == "-"} {
+ set listed 0
+ set ids [string range $ids 1 end]
+ }
set ok 1
foreach id $ids {
if {[string length $id] != 40} {
exit 1
}
set id [lindex $ids 0]
- set olds [lrange $ids 1 end]
- set commitlisted($id) 1
- updatechildren $id $olds
+ if {$listed} {
+ set olds [lrange $ids 1 end]
+ if {[llength $olds] > 1} {
+ set olds [lsort -unique $olds]
+ }
+ foreach p $olds {
+ lappend children($p) $id
+ }
+ } else {
+ set olds {}
+ }
+ lappend parentlist $olds
+ if {[info exists children($id)]} {
+ lappend childlist $children($id)
+ } else {
+ lappend childlist {}
+ }
set commitdata($id) [string range $cmit [expr {$j + 1}] end]
set commitrow($id) $commitidx
incr commitidx
lappend displayorder $id
+ lappend commitlisted $listed
set gotsome 1
}
if {$gotsome} {
proc readcommit {id} {
if {[catch {set contents [exec git-cat-file commit $id]}]} return
- updatechildren $id {}
parsecommit $id $contents 0
}
proc updatecommits {rargs} {
stopfindproc
- foreach v {children nchildren parents nparents commitlisted
- colormap selectedline matchinglines treediffs
+ foreach v {colormap selectedline matchinglines treediffs
mergefilelist currentid rowtextx commitrow
rowidlist rowoffsets idrowranges idrangedrawn iddrawn
linesegends crossings cornercrossings} {
getcommits $rargs
}
-proc updatechildren {id olds} {
- global children nchildren parents nparents
-
- if {![info exists nchildren($id)]} {
- set children($id) {}
- set nchildren($id) 0
- }
- set parents($id) $olds
- set nparents($id) [llength $olds]
- foreach p $olds {
- if {![info exists nchildren($p)]} {
- set children($p) [list $id]
- set nchildren($p) 1
- } elseif {[lsearch -exact $children($p) $id] < 0} {
- lappend children($p) $id
- incr nchildren($p)
- }
- }
-}
-
proc parsecommit {id contents listed} {
global commitinfo cdate
}
proc getcommit {id} {
- global commitdata commitinfo nparents
+ global commitdata commitinfo
if {[info exists commitdata($id)]} {
parsecommit $id $commitdata($id) 1
readcommit $id
if {![info exists commitinfo($id)]} {
set commitinfo($id) {"No commit information available"}
- set nparents($id) 0
}
}
return 1
#bindall <B1-Motion> {selcanvline %W %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"
+ bindall <2> "canvscan mark %W %x %y"
+ bindall <B2-Motion> "canvscan dragto %W %x %y"
bind . <Key-Up> "selnextline -1"
bind . <Key-Down> "selnextline 1"
bind . <Key-Right> "goforw"
$rowctxmenu add command -label "Write commit to file" -command writecommit
}
+# mouse-2 makes all windows scan vertically, but only the one
+# the cursor is in scans horizontally
+proc canvscan {op w x y} {
+ global canv canv2 canv3
+ foreach c [list $canv $canv2 $canv3] {
+ if {$c == $w} {
+ $c scan $op $x $y
+ } else {
+ $c scan $op 0 $y
+ }
+ }
+}
+
proc scrollcanv {cscroll f0 f1} {
$cscroll set $f0 $f1
drawfrac $f0 $f1
}
proc initlayout {} {
- global rowidlist rowoffsets displayorder
+ global rowidlist rowoffsets displayorder commitlisted
global rowlaidout rowoptim
global idinlist rowchk
- global commitidx numcommits
+ global commitidx numcommits canvxmax canv
global nextcolor
+ global parentlist childlist children
set commitidx 0
set numcommits 0
set displayorder {}
+ set commitlisted {}
+ set parentlist {}
+ set childlist {}
+ catch {unset children}
set nextcolor 0
set rowidlist {{}}
set rowoffsets {{}}
catch {unset rowchk}
set rowlaidout 0
set rowoptim 0
+ set canvxmax [$canv cget -width]
+}
+
+proc setcanvscroll {} {
+ global canv canv2 canv3 numcommits linespc canvxmax canvy0
+
+ set ymax [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]
+ $canv conf -scrollregion [list 0 0 $canvxmax $ymax]
+ $canv2 conf -scrollregion [list 0 0 0 $ymax]
+ $canv3 conf -scrollregion [list 0 0 0 $ymax]
}
proc visiblerows {} {
proc showstuff {canshow} {
global numcommits
- global canvy0 linespc
global linesegends idrowranges idrangedrawn
if {$numcommits == 0} {
}
set row $numcommits
set numcommits $canshow
- allcanvs conf -scrollregion \
- [list 0 0 0 [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]]
+ setcanvscroll
set rows [visiblerows]
set r0 [lindex $rows 0]
set r1 [lindex $rows 1]
proc layoutrows {row endrow last} {
global rowidlist rowoffsets displayorder
global uparrowlen downarrowlen maxwidth mingaplen
- global nchildren parents nparents
+ global childlist parentlist
global idrowranges linesegends
global commitidx
global idinlist rowchk
set id [lindex $displayorder $row]
set oldolds {}
set newolds {}
- foreach p $parents($id) {
+ foreach p [lindex $parentlist $row] {
if {![info exists idinlist($p)]} {
lappend newolds $p
} elseif {!$idinlist($p)} {
lappend idlist $id
lset rowidlist $row $idlist
set z {}
- if {$nchildren($id) > 0} {
+ if {[lindex $childlist $row] ne {}} {
set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
unset idinlist($id)
}
}
proc addextraid {id row} {
- global displayorder commitrow commitinfo nparents
+ global displayorder commitrow commitinfo
global commitidx
+ global parentlist childlist children
incr commitidx
lappend displayorder $id
+ lappend parentlist {}
set commitrow($id) $row
readcommit $id
if {![info exists commitinfo($id)]} {
set commitinfo($id) {"No commit information available"}
- set nparents($id) 0
+ }
+ if {[info exists children($id)]} {
+ lappend childlist $children($id)
+ } else {
+ lappend childlist {}
}
}
set idlist [lindex $rowidlist $row]
set offs [lindex $rowoffsets $row]
set haspad 0
- set downarrowcols {}
- if {[info exists linesegends($row)]} {
- set downarrowcols $linesegends($row)
- if {$col > 0} {
- while {$downarrowcols ne {}} {
- set i [lsearch -exact $idlist [lindex $downarrowcols 0]]
- if {$i < 0 || $i >= $col} break
- set downarrowcols [lrange $downarrowcols 1 end]
- }
- }
- }
for {} {$col < [llength $offs]} {incr col} {
if {[lindex $idlist $col] eq {}} {
set haspad 1
$y0 > [lindex $idrowranges($id) 0]} {
set isarrow 1
}
- } elseif {$downarrowcols ne {} &&
- [lindex $idlist $col] eq [lindex $downarrowcols 0]} {
- set downarrowcols [lrange $downarrowcols 1 end]
- set isarrow 1
}
if {$z < -1 || ($z < 0 && $isarrow)} {
set npad [expr {-1 - $z + $isarrow}]
set z [lindex $offs $col]
set haspad 1
}
+ if {$z0 eq {} && !$isarrow} {
+ # this line links to its first child on row $row-2
+ set rm2 [expr {$row - 2}]
+ set id [lindex $displayorder $rm2]
+ set xc [lsearch -exact [lindex $rowidlist $rm2] $id]
+ if {$xc >= 0} {
+ set z0 [expr {$xc - $x0}]
+ }
+ }
if {$z0 ne {} && $z < 0 && $z0 > 0} {
insert_pad $y0 $x0 1
set offs [incrange $offs $col 1]
}
}
if {!$haspad} {
+ set o {}
for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
set o [lindex $offs $col]
+ if {$o eq {}} {
+ # check if this is the link to the first child
+ set id [lindex $idlist $col]
+ if {[info exists idrowranges($id)] &&
+ $row == [lindex $idrowranges($id) 0]} {
+ # it is, work out offset to child
+ set y0 [expr {$row - 1}]
+ set id [lindex $displayorder $y0]
+ set x0 [lsearch -exact [lindex $rowidlist $y0] $id]
+ if {$x0 >= 0} {
+ set o [expr {$x0 - $col}]
+ }
+ }
+ }
if {$o eq {} || $o <= 0} break
}
- if {[incr col] < [llength $idlist]} {
+ if {$o ne {} && [incr col] < [llength $idlist]} {
set y1 [expr {$row + 1}]
set offs2 [lindex $rowoffsets $y1]
set x1 -1
proc drawlineseg {id i} {
global rowoffsets rowidlist idrowranges
- global canv colormap
+ global displayorder
+ global canv colormap linespc
set startrow [lindex $idrowranges($id) [expr {2 * $i}]]
set row [lindex $idrowranges($id) [expr {2 * $i + 1}]]
incr col $o
incr row -1
}
- if {$coords eq {}} return
- set last [expr {[llength $idrowranges($id)] / 2 - 1}]
- set arrow [expr {2 * ($i > 0) + ($i < $last)}]
- set arrow [lindex {none first last both} $arrow]
set x [xc $row $col]
set y [yc $row]
lappend coords $x $y
+ if {$i == 0} {
+ # draw the link to the first child as part of this line
+ incr row -1
+ set child [lindex $displayorder $row]
+ set ccol [lsearch -exact [lindex $rowidlist $row] $child]
+ if {$ccol >= 0} {
+ set x [xc $row $ccol]
+ set y [yc $row]
+ if {$ccol < $col - 1} {
+ lappend coords [xc $row [expr {$col - 1}]] [yc $row]
+ } elseif {$ccol > $col + 1} {
+ lappend coords [xc $row [expr {$col + 1}]] [yc $row]
+ }
+ lappend coords $x $y
+ }
+ }
+ if {[llength $coords] < 4} return
+ set last [expr {[llength $idrowranges($id)] / 2 - 1}]
+ if {$i < $last} {
+ # This line has an arrow at the lower end: check if the arrow is
+ # on a diagonal segment, and if so, work around the Tk 8.4
+ # refusal to draw arrows on diagonal lines.
+ set x0 [lindex $coords 0]
+ set x1 [lindex $coords 2]
+ if {$x0 != $x1} {
+ set y0 [lindex $coords 1]
+ set y1 [lindex $coords 3]
+ if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
+ # we have a nearby vertical segment, just trim off the diag bit
+ set coords [lrange $coords 2 end]
+ } else {
+ set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
+ set xi [expr {$x0 - $slope * $linespc / 2}]
+ set yi [expr {$y0 - $linespc / 2}]
+ set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
+ }
+ }
+ }
+ set arrow [expr {2 * ($i > 0) + ($i < $last)}]
+ set arrow [lindex {none first last both} $arrow]
set t [$canv create line $coords -width [linewidth $id] \
-fill $colormap($id) -tags lines.$id -arrow $arrow]
$canv lower $t
}
proc drawparentlinks {id row col olds} {
- global rowidlist canv colormap
+ global rowidlist canv colormap idrowranges
set row2 [expr {$row + 1}]
set x [xc $row $col]
puts "oops, parent $p of $id not in list"
continue
}
+ set x2 [xc $row2 $i]
+ if {$x2 > $rmx} {
+ set rmx $x2
+ }
+ if {[info exists idrowranges($p)] &&
+ $row2 == [lindex $idrowranges($p) 0] &&
+ $row2 < [lindex $idrowranges($p) 1]} {
+ # drawlineseg will do this one for us
+ continue
+ }
assigncolor $p
# should handle duplicated parents here...
set coords [list $x $y]
} elseif {$i > $col + 1} {
lappend coords [xc $row [expr {$i - 1}]] $y
}
- set x2 [xc $row2 $i]
- if {$x2 > $rmx} {
- set rmx $x2
- }
lappend coords $x2 $y2
set t [$canv create line $coords -width [linewidth $p] \
-fill $colormap($p) -tags lines.$p]
proc drawlines {id} {
global colormap canv
global idrowranges idrangedrawn
- global children iddrawn commitrow rowidlist
+ global childlist iddrawn commitrow rowidlist
$canv delete lines.$id
set nr [expr {[llength $idrowranges($id)] / 2}]
drawlineseg $id $i
}
}
- if {[info exists children($id)]} {
- foreach child $children($id) {
- if {[info exists iddrawn($child)]} {
- set row $commitrow($child)
- set col [lsearch -exact [lindex $rowidlist $row] $child]
- if {$col >= 0} {
- drawparentlinks $child $row $col [list $id]
- }
+ foreach child [lindex $childlist $commitrow($id)] {
+ if {[info exists iddrawn($child)]} {
+ set row $commitrow($child)
+ set col [lsearch -exact [lindex $rowidlist $row] $child]
+ if {$col >= 0} {
+ drawparentlinks $child $row $col [list $id]
}
}
}
global commitlisted commitinfo rowidlist
global rowtextx idpos idtags idheads idotherrefs
global linehtag linentag linedtag
- global mainfont namefont
+ global mainfont namefont canvxmax
- set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}]
+ set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
set x [xc $row $col]
set y [yc $row]
set orad [expr {$linespc / 3}]
-text $name -font $namefont]
set linedtag($row) [$canv3 create text 3 $y -anchor w \
-text $date -font $mainfont]
+ set xr [expr {$xt + [font measure $mainfont $headline]}]
+ if {$xr > $canvxmax} {
+ set canvxmax $xr
+ setcanvscroll
+ }
}
proc drawcmitrow {row} {
global displayorder rowidlist
global idrowranges idrangedrawn iddrawn
- global commitinfo commitlisted parents numcommits
+ global commitinfo commitlisted parentlist numcommits
if {$row >= $numcommits} return
foreach id [lindex $rowidlist $row] {
getcommit $id
}
assigncolor $id
- if {[info exists commitlisted($id)] && [info exists parents($id)]
- && $parents($id) ne {}} {
- set rmx [drawparentlinks $id $row $col $parents($id)]
+ set olds [lindex $parentlist $row]
+ if {$olds ne {}} {
+ set rmx [drawparentlinks $id $row $col $olds]
} else {
set rmx 0
}
proc assigncolor {id} {
global colormap colors nextcolor
- global parents nparents children nchildren
+ global commitrow parentlist children childlist
global cornercrossings crossings
if {[info exists colormap($id)]} return
set ncolors [llength $colors]
- if {$nchildren($id) == 1} {
- set child [lindex $children($id) 0]
+ if {[info exists commitrow($id)]} {
+ set kids [lindex $childlist $commitrow($id)]
+ } elseif {[info exists children($id)]} {
+ set kids $children($id)
+ } else {
+ set kids {}
+ }
+ if {[llength $kids] == 1} {
+ set child [lindex $kids 0]
if {[info exists colormap($child)]
- && $nparents($child) == 1} {
+ && [llength [lindex $parentlist $commitrow($child)]] == 1} {
set colormap($id) $colormap($child)
return
}
set origbad $badcolors
}
if {[llength $badcolors] < $ncolors - 1} {
- foreach child $children($id) {
+ foreach child $kids {
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)
- }
+ foreach p [lindex $parentlist $commitrow($child)] {
+ if {[info exists colormap($p)]
+ && [lsearch -exact $badcolors $colormap($p)] < 0} {
+ lappend badcolors $colormap($p)
}
}
}
}
proc checkcrossings {row endrow} {
- global displayorder parents rowidlist
+ global displayorder parentlist rowidlist
for {} {$row < $endrow} {incr row} {
set id [lindex $displayorder $row]
set i [lsearch -exact [lindex $rowidlist $row] $id]
if {$i < 0} continue
set idlist [lindex $rowidlist [expr {$row+1}]]
- foreach p $parents($id) {
+ foreach p [lindex $parentlist $row] {
set j [lsearch -exact $idlist $p]
if {$j > 0} {
if {$j < $i - 1} {
showstuff $commitidx
set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
- #puts "overall $drawmsecs ms for $numcommits commits"
+ puts "overall $drawmsecs ms for $numcommits commits"
}
proc findmatches {f} {
proc findfiles {} {
global selectedline numcommits displayorder ctext
- global ffileline finddidsel parents nparents
+ global ffileline finddidsel parentlist
global findinprogress findstartline findinsertpos
global treediffs fdiffid fdiffsneeded fdiffpos
global findmergefiles
set fdiffsneeded {}
while 1 {
set id [lindex $displayorder $l]
- if {$findmergefiles || $nparents($id) == 1} {
+ if {$findmergefiles || [llength [lindex $parentlist $l]] == 1} {
if {![info exists treediffs($id)]} {
append diffsneeded "$id\n"
lappend fdiffsneeded $id
. config -cursor watch
settextcursor watch
set findinprogress 1
- findcont $id
+ findcont
update
}
set treediffs($nullid) {}
if {[info exists findid] && $nullid eq $findid} {
unset findid
- findcont $nullid
+ findcont
}
incr fdiffpos
}
}
if {[info exists findid] && $fdiffid eq $findid} {
unset findid
- findcont $fdiffid
+ findcont
}
}
}
proc findcont {id} {
- global findid treediffs parents nparents
+ global findid treediffs parentlist
global ffileline findstartline finddidsel
global displayorder numcommits matchinglines findinprogress
global findmergefiles
set l $ffileline
- while 1 {
- if {$findmergefiles || $nparents($id) == 1} {
+ while {1} {
+ set id [lindex $displayorder $l]
+ if {$findmergefiles || [llength [lindex $parentlist $l]] == 1} {
if {![info exists treediffs($id)]} {
set findid $id
set ffileline $l
set l 0
}
if {$l == $findstartline} break
- set id [lindex $displayorder $l]
}
stopfindproc
if {!$finddidsel} {
proc selectline {l isnew} {
global canv canv2 canv3 ctext commitinfo selectedline
global displayorder linehtag linentag linedtag
- global canvy0 linespc parents nparents children
+ global canvy0 linespc parentlist childlist
global cflist currentid sha1entry
global commentend idtags linknum
global mergemax numcommits
}
set comment {}
- if {$nparents($id) > 1} {
+ set olds [lindex $parentlist $l]
+ if {[llength $olds] > 1} {
set np 0
- foreach p $parents($id) {
+ foreach p $olds {
if {$np >= $mergemax} {
set tag mmax
} else {
incr np
}
} else {
- if {[info exists parents($id)]} {
- foreach p $parents($id) {
- append comment "Parent: [commit_descriptor $p]\n"
- }
+ foreach p $olds {
+ append comment "Parent: [commit_descriptor $p]\n"
}
}
- if {[info exists children($id)]} {
- foreach c $children($id) {
- append comment "Child: [commit_descriptor $c]\n"
- }
+ foreach c [lindex $childlist $l] {
+ append comment "Child: [commit_descriptor $c]\n"
}
append comment "\n"
append comment [lindex $info 5]
$cflist delete 0 end
$cflist insert end "Comments"
- if {$nparents($id) == 1} {
+ if {[llength $olds] <= 1} {
startdiff $id
- } elseif {$nparents($id) > 1} {
- mergediff $id
+ } else {
+ mergediff $id $l
}
}
}
}
-proc mergediff {id} {
- global parents diffmergeid diffopts mdifffd
- global difffilestart
+proc mergediff {id l} {
+ global diffmergeid diffopts mdifffd
+ global difffilestart diffids
+ global parentlist
set diffmergeid $id
+ set diffids $id
catch {unset difffilestart}
# this doesn't seem to actually affect anything...
set env(GIT_DIFF_OPTS) $diffopts
}
fconfigure $mdf -blocking 0
set mdifffd($id) $mdf
- fileevent $mdf readable [list getmergediffline $mdf $id]
+ set np [llength [lindex $parentlist $l]]
+ fileevent $mdf readable [list getmergediffline $mdf $id $np]
set nextupdate [expr {[clock clicks -milliseconds] + 100}]
}
-proc getmergediffline {mdf id} {
- global diffmergeid ctext cflist nextupdate nparents mergemax
- global difffilestart
+proc getmergediffline {mdf id np} {
+ global diffmergeid ctext cflist nextupdate mergemax
+ global difffilestart mdifffd
set n [gets $mdf line]
if {$n < 0} {
}
return
}
- if {![info exists diffmergeid] || $id != $diffmergeid} {
+ if {![info exists diffmergeid] || $id != $diffmergeid
+ || $mdf != $mdifffd($id)} {
return
}
$ctext conf -state normal
# do nothing
} else {
# parse the prefix - one ' ', '-' or '+' for each parent
- set np $nparents($id)
set spaces {}
set minuses {}
set pluses {}
}
proc gettreediffs {ids} {
- global treediff parents treepending
+ global treediff treepending
set treepending $ids
set treediff {}
if {[catch \
set treediffs($ids) $treediff
unset treepending
if {$ids != $diffids} {
- gettreediffs $diffids
- } else {
- if {[info exists diffmergeid]} {
- contmergediff $ids
- } else {
- addtocflist $ids
+ if {![info exists diffmergeid]} {
+ gettreediffs $diffids
}
+ } else {
+ addtocflist $ids
}
return
}
}
proc redisplay {} {
- global canv canvy0 linespc numcommits
+ global canv
global selectedline
set ymax [lindex [$canv cget -scrollregion] 3]
if {$ymax eq {} || $ymax == 0} return
set span [$canv yview]
clear_display
- allcanvs conf -scrollregion \
- [list 0 0 0 [expr {$canvy0 + ($numcommits - 0.5) * $linespc + 2}]]
+ setcanvscroll
allcanvs yview moveto [lindex $span 0]
drawvisible
if {[info exists selectedline]} {
}
proc lineclick {x y id isnew} {
- global ctext commitinfo children cflist canv thickerline
+ global ctext commitinfo childlist commitrow cflist canv thickerline
if {![info exists commitinfo($id)] && ![getcommit $id]} return
unmarkmatches
$ctext insert end "\tAuthor:\t[lindex $info 1]\n"
set date [formatdate [lindex $info 2]]
$ctext insert end "\tDate:\t$date\n"
- if {[info exists children($id)]} {
+ set kids [lindex $childlist $commitrow($id)]
+ if {$kids ne {}} {
$ctext insert end "\nChildren:"
set i 0
- foreach child $children($id) {
+ foreach child $kids {
incr i
if {![info exists commitinfo($child)] && ![getcommit $child]} continue
set info $commitinfo($child)