@ -273,7 +273,7 @@ proc makewindow {} {
@@ -273,7 +273,7 @@ proc makewindow {} {
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
global maincursor textcursor
global rowctxmenu gaudydiff
global rowctxmenu gaudydiff mergemax
menu .bar
.bar add cascade -label "File" -menu .bar.file
@ -373,6 +373,15 @@ proc makewindow {} {
@@ -373,6 +373,15 @@ proc makewindow {} {
$ctext tag conf hunksep -fore blue
$ctext tag conf d0 -fore red
$ctext tag conf d1 -fore "#00a000"
$ctext tag conf m0 -fore red
$ctext tag conf m1 -fore blue
$ctext tag conf m2 -fore green
$ctext tag conf m3 -fore purple
$ctext tag conf m4 -fore brown
$ctext tag conf mmax -fore darkgrey
set mergemax 5
$ctext tag conf mresult -font [concat $textfont bold]
$ctext tag conf msep -font [concat $textfont bold]
$ctext tag conf found -back yellow
}
@ -1752,7 +1761,9 @@ proc contmergediff {ids} {
@@ -1752,7 +1761,9 @@ proc contmergediff {ids} {
}
if {![info exists treediffs($ids)]} {
set diffids $ids
gettreediffs $ids
if {![info exists treepending]} {
gettreediffs $ids
}
return
}
}
@ -1790,16 +1801,364 @@ proc contmergediff {ids} {
@@ -1790,16 +1801,364 @@ proc contmergediff {ids} {
}
set mergefilelist($diffmergeid) $files
showmergediff
if {$files ne {}} {
showmergediff
}
}
proc showmergediff {} {
global cflist diffmergeid mergefilelist
global cflist diffmergeid mergefilelist parents
global diffopts diffinhunk currentfile diffblocked
global groupfilelast mergefds
set files $mergefilelist($diffmergeid)
foreach f $files {
$cflist insert end $f
}
set env(GIT_DIFF_OPTS) $diffopts
set flist {}
catch {unset currentfile}
catch {unset currenthunk}
catch {unset filelines}
set groupfilelast -1
foreach p $parents($diffmergeid) {
set cmd [list | git-diff-tree -p $p $diffmergeid]
set cmd [concat $cmd $mergefilelist($diffmergeid)]
if {[catch {set f [open $cmd r]} err]} {
error_popup "Error getting diffs: $err"
foreach f $flist {
catch {close $f}
}
return
}
lappend flist $f
set ids [list $diffmergeid $p]
set mergefds($ids) $f
set diffinhunk($ids) 0
set diffblocked($ids) 0
fconfigure $f -blocking 0
fileevent $f readable [list getmergediffline $f $ids $diffmergeid]
}
}
proc getmergediffline {f ids id} {
global diffmergeid diffinhunk diffoldlines diffnewlines
global currentfile currenthunk
global diffoldstart diffnewstart diffoldlno diffnewlno
global diffblocked mergefilelist
global noldlines nnewlines difflcounts filelines
set n [gets $f line]
if {$n < 0} {
if {![eof $f]} return
}
if {!([info exists diffmergeid] && $diffmergeid == $id)} {
if {$n < 0} {
close $f
}
return
}
if {$diffinhunk($ids) != 0} {
set fi $currentfile($ids)
if {$n > 0 && [regexp {^[-+ \\]} $line match]} {
# continuing an existing hunk
set line [string range $line 1 end]
set p [lindex $ids 1]
if {$match eq "-" || $match eq " "} {
set filelines($p,$fi,$diffoldlno($ids)) $line
incr diffoldlno($ids)
}
if {$match eq "+" || $match eq " "} {
set filelines($id,$fi,$diffnewlno($ids)) $line
incr diffnewlno($ids)
}
if {$match eq " "} {
if {$diffinhunk($ids) == 2} {
lappend difflcounts($ids) \
[list $noldlines($ids) $nnewlines($ids)]
set noldlines($ids) 0
set diffinhunk($ids) 1
}
incr noldlines($ids)
} elseif {$match eq "-" || $match eq "+"} {
if {$diffinhunk($ids) == 1} {
lappend difflcounts($ids) [list $noldlines($ids)]
set noldlines($ids) 0
set nnewlines($ids) 0
set diffinhunk($ids) 2
}
if {$match eq "-"} {
incr noldlines($ids)
} else {
incr nnewlines($ids)
}
}
# and if it's \ No newline at end of line, then what?
return
}
# end of a hunk
if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} {
lappend difflcounts($ids) [list $noldlines($ids)]
} elseif {$diffinhunk($ids) == 2
&& ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} {
lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)]
}
set currenthunk($ids) [list $currentfile($ids) \
$diffoldstart($ids) $diffnewstart($ids) \
$diffoldlno($ids) $diffnewlno($ids) \
$difflcounts($ids)]
set diffinhunk($ids) 0
# -1 = need to block, 0 = unblocked, 1 = is blocked
set diffblocked($ids) -1
processhunks
if {$diffblocked($ids) == -1} {
fileevent $f readable {}
set diffblocked($ids) 1
}
}
if {$n < 0} {
# eof
if {!$diffblocked($ids)} {
close $f
set currentfile($ids) [llength $mergefilelist($diffmergeid)]
set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}]
processhunks
}
} elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} {
# start of a new file
set currentfile($ids) \
[lsearch -exact $mergefilelist($diffmergeid) $fname]
} elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
$line match f1l f1c f2l f2c rest]} {
if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} {
# start of a new hunk
if {$f1l == 0 && $f1c == 0} {
set f1l 1
}
if {$f2l == 0 && $f2c == 0} {
set f2l 1
}
set diffinhunk($ids) 1
set diffoldstart($ids) $f1l
set diffnewstart($ids) $f2l
set diffoldlno($ids) $f1l
set diffnewlno($ids) $f2l
set difflcounts($ids) {}
set noldlines($ids) 0
set nnewlines($ids) 0
}
}
}
proc processhunks {} {
global diffmergeid parents nparents currenthunk
global mergefilelist diffblocked mergefds
global grouphunks grouplinestart grouplineend groupfilenum
set nfiles [llength $mergefilelist($diffmergeid)]
while 1 {
set fi $nfiles
set lno 0
# look for the earliest hunk
foreach p $parents($diffmergeid) {
set ids [list $diffmergeid $p]
if {![info exists currenthunk($ids)]} return
set i [lindex $currenthunk($ids) 0]
set l [lindex $currenthunk($ids) 2]
if {$i < $fi || ($i == $fi && $l < $lno)} {
set fi $i
set lno $l
set pi $p
}
}
if {$fi < $nfiles} {
set ids [list $diffmergeid $pi]
set hunk $currenthunk($ids)
unset currenthunk($ids)
if {$diffblocked($ids) > 0} {
fileevent $mergefds($ids) readable \
[list getmergediffline $mergefds($ids) $ids $diffmergeid]
}
set diffblocked($ids) 0
if {[info exists groupfilenum] && $groupfilenum == $fi
&& $lno <= $grouplineend} {
# add this hunk to the pending group
lappend grouphunks($pi) $hunk
set endln [lindex $hunk 4]
if {$endln > $grouplineend} {
set grouplineend $endln
}
continue
}
}
# succeeding stuff doesn't belong in this group, so
# process the group now
if {[info exists groupfilenum]} {
processgroup
unset groupfilenum
unset grouphunks
}
if {$fi >= $nfiles} break
# start a new group
set groupfilenum $fi
set grouphunks($pi) [list $hunk]
set grouplinestart $lno
set grouplineend [lindex $hunk 4]
}
}
proc processgroup {} {
global groupfilelast groupfilenum difffilestart
global mergefilelist diffmergeid ctext filelines
global parents diffmergeid diffoffset
global grouphunks grouplinestart grouplineend nparents
global mergemax
$ctext conf -state normal
set id $diffmergeid
set f $groupfilenum
if {$groupfilelast != $f} {
$ctext insert end "\n"
set here [$ctext index "end - 1c"]
set difffilestart($f) $here
set mark fmark.[expr {$f + 1}]
$ctext mark set $mark $here
$ctext mark gravity $mark left
set header [lindex $mergefilelist($id) $f]
set l [expr {(78 - [string length $header]) / 2}]
set pad [string range "----------------------------------------" 1 $l]
$ctext insert end "$pad $header $pad\n" filesep
set groupfilelast $f
foreach p $parents($id) {
set diffoffset($p) 0
}
}
$ctext insert end "@@" msep
set nlines [expr {$grouplineend - $grouplinestart}]
set events {}
set pnum 0
foreach p $parents($id) {
set startline [expr {$grouplinestart + $diffoffset($p)}]
set offset($p) $diffoffset($p)
set ol $startline
set nl $grouplinestart
if {[info exists grouphunks($p)]} {
foreach h $grouphunks($p) {
set l [lindex $h 2]
if {$nl < $l} {
for {} {$nl < $l} {incr nl} {
set filelines($p,$f,$ol) $filelines($id,$f,$nl)
incr ol
}
}
foreach chunk [lindex $h 5] {
if {[llength $chunk] == 2} {
set olc [lindex $chunk 0]
set nlc [lindex $chunk 1]
set nnl [expr {$nl + $nlc}]
lappend events [list $nl $nnl $pnum $olc $nlc]
incr ol $olc
set nl $nnl
} else {
incr ol [lindex $chunk 0]
incr nl [lindex $chunk 0]
}
}
}
}
if {$nl < $grouplineend} {
for {} {$nl < $grouplineend} {incr nl} {
set filelines($p,$f,$ol) $filelines($id,$f,$nl)
incr ol
}
}
set nlines [expr {$ol - $startline}]
$ctext insert end " -$startline,$nlines" msep
incr pnum
}
set nlines [expr {$grouplineend - $grouplinestart}]
$ctext insert end " +$grouplinestart,$nlines @@\n" msep
set events [lsort -integer -index 0 $events]
set nevents [llength $events]
set nmerge $nparents($diffmergeid)
set i 0
set l $grouplinestart
while {$i < $nevents} {
set nl [lindex $events $i 0]
while {$l < $nl} {
$ctext insert end " $filelines($id,$f,$l)\n"
incr l
}
set e [lindex $events $i]
set enl [lindex $e 1]
set j $i
set active {}
while 1 {
set pnum [lindex $e 2]
set olc [lindex $e 3]
set nlc [lindex $e 4]
if {![info exists delta($pnum)]} {
set delta($pnum) [expr {$olc - $nlc}]
lappend active $pnum
} else {
incr delta($pnum) [expr {$olc - $nlc}]
}
if {[incr j] >= $nevents} break
set e [lindex $events $j]
if {[lindex $e 0] >= $enl} break
if {[lindex $e 1] > $enl} {
set enl [lindex $e 1]
}
}
set nlc [expr {$enl - $l}]
set ncol mresult
if {[llength $active] == $nmerge - 1} {
for {set pnum 0} {$pnum < $nmerge} {incr pnum} {
if {![info exists delta($pnum)]} {
if {$pnum < $mergemax} {
lappend ncol m$pnum
} else {
lappend ncol mmax
}
break
}
}
}
set pnum -1
foreach p $parents($id) {
incr pnum
if {![info exists delta($pnum)]} continue
set olc [expr {$nlc + $delta($pnum)}]
set ol [expr {$l + $diffoffset($p)}]
incr diffoffset($p) $delta($pnum)
unset delta($pnum)
for {} {$olc > 0} {incr olc -1} {
$ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum
incr ol
}
}
for {} {$nlc > 0} {incr nlc -1} {
$ctext insert end "+$filelines($id,$f,$l)\n" $ncol
incr l
}
set i $j
}
while {$l < $grouplineend} {
$ctext insert end " $filelines($id,$f,$l)\n"
incr l
}
$ctext conf -state disabled
}
proc startdiff {ids} {