X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=gitk;h=faaffe13a0e8903fa84690c89d6b5a9473bae39d;hb=1abb3f14c872ac1b5b70db4334b21dde60e57b7a;hp=f33c3fa0cc369f9f8544b194564ab3305f4f0c1b;hpb=9ccbdfbfbcd26ab751e3edaa9ccd9dff278857c1;p=git.git diff --git a/gitk b/gitk index f33c3fa0..faaffe13 100755 --- a/gitk +++ b/gitk @@ -7,37 +7,50 @@ exec wish "$0" -- "${1+$@}" # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. -# CVS $Revision: 1.22 $ +# CVS $Revision: 1.24 $ proc getcommits {rargs} { global commits commfd phase canv mainfont global startmsecs nextupdate + global ctext maincursor textcursor leftover - if {$rargs == {}} { - set rargs HEAD - } set commits {} set phase getcommits set startmsecs [clock clicks -milliseconds] set nextupdate [expr $startmsecs + 100] - if [catch {set commfd [open "|git-rev-list --merge-order $rargs" r]} err] { + if [catch { + set parse_args [concat --default HEAD $rargs] + set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"] + }] { + # if git-rev-parse failed for some reason... + if {$rargs == {}} { + set rargs HEAD + } + set parsed_args $rargs + } + if [catch { + set commfd [open "|git-rev-list --header --merge-order $parsed_args" r] + } err] { puts stderr "Error executing git-rev-list: $err" exit 1 } - fconfigure $commfd -blocking 0 - fileevent $commfd readable "getcommitline $commfd" + set leftover {} + fconfigure $commfd -blocking 0 -translation binary + fileevent $commfd readable "getcommitlines $commfd" $canv delete all $canv create text 3 3 -anchor nw -text "Reading commits..." \ -font $mainfont -tags textitems + . config -cursor watch + $ctext config -cursor watch } -proc getcommitline {commfd} { - global commits parents cdate children nchildren ncleft +proc getcommitlines {commfd} { + global commits parents cdate children nchildren global commitlisted phase commitinfo nextupdate - global stopped redisplaying + global stopped redisplaying leftover - set n [gets $commfd line] - if {$n < 0} { + set stuff [read $commfd] + if {$stuff == {}} { if {![eof $commfd]} return # this works around what is apparently a bug in Tcl... fconfigure $commfd -blocking 1 @@ -56,34 +69,41 @@ to allow selection of commits to be displayed.)} error_popup $err exit 1 } - if {![regexp {^[0-9a-f]{40}$} $line id]} { - error_popup "Can't parse git-rev-list output: {$line}" - exit 1 - } - lappend commits $id - set commitlisted($id) 1 - if {![info exists commitinfo($id)]} { - readcommit $id - } - foreach p $parents($id) { - if {[info exists commitlisted($p)]} { - puts "oops, parent $p before child $id" + set start 0 + while 1 { + set i [string first "\0" $stuff $start] + if {$i < 0} { + set leftover [string range $stuff $start end] + return } - } - drawcommit $id - if {[clock clicks -milliseconds] >= $nextupdate} { - doupdate - } - while {$redisplaying} { - set redisplaying 0 - if {$stopped == 1} { - set stopped 0 - set phase "getcommits" - foreach id $commits { - drawcommit $id - if {$stopped} break - if {[clock clicks -milliseconds] >= $nextupdate} { - doupdate + set cmit [string range $stuff $start [expr {$i - 1}]] + if {$start == 0} { + set cmit "$leftover$cmit" + } + set start [expr {$i + 1}] + if {![regexp {^([0-9a-f]{40})\n} $cmit match id]} { + error_popup "Can't parse git-rev-list output: {$cmit}" + exit 1 + } + set cmit [string range $cmit 41 end] + lappend commits $id + set commitlisted($id) 1 + parsecommit $id $cmit 1 + drawcommit $id + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + } + while {$redisplaying} { + set redisplaying 0 + if {$stopped == 1} { + set stopped 0 + set phase "getcommits" + foreach id $commits { + drawcommit $id + if {$stopped} break + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate + } } } } @@ -96,12 +116,16 @@ proc doupdate {} { incr nextupdate 100 fileevent $commfd readable {} update - fileevent $commfd readable "getcommitline $commfd" + fileevent $commfd readable "getcommitlines $commfd" } proc readcommit {id} { + if [catch {set contents [exec git-cat-file commit $id]}] return + parsecommit $id $contents 0 +} + +proc parsecommit {id contents listed} { global commitinfo children nchildren parents nparents cdate ncleft - global noreadobj set inhdr 1 set comment {} @@ -117,13 +141,6 @@ proc readcommit {id} { } set parents($id) {} set nparents($id) 0 - if {$noreadobj} { - if [catch {set contents [exec git-cat-file commit $id]}] return - } else { - if [catch {set x [readobj $id]}] return - if {[lindex $x 0] != "commit"} return - set contents [lindex $x 1] - } foreach line [split $contents "\n"] { if {$inhdr} { if {$line == {}} { @@ -139,12 +156,11 @@ proc readcommit {id} { } lappend parents($id) $p incr nparents($id) - if {[lsearch -exact $children($p) $id] < 0} { + # sometimes we get a commit that lists a parent twice... + if {$listed && [lsearch -exact $children($p) $id] < 0} { lappend children($p) $id incr nchildren($p) incr ncleft($p) - } else { - puts "child $id already in $p's list??" } } elseif {$tag == "author"} { set x [expr {[llength $line] - 2}] @@ -158,10 +174,15 @@ proc readcommit {id} { } } else { if {$comment == {}} { - set headline $line + set headline [string trim $line] } else { append comment "\n" } + if {!$listed} { + # git-rev-list indents the comment by 4 spaces; + # if we got this via git-cat-file, add the indentation + append comment " " + } append comment $line } } @@ -238,6 +259,8 @@ proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont global findtype findloc findstring fstring geometry global entries sha1entry sha1string sha1but + global maincursor textcursor + global linectxmenu menu .bar .bar add cascade -label "File" -menu .bar.file @@ -377,6 +400,13 @@ proc makewindow {} { bind . "click %W" bind $fstring dofind bind $sha1entry gotocommit + + set maincursor [. cget -cursor] + set textcursor [$ctext cget -cursor] + + set linectxmenu .linectxmenu + menu $linectxmenu -tearoff 0 + $linectxmenu add command -label "Select" -command lineselect } # when we make a key binding for the toplevel, make sure @@ -512,7 +542,7 @@ Copyright Use and redistribute under the terms of the GNU General Public License -(CVS $Revision: 1.22 $)} \ +(CVS $Revision: 1.24 $)} \ -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 button $w.ok -text Close -command "destroy $w" @@ -522,9 +552,11 @@ Use and redistribute under the terms of the GNU General Public License proc assigncolor {id} { global commitinfo colormap commcolors colors nextcolor global parents nparents children nchildren + global cornercrossings crossings + if [info exists colormap($id)] return set ncolors [llength $colors] - if {$nparents($id) == 1 && $nchildren($id) == 1} { + if {$nparents($id) <= 1 && $nchildren($id) == 1} { set child [lindex $children($id) 0] if {[info exists colormap($child)] && $nparents($child) == 1} { @@ -533,22 +565,50 @@ proc assigncolor {id} { } } set badcolors {} - foreach child $children($id) { - if {[info exists colormap($child)] - && [lsearch -exact $badcolors $colormap($child)] < 0} { - lappend badcolors $colormap($child) + if {[info exists cornercrossings($id)]} { + foreach x $cornercrossings($id) { + if {[info exists colormap($x)] + && [lsearch -exact $badcolors $colormap($x)] < 0} { + lappend badcolors $colormap($x) + } + } + if {[llength $badcolors] >= $ncolors} { + set badcolors {} } - if {[info exists parents($child)]} { - foreach p $parents($child) { - if {[info exists colormap($p)] - && [lsearch -exact $badcolors $colormap($p)] < 0} { - lappend badcolors $colormap($p) + } + set origbad $badcolors + if {[llength $badcolors] < $ncolors - 1} { + if {[info exists crossings($id)]} { + foreach x $crossings($id) { + if {[info exists colormap($x)] + && [lsearch -exact $badcolors $colormap($x)] < 0} { + lappend badcolors $colormap($x) } } + if {[llength $badcolors] >= $ncolors} { + set badcolors $origbad + } } + set origbad $badcolors } - if {[llength $badcolors] >= $ncolors} { - set badcolors {} + if {[llength $badcolors] < $ncolors - 1} { + 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 $origbad + } } for {set i 0} {$i <= $ncolors} {incr i} { set c [lindex $colors $nextcolor] @@ -562,7 +622,7 @@ proc assigncolor {id} { proc initgraph {} { global canvy canvy0 lineno numcommits lthickness nextcolor linespc - global linestarty + global mainline sidelines global nchildren ncleft allcanvs delete all @@ -571,21 +631,30 @@ proc initgraph {} { set lineno -1 set numcommits 0 set lthickness [expr {int($linespc / 9) + 1}] - catch {unset linestarty} + catch {unset mainline} + catch {unset sidelines} foreach id [array names nchildren] { set ncleft($id) $nchildren($id) } } +proc bindline {t id} { + global canv + + $canv bind $t "linemenu %X %Y $id" + $canv bind $t "lineenter %x %y $id" + $canv bind $t "linemotion %x %y $id" + $canv bind $t "lineleave $id" +} + proc drawcommitline {level} { - global parents children nparents nchildren ncleft todo + global parents children nparents nchildren todo global canv canv2 canv3 mainfont namefont canvx0 canvy linespc - global datemode cdate global lineid linehtag linentag linedtag commitinfo - global colormap numcommits currentparents + global colormap numcommits currentparents dupparents global oldlevel oldnlines oldtodo global idtags idline idheads - global lineno lthickness linestarty + global lineno lthickness mainline sidelines global commitlisted incr numcommits @@ -601,19 +670,40 @@ proc drawcommitline {level} { set nparents($id) 0 } } + assigncolor $id set currentparents {} + set dupparents {} if {[info exists commitlisted($id)] && [info exists parents($id)]} { - set currentparents $parents($id) + foreach p $parents($id) { + if {[lsearch -exact $currentparents $p] < 0} { + lappend currentparents $p + } else { + # remember that this parent was listed twice + lappend dupparents $p + } + } } set x [expr $canvx0 + $level * $linespc] set y1 $canvy set canvy [expr $canvy + $linespc] allcanvs conf -scrollregion \ [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]] - if {[info exists linestarty($id)] && $linestarty($id) < $y1} { - set t [$canv create line $x $linestarty($id) $x $y1 \ + if {[info exists mainline($id)]} { + lappend mainline($id) $x $y1 + set t [$canv create line $mainline($id) \ -width $lthickness -fill $colormap($id)] $canv lower $t + bindline $t $id + } + if {[info exists sidelines($id)]} { + foreach ls $sidelines($id) { + set coords [lindex $ls 0] + set thick [lindex $ls 1] + set t [$canv create line $coords -fill $colormap($id) \ + -width [expr {$thick * $lthickness}]] + $canv lower $t + bindline $t $id + } } set orad [expr {$linespc / 3}] set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \ @@ -621,8 +711,8 @@ proc drawcommitline {level} { -fill $ofill -outline black -width 1] $canv raise $t set xt [expr $canvx0 + [llength $todo] * $linespc] - if {$nparents($id) > 2} { - set xt [expr {$xt + ($nparents($id) - 2) * $linespc}] + if {[llength $currentparents] > 2} { + set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}] } set marks {} set ntags 0 @@ -678,36 +768,32 @@ proc drawcommitline {level} { } proc updatetodo {level noshortcut} { - global datemode currentparents ncleft todo - global linestarty oldlevel oldtodo oldnlines - global canvy linespc + global currentparents ncleft todo + global mainline oldlevel oldtodo oldnlines + global canvx0 canvy linespc mainline global commitinfo - foreach p $currentparents { - if {![info exists commitinfo($p)]} { - readcommit $p - } - } + set oldlevel $level + set oldtodo $todo + set oldnlines [llength $todo] if {!$noshortcut && [llength $currentparents] == 1} { set p [lindex $currentparents 0] - if {$ncleft($p) == 0 && [lsearch -exact $todo $p] < 0} { - assigncolor $p - set linestarty($p) [expr $canvy - $linespc] + if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} { + set ncleft($p) 0 + set x [expr $canvx0 + $level * $linespc] + set y [expr $canvy - $linespc] + set mainline($p) [list $x $y] set todo [lreplace $todo $level $level $p] return 0 } } - set oldlevel $level - set oldtodo $todo - set oldnlines [llength $todo] set todo [lreplace $todo $level $level] set i $level foreach p $currentparents { incr ncleft($p) -1 set k [lsearch -exact $todo $p] if {$k < 0} { - assigncolor $p set todo [linsert $todo $i $p] incr i } @@ -715,9 +801,37 @@ proc updatetodo {level noshortcut} { return 1 } +proc notecrossings {id lo hi corner} { + global oldtodo crossings cornercrossings + + for {set i $lo} {[incr i] < $hi} {} { + set p [lindex $oldtodo $i] + if {$p == {}} continue + if {$i == $corner} { + if {![info exists cornercrossings($id)] + || [lsearch -exact $cornercrossings($id) $p] < 0} { + lappend cornercrossings($id) $p + } + if {![info exists cornercrossings($p)] + || [lsearch -exact $cornercrossings($p) $id] < 0} { + lappend cornercrossings($p) $id + } + } else { + if {![info exists crossings($id)] + || [lsearch -exact $crossings($id) $p] < 0} { + lappend crossings($id) $p + } + if {![info exists crossings($p)] + || [lsearch -exact $crossings($p) $id] < 0} { + lappend crossings($p) $id + } + } + } +} + proc drawslants {} { - global canv linestarty canvx0 canvy linespc - global oldlevel oldtodo todo currentparents + global canv mainline sidelines canvx0 canvy linespc + global oldlevel oldtodo todo currentparents dupparents global lthickness linespc canvy colormap set y1 [expr $canvy - $linespc] @@ -730,37 +844,39 @@ proc drawslants {} { if {$i == $oldlevel} { foreach p $currentparents { set j [lsearch -exact $todo $p] - if {$i == $j && ![info exists linestarty($p)]} { - set linestarty($p) $y1 - } else { - set xj [expr {$canvx0 + $j * $linespc}] - set coords [list $xi $y1] - if {$j < $i - 1} { - lappend coords [expr $xj + $linespc] $y1 - } elseif {$j > $i + 1} { - lappend coords [expr $xj - $linespc] $y1 - } + set coords [list $xi $y1] + set xj [expr {$canvx0 + $j * $linespc}] + if {$j < $i - 1} { + lappend coords [expr $xj + $linespc] $y1 + notecrossings $p $j $i [expr {$j + 1}] + } elseif {$j > $i + 1} { + lappend coords [expr $xj - $linespc] $y1 + notecrossings $p $i $j [expr {$j - 1}] + } + if {[lsearch -exact $dupparents $p] >= 0} { + # draw a double-width line to indicate the doubled parent lappend coords $xj $y2 - set t [$canv create line $coords -width $lthickness \ - -fill $colormap($p)] - $canv lower $t - if {![info exists linestarty($p)]} { - set linestarty($p) $y2 + lappend sidelines($p) [list $coords 2] + if {![info exists mainline($p)]} { + set mainline($p) [list $xj $y2] + } + } else { + # normal case, no parent duplicated + if {![info exists mainline($p)]} { + if {$i != $j} { + lappend coords $xj $y2 + } + set mainline($p) $coords + } else { + lappend coords $xj $y2 + lappend sidelines($p) [list $coords 1] } } } } elseif {[lindex $todo $i] != $id} { set j [lsearch -exact $todo $id] set xj [expr {$canvx0 + $j * $linespc}] - set coords {} - if {[info exists linestarty($id)] && $linestarty($id) < $y1} { - lappend coords $xi $linestarty($id) - } - lappend coords $xi $y1 $xj $y2 - set t [$canv create line $coords -width $lthickness \ - -fill $colormap($id)] - $canv lower $t - set linestarty($id) $y2 + lappend mainline($id) $xi $y1 $xj $y2 } } } @@ -801,7 +917,7 @@ proc decidenext {} { if {$todo != {}} { puts "ERROR: none of the pending commits can be done yet:" foreach p $todo { - puts " $p" + puts " $p ($ncleft($p))" } } return -1 @@ -840,14 +956,12 @@ proc drawcommit {id} { set todo $id set startcommits $id initgraph - assigncolor $id drawcommitline 0 updatetodo 0 $datemode } else { if {$nchildren($id) == 0} { lappend todo $id lappend startcommits $id - assigncolor $id } set level [decidenext] if {$id != [lindex $todo $level]} { @@ -874,6 +988,7 @@ proc drawcommit {id} { proc finishcommits {} { global phase global startcommits + global ctext maincursor textcursor if {$phase != "incrdraw"} { $canv delete all @@ -885,6 +1000,8 @@ proc finishcommits {} { drawslants set level [decidenext] drawrest $level [llength $startcommits] + . config -cursor $maincursor + $ctext config -cursor $textcursor } proc drawgraph {} { @@ -904,39 +1021,41 @@ proc drawrest {level startix} { global numcommits global nextupdate startmsecs startcommits idline - set phase drawgraph - set startid [lindex $startcommits $startix] - set startline -1 - if {$startid != {}} { - set startline $idline($startid) - } - while 1 { - if {$stopped} break - drawcommitline $level - set hard [updatetodo $level $datemode] - if {$numcommits == $startline} { - lappend todo $startid - set hard 1 - incr startix - set startid [lindex $startcommits $startix] - set startline -1 - if {$startid != {}} { - set startline $idline($startid) - } - } - if {$hard} { - set level [decidenext] - if {$level < 0} break - drawslants + if {$level >= 0} { + set phase drawgraph + set startid [lindex $startcommits $startix] + set startline -1 + if {$startid != {}} { + set startline $idline($startid) } - if {[clock clicks -milliseconds] >= $nextupdate} { - update - incr nextupdate 100 + while 1 { + if {$stopped} break + drawcommitline $level + set hard [updatetodo $level $datemode] + if {$numcommits == $startline} { + lappend todo $startid + set hard 1 + incr startix + set startid [lindex $startcommits $startix] + set startline -1 + if {$startid != {}} { + set startline $idline($startid) + } + } + if {$hard} { + set level [decidenext] + if {$level < 0} break + drawslants + } + if {[clock clicks -milliseconds] >= $nextupdate} { + update + incr nextupdate 100 + } } } set phase {} set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs] - puts "overall $drawmsecs ms for $numcommits commits" + #puts "overall $drawmsecs ms for $numcommits commits" if {$redisplaying} { if {$stopped == 0 && [info exists selectedline]} { selectline $selectedline @@ -1121,6 +1240,7 @@ proc selectline {l} { global canvy0 linespc nparents treepending global cflist treediffs currentid sha1entry global commentend seenfile idtags + $canv delete hover if {![info exists lineid($l)] || ![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ @@ -1471,6 +1591,82 @@ proc gotocommit {} { error_popup "$type $sha1string is not known" } +proc linemenu {x y id} { + global linectxmenu linemenuid + set linemenuid $id + $linectxmenu post $x $y +} + +proc lineselect {} { + global linemenuid idline + if {[info exists linemenuid] && [info exists idline($linemenuid)]} { + selectline $idline($linemenuid) + } +} + +proc lineenter {x y id} { + global hoverx hovery hoverid hovertimer + global commitinfo canv + + if {![info exists commitinfo($id)]} return + set hoverx $x + set hovery $y + set hoverid $id + if {[info exists hovertimer]} { + after cancel $hovertimer + } + set hovertimer [after 500 linehover] + $canv delete hover +} + +proc linemotion {x y id} { + global hoverx hovery hoverid hovertimer + + if {[info exists hoverid] && $id == $hoverid} { + set hoverx $x + set hovery $y + if {[info exists hovertimer]} { + after cancel $hovertimer + } + set hovertimer [after 500 linehover] + } +} + +proc lineleave {id} { + global hoverid hovertimer canv + + if {[info exists hoverid] && $id == $hoverid} { + $canv delete hover + if {[info exists hovertimer]} { + after cancel $hovertimer + unset hovertimer + } + unset hoverid + } +} + +proc linehover {} { + global hoverx hovery hoverid hovertimer + global canv linespc lthickness + global commitinfo mainfont + + set text [lindex $commitinfo($hoverid) 0] + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax == {}} return + set yfrac [lindex [$canv yview] 0] + set x [expr {$hoverx + 2 * $linespc}] + set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}] + set x0 [expr {$x - 2 * $lthickness}] + set y0 [expr {$y - 2 * $lthickness}] + set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}] + set y1 [expr {$y + $linespc + 2 * $lthickness}] + set t [$canv create rectangle $x0 $y0 $x1 $y1 \ + -fill \#ffff80 -outline black -width 1 -tags hover] + $canv raise $t + set t [$canv create text $x $y -anchor nw -text $text -tags hover] + $canv raise $t +} + proc doquit {} { global stopped set stopped 100 @@ -1506,8 +1702,6 @@ foreach arg $argv { } } -set noreadobj [load libreadobj.so.0.0] -set noreadobj 0 set stopped 0 set redisplaying 0 set stuffsaved 0