[PATCH] Cleanup: git-verify-tag-script
[git.git] / gitk
diff --git a/gitk b/gitk
index a1d65fa..5ebcf33 100755 (executable)
--- 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}