X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=gitk;h=5ebcf3377ebf0baba09386fde57df153f9415191;hb=df076bdbccd26ccaf49fc332303f512403c8cde6;hp=a1d65fa87a09fee306dfe86ad1aed77758bfeaf0;hpb=b74fd579662c9d05db5cfb4b0e2b95f8919b9916;p=git.git diff --git a/gitk b/gitk index a1d65fa8..5ebcf337 100755 --- a/gitk +++ b/gitk @@ -37,7 +37,7 @@ proc getcommits {rargs} { set parsed_args $rargs } if [catch { - set commfd [open "|git-rev-list --header --merge-order $parsed_args" r] + set commfd [open "|git-rev-list --header --topo-order $parsed_args" r] } err] { puts stderr "Error executing git-rev-list: $err" exit 1 @@ -60,7 +60,7 @@ proc getcommitlines {commfd} { set stuff [read $commfd] if {$stuff == {}} { if {![eof $commfd]} return - # this works around what is apparently a bug in Tcl... + # set it blocking so we wait for the process to terminate fconfigure $commfd -blocking 1 if {![catch {close $commfd} err]} { after idle finishcommits @@ -273,7 +273,7 @@ proc makewindow {} { global findtype findtypemenu findloc findstring fstring geometry global entries sha1entry sha1string sha1but global maincursor textcursor - global rowctxmenu + global rowctxmenu gaudydiff menu .bar .bar add cascade -label "File" -menu .bar.file @@ -364,11 +364,17 @@ proc makewindow {} { 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 + $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa" + if {$gaudydiff} { + $ctext tag conf hunksep -back blue -fore white + $ctext tag conf d0 -back "#ff8080" + $ctext tag conf d1 -back green + } else { + $ctext tag conf hunksep -fore blue + $ctext tag conf d0 -fore red + $ctext tag conf d1 -fore "#00a000" + $ctext tag conf found -back yellow + } frame .ctop.cdet.right set cflist .ctop.cdet.right.cfiles @@ -465,8 +471,10 @@ proc savestuff {w} { if {![winfo viewable .]} return catch { set f [open "~/.gitk-new" w] - puts $f "set mainfont {$mainfont}" - puts $f "set textfont {$textfont}" + puts $f [list set mainfont $mainfont] + puts $f [list set textfont $textfont] + puts $f [list set findmergefiles $findmergefiles] + puts $f [list set gaudydiff $gaudydiff] 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]" @@ -1291,6 +1299,7 @@ proc findpatches {} { global findstring selectedline numcommits global findprocpid findprocfile global finddidsel ctext lineid findinprogress + global findinsertpos if {$numcommits == 0} return @@ -1317,6 +1326,7 @@ proc findpatches {} { return } + set findinsertpos end set findprocfile $f set findprocpid [pid $f] fconfigure $f -blocking 0 @@ -1329,7 +1339,7 @@ proc findpatches {} { proc readfindproc {} { global findprocfile finddidsel - global idline matchinglines + global idline matchinglines findinsertpos set n [gets $findprocfile line] if {$n < 0} { @@ -1351,7 +1361,24 @@ proc readfindproc {} { 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 @@ -1359,9 +1386,11 @@ proc readfindproc {} { } 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 @@ -1371,15 +1400,107 @@ proc findfiles {} { 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} { @@ -1397,9 +1518,6 @@ proc findcont {ids} { if {![info exists treediffs($ids)]} { set findids $ids set ffileline $l - if {![info exists treepending]} { - gettreediffs $ids - } return } set doesmatch 0 @@ -1411,12 +1529,7 @@ proc findcont {ids} { } } if {$doesmatch} { - lappend matchinglines $l - markheadline $l $id - if {!$finddidsel} { - findselectline $l - set finddidsel 1 - } + insertmatch $l $id set pi $nparents($id) } } else { @@ -1496,8 +1609,8 @@ proc selectline {l} { 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 @@ -1550,7 +1663,6 @@ proc selectline {l} { 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 @@ -1580,21 +1692,33 @@ proc selectline {l} { $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 } } @@ -1607,9 +1731,13 @@ proc selnextline {dir} { } 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 } @@ -1626,7 +1754,7 @@ proc gettreediffs {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 @@ -1639,15 +1767,6 @@ proc gettreediffline {gdtf ids} { addtocflist $ids } } - if {[info exists findids]} { - if {$ids != $findids} { - if {![info exists treepending]} { - gettreediffs $findids - } - } else { - findcont $ids - } - } return } set file [lindex $line 5] @@ -1655,8 +1774,8 @@ proc gettreediffline {gdtf ids} { } 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] @@ -1665,51 +1784,44 @@ proc getblobdiffs {ids} { 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 + global gaudydiff 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 @@ -1721,37 +1833,33 @@ proc getblobdiffline {bdf ids} { 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 + if {$gaudydiff} { + $ctext insert end "\t" hunksep + $ctext insert end " $f1l " d0 " $f2l " d1 + $ctext insert end " $rest \n" hunksep + } else { + $ctext insert end "$line\n" hunksep + } + set diffinhdr 0 } else { set x [string range $line 0 0] if {$x == "-" || $x == "+"} { set tag [expr {$x == "+"}] - set line [string range $line 1 end] + if {$gaudydiff} { + set line [string range $line 1 end] + } $ctext insert end "$line\n" d$tag } elseif {$x == " "} { - set line [string range $line 1 end] + if {$gaudydiff} { + 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 { @@ -1759,7 +1867,6 @@ proc getblobdiffline {bdf ids} { 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 } @@ -1787,7 +1894,7 @@ proc nextfile {} { } 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 @@ -1859,18 +1966,35 @@ proc sha1change {n1 n2 op} { proc gotocommit {} { global sha1string currentid idline tagids + global lineid numcommits + if {$sha1string == {} || ([info exists currentid] && $sha1string == $currentid)} return if {[info exists tagids($sha1string)]} { set id $tagids($sha1string) } else { set id [string tolower $sha1string] + if {[regexp {^[0-9a-f]{4,39}$} $id]} { + set matches {} + for {set l 0} {$l < $numcommits} {incr l} { + if {[string match $id* $lineid($l)]} { + lappend matches $lineid($l) + } + } + if {$matches ne {}} { + if {[llength $matches] > 1} { + error_popup "Short SHA1 id $id is ambiguous" + return + } + set id [lindex $matches 0] + } + } } if {[info exists idline($id)]} { selectline $idline($id) return } - if {[regexp {^[0-9a-fA-F]{40}$} $sha1string]} { + if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} { set type "SHA1 id" } else { set type "Tag" @@ -2009,7 +2133,7 @@ proc rowmenu {x y id} { proc diffvssel {dirn} { global rowmenuid selectedline lineid global ctext cflist - global diffids commitinfo + global commitinfo if {![info exists selectedline]} return if {$dirn} { @@ -2033,8 +2157,7 @@ proc diffvssel {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 {} { @@ -2273,6 +2396,7 @@ set wrcomcmd "git-diff-tree --stdin -p --pretty" set mainfont {Helvetica 9} set textfont {Courier 9} set findmergefiles 0 +set gaudydiff 0 set colors {green red blue magenta darkgrey brown orange}