gitk: Factored out some common code into a new start_rev_list procedure
[git.git] / gitk
diff --git a/gitk b/gitk
index e1c3954..42e96d0 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -16,22 +16,9 @@ proc gitdir {} {
     }
 }
 
-proc getcommits {rargs} {
-    global commits commfd phase canv mainfont env
-    global startmsecs nextupdate ncmupdate
-    global ctext maincursor textcursor leftover gitencoding
+proc parse_args {rargs} {
+    global parsed_args
 
-    # check that we can find a .git directory somewhere...
-    set gitdir [gitdir]
-    if {![file isdirectory $gitdir]} {
-       error_popup "Cannot find the git directory \"$gitdir\"."
-       exit 1
-    }
-    set commits {}
-    set phase getcommits
-    set startmsecs [clock clicks -milliseconds]
-    set nextupdate [expr {$startmsecs + 100}]
-    set ncmupdate 1
     if [catch {
        set parse_args [concat --default HEAD $rargs]
        set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
@@ -42,8 +29,19 @@ proc getcommits {rargs} {
        }
        set parsed_args $rargs
     }
+    return $parsed_args
+}
+
+proc start_rev_list {rlargs} {
+    global startmsecs nextupdate ncmupdate
+    global commfd leftover gitencoding
+
+    set startmsecs [clock clicks -milliseconds]
+    set nextupdate [expr {$startmsecs + 100}]
+    set ncmupdate 1
     if [catch {
-       set commfd [open "|git-rev-list --header --topo-order --parents $parsed_args" r]
+       set commfd [open [concat | git-rev-list --header --topo-order \
+                             --parents $rlargs] r]
     } err] {
        puts stderr "Error executing git-rev-list: $err"
        exit 1
@@ -51,17 +49,33 @@ proc getcommits {rargs} {
     set leftover {}
     fconfigure $commfd -blocking 0 -translation lf -encoding $gitencoding
     fileevent $commfd readable [list getcommitlines $commfd]
+    . config -cursor watch
+    settextcursor watch
+}
+
+proc getcommits {rargs} {
+    global oldcommits commits phase canv mainfont env
+
+    # check that we can find a .git directory somewhere...
+    set gitdir [gitdir]
+    if {![file isdirectory $gitdir]} {
+       error_popup "Cannot find the git directory \"$gitdir\"."
+       exit 1
+    }
+    set oldcommits {}
+    set commits {}
+    set phase getcommits
+    start_rev_list [parse_args $rargs]
     $canv delete all
     $canv create text 3 3 -anchor nw -text "Reading commits..." \
        -font $mainfont -tags textitems
-    . config -cursor watch
-    settextcursor watch
 }
 
 proc getcommitlines {commfd}  {
-    global commits parents cdate children
+    global oldcommits commits parents cdate children nchildren
     global commitlisted phase nextupdate
     global stopped redisplaying leftover
+    global canv
 
     set stuff [read $commfd]
     if {$stuff == {}} {
@@ -119,10 +133,18 @@ proc getcommitlines {commfd}  {
        set id [lindex $ids 0]
        set olds [lrange $ids 1 end]
        set cmit [string range $cmit [expr {$j + 1}] end]
+       if {$phase == "updatecommits"} {
+           $canv delete all
+           set oldcommits $commits
+           set commits {}
+           unset children
+           unset nchildren
+           set phase getcommits
+       }
        lappend commits $id
        set commitlisted($id) 1
        parsecommit $id $cmit 1 [lrange $ids 1 end]
-       drawcommit $id
+       drawcommit $id 1
        if {[clock clicks -milliseconds] >= $nextupdate} {
            doupdate 1
        }
@@ -132,7 +154,7 @@ proc getcommitlines {commfd}  {
                set stopped 0
                set phase "getcommits"
                foreach id $commits {
-                   drawcommit $id
+                   drawcommit $id 1
                    if {$stopped} break
                    if {[clock clicks -milliseconds] >= $nextupdate} {
                        doupdate 1
@@ -168,16 +190,9 @@ proc readcommit {id} {
     parsecommit $id $contents 0 {}
 }
 
-proc parsecommit {id contents listed olds} {
-    global commitinfo children nchildren parents nparents cdate ncleft
+proc updatechildren {id olds} {
+    global children nchildren parents nparents ncleft
 
-    set inhdr 1
-    set comment {}
-    set headline {}
-    set auname {}
-    set audate {}
-    set comname {}
-    set comdate {}
     if {![info exists nchildren($id)]} {
        set children($id) {}
        set nchildren($id) 0
@@ -196,6 +211,19 @@ proc parsecommit {id contents listed olds} {
            incr ncleft($p)
        }
     }
+}
+
+proc parsecommit {id contents listed olds} {
+    global commitinfo cdate
+
+    set inhdr 1
+    set comment {}
+    set headline {}
+    set auname {}
+    set audate {}
+    set comname {}
+    set comdate {}
+    updatechildren $id $olds
     set hdrend [string first "\n\n" $contents]
     if {$hdrend < 0} {
        # should never happen...
@@ -243,6 +271,9 @@ proc readrefs {} {
     global tagids idtags headids idheads tagcontents
     global otherrefids idotherrefs
 
+    foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
+       catch {unset $v}
+    }
     set refd [open [list | git-ls-remote [gitdir]] r]
     while {0 <= [set n [gets $refd line]]} {
        if {![regexp {^([0-9a-f]{40})   refs/([^^]*)$} $line \
@@ -292,18 +323,22 @@ proc error_popup msg {
     tkwait window $w
 }
 
-proc makewindow {} {
+proc makewindow {rargs} {
     global canv canv2 canv3 linespc charspc ctext cflist textfont
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
-    global rowctxmenu gaudydiff mergemax
+    global rowctxmenu mergemax
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
+    .bar.file add command -label "Update" -command [list updatecommits $rargs]
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
+    menu .bar.edit
+    .bar add cascade -label "Edit" -menu .bar.edit
+    .bar.edit add command -label "Preferences" -command doprefs
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.help add command -label "About gitk" -command about
@@ -414,25 +449,19 @@ proc makewindow {} {
     .ctop.cdet add .ctop.cdet.left
 
     $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 m0 -fore red
-       $ctext tag conf m1 -fore blue
-       $ctext tag conf m2 -fore green
-       $ctext tag conf m3 -fore purple
-       $ctext tag conf m4 -fore brown
-       $ctext tag conf mmax -fore darkgrey
-       set mergemax 5
-       $ctext tag conf mresult -font [concat $textfont bold]
-       $ctext tag conf msep -font [concat $textfont bold]
-       $ctext tag conf found -back yellow
-    }
+    $ctext tag conf hunksep -fore blue
+    $ctext tag conf d0 -fore red
+    $ctext tag conf d1 -fore "#00a000"
+    $ctext tag conf m0 -fore red
+    $ctext tag conf m1 -fore blue
+    $ctext tag conf m2 -fore green
+    $ctext tag conf m3 -fore purple
+    $ctext tag conf m4 -fore brown
+    $ctext tag conf mmax -fore darkgrey
+    set mergemax 5
+    $ctext tag conf mresult -font [concat $textfont bold]
+    $ctext tag conf msep -font [concat $textfont bold]
+    $ctext tag conf found -back yellow
 
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
@@ -533,7 +562,7 @@ proc click {w} {
 
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
-    global stuffsaved findmergefiles gaudydiff maxgraphpct
+    global stuffsaved findmergefiles maxgraphpct
     global maxwidth
 
     if {$stuffsaved} return
@@ -543,7 +572,6 @@ proc savestuff {w} {
        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 [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
        puts $f "set geometry(width) [winfo width .ctop]"
@@ -1416,8 +1444,9 @@ proc decidenext {{noread 0}} {
     return $level
 }
 
-proc drawcommit {id} {
+proc drawcommit {id reading} {
     global phase todo nchildren datemode nextupdate revlistorder
+    global numcommits ncmupdate displayorder todo onscreen
     global numcommits ncmupdate displayorder todo onscreen parents
 
     if {$phase != "incrdraw"} {
@@ -1455,20 +1484,29 @@ proc drawcommit {id} {
            }
        }
     }
-    drawmore 1
+    drawmore $reading
 }
 
 proc finishcommits {} {
-    global phase
+    global phase oldcommits commits
     global canv mainfont ctext maincursor textcursor
+    global parents
 
-    if {$phase != "incrdraw"} {
+    if {$phase == "incrdraw" || $phase == "removecommits"} {
+       foreach id $oldcommits {
+           lappend commits $id
+           updatechildren $id $parents($id)
+           drawcommit $id 0
+       }
+       set oldcommits {}
+       drawrest
+    } elseif {$phase == "updatecommits"} {
+       set phase {}
+    } else {
        $canv delete all
        $canv create text 3 3 -anchor nw -text "No commits selected" \
            -font $mainfont -tags textitems
        set phase {}
-    } else {
-       drawrest
     }
     . config -cursor $maincursor
     settextcursor $textcursor
@@ -2841,7 +2879,6 @@ proc getblobdiffline {bdf ids} {
     global diffids blobdifffd ctext curdifftag curtagstart
     global diffnexthead diffnextnote difffilestart
     global nextupdate diffinhdr treediffs
-    global gaudydiff
 
     set n [gets $bdf line]
     if {$n < 0} {
@@ -2890,26 +2927,14 @@ proc getblobdiffline {bdf ids} {
        set diffinhdr 0
     } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
                   $line match f1l f1c f2l f2c rest]} {
-       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
-       }
+       $ctext insert end "$line\n" hunksep
        set diffinhdr 0
     } else {
        set x [string range $line 0 0]
        if {$x == "-" || $x == "+"} {
            set tag [expr {$x == "+"}]
-           if {$gaudydiff} {
-               set line [string range $line 1 end]
-           }
            $ctext insert end "$line\n" d$tag
        } elseif {$x == " "} {
-           if {$gaudydiff} {
-               set line [string range $line 1 end]
-           }
            $ctext insert end "$line\n"
        } elseif {$diffinhdr || $x == "\\"} {
            # e.g. "\ No newline at end of file"
@@ -3595,9 +3620,6 @@ proc rereadrefs {} {
            set ref($id) [listrefs $id]
        }
     }
-    foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
-       catch {unset $v}
-    }
     readrefs
     set refids [lsort -unique [concat $refids [array names idtags] \
                        [array names idheads] [array names idotherrefs]]]
@@ -3609,6 +3631,67 @@ proc rereadrefs {} {
     }
 }
 
+proc updatecommits {rargs} {
+    global commitlisted commfd phase
+    global startmsecs nextupdate ncmupdate
+    global idtags idheads idotherrefs
+    global leftover
+    global parsed_args
+    global canv
+    global oldcommits commits
+    global parents nchildren children ncleft
+
+    set old_args $parsed_args
+    parse_args $rargs
+
+    foreach id $old_args {
+       if {![regexp {^[0-9a-f]{40}$} $id]} continue
+       if {[info exists oldref($id)]} continue
+       set oldref($id) $id
+       lappend ignoreold "^$id"
+    }
+    foreach id $parsed_args {
+       if {![regexp {^[0-9a-f]{40}$} $id]} continue
+       if {[info exists ref($id)]} continue
+       set ref($id) $id
+       lappend ignorenew "^$id"
+    }
+
+    foreach a $old_args {
+       if {![info exists ref($a)]} {
+           lappend ignorenew $a
+       }
+    }
+
+    set phase updatecommits
+    set removed_commits [split [eval exec git-rev-list $ignorenew] "\n" ]
+    if {[llength $removed_commits] > 0} {
+       $canv delete all
+       set oldcommits {}
+       foreach c $commits {
+           if {[lsearch $c $removed_commits] < 0} {
+               lappend oldcommits $c
+           } else {
+               unset commitlisted($c)
+           }
+       }
+       set commits {}
+       unset children
+       unset nchildren
+       set phase removecommits
+    }
+
+    set args {}
+    foreach a $parsed_args {
+       if {![info exists oldref($a)]} {
+           lappend args $a
+       }
+    }
+
+    readrefs
+    start_rev_list [concat $ignoreold $args]
+}
+
 proc showtag {tag isnew} {
     global ctext cflist tagcontents tagids linknum
 
@@ -3634,34 +3717,94 @@ proc doquit {} {
     destroy .
 }
 
-proc formatdate {d} {
-    global hours nhours tfd fastdate
+proc doprefs {} {
+    global maxwidth maxgraphpct diffopts findmergefiles
+    global oldprefs prefstop
+
+    set top .gitkprefs
+    set prefstop $top
+    if {[winfo exists $top]} {
+       raise $top
+       return
+    }
+    foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+       set oldprefs($v) [set $v]
+    }
+    toplevel $top
+    wm title $top "Gitk preferences"
+    label $top.ldisp -text "Commit list display options"
+    grid $top.ldisp - -sticky w -pady 10
+    label $top.spacer -text " "
+    label $top.maxwidthl -text "Maximum graph width (lines)" \
+       -font optionfont
+    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
+    label $top.maxpctl -text "Maximum graph width (% of pane)" \
+       -font optionfont
+    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $top.maxpctl $top.maxpct -sticky w
+    checkbutton $top.findm -variable findmergefiles
+    label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
+       -font optionfont
+    grid $top.findm $top.findml - -sticky w
+    label $top.ddisp -text "Diff display options"
+    grid $top.ddisp - -sticky w -pady 10
+    label $top.diffoptl -text "Options for diff program" \
+       -font optionfont
+    entry $top.diffopt -width 20 -textvariable diffopts
+    grid x $top.diffoptl $top.diffopt -sticky w
+    frame $top.buts
+    button $top.buts.ok -text "OK" -command prefsok
+    button $top.buts.can -text "Cancel" -command prefscan
+    grid $top.buts.ok $top.buts.can
+    grid columnconfigure $top.buts 0 -weight 1 -uniform a
+    grid columnconfigure $top.buts 1 -weight 1 -uniform a
+    grid $top.buts - - -pady 10 -sticky ew
+}
+
+proc prefscan {} {
+    global maxwidth maxgraphpct diffopts findmergefiles
+    global oldprefs prefstop
 
-    if {!$fastdate} {
-       return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+    foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
+       set $v $oldprefs($v)
     }
-    set hr [expr {$d / 3600}]
-    set ms [expr {$d % 3600}]
-    if {![info exists hours($hr)]} {
-       set hours($hr) [clock format $d -format "%Y-%m-%d %H"]
-       set nhours($hr) 0
+    catch {destroy $prefstop}
+    unset prefstop
+}
+
+proc prefsok {} {
+    global maxwidth maxgraphpct
+    global oldprefs prefstop
+
+    catch {destroy $prefstop}
+    unset prefstop
+    if {$maxwidth != $oldprefs(maxwidth)
+       || $maxgraphpct != $oldprefs(maxgraphpct)} {
+       redisplay
     }
-    incr nhours($hr)
-    set minsec [format "%.2d:%.2d" [expr {$ms/60}] [expr {$ms%60}]]
-    return "$hours($hr):$minsec"
+}
+
+proc formatdate {d} {
+    return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
 }
 
 # defaults...
 set datemode 0
-set boldnames 0
 set diffopts "-U 5 -p"
 set wrcomcmd "git-diff-tree --stdin -p --pretty"
-set gitencoding "utf-8"
+
+set gitencoding ""
+catch {
+    set gitencoding [exec git-repo-config --get i18n.commitencoding]
+}
+if {$gitencoding == ""} {
+       set gitencoding "utf-8"
+}
 
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
 set findmergefiles 0
-set gaudydiff 0
 set maxgraphpct 50
 set maxwidth 16
 set revlistorder 0
@@ -3672,15 +3815,13 @@ set colors {green red blue magenta darkgrey brown orange}
 catch {source ~/.gitk}
 
 set namefont $mainfont
-if {$boldnames} {
-    lappend namefont bold
-}
+
+font create optionfont -family sans-serif -size -12
 
 set revtreeargs {}
 foreach arg $argv {
     switch -regexp -- $arg {
        "^$" { }
-       "^-b" { set boldnames 1 }
        "^-d" { set datemode 1 }
        "^-r" { set revlistorder 1 }
        default {
@@ -3697,6 +3838,6 @@ set redisplaying 0
 set stuffsaved 0
 set patchnum 0
 setcoords
-makewindow
+makewindow $revtreeargs
 readrefs
 getcommits $revtreeargs