From b74fd579662c9d05db5cfb4b0e2b95f8919b9916 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 16 Jul 2005 07:46:13 -0400 Subject: [PATCH] Add "Files" and "Pickaxe" to the find menu. "Files" matches the find string against each of the files modified by each commit, and can do exact, case-ignoring or regexp matching. "Pickaxe" uses git-diff-tree -S'string' and can only do exact matching. I called it "pickaxe" rather than "find within patch" since it only finds commits where the string is present in the child but not the parents or vice versa, and "pickaxe" is what the author of that feature calls it. --- gitk | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 247 insertions(+), 18 deletions(-) diff --git a/gitk b/gitk index f969c14f1..a1d65fa87 100755 --- a/gitk +++ b/gitk @@ -270,7 +270,7 @@ proc error_popup msg { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist textfont - global findtype findloc findstring fstring geometry + global findtype findtypemenu findloc findstring fstring geometry global entries sha1entry sha1string sha1but global maincursor textcursor global rowctxmenu @@ -342,12 +342,15 @@ proc makewindow {} { entry $fstring -width 30 -font $textfont -textvariable findstring pack $fstring -side left -expand 1 -fill x set findtype Exact - tk_optionMenu .ctop.top.bar.findtype findtype Exact IgnCase Regexp + set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \ + findtype Exact IgnCase Regexp] set findloc "All fields" tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \ - Comments Author Committer + Comments Author Committer Files Pickaxe pack .ctop.top.bar.findloc -side right pack .ctop.top.bar.findtype -side right + # for making sure type==Exact whenever loc==Pickaxe + trace add variable findloc write findlocchange panedwindow .ctop.cdet -orient horizontal .ctop add .ctop.cdet @@ -397,12 +400,13 @@ proc makewindow {} { bindkey b "$ctext yview scroll -1 pages" bindkey d "$ctext yview scroll 18 units" bindkey u "$ctext yview scroll -18 units" - bindkey / findnext + bindkey / {findnext 1} + bindkey {findnext 0} bindkey ? findprev bindkey f nextfile bind . doquit bind . dofind - bind . findnext + bind . {findnext 0} bind . findprev bind . {incrfont 1} bind . {incrfont 1} @@ -1136,10 +1140,15 @@ proc dofind {} { global numcommits lineid linehtag linentag linedtag global mainfont namefont canv canv2 canv3 selectedline global matchinglines foundstring foundstrlen + + stopfindproc unmarkmatches focus . set matchinglines {} - set fldtypes {Headline Author Date Committer CDate Comment} + if {$findloc == "Pickaxe"} { + findpatches + return + } if {$findtype == "IgnCase"} { set foundstring [string tolower $findstring] } else { @@ -1147,12 +1156,17 @@ proc dofind {} { } set foundstrlen [string length $findstring] if {$foundstrlen == 0} return + if {$findloc == "Files"} { + findfiles + return + } if {![info exists selectedline]} { set oldsel -1 } else { set oldsel $selectedline } set didsel 0 + set fldtypes {Headline Author Date Committer CDate Comment} for {set l 0} {$l < $numcommits} {incr l} { set id $lineid($l) set info $commitinfo($id) @@ -1202,10 +1216,12 @@ proc findselectline {l} { } } -proc findnext {} { +proc findnext {restart} { global matchinglines selectedline if {![info exists matchinglines]} { - dofind + if {$restart} { + dofind + } return } if {![info exists selectedline]} return @@ -1237,6 +1253,203 @@ proc findprev {} { } } +proc findlocchange {name ix op} { + global findloc findtype findtypemenu + if {$findloc == "Pickaxe"} { + set findtype Exact + set state disabled + } else { + set state normal + } + $findtypemenu entryconf 1 -state $state + $findtypemenu entryconf 2 -state $state +} + +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 + } + if {[info exists findinprogress]} { + unset findinprogress + if {$phase != "incrdraw"} { + . config -cursor $maincursor + $ctext config -cursor $textcursor + } + } +} + +proc findpatches {} { + global findstring selectedline numcommits + global findprocpid findprocfile + global finddidsel ctext lineid findinprogress + + if {$numcommits == 0} return + + # make a list of all the ids to search, starting at the one + # after the selected line (if any) + if {[info exists selectedline]} { + set l $selectedline + } else { + set l -1 + } + set inputids {} + for {set i 0} {$i < $numcommits} {incr i} { + if {[incr l] >= $numcommits} { + set l 0 + } + append inputids $lineid($l) "\n" + } + + if {[catch { + set f [open [list | git-diff-tree --stdin -s -r -S$findstring \ + << $inputids] r] + } err]} { + error_popup "Error starting search process: $err" + return + } + + set findprocfile $f + set findprocpid [pid $f] + fconfigure $f -blocking 0 + fileevent $f readable readfindproc + set finddidsel 0 + . config -cursor watch + $ctext config -cursor watch + set findinprogress 1 +} + +proc readfindproc {} { + global findprocfile finddidsel + global idline matchinglines + + set n [gets $findprocfile line] + if {$n < 0} { + if {[eof $findprocfile]} { + stopfindproc 1 + if {!$finddidsel} { + bell + } + } + return + } + if {![regexp {^[0-9a-f]{40}} $line id]} { + error_popup "Can't parse git-diff-tree output: $line" + stopfindproc + return + } + if {![info exists idline($id)]} { + puts stderr "spurious id: $id" + return + } + set l $idline($id) + lappend matchinglines $l + if {!$finddidsel} { + findselectline $l + set finddidsel 1 + } +} + +proc findfiles {} { + global selectedline numcommits lineid + global ffileline finddidsel parents findstartline + global findinprogress ctext + + if {$numcommits == 0} return + + if {[info exists selectedline]} { + set l [expr {$selectedline + 1}] + } else { + set l 0 + } + set ffileline $l + set finddidsel 0 + set findstartline $l + 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] +} + +proc findcont {ids} { + global findids treediffs parents nparents treepending + global ffileline findstartline finddidsel + global lineid numcommits matchinglines findinprogress + global findmergefiles + + set id [lindex $ids 0] + set p [lindex $ids 1] + set pi [lsearch -exact $parents($id) $p] + set l $ffileline + while 1 { + if {$findmergefiles || $nparents($id) == 1} { + if {![info exists treediffs($ids)]} { + set findids $ids + set ffileline $l + if {![info exists treepending]} { + gettreediffs $ids + } + return + } + set doesmatch 0 + foreach f $treediffs($ids) { + set x [findmatches $f] + if {$x != {}} { + set doesmatch 1 + break + } + } + if {$doesmatch} { + lappend matchinglines $l + markheadline $l $id + if {!$finddidsel} { + findselectline $l + set finddidsel 1 + } + set pi $nparents($id) + } + } else { + set pi $nparents($id) + } + if {[incr pi] >= $nparents($id)} { + set pi 0 + if {[incr l] >= $numcommits} { + set l 0 + } + if {$l == $findstartline} break + set id $lineid($l) + } + set p [lindex $parents($id) $pi] + set ids [list $id $p] + } + stopfindproc + if {!$finddidsel} { + bell + } +} + +# mark a commit as matching by putting a yellow background +# behind the headline +proc markheadline {l id} { + global canv mainfont linehtag commitinfo + + 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 proc markmatches {canv l str tag matches font} { set bbox [$canv bbox $tag] set x0 [lindex $bbox 0] @@ -1255,9 +1468,10 @@ proc markmatches {canv l str tag matches font} { } proc unmarkmatches {} { - global matchinglines + global matchinglines findids allcanvs delete matches catch {unset matchinglines} + catch {unset findids} } proc selcanvline {w x y} { @@ -1393,11 +1607,7 @@ proc selnextline {dir} { } proc addtocflist {ids} { - global diffids treediffs cflist - if {$ids != $diffids} { - gettreediffs $diffids - return - } + global treediffs cflist foreach f $treediffs($ids) { $cflist insert end $f } @@ -1416,13 +1626,28 @@ proc gettreediffs {ids} { } proc gettreediffline {gdtf ids} { - global treediffs treepending + global treediffs treepending diffids findids set n [gets $gdtf line] if {$n < 0} { if {![eof $gdtf]} return close $gdtf unset treepending - addtocflist $ids + if {[info exists diffids]} { + if {$ids != $diffids} { + gettreediffs $diffids + } else { + addtocflist $ids + } + } + if {[info exists findids]} { + if {$ids != $findids} { + if {![info exists treepending]} { + gettreediffs $findids + } + } else { + findcont $ids + } + } return } set file [lindex $line 5] @@ -1459,14 +1684,17 @@ proc getblobdiffline {bdf ids} { if {$n < 0} { if {[eof $bdf]} { close $bdf - if {$ids == $diffids && $bdf == $blobdifffd($ids)} { + if {[info exists diffids] && $ids == $diffids + && $bdf == $blobdifffd($ids)} { $ctext tag add $curdifftag $curtagstart end set seenfile($curdifftag) 1 + unset diffids } } return } - if {$ids != $diffids || $bdf != $blobdifffd($ids)} { + if {![info exists diffids] || $ids != $diffids + || $bdf != $blobdifffd($ids)} { return } $ctext conf -state normal @@ -2044,6 +2272,7 @@ set wrcomcmd "git-diff-tree --stdin -p --pretty" set mainfont {Helvetica 9} set textfont {Courier 9} +set findmergefiles 0 set colors {green red blue magenta darkgrey brown orange} -- 2.30.2