From 4fb0fa197e14c82d64adb292320f9444d7ac46c5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 4 Jul 2007 19:43:51 +1000 Subject: [PATCH 1/7] gitk: Fix the find and highlight functions This reworks the way that the "Find" button (and the /, ?, ^F, and ^G keys) works. Previously, pressing the "Find" button would cause gitk to go off and scan through every commit to see which commits matched, and the user interface was completely unreponsive during that time. Now the searching is done in chunks using the scheduler, so the UI still responds, and the search stops as soon as a matching commit is found. The highlighting of matches using a yellow background is now done in the commit-drawing code and the highlighting code. This ensures that all the commits that are visible that match are highlighted without the search code having to find them all. This also fixes a bug where previously-drawn commits that need to be highlighted were not being highlighted. Signed-off-by: Paul Mackerras --- gitk | 323 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 185 insertions(+), 138 deletions(-) diff --git a/gitk b/gitk index 2d6a6ef9c..d50914549 100755 --- a/gitk +++ b/gitk @@ -1758,7 +1758,7 @@ proc showview {n} { global colormap rowtextx commitrow nextcolor canvxmax global numcommits rowrangelist commitlisted idrowranges rowchk global selectedline currentid canv canvy0 - global matchinglines treediffs + global treediffs global pending_select phase global commitidx rowlaidout rowoptim global commfd @@ -1802,7 +1802,6 @@ proc showview {n} { [list {} $rowidlist $rowoffsets $rowrangelist] } } - catch {unset matchinglines} catch {unset treediffs} clear_display if {[info exists hlview] && $hlview == $n} { @@ -2132,7 +2131,7 @@ proc readfhighlight {} { proc find_change {name ix op} { global nhighlights mainfont boldnamerows - global findstring findpattern findtype + global findstring findpattern findtype markingmatches # delete previous highlights, if any foreach row $boldnamerows { @@ -2141,17 +2140,32 @@ proc find_change {name ix op} { set boldnamerows {} catch {unset nhighlights} unbolden + unmarkmatches if {$findtype ne "Regexp"} { set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \ $findstring] set findpattern "*$e*" } + set markingmatches [expr {$findstring ne {}}] drawvisible } +proc doesmatch {f} { + global findtype findstring findpattern + + if {$findtype eq "Regexp"} { + return [regexp $findstring $f] + } elseif {$findtype eq "IgnCase"} { + return [string match -nocase $findpattern $f] + } else { + return [string match $findpattern $f] + } +} + proc askfindhighlight {row id} { global nhighlights commitinfo iddrawn mainfont - global findstring findtype findloc findpattern + global findloc + global markingmatches if {![info exists commitinfo($id)]} { getcommit $id @@ -2160,35 +2174,47 @@ proc askfindhighlight {row id} { set isbold 0 set fldtypes {Headline Author Date Committer CDate Comments} foreach f $info ty $fldtypes { - if {$findloc ne "All fields" && $findloc ne $ty} { - continue - } - if {$findtype eq "Regexp"} { - set doesmatch [regexp $findstring $f] - } elseif {$findtype eq "IgnCase"} { - set doesmatch [string match -nocase $findpattern $f] - } else { - set doesmatch [string match $findpattern $f] - } - if {$doesmatch} { + if {($findloc eq "All fields" || $findloc eq $ty) && + [doesmatch $f]} { if {$ty eq "Author"} { set isbold 2 - } else { - set isbold 1 + break } + set isbold 1 } } - if {[info exists iddrawn($id)]} { - if {$isbold && ![ishighlighted $row]} { - bolden $row [concat $mainfont bold] + if {$isbold && [info exists iddrawn($id)]} { + set f [concat $mainfont bold] + if {![ishighlighted $row]} { + bolden $row $f + if {$isbold > 1} { + bolden_name $row $f + } } - if {$isbold >= 2} { - bolden_name $row [concat $mainfont bold] + if {$markingmatches} { + markrowmatches $row [lindex $info 0] [lindex $info 1] } } set nhighlights($row) $isbold } +proc markrowmatches {row headline author} { + global canv canv2 linehtag linentag + + $canv delete match$row + $canv2 delete match$row + set m [findmatches $headline] + if {$m ne {}} { + markmatches $canv $row $headline $linehtag($row) $m \ + [$canv itemcget $linehtag($row) -font] + } + set m [findmatches $author] + if {$m ne {}} { + markmatches $canv2 $row $author $linentag($row) $m \ + [$canv2 itemcget $linentag($row) -font] + } +} + proc vrel_change {name ix op} { global highlight_related @@ -3309,7 +3335,7 @@ proc drawcmittext {id row col} { global linespc canv canv2 canv3 canvy0 fgcolor global commitlisted commitinfo rowidlist parentlist global rowtextx idpos idtags idheads idotherrefs - global linehtag linentag linedtag + global linehtag linentag linedtag markingmatches global mainfont canvxmax boldrows boldnamerows fgcolor nullid if {$id eq $nullid} { @@ -3366,6 +3392,9 @@ proc drawcmittext {id row col} { set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \ -text $date -font $mainfont -tags text] set xr [expr {$xt + [font measure $mainfont $headline]}] + if {$markingmatches} { + markrowmatches $row $headline $name + } if {$xr > $canvxmax} { set canvxmax $xr setcanvscroll @@ -3436,9 +3465,7 @@ proc drawcommits {row {endrow {}}} { for {} {$r <= $er} {incr r} { set id [lindex $displayorder $r] set wasdrawn [info exists iddrawn($id)] - if {!$wasdrawn} { - drawcmitrow $r - } + drawcmitrow $r if {$r == $er} break set nextid [lindex $displayorder [expr {$r + 1}]] if {$wasdrawn && [info exists iddrawn($nextid)]} { @@ -3889,101 +3916,166 @@ proc notbusy {what} { } proc findmatches {f} { - global findtype foundstring foundstrlen + global findtype findstring if {$findtype == "Regexp"} { - set matches [regexp -indices -all -inline $foundstring $f] + set matches [regexp -indices -all -inline $findstring $f] } else { + set fs $findstring if {$findtype == "IgnCase"} { - set str [string tolower $f] - } else { - set str $f + set f [string tolower $f] + set fs [string tolower $fs] } set matches {} set i 0 - while {[set j [string first $foundstring $str $i]] >= 0} { - lappend matches [list $j [expr {$j+$foundstrlen-1}]] - set i [expr {$j + $foundstrlen}] + set l [string length $fs] + while {[set j [string first $fs $f $i]] >= 0} { + lappend matches [list $j [expr {$j+$l-1}]] + set i [expr {$j + $l}] } } return $matches } -proc dofind {} { - global findtype findloc findstring markedmatches commitinfo - global numcommits displayorder linehtag linentag linedtag - global mainfont canv canv2 canv3 selectedline - global matchinglines foundstring foundstrlen matchstring - global commitdata +proc dofind {{rev 0}} { + global findstring findstartline findcurline selectedline numcommits stopfindproc unmarkmatches cancel_next_highlight focus . - set matchinglines {} - if {$findtype == "IgnCase"} { - set foundstring [string tolower $findstring] + if {$findstring eq {} || $numcommits == 0} return + if {![info exists selectedline]} { + set findstartline [lindex [visiblerows] $rev] } else { - set foundstring $findstring + set findstartline $selectedline } - set foundstrlen [string length $findstring] - if {$foundstrlen == 0} return - regsub -all {[*?\[\\]} $foundstring {\\&} matchstring - set matchstring "*$matchstring*" - if {![info exists selectedline]} { - set oldsel -1 + set findcurline $findstartline + nowbusy finding + if {!$rev} { + run findmore } else { - set oldsel $selectedline + set findcurline $findstartline + if {$findcurline == 0} { + set findcurline $numcommits + } + incr findcurline -1 + run findmorerev } - set didsel 0 - set fldtypes {Headline Author Date Committer CDate Comments} - set l -1 - foreach id $displayorder { - set d $commitdata($id) - incr l - if {$findtype == "Regexp"} { - set doesmatch [regexp $foundstring $d] - } elseif {$findtype == "IgnCase"} { - set doesmatch [string match -nocase $matchstring $d] +} + +proc findnext {restart} { + global findcurline + if {![info exists findcurline]} { + if {$restart} { + dofind } else { - set doesmatch [string match $matchstring $d] + bell } - if {!$doesmatch} continue + } else { + run findmore + nowbusy finding + } +} + +proc findprev {} { + global findcurline + if {![info exists findcurline]} { + dofind 1 + } else { + run findmorerev + nowbusy finding + } +} + +proc findmore {} { + global commitdata commitinfo numcommits findstring findpattern findloc + global findstartline findcurline markingmatches displayorder + + set fldtypes {Headline Author Date Committer CDate Comments} + set l [expr {$findcurline + 1}] + if {$l >= $numcommits} { + set l 0 + } + if {$l <= $findstartline} { + set lim [expr {$findstartline + 1}] + } else { + set lim $numcommits + } + if {$lim - $l > 500} { + set lim [expr {$l + 500}] + } + set last 0 + for {} {$l < $lim} {incr l} { + set id [lindex $displayorder $l] + if {![doesmatch $commitdata($id)]} continue if {![info exists commitinfo($id)]} { getcommit $id } set info $commitinfo($id) - set doesmatch 0 foreach f $info ty $fldtypes { - if {$findloc != "All fields" && $findloc != $ty} { - continue - } - set matches [findmatches $f] - if {$matches == {}} continue - set doesmatch 1 - if {$ty == "Headline"} { - drawcommits $l - markmatches $canv $l $f $linehtag($l) $matches $mainfont - } elseif {$ty == "Author"} { - drawcommits $l - markmatches $canv2 $l $f $linentag($l) $matches $mainfont - } elseif {$ty == "Date"} { - drawcommits $l - markmatches $canv3 $l $f $linedtag($l) $matches $mainfont + if {($findloc eq "All fields" || $findloc eq $ty) && + [doesmatch $f]} { + set markingmatches 1 + findselectline $l + notbusy finding + return 0 } } - if {$doesmatch} { - lappend matchinglines $l - if {!$didsel && $l > $oldsel} { + } + if {$l == $findstartline + 1} { + bell + unset findcurline + notbusy finding + return 0 + } + set findcurline [expr {$l - 1}] + return 1 +} + +proc findmorerev {} { + global commitdata commitinfo numcommits findstring findpattern findloc + global findstartline findcurline markingmatches displayorder + + set fldtypes {Headline Author Date Committer CDate Comments} + set l $findcurline + if {$l == 0} { + set l $numcommits + } + incr l -1 + if {$l >= $findstartline} { + set lim [expr {$findstartline - 1}] + } else { + set lim -1 + } + if {$l - $lim > 500} { + set lim [expr {$l - 500}] + } + set last 0 + for {} {$l > $lim} {incr l -1} { + set id [lindex $displayorder $l] + if {![doesmatch $commitdata($id)]} continue + if {![info exists commitinfo($id)]} { + getcommit $id + } + set info $commitinfo($id) + foreach f $info ty $fldtypes { + if {($findloc eq "All fields" || $findloc eq $ty) && + [doesmatch $f]} { + set markingmatches 1 findselectline $l - set didsel 1 + notbusy finding + return 0 } } } - if {$matchinglines == {}} { + if {$l == -1} { bell - } elseif {!$didsel} { - findselectline [lindex $matchinglines 0] + unset findcurline + notbusy finding + return 0 } + set findcurline [expr {$l + 1}] + return 1 } proc findselectline {l} { @@ -4001,43 +4093,6 @@ proc findselectline {l} { } } -proc findnext {restart} { - global matchinglines selectedline - if {![info exists matchinglines]} { - if {$restart} { - dofind - } - return - } - if {![info exists selectedline]} return - foreach l $matchinglines { - if {$l > $selectedline} { - findselectline $l - return - } - } - bell -} - -proc findprev {} { - global matchinglines selectedline - if {![info exists matchinglines]} { - dofind - return - } - if {![info exists selectedline]} return - set prev {} - foreach l $matchinglines { - if {$l >= $selectedline} break - set prev $l - } - if {$prev != {}} { - findselectline $prev - } else { - bell - } -} - proc stopfindproc {{done 0}} { global findprocpid findprocfile findids global ctext findoldcursor phase maincursor textcursor @@ -4055,18 +4110,7 @@ proc stopfindproc {{done 0}} { notbusy find } -# mark a commit as matching by putting a yellow background -# behind the headline -proc markheadline {l id} { - global canv mainfont linehtag - - drawcommits $l - set bbox [$canv bbox $linehtag($l)] - set t [$canv create rect $bbox -outline {} -tags matches -fill yellow] - $canv lower $t -} - -# mark the bits of a headline, author or date that match a find string +# mark the bits of a headline or author that match a find string proc markmatches {canv l str tag matches font} { set bbox [$canv bbox $tag] set x0 [lindex $bbox 0] @@ -4080,16 +4124,18 @@ proc markmatches {canv l str tag matches font} { set xlen [font measure $font [string range $str 0 [expr {$end}]]] set t [$canv create rect [expr {$x0+$xoff}] $y0 \ [expr {$x0+$xlen+2}] $y1 \ - -outline {} -tags matches -fill yellow] + -outline {} -tags [list match$l matches] -fill yellow] $canv lower $t } } proc unmarkmatches {} { - global matchinglines findids + global findids markingmatches findcurline + allcanvs delete matches - catch {unset matchinglines} catch {unset findids} + set markingmatches 0 + catch {unset findcurline} } proc selcanvline {w x y} { @@ -7471,6 +7517,7 @@ set searchdirn -forwards set boldrows {} set boldnamerows {} set diffelide {0 0} +set markingmatches 0 set optim_delay 16 From 69c0b5d2408cfe207f2976fc99cbe71208ba83ad Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 4 Jul 2007 21:57:04 +1000 Subject: [PATCH 2/7] gitk: Fix bug in the anc_or_desc routine I missed the case where both nodes have no children and therefore have no incoming arcs. This fixes it. Signed-off-by: Paul Mackerras --- gitk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitk b/gitk index d50914549..767b0ed8b 100755 --- a/gitk +++ b/gitk @@ -6261,7 +6261,8 @@ proc anc_or_desc {a b} { # Both are on the same arc(s); either both are the same BMP, # or if one is not a BMP, the other is also not a BMP or is # the BMP at end of the arc (and it only has 1 incoming arc). - if {$a eq $b} { + # Or both can be BMPs with no incoming arcs. + if {$a eq $b || $arcnos($a) eq {}} { return 0 } # assert {[llength $arcnos($a)] == 1} From d36d385efd89d79c9d1f95ab79849ff1478dc425 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 4 Jul 2007 22:41:19 +1000 Subject: [PATCH 3/7] gitk: Remove the unused stopfindproc function This was a hangover from before the "Files" and "Pickaxe" parts of the Find function were moved to the highlight facility in commit 60f7a7dc4904ba4baab44b70e2675a01e6172f54. It serves no useful purpose any more, so this removes it. Signed-off-by: Paul Mackerras --- gitk | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/gitk b/gitk index 767b0ed8b..45e16e4fd 100755 --- a/gitk +++ b/gitk @@ -1786,7 +1786,6 @@ proc showview {n} { } unselectline normalline - stopfindproc if {$curview >= 0} { set vparentlist($curview) $parentlist set vdisporder($curview) $displayorder @@ -3939,7 +3938,6 @@ proc findmatches {f} { proc dofind {{rev 0}} { global findstring findstartline findcurline selectedline numcommits - stopfindproc unmarkmatches cancel_next_highlight focus . @@ -4093,23 +4091,6 @@ proc findselectline {l} { } } -proc stopfindproc {{done 0}} { - global findprocpid findprocfile findids - global ctext findoldcursor phase maincursor textcursor - global findinprogress - - catch {unset findids} - if {[info exists findprocpid]} { - if {!$done} { - catch {exec kill $findprocpid} - } - catch {close $findprocfile} - unset findprocpid - } - catch {unset findinprogress} - notbusy find -} - # mark the bits of a headline or author that match a find string proc markmatches {canv l str tag matches font} { set bbox [$canv bbox $tag] From 096e96b493bfc30687c87b303b93e75864942786 Mon Sep 17 00:00:00 2001 From: Brian Downing Date: Thu, 5 Jul 2007 06:33:02 -0500 Subject: [PATCH 4/7] [PATCH] gitk: Fix for tree view ending in nested directories Unroll the prefix stack when assigning treeheights when leaving proc treeview. Previously, when the ls-tree output ended in multiple nested directories (for instance in a repository with a single file "foo/bar/baz"), $treeheight("foo/bar/") was assigned twice, and $treeheight("foo/") was never assigned. This led to an error when expanding the "foo" directory in the gitk treeview. Signed-off-by: Brian Downing Signed-off-by: Paul Mackerras --- gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk b/gitk index 45e16e4fd..28a6bac3a 100755 --- a/gitk +++ b/gitk @@ -1216,6 +1216,9 @@ proc treeview {w l openlevs} { set treeheight($prefix) $ht incr ht [lindex $htstack end] set htstack [lreplace $htstack end end] + set prefixend [lindex $prefendstack end] + set prefendstack [lreplace $prefendstack end end] + set prefix [string range $prefix 0 $prefixend] } $w conf -state disabled } From 8c93917d23ec7ef998154a6b2ac91ed1a1bf5e3a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 9 Jul 2007 22:29:24 +1000 Subject: [PATCH 5/7] gitk: Fix bug causing "can't read commitrow(0,n)" error In commit 66e46f37de3ed3211a8ae0e8fc09c063bc3a1e08 I changed gitk to store ids in rowrangelist and idrowranges rather than row numbers, but I missed two places in the layouttail procedure. This resulted in occasional errors such as the "can't read "commitrow(0,8572)": no such element in array" error reported by Mark Levedahl. This fixes it by using the id rather than the row number. Signed-off-by: Paul Mackerras --- gitk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index 28a6bac3a..ee818647c 100755 --- a/gitk +++ b/gitk @@ -2885,7 +2885,7 @@ proc layouttail {} { set id [lindex $idlist $col] addextraid $id $row unset idinlist($id) - lappend idrowranges($id) $row + lappend idrowranges($id) $id lappend rowrangelist $idrowranges($id) unset idrowranges($id) incr row @@ -2901,7 +2901,7 @@ proc layouttail {} { lset rowidlist $row [list $id] lset rowoffsets $row 0 makeuparrow $id 0 $row 0 - lappend idrowranges($id) $row + lappend idrowranges($id) $id lappend rowrangelist $idrowranges($id) unset idrowranges($id) incr row From c961b228bcab390a1b42d517b6ed5a1edb55efed Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 9 Jul 2007 22:45:47 +1000 Subject: [PATCH 6/7] gitk: Use git log and add support for --left-right This is based on patches from Linus Torvalds and Junio Hamano, so the ideas here are theirs. This makes gitk use "git log -z --pretty=raw" instead of "git rev-list" to generate the list of commits, and also makes it grok the "<" and ">" markers that git log (and git rev-list) output with the --left-right flag to indicate which side of a symmetric diff a commit is reachable from. Left-side commits are drawn with a triangle pointing leftwards instead of a circle, and right-side commits are drawn with a triangle pointing rightwards. The commitlisted list is used to store the left/right information as well as the information about whether each commit is on the boundary. Signed-off-by: Paul Mackerras --- gitk | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/gitk b/gitk index ee818647c..468cf3222 100755 --- a/gitk +++ b/gitk @@ -96,8 +96,8 @@ proc start_rev_list {view} { set order "--date-order" } if {[catch { - set fd [open [concat | git rev-list --header $order \ - --parents --boundary --default HEAD $args] r] + set fd [open [concat | git log -z --pretty=raw $order \ + --parents --boundary $args] r] } err]} { puts stderr "Error executing git rev-list: $err" exit 1 @@ -194,10 +194,14 @@ proc getcommitlines {fd view} { 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 + if {$j >= 0 && [string match "commit *" $cmit]} { + set ids [string range $cmit 7 [expr {$j - 1}]] + if {[string match {[-<>]*} $ids]} { + switch -- [string index $ids 0] { + "-" {set listed 0} + "<" {set listed 2} + ">" {set listed 3} + } set ids [string range $ids 1 end] } set ok 1 @@ -213,7 +217,7 @@ proc getcommitlines {fd view} { if {[string length $shortcmit] > 80} { set shortcmit "[string range $shortcmit 0 80]..." } - error_popup "Can't parse git rev-list output: {$shortcmit}" + error_popup "Can't parse git log output: {$shortcmit}" exit 1 } set id [lindex $ids 0] @@ -3334,23 +3338,41 @@ proc drawlines {id} { } proc drawcmittext {id row col} { - global linespc canv canv2 canv3 canvy0 fgcolor + global linespc canv canv2 canv3 canvy0 fgcolor curview global commitlisted commitinfo rowidlist parentlist global rowtextx idpos idtags idheads idotherrefs global linehtag linentag linedtag markingmatches global mainfont canvxmax boldrows boldnamerows fgcolor nullid + # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right + set listed [lindex $commitlisted $row] if {$id eq $nullid} { set ofill red } else { - set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}] + set ofill [expr {$listed != 0? "blue": "white"}] } set x [xc $row $col] set y [yc $row] set orad [expr {$linespc / 3}] - set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \ - [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \ - -fill $ofill -outline $fgcolor -width 1 -tags circle] + if {$listed <= 1} { + set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \ + [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \ + -fill $ofill -outline $fgcolor -width 1 -tags circle] + } elseif {$listed == 2} { + # triangle pointing left for left-side commits + set t [$canv create polygon \ + [expr {$x - $orad}] $y \ + [expr {$x + $orad - 1}] [expr {$y - $orad}] \ + [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \ + -fill $ofill -outline $fgcolor -width 1 -tags circle] + } else { + # triangle pointing right for right-side commits + set t [$canv create polygon \ + [expr {$x + $orad - 1}] $y \ + [expr {$x - $orad}] [expr {$y - $orad}] \ + [expr {$x - $orad}] [expr {$y + $orad - 1}] \ + -fill $ofill -outline $fgcolor -width 1 -tags circle] + } $canv raise $t $canv bind $t <1> {selcanvline {} %x %y} set rmx [llength [lindex $rowidlist $row]] From cdaee5db165ba8bae8d3b524950e61666fc36a84 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 12 Jul 2007 22:29:49 +1000 Subject: [PATCH 7/7] gitk: Improve handling of -- and ambiguous arguments This makes gitk more consistent with git rev-list and git log in its handling of arguments that could be either a revision or a filename; now gitk displays an error message and quits, rather than treating it as a revision and getting an error in the underlying git log. Now gitk always passes "--" to git log even if no filenames are being specified. It also makes gitk display errors in invoking git log in a window rather than on stderr, and makes gitk stop looking for a -d flag when it sees a "--" argument. Signed-off-by: Paul Mackerras --- gitk | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/gitk b/gitk index 468cf3222..b9219c2c7 100755 --- a/gitk +++ b/gitk @@ -87,19 +87,15 @@ proc start_rev_list {view} { set startmsecs [clock clicks -milliseconds] set commitidx($view) 0 - set args $viewargs($view) - if {$viewfiles($view) ne {}} { - set args [concat $args "--" $viewfiles($view)] - } set order "--topo-order" if {$datemode} { set order "--date-order" } if {[catch { - set fd [open [concat | git log -z --pretty=raw $order \ - --parents --boundary $args] r] + set fd [open [concat | git log -z --pretty=raw $order --parents \ + --boundary $viewargs($view) "--" $viewfiles($view)] r] } err]} { - puts stderr "Error executing git rev-list: $err" + error_popup "Error executing git rev-list: $err" exit 1 } set commfd($view) $fd @@ -7471,35 +7467,48 @@ catch {source ~/.gitk} font create optionfont -family sans-serif -size -12 +# check that we can find a .git directory somewhere... +set gitdir [gitdir] +if {![file isdirectory $gitdir]} { + show_error {} . "Cannot find the git directory \"$gitdir\"." + exit 1 +} + set revtreeargs {} +set cmdline_files {} +set i 0 foreach arg $argv { switch -regexp -- $arg { "^$" { } "^-d" { set datemode 1 } + "--" { + set cmdline_files [lrange $argv [expr {$i + 1}] end] + break + } default { lappend revtreeargs $arg } } + incr i } -# check that we can find a .git directory somewhere... -set gitdir [gitdir] -if {![file isdirectory $gitdir]} { - show_error {} . "Cannot find the git directory \"$gitdir\"." - exit 1 -} - -set cmdline_files {} -set i [lsearch -exact $revtreeargs "--"] -if {$i >= 0} { - set cmdline_files [lrange $revtreeargs [expr {$i + 1}] end] - set revtreeargs [lrange $revtreeargs 0 [expr {$i - 1}]] -} elseif {$revtreeargs ne {}} { +if {$i >= [llength $argv] && $revtreeargs ne {}} { + # no -- on command line, but some arguments (other than -d) if {[catch { set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs] set cmdline_files [split $f "\n"] set n [llength $cmdline_files] set revtreeargs [lrange $revtreeargs 0 end-$n] + # Unfortunately git rev-parse doesn't produce an error when + # something is both a revision and a filename. To be consistent + # with git log and git rev-list, check revtreeargs for filenames. + foreach arg $revtreeargs { + if {[file exists $arg]} { + show_error {} . "Ambiguous argument '$arg': both revision\ + and filename" + exit 1 + } + } } err]} { # unfortunately we get both stdout and stderr in $err, # so look for "fatal:".