Code

Allow frontends to bidirectionally communicate with fast-import
[git.git] / gitk
diff --git a/gitk b/gitk
index 5cfb1cc391bad62f81e52bcd35ef4e1b2ad759cc..57617d58b070892a730e956e82a2f382c28659e2 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -139,6 +139,10 @@ proc getcommitlines {fd view}  {
     global vparentlist vdisporder vcmitlisted
 
     set stuff [read $fd 500000]
     global vparentlist vdisporder vcmitlisted
 
     set stuff [read $fd 500000]
+    # git log doesn't terminate the last commit with a null...
+    if {$stuff == {} && $leftover($view) ne {} && [eof $fd]} {
+       set stuff "\0"
+    }
     if {$stuff == {}} {
        if {![eof $fd]} {
            return 1
     if {$stuff == {}} {
        if {![eof $fd]} {
            return 1
@@ -292,7 +296,7 @@ proc readcommit {id} {
 
 proc updatecommits {} {
     global viewdata curview phase displayorder
 
 proc updatecommits {} {
     global viewdata curview phase displayorder
-    global children commitrow selectedline thickerline
+    global children commitrow selectedline thickerline showneartags
 
     if {$phase ne {}} {
        stop_rev_list
 
     if {$phase ne {}} {
        stop_rev_list
@@ -309,7 +313,9 @@ proc updatecommits {} {
     catch {unset viewdata($n)}
     readrefs
     changedrefs
     catch {unset viewdata($n)}
     readrefs
     changedrefs
-    regetallcommits
+    if {$showneartags} {
+       getallcommits
+    }
     showview $n
 }
 
     showview $n
 }
 
@@ -423,7 +429,7 @@ proc readrefs {} {
            lappend idotherrefs($id) $name
        }
     }
            lappend idotherrefs($id) $name
        }
     }
-    close $refd
+    catch {close $refd}
     set mainhead {}
     set mainheadid {}
     catch {
     set mainhead {}
     set mainheadid {}
     catch {
@@ -819,8 +825,13 @@ proc makewindow {} {
     pack .ctop -fill both -expand 1
     bindall <1> {selcanvline %W %x %y}
     #bindall <B1-Motion> {selcanvline %W %x %y}
     pack .ctop -fill both -expand 1
     bindall <1> {selcanvline %W %x %y}
     #bindall <B1-Motion> {selcanvline %W %x %y}
-    bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
-    bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+    if {[tk windowingsystem] == "win32"} {
+       bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D }
+       bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break }
+    } else {
+       bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
+       bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+    }
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
     bindkey <Home> selfirstline
     bindall <2> "canvscan mark %W %x %y"
     bindall <B2-Motion> "canvscan dragto %W %x %y"
     bindkey <Home> selfirstline
@@ -875,6 +886,7 @@ proc makewindow {} {
     bind $cflist <1> {sel_flist %W %x %y; break}
     bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
     bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
     bind $cflist <1> {sel_flist %W %x %y; break}
     bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
     bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
+    bind $cflist <Button-3> {pop_flist_menu %W %X %Y %x %y}
 
     set maincursor [. cget -cursor]
     set textcursor [$ctext cget -cursor]
 
     set maincursor [. cget -cursor]
     set textcursor [$ctext cget -cursor]
@@ -912,6 +924,32 @@ proc makewindow {} {
        -command cobranch
     $headctxmenu add command -label "Remove this branch" \
        -command rmbranch
        -command cobranch
     $headctxmenu add command -label "Remove this branch" \
        -command rmbranch
+
+    global flist_menu
+    set flist_menu .flistctxmenu
+    menu $flist_menu -tearoff 0
+    $flist_menu add command -label "Highlight this too" \
+       -command {flist_hl 0}
+    $flist_menu add command -label "Highlight this only" \
+       -command {flist_hl 1}
+}
+
+# Windows sends all mouse wheel events to the current focused window, not
+# the one where the mouse hovers, so bind those events here and redirect
+# to the correct window
+proc windows_mousewheel_redirector {W X Y D} {
+    global canv canv2 canv3
+    set w [winfo containing -displayof $W $X $Y]
+    if {$w ne ""} {
+       set u [expr {$D < 0 ? 5 : -5}]
+       if {$w == $canv || $w == $canv2 || $w == $canv3} {
+           allcanvs yview scroll $u units
+       } else {
+           catch {
+               $w yview scroll $u units
+           }
+       }
+    }
 }
 
 # mouse-2 makes all windows scan vertically, but only the one
 }
 
 # mouse-2 makes all windows scan vertically, but only the one
@@ -951,8 +989,8 @@ proc bindkey {ev script} {
 # set the focus back to the toplevel for any click outside
 # the entry widgets
 proc click {w} {
 # set the focus back to the toplevel for any click outside
 # the entry widgets
 proc click {w} {
-    global entries
-    foreach e $entries {
+    global ctext entries
+    foreach e [concat $entries $ctext] {
        if {$w == $e} return
     }
     focus .
        if {$w == $e} return
     }
     focus .
@@ -1495,6 +1533,33 @@ proc sel_flist {w x y} {
     }
 }
 
     }
 }
 
+proc pop_flist_menu {w X Y x y} {
+    global ctext cflist cmitmode flist_menu flist_menu_file
+    global treediffs diffids
+
+    set l [lindex [split [$w index "@$x,$y"] "."] 0]
+    if {$l <= 1} return
+    if {$cmitmode eq "tree"} {
+       set e [linetoelt $l]
+       if {[string index $e end] eq "/"} return
+    } else {
+       set e [lindex $treediffs($diffids) [expr {$l-2}]]
+    }
+    set flist_menu_file $e
+    tk_popup $flist_menu $X $Y
+}
+
+proc flist_hl {only} {
+    global flist_menu_file highlight_files
+
+    set x [shellquote $flist_menu_file]
+    if {$only || $highlight_files eq {}} {
+       set highlight_files $x
+    } else {
+       append highlight_files " " $x
+    }
+}
+
 # Functions for adding and removing shell-type quoting
 
 proc shellquote {str} {
 # Functions for adding and removing shell-type quoting
 
 proc shellquote {str} {
@@ -2157,7 +2222,7 @@ proc readfhighlight {} {
 
 proc find_change {name ix op} {
     global nhighlights mainfont boldnamerows
 
 proc find_change {name ix op} {
     global nhighlights mainfont boldnamerows
-    global findstring findpattern findtype markingmatches
+    global findstring findpattern findtype
 
     # delete previous highlights, if any
     foreach row $boldnamerows {
 
     # delete previous highlights, if any
     foreach row $boldnamerows {
@@ -2172,7 +2237,6 @@ proc find_change {name ix op} {
                   $findstring]
        set findpattern "*$e*"
     }
                   $findstring]
        set findpattern "*$e*"
     }
-    set markingmatches [expr {$findstring ne {}}]
     drawvisible
 }
 
     drawvisible
 }
 
@@ -2218,26 +2282,32 @@ proc askfindhighlight {row id} {
            }
        }
        if {$markingmatches} {
            }
        }
        if {$markingmatches} {
-           markrowmatches $row [lindex $info 0] [lindex $info 1]
+           markrowmatches $row $id
        }
     }
     set nhighlights($row) $isbold
 }
 
        }
     }
     set nhighlights($row) $isbold
 }
 
-proc markrowmatches {row headline author} {
-    global canv canv2 linehtag linentag
+proc markrowmatches {row id} {
+    global canv canv2 linehtag linentag commitinfo findloc
 
 
+    set headline [lindex $commitinfo($id) 0]
+    set author [lindex $commitinfo($id) 1]
     $canv delete match$row
     $canv2 delete match$row
     $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]
+    if {$findloc eq "All fields" || $findloc eq "Headline"} {
+       set m [findmatches $headline]
+       if {$m ne {}} {
+           markmatches $canv $row $headline $linehtag($row) $m \
+               [$canv itemcget $linehtag($row) -font] $row
+       }
     }
     }
-    set m [findmatches $author]
-    if {$m ne {}} {
-       markmatches $canv2 $row $author $linentag($row) $m \
-           [$canv2 itemcget $linentag($row) -font]
+    if {$findloc eq "All fields" || $findloc eq "Author"} {
+       set m [findmatches $author]
+       if {$m ne {}} {
+           markmatches $canv2 $row $author $linentag($row) $m \
+               [$canv2 itemcget $linentag($row) -font] $row
+       }
     }
 }
 
     }
 }
 
@@ -2827,17 +2897,12 @@ proc layoutrows {row endrow last} {
     set offs [lindex $rowoffsets $row]
     while {$row < $endrow} {
        set id [lindex $displayorder $row]
     set offs [lindex $rowoffsets $row]
     while {$row < $endrow} {
        set id [lindex $displayorder $row]
-       set oldolds {}
-       set newolds {}
+       set nev [expr {[llength $idlist] - $maxwidth + 1}]
        foreach p [lindex $parentlist $row] {
        foreach p [lindex $parentlist $row] {
-           if {![info exists idinlist($p)]} {
-               lappend newolds $p
-           } elseif {!$idinlist($p)} {
-               lappend oldolds $p
+           if {![info exists idinlist($p)] || !$idinlist($p)} {
+               incr nev
            }
        }
            }
        }
-       set nev [expr {[llength $idlist] + [llength $newolds]
-                      + [llength $oldolds] - $maxwidth + 1}]
        if {$nev > 0} {
            if {!$last &&
                $row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
        if {$nev > 0} {
            if {!$last &&
                $row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
@@ -2856,12 +2921,22 @@ proc layoutrows {row endrow last} {
                        if {[incr nev -1] <= 0} break
                        continue
                    }
                        if {[incr nev -1] <= 0} break
                        continue
                    }
-                   set rowchk($id) [expr {$row + $r}]
+                   set rowchk($i) [expr {$row + $r}]
                }
            }
            lset rowidlist $row $idlist
            lset rowoffsets $row $offs
        }
                }
            }
            lset rowidlist $row $idlist
            lset rowoffsets $row $offs
        }
+       set oldolds {}
+       set newolds {}
+       foreach p [lindex $parentlist $row] {
+           if {![info exists idinlist($p)]} {
+               lappend newolds $p
+           } elseif {!$idinlist($p)} {
+               lappend oldolds $p
+           }
+           set idinlist($p) 1
+       }
        set col [lsearch -exact $idlist $id]
        if {$col < 0} {
            set col [llength $idlist]
        set col [lsearch -exact $idlist $id]
        if {$col < 0} {
            set col [llength $idlist]
@@ -2907,12 +2982,10 @@ proc layoutrows {row endrow last} {
            lset offs $col {}
        }
        foreach i $newolds {
            lset offs $col {}
        }
        foreach i $newolds {
-           set idinlist($i) 1
            set idrowranges($i) $id
        }
        incr col $l
        foreach oid $oldolds {
            set idrowranges($i) $id
        }
        incr col $l
        foreach oid $oldolds {
-           set idinlist($oid) 1
            set idlist [linsert $idlist $col $oid]
            set offs [linsert $offs $col $o]
            makeuparrow $oid $col $row $o
            set idlist [linsert $idlist $col $oid]
            set offs [linsert $offs $col $o]
            makeuparrow $oid $col $row $o
@@ -2953,7 +3026,7 @@ proc layouttail {} {
        set col [expr {[llength $idlist] - 1}]
        set id [lindex $idlist $col]
        addextraid $id $row
        set col [expr {[llength $idlist] - 1}]
        set id [lindex $idlist $col]
        addextraid $id $row
-       unset idinlist($id)
+       catch {unset idinlist($id)}
        lappend idrowranges($id) $id
        lappend rowrangelist $idrowranges($id)
        unset idrowranges($id)
        lappend idrowranges($id) $id
        lappend rowrangelist $idrowranges($id)
        unset idrowranges($id)
@@ -3406,7 +3479,7 @@ proc drawcmittext {id row col} {
     global linespc canv canv2 canv3 canvy0 fgcolor curview
     global commitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
     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 linehtag linentag linedtag
     global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
 
     # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
     global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
 
     # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
@@ -3483,9 +3556,6 @@ 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]}]
     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
     if {$xr > $canvxmax} {
        set canvxmax $xr
        setcanvscroll
@@ -3494,7 +3564,7 @@ proc drawcmittext {id row col} {
 
 proc drawcmitrow {row} {
     global displayorder rowidlist
 
 proc drawcmitrow {row} {
     global displayorder rowidlist
-    global iddrawn
+    global iddrawn markingmatches
     global commitinfo parentlist numcommits
     global filehighlight fhighlights findstring nhighlights
     global hlview vhighlights
     global commitinfo parentlist numcommits
     global filehighlight fhighlights findstring nhighlights
     global hlview vhighlights
@@ -3515,18 +3585,22 @@ proc drawcmitrow {row} {
     if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
        askrelhighlight $row $id
     }
     if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
        askrelhighlight $row $id
     }
-    if {[info exists iddrawn($id)]} return
-    set col [lsearch -exact [lindex $rowidlist $row] $id]
-    if {$col < 0} {
-       puts "oops, row $row id $id not in list"
-       return
+    if {![info exists iddrawn($id)]} {
+       set col [lsearch -exact [lindex $rowidlist $row] $id]
+       if {$col < 0} {
+           puts "oops, row $row id $id not in list"
+           return
+       }
+       if {![info exists commitinfo($id)]} {
+           getcommit $id
+       }
+       assigncolor $id
+       drawcmittext $id $row $col
+       set iddrawn($id) 1
     }
     }
-    if {![info exists commitinfo($id)]} {
-       getcommit $id
+    if {$markingmatches} {
+       markrowmatches $row $id
     }
     }
-    assigncolor $id
-    drawcmittext $id $row $col
-    set iddrawn($id) 1
 }
 
 proc drawcommits {row {endrow {}}} {
 }
 
 proc drawcommits {row {endrow {}}} {
@@ -4044,7 +4118,6 @@ proc dofind {{rev 0}} {
     if {!$rev} {
        run findmore
     } else {
     if {!$rev} {
        run findmore
     } else {
-       set findcurline $findstartline
        if {$findcurline == 0} {
            set findcurline $numcommits
        }
        if {$findcurline == 0} {
            set findcurline $numcommits
        }
@@ -4079,7 +4152,7 @@ proc findprev {} {
 
 proc findmore {} {
     global commitdata commitinfo numcommits findstring findpattern findloc
 
 proc findmore {} {
     global commitdata commitinfo numcommits findstring findpattern findloc
-    global findstartline findcurline markingmatches displayorder
+    global findstartline findcurline displayorder
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l [expr {$findcurline + 1}]
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l [expr {$findcurline + 1}]
@@ -4097,6 +4170,8 @@ proc findmore {} {
     set last 0
     for {} {$l < $lim} {incr l} {
        set id [lindex $displayorder $l]
     set last 0
     for {} {$l < $lim} {incr l} {
        set id [lindex $displayorder $l]
+       # shouldn't happen unless git log doesn't give all the commits...
+       if {![info exists commitdata($id)]} continue
        if {![doesmatch $commitdata($id)]} continue
        if {![info exists commitinfo($id)]} {
            getcommit $id
        if {![doesmatch $commitdata($id)]} continue
        if {![info exists commitinfo($id)]} {
            getcommit $id
@@ -4105,7 +4180,6 @@ proc findmore {} {
        foreach f $info ty $fldtypes {
            if {($findloc eq "All fields" || $findloc eq $ty) &&
                [doesmatch $f]} {
        foreach f $info ty $fldtypes {
            if {($findloc eq "All fields" || $findloc eq $ty) &&
                [doesmatch $f]} {
-               set markingmatches 1
                findselectline $l
                notbusy finding
                return 0
                findselectline $l
                notbusy finding
                return 0
@@ -4124,7 +4198,7 @@ proc findmore {} {
 
 proc findmorerev {} {
     global commitdata commitinfo numcommits findstring findpattern findloc
 
 proc findmorerev {} {
     global commitdata commitinfo numcommits findstring findpattern findloc
-    global findstartline findcurline markingmatches displayorder
+    global findstartline findcurline displayorder
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l $findcurline
 
     set fldtypes {Headline Author Date Committer CDate Comments}
     set l $findcurline
@@ -4151,7 +4225,6 @@ proc findmorerev {} {
        foreach f $info ty $fldtypes {
            if {($findloc eq "All fields" || $findloc eq $ty) &&
                [doesmatch $f]} {
        foreach f $info ty $fldtypes {
            if {($findloc eq "All fields" || $findloc eq $ty) &&
                [doesmatch $f]} {
-               set markingmatches 1
                findselectline $l
                notbusy finding
                return 0
                findselectline $l
                notbusy finding
                return 0
@@ -4169,7 +4242,10 @@ proc findmorerev {} {
 }
 
 proc findselectline {l} {
 }
 
 proc findselectline {l} {
-    global findloc commentend ctext
+    global findloc commentend ctext findcurline markingmatches
+
+    set markingmatches 1
+    set findcurline $l
     selectline $l 1
     if {$findloc == "All fields" || $findloc == "Comments"} {
        # highlight the matches in the comments
     selectline $l 1
     if {$findloc == "All fields" || $findloc == "Comments"} {
        # highlight the matches in the comments
@@ -4181,10 +4257,13 @@ proc findselectline {l} {
            $ctext tag add found "1.0 + $start c" "1.0 + $end c"
        }
     }
            $ctext tag add found "1.0 + $start c" "1.0 + $end c"
        }
     }
+    drawvisible
 }
 
 # mark the bits of a headline or author 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} {
+proc markmatches {canv l str tag matches font row} {
+    global selectedline
+
     set bbox [$canv bbox $tag]
     set x0 [lindex $bbox 0]
     set y0 [lindex $bbox 1]
     set bbox [$canv bbox $tag]
     set x0 [lindex $bbox 0]
     set y0 [lindex $bbox 1]
@@ -4199,6 +4278,9 @@ proc markmatches {canv l str tag matches font} {
                   [expr {$x0+$xlen+2}] $y1 \
                   -outline {} -tags [list match$l matches] -fill yellow]
        $canv lower $t
                   [expr {$x0+$xlen+2}] $y1 \
                   -outline {} -tags [list match$l matches] -fill yellow]
        $canv lower $t
+       if {[info exists selectedline] && $row == $selectedline} {
+           $canv raise $t secsel
+       }
     }
 }
 
     }
 }
 
@@ -4547,6 +4629,7 @@ proc sellastline {} {
 
 proc selnextline {dir} {
     global selectedline
 
 proc selnextline {dir} {
     global selectedline
+    focus .
     if {![info exists selectedline]} return
     set l [expr {$selectedline + $dir}]
     unmarkmatches
     if {![info exists selectedline]} return
     set l [expr {$selectedline + $dir}]
     unmarkmatches
@@ -4627,6 +4710,7 @@ proc godo {elt} {
 
 proc goback {} {
     global history historyindex
 
 proc goback {} {
     global history historyindex
+    focus .
 
     if {$historyindex > 1} {
        incr historyindex -1
 
     if {$historyindex > 1} {
        incr historyindex -1
@@ -4640,6 +4724,7 @@ proc goback {} {
 
 proc goforw {} {
     global history historyindex
 
 proc goforw {} {
     global history historyindex
+    focus .
 
     if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
 
     if {$historyindex < [llength $history]} {
        set cmd [lindex $history $historyindex]
@@ -6116,17 +6201,13 @@ proc rmbranch {} {
 proc getallcommits {} {
     global allcommits allids nbmp nextarc seeds
 
 proc getallcommits {} {
     global allcommits allids nbmp nextarc seeds
 
-    set allids {}
-    set nbmp 0
-    set nextarc 0
-    set allcommits 0
-    set seeds {}
-    regetallcommits
-}
-
-# Called when the graph might have changed
-proc regetallcommits {} {
-    global allcommits seeds
+    if {![info exists allcommits]} {
+       set allids {}
+       set nbmp 0
+       set nextarc 0
+       set allcommits 0
+       set seeds {}
+    }
 
     set cmd [concat | git rev-list --all --parents]
     foreach id $seeds {
 
     set cmd [concat | git rev-list --all --parents]
     foreach id $seeds {
@@ -7557,7 +7638,10 @@ catch {source ~/.gitk}
 font create optionfont -family sans-serif -size -12
 
 # check that we can find a .git directory somewhere...
 font create optionfont -family sans-serif -size -12
 
 # check that we can find a .git directory somewhere...
-set gitdir [gitdir]
+if {[catch {set gitdir [gitdir]}]} {
+    show_error {} . "Cannot find a git repository here."
+    exit 1
+}
 if {![file isdirectory $gitdir]} {
     show_error {} . "Cannot find the git directory \"$gitdir\"."
     exit 1
 if {![file isdirectory $gitdir]} {
     show_error {} . "Cannot find the git directory \"$gitdir\"."
     exit 1