}
}
-proc start_rev_list {} {
+proc start_rev_list {view} {
global startmsecs nextupdate ncmupdate
global commfd leftover tclencoding datemode
- global revtreeargs curview viewfiles
+ global viewargs viewfiles commitidx
set startmsecs [clock clicks -milliseconds]
set nextupdate [expr {$startmsecs + 100}]
set ncmupdate 1
- initlayout
- set args $revtreeargs
- if {$viewfiles($curview) ne {}} {
- set args [concat $args "--" $viewfiles($curview)]
+ 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 commfd [open [concat | git-rev-list --header $order \
- --parents --boundary --default HEAD $args] r]
+ set fd [open [concat | git-rev-list --header $order \
+ --parents --boundary --default HEAD $args] r]
} err]} {
puts stderr "Error executing git-rev-list: $err"
exit 1
}
- set leftover {}
- fconfigure $commfd -blocking 0 -translation lf
+ set commfd($view) $fd
+ set leftover($view) {}
+ fconfigure $fd -blocking 0 -translation lf
if {$tclencoding != {}} {
- fconfigure $commfd -encoding $tclencoding
+ fconfigure $fd -encoding $tclencoding
}
- fileevent $commfd readable [list getcommitlines $commfd]
- . config -cursor watch
- settextcursor watch
+ fileevent $fd readable [list getcommitlines $fd $view]
+ nowbusy $view
}
proc stop_rev_list {} {
- global commfd
+ global commfd curview
- if {![info exists commfd]} return
+ if {![info exists commfd($curview)]} return
+ set fd $commfd($curview)
catch {
- set pid [pid $commfd]
+ set pid [pid $fd]
exec kill $pid
}
- catch {close $commfd}
- unset commfd
+ catch {close $fd}
+ unset commfd($curview)
}
proc getcommits {} {
- global phase canv mainfont
+ global phase canv mainfont curview
set phase getcommits
- start_rev_list
- $canv delete all
- $canv create text 3 3 -anchor nw -text "Reading commits..." \
- -font $mainfont -tags textitems
+ initlayout
+ start_rev_list $curview
+ show_status "Reading commits..."
}
-proc getcommitlines {commfd} {
+proc getcommitlines {fd view} {
global commitlisted nextupdate
- global leftover
+ global leftover commfd
global displayorder commitidx commitrow commitdata
- global parentlist childlist children
+ global parentlist childlist children curview hlview
+ global vparentlist vchildlist vdisporder vcmitlisted
- set stuff [read $commfd]
+ set stuff [read $fd]
if {$stuff == {}} {
- if {![eof $commfd]} return
+ if {![eof $fd]} return
+ global viewname
+ unset commfd($view)
+ notbusy $view
# set it blocking so we wait for the process to terminate
- fconfigure $commfd -blocking 1
- if {![catch {close $commfd} err]} {
- after idle finishcommits
- return
+ fconfigure $fd -blocking 1
+ if {[catch {close $fd} err]} {
+ set fv {}
+ if {$view != $curview} {
+ set fv " for the \"$viewname($view)\" view"
+ }
+ if {[string range $err 0 4] == "usage"} {
+ set err "Gitk: error reading commits$fv:\
+ bad arguments to git-rev-list."
+ if {$viewname($view) eq "Command line"} {
+ append err \
+ " (Note: arguments to gitk are passed to git-rev-list\
+ to allow selection of commits to be displayed.)"
+ }
+ } else {
+ set err "Error reading commits$fv: $err"
+ }
+ error_popup $err
}
- if {[string range $err 0 4] == "usage"} {
- set err \
- "Gitk: error reading commits: bad arguments to git-rev-list.\
- (Note: arguments to gitk are passed to git-rev-list\
- to allow selection of commits to be displayed.)"
- } else {
- set err "Error reading commits: $err"
+ if {$view == $curview} {
+ after idle finishcommits
}
- error_popup $err
- exit 1
+ return
}
set start 0
set gotsome 0
while 1 {
set i [string first "\0" $stuff $start]
if {$i < 0} {
- append leftover [string range $stuff $start end]
+ append leftover($view) [string range $stuff $start end]
break
}
if {$start == 0} {
- set cmit $leftover
+ set cmit $leftover($view)
append cmit [string range $stuff 0 [expr {$i - 1}]]
- set leftover {}
+ set leftover($view) {}
} else {
set cmit [string range $stuff $start [expr {$i - 1}]]
}
set i 0
foreach p $olds {
if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
- lappend children($p) $id
+ lappend children($view,$p) $id
}
incr i
}
} else {
set olds {}
}
- lappend parentlist $olds
- if {[info exists children($id)]} {
- lappend childlist $children($id)
- unset children($id)
- } else {
- lappend childlist {}
+ if {![info exists children($view,$id)]} {
+ set children($view,$id) {}
}
set commitdata($id) [string range $cmit [expr {$j + 1}] end]
- set commitrow($id) $commitidx
- incr commitidx
- lappend displayorder $id
- lappend commitlisted $listed
+ set commitrow($view,$id) $commitidx($view)
+ incr commitidx($view)
+ if {$view == $curview} {
+ lappend parentlist $olds
+ lappend childlist $children($view,$id)
+ lappend displayorder $id
+ lappend commitlisted $listed
+ } else {
+ lappend vparentlist($view) $olds
+ lappend vchildlist($view) $children($view,$id)
+ lappend vdisporder($view) $id
+ lappend vcmitlisted($view) $listed
+ }
set gotsome 1
}
if {$gotsome} {
- layoutmore
+ if {$view == $curview} {
+ layoutmore
+ } elseif {[info exists hlview] && $view == $hlview} {
+ highlightmore
+ }
}
if {[clock clicks -milliseconds] >= $nextupdate} {
- doupdate 1
+ doupdate
}
}
-proc doupdate {reading} {
+proc doupdate {} {
global commfd nextupdate numcommits ncmupdate
- if {$reading} {
- fileevent $commfd readable {}
+ foreach v [array names commfd] {
+ fileevent $commfd($v) readable {}
}
update
set nextupdate [expr {[clock clicks -milliseconds] + 100}]
} else {
set ncmupdate [expr {$numcommits + 100}]
}
- if {$reading} {
- fileevent $commfd readable [list getcommitlines $commfd]
+ foreach v [array names commfd] {
+ set fd $commfd($v)
+ fileevent $fd readable [list getcommitlines $fd $v]
}
}
}
proc updatecommits {} {
- global viewdata curview revtreeargs phase
+ global viewdata curview phase displayorder
+ global children commitrow
if {$phase ne {}} {
stop_rev_list
set phase {}
}
set n $curview
+ foreach id $displayorder {
+ catch {unset children($n,$id)}
+ catch {unset commitrow($n,$id)}
+ }
set curview -1
catch {unset viewdata($n)}
readrefs
close $refd
}
-proc error_popup msg {
- set w .error
- toplevel $w
- wm transient $w .
+proc show_error {w msg} {
message $w.m -text $msg -justify center -aspect 400
pack $w.m -side top -fill x -padx 20 -pady 20
button $w.ok -text OK -command "destroy $w"
tkwait window $w
}
+proc error_popup msg {
+ set w .error
+ toplevel $w
+ wm transient $w .
+ show_error $w $msg
+}
+
proc makewindow {} {
global canv canv2 canv3 linespc charspc ctext cflist
global textfont mainfont uifont
.bar add cascade -label "Edit" -menu .bar.edit
.bar.edit add command -label "Preferences" -command doprefs
.bar.edit configure -font $uifont
+
menu .bar.view -font $uifont
+ menu .bar.view.hl -font $uifont -tearoff 0
.bar add cascade -label "View" -menu .bar.view
- .bar.view add command -label "New view..." -command newview
- .bar.view add command -label "Edit view..." -command editview
+ .bar.view add command -label "New view..." -command {newview 0}
+ .bar.view add command -label "Edit view..." -command editview \
+ -state disabled
.bar.view add command -label "Delete view" -command delview -state disabled
+ .bar.view add cascade -label "Highlight" -menu .bar.view.hl
.bar.view add separator
.bar.view add radiobutton -label "All files" -command {showview 0} \
-variable selectedview -value 0
+ .bar.view.hl add command -label "New view..." -command {newview 1}
+ .bar.view.hl add command -label "Remove" -command delhighlight \
+ -state disabled
+ .bar.view.hl add separator
+
menu .bar.help
.bar add cascade -label "Help" -menu .bar.help
.bar.help add command -label "About gitk" -command about
set ctext .ctop.cdet.left.ctext
text $ctext -bg white -state disabled -font $textfont \
-width $geometry(ctextw) -height $geometry(ctexth) \
- -yscrollcommand scrolltext -wrap none
+ -yscrollcommand {.ctop.cdet.left.sb set} -wrap none
scrollbar .ctop.cdet.left.sb -command "$ctext yview"
pack .ctop.cdet.left.sb -side right -fill y
pack $ctext -side left -fill both -expand 1
scrollbar .ctop.cdet.right.sb -command "$cflist yview"
pack .ctop.cdet.right.sb -side right -fill y
pack $cflist -side left -fill both -expand 1
- $cflist tag configure highlight -background yellow
+ $cflist tag configure highlight \
+ -background [$cflist cget -selectbackground]
.ctop.cdet add .ctop.cdet.right
bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
global canv canv2 canv3 ctext cflist mainfont textfont uifont
global stuffsaved findmergefiles maxgraphpct
global maxwidth
- global viewname viewfiles viewperm nextviewnum
+ global viewname viewfiles viewargs viewperm nextviewnum
global cmitmode
if {$stuffsaved} return
puts -nonewline $f "set permviews {"
for {set v 0} {$v < $nextviewnum} {incr v} {
if {$viewperm($v)} {
- puts $f "{[list $viewname($v) $viewfiles($v)]}"
+ puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v)]}"
}
}
puts $f "}"
}
proc init_flist {first} {
- global cflist cflist_top cflist_bot selectedline difffilestart
+ global cflist cflist_top selectedline difffilestart
$cflist conf -state normal
$cflist delete 0.0 end
if {$first ne {}} {
$cflist insert end $first
set cflist_top 1
- set cflist_bot 1
$cflist tag add highlight 1.0 "1.0 lineend"
} else {
catch {unset cflist_top}
if {$cmitmode eq "tree"} return
if {![info exists cflist_top]} return
set l [lindex [split [$w index "@$x,$y"] "."] 0]
+ $cflist tag remove highlight $cflist_top.0 "$cflist_top.0 lineend"
+ $cflist tag add highlight $l.0 "$l.0 lineend"
+ set cflist_top $l
if {$l == 1} {
$ctext yview 1.0
} else {
catch {$ctext yview [lindex $difffilestart [expr {$l - 2}]]}
}
- highlight_flist $l
}
-proc scrolltext {f0 f1} {
- global cflist_top
+# Functions for adding and removing shell-type quoting
- .ctop.cdet.left.sb set $f0 $f1
- if {[info exists cflist_top]} {
- highlight_flist $cflist_top
+proc shellquote {str} {
+ if {![string match "*\['\"\\ \t]*" $str]} {
+ return $str
}
-}
-
-# Given an index $tl in the $ctext window, this works out which line
-# of the $cflist window displays the filename whose patch is shown
-# at the given point in the $ctext window. $ll is a hint about which
-# line it might be, and is used as the starting point of the search.
-proc ctext_index {tl ll} {
- global ctext difffilestart
-
- while {$ll >= 2 && [$ctext compare $tl < \
- [lindex $difffilestart [expr {$ll - 2}]]]} {
- incr ll -1
+ if {![string match "*\['\"\\]*" $str]} {
+ return "\"$str\""
}
- set nfiles [llength $difffilestart]
- while {$ll - 1 < $nfiles && [$ctext compare $tl >= \
- [lindex $difffilestart [expr {$ll - 1}]]]} {
- incr ll
+ if {![string match "*'*" $str]} {
+ return "'$str'"
}
- return $ll
+ return "\"[string map {\" \\\" \\ \\\\} $str]\""
}
-proc highlight_flist {ll} {
- global ctext cflist cflist_top cflist_bot difffilestart
-
- if {![info exists difffilestart] || [llength $difffilestart] == 0} return
- set ll [ctext_index [$ctext index @0,1] $ll]
- set lb $cflist_bot
- if {$lb < $ll} {
- set lb $ll
+proc shellarglist {l} {
+ set str {}
+ foreach a $l {
+ if {$str ne {}} {
+ append str " "
+ }
+ append str [shellquote $a]
}
- set y [expr {[winfo height $ctext] - 2}]
- set lb [ctext_index [$ctext index @0,$y] $lb]
- if {$ll != $cflist_top || $lb != $cflist_bot} {
- $cflist tag remove highlight $cflist_top.0 "$cflist_bot.0 lineend"
- for {set l $ll} {$l <= $lb} {incr l} {
- $cflist tag add highlight $l.0 "$l.0 lineend"
+ return $str
+}
+
+proc shelldequote {str} {
+ set ret {}
+ set used -1
+ while {1} {
+ incr used
+ if {![regexp -start $used -indices "\['\"\\\\ \t]" $str first]} {
+ append ret [string range $str $used end]
+ set used [string length $str]
+ break
+ }
+ set first [lindex $first 0]
+ set ch [string index $str $first]
+ if {$first > $used} {
+ append ret [string range $str $used [expr {$first - 1}]]
+ set used $first
+ }
+ if {$ch eq " " || $ch eq "\t"} break
+ incr used
+ if {$ch eq "'"} {
+ set first [string first "'" $str $used]
+ if {$first < 0} {
+ error "unmatched single-quote"
+ }
+ append ret [string range $str $used [expr {$first - 1}]]
+ set used $first
+ continue
+ }
+ if {$ch eq "\\"} {
+ if {$used >= [string length $str]} {
+ error "trailing backslash"
+ }
+ append ret [string index $str $used]
+ continue
+ }
+ # here ch == "\""
+ while {1} {
+ if {![regexp -start $used -indices "\[\"\\\\]" $str first]} {
+ error "unmatched double-quote"
+ }
+ set first [lindex $first 0]
+ set ch [string index $str $first]
+ if {$first > $used} {
+ append ret [string range $str $used [expr {$first - 1}]]
+ set used $first
+ }
+ if {$ch eq "\""} break
+ incr used
+ append ret [string index $str $used]
+ incr used
}
- set cflist_top $ll
- set cflist_bot $lb
}
+ return [list $used $ret]
+}
+
+proc shellsplit {str} {
+ set l {}
+ while {1} {
+ set str [string trimleft $str]
+ if {$str eq {}} break
+ set dq [shelldequote $str]
+ set n [lindex $dq 0]
+ set word [lindex $dq 1]
+ set str [string range $str $n end]
+ lappend l $word
+ }
+ return $l
}
# Code to implement multiple views
-proc newview {} {
- global nextviewnum newviewname newviewperm uifont
+proc newview {ishighlight} {
+ global nextviewnum newviewname newviewperm uifont newishighlight
+ global newviewargs revtreeargs
+ set newishighlight $ishighlight
set top .gitkview
if {[winfo exists $top]} {
raise $top
}
set newviewname($nextviewnum) "View $nextviewnum"
set newviewperm($nextviewnum) 0
+ set newviewargs($nextviewnum) [shellarglist $revtreeargs]
vieweditor $top $nextviewnum "Gitk view definition"
}
proc editview {} {
global curview
global viewname viewperm newviewname newviewperm
+ global viewargs newviewargs
set top .gitkvedit-$curview
if {[winfo exists $top]} {
}
set newviewname($curview) $viewname($curview)
set newviewperm($curview) $viewperm($curview)
+ set newviewargs($curview) [shellarglist $viewargs($curview)]
vieweditor $top $curview "Gitk: edit view $viewname($curview)"
}
grid $top.nl $top.name -sticky w -pady 5
checkbutton $top.perm -text "Remember this view" -variable newviewperm($n)
grid $top.perm - -pady 5 -sticky w
- message $top.l -aspect 500 -font $uifont \
+ message $top.al -aspect 1000 -font $uifont \
+ -text "Commits to include (arguments to git-rev-list):"
+ grid $top.al - -sticky w -pady 5
+ entry $top.args -width 50 -textvariable newviewargs($n) \
+ -background white
+ grid $top.args - -sticky ew -padx 5
+ message $top.l -aspect 1000 -font $uifont \
-text "Enter files and directories to include, one per line:"
grid $top.l - -sticky w
text $top.t -width 40 -height 10 -background white
$top.t delete {end - 1c} end
$top.t mark set insert 0.0
}
- grid $top.t - -sticky w -padx 5
+ grid $top.t - -sticky ew -padx 5
frame $top.buts
button $top.buts.ok -text "OK" -command [list newviewok $top $n]
button $top.buts.can -text "Cancel" -command [list destroy $top]
focus $top.t
}
-proc viewmenuitem {n} {
- set nmenu [.bar.view index end]
- set targetcmd [list showview $n]
- for {set i 6} {$i <= $nmenu} {incr i} {
- if {[.bar.view entrycget $i -command] eq $targetcmd} {
- return $i
+proc doviewmenu {m first cmd op args} {
+ set nmenu [$m index end]
+ for {set i $first} {$i <= $nmenu} {incr i} {
+ if {[$m entrycget $i -command] eq $cmd} {
+ eval $m $op $i $args
+ break
}
}
- return {}
+}
+
+proc allviewmenus {n op args} {
+ doviewmenu .bar.view 7 [list showview $n] $op $args
+ doviewmenu .bar.view.hl 3 [list addhighlight $n] $op $args
}
proc newviewok {top n} {
- global nextviewnum newviewperm newviewname
+ global nextviewnum newviewperm newviewname newishighlight
global viewname viewfiles viewperm selectedview curview
+ global viewargs newviewargs
+ if {[catch {
+ set newargs [shellsplit $newviewargs($n)]
+ } err]} {
+ error_popup "Error in commit selection arguments: $err"
+ wm raise $top
+ focus $top
+ return
+ }
set files {}
foreach f [split [$top.t get 0.0 end] "\n"] {
set ft [string trim $f]
set viewname($n) $newviewname($n)
set viewperm($n) $newviewperm($n)
set viewfiles($n) $files
- .bar.view add radiobutton -label $viewname($n) \
- -command [list showview $n] -variable selectedview -value $n
- after idle showview $n
+ set viewargs($n) $newargs
+ addviewmenu $n
+ if {!$newishighlight} {
+ after idle showview $n
+ } else {
+ after idle addhighlight $n
+ }
} else {
# editing an existing view
set viewperm($n) $newviewperm($n)
if {$newviewname($n) ne $viewname($n)} {
set viewname($n) $newviewname($n)
- set i [viewmenuitem $n]
- if {$i ne {}} {
- .bar.view entryconf $i -label $viewname($n)
- }
+ allviewmenus $n entryconf -label $viewname($n)
}
- if {$files ne $viewfiles($n)} {
+ if {$files ne $viewfiles($n) || $newargs ne $viewargs($n)} {
set viewfiles($n) $files
+ set viewargs($n) $newargs
if {$curview == $n} {
after idle updatecommits
}
global curview viewdata viewperm
if {$curview == 0} return
- set i [viewmenuitem $curview]
- if {$i ne {}} {
- .bar.view delete $i
- }
+ allviewmenus $curview delete
set viewdata($curview) {}
set viewperm($curview) 0
showview 0
}
+proc addviewmenu {n} {
+ global viewname
+
+ .bar.view add radiobutton -label $viewname($n) \
+ -command [list showview $n] -variable selectedview -value $n
+ .bar.view.hl add radiobutton -label $viewname($n) \
+ -command [list addhighlight $n] -variable selectedhlview -value $n
+}
+
proc flatten {var} {
global $var
proc showview {n} {
global curview viewdata viewfiles
global displayorder parentlist childlist rowidlist rowoffsets
- global colormap rowtextx commitrow
+ global colormap rowtextx commitrow nextcolor canvxmax
global numcommits rowrangelist commitlisted idrowranges
global selectedline currentid canv canvy0
global matchinglines treediffs
global pending_select phase
- global commitidx rowlaidout rowoptim linesegends leftover
+ global commitidx rowlaidout rowoptim linesegends
global commfd nextupdate
- global selectedview
+ global selectedview hlview selectedhlview
+ global vparentlist vchildlist vdisporder vcmitlisted
if {$n == $curview} return
set selid {}
normalline
stopfindproc
if {$curview >= 0} {
+ set vparentlist($curview) $parentlist
+ set vchildlist($curview) $childlist
+ set vdisporder($curview) $displayorder
+ set vcmitlisted($curview) $commitlisted
if {$phase ne {}} {
set viewdata($curview) \
- [list $phase $displayorder $parentlist $childlist $rowidlist \
- $rowoffsets $rowrangelist $commitlisted \
- [flatten children] [flatten idrowranges] \
- [flatten idinlist] \
- $commitidx $rowlaidout $rowoptim $numcommits \
- $linesegends $leftover $commfd]
- fileevent $commfd readable {}
+ [list $phase $rowidlist $rowoffsets $rowrangelist \
+ [flatten idrowranges] [flatten idinlist] \
+ $rowlaidout $rowoptim $numcommits $linesegends]
} elseif {![info exists viewdata($curview)]
|| [lindex $viewdata($curview) 0] ne {}} {
set viewdata($curview) \
- [list {} $displayorder $parentlist $childlist $rowidlist \
- $rowoffsets $rowrangelist $commitlisted]
+ [list {} $rowidlist $rowoffsets $rowrangelist]
}
}
catch {unset matchinglines}
set curview $n
set selectedview $n
+ set selectedhlview -1
.bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}]
.bar.view entryconf 3 -state [expr {$n == 0? "disabled": "normal"}]
+ catch {unset hlview}
+ .bar.view.hl entryconf 1 -state disabled
if {![info exists viewdata($n)]} {
set pending_select $selid
set v $viewdata($n)
set phase [lindex $v 0]
- set displayorder [lindex $v 1]
- set parentlist [lindex $v 2]
- set childlist [lindex $v 3]
- set rowidlist [lindex $v 4]
- set rowoffsets [lindex $v 5]
- set rowrangelist [lindex $v 6]
- set commitlisted [lindex $v 7]
+ set displayorder $vdisporder($n)
+ set parentlist $vparentlist($n)
+ set childlist $vchildlist($n)
+ set commitlisted $vcmitlisted($n)
+ set rowidlist [lindex $v 1]
+ set rowoffsets [lindex $v 2]
+ set rowrangelist [lindex $v 3]
if {$phase eq {}} {
set numcommits [llength $displayorder]
catch {unset idrowranges}
- catch {unset children}
} else {
- unflatten children [lindex $v 8]
- unflatten idrowranges [lindex $v 9]
- unflatten idinlist [lindex $v 10]
- set commitidx [lindex $v 11]
- set rowlaidout [lindex $v 12]
- set rowoptim [lindex $v 13]
- set numcommits [lindex $v 14]
- set linesegends [lindex $v 15]
- set leftover [lindex $v 16]
- set commfd [lindex $v 17]
- fileevent $commfd readable [list getcommitlines $commfd]
- set nextupdate [expr {[clock clicks -milliseconds] + 100}]
+ unflatten idrowranges [lindex $v 4]
+ unflatten idinlist [lindex $v 5]
+ set rowlaidout [lindex $v 6]
+ set rowoptim [lindex $v 7]
+ set numcommits [lindex $v 8]
+ set linesegends [lindex $v 9]
}
catch {unset colormap}
catch {unset rowtextx}
- catch {unset commitrow}
+ set nextcolor 0
+ set canvxmax [$canv cget -width]
set curview $n
set row 0
- foreach id $displayorder {
- set commitrow($id) $row
- incr row
- }
setcanvscroll
set yf 0
set row 0
- if {$selid ne {} && [info exists commitrow($selid)]} {
- set row $commitrow($selid)
+ if {$selid ne {} && [info exists commitrow($n,$selid)]} {
+ set row $commitrow($n,$selid)
# try to get the selected row in the same position on the screen
set ymax [lindex [$canv cget -scrollregion] 3]
set ytop [expr {[yc $row] - $yscreen}]
allcanvs yview moveto $yf
drawvisible
selectline $row 0
- if {$phase eq {}} {
- global maincursor textcursor
- . config -cursor $maincursor
- settextcursor $textcursor
- } else {
- . config -cursor watch
- settextcursor watch
+ if {$phase ne {}} {
if {$phase eq "getcommits"} {
- global mainfont
- $canv create text 3 3 -anchor nw -text "Reading commits..." \
- -font $mainfont -tags textitems
+ show_status "Reading commits..."
+ }
+ if {[info exists commfd($n)]} {
+ layoutmore
+ } else {
+ finishcommits
+ }
+ } elseif {$numcommits == 0} {
+ show_status "No commits selected"
+ }
+}
+
+proc addhighlight {n} {
+ global hlview curview viewdata highlighted highlightedrows
+ global selectedhlview
+
+ if {[info exists hlview]} {
+ delhighlight
+ }
+ set hlview $n
+ set selectedhlview $n
+ .bar.view.hl entryconf 1 -state normal
+ set highlighted($n) 0
+ set highlightedrows {}
+ if {$n != $curview && ![info exists viewdata($n)]} {
+ set viewdata($n) [list getcommits {{}} {{}} {} {} {} 0 0 0 {}]
+ set vparentlist($n) {}
+ set vchildlist($n) {}
+ set vdisporder($n) {}
+ set vcmitlisted($n) {}
+ start_rev_list $n
+ } else {
+ highlightmore
+ }
+}
+
+proc delhighlight {} {
+ global hlview highlightedrows canv linehtag mainfont
+ global selectedhlview selectedline
+
+ if {![info exists hlview]} return
+ unset hlview
+ set selectedhlview {}
+ .bar.view.hl entryconf 1 -state disabled
+ foreach l $highlightedrows {
+ $canv itemconf $linehtag($l) -font $mainfont
+ if {$l == $selectedline} {
+ $canv delete secsel
+ set t [eval $canv create rect [$canv bbox $linehtag($l)] \
+ -outline {{}} -tags secsel \
+ -fill [$canv cget -selectbackground]]
+ $canv lower $t
}
}
}
+proc highlightmore {} {
+ global hlview highlighted commitidx highlightedrows linehtag mainfont
+ global displayorder vdisporder curview canv commitrow selectedline
+
+ set font [concat $mainfont bold]
+ set max $commitidx($hlview)
+ if {$hlview == $curview} {
+ set disp $displayorder
+ } else {
+ set disp $vdisporder($hlview)
+ }
+ for {set i $highlighted($hlview)} {$i < $max} {incr i} {
+ set id [lindex $disp $i]
+ if {[info exists commitrow($curview,$id)]} {
+ set row $commitrow($curview,$id)
+ if {[info exists linehtag($row)]} {
+ $canv itemconf $linehtag($row) -font $font
+ lappend highlightedrows $row
+ if {$row == $selectedline} {
+ $canv delete secsel
+ set t [eval $canv create rect \
+ [$canv bbox $linehtag($row)] \
+ -outline {{}} -tags secsel \
+ -fill [$canv cget -selectbackground]]
+ $canv lower $t
+ }
+ }
+ }
+ }
+ set highlighted($hlview) $max
+}
+
+# Graph layout functions
+
proc shortids {ids} {
set res {}
foreach id $ids {
}
proc usedinrange {id l1 l2} {
- global children commitrow childlist
+ global children commitrow childlist curview
- if {[info exists commitrow($id)]} {
- set r $commitrow($id)
+ if {[info exists commitrow($curview,$id)]} {
+ set r $commitrow($curview,$id)
if {$l1 <= $r && $r <= $l2} {
return [expr {$r - $l1 + 1}]
}
set kids [lindex $childlist $r]
} else {
- set kids $children($id)
+ set kids $children($curview,$id)
}
foreach c $kids {
- set r $commitrow($c)
+ set r $commitrow($curview,$c)
if {$l1 <= $r && $r <= $l2} {
return [expr {$r - $l1 + 1}]
}
global rowidlist rowoffsets displayorder commitlisted
global rowlaidout rowoptim
global idinlist rowchk rowrangelist idrowranges
- global commitidx numcommits canvxmax canv
+ global numcommits canvxmax canv
global nextcolor
global parentlist childlist children
- global colormap rowtextx commitrow
+ global colormap rowtextx
global linesegends
- set commitidx 0
set numcommits 0
set displayorder {}
set commitlisted {}
set parentlist {}
set childlist {}
set rowrangelist {}
- catch {unset children}
set nextcolor 0
set rowidlist {{}}
set rowoffsets {{}}
set canvxmax [$canv cget -width]
catch {unset colormap}
catch {unset rowtextx}
- catch {unset commitrow}
catch {unset idrowranges}
set linesegends {}
}
proc layoutmore {} {
global rowlaidout rowoptim commitidx numcommits optim_delay
- global uparrowlen
+ global uparrowlen curview
set row $rowlaidout
- set rowlaidout [layoutrows $row $commitidx 0]
+ set rowlaidout [layoutrows $row $commitidx($curview) 0]
set orow [expr {$rowlaidout - $uparrowlen - 1}]
if {$orow > $rowoptim} {
optimize_rows $rowoptim 0 $orow
proc showstuff {canshow} {
global numcommits commitrow pending_select selectedline
- global linesegends idrowranges idrangedrawn
+ global linesegends idrowranges idrangedrawn curview
if {$numcommits == 0} {
global phase
incr row
}
if {[info exists pending_select] &&
- [info exists commitrow($pending_select)] &&
- $commitrow($pending_select) < $numcommits} {
- selectline $commitrow($pending_select) 1
+ [info exists commitrow($curview,$pending_select)] &&
+ $commitrow($curview,$pending_select) < $numcommits} {
+ selectline $commitrow($curview,$pending_select) 1
}
if {![info exists selectedline] && ![info exists pending_select]} {
selectline 0 1
global uparrowlen downarrowlen maxwidth mingaplen
global childlist parentlist
global idrowranges linesegends
- global commitidx
+ global commitidx curview
global idinlist rowchk rowrangelist
set idlist [lindex $rowidlist $row]
set nev [expr {[llength $idlist] + [llength $newolds]
+ [llength $oldolds] - $maxwidth + 1}]
if {$nev > 0} {
- if {!$last && $row + $uparrowlen + $mingaplen >= $commitidx} break
+ if {!$last &&
+ $row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
for {set x [llength $idlist]} {[incr x -1] >= 0} {} {
set i [lindex $idlist $x]
if {![info exists rowchk($i)] || $row >= $rowchk($i)} {
proc addextraid {id row} {
global displayorder commitrow commitinfo
global commitidx commitlisted
- global parentlist childlist children
+ global parentlist childlist children curview
- incr commitidx
+ incr commitidx($curview)
lappend displayorder $id
lappend commitlisted 0
lappend parentlist {}
- set commitrow($id) $row
+ set commitrow($curview,$id) $row
readcommit $id
if {![info exists commitinfo($id)]} {
set commitinfo($id) {"No commit information available"}
}
- if {[info exists children($id)]} {
- lappend childlist $children($id)
- unset children($id)
- } else {
- lappend childlist {}
+ if {![info exists children($curview,$id)]} {
+ set children($curview,$id) {}
}
+ lappend childlist $children($curview,$id)
}
proc layouttail {} {
- global rowidlist rowoffsets idinlist commitidx
+ global rowidlist rowoffsets idinlist commitidx curview
global idrowranges rowrangelist
- set row $commitidx
+ set row $commitidx($curview)
set idlist [lindex $rowidlist $row]
while {$idlist ne {}} {
set col [expr {[llength $idlist] - 1}]
}
proc rowranges {id} {
- global phase idrowranges commitrow rowlaidout rowrangelist
+ global phase idrowranges commitrow rowlaidout rowrangelist curview
set ranges {}
if {$phase eq {} ||
- ([info exists commitrow($id)] && $commitrow($id) < $rowlaidout)} {
- set ranges [lindex $rowrangelist $commitrow($id)]
+ ([info exists commitrow($curview,$id)]
+ && $commitrow($curview,$id) < $rowlaidout)} {
+ set ranges [lindex $rowrangelist $commitrow($curview,$id)]
} elseif {[info exists idrowranges($id)]} {
set ranges $idrowranges($id)
}
global rowoffsets rowidlist
global displayorder
global canv colormap linespc
- global numcommits commitrow
+ global numcommits commitrow curview
set ranges [rowranges $id]
set downarrow 1
- if {[info exists commitrow($id)] && $commitrow($id) < $numcommits} {
+ if {[info exists commitrow($curview,$id)]
+ && $commitrow($curview,$id) < $numcommits} {
set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
} else {
set downarrow 1
proc drawlines {id} {
global colormap canv
global idrangedrawn
- global childlist iddrawn commitrow rowidlist
+ global children iddrawn commitrow rowidlist curview
$canv delete lines.$id
set nr [expr {[llength [rowranges $id]] / 2}]
drawlineseg $id $i
}
}
- foreach child [lindex $childlist $commitrow($id)] {
+ foreach child $children($curview,$id) {
if {[info exists iddrawn($child)]} {
- set row $commitrow($child)
+ set row $commitrow($curview,$child)
set col [lsearch -exact [lindex $rowidlist $row] $child]
if {$col >= 0} {
drawparentlinks $child $row $col [list $id]
global commitlisted commitinfo rowidlist
global rowtextx idpos idtags idheads idotherrefs
global linehtag linentag linedtag
- global mainfont namefont canvxmax
+ global mainfont canvxmax
+ global hlview commitrow highlightedrows
set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
set x [xc $row $col]
set name [lindex $commitinfo($id) 1]
set date [lindex $commitinfo($id) 2]
set date [formatdate $date]
+ set font $mainfont
+ if {[info exists hlview] && [info exists commitrow($hlview,$id)]} {
+ lappend font bold
+ lappend highlightedrows $row
+ }
set linehtag($row) [$canv create text $xt $y -anchor w \
- -text $headline -font $mainfont ]
+ -text $headline -font $font]
$canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id"
set linentag($row) [$canv2 create text 3 $y -anchor w \
- -text $name -font $namefont]
+ -text $name -font $mainfont]
set linedtag($row) [$canv3 create text 3 $y -anchor w \
-text $date -font $mainfont]
set xr [expr {$xt + [font measure $mainfont $headline]}]
proc assigncolor {id} {
global colormap colors nextcolor
- global commitrow parentlist children childlist
+ global commitrow parentlist children children curview
if {[info exists colormap($id)]} return
set ncolors [llength $colors]
- if {[info exists commitrow($id)]} {
- set kids [lindex $childlist $commitrow($id)]
- } elseif {[info exists children($id)]} {
- set kids $children($id)
+ if {[info exists children($curview,$id)]} {
+ set kids $children($curview,$id)
} else {
set kids {}
}
if {[llength $kids] == 1} {
set child [lindex $kids 0]
if {[info exists colormap($child)]
- && [llength [lindex $parentlist $commitrow($child)]] == 1} {
+ && [llength [lindex $parentlist $commitrow($curview,$child)]] == 1} {
set colormap($id) $colormap($child)
return
}
&& [lsearch -exact $badcolors $colormap($child)] < 0} {
lappend badcolors $colormap($child)
}
- foreach p [lindex $parentlist $commitrow($child)] {
+ foreach p [lindex $parentlist $commitrow($curview,$child)] {
if {[info exists colormap($p)]
&& [lsearch -exact $badcolors $colormap($p)] < 0} {
lappend badcolors $colormap($p)
proc drawtags {id x xt y1} {
global idtags idheads idotherrefs
global linespc lthickness
- global canv mainfont commitrow rowtextx
+ global canv mainfont commitrow rowtextx curview
set marks {}
set ntags 0
$xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
-width 1 -outline black -fill yellow -tags tag.$id]
$canv bind $t <1> [list showtag $tag 1]
- set rowtextx($commitrow($id)) [expr {$xr + $linespc}]
+ set rowtextx($commitrow($curview,$id)) [expr {$xr + $linespc}]
} else {
# draw a head or other ref
if {[incr nheads -1] >= 0} {
return $x
}
+proc show_status {msg} {
+ global canv mainfont
+
+ clear_display
+ $canv create text 3 3 -anchor nw -text $msg -font $mainfont -tags textitems
+}
+
proc finishcommits {} {
- global commitidx phase
+ global commitidx phase curview
global canv mainfont ctext maincursor textcursor
global findinprogress pending_select
- if {$commitidx > 0} {
+ if {$commitidx($curview) > 0} {
drawrest
} else {
- $canv delete all
- $canv create text 3 3 -anchor nw -text "No commits selected" \
- -font $mainfont -tags textitems
- }
- if {![info exists findinprogress]} {
- . config -cursor $maincursor
- settextcursor $textcursor
+ show_status "No commits selected"
}
set phase {}
catch {unset pending_select}
set curtextcursor $c
}
+proc nowbusy {what} {
+ global isbusy
+
+ if {[array names isbusy] eq {}} {
+ . config -cursor watch
+ settextcursor watch
+ }
+ set isbusy($what) 1
+}
+
+proc notbusy {what} {
+ global isbusy maincursor textcursor
+
+ catch {unset isbusy($what)}
+ if {[array names isbusy] eq {}} {
+ . config -cursor $maincursor
+ settextcursor $textcursor
+ }
+}
+
proc drawrest {} {
global numcommits
global startmsecs
global canvy0 numcommits linespc
- global rowlaidout commitidx
+ global rowlaidout commitidx curview
global pending_select
set row $rowlaidout
- layoutrows $rowlaidout $commitidx 1
+ layoutrows $rowlaidout $commitidx($curview) 1
layouttail
- optimize_rows $row 0 $commitidx
- showstuff $commitidx
+ optimize_rows $row 0 $commitidx($curview)
+ showstuff $commitidx($curview)
if {[info exists pending_select]} {
selectline 0 1
}
proc dofind {} {
global findtype findloc findstring markedmatches commitinfo
global numcommits displayorder linehtag linentag linedtag
- global mainfont namefont canv canv2 canv3 selectedline
+ global mainfont canv canv2 canv3 selectedline
global matchinglines foundstring foundstrlen matchstring
global commitdata
markmatches $canv $l $f $linehtag($l) $matches $mainfont
} elseif {$ty == "Author"} {
drawcmitrow $l
- markmatches $canv2 $l $f $linentag($l) $matches $namefont
+ markmatches $canv2 $l $f $linentag($l) $matches $mainfont
} elseif {$ty == "Date"} {
drawcmitrow $l
markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
catch {close $findprocfile}
unset findprocpid
}
- if {[info exists findinprogress]} {
- unset findinprogress
- if {$phase eq {}} {
- . config -cursor $maincursor
- settextcursor $textcursor
- }
- }
+ catch {unset findinprogress}
+ notbusy find
}
proc findpatches {} {
fconfigure $f -blocking 0
fileevent $f readable readfindproc
set finddidsel 0
- . config -cursor watch
- settextcursor watch
+ nowbusy find
set findinprogress 1
}
proc readfindproc {} {
global findprocfile finddidsel
- global commitrow matchinglines findinsertpos
+ global commitrow matchinglines findinsertpos curview
set n [gets $findprocfile line]
if {$n < 0} {
stopfindproc
return
}
- if {![info exists commitrow($id)]} {
+ if {![info exists commitrow($curview,$id)]} {
puts stderr "spurious id: $id"
return
}
- set l $commitrow($id)
+ set l $commitrow($curview,$id)
insertmatch $l $id
}
set finddidsel 0
set findinsertpos end
set id [lindex $displayorder $l]
- . config -cursor watch
- settextcursor watch
+ nowbusy find
set findinprogress 1
findcont
update
# append some text to the ctext widget, and make any SHA1 ID
# that we know about be a clickable link.
proc appendwithlinks {text} {
- global ctext commitrow linknum
+ global ctext commitrow linknum curview
set start [$ctext index "end - 1c"]
$ctext insert end $text
set s [lindex $l 0]
set e [lindex $l 1]
set linkid [string range $text $s $e]
- if {![info exists commitrow($linkid)]} continue
+ if {![info exists commitrow($curview,$linkid)]} continue
incr e
$ctext tag add link "$start + $s c" "$start + $e c"
$ctext tag add link$linknum "$start + $s c" "$start + $e c"
- $ctext tag bind link$linknum <1> [list selectline $commitrow($linkid) 1]
+ $ctext tag bind link$linknum <1> \
+ [list selectline $commitrow($curview,$linkid) 1]
incr linknum
}
$ctext tag conf link -foreground blue -underline 1
# start of a new file
$ctext insert end "\n"
set here [$ctext index "end - 1c"]
- $ctext mark set f:$fname $here
- $ctext mark gravity f:$fname left
lappend difffilestart $here
add_flist [list $fname]
set l [expr {(78 - [string length $fname]) / 2}]
set nextupdate [expr {[clock clicks -milliseconds] + 100}]
}
+proc setinlist {var i val} {
+ global $var
+
+ while {[llength [set $var]] < $i} {
+ lappend $var {}
+ }
+ if {[llength [set $var]] == $i} {
+ lappend $var $val
+ } else {
+ lset $var $i $val
+ }
+}
+
proc getblobdiffline {bdf ids} {
global diffids blobdifffd ctext curdifftag curtagstart
global diffnexthead diffnextnote difffilestart
set here [$ctext index "end - 1c"]
set curtagstart $here
set header $newname
- lappend difffilestart $here
- $ctext mark set f:$fname $here
- $ctext mark gravity f:$fname left
- if {$newname != $fname} {
- $ctext mark set f:$newfname $here
- $ctext mark gravity f:$newfname left
+ set i [lsearch -exact $treediffs($ids) $fname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $here
+ }
+ if {$newname ne $fname} {
+ set i [lsearch -exact $treediffs($ids) $newname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $here
+ }
}
set curdifftag "f:$fname"
$ctext tag delete $curdifftag
}
proc incrfont {inc} {
- global mainfont namefont textfont ctext canv phase
+ global mainfont textfont ctext canv phase
global stopped entries
unmarkmatches
set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
- set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]]
set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
setcoords
$ctext conf -font $textfont
proc gotocommit {} {
global sha1string currentid commitrow tagids headids
- global displayorder numcommits
+ global displayorder numcommits curview
if {$sha1string == {}
|| ([info exists currentid] && $sha1string == $currentid)} return
}
}
}
- if {[info exists commitrow($id)]} {
- selectline $commitrow($id) 1
+ if {[info exists commitrow($curview,$id)]} {
+ selectline $commitrow($curview,$id) 1
return
}
if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
}
proc lineclick {x y id isnew} {
- global ctext commitinfo childlist commitrow canv thickerline
+ global ctext commitinfo children canv thickerline curview
if {![info exists commitinfo($id)] && ![getcommit $id]} return
unmarkmatches
$ctext insert end "\tAuthor:\t[lindex $info 1]\n"
set date [formatdate [lindex $info 2]]
$ctext insert end "\tDate:\t$date\n"
- set kids [lindex $childlist $commitrow($id)]
+ set kids $children($curview,$id)
if {$kids ne {}} {
$ctext insert end "\nChildren:"
set i 0
}
proc selbyid {id} {
- global commitrow
- if {[info exists commitrow($id)]} {
- selectline $commitrow($id) 1
+ global commitrow curview
+ if {[info exists commitrow($curview,$id)]} {
+ selectline $commitrow($curview,$id) 1
}
}
}
proc rowmenu {x y id} {
- global rowctxmenu commitrow selectedline rowmenuid
+ global rowctxmenu commitrow selectedline rowmenuid curview
- if {![info exists selectedline] || $commitrow($id) eq $selectedline} {
+ if {![info exists selectedline]
+ || $commitrow($curview,$id) eq $selectedline} {
set state disabled
} else {
set state normal
}
proc redrawtags {id} {
- global canv linehtag commitrow idpos selectedline
+ global canv linehtag commitrow idpos selectedline curview
- if {![info exists commitrow($id)]} return
- drawcmitrow $commitrow($id)
+ if {![info exists commitrow($curview,$id)]} return
+ drawcmitrow $commitrow($curview,$id)
$canv delete tag.$id
set xt [eval drawtags $id $idpos($id)]
- $canv coords $linehtag($commitrow($id)) $xt [lindex $idpos($id) 2]
- if {[info exists selectedline] && $selectedline == $commitrow($id)} {
+ $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2]
+ if {[info exists selectedline]
+ && $selectedline == $commitrow($curview,$id)} {
selectline $selectedline 0
}
}
catch {source ~/.gitk}
-set namefont $mainfont
-
font create optionfont -family sans-serif -size -12
set revtreeargs {}
# check that we can find a .git directory somewhere...
set gitdir [gitdir]
if {![file isdirectory $gitdir]} {
- error_popup "Cannot find the git directory \"$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 {[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]
+ } err]} {
+ # unfortunately we get both stdout and stderr in $err,
+ # so look for "fatal:".
+ set i [string first "fatal:" $err]
+ if {$i > 0} {
+ set err [string range [expr {$i + 6}] end]
+ }
+ show_error . "Bad arguments to gitk:\n$err"
+ exit 1
+ }
+}
+
set history {}
set historyindex 0
set nextviewnum 1
set curview 0
set selectedview 0
+set selectedhlview {}
set viewfiles(0) {}
set viewperm(0) 0
+set viewargs(0) {}
+set cmdlineok 0
set stopped 0
set stuffsaved 0
set patchnum 0
makewindow
readrefs
-set cmdline_files {}
-catch {
- set fileargs [eval exec git-rev-parse --no-revs --no-flags $revtreeargs]
- set cmdline_files [split $fileargs "\n"]
- set n [llength $cmdline_files]
- set revtreeargs [lrange $revtreeargs 0 end-$n]
-}
-if {[lindex $revtreeargs end] eq "--"} {
- set revtreeargs [lrange $revtreeargs 0 end-1]
-}
-
-if {$cmdline_files ne {}} {
+if {$cmdline_files ne {} || $revtreeargs ne {}} {
# create a view for the files/dirs specified on the command line
set curview 1
set selectedview 1
set nextviewnum 2
set viewname(1) "Command line"
set viewfiles(1) $cmdline_files
+ set viewargs(1) $revtreeargs
set viewperm(1) 0
- .bar.view add radiobutton -label $viewname(1) -command {showview 1} \
- -variable selectedview -value 1
+ addviewmenu 1
.bar.view entryconf 2 -state normal
.bar.view entryconf 3 -state normal
}
incr nextviewnum
set viewname($n) [lindex $v 0]
set viewfiles($n) [lindex $v 1]
+ set viewargs($n) [lindex $v 2]
set viewperm($n) 1
- .bar.view add radiobutton -label $viewname($n) \
- -command [list showview $n] -variable selectedview -value $n
+ addviewmenu $n
}
}
getcommits