global findstring selectedline numcommits
global findprocpid findprocfile
global finddidsel ctext lineid findinprogress
+ global findinsertpos
if {$numcommits == 0} return
return
}
+ set findinsertpos end
set findprocfile $f
set findprocpid [pid $f]
fconfigure $f -blocking 0
proc readfindproc {} {
global findprocfile finddidsel
- global idline matchinglines
+ global idline matchinglines findinsertpos
set n [gets $findprocfile line]
if {$n < 0} {
return
}
set l $idline($id)
- lappend matchinglines $l
+ insertmatch $l $id
+}
+
+proc insertmatch {l id} {
+ global matchinglines findinsertpos finddidsel
+
+ if {$findinsertpos == "end"} {
+ if {$matchinglines != {} && $l < [lindex $matchinglines 0]} {
+ set matchinglines [linsert $matchinglines 0 $l]
+ set findinsertpos 1
+ } else {
+ lappend matchinglines $l
+ }
+ } else {
+ set matchinglines [linsert $matchinglines $findinsertpos $l]
+ incr findinsertpos
+ }
+ markheadline $l $id
if {!$finddidsel} {
findselectline $l
set finddidsel 1
}
proc findfiles {} {
- global selectedline numcommits lineid
- global ffileline finddidsel parents findstartline
- global findinprogress ctext
+ global selectedline numcommits lineid ctext
+ global ffileline finddidsel parents nparents
+ global findinprogress findstartline findinsertpos
+ global treediffs fdiffids fdiffsneeded fdiffpos
+ global findmergefiles
if {$numcommits == 0} return
set l 0
}
set ffileline $l
- set finddidsel 0
set findstartline $l
+ set diffsneeded {}
+ set fdiffsneeded {}
+ while 1 {
+ set id $lineid($l)
+ if {$findmergefiles || $nparents($id) == 1} {
+ foreach p $parents($id) {
+ if {![info exists treediffs([list $id $p])]} {
+ append diffsneeded "$id $p\n"
+ lappend fdiffsneeded [list $id $p]
+ }
+ }
+ }
+ if {[incr l] >= $numcommits} {
+ set l 0
+ }
+ if {$l == $findstartline} break
+ }
+
+ # start off a git-diff-tree process if needed
+ if {$diffsneeded ne {}} {
+ if {[catch {
+ set df [open [list | git-diff-tree -r --stdin << $diffsneeded] r]
+ } err ]} {
+ error_popup "Error starting search process: $err"
+ return
+ }
+ catch {unset fdiffids}
+ set fdiffpos 0
+ fconfigure $df -blocking 0
+ fileevent $df readable [list readfilediffs $df]
+ }
+
+ set finddidsel 0
+ set findinsertpos end
set id $lineid($l)
set p [lindex $parents($id) 0]
. config -cursor watch
$ctext config -cursor watch
set findinprogress 1
- update
findcont [list $id $p]
+ update
+}
+
+proc readfilediffs {df} {
+ global findids fdiffids fdiffs
+
+ set n [gets $df line]
+ if {$n < 0} {
+ if {[eof $df]} {
+ donefilediff
+ if {[catch {close $df} err]} {
+ stopfindproc
+ bell
+ error_popup "Error in git-diff-tree: $err"
+ } elseif {[info exists findids]} {
+ set ids $findids
+ stopfindproc
+ bell
+ error_popup "Couldn't find diffs for {$ids}"
+ }
+ }
+ return
+ }
+ if {[regexp {^([0-9a-f]{40}) \(from ([0-9a-f]{40})\)} $line match id p]} {
+ # start of a new string of diffs
+ donefilediff
+ set fdiffids [list $id $p]
+ set fdiffs {}
+ } elseif {[string match ":*" $line]} {
+ lappend fdiffs [lindex $line 5]
+ }
+}
+
+proc donefilediff {} {
+ global fdiffids fdiffs treediffs findids
+ global fdiffsneeded fdiffpos
+
+ if {[info exists fdiffids]} {
+ while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids
+ && $fdiffpos < [llength $fdiffsneeded]} {
+ # git-diff-tree doesn't output anything for a commit
+ # which doesn't change anything
+ set nullids [lindex $fdiffsneeded $fdiffpos]
+ set treediffs($nullids) {}
+ if {[info exists findids] && $nullids eq $findids} {
+ unset findids
+ findcont $nullids
+ }
+ incr fdiffpos
+ }
+ incr fdiffpos
+
+ if {![info exists treediffs($fdiffids)]} {
+ set treediffs($fdiffids) $fdiffs
+ }
+ if {[info exists findids] && $fdiffids eq $findids} {
+ unset findids
+ findcont $fdiffids
+ }
+ }
}
proc findcont {ids} {
if {![info exists treediffs($ids)]} {
set findids $ids
set ffileline $l
- if {![info exists treepending]} {
- gettreediffs $ids
- }
return
}
set doesmatch 0
}
}
if {$doesmatch} {
- lappend matchinglines $l
- markheadline $l $id
- if {!$finddidsel} {
- findselectline $l
- set finddidsel 1
- }
+ insertmatch $l $id
set pi $nparents($id)
}
} else {
global canv canv2 canv3 ctext commitinfo selectedline
global lineid linehtag linentag linedtag
global canvy0 linespc parents nparents
- global cflist currentid sha1entry diffids
- global commentend seenfile idtags
+ global cflist currentid sha1entry
+ global commentend idtags
$canv delete hover
if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
$canv delete secsel
set id $lineid($l)
set currentid $id
- set diffids [concat $id $parents($id)]
$sha1entry delete 0 end
$sha1entry insert 0 $id
$sha1entry selection from 0
$cflist delete 0 end
$cflist insert end "Comments"
- if {$nparents($id) == 1} {
- startdiff
- }
- catch {unset seenfile}
+ startdiff $id $parents($id)
}
-proc startdiff {} {
+proc startdiff {id vs} {
+ global diffpending diffpindex
+ global diffindex difffilestart
+ global curdifftag curtagstart
+
+ set diffpending $vs
+ set diffpindex 0
+ set diffindex 0
+ catch {unset difffilestart}
+ set curdifftag Comments
+ set curtagstart 0.0
+ contdiff [list $id [lindex $vs 0]]
+}
+
+proc contdiff {ids} {
global treediffs diffids treepending
- if {![info exists treediffs($diffids)]} {
+ set diffids $ids
+ if {![info exists treediffs($ids)]} {
if {![info exists treepending]} {
- gettreediffs $diffids
+ gettreediffs $ids
}
} else {
- addtocflist $diffids
+ addtocflist $ids
}
}
}
proc addtocflist {ids} {
- global treediffs cflist
+ global treediffs cflist diffpindex
+
+ set colors {black blue green red cyan magenta}
+ set color [lindex $colors [expr {$diffpindex % [llength $colors]}]]
foreach f $treediffs($ids) {
$cflist insert end $f
+ $cflist itemconf end -foreground $color
}
getblobdiffs $ids
}
}
proc gettreediffline {gdtf ids} {
- global treediffs treepending diffids findids
+ global treediffs treepending diffids
set n [gets $gdtf line]
if {$n < 0} {
if {![eof $gdtf]} return
addtocflist $ids
}
}
- if {[info exists findids]} {
- if {$ids != $findids} {
- if {![info exists treepending]} {
- gettreediffs $findids
- }
- } else {
- findcont $ids
- }
- }
return
}
set file [lindex $line 5]
}
proc getblobdiffs {ids} {
- global diffopts blobdifffd env curdifftag curtagstart
- global diffindex difffilestart nextupdate
+ global diffopts blobdifffd diffids env
+ global nextupdate diffinhdr
set id [lindex $ids 0]
set p [lindex $ids 1]
puts "error getting diffs: $err"
return
}
+ set diffinhdr 0
fconfigure $bdf -blocking 0
set blobdifffd($ids) $bdf
- set curdifftag Comments
- set curtagstart 0.0
- set diffindex 0
- catch {unset difffilestart}
- fileevent $bdf readable "getblobdiffline $bdf {$ids}"
+ fileevent $bdf readable [list getblobdiffline $bdf $ids]
set nextupdate [expr {[clock clicks -milliseconds] + 100}]
}
proc getblobdiffline {bdf ids} {
- global diffids blobdifffd ctext curdifftag curtagstart seenfile
+ global diffids blobdifffd ctext curdifftag curtagstart
global diffnexthead diffnextnote diffindex difffilestart
- global nextupdate
+ global nextupdate diffpending diffpindex diffinhdr
set n [gets $bdf line]
if {$n < 0} {
if {[eof $bdf]} {
close $bdf
- if {[info exists diffids] && $ids == $diffids
- && $bdf == $blobdifffd($ids)} {
+ if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
$ctext tag add $curdifftag $curtagstart end
- set seenfile($curdifftag) 1
- unset diffids
+ if {[incr diffpindex] < [llength $diffpending]} {
+ set id [lindex $ids 0]
+ set p [lindex $diffpending $diffpindex]
+ contdiff [list $id $p]
+ }
}
}
return
}
- if {![info exists diffids] || $ids != $diffids
- || $bdf != $blobdifffd($ids)} {
+ if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
return
}
$ctext conf -state normal
- if {[regexp {^---[ \t]+([^/])*/(.*)} $line match s1 fname]} {
+ if {[regexp {^diff --git a/(.*) b/} $line match fname]} {
# 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 here [$ctext index "end - 1c"]
set difffilestart($diffindex) $here
incr diffindex
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"
+ set diffinhdr 1
+ } elseif {[regexp {^(---|\+\+\+)} $line]} {
+ set diffinhdr 0
} 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
+ set diffinhdr 0
} else {
set x [string range $line 0 0]
if {$x == "-" || $x == "+"} {
} elseif {$x == " "} {
set line [string range $line 1 end]
$ctext insert end "$line\n"
- } elseif {$x == "\\"} {
+ } elseif {$diffinhdr || $x == "\\"} {
# e.g. "\ No newline at end of file"
$ctext insert end "$line\n" filesep
} else {
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
}
}
proc listboxsel {} {
- global ctext cflist currentid treediffs seenfile
+ global ctext cflist currentid treediffs
if {![info exists currentid]} return
set sel [lsort [$cflist curselection]]
if {$sel eq {}} return
proc diffvssel {dirn} {
global rowmenuid selectedline lineid
global ctext cflist
- global diffids commitinfo
+ global commitinfo
if {![info exists selectedline]} return
if {$dirn} {
$ctext conf -state disabled
$ctext tag delete Comments
$ctext tag remove found 1.0 end
- set diffids [list $newid $oldid]
- startdiff
+ startdiff [list $newid $oldid]
}
proc mkpatch {} {