proc start_rev_list {view} {
global startmsecs nextupdate ncmupdate
global commfd leftover tclencoding datemode
- global revtreeargs viewfiles commitidx
+ global viewargs viewfiles commitidx
set startmsecs [clock clicks -milliseconds]
set nextupdate [expr {$startmsecs + 100}]
set ncmupdate 1
set commitidx($view) 0
- set args $revtreeargs
+ set args $viewargs($view)
if {$viewfiles($view) ne {}} {
set args [concat $args "--" $viewfiles($view)]
}
set phase getcommits
initlayout
start_rev_list $curview
- $canv delete all
- $canv create text 3 3 -anchor nw -text "Reading commits..." \
- -font $mainfont -tags textitems
+ show_status "Reading commits..."
}
proc getcommitlines {fd view} {
set stuff [read $fd]
if {$stuff == {}} {
if {![eof $fd]} return
+ global viewname
unset commfd($view)
+ notbusy $view
# set it blocking so we wait for the process to terminate
fconfigure $fd -blocking 1
- if {![catch {close $fd} err]} {
- notbusy $view
- if {$view == $curview} {
- after idle finishcommits
+ if {[catch {close $fd} err]} {
+ set fv {}
+ if {$view != $curview} {
+ set fv " for the \"$viewname($view)\" view"
}
- return
+ 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
if {$view == $curview} {
layoutmore
} elseif {[info exists hlview] && $view == $hlview} {
- highlightmore
+ vhighlightmore
}
}
if {[clock clicks -milliseconds] >= $nextupdate} {
}
proc updatecommits {} {
- global viewdata curview revtreeargs phase displayorder
- global children commitrow
+ global viewdata curview phase displayorder
+ global children commitrow selectedline thickerline
if {$phase ne {}} {
stop_rev_list
catch {unset commitrow($n,$id)}
}
set curview -1
+ catch {unset selectedline}
+ catch {unset thickerline}
catch {unset viewdata($n)}
readrefs
showview $n
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
global entries sha1entry sha1string sha1but
global maincursor textcursor curtextcursor
global rowctxmenu mergemax
+ global highlight_files highlight_names
+ global searchstring sstring
menu .bar
.bar add cascade -label "File" -menu .bar.file
.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 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
}
frame .ctop.top
frame .ctop.top.bar
+ frame .ctop.top.lbar
+ pack .ctop.top.lbar -side bottom -fill x
pack .ctop.top.bar -side bottom -fill x
set cscroll .ctop.top.csb
scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
set findstring {}
set fstring .ctop.top.bar.findstring
lappend entries $fstring
- entry $fstring -width 30 -font $textfont -textvariable findstring -font $textfont
+ entry $fstring -width 30 -font $textfont -textvariable findstring
pack $fstring -side left -expand 1 -fill x
set findtype Exact
set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
# for making sure type==Exact whenever loc==Pickaxe
trace add variable findloc write findlocchange
+ label .ctop.top.lbar.flabel -text "Highlight: Commits touching paths:" \
+ -font $uifont
+ pack .ctop.top.lbar.flabel -side left -fill y
+ entry .ctop.top.lbar.fent -width 25 -font $textfont \
+ -textvariable highlight_files
+ trace add variable highlight_files write hfiles_change
+ lappend entries .ctop.top.lbar.fent
+ pack .ctop.top.lbar.fent -side left -fill x -expand 1
+ label .ctop.top.lbar.vlabel -text " OR in view" -font $uifont
+ pack .ctop.top.lbar.vlabel -side left -fill y
+ global viewhlmenu selectedhlview
+ set viewhlmenu [tk_optionMenu .ctop.top.lbar.vhl selectedhlview None]
+ $viewhlmenu entryconf 0 -command delvhighlight
+ $viewhlmenu conf -font $uifont
+ .ctop.top.lbar.vhl conf -font $uifont
+ pack .ctop.top.lbar.vhl -side left -fill y
+ label .ctop.top.lbar.alabel -text " OR author/committer:" \
+ -font $uifont
+ pack .ctop.top.lbar.alabel -side left -fill y
+ entry .ctop.top.lbar.aent -width 20 -font $textfont \
+ -textvariable highlight_names
+ trace add variable highlight_names write hnames_change
+ lappend entries .ctop.top.lbar.aent
+ pack .ctop.top.lbar.aent -side right -fill x -expand 1
+
panedwindow .ctop.cdet -orient horizontal
.ctop add .ctop.cdet
frame .ctop.cdet.left
+ frame .ctop.cdet.left.bot
+ pack .ctop.cdet.left.bot -side bottom -fill x
+ button .ctop.cdet.left.bot.search -text "Search" -command dosearch \
+ -font $uifont
+ pack .ctop.cdet.left.bot.search -side left -padx 5
+ set sstring .ctop.cdet.left.bot.sstring
+ entry $sstring -width 20 -font $textfont -textvariable searchstring
+ lappend entries $sstring
+ trace add variable searchstring write incrsearch
+ pack $sstring -side left -expand 1 -fill x
set ctext .ctop.cdet.left.ctext
text $ctext -bg white -state disabled -font $textfont \
-width $geometry(ctextw) -height $geometry(ctexth) \
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]
+ $cflist tag configure bold -font [concat $mainfont bold]
.ctop.cdet add .ctop.cdet.right
bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
bind . <Control-f> dofind
bind . <Control-g> {findnext 0}
bind . <Control-r> findprev
+ bind . <Control-s> dosearch
bind . <Control-equal> {incrfont 1}
bind . <Control-KP_Add> {incrfont 1}
bind . <Control-minus> {incrfont -1}
proc scrollcanv {cscroll f0 f1} {
$cscroll set $f0 $f1
drawfrac $f0 $f1
+ flushhighlights
}
# when we make a key binding for the toplevel, make sure
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 "}"
$w insert end $str
$w image create end -align center -image $bm -padx 1 \
-name a:$ix
- $w insert end $d
+ $w insert end $d [highlight_tag $prefix]
$w mark set s:$ix "end -1c"
$w mark gravity s:$ix left
}
set str "\n"
for {set i 0} {$i < $lev} {incr i} {append str "\t"}
$w insert end $str
- $w insert end $tail
+ $w insert end $tail [highlight_tag $f]
}
lappend treecontents($prefix) $tail
}
}
}
+proc highlight_tree {y prefix} {
+ global treeheight treecontents cflist
+
+ foreach e $treecontents($prefix) {
+ set path $prefix$e
+ if {[highlight_tag $path] ne {}} {
+ $cflist tag add bold $y.0 "$y.0 lineend"
+ }
+ incr y
+ if {[string index $e end] eq "/" && $treeheight($path) > 1} {
+ set y [highlight_tree $y $path]
+ }
+ }
+ return $y
+}
+
proc treeclosedir {w dir} {
global treediropen treeheight treeparent treeindex
incr treeheight($x) $n
}
foreach e $treecontents($dir) {
+ set de $dir$e
if {[string index $e end] eq "/"} {
- set de $dir$e
set iy $treeindex($de)
$w mark set d:$iy e:$ix
$w mark gravity d:$iy left
set treediropen($de) 0
$w image create e:$ix -align center -image tri-rt -padx 1 \
-name a:$iy
- $w insert e:$ix $e
+ $w insert e:$ix $e [highlight_tag $de]
$w mark set s:$iy e:$ix
$w mark gravity s:$iy left
set treeheight($de) 1
} else {
$w insert e:$ix $str
- $w insert e:$ix $e
+ $w insert e:$ix $e [highlight_tag $de]
}
}
$w mark gravity e:$ix left
}
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}
set difffilestart {}
}
-proc add_flist {fl} {
- global flistmode cflist
+proc highlight_tag {f} {
+ global highlight_paths
+
+ foreach p $highlight_paths {
+ if {[string match $p $f]} {
+ return "bold"
+ }
+ }
+ return {}
+}
+
+proc highlight_filelist {} {
+ global cmitmode cflist
$cflist conf -state normal
- if {$flistmode eq "flat"} {
- foreach f $fl {
- $cflist insert end "\n$f"
+ if {$cmitmode ne "tree"} {
+ set end [lindex [split [$cflist index end] .] 0]
+ for {set l 2} {$l < $end} {incr l} {
+ set line [$cflist get $l.0 "$l.0 lineend"]
+ if {[highlight_tag $line] ne {}} {
+ $cflist tag add bold $l.0 "$l.0 lineend"
+ }
}
+ } else {
+ highlight_tree 2 {}
+ }
+ $cflist conf -state disabled
+}
+
+proc unhighlight_filelist {} {
+ global cflist
+
+ $cflist conf -state normal
+ $cflist tag remove bold 1.0 end
+ $cflist conf -state disabled
+}
+
+proc add_flist {fl} {
+ global cflist
+
+ $cflist conf -state normal
+ foreach f $fl {
+ $cflist insert end "\n"
+ $cflist insert end $f [highlight_tag $f]
}
$cflist conf -state disabled
}
proc sel_flist {w x y} {
- global flistmode ctext difffilestart cflist cflist_top cmitmode
+ global ctext difffilestart cflist cflist_top cmitmode
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 cflist_top $ll
- set cflist_bot $lb
+ 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
+ }
+ }
+ 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 {ishighlight} {
global nextviewnum newviewname newviewperm uifont newishighlight
+ global newviewargs revtreeargs
set newishighlight $ishighlight
set top .gitkview
}
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 doviewmenu {m first cmd op args} {
+proc doviewmenu {m first cmd op argv} {
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
+ eval $m $op $i $argv
break
}
}
}
proc allviewmenus {n op args} {
- doviewmenu .bar.view 6 [list showview $n] $op $args
- doviewmenu .bar.view.hl 3 [list addhighlight $n] $op $args
+ global viewhlmenu
+
+ doviewmenu .bar.view 7 [list showview $n] $op $args
+ doviewmenu $viewhlmenu 1 [list addvhighlight $n] $op $args
}
proc newviewok {top n} {
global nextviewnum newviewperm newviewname newishighlight
global viewname viewfiles viewperm selectedview curview
+ global viewargs newviewargs viewhlmenu
+ 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
+ set viewargs($n) $newargs
addviewmenu $n
if {!$newishighlight} {
after idle showview $n
} else {
- after idle addhighlight $n
+ after idle addvhighlight $n
}
} else {
# editing an existing view
set viewperm($n) $newviewperm($n)
if {$newviewname($n) ne $viewname($n)} {
set viewname($n) $newviewname($n)
- allviewmenus $n entryconf -label $viewname($n)
+ doviewmenu .bar.view 7 [list showview $n] \
+ entryconf [list -label $viewname($n)]
+ doviewmenu $viewhlmenu 1 [list addvhighlight $n] \
+ entryconf [list -label $viewname($n) -value $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
}
}
proc delview {} {
- global curview viewdata viewperm
+ global curview viewdata viewperm hlview selectedhlview
if {$curview == 0} return
+ if {[info exists hlview] && $hlview == $curview} {
+ set selectedhlview None
+ unset hlview
+ }
allviewmenus $curview delete
set viewdata($curview) {}
set viewperm($curview) 0
}
proc addviewmenu {n} {
- global viewname
+ global viewname viewhlmenu
.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
+ $viewhlmenu add radiobutton -label $viewname($n) \
+ -command [list addvhighlight $n] -variable selectedhlview
}
proc flatten {var} {
global pending_select phase
global commitidx rowlaidout rowoptim linesegends
global commfd nextupdate
- global selectedview hlview selectedhlview
+ global selectedview
global vparentlist vchildlist vdisporder vcmitlisted
+ global hlview selectedhlview
if {$n == $curview} return
set selid {}
catch {unset matchinglines}
catch {unset treediffs}
clear_display
+ if {[info exists hlview] && $hlview == $n} {
+ unset hlview
+ set selectedhlview None
+ }
set curview $n
set selectedview $n
- set selectedhlview -1
- .bar.view entryconf 1 -state [expr {$n == 0? "disabled": "normal"}]
.bar.view entryconf 2 -state [expr {$n == 0? "disabled": "normal"}]
- catch {unset hlview}
- .bar.view.hl entryconf 1 -state disabled
+ .bar.view entryconf 3 -state [expr {$n == 0? "disabled": "normal"}]
if {![info exists viewdata($n)]} {
set pending_select $selid
selectline $row 0
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
+# Stuff relating to the highlighting facility
+
+proc ishighlighted {row} {
+ global vhighlights fhighlights nhighlights
+
+ if {[info exists nhighlights($row)] && $nhighlights($row) > 0} {
+ return $nhighlights($row)
+ }
+ if {[info exists vhighlights($row)] && $vhighlights($row) > 0} {
+ return $vhighlights($row)
+ }
+ if {[info exists fhighlights($row)] && $fhighlights($row) > 0} {
+ return $fhighlights($row)
+ }
+ return 0
+}
+
+proc bolden {row font} {
+ global canv linehtag selectedline
+
+ $canv itemconf $linehtag($row) -font $font
+ 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
+ }
+}
+
+proc bolden_name {row font} {
+ global canv2 linentag selectedline
+
+ $canv2 itemconf $linentag($row) -font $font
+ if {$row == $selectedline} {
+ $canv2 delete secsel
+ set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \
+ -outline {{}} -tags secsel \
+ -fill [$canv2 cget -selectbackground]]
+ $canv2 lower $t
+ }
+}
+
+proc unbolden {rows} {
+ global mainfont
+
+ foreach row $rows {
+ if {![ishighlighted $row]} {
+ bolden $row $mainfont
+ }
+ }
+}
+
+proc addvhighlight {n} {
+ global hlview curview viewdata vhl_done vhighlights commitidx
if {[info exists hlview]} {
- delhighlight
+ delvhighlight
}
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 vdisporder($n) {}
set vcmitlisted($n) {}
start_rev_list $n
- } else {
- highlightmore
+ }
+ set vhl_done $commitidx($hlview)
+ if {$vhl_done > 0} {
+ drawvisible
}
}
-proc delhighlight {} {
- global hlview highlightedrows canv linehtag mainfont
- global selectedhlview selectedline
+proc delvhighlight {} {
+ global hlview vhighlights
+ global 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
- }
+ set rows [array names vhighlights]
+ if {$rows ne {}} {
+ unset vhighlights
+ unbolden $rows
}
}
-proc highlightmore {} {
- global hlview highlighted commitidx highlightedrows linehtag mainfont
- global displayorder vdisporder curview canv commitrow selectedline
+proc vhighlightmore {} {
+ global hlview vhl_done commitidx vhighlights
+ global displayorder vdisporder curview mainfont
set font [concat $mainfont bold]
set max $commitidx($hlview)
} else {
set disp $vdisporder($hlview)
}
- for {set i $highlighted($hlview)} {$i < $max} {incr i} {
+ set vr [visiblerows]
+ set r0 [lindex $vr 0]
+ set r1 [lindex $vr 1]
+ for {set i $vhl_done} {$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
+ if {$r0 <= $row && $row <= $r1} {
+ if {![highlighted $row]} {
+ bolden $row $font
}
+ set vhighlights($row) 1
+ }
+ }
+ }
+ set vhl_done $max
+}
+
+proc askvhighlight {row id} {
+ global hlview vhighlights commitrow iddrawn mainfont
+
+ if {[info exists commitrow($hlview,$id)]} {
+ if {[info exists iddrawn($id)] && ![ishighlighted $row]} {
+ bolden $row [concat $mainfont bold]
+ }
+ set vhighlights($row) 1
+ } else {
+ set vhighlights($row) 0
+ }
+}
+
+proc hfiles_change {name ix op} {
+ global highlight_files filehighlight fhighlights fh_serial
+ global mainfont highlight_paths
+
+ if {[info exists filehighlight]} {
+ # delete previous highlights
+ catch {close $filehighlight}
+ unset filehighlight
+ set rows [array names fhighlights]
+ if {$rows ne {}} {
+ unset fhighlights
+ unbolden $rows
+ }
+ unhighlight_filelist
+ }
+ set highlight_paths {}
+ after cancel do_file_hl $fh_serial
+ incr fh_serial
+ if {$highlight_files ne {}} {
+ after 300 do_file_hl $fh_serial
+ }
+}
+
+proc makepatterns {l} {
+ set ret {}
+ foreach e $l {
+ set ee [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} $e]
+ if {[string index $ee end] eq "/"} {
+ lappend ret "$ee*"
+ } else {
+ lappend ret $ee
+ lappend ret "$ee/*"
+ }
+ }
+ return $ret
+}
+
+proc do_file_hl {serial} {
+ global highlight_files filehighlight highlight_paths
+
+ if {[catch {set paths [shellsplit $highlight_files]}]} return
+ set highlight_paths [makepatterns $paths]
+ highlight_filelist
+ set cmd [concat | git-diff-tree -r -s --stdin -- $paths]
+ set filehighlight [open $cmd r+]
+ fconfigure $filehighlight -blocking 0
+ fileevent $filehighlight readable readfhighlight
+ drawvisible
+ flushhighlights
+}
+
+proc flushhighlights {} {
+ global filehighlight
+
+ if {[info exists filehighlight]} {
+ puts $filehighlight ""
+ flush $filehighlight
+ }
+}
+
+proc askfilehighlight {row id} {
+ global filehighlight fhighlights
+
+ set fhighlights($row) 0
+ puts $filehighlight $id
+}
+
+proc readfhighlight {} {
+ global filehighlight fhighlights commitrow curview mainfont iddrawn
+
+ set n [gets $filehighlight line]
+ if {$n < 0} {
+ if {[eof $filehighlight]} {
+ # strange...
+ puts "oops, git-diff-tree died"
+ catch {close $filehighlight}
+ unset filehighlight
+ }
+ return
+ }
+ set line [string trim $line]
+ if {$line eq {}} return
+ if {![info exists commitrow($curview,$line)]} return
+ set row $commitrow($curview,$line)
+ if {[info exists iddrawn($line)] && ![ishighlighted $row]} {
+ bolden $row [concat $mainfont bold]
+ }
+ set fhighlights($row) 1
+}
+
+proc hnames_change {name ix op} {
+ global highlight_names nhighlights nhl_names mainfont
+
+ # delete previous highlights, if any
+ set rows [array names nhighlights]
+ if {$rows ne {}} {
+ foreach row $rows {
+ if {$nhighlights($row) >= 2} {
+ bolden_name $row $mainfont
}
}
+ unset nhighlights
+ unbolden $rows
+ }
+ if {[catch {set nhl_names [shellsplit $highlight_names]}]} {
+ set nhl_names {}
+ return
+ }
+ drawvisible
+}
+
+proc asknamehighlight {row id} {
+ global nhl_names nhighlights commitinfo iddrawn mainfont
+
+ if {![info exists commitinfo($id)]} {
+ getcommit $id
+ }
+ set isbold 0
+ set author [lindex $commitinfo($id) 1]
+ set committer [lindex $commitinfo($id) 3]
+ foreach name $nhl_names {
+ set pattern "*$name*"
+ if {[string match -nocase $pattern $author]} {
+ set isbold 2
+ break
+ }
+ if {!$isbold && [string match -nocase $pattern $committer]} {
+ set isbold 1
+ }
+ }
+ if {[info exists iddrawn($id)]} {
+ if {$isbold && ![ishighlighted $row]} {
+ bolden $row [concat $mainfont bold]
+ }
+ if {$isbold >= 2} {
+ bolden_name $row [concat $mainfont bold]
+ }
}
- set highlighted($hlview) $max
+ set nhighlights($row) $isbold
}
# Graph layout functions
global rowtextx idpos idtags idheads idotherrefs
global linehtag linentag linedtag
global mainfont canvxmax
- global hlview commitrow highlightedrows
set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
set x [xc $row $col]
set date [lindex $commitinfo($id) 2]
set date [formatdate $date]
set font $mainfont
- if {[info exists hlview] && [info exists commitrow($hlview,$id)]} {
+ set nfont $mainfont
+ set isbold [ishighlighted $row]
+ if {$isbold > 0} {
lappend font bold
- lappend highlightedrows $row
+ if {$isbold > 1} {
+ lappend nfont bold
+ }
}
set linehtag($row) [$canv create text $xt $y -anchor w \
-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 $mainfont]
+ -text $name -font $nfont]
set linedtag($row) [$canv3 create text 3 $y -anchor w \
-text $date -font $mainfont]
set xr [expr {$xt + [font measure $mainfont $headline]}]
global displayorder rowidlist
global idrangedrawn iddrawn
global commitinfo parentlist numcommits
+ global filehighlight fhighlights nhl_names nhighlights
+ global hlview vhighlights
if {$row >= $numcommits} return
foreach id [lindex $rowidlist $row] {
}
set id [lindex $displayorder $row]
+ if {[info exists hlview] && ![info exists vhighlights($row)]} {
+ askvhighlight $row $id
+ }
+ if {[info exists filehighlight] && ![info exists fhighlights($row)]} {
+ askfilehighlight $row $id
+ }
+ if {$nhl_names ne {} && ![info exists nhighlights($row)]} {
+ asknamehighlight $row $id
+ }
if {[info exists iddrawn($id)]} return
set col [lsearch -exact [lindex $rowidlist $row] $id]
if {$col < 0} {
proc clear_display {} {
global iddrawn idrangedrawn
+ global vhighlights fhighlights nhighlights
allcanvs delete all
catch {unset iddrawn}
catch {unset idrangedrawn}
+ catch {unset vhighlights}
+ catch {unset fhighlights}
+ catch {unset nhighlights}
}
proc findcrossings {id} {
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 curview
global canv mainfont ctext maincursor textcursor
if {$commitidx($curview) > 0} {
drawrest
} else {
- $canv delete all
- $canv create text 3 3 -anchor nw -text "No commits selected" \
- -font $mainfont -tags textitems
+ show_status "No commits selected"
}
set phase {}
catch {unset pending_select}
proc commit_descriptor {p} {
global commitinfo
+ if {![info exists commitinfo($p)]} {
+ getcommit $p
+ }
set l "..."
- if {[info exists commitinfo($p)]} {
+ if {[llength $commitinfo($p)] > 1} {
set l [lindex $commitinfo($p) 0]
}
return "$p ($l)"
$sha1entry selection to end
$ctext conf -state normal
- $ctext delete 0.0 end
+ clear_ctext
set linknum 0
set info $commitinfo($id)
set date [formatdate [lindex $info 2]]
set lpp 1
}
allcanvs yview scroll [expr {$dir * $lpp}] units
+ drawvisible
if {![info exists selectedline]} return
set l [expr {$selectedline + $dir * $lpp}]
if {$l < 0} {
fconfigure $bf -blocking 0
fileevent $bf readable [list getblobline $bf $diffids]
$ctext config -state normal
- $ctext delete $commentend end
+ clear_ctext $commentend
$ctext insert end "\n"
$ctext insert end "$f\n" filesep
$ctext config -state disabled
# 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 clear_ctext {{first 1.0}} {
+ global ctext smarktop smarkbot
+
+ if {![info exists smarktop] || [$ctext compare $first < $smarktop]} {
+ set smarktop $first
+ }
+ if {![info exists smarkbot] || [$ctext compare $first < $smarkbot]} {
+ set smarkbot $first
+ }
+ $ctext delete $first end
+}
+
+proc incrsearch {name ix op} {
+ global ctext searchstring
+
+ $ctext tag remove found 1.0 end
+ if {$searchstring ne {}} {
+ searchmarkvisible 1
+ }
+}
+
+proc dosearch {} {
+ global sstring ctext searchstring
+
+ focus $sstring
+ $sstring icursor end
+ $ctext tag remove sel 1.0 end
+ if {$searchstring eq {}} return
+ set here [$ctext index insert]
+ set match [$ctext search -count mlen -- $searchstring $here]
+ if {$match eq {}} {
+ bell
+ return
+ }
+ $ctext see $match
+ set mend "$match + $mlen c"
+ $ctext tag add sel $match $mend
+ $ctext mark set insert $mend
+}
+
+proc searchmark {first last} {
+ global ctext searchstring
+
+ set mend $first.0
+ while {1} {
+ set match [$ctext search -count mlen -- $searchstring $mend $last.end]
+ if {$match eq {}} break
+ set mend "$match + $mlen c"
+ $ctext tag add found $match $mend
+ }
+}
+
+proc searchmarkvisible {doall} {
+ global ctext smarktop smarkbot
+
+ set topline [lindex [split [$ctext index @0,0] .] 0]
+ set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0]
+ if {$doall || $botline < $smarktop || $topline > $smarkbot} {
+ # no overlap with previous
+ searchmark $topline $botline
+ set smarktop $topline
+ set smarkbot $botline
+ } else {
+ if {$topline < $smarktop} {
+ searchmark $topline [expr {$smarktop-1}]
+ set smarktop $topline
+ }
+ if {$botline > $smarkbot} {
+ searchmark [expr {$smarkbot+1}] $botline
+ set smarkbot $botline
+ }
+ }
+}
+
+proc scrolltext {f0 f1} {
+ global ctext smarktop smarkbot searchstring
+
+ .ctop.cdet.left.sb set $f0 $f1
+ if {$searchstring ne {}} {
+ searchmarkvisible 0
+ }
+}
+
proc setcoords {} {
global linespc charspc canvx0 canvy0 mainfont
global xspc1 xspc2 lthickness
}
# fill the details pane with info about this line
$ctext conf -state normal
- $ctext delete 0.0 end
+ clear_ctext
$ctext tag conf link -foreground blue -underline 1
$ctext tag bind link <Enter> { %W configure -cursor hand2 }
$ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
global commitinfo
$ctext conf -state normal
- $ctext delete 0.0 end
+ clear_ctext
init_flist "Top"
$ctext insert end "From "
$ctext tag conf link -foreground blue -underline 1
addtohistory [list showtag $tag 0]
}
$ctext conf -state normal
- $ctext delete 0.0 end
+ clear_ctext
set linknum 0
if {[info exists tagcontents($tag)]} {
set text $tagcontents($tag)
set uparrowlen 7
set downarrowlen 7
set mingaplen 30
-set flistmode "flat"
set cmitmode "patch"
set colors {green red blue magenta darkgrey brown orange}
# 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 fh_serial 0
+set highlight_names {}
+set nhl_names {}
+set highlight_paths {}
set optim_delay 16
set nextviewnum 1
set curview 0
set selectedview 0
-set selectedhlview {}
+set selectedhlview None
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
addviewmenu 1
- .bar.view entryconf 1 -state normal
.bar.view entryconf 2 -state normal
+ .bar.view entryconf 3 -state normal
}
if {[info exists permviews]} {
incr nextviewnum
set viewname($n) [lindex $v 0]
set viewfiles($n) [lindex $v 1]
+ set viewargs($n) [lindex $v 2]
set viewperm($n) 1
addviewmenu $n
}