set order "--date-order"
}
if {[catch {
- set fd [open [concat | git-rev-list --header $order \
+ set fd [open [concat | git rev-list --header $order \
--parents --boundary --default HEAD $args] r]
} err]} {
- puts stderr "Error executing git-rev-list: $err"
+ puts stderr "Error executing git rev-list: $err"
exit 1
}
set commfd($view) $fd
}
if {[string range $err 0 4] == "usage"} {
set err "Gitk: error reading commits$fv:\
- bad arguments to git-rev-list."
+ bad arguments to git rev-list."
if {$viewname($view) eq "Command line"} {
append err \
- " (Note: arguments to gitk are passed to git-rev-list\
+ " (Note: arguments to gitk are passed to git rev-list\
to allow selection of commits to be displayed.)"
}
} else {
if {[string length $shortcmit] > 80} {
set shortcmit "[string range $shortcmit 0 80]..."
}
- error_popup "Can't parse git-rev-list output: {$shortcmit}"
+ error_popup "Can't parse git rev-list output: {$shortcmit}"
exit 1
}
set id [lindex $ids 0]
}
proc readcommit {id} {
- if {[catch {set contents [exec git-cat-file commit $id]}]} return
+ if {[catch {set contents [exec git cat-file commit $id]}]} return
parsecommit $id $contents 0
}
catch {unset selectedline}
catch {unset thickerline}
catch {unset viewdata($n)}
+ discardallcommits
readrefs
showview $n
}
set headline $comment
}
if {!$listed} {
- # git-rev-list indents the comment by 4 spaces;
- # if we got this via git-cat-file, add the indentation
+ # git rev-list indents the comment by 4 spaces;
+ # if we got this via git cat-file, add the indentation
set newcomment {}
foreach line [split $comment "\n"] {
append newcomment " "
set type {}
set tag {}
catch {
- set commit [exec git-rev-parse "$id^0"]
+ set commit [exec git rev-parse "$id^0"]
if {"$commit" != "$id"} {
set tagids($name) $commit
lappend idtags($commit) $name
}
}
catch {
- set tagcontents($name) [exec git-cat-file tag "$id"]
+ set tagcontents($name) [exec git cat-file tag "$id"]
}
} elseif { $type == "heads" } {
set headids($name) $id
close $refd
}
-proc show_error {w msg} {
+proc show_error {w top 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"
+ button $w.ok -text OK -command "destroy $top"
pack $w.ok -side bottom -fill x
- bind $w <Visibility> "grab $w; focus $w"
- bind $w <Key-Return> "destroy $w"
- tkwait window $w
+ bind $top <Visibility> "grab $top; focus $top"
+ bind $top <Key-Return> "destroy $top"
+ tkwait window $top
}
proc error_popup msg {
set w .error
toplevel $w
wm transient $w .
- show_error $w $msg
+ show_error $w $w $msg
}
proc makewindow {} {
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
global maincursor textcursor curtextcursor
- global rowctxmenu mergemax
+ global rowctxmenu mergemax wrapcomment
global highlight_files gdttype
global searchstring sstring
pack $ctext -side left -fill both -expand 1
.ctop.cdet add .ctop.cdet.left
+ $ctext tag conf comment -wrap $wrapcomment
$ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
$ctext tag conf hunksep -fore blue
$ctext tag conf d0 -fore red
proc savestuff {w} {
global canv canv2 canv3 ctext cflist mainfont textfont uifont
global stuffsaved findmergefiles maxgraphpct
- global maxwidth
+ global maxwidth showneartags
global viewname viewfiles viewargs viewperm nextviewnum
- global cmitmode
+ global cmitmode wrapcomment
if {$stuffsaved} return
if {![winfo viewable .]} return
puts $f [list set maxgraphpct $maxgraphpct]
puts $f [list set maxwidth $maxwidth]
puts $f [list set cmitmode $cmitmode]
+ puts $f [list set wrapcomment $wrapcomment]
+ puts $f [list set showneartags $showneartags]
puts $f "set geometry(width) [winfo width .ctop]"
puts $f "set geometry(height) [winfo height .ctop]"
puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
checkbutton $top.perm -text "Remember this view" -variable newviewperm($n)
grid $top.perm - -pady 5 -sticky w
message $top.al -aspect 1000 -font $uifont \
- -text "Commits to include (arguments to git-rev-list):"
+ -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
if {[llength $commitinfo($p)] > 1} {
set l [lindex $commitinfo($p) 0]
}
- return "$p ($l)"
+ return "$p ($l)\n"
}
# append some text to the ctext widget, and make any SHA1 ID
# that we know about be a clickable link.
-proc appendwithlinks {text} {
+proc appendwithlinks {text tags} {
global ctext commitrow linknum curview
set start [$ctext index "end - 1c"]
- $ctext insert end $text
- $ctext insert end "\n"
+ $ctext insert end $text $tags
set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
foreach l $links {
set s [lindex $l 0]
allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
}
+# add a list of tag or branch names at position pos
+# returns the number of names inserted
+proc appendrefs {pos l var} {
+ global ctext commitrow linknum curview idtags $var
+
+ if {[catch {$ctext index $pos}]} {
+ return 0
+ }
+ set tags {}
+ foreach id $l {
+ foreach tag [set $var\($id\)] {
+ lappend tags [concat $tag $id]
+ }
+ }
+ set tags [lsort -index 1 $tags]
+ set sep {}
+ foreach tag $tags {
+ set name [lindex $tag 0]
+ set id [lindex $tag 1]
+ set lk link$linknum
+ incr linknum
+ $ctext insert $pos $sep
+ $ctext insert $pos $name $lk
+ $ctext tag conf $lk -foreground blue
+ if {[info exists commitrow($curview,$id)]} {
+ $ctext tag bind $lk <1> \
+ [list selectline $commitrow($curview,$id) 1]
+ $ctext tag conf $lk -underline 1
+ $ctext tag bind $lk <Enter> { %W configure -cursor hand2 }
+ $ctext tag bind $lk <Leave> { %W configure -cursor $curtextcursor }
+ }
+ set sep ", "
+ }
+ return [llength $tags]
+}
+
+# called when we have finished computing the nearby tags
+proc dispneartags {} {
+ global selectedline currentid ctext anc_tags desc_tags showneartags
+ global desc_heads
+
+ if {![info exists selectedline] || !$showneartags} return
+ set id $currentid
+ $ctext conf -state normal
+ if {[info exists desc_heads($id)]} {
+ if {[appendrefs branch $desc_heads($id) idheads] > 1} {
+ $ctext insert "branch -2c" "es"
+ }
+ }
+ if {[info exists anc_tags($id)]} {
+ appendrefs follows $anc_tags($id) idtags
+ }
+ if {[info exists desc_tags($id)]} {
+ appendrefs precedes $desc_tags($id) idtags
+ }
+ $ctext conf -state disabled
+}
+
proc selectline {l isnew} {
global canv canv2 canv3 ctext commitinfo selectedline
global displayorder linehtag linentag linedtag
global currentid sha1entry
global commentend idtags linknum
global mergemax numcommits pending_select
- global cmitmode
+ global cmitmode desc_tags anc_tags showneartags allcommits desc_heads
catch {unset pending_select}
$canv delete hover
$ctext insert end "\n"
}
- set comment {}
+ set headers {}
set olds [lindex $parentlist $l]
if {[llength $olds] > 1} {
set np 0
set tag m$np
}
$ctext insert end "Parent: " $tag
- appendwithlinks [commit_descriptor $p]
+ appendwithlinks [commit_descriptor $p] {}
incr np
}
} else {
foreach p $olds {
- append comment "Parent: [commit_descriptor $p]\n"
+ append headers "Parent: [commit_descriptor $p]"
}
}
foreach c [lindex $childlist $l] {
- append comment "Child: [commit_descriptor $c]\n"
+ append headers "Child: [commit_descriptor $c]"
}
- append comment "\n"
- append comment [lindex $info 5]
# make anything that looks like a SHA1 ID be a clickable link
- appendwithlinks $comment
+ appendwithlinks $headers {}
+ if {$showneartags} {
+ if {![info exists allcommits]} {
+ getallcommits
+ }
+ $ctext insert end "Branch: "
+ $ctext mark set branch "end -1c"
+ $ctext mark gravity branch left
+ if {[info exists desc_heads($id)]} {
+ if {[appendrefs branch $desc_heads($id) idheads] > 1} {
+ # turn "Branch" into "Branches"
+ $ctext insert "branch -2c" "es"
+ }
+ }
+ $ctext insert end "\nFollows: "
+ $ctext mark set follows "end -1c"
+ $ctext mark gravity follows left
+ if {[info exists anc_tags($id)]} {
+ appendrefs follows $anc_tags($id) idtags
+ }
+ $ctext insert end "\nPrecedes: "
+ $ctext mark set precedes "end -1c"
+ $ctext mark gravity precedes left
+ if {[info exists desc_tags($id)]} {
+ appendrefs precedes $desc_tags($id) idtags
+ }
+ $ctext insert end "\n"
+ }
+ $ctext insert end "\n"
+ appendwithlinks [lindex $info 5] {comment}
$ctext tag delete Comments
$ctext tag remove found 1.0 end
catch {unset diffmergeid}
if {![info exists treefilelist($id)]} {
if {![info exists treepending]} {
- if {[catch {set gtf [open [concat | git-ls-tree -r $id] r]}]} {
+ if {[catch {set gtf [open [concat | git ls-tree -r $id] r]}]} {
return
}
set treepending $id
return
}
set blob [lindex $treeidlist($diffids) $i]
- if {[catch {set bf [open [concat | git-cat-file blob $blob] r]} err]} {
+ if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
puts "oops, error reading blob $blob: $err"
return
}
set diffids $id
# this doesn't seem to actually affect anything...
set env(GIT_DIFF_OPTS) $diffopts
- set cmd [concat | git-diff-tree --no-commit-id --cc $id]
+ set cmd [concat | git diff-tree --no-commit-id --cc $id]
if {[catch {set mdf [open $cmd r]} err]} {
error_popup "Error getting merge diffs: $err"
return
set treepending $ids
set treediff {}
if {[catch \
- {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]} \
+ {set gdtf [open [concat | git diff-tree --no-commit-id -r $ids] r]} \
]} return
fconfigure $gdtf -blocking 0
fileevent $gdtf readable [list gettreediffline $gdtf $ids]
global nextupdate diffinhdr treediffs
set env(GIT_DIFF_OPTS) $diffopts
- set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids]
+ set cmd [concat | git diff-tree --no-commit-id -r -p -C $ids]
if {[catch {set bdf [open $cmd r]} err]} {
puts "error getting diffs: $err"
return
set oldid [$patchtop.fromsha1 get]
set newid [$patchtop.tosha1 get]
set fname [$patchtop.fname get]
- if {[catch {exec git-diff-tree -p $oldid $newid >$fname &} err]} {
+ if {[catch {exec git diff-tree -p $oldid $newid >$fname &} err]} {
error_popup "Error creating patch: $err"
}
catch {destroy $patchtop}
proc redrawtags {id} {
global canv linehtag commitrow idpos selectedline curview
+ global mainfont
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($curview,$id)) $xt [lindex $idpos($id) 2]
+ set text [$canv itemcget $linehtag($commitrow($curview,$id)) -text]
+ set xr [expr {$xt + [font measure $mainfont $text]}]
+ if {$xr > $canvxmax} {
+ set canvxmax $xr
+ setcanvscroll
+ }
if {[info exists selectedline]
&& $selectedline == $commitrow($curview,$id)} {
selectline $selectedline 0
unset wrcomtop
}
-proc listrefs {id} {
- global idtags idheads idotherrefs
+# Stuff for finding nearby tags
+proc getallcommits {} {
+ global allcstart allcommits allcfd
- set x {}
- if {[info exists idtags($id)]} {
- set x $idtags($id)
+ set fd [open [concat | git rev-list --all --topo-order --parents] r]
+ set allcfd $fd
+ fconfigure $fd -blocking 0
+ set allcommits "reading"
+ nowbusy allcommits
+ restartgetall $fd
+}
+
+proc discardallcommits {} {
+ global allparents allchildren allcommits allcfd
+ global desc_tags anc_tags alldtags tagisdesc allids desc_heads
+
+ if {![info exists allcommits]} return
+ if {$allcommits eq "reading"} {
+ catch {close $allcfd}
}
- set y {}
- if {[info exists idheads($id)]} {
- set y $idheads($id)
+ foreach v {allcommits allchildren allparents allids desc_tags anc_tags
+ alldtags tagisdesc desc_heads} {
+ catch {unset $v}
}
- set z {}
- if {[info exists idotherrefs($id)]} {
- set z $idotherrefs($id)
+}
+
+proc restartgetall {fd} {
+ global allcstart
+
+ fileevent $fd readable [list getallclines $fd]
+ set allcstart [clock clicks -milliseconds]
+}
+
+proc combine_dtags {l1 l2} {
+ global tagisdesc notfirstd
+
+ set res [lsort -unique [concat $l1 $l2]]
+ for {set i 0} {$i < [llength $res]} {incr i} {
+ set x [lindex $res $i]
+ for {set j [expr {$i+1}]} {$j < [llength $res]} {} {
+ set y [lindex $res $j]
+ if {[info exists tagisdesc($x,$y)]} {
+ if {$tagisdesc($x,$y) > 0} {
+ # x is a descendent of y, exclude x
+ set res [lreplace $res $i $i]
+ incr i -1
+ break
+ } else {
+ # y is a descendent of x, exclude y
+ set res [lreplace $res $j $j]
+ }
+ } else {
+ # no relation, keep going
+ incr j
+ }
+ }
+ }
+ return $res
+}
+
+proc combine_atags {l1 l2} {
+ global tagisdesc
+
+ set res [lsort -unique [concat $l1 $l2]]
+ for {set i 0} {$i < [llength $res]} {incr i} {
+ set x [lindex $res $i]
+ for {set j [expr {$i+1}]} {$j < [llength $res]} {} {
+ set y [lindex $res $j]
+ if {[info exists tagisdesc($x,$y)]} {
+ if {$tagisdesc($x,$y) < 0} {
+ # x is an ancestor of y, exclude x
+ set res [lreplace $res $i $i]
+ incr i -1
+ break
+ } else {
+ # y is an ancestor of x, exclude y
+ set res [lreplace $res $j $j]
+ }
+ } else {
+ # no relation, keep going
+ incr j
+ }
+ }
+ }
+ return $res
+}
+
+proc getallclines {fd} {
+ global allparents allchildren allcommits allcstart
+ global desc_tags anc_tags idtags alldtags tagisdesc allids
+ global desc_heads idheads
+
+ while {[gets $fd line] >= 0} {
+ set id [lindex $line 0]
+ lappend allids $id
+ set olds [lrange $line 1 end]
+ set allparents($id) $olds
+ if {![info exists allchildren($id)]} {
+ set allchildren($id) {}
+ }
+ foreach p $olds {
+ lappend allchildren($p) $id
+ }
+ # compute nearest tagged descendents as we go
+ # also compute descendent heads
+ set dtags {}
+ set dheads {}
+ foreach child $allchildren($id) {
+ if {[info exists idtags($child)]} {
+ set ctags [list $child]
+ } else {
+ set ctags $desc_tags($child)
+ }
+ if {$dtags eq {}} {
+ set dtags $ctags
+ } elseif {$ctags ne $dtags} {
+ set dtags [combine_dtags $dtags $ctags]
+ }
+ set cheads $desc_heads($child)
+ if {$dheads eq {}} {
+ set dheads $cheads
+ } elseif {$cheads ne $dheads} {
+ set dheads [lsort -unique [concat $dheads $cheads]]
+ }
+ }
+ set desc_tags($id) $dtags
+ if {[info exists idtags($id)]} {
+ set adt $dtags
+ foreach tag $dtags {
+ set adt [concat $adt $alldtags($tag)]
+ }
+ set adt [lsort -unique $adt]
+ set alldtags($id) $adt
+ foreach tag $adt {
+ set tagisdesc($id,$tag) -1
+ set tagisdesc($tag,$id) 1
+ }
+ }
+ if {[info exists idheads($id)]} {
+ lappend dheads $id
+ }
+ set desc_heads($id) $dheads
+ if {[clock clicks -milliseconds] - $allcstart >= 50} {
+ fileevent $fd readable {}
+ after idle restartgetall $fd
+ return
+ }
+ }
+ if {[eof $fd]} {
+ after idle restartatags [llength $allids]
+ if {[catch {close $fd} err]} {
+ error_popup "Error reading full commit graph: $err.\n\
+ Results may be incomplete."
+ }
}
- return [list $x $y $z]
+}
+
+# walk backward through the tree and compute nearest tagged ancestors
+proc restartatags {i} {
+ global allids allparents idtags anc_tags t0
+
+ set t0 [clock clicks -milliseconds]
+ while {[incr i -1] >= 0} {
+ set id [lindex $allids $i]
+ set atags {}
+ foreach p $allparents($id) {
+ if {[info exists idtags($p)]} {
+ set ptags [list $p]
+ } else {
+ set ptags $anc_tags($p)
+ }
+ if {$atags eq {}} {
+ set atags $ptags
+ } elseif {$ptags ne $atags} {
+ set atags [combine_atags $atags $ptags]
+ }
+ }
+ set anc_tags($id) $atags
+ if {[clock clicks -milliseconds] - $t0 >= 50} {
+ after idle restartatags $i
+ return
+ }
+ }
+ set allcommits "done"
+ notbusy allcommits
+ dispneartags
}
proc rereadrefs {} {
}
}
+proc listrefs {id} {
+ global idtags idheads idotherrefs
+
+ set x {}
+ if {[info exists idtags($id)]} {
+ set x $idtags($id)
+ }
+ set y {}
+ if {[info exists idheads($id)]} {
+ set y $idheads($id)
+ }
+ set z {}
+ if {[info exists idotherrefs($id)]} {
+ set z $idotherrefs($id)
+ }
+ return [list $x $y $z]
+}
+
proc showtag {tag isnew} {
global ctext tagcontents tagids linknum
} else {
set text "Tag: $tag\nId: $tagids($tag)"
}
- appendwithlinks $text
+ appendwithlinks $text {}
$ctext conf -state disabled
init_flist {}
}
proc doprefs {} {
global maxwidth maxgraphpct diffopts
- global oldprefs prefstop
+ global oldprefs prefstop showneartags
set top .gitkprefs
set prefstop $top
raise $top
return
}
- foreach v {maxwidth maxgraphpct diffopts} {
+ foreach v {maxwidth maxgraphpct diffopts showneartags} {
set oldprefs($v) [set $v]
}
toplevel $top
-font optionfont
entry $top.diffopt -width 20 -textvariable diffopts
grid x $top.diffoptl $top.diffopt -sticky w
+ frame $top.ntag
+ label $top.ntag.l -text "Display nearby tags" -font optionfont
+ checkbutton $top.ntag.b -variable showneartags
+ pack $top.ntag.b $top.ntag.l -side left
+ grid x $top.ntag -sticky w
frame $top.buts
button $top.buts.ok -text "OK" -command prefsok
button $top.buts.can -text "Cancel" -command prefscan
proc prefscan {} {
global maxwidth maxgraphpct diffopts
- global oldprefs prefstop
+ global oldprefs prefstop showneartags
- foreach v {maxwidth maxgraphpct diffopts} {
+ foreach v {maxwidth maxgraphpct diffopts showneartags} {
set $v $oldprefs($v)
}
catch {destroy $prefstop}
proc prefsok {} {
global maxwidth maxgraphpct
- global oldprefs prefstop
+ global oldprefs prefstop showneartags
catch {destroy $prefstop}
unset prefstop
if {$maxwidth != $oldprefs(maxwidth)
|| $maxgraphpct != $oldprefs(maxgraphpct)} {
redisplay
+ } elseif {$showneartags != $oldprefs(showneartags)} {
+ reselectline
}
}
# defaults...
set datemode 0
set diffopts "-U 5 -p"
-set wrcomcmd "git-diff-tree --stdin -p --pretty"
+set wrcomcmd "git diff-tree --stdin -p --pretty"
set gitencoding {}
catch {
- set gitencoding [exec git-repo-config --get i18n.commitencoding]
+ set gitencoding [exec git repo-config --get i18n.commitencoding]
}
if {$gitencoding == ""} {
set gitencoding "utf-8"
set downarrowlen 7
set mingaplen 30
set cmitmode "patch"
+set wrapcomment "none"
+set showneartags 1
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]} {
- show_error . "Cannot find the git directory \"$gitdir\"."
+ show_error {} . "Cannot find the git directory \"$gitdir\"."
exit 1
}
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 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]
# so look for "fatal:".
set i [string first "fatal:" $err]
if {$i > 0} {
- set err [string range [expr {$i + 6}] end]
+ set err [string range $err [expr {$i + 6}] end]
}
- show_error . "Bad arguments to gitk:\n$err"
+ show_error {} . "Bad arguments to gitk:\n$err"
exit 1
}
}