global startmsecs
global commfd leftover tclencoding datemode
global viewargs viewfiles commitidx
+ global lookingforhead showlocalchanges
set startmsecs [clock clicks -milliseconds]
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 fd [open [concat | git rev-list --header $order \
- --parents --boundary --default HEAD $args] r]
+ set fd [open [concat | git log --no-color -z --pretty=raw $order --parents \
+ --boundary $viewargs($view) "--" $viewfiles($view)] r]
} err]} {
- puts stderr "Error executing git rev-list: $err"
+ error_popup "Error executing git rev-list: $err"
exit 1
}
set commfd($view) $fd
set leftover($view) {}
- fconfigure $fd -blocking 0 -translation lf
+ set lookingforhead $showlocalchanges
+ fconfigure $fd -blocking 0 -translation lf -eofchar {}
if {$tclencoding != {}} {
fconfigure $fd -encoding $tclencoding
}
global commitlisted
global leftover commfd
global displayorder commitidx commitrow commitdata
- global parentlist childlist children curview hlview
- global vparentlist vchildlist vdisporder vcmitlisted
+ global parentlist children curview hlview
+ global vparentlist vdisporder vcmitlisted
set stuff [read $fd 500000]
+ # git log doesn't terminate the last commit with a null...
+ if {$stuff == {} && $leftover($view) ne {} && [eof $fd]} {
+ set stuff "\0"
+ }
if {$stuff == {}} {
if {![eof $fd]} {
return 1
set j [string first "\n" $cmit]
set ok 0
set listed 1
- if {$j >= 0} {
- set ids [string range $cmit 0 [expr {$j - 1}]]
- if {[string range $ids 0 0] == "-"} {
- set listed 0
+ if {$j >= 0 && [string match "commit *" $cmit]} {
+ set ids [string range $cmit 7 [expr {$j - 1}]]
+ if {[string match {[-<>]*} $ids]} {
+ switch -- [string index $ids 0] {
+ "-" {set listed 0}
+ "<" {set listed 2}
+ ">" {set listed 3}
+ }
set ids [string range $ids 1 end]
}
set ok 1
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 log output: {$shortcmit}"
exit 1
}
set id [lindex $ids 0]
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
}
global numcommits startmsecs
if {[info exists pending_select]} {
- set row [expr {[lindex $displayorder 0] eq $nullid}]
+ set row [first_real_row]
selectline $row 1
}
if {$commitidx($curview) > 0} {
proc updatecommits {} {
global viewdata curview phase displayorder
- global children commitrow selectedline thickerline
+ global children commitrow selectedline thickerline showneartags
if {$phase ne {}} {
stop_rev_list
catch {unset viewdata($n)}
readrefs
changedrefs
- regetallcommits
+ if {$showneartags} {
+ getallcommits
+ }
showview $n
}
}
proc readrefs {} {
- global tagids idtags headids idheads tagcontents
- global otherrefids idotherrefs mainhead
+ global tagids idtags headids idheads tagobjid
+ global otherrefids idotherrefs mainhead mainheadid
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
catch {unset $v}
}
- set refd [open [list | git show-ref] r]
- while {0 <= [set n [gets $refd line]]} {
- if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
- match id path]} {
- continue
- }
- if {[regexp {^remotes/.*/HEAD$} $path match]} {
- continue
- }
- if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
- set type others
- set name $path
- }
- if {[regexp {^remotes/} $path match]} {
- set type heads
- }
- if {$type == "tags"} {
- set tagids($name) $id
- lappend idtags($id) $name
- set obj {}
- set type {}
- set tag {}
- catch {
- 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 refd [open [list | git show-ref -d] r]
+ while {[gets $refd line] >= 0} {
+ if {[string index $line 40] ne " "} continue
+ set id [string range $line 0 39]
+ set ref [string range $line 41 end]
+ if {![string match "refs/*" $ref]} continue
+ set name [string range $ref 5 end]
+ if {[string match "remotes/*" $name]} {
+ if {![string match "*/HEAD" $name]} {
+ set headids($name) $id
+ lappend idheads($id) $name
}
- } elseif { $type == "heads" } {
+ } elseif {[string match "heads/*" $name]} {
+ set name [string range $name 6 end]
set headids($name) $id
lappend idheads($id) $name
+ } elseif {[string match "tags/*" $name]} {
+ # this lets refs/tags/foo^{} overwrite refs/tags/foo,
+ # which is what we want since the former is the commit ID
+ set name [string range $name 5 end]
+ if {[string match "*^{}" $name]} {
+ set name [string range $name 0 end-3]
+ } else {
+ set tagobjid($name) $id
+ }
+ set tagids($name) $id
+ lappend idtags($id) $name
} else {
set otherrefids($name) $id
lappend idotherrefs($id) $name
}
}
- close $refd
+ catch {close $refd}
set mainhead {}
+ set mainheadid {}
catch {
set thehead [exec git symbolic-ref HEAD]
if {[string match "refs/heads/*" $thehead]} {
set mainhead [string range $thehead 11 end]
+ if {[info exists headids($mainhead)]} {
+ set mainheadid $headids($mainhead)
+ }
+ }
+ }
+}
+
+# skip over fake commits
+proc first_real_row {} {
+ global nullid nullid2 displayorder numcommits
+
+ for {set row 0} {$row < $numcommits} {incr row} {
+ set id [lindex $displayorder $row]
+ if {$id ne $nullid && $id ne $nullid2} {
+ break
}
}
+ return $row
}
# update things for a head moved to a child of its previous location
global textfont mainfont uifont tabstop
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
+ global diffcontextstring diffcontext
global maincursor textcursor curtextcursor
- global rowctxmenu mergemax wrapcomment
+ global rowctxmenu fakerowmenu mergemax wrapcomment
global highlight_files gdttype
global searchstring sstring
global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
menu .bar.file
.bar.file add command -label "Update" -command updatecommits
.bar.file add command -label "Reread references" -command rereadrefs
+ .bar.file add command -label "List references" -command showrefs
.bar.file add command -label "Quit" -command doquit
.bar.file configure -font $uifont
menu .bar.edit
-command changediffdisp -variable diffelide -value {0 1}
radiobutton .bleft.mid.new -text "New version" \
-command changediffdisp -variable diffelide -value {1 0}
+ label .bleft.mid.labeldiffcontext -text " Lines of context: " \
+ -font $uifont
pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
+ spinbox .bleft.mid.diffcontext -width 5 -font $textfont \
+ -from 1 -increment 1 -to 10000000 \
+ -validate all -validatecommand "diffcontextvalidate %P" \
+ -textvariable diffcontextstring
+ .bleft.mid.diffcontext set $diffcontext
+ trace add variable diffcontextstring write diffcontextchange
+ lappend entries .bleft.mid.diffcontext
+ pack .bleft.mid.labeldiffcontext .bleft.mid.diffcontext -side left
set ctext .bleft.ctext
text $ctext -background $bgcolor -foreground $fgcolor \
-tabs "[expr {$tabstop * $charspc}]" \
wm geometry . "$geometry(main)"
}
+ if {[tk windowingsystem] eq {aqua}} {
+ set M1B M1
+ } else {
+ set M1B Control
+ }
+
bind .pwbottom <Configure> {resizecdetpanes %W %w}
pack .ctop -fill both -expand 1
bindall <1> {selcanvline %W %x %y}
#bindall <B1-Motion> {selcanvline %W %x %y}
- bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
- bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+ if {[tk windowingsystem] == "win32"} {
+ bind . <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D }
+ bind $ctext <MouseWheel> { windows_mousewheel_redirector %W %X %Y %D ; break }
+ } else {
+ bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
+ bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
+ if {[tk windowingsystem] eq "aqua"} {
+ bindall <MouseWheel> {
+ set delta [expr {- (%D)}]
+ allcanvs yview scroll $delta units
+ }
+ }
+ }
bindall <2> "canvscan mark %W %x %y"
bindall <B2-Motion> "canvscan dragto %W %x %y"
bindkey <Home> selfirstline
bindkey <Key-Left> "goback"
bind . <Key-Prior> "selnextpage -1"
bind . <Key-Next> "selnextpage 1"
- bind . <Control-Home> "allcanvs yview moveto 0.0"
- bind . <Control-End> "allcanvs yview moveto 1.0"
- bind . <Control-Key-Up> "allcanvs yview scroll -1 units"
- bind . <Control-Key-Down> "allcanvs yview scroll 1 units"
- bind . <Control-Key-Prior> "allcanvs yview scroll -1 pages"
- bind . <Control-Key-Next> "allcanvs yview scroll 1 pages"
+ bind . <$M1B-Home> "allcanvs yview moveto 0.0"
+ bind . <$M1B-End> "allcanvs yview moveto 1.0"
+ bind . <$M1B-Key-Up> "allcanvs yview scroll -1 units"
+ bind . <$M1B-Key-Down> "allcanvs yview scroll 1 units"
+ bind . <$M1B-Key-Prior> "allcanvs yview scroll -1 pages"
+ bind . <$M1B-Key-Next> "allcanvs yview scroll 1 pages"
bindkey <Key-Delete> "$ctext yview scroll -1 pages"
bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
bindkey <Key-space> "$ctext yview scroll 1 pages"
bindkey ? findprev
bindkey f nextfile
bindkey <F5> updatecommits
- bind . <Control-q> doquit
- bind . <Control-f> dofind
- bind . <Control-g> {findnext 0}
- bind . <Control-r> dosearchback
- bind . <Control-s> dosearch
- bind . <Control-equal> {incrfont 1}
- bind . <Control-KP_Add> {incrfont 1}
- bind . <Control-minus> {incrfont -1}
- bind . <Control-KP_Subtract> {incrfont -1}
+ bind . <$M1B-q> doquit
+ bind . <$M1B-f> dofind
+ bind . <$M1B-g> {findnext 0}
+ bind . <$M1B-r> dosearchback
+ bind . <$M1B-s> dosearch
+ bind . <$M1B-equal> {incrfont 1}
+ bind . <$M1B-KP_Add> {incrfont 1}
+ bind . <$M1B-minus> {incrfont -1}
+ bind . <$M1B-KP_Subtract> {incrfont -1}
wm protocol . WM_DELETE_WINDOW doquit
bind . <Button-1> "click %W"
bind $fstring <Key-Return> dofind
bind $cflist <1> {sel_flist %W %x %y; break}
bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
+ bind $cflist <Button-3> {pop_flist_menu %W %X %Y %x %y}
set maincursor [. cget -cursor]
set textcursor [$ctext cget -cursor]
$rowctxmenu add command -label "Create new branch" -command mkbranch
$rowctxmenu add command -label "Cherry-pick this commit" \
-command cherrypick
+ $rowctxmenu add command -label "Reset HEAD branch to here" \
+ -command resethead
+
+ set fakerowmenu .fakerowmenu
+ menu $fakerowmenu -tearoff 0
+ $fakerowmenu add command -label "Diff this -> selected" \
+ -command {diffvssel 0}
+ $fakerowmenu add command -label "Diff selected -> this" \
+ -command {diffvssel 1}
+ $fakerowmenu add command -label "Make patch" -command mkpatch
+# $fakerowmenu add command -label "Commit" -command {mkcommit 0}
+# $fakerowmenu add command -label "Commit all" -command {mkcommit 1}
+# $fakerowmenu add command -label "Revert local changes" -command revertlocal
set headctxmenu .headctxmenu
menu $headctxmenu -tearoff 0
-command cobranch
$headctxmenu add command -label "Remove this branch" \
-command rmbranch
+
+ global flist_menu
+ set flist_menu .flistctxmenu
+ menu $flist_menu -tearoff 0
+ $flist_menu add command -label "Highlight this too" \
+ -command {flist_hl 0}
+ $flist_menu add command -label "Highlight this only" \
+ -command {flist_hl 1}
+}
+
+# Windows sends all mouse wheel events to the current focused window, not
+# the one where the mouse hovers, so bind those events here and redirect
+# to the correct window
+proc windows_mousewheel_redirector {W X Y D} {
+ global canv canv2 canv3
+ set w [winfo containing -displayof $W $X $Y]
+ if {$w ne ""} {
+ set u [expr {$D < 0 ? 5 : -5}]
+ if {$w == $canv || $w == $canv2 || $w == $canv3} {
+ allcanvs yview scroll $u units
+ } else {
+ catch {
+ $w yview scroll $u units
+ }
+ }
+ }
}
# mouse-2 makes all windows scan vertically, but only the one
# set the focus back to the toplevel for any click outside
# the entry widgets
proc click {w} {
- global entries
- foreach e $entries {
+ global ctext entries
+ foreach e [concat $entries $ctext] {
if {$w == $e} return
}
focus .
proc savestuff {w} {
global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop
global stuffsaved findmergefiles maxgraphpct
- global maxwidth showneartags
+ global maxwidth showneartags showlocalchanges
global viewname viewfiles viewargs viewperm nextviewnum
- global cmitmode wrapcomment
- global colors bgcolor fgcolor diffcolors selectbgcolor
+ global cmitmode wrapcomment datetimeformat
+ global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
if {$stuffsaved} return
if {![winfo viewable .]} return
puts $f [list set cmitmode $cmitmode]
puts $f [list set wrapcomment $wrapcomment]
puts $f [list set showneartags $showneartags]
+ puts $f [list set showlocalchanges $showlocalchanges]
+ puts $f [list set datetimeformat $datetimeformat]
puts $f [list set bgcolor $bgcolor]
puts $f [list set fgcolor $fgcolor]
puts $f [list set colors $colors]
puts $f [list set diffcolors $diffcolors]
+ puts $f [list set diffcontext $diffcontext]
puts $f [list set selectbgcolor $selectbgcolor]
puts $f "set geometry(main) [wm geometry .]"
raise $w
return
}
+ if {[tk windowingsystem] eq {aqua}} {
+ set M1T Cmd
+ } else {
+ set M1T Ctrl
+ }
toplevel $w
wm title $w "Gitk key bindings"
- message $w.m -text {
+ message $w.m -text "
Gitk key bindings:
-<Ctrl-Q> Quit
+<$M1T-Q> Quit
<Home> Move to first commit
<End> Move to last commit
<Up>, p, i Move up one commit
<Right>, x, l Go forward in history list
<PageUp> Move up one page in commit list
<PageDown> Move down one page in commit list
-<Ctrl-Home> Scroll to top of commit list
-<Ctrl-End> Scroll to bottom of commit list
-<Ctrl-Up> Scroll commit list up one line
-<Ctrl-Down> Scroll commit list down one line
-<Ctrl-PageUp> Scroll commit list up one page
-<Ctrl-PageDown> Scroll commit list down one page
+<$M1T-Home> Scroll to top of commit list
+<$M1T-End> Scroll to bottom of commit list
+<$M1T-Up> Scroll commit list up one line
+<$M1T-Down> Scroll commit list down one line
+<$M1T-PageUp> Scroll commit list up one page
+<$M1T-PageDown> Scroll commit list down one page
<Shift-Up> Move to previous highlighted line
<Shift-Down> Move to next highlighted line
<Delete>, b Scroll diff view up one page
<Space> Scroll diff view down one page
u Scroll diff view up 18 lines
d Scroll diff view down 18 lines
-<Ctrl-F> Find
-<Ctrl-G> Move to next find hit
+<$M1T-F> Find
+<$M1T-G> Move to next find hit
<Return> Move to next find hit
/ Move to next find hit, or redo find
? Move to previous find hit
f Scroll diff view to next file
-<Ctrl-S> Search for next hit in diff view
-<Ctrl-R> Search for previous hit in diff view
-<Ctrl-KP+> Increase font size
-<Ctrl-plus> Increase font size
-<Ctrl-KP-> Decrease font size
-<Ctrl-minus> Decrease font size
+<$M1T-S> Search for next hit in diff view
+<$M1T-R> Search for previous hit in diff view
+<$M1T-KP+> Increase font size
+<$M1T-plus> Increase font size
+<$M1T-KP-> Decrease font size
+<$M1T-minus> Decrease font size
<F5> Update
-} \
+" \
-justify left -bg white -border 2 -relief groove
pack $w.m -side top -fill both -padx 2 -pady 2
$w.m configure -font $uifont
set treeheight($prefix) $ht
incr ht [lindex $htstack end]
set htstack [lreplace $htstack end end]
+ set prefixend [lindex $prefendstack end]
+ set prefendstack [lreplace $prefendstack end end]
+ set prefix [string range $prefix 0 $prefixend]
}
$w conf -state disabled
}
0x00, 0x00};
}
+image create bitmap reficon-T -background black -foreground yellow -data {
+ #define tagicon_width 13
+ #define tagicon_height 9
+ static unsigned char tagicon_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0xf8, 0x07,
+ 0xfc, 0x07, 0xf8, 0x07, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00};
+} -maskdata {
+ #define tagicon-mask_width 13
+ #define tagicon-mask_height 9
+ static unsigned char tagicon-mask_bits[] = {
+ 0x00, 0x00, 0xf0, 0x0f, 0xf8, 0x0f, 0xfc, 0x0f,
+ 0xfe, 0x0f, 0xfc, 0x0f, 0xf8, 0x0f, 0xf0, 0x0f, 0x00, 0x00};
+}
+set rectdata {
+ #define headicon_width 13
+ #define headicon_height 9
+ static unsigned char headicon_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0xf8, 0x07,
+ 0xf8, 0x07, 0xf8, 0x07, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00};
+}
+set rectmask {
+ #define headicon-mask_width 13
+ #define headicon-mask_height 9
+ static unsigned char headicon-mask_bits[] = {
+ 0x00, 0x00, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f,
+ 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x0f, 0x00, 0x00};
+}
+image create bitmap reficon-H -background black -foreground green \
+ -data $rectdata -maskdata $rectmask
+image create bitmap reficon-o -background black -foreground "#ddddff" \
+ -data $rectdata -maskdata $rectmask
+
proc init_flist {first} {
global cflist cflist_top selectedline difffilestart
}
}
+proc pop_flist_menu {w X Y x y} {
+ global ctext cflist cmitmode flist_menu flist_menu_file
+ global treediffs diffids
+
+ set l [lindex [split [$w index "@$x,$y"] "."] 0]
+ if {$l <= 1} return
+ if {$cmitmode eq "tree"} {
+ set e [linetoelt $l]
+ if {[string index $e end] eq "/"} return
+ } else {
+ set e [lindex $treediffs($diffids) [expr {$l-2}]]
+ }
+ set flist_menu_file $e
+ tk_popup $flist_menu $X $Y
+}
+
+proc flist_hl {only} {
+ global flist_menu_file highlight_files
+
+ set x [shellquote $flist_menu_file]
+ if {$only || $highlight_files eq {}} {
+ set highlight_files $x
+ } else {
+ append highlight_files " " $x
+ }
+}
+
# Functions for adding and removing shell-type quoting
proc shellquote {str} {
proc showview {n} {
global curview viewdata viewfiles
- global displayorder parentlist childlist rowidlist rowoffsets
+ global displayorder parentlist rowidlist rowoffsets
global colormap rowtextx commitrow nextcolor canvxmax
- global numcommits rowrangelist commitlisted idrowranges
+ global numcommits rowrangelist commitlisted idrowranges rowchk
global selectedline currentid canv canvy0
- global matchinglines treediffs
+ global treediffs
global pending_select phase
- global commitidx rowlaidout rowoptim linesegends
+ global commitidx rowlaidout rowoptim
global commfd
global selectedview selectfirst
- global vparentlist vchildlist vdisporder vcmitlisted
+ global vparentlist vdisporder vcmitlisted
global hlview selectedhlview
if {$n == $curview} return
}
unselectline
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 $rowidlist $rowoffsets $rowrangelist \
[flatten idrowranges] [flatten idinlist] \
- $rowlaidout $rowoptim $numcommits $linesegends]
+ $rowlaidout $rowoptim $numcommits]
} elseif {![info exists viewdata($curview)]
|| [lindex $viewdata($curview) 0] ne {}} {
set viewdata($curview) \
[list {} $rowidlist $rowoffsets $rowrangelist]
}
}
- catch {unset matchinglines}
catch {unset treediffs}
clear_display
if {[info exists hlview] && $hlview == $n} {
set phase [lindex $v 0]
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 rowlaidout [lindex $v 6]
set rowoptim [lindex $v 7]
set numcommits [lindex $v 8]
- set linesegends [lindex $v 9]
+ catch {unset rowchk}
}
catch {unset colormap}
} elseif {$selid ne {}} {
set pending_select $selid
} else {
- if {$numcommits > 0} {
- selectline 0 0
+ set row [first_real_row]
+ if {$row < $numcommits} {
+ selectline $row 0
} else {
set selectfirst 1
}
} elseif {$numcommits == 0} {
show_status "No commits selected"
}
+ run refill_reflist
}
# Stuff relating to the highlighting facility
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
set boldnamerows {}
catch {unset nhighlights}
unbolden
+ unmarkmatches
if {$findtype ne "Regexp"} {
set e [string map {"*" "\\*" "?" "\\?" "\[" "\\\[" "\\" "\\\\"} \
$findstring]
drawvisible
}
+proc doesmatch {f} {
+ global findtype findstring findpattern
+
+ if {$findtype eq "Regexp"} {
+ return [regexp $findstring $f]
+ } elseif {$findtype eq "IgnCase"} {
+ return [string match -nocase $findpattern $f]
+ } else {
+ return [string match $findpattern $f]
+ }
+}
+
proc askfindhighlight {row id} {
global nhighlights commitinfo iddrawn mainfont
- global findstring findtype findloc findpattern
+ global findloc
+ global markingmatches
if {![info exists commitinfo($id)]} {
getcommit $id
set isbold 0
set fldtypes {Headline Author Date Committer CDate Comments}
foreach f $info ty $fldtypes {
- if {$findloc ne "All fields" && $findloc ne $ty} {
- continue
- }
- if {$findtype eq "Regexp"} {
- set doesmatch [regexp $findstring $f]
- } elseif {$findtype eq "IgnCase"} {
- set doesmatch [string match -nocase $findpattern $f]
- } else {
- set doesmatch [string match $findpattern $f]
- }
- if {$doesmatch} {
+ if {($findloc eq "All fields" || $findloc eq $ty) &&
+ [doesmatch $f]} {
if {$ty eq "Author"} {
set isbold 2
- } else {
- set isbold 1
+ break
}
+ set isbold 1
}
}
- if {[info exists iddrawn($id)]} {
- if {$isbold && ![ishighlighted $row]} {
- bolden $row [concat $mainfont bold]
+ if {$isbold && [info exists iddrawn($id)]} {
+ set f [concat $mainfont bold]
+ if {![ishighlighted $row]} {
+ bolden $row $f
+ if {$isbold > 1} {
+ bolden_name $row $f
+ }
}
- if {$isbold >= 2} {
- bolden_name $row [concat $mainfont bold]
+ if {$markingmatches} {
+ markrowmatches $row $id
}
}
set nhighlights($row) $isbold
}
+proc markrowmatches {row id} {
+ global canv canv2 linehtag linentag commitinfo findloc
+
+ set headline [lindex $commitinfo($id) 0]
+ set author [lindex $commitinfo($id) 1]
+ $canv delete match$row
+ $canv2 delete match$row
+ if {$findloc eq "All fields" || $findloc eq "Headline"} {
+ set m [findmatches $headline]
+ if {$m ne {}} {
+ markmatches $canv $row $headline $linehtag($row) $m \
+ [$canv itemcget $linehtag($row) -font] $row
+ }
+ }
+ if {$findloc eq "All fields" || $findloc eq "Author"} {
+ set m [findmatches $author]
+ if {$m ne {}} {
+ markmatches $canv2 $row $author $linentag($row) $m \
+ [$canv2 itemcget $linentag($row) -font] $row
+ }
+ }
+}
+
proc vrel_change {name ix op} {
global highlight_related
}
proc usedinrange {id l1 l2} {
- global children commitrow childlist curview
+ global children commitrow curview
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($curview,$id)
}
+ set kids $children($curview,$id)
foreach c $kids {
set r $commitrow($curview,$c)
if {$l1 <= $r && $r <= $l2} {
global idinlist rowchk rowrangelist idrowranges
global numcommits canvxmax canv
global nextcolor
- global parentlist childlist children
+ global parentlist
global colormap rowtextx
- global linesegends selectfirst
+ global selectfirst
set numcommits 0
set displayorder {}
set commitlisted {}
set parentlist {}
- set childlist {}
set rowrangelist {}
set nextcolor 0
set rowidlist {{}}
catch {unset colormap}
catch {unset rowtextx}
catch {unset idrowranges}
- set linesegends {}
set selectfirst 1
}
global rowlaidout rowoptim commitidx numcommits optim_delay
global uparrowlen curview rowidlist idinlist
+ set showlast 0
set showdelay $optim_delay
set optdelay [expr {$uparrowlen + 1}]
while {1} {
if {$rowoptim - $showdelay > $numcommits} {
- showstuff [expr {$rowoptim - $showdelay}]
+ showstuff [expr {$rowoptim - $showdelay}] $showlast
} elseif {$rowlaidout - $optdelay > $rowoptim} {
set nr [expr {$rowlaidout - $optdelay - $rowoptim}]
if {$nr > 100} {
set rowlaidout $commitidx($curview)
} elseif {$rowoptim == $nrows} {
set showdelay 0
+ set showlast 1
if {$numcommits == $nrows} {
return 0
}
}
}
-proc showstuff {canshow} {
- global numcommits commitrow pending_select selectedline
- global linesegends idrangedrawn curview
- global displayorder selectfirst
+proc showstuff {canshow last} {
+ global numcommits commitrow pending_select selectedline curview
+ global lookingforhead mainheadid displayorder selectfirst
+ global lastscrollset commitinterest
if {$numcommits == 0} {
global phase
set phase "incrdraw"
allcanvs delete all
}
- set row $numcommits
- set numcommits $canshow
- setcanvscroll
- set rows [visiblerows]
- set r0 [lindex $rows 0]
- set r1 [lindex $rows 1]
- set selrow -1
- for {set r $row} {$r < $canshow} {incr r} {
- foreach id [lindex $linesegends [expr {$r+1}]] {
- set i -1
- set ranges [rowranges $id]
- foreach {s e} $ranges {
- incr i
- if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
- && ![info exists idrangedrawn($id,$i)]} {
- drawlineseg $id $i $ranges
- set idrangedrawn($id,$i) 1
- }
+ for {set l $numcommits} {$l < $canshow} {incr l} {
+ set id [lindex $displayorder $l]
+ if {[info exists commitinterest($id)]} {
+ foreach script $commitinterest($id) {
+ eval [string map [list "%I" $id] $script]
}
+ unset commitinterest($id)
}
}
- if {$canshow > $r1} {
- set canshow $r1
+ set r0 $numcommits
+ set prev $numcommits
+ set numcommits $canshow
+ set t [clock clicks -milliseconds]
+ if {$prev < 100 || $last || $t - $lastscrollset > 500} {
+ set lastscrollset $t
+ setcanvscroll
}
- while {$row < $canshow} {
- drawcmitrow $row
- incr row
+ set rows [visiblerows]
+ set r1 [lindex $rows 1]
+ if {$r1 >= $canshow} {
+ set r1 [expr {$canshow - 1}]
+ }
+ if {$r0 <= $r1} {
+ drawcommits $r0 $r1
}
if {[info exists pending_select] &&
[info exists commitrow($curview,$pending_select)] &&
if {[info exists selectedline] || [info exists pending_select]} {
set selectfirst 0
} else {
- selectline 0 1
+ set l [first_real_row]
+ selectline $l 1
set selectfirst 0
}
}
+ if {$lookingforhead && [info exists commitrow($curview,$mainheadid)]
+ && ($last || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
+ set lookingforhead 0
+ dodiffindex
+ }
+}
+
+proc doshowlocalchanges {} {
+ global lookingforhead curview mainheadid phase commitrow
+
+ if {[info exists commitrow($curview,$mainheadid)] &&
+ ($phase eq {} || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
+ dodiffindex
+ } elseif {$phase ne {}} {
+ set lookingforhead 1
+ }
+}
+
+proc dohidelocalchanges {} {
+ global lookingforhead localfrow localirow lserial
+
+ set lookingforhead 0
+ if {$localfrow >= 0} {
+ removerow $localfrow
+ set localfrow -1
+ if {$localirow > 0} {
+ incr localirow -1
+ }
+ }
+ if {$localirow >= 0} {
+ removerow $localirow
+ set localirow -1
+ }
+ incr lserial
+}
+
+# spawn off a process to do git diff-index --cached HEAD
+proc dodiffindex {} {
+ global localirow localfrow lserial
+
+ incr lserial
+ set localfrow -1
+ set localirow -1
+ set fd [open "|git diff-index --cached HEAD" r]
+ fconfigure $fd -blocking 0
+ filerun $fd [list readdiffindex $fd $lserial]
+}
+
+proc readdiffindex {fd serial} {
+ global localirow commitrow mainheadid nullid2 curview
+ global commitinfo commitdata lserial
+
+ set isdiff 1
+ if {[gets $fd line] < 0} {
+ if {![eof $fd]} {
+ return 1
+ }
+ set isdiff 0
+ }
+ # we only need to see one line and we don't really care what it says...
+ close $fd
+
+ # now see if there are any local changes not checked in to the index
+ if {$serial == $lserial} {
+ set fd [open "|git diff-files" r]
+ fconfigure $fd -blocking 0
+ filerun $fd [list readdifffiles $fd $serial]
+ }
+
+ if {$isdiff && $serial == $lserial && $localirow == -1} {
+ # add the line for the changes in the index to the graph
+ set localirow $commitrow($curview,$mainheadid)
+ set hl "Local changes checked in to index but not committed"
+ set commitinfo($nullid2) [list $hl {} {} {} {} " $hl\n"]
+ set commitdata($nullid2) "\n $hl\n"
+ insertrow $localirow $nullid2
+ }
+ return 0
+}
+
+proc readdifffiles {fd serial} {
+ global localirow localfrow commitrow mainheadid nullid curview
+ global commitinfo commitdata lserial
+
+ set isdiff 1
+ if {[gets $fd line] < 0} {
+ if {![eof $fd]} {
+ return 1
+ }
+ set isdiff 0
+ }
+ # we only need to see one line and we don't really care what it says...
+ close $fd
+
+ if {$isdiff && $serial == $lserial && $localfrow == -1} {
+ # add the line for the local diff to the graph
+ if {$localirow >= 0} {
+ set localfrow $localirow
+ incr localirow
+ } else {
+ set localfrow $commitrow($curview,$mainheadid)
+ }
+ set hl "Local uncommitted changes, not checked in to index"
+ set commitinfo($nullid) [list $hl {} {} {} {} " $hl\n"]
+ set commitdata($nullid) "\n $hl\n"
+ insertrow $localfrow $nullid
+ }
+ return 0
}
proc layoutrows {row endrow last} {
global rowidlist rowoffsets displayorder
global uparrowlen downarrowlen maxwidth mingaplen
- global childlist parentlist
- global idrowranges linesegends
+ global children parentlist
+ global idrowranges
global commitidx curview
global idinlist rowchk rowrangelist
set offs [lindex $rowoffsets $row]
while {$row < $endrow} {
set id [lindex $displayorder $row]
- set oldolds {}
- set newolds {}
+ set nev [expr {[llength $idlist] - $maxwidth + 1}]
foreach p [lindex $parentlist $row] {
- if {![info exists idinlist($p)]} {
- lappend newolds $p
- } elseif {!$idinlist($p)} {
- lappend oldolds $p
+ if {![info exists idinlist($p)] || !$idinlist($p)} {
+ incr nev
}
}
- set lse {}
- set nev [expr {[llength $idlist] + [llength $newolds]
- + [llength $oldolds] - $maxwidth + 1}]
if {$nev > 0} {
if {!$last &&
$row + $uparrowlen + $mingaplen >= $commitidx($curview)} break
set offs [incrange $offs $x 1]
set idinlist($i) 0
set rm1 [expr {$row - 1}]
- lappend lse $i
lappend idrowranges($i) [lindex $displayorder $rm1]
if {[incr nev -1] <= 0} break
continue
}
- set rowchk($id) [expr {$row + $r}]
+ set rowchk($i) [expr {$row + $r}]
}
}
lset rowidlist $row $idlist
lset rowoffsets $row $offs
}
- lappend linesegends $lse
+ set oldolds {}
+ set newolds {}
+ foreach p [lindex $parentlist $row] {
+ if {![info exists idinlist($p)]} {
+ lappend newolds $p
+ } elseif {!$idinlist($p)} {
+ lappend oldolds $p
+ }
+ set idinlist($p) 1
+ }
set col [lsearch -exact $idlist $id]
if {$col < 0} {
set col [llength $idlist]
lappend idlist $id
lset rowidlist $row $idlist
set z {}
- if {[lindex $childlist $row] ne {}} {
+ if {$children($curview,$id) ne {}} {
set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
unset idinlist($id)
}
lset offs $col {}
}
foreach i $newolds {
- set idinlist($i) 1
set idrowranges($i) $id
}
incr col $l
foreach oid $oldolds {
- set idinlist($oid) 1
set idlist [linsert $idlist $col $oid]
set offs [linsert $offs $col $o]
makeuparrow $oid $col $row $o
proc addextraid {id row} {
global displayorder commitrow commitinfo
global commitidx commitlisted
- global parentlist childlist children curview
+ global parentlist children curview
incr commitidx($curview)
lappend displayorder $id
if {![info exists children($curview,$id)]} {
set children($curview,$id) {}
}
- lappend childlist $children($curview,$id)
}
proc layouttail {} {
set col [expr {[llength $idlist] - 1}]
set id [lindex $idlist $col]
addextraid $id $row
- unset idinlist($id)
- lappend idrowranges($id) $row
+ catch {unset idinlist($id)}
+ lappend idrowranges($id) $id
lappend rowrangelist $idrowranges($id)
unset idrowranges($id)
incr row
lset rowidlist $row [list $id]
lset rowoffsets $row 0
makeuparrow $id 0 $row 0
- lappend idrowranges($id) $row
+ lappend idrowranges($id) $id
lappend rowrangelist $idrowranges($id)
unset idrowranges($id)
incr row
}
proc optimize_rows {row col endrow} {
- global rowidlist rowoffsets idrowranges displayorder
+ global rowidlist rowoffsets displayorder
for {} {$row < $endrow} {incr row} {
set idlist [lindex $rowidlist $row]
return $linenos
}
-proc drawlineseg {id i ranges} {
- global rowoffsets rowidlist
- global displayorder
- global canv colormap linespc
- global numcommits commitrow curview
+# work around tk8.4 refusal to draw arrows on diagonal segments
+proc adjarrowhigh {coords} {
+ global linespc
- set downarrow 1
- if {[info exists commitrow($curview,$id)]
- && $commitrow($curview,$id) < $numcommits} {
- set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
- } else {
- set downarrow 1
- }
- set startrow [lindex $ranges [expr {2 * $i}]]
- set row [lindex $ranges [expr {2 * $i + 1}]]
- if {$startrow == $row} return
- assigncolor $id
- set coords {}
- set col [lsearch -exact [lindex $rowidlist $row] $id]
- if {$col < 0} {
- puts "oops: drawline: id $id not on row $row"
- return
+ set x0 [lindex $coords 0]
+ set x1 [lindex $coords 2]
+ if {$x0 != $x1} {
+ set y0 [lindex $coords 1]
+ set y1 [lindex $coords 3]
+ if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
+ # we have a nearby vertical segment, just trim off the diag bit
+ set coords [lrange $coords 2 end]
+ } else {
+ set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
+ set xi [expr {$x0 - $slope * $linespc / 2}]
+ set yi [expr {$y0 - $linespc / 2}]
+ set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
+ }
}
- set lasto {}
- set ns 0
+ return $coords
+}
+
+proc drawlineseg {id row endrow arrowlow} {
+ global rowidlist displayorder iddrawn linesegs
+ global canv colormap linespc curview maxlinelen
+
+ set cols [list [lsearch -exact [lindex $rowidlist $row] $id]]
+ set le [expr {$row + 1}]
+ set arrowhigh 1
while {1} {
- set o [lindex $rowoffsets $row $col]
- if {$o eq {}} break
- if {$o ne $lasto} {
- # changing direction
- set x [xc $row $col]
- set y [yc $row]
- lappend coords $x $y
- set lasto $o
+ set c [lsearch -exact [lindex $rowidlist $le] $id]
+ if {$c < 0} {
+ incr le -1
+ break
+ }
+ lappend cols $c
+ set x [lindex $displayorder $le]
+ if {$x eq $id} {
+ set arrowhigh 0
+ break
}
- incr col $o
- incr row -1
+ if {[info exists iddrawn($x)] || $le == $endrow} {
+ set c [lsearch -exact [lindex $rowidlist [expr {$le+1}]] $id]
+ if {$c >= 0} {
+ lappend cols $c
+ set arrowhigh 0
+ }
+ break
+ }
+ incr le
}
- set x [xc $row $col]
- set y [yc $row]
- lappend coords $x $y
- if {$i == 0} {
- # draw the link to the first child as part of this line
- incr row -1
- set child [lindex $displayorder $row]
- set ccol [lsearch -exact [lindex $rowidlist $row] $child]
- if {$ccol >= 0} {
- set x [xc $row $ccol]
- set y [yc $row]
- if {$ccol < $col - 1} {
- lappend coords [xc $row [expr {$col - 1}]] [yc $row]
- } elseif {$ccol > $col + 1} {
- lappend coords [xc $row [expr {$col + 1}]] [yc $row]
- }
- lappend coords $x $y
- }
- }
- if {[llength $coords] < 4} return
- if {$downarrow} {
- # This line has an arrow at the lower end: check if the arrow is
- # on a diagonal segment, and if so, work around the Tk 8.4
- # refusal to draw arrows on diagonal lines.
- set x0 [lindex $coords 0]
- set x1 [lindex $coords 2]
- if {$x0 != $x1} {
- set y0 [lindex $coords 1]
- set y1 [lindex $coords 3]
- if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
- # we have a nearby vertical segment, just trim off the diag bit
- set coords [lrange $coords 2 end]
+ if {$le <= $row} {
+ return $row
+ }
+
+ set lines {}
+ set i 0
+ set joinhigh 0
+ if {[info exists linesegs($id)]} {
+ set lines $linesegs($id)
+ foreach li $lines {
+ set r0 [lindex $li 0]
+ if {$r0 > $row} {
+ if {$r0 == $le && [lindex $li 1] - $row <= $maxlinelen} {
+ set joinhigh 1
+ }
+ break
+ }
+ incr i
+ }
+ }
+ set joinlow 0
+ if {$i > 0} {
+ set li [lindex $lines [expr {$i-1}]]
+ set r1 [lindex $li 1]
+ if {$r1 == $row && $le - [lindex $li 0] <= $maxlinelen} {
+ set joinlow 1
+ }
+ }
+
+ set x [lindex $cols [expr {$le - $row}]]
+ set xp [lindex $cols [expr {$le - 1 - $row}]]
+ set dir [expr {$xp - $x}]
+ if {$joinhigh} {
+ set ith [lindex $lines $i 2]
+ set coords [$canv coords $ith]
+ set ah [$canv itemcget $ith -arrow]
+ set arrowhigh [expr {$ah eq "first" || $ah eq "both"}]
+ set x2 [lindex $cols [expr {$le + 1 - $row}]]
+ if {$x2 ne {} && $x - $x2 == $dir} {
+ set coords [lrange $coords 0 end-2]
+ }
+ } else {
+ set coords [list [xc $le $x] [yc $le]]
+ }
+ if {$joinlow} {
+ set itl [lindex $lines [expr {$i-1}] 2]
+ set al [$canv itemcget $itl -arrow]
+ set arrowlow [expr {$al eq "last" || $al eq "both"}]
+ } elseif {$arrowlow &&
+ [lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0} {
+ set arrowlow 0
+ }
+ set arrow [lindex {none first last both} [expr {$arrowhigh + 2*$arrowlow}]]
+ for {set y $le} {[incr y -1] > $row} {} {
+ set x $xp
+ set xp [lindex $cols [expr {$y - 1 - $row}]]
+ set ndir [expr {$xp - $x}]
+ if {$dir != $ndir || $xp < 0} {
+ lappend coords [xc $y $x] [yc $y]
+ }
+ set dir $ndir
+ }
+ if {!$joinlow} {
+ if {$xp < 0} {
+ # join parent line to first child
+ set ch [lindex $displayorder $row]
+ set xc [lsearch -exact [lindex $rowidlist $row] $ch]
+ if {$xc < 0} {
+ puts "oops: drawlineseg: child $ch not on row $row"
} else {
- set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
- set xi [expr {$x0 - $slope * $linespc / 2}]
- set yi [expr {$y0 - $linespc / 2}]
- set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
+ if {$xc < $x - 1} {
+ lappend coords [xc $row [expr {$x-1}]] [yc $row]
+ } elseif {$xc > $x + 1} {
+ lappend coords [xc $row [expr {$x+1}]] [yc $row]
+ }
+ set x $xc
+ }
+ lappend coords [xc $row $x] [yc $row]
+ } else {
+ set xn [xc $row $xp]
+ set yn [yc $row]
+ # work around tk8.4 refusal to draw arrows on diagonal segments
+ if {$arrowlow && $xn != [lindex $coords end-1]} {
+ if {[llength $coords] < 4 ||
+ [lindex $coords end-3] != [lindex $coords end-1] ||
+ [lindex $coords end] - $yn > 2 * $linespc} {
+ set xn [xc $row [expr {$xp - 0.5 * $dir}]]
+ set yo [yc [expr {$row + 0.5}]]
+ lappend coords $xn $yo $xn $yn
+ }
+ } else {
+ lappend coords $xn $yn
+ }
+ }
+ if {!$joinhigh} {
+ if {$arrowhigh} {
+ set coords [adjarrowhigh $coords]
+ }
+ assigncolor $id
+ set t [$canv create line $coords -width [linewidth $id] \
+ -fill $colormap($id) -tags lines.$id -arrow $arrow]
+ $canv lower $t
+ bindline $t $id
+ set lines [linsert $lines $i [list $row $le $t]]
+ } else {
+ $canv coords $ith $coords
+ if {$arrow ne $ah} {
+ $canv itemconf $ith -arrow $arrow
+ }
+ lset lines $i 0 $row
+ }
+ } else {
+ set xo [lsearch -exact [lindex $rowidlist [expr {$row - 1}]] $id]
+ set ndir [expr {$xo - $xp}]
+ set clow [$canv coords $itl]
+ if {$dir == $ndir} {
+ set clow [lrange $clow 2 end]
+ }
+ set coords [concat $coords $clow]
+ if {!$joinhigh} {
+ lset lines [expr {$i-1}] 1 $le
+ if {$arrowhigh} {
+ set coords [adjarrowhigh $coords]
}
+ } else {
+ # coalesce two pieces
+ $canv delete $ith
+ set b [lindex $lines [expr {$i-1}] 0]
+ set e [lindex $lines $i 1]
+ set lines [lreplace $lines [expr {$i-1}] $i [list $b $e $itl]]
+ }
+ $canv coords $itl $coords
+ if {$arrow ne $al} {
+ $canv itemconf $itl -arrow $arrow
}
}
- set arrow [expr {2 * ($i > 0) + $downarrow}]
- set arrow [lindex {none first last both} $arrow]
- set t [$canv create line $coords -width [linewidth $id] \
- -fill $colormap($id) -tags lines.$id -arrow $arrow]
- $canv lower $t
- bindline $t $id
+
+ set linesegs($id) $lines
+ return $le
}
-proc drawparentlinks {id row col olds} {
- global rowidlist canv colormap
+proc drawparentlinks {id row} {
+ global rowidlist canv colormap curview parentlist
+ global idpos
+ set rowids [lindex $rowidlist $row]
+ set col [lsearch -exact $rowids $id]
+ if {$col < 0} return
+ set olds [lindex $parentlist $row]
set row2 [expr {$row + 1}]
set x [xc $row $col]
set y [yc $row]
if {$x2 > $rmx} {
set rmx $x2
}
- set ranges [rowranges $p]
- if {$ranges ne {} && $row2 == [lindex $ranges 0]
- && $row2 < [lindex $ranges 1]} {
+ if {[lsearch -exact $rowids $p] < 0} {
# drawlineseg will do this one for us
continue
}
$canv lower $t
bindline $t $p
}
- return $rmx
+ if {$rmx > [lindex $idpos($id) 1]} {
+ lset idpos($id) 1 $rmx
+ redrawtags $id
+ }
}
proc drawlines {id} {
- global colormap canv
- global idrangedrawn
- global children iddrawn commitrow rowidlist curview
+ global canv
- $canv delete lines.$id
- set ranges [rowranges $id]
- set nr [expr {[llength $ranges] / 2}]
- for {set i 0} {$i < $nr} {incr i} {
- if {[info exists idrangedrawn($id,$i)]} {
- drawlineseg $id $i $ranges
- }
- }
- foreach child $children($curview,$id) {
- if {[info exists iddrawn($child)]} {
- set row $commitrow($curview,$child)
- set col [lsearch -exact [lindex $rowidlist $row] $child]
- if {$col >= 0} {
- drawparentlinks $child $row $col [list $id]
- }
- }
- }
+ $canv itemconf lines.$id -width [linewidth $id]
}
-proc drawcmittext {id row col rmx} {
- global linespc canv canv2 canv3 canvy0 fgcolor
- global commitlisted commitinfo rowidlist
+proc drawcmittext {id row col} {
+ global linespc canv canv2 canv3 canvy0 fgcolor curview
+ global commitlisted commitinfo rowidlist parentlist
global rowtextx idpos idtags idheads idotherrefs
global linehtag linentag linedtag
- global mainfont canvxmax boldrows boldnamerows fgcolor
-
- set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
+ global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
+
+ # listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
+ set listed [lindex $commitlisted $row]
+ if {$id eq $nullid} {
+ set ofill red
+ } elseif {$id eq $nullid2} {
+ set ofill green
+ } else {
+ set ofill [expr {$listed != 0? "blue": "white"}]
+ }
set x [xc $row $col]
set y [yc $row]
set orad [expr {$linespc / 3}]
- set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
- [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
- -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ if {$listed <= 1} {
+ set t [$canv create oval [expr {$x - $orad}] [expr {$y - $orad}] \
+ [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
+ -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ } elseif {$listed == 2} {
+ # triangle pointing left for left-side commits
+ set t [$canv create polygon \
+ [expr {$x - $orad}] $y \
+ [expr {$x + $orad - 1}] [expr {$y - $orad}] \
+ [expr {$x + $orad - 1}] [expr {$y + $orad - 1}] \
+ -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ } else {
+ # triangle pointing right for right-side commits
+ set t [$canv create polygon \
+ [expr {$x + $orad - 1}] $y \
+ [expr {$x - $orad}] [expr {$y - $orad}] \
+ [expr {$x - $orad}] [expr {$y + $orad - 1}] \
+ -fill $ofill -outline $fgcolor -width 1 -tags circle]
+ }
$canv raise $t
$canv bind $t <1> {selcanvline {} %x %y}
- set xt [xc $row [llength [lindex $rowidlist $row]]]
- if {$xt < $rmx} {
- set xt $rmx
+ set rmx [llength [lindex $rowidlist $row]]
+ set olds [lindex $parentlist $row]
+ if {$olds ne {}} {
+ set nextids [lindex $rowidlist [expr {$row + 1}]]
+ foreach p $olds {
+ set i [lsearch -exact $nextids $p]
+ if {$i > $rmx} {
+ set rmx $i
+ }
+ }
}
+ set xt [xc $row $rmx]
set rowtextx($row) $xt
set idpos($id) [list $x $xt $y]
if {[info exists idtags($id)] || [info exists idheads($id)]
proc drawcmitrow {row} {
global displayorder rowidlist
- global idrangedrawn iddrawn
+ global iddrawn markingmatches
global commitinfo parentlist numcommits
global filehighlight fhighlights findstring nhighlights
global hlview vhighlights
global highlight_related rhighlights
if {$row >= $numcommits} return
- foreach id [lindex $rowidlist $row] {
- if {$id eq {}} continue
- set i -1
- set ranges [rowranges $id]
- foreach {s e} $ranges {
- incr i
- if {$row < $s} continue
- if {$e eq {}} break
- if {$row <= $e} {
- if {$e < $numcommits && ![info exists idrangedrawn($id,$i)]} {
- drawlineseg $id $i $ranges
- set idrangedrawn($id,$i) 1
- }
- break
- }
- }
- }
set id [lindex $displayorder $row]
if {[info exists hlview] && ![info exists vhighlights($row)]} {
if {$highlight_related ne "None" && ![info exists rhighlights($row)]} {
askrelhighlight $row $id
}
- if {[info exists iddrawn($id)]} return
- set col [lsearch -exact [lindex $rowidlist $row] $id]
- if {$col < 0} {
- puts "oops, row $row id $id not in list"
- return
+ if {![info exists iddrawn($id)]} {
+ set col [lsearch -exact [lindex $rowidlist $row] $id]
+ if {$col < 0} {
+ puts "oops, row $row id $id not in list"
+ return
+ }
+ if {![info exists commitinfo($id)]} {
+ getcommit $id
+ }
+ assigncolor $id
+ drawcmittext $id $row $col
+ set iddrawn($id) 1
}
- if {![info exists commitinfo($id)]} {
- getcommit $id
+ if {$markingmatches} {
+ markrowmatches $row $id
}
- assigncolor $id
- set olds [lindex $parentlist $row]
- if {$olds ne {}} {
- set rmx [drawparentlinks $id $row $col $olds]
- } else {
- set rmx 0
+}
+
+proc drawcommits {row {endrow {}}} {
+ global numcommits iddrawn displayorder curview
+ global parentlist rowidlist
+
+ if {$row < 0} {
+ set row 0
+ }
+ if {$endrow eq {}} {
+ set endrow $row
+ }
+ if {$endrow >= $numcommits} {
+ set endrow [expr {$numcommits - 1}]
+ }
+
+ # make the lines join to already-drawn rows either side
+ set r [expr {$row - 1}]
+ if {$r < 0 || ![info exists iddrawn([lindex $displayorder $r])]} {
+ set r $row
+ }
+ set er [expr {$endrow + 1}]
+ if {$er >= $numcommits ||
+ ![info exists iddrawn([lindex $displayorder $er])]} {
+ set er $endrow
+ }
+ for {} {$r <= $er} {incr r} {
+ set id [lindex $displayorder $r]
+ set wasdrawn [info exists iddrawn($id)]
+ drawcmitrow $r
+ if {$r == $er} break
+ set nextid [lindex $displayorder [expr {$r + 1}]]
+ if {$wasdrawn && [info exists iddrawn($nextid)]} continue
+ drawparentlinks $id $r
+
+ set rowids [lindex $rowidlist $r]
+ foreach lid $rowids {
+ if {$lid eq {}} continue
+ if {[info exists lineend($lid)] && $lineend($lid) > $r} continue
+ if {$lid eq $id} {
+ # see if this is the first child of any of its parents
+ foreach p [lindex $parentlist $r] {
+ if {[lsearch -exact $rowids $p] < 0} {
+ # make this line extend up to the child
+ set lineend($p) [drawlineseg $p $r $er 0]
+ }
+ }
+ } else {
+ set lineend($lid) [drawlineseg $lid $r $er 1]
+ }
+ }
}
- drawcmittext $id $row $col $rmx
- set iddrawn($id) 1
}
proc drawfrac {f0 f1} {
- global numcommits canv
- global linespc
+ global canv linespc
set ymax [lindex [$canv cget -scrollregion] 3]
if {$ymax eq {} || $ymax == 0} return
set y0 [expr {int($f0 * $ymax)}]
set row [expr {int(($y0 - 3) / $linespc) - 1}]
- if {$row < 0} {
- set row 0
- }
set y1 [expr {int($f1 * $ymax)}]
set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
- if {$endrow >= $numcommits} {
- set endrow [expr {$numcommits - 1}]
- }
- for {} {$row <= $endrow} {incr row} {
- drawcmitrow $row
- }
+ drawcommits $row $endrow
}
proc drawvisible {} {
}
proc clear_display {} {
- global iddrawn idrangedrawn
+ global iddrawn linesegs
global vhighlights fhighlights nhighlights rhighlights
allcanvs delete all
catch {unset iddrawn}
- catch {unset idrangedrawn}
+ catch {unset linesegs}
catch {unset vhighlights}
catch {unset fhighlights}
catch {unset nhighlights}
# The new commit will be displayed on row $row and the commits
# on that row and below will move down one row.
proc insertrow {row newcmit} {
- global displayorder parentlist childlist commitlisted
+ global displayorder parentlist commitlisted children
global commitrow curview rowidlist rowoffsets numcommits
global rowrangelist rowlaidout rowoptim numcommits
- global linesegends selectedline
+ global selectedline rowchk commitidx
if {$row >= $numcommits} {
puts "oops, inserting new row $row but only have $numcommits rows"
set p [lindex $displayorder $row]
set displayorder [linsert $displayorder $row $newcmit]
set parentlist [linsert $parentlist $row $p]
- set kids [lindex $childlist $row]
+ set kids $children($curview,$p)
lappend kids $newcmit
- lset childlist $row $kids
- set childlist [linsert $childlist $row {}]
+ set children($curview,$p) $kids
+ set children($curview,$newcmit) {}
set commitlisted [linsert $commitlisted $row 1]
set l [llength $displayorder]
for {set r $row} {$r < $l} {incr r} {
set id [lindex $displayorder $r]
set commitrow($curview,$id) $r
}
+ incr commitidx($curview)
set idlist [lindex $rowidlist $row]
set offs [lindex $rowoffsets $row]
lset rowrangelist $rp1 $ranges
}
- set linesegends [linsert $linesegends $row {}]
+ catch {unset rowchk}
incr rowlaidout
incr rowoptim
redisplay
}
+# Remove a commit that was inserted with insertrow on row $row.
+proc removerow {row} {
+ global displayorder parentlist commitlisted children
+ global commitrow curview rowidlist rowoffsets numcommits
+ global rowrangelist idrowranges rowlaidout rowoptim numcommits
+ global linesegends selectedline rowchk commitidx
+
+ if {$row >= $numcommits} {
+ puts "oops, removing row $row but only have $numcommits rows"
+ return
+ }
+ set rp1 [expr {$row + 1}]
+ set id [lindex $displayorder $row]
+ set p [lindex $parentlist $row]
+ set displayorder [lreplace $displayorder $row $row]
+ set parentlist [lreplace $parentlist $row $row]
+ set commitlisted [lreplace $commitlisted $row $row]
+ set kids $children($curview,$p)
+ set i [lsearch -exact $kids $id]
+ if {$i >= 0} {
+ set kids [lreplace $kids $i $i]
+ set children($curview,$p) $kids
+ }
+ set l [llength $displayorder]
+ for {set r $row} {$r < $l} {incr r} {
+ set id [lindex $displayorder $r]
+ set commitrow($curview,$id) $r
+ }
+ incr commitidx($curview) -1
+
+ set rowidlist [lreplace $rowidlist $row $row]
+ set rowoffsets [lreplace $rowoffsets $rp1 $rp1]
+ if {$kids ne {}} {
+ set offs [lindex $rowoffsets $row]
+ set offs [lreplace $offs end end]
+ lset rowoffsets $row $offs
+ }
+
+ set rowrangelist [lreplace $rowrangelist $row $row]
+ if {[llength $kids] > 0} {
+ set ranges [lindex $rowrangelist $row]
+ if {[lindex $ranges end-1] eq $id} {
+ set ranges [lreplace $ranges end-1 end]
+ lset rowrangelist $row $ranges
+ }
+ }
+
+ catch {unset rowchk}
+
+ incr rowlaidout -1
+ incr rowoptim -1
+ incr numcommits -1
+
+ if {[info exists selectedline] && $selectedline > $row} {
+ incr selectedline -1
+ }
+ redisplay
+}
+
# Don't change the text pane cursor if it is currently the hand cursor,
# showing that we are over a sha1 ID link.
proc settextcursor {c} {
}
proc findmatches {f} {
- global findtype foundstring foundstrlen
+ global findtype findstring
if {$findtype == "Regexp"} {
- set matches [regexp -indices -all -inline $foundstring $f]
+ set matches [regexp -indices -all -inline $findstring $f]
} else {
+ set fs $findstring
if {$findtype == "IgnCase"} {
- set str [string tolower $f]
+ set f [string tolower $f]
+ set fs [string tolower $fs]
+ }
+ set matches {}
+ set i 0
+ set l [string length $fs]
+ while {[set j [string first $fs $f $i]] >= 0} {
+ lappend matches [list $j [expr {$j+$l-1}]]
+ set i [expr {$j + $l}]
+ }
+ }
+ return $matches
+}
+
+proc dofind {{rev 0}} {
+ global findstring findstartline findcurline selectedline numcommits
+
+ unmarkmatches
+ cancel_next_highlight
+ focus .
+ if {$findstring eq {} || $numcommits == 0} return
+ if {![info exists selectedline]} {
+ set findstartline [lindex [visiblerows] $rev]
+ } else {
+ set findstartline $selectedline
+ }
+ set findcurline $findstartline
+ nowbusy finding
+ if {!$rev} {
+ run findmore
+ } else {
+ if {$findcurline == 0} {
+ set findcurline $numcommits
+ }
+ incr findcurline -1
+ run findmorerev
+ }
+}
+
+proc findnext {restart} {
+ global findcurline
+ if {![info exists findcurline]} {
+ if {$restart} {
+ dofind
} else {
- set str $f
+ bell
+ }
+ } else {
+ run findmore
+ nowbusy finding
+ }
+}
+
+proc findprev {} {
+ global findcurline
+ if {![info exists findcurline]} {
+ dofind 1
+ } else {
+ run findmorerev
+ nowbusy finding
+ }
+}
+
+proc findmore {} {
+ global commitdata commitinfo numcommits findstring findpattern findloc
+ global findstartline findcurline displayorder
+
+ set fldtypes {Headline Author Date Committer CDate Comments}
+ set l [expr {$findcurline + 1}]
+ if {$l >= $numcommits} {
+ set l 0
+ }
+ if {$l <= $findstartline} {
+ set lim [expr {$findstartline + 1}]
+ } else {
+ set lim $numcommits
+ }
+ if {$lim - $l > 500} {
+ set lim [expr {$l + 500}]
+ }
+ set last 0
+ for {} {$l < $lim} {incr l} {
+ set id [lindex $displayorder $l]
+ # shouldn't happen unless git log doesn't give all the commits...
+ if {![info exists commitdata($id)]} continue
+ if {![doesmatch $commitdata($id)]} continue
+ if {![info exists commitinfo($id)]} {
+ getcommit $id
}
- set matches {}
- set i 0
- while {[set j [string first $foundstring $str $i]] >= 0} {
- lappend matches [list $j [expr {$j+$foundstrlen-1}]]
- set i [expr {$j + $foundstrlen}]
+ set info $commitinfo($id)
+ foreach f $info ty $fldtypes {
+ if {($findloc eq "All fields" || $findloc eq $ty) &&
+ [doesmatch $f]} {
+ findselectline $l
+ notbusy finding
+ return 0
+ }
}
}
- return $matches
+ if {$l == $findstartline + 1} {
+ bell
+ unset findcurline
+ notbusy finding
+ return 0
+ }
+ set findcurline [expr {$l - 1}]
+ return 1
}
-proc dofind {} {
- global findtype findloc findstring markedmatches commitinfo
- global numcommits displayorder linehtag linentag linedtag
- global mainfont canv canv2 canv3 selectedline
- global matchinglines foundstring foundstrlen matchstring
- global commitdata
+proc findmorerev {} {
+ global commitdata commitinfo numcommits findstring findpattern findloc
+ global findstartline findcurline displayorder
- stopfindproc
- unmarkmatches
- cancel_next_highlight
- focus .
- set matchinglines {}
- if {$findtype == "IgnCase"} {
- set foundstring [string tolower $findstring]
- } else {
- set foundstring $findstring
+ set fldtypes {Headline Author Date Committer CDate Comments}
+ set l $findcurline
+ if {$l == 0} {
+ set l $numcommits
}
- set foundstrlen [string length $findstring]
- if {$foundstrlen == 0} return
- regsub -all {[*?\[\\]} $foundstring {\\&} matchstring
- set matchstring "*$matchstring*"
- if {![info exists selectedline]} {
- set oldsel -1
+ incr l -1
+ if {$l >= $findstartline} {
+ set lim [expr {$findstartline - 1}]
} else {
- set oldsel $selectedline
+ set lim -1
}
- set didsel 0
- set fldtypes {Headline Author Date Committer CDate Comments}
- set l -1
- foreach id $displayorder {
- set d $commitdata($id)
- incr l
- if {$findtype == "Regexp"} {
- set doesmatch [regexp $foundstring $d]
- } elseif {$findtype == "IgnCase"} {
- set doesmatch [string match -nocase $matchstring $d]
- } else {
- set doesmatch [string match $matchstring $d]
- }
- if {!$doesmatch} continue
+ if {$l - $lim > 500} {
+ set lim [expr {$l - 500}]
+ }
+ set last 0
+ for {} {$l > $lim} {incr l -1} {
+ set id [lindex $displayorder $l]
+ if {![doesmatch $commitdata($id)]} continue
if {![info exists commitinfo($id)]} {
getcommit $id
}
set info $commitinfo($id)
- set doesmatch 0
foreach f $info ty $fldtypes {
- if {$findloc != "All fields" && $findloc != $ty} {
- continue
- }
- set matches [findmatches $f]
- if {$matches == {}} continue
- set doesmatch 1
- if {$ty == "Headline"} {
- drawcmitrow $l
- markmatches $canv $l $f $linehtag($l) $matches $mainfont
- } elseif {$ty == "Author"} {
- drawcmitrow $l
- markmatches $canv2 $l $f $linentag($l) $matches $mainfont
- } elseif {$ty == "Date"} {
- drawcmitrow $l
- markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
- }
- }
- if {$doesmatch} {
- lappend matchinglines $l
- if {!$didsel && $l > $oldsel} {
+ if {($findloc eq "All fields" || $findloc eq $ty) &&
+ [doesmatch $f]} {
findselectline $l
- set didsel 1
+ notbusy finding
+ return 0
}
}
}
- if {$matchinglines == {}} {
+ if {$l == -1} {
bell
- } elseif {!$didsel} {
- findselectline [lindex $matchinglines 0]
+ unset findcurline
+ notbusy finding
+ return 0
}
+ set findcurline [expr {$l + 1}]
+ return 1
}
proc findselectline {l} {
- global findloc commentend ctext
+ global findloc commentend ctext findcurline markingmatches
+
+ set markingmatches 1
+ set findcurline $l
selectline $l 1
if {$findloc == "All fields" || $findloc == "Comments"} {
# highlight the matches in the comments
$ctext tag add found "1.0 + $start c" "1.0 + $end c"
}
}
+ drawvisible
}
-proc findnext {restart} {
- global matchinglines selectedline
- if {![info exists matchinglines]} {
- if {$restart} {
- dofind
- }
- return
- }
- if {![info exists selectedline]} return
- foreach l $matchinglines {
- if {$l > $selectedline} {
- findselectline $l
- return
- }
- }
- bell
-}
-
-proc findprev {} {
- global matchinglines selectedline
- if {![info exists matchinglines]} {
- dofind
- return
- }
- if {![info exists selectedline]} return
- set prev {}
- foreach l $matchinglines {
- if {$l >= $selectedline} break
- set prev $l
- }
- if {$prev != {}} {
- findselectline $prev
- } else {
- bell
- }
-}
-
-proc stopfindproc {{done 0}} {
- global findprocpid findprocfile findids
- global ctext findoldcursor phase maincursor textcursor
- global findinprogress
-
- catch {unset findids}
- if {[info exists findprocpid]} {
- if {!$done} {
- catch {exec kill $findprocpid}
- }
- catch {close $findprocfile}
- unset findprocpid
- }
- catch {unset findinprogress}
- notbusy find
-}
-
-# mark a commit as matching by putting a yellow background
-# behind the headline
-proc markheadline {l id} {
- global canv mainfont linehtag
-
- drawcmitrow $l
- set bbox [$canv bbox $linehtag($l)]
- set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
- $canv lower $t
-}
+# mark the bits of a headline or author that match a find string
+proc markmatches {canv l str tag matches font row} {
+ global selectedline
-# mark the bits of a headline, author or date that match a find string
-proc markmatches {canv l str tag matches font} {
set bbox [$canv bbox $tag]
set x0 [lindex $bbox 0]
set y0 [lindex $bbox 1]
set xlen [font measure $font [string range $str 0 [expr {$end}]]]
set t [$canv create rect [expr {$x0+$xoff}] $y0 \
[expr {$x0+$xlen+2}] $y1 \
- -outline {} -tags matches -fill yellow]
+ -outline {} -tags [list match$l matches] -fill yellow]
$canv lower $t
+ if {[info exists selectedline] && $row == $selectedline} {
+ $canv raise $t secsel
+ }
}
}
proc unmarkmatches {} {
- global matchinglines findids
+ global findids markingmatches findcurline
+
allcanvs delete matches
- catch {unset matchinglines}
catch {unset findids}
+ set markingmatches 0
+ catch {unset findcurline}
}
proc selcanvline {w x y} {
proc selectline {l isnew} {
global canv canv2 canv3 ctext commitinfo selectedline
global displayorder linehtag linentag linedtag
- global canvy0 linespc parentlist childlist
+ global canvy0 linespc parentlist children curview
global currentid sha1entry
global commentend idtags linknum
global mergemax numcommits pending_select
$canv delete hover
normalline
cancel_next_highlight
+ unsel_reflist
if {$l < 0 || $l >= $numcommits} return
set y [expr {$canvy0 + $l * $linespc}]
set ymax [lindex [$canv cget -scrollregion] 3]
}
}
- foreach c [lindex $childlist $l] {
+ foreach c $children($curview,$id) {
append headers "Child: [commit_descriptor $c]"
}
}
appendwithlinks $comment {comment}
- $ctext tag delete Comments
$ctext tag remove found 1.0 end
$ctext conf -state disabled
set commentend [$ctext index "end - 1c"]
proc selnextline {dir} {
global selectedline
+ focus .
if {![info exists selectedline]} return
set l [expr {$selectedline + $dir}]
unmarkmatches
proc goback {} {
global history historyindex
+ focus .
if {$historyindex > 1} {
incr historyindex -1
proc goforw {} {
global history historyindex
+ focus .
if {$historyindex < [llength $history]} {
set cmd [lindex $history $historyindex]
proc gettree {id} {
global treefilelist treeidlist diffids diffmergeid treepending
+ global nullid nullid2
set diffids $id
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 {$id eq $nullid} {
+ set cmd [list | git ls-files]
+ } elseif {$id eq $nullid2} {
+ set cmd [list | git ls-files --stage -t]
+ } else {
+ set cmd [list | git ls-tree -r $id]
+ }
+ if {[catch {set gtf [open $cmd r]}]} {
return
}
set treepending $id
}
proc gettreeline {gtf id} {
- global treefilelist treeidlist treepending cmitmode diffids
+ global treefilelist treeidlist treepending cmitmode diffids nullid nullid2
set nl 0
while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
- set tl [split $line "\t"]
- if {[lindex $tl 0 1] ne "blob"} continue
- set sha1 [lindex $tl 0 2]
- set fname [lindex $tl 1]
- if {[string index $fname 0] eq "\""} {
- set fname [lindex $fname 0]
- }
- lappend treeidlist($id) $sha1
+ if {$diffids eq $nullid} {
+ set fname $line
+ } else {
+ if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
+ set i [string first "\t" $line]
+ if {$i < 0} continue
+ set sha1 [lindex $line 2]
+ set fname [string range $line [expr {$i+1}] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ lappend treeidlist($id) $sha1
+ }
lappend treefilelist($id) $fname
}
if {![eof $gtf]} {
}
proc showfile {f} {
- global treefilelist treeidlist diffids
+ global treefilelist treeidlist diffids nullid nullid2
global ctext commentend
set i [lsearch -exact $treefilelist($diffids) $f]
puts "oops, $f not in list for id $diffids"
return
}
- set blob [lindex $treeidlist($diffids) $i]
- if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
- puts "oops, error reading blob $blob: $err"
- return
+ if {$diffids eq $nullid} {
+ if {[catch {set bf [open $f r]} err]} {
+ puts "oops, can't read $f: $err"
+ return
+ }
+ } else {
+ set blob [lindex $treeidlist($diffids) $i]
+ if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
+ puts "oops, error reading blob $blob: $err"
+ return
+ }
}
fconfigure $bf -blocking 0
filerun $bf [list getblobline $bf $diffids]
}
proc startdiff {ids} {
- global treediffs diffids treepending diffmergeid
+ global treediffs diffids treepending diffmergeid nullid nullid2
set diffids $ids
catch {unset diffmergeid}
- if {![info exists treediffs($ids)]} {
+ if {![info exists treediffs($ids)] ||
+ [lsearch -exact $ids $nullid] >= 0 ||
+ [lsearch -exact $ids $nullid2] >= 0} {
if {![info exists treepending]} {
gettreediffs $ids
}
getblobdiffs $ids
}
+proc diffcmd {ids flags} {
+ global nullid nullid2
+
+ set i [lsearch -exact $ids $nullid]
+ set j [lsearch -exact $ids $nullid2]
+ if {$i >= 0} {
+ if {[llength $ids] > 1 && $j < 0} {
+ # comparing working directory with some specific revision
+ set cmd [concat | git diff-index $flags]
+ if {$i == 0} {
+ lappend cmd -R [lindex $ids 1]
+ } else {
+ lappend cmd [lindex $ids 0]
+ }
+ } else {
+ # comparing working directory with index
+ set cmd [concat | git diff-files $flags]
+ if {$j == 1} {
+ lappend cmd -R
+ }
+ }
+ } elseif {$j >= 0} {
+ set cmd [concat | git diff-index --cached $flags]
+ if {[llength $ids] > 1} {
+ # comparing index with specific revision
+ if {$i == 0} {
+ lappend cmd -R [lindex $ids 1]
+ } else {
+ lappend cmd [lindex $ids 0]
+ }
+ } else {
+ # comparing index with HEAD
+ lappend cmd HEAD
+ }
+ } else {
+ set cmd [concat | git diff-tree -r $flags $ids]
+ }
+ return $cmd
+}
+
proc gettreediffs {ids} {
global treediff treepending
+
set treepending $ids
set treediff {}
- if {[catch \
- {set gdtf [open [concat | git diff-tree --no-commit-id -r $ids] r]} \
- ]} return
+ if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
fconfigure $gdtf -blocking 0
filerun $gdtf [list gettreediffline $gdtf $ids]
}
set nr 0
while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
- set file [lindex $line 5]
- lappend treediff $file
+ set i [string first "\t" $line]
+ if {$i >= 0} {
+ set file [string range $line [expr {$i+1}] end]
+ if {[string index $file 0] eq "\""} {
+ set file [lindex $file 0]
+ }
+ lappend treediff $file
+ }
}
if {![eof $gdtf]} {
return [expr {$nr >= 1000? 2: 1}]
return 0
}
+# empty string or positive integer
+proc diffcontextvalidate {v} {
+ return [regexp {^(|[1-9][0-9]*)$} $v]
+}
+
+proc diffcontextchange {n1 n2 op} {
+ global diffcontextstring diffcontext
+
+ if {[string is integer -strict $diffcontextstring]} {
+ if {$diffcontextstring > 0} {
+ set diffcontext $diffcontextstring
+ reselectline
+ }
+ }
+}
+
proc getblobdiffs {ids} {
- global diffopts blobdifffd diffids env curdifftag curtagstart
+ global diffopts blobdifffd diffids env
global diffinhdr treediffs
+ global diffcontext
set env(GIT_DIFF_OPTS) $diffopts
- set cmd [concat | git diff-tree --no-commit-id -r -p -C $ids]
- if {[catch {set bdf [open $cmd r]} err]} {
+ if {[catch {set bdf [open [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"] r]} err]} {
puts "error getting diffs: $err"
return
}
set diffinhdr 0
fconfigure $bdf -blocking 0
set blobdifffd($ids) $bdf
- set curdifftag Comments
- set curtagstart 0.0
filerun $bdf [list getblobdiffline $bdf $diffids]
}
}
}
+proc makediffhdr {fname ids} {
+ global ctext curdiffstart treediffs
+
+ set i [lsearch -exact $treediffs($ids) $fname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $curdiffstart
+ }
+ set l [expr {(78 - [string length $fname]) / 2}]
+ set pad [string range "----------------------------------------" 1 $l]
+ $ctext insert $curdiffstart "$pad $fname $pad" filesep
+}
+
proc getblobdiffline {bdf ids} {
- global diffids blobdifffd ctext curdifftag curtagstart
+ global diffids blobdifffd ctext curdiffstart
global diffnexthead diffnextnote difffilestart
global diffinhdr treediffs
close $bdf
return 0
}
- if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
+ if {![string compare -length 11 "diff --git " $line]} {
+ # trim off "diff --git "
+ set line [string range $line 11 end]
+ set diffinhdr 1
# start of a new file
$ctext insert end "\n"
- $ctext tag add $curdifftag $curtagstart end
- set here [$ctext index "end - 1c"]
- set curtagstart $here
- set header $newname
- 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 curdiffstart [$ctext index "end - 1c"]
+ $ctext insert end "\n" filesep
+ # If the name hasn't changed the length will be odd,
+ # the middle char will be a space, and the two bits either
+ # side will be a/name and b/name, or "a/name" and "b/name".
+ # If the name has changed we'll get "rename from" and
+ # "rename to" or "copy from" and "copy to" lines following this,
+ # and we'll use them to get the filenames.
+ # This complexity is necessary because spaces in the filename(s)
+ # don't get escaped.
+ set l [string length $line]
+ set i [expr {$l / 2}]
+ if {!(($l & 1) && [string index $line $i] eq " " &&
+ [string range $line 2 [expr {$i - 1}]] eq \
+ [string range $line [expr {$i + 3}] end])} {
+ continue
}
- set curdifftag "f:$fname"
- $ctext tag delete $curdifftag
- set l [expr {(78 - [string length $header]) / 2}]
- set pad [string range "----------------------------------------" \
- 1 $l]
- $ctext insert end "$pad $header $pad\n" filesep
- set diffinhdr 1
- } elseif {$diffinhdr && [string compare -length 3 $line "---"] == 0} {
- # do nothing
- } elseif {$diffinhdr && [string compare -length 3 $line "+++"] == 0} {
- set diffinhdr 0
- } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
+ # unescape if quoted and chop off the a/ from the front
+ if {[string index $line 0] eq "\""} {
+ set fname [string range [lindex $line 0] 2 end]
+ } else {
+ set fname [string range $line 2 [expr {$i - 1}]]
+ }
+ makediffhdr $fname $ids
+
+ } elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \
$line match f1l f1c f2l f2c rest]} {
$ctext insert end "$line\n" hunksep
set diffinhdr 0
+
+ } elseif {$diffinhdr} {
+ if {![string compare -length 12 "rename from " $line]} {
+ set fname [string range $line [expr 6 + [string first " from " $line] ] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ set i [lsearch -exact $treediffs($ids) $fname]
+ if {$i >= 0} {
+ setinlist difffilestart $i $curdiffstart
+ }
+ } elseif {![string compare -length 10 $line "rename to "] ||
+ ![string compare -length 8 $line "copy to "]} {
+ set fname [string range $line [expr 4 + [string first " to " $line] ] end]
+ if {[string index $fname 0] eq "\""} {
+ set fname [lindex $fname 0]
+ }
+ makediffhdr $fname $ids
+ } elseif {[string compare -length 3 $line "---"] == 0} {
+ # do nothing
+ continue
+ } elseif {[string compare -length 3 $line "+++"] == 0} {
+ set diffinhdr 0
+ continue
+ }
+ $ctext insert end "$line\n" filesep
+
} else {
set x [string range $line 0 0]
if {$x == "-" || $x == "+"} {
$ctext insert end "$line\n" d$tag
} elseif {$x == " "} {
$ctext insert end "$line\n"
- } elseif {$diffinhdr || $x == "\\"} {
- # e.g. "\ No newline at end of file"
- $ctext insert end "$line\n" filesep
} else {
- # Something else we don't recognize
- if {$curdifftag != "Comments"} {
- $ctext insert end "\n"
- $ctext tag add $curdifftag $curtagstart end
- set curtagstart [$ctext index "end - 1c"]
- set curdifftag Comments
- }
- $ctext insert end "$line\n" filesep
+ # "\ No newline at end of file",
+ # or something else we don't recognize
+ $ctext insert end "$line\n" hunksep
}
}
}
$ctext conf -state disabled
if {[eof $bdf]} {
close $bdf
- if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
- $ctext tag add $curdifftag $curtagstart end
- }
return 0
}
return [expr {$nr >= 1000? 2: 1}]
}
proc incrfont {inc} {
- global mainfont textfont ctext canv phase cflist
+ global mainfont textfont ctext canv phase cflist showrefstop
global charspc tabstop
global stopped entries
unmarkmatches
if {$phase eq "getcommits"} {
$canv itemconf textitems -font $mainfont
}
+ if {[info exists showrefstop] && [winfo exists $showrefstop]} {
+ $showrefstop.list conf -font $mainfont
+ }
redisplay
}
proc rowmenu {x y id} {
global rowctxmenu commitrow selectedline rowmenuid curview
+ global nullid nullid2 fakerowmenu mainhead
+ set rowmenuid $id
if {![info exists selectedline]
|| $commitrow($curview,$id) eq $selectedline} {
set state disabled
} else {
set state normal
}
- $rowctxmenu entryconfigure "Diff this*" -state $state
- $rowctxmenu entryconfigure "Diff selected*" -state $state
- $rowctxmenu entryconfigure "Make patch" -state $state
- set rowmenuid $id
- tk_popup $rowctxmenu $x $y
+ if {$id ne $nullid && $id ne $nullid2} {
+ set menu $rowctxmenu
+ $menu entryconfigure 7 -label "Reset $mainhead branch to here"
+ } else {
+ set menu $fakerowmenu
+ }
+ $menu entryconfigure "Diff this*" -state $state
+ $menu entryconfigure "Diff selected*" -state $state
+ $menu entryconfigure "Make patch" -state $state
+ tk_popup $menu $x $y
}
proc diffvssel {dirn} {
$ctext insert end [lindex $commitinfo($newid) 0]
$ctext insert end "\n"
$ctext conf -state disabled
- $ctext tag delete Comments
$ctext tag remove found 1.0 end
startdiff [list $oldid $newid]
}
}
proc mkpatchgo {} {
- global patchtop
+ global patchtop nullid nullid2
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]} {
+ set cmd [diffcmd [list $oldid $newid] -p]
+ lappend cmd >$fname &
+ if {[catch {eval exec $cmd} err]} {
error_popup "Error creating patch: $err"
}
catch {destroy $patchtop}
lappend idtags($id) $tag
redrawtags $id
addedtag $id
+ dispneartags 0
+ run refill_reflist
}
proc redrawtags {id} {
global canv linehtag commitrow idpos selectedline curview
- global mainfont canvxmax
+ global mainfont canvxmax iddrawn
if {![info exists commitrow($curview,$id)]} return
- drawcmitrow $commitrow($curview,$id)
+ if {![info exists iddrawn($id)]} return
+ drawcommits $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]
notbusy newbranch
redrawtags $id
dispneartags 0
+ run refill_reflist
}
}
notbusy cherrypick
}
+proc resethead {} {
+ global mainheadid mainhead rowmenuid confirm_ok resettype
+ global showlocalchanges
+
+ set confirm_ok 0
+ set w ".confirmreset"
+ toplevel $w
+ wm transient $w .
+ wm title $w "Confirm reset"
+ message $w.m -text \
+ "Reset branch $mainhead to [string range $rowmenuid 0 7]?" \
+ -justify center -aspect 1000
+ pack $w.m -side top -fill x -padx 20 -pady 20
+ frame $w.f -relief sunken -border 2
+ message $w.f.rt -text "Reset type:" -aspect 1000
+ grid $w.f.rt -sticky w
+ set resettype mixed
+ radiobutton $w.f.soft -value soft -variable resettype -justify left \
+ -text "Soft: Leave working tree and index untouched"
+ grid $w.f.soft -sticky w
+ radiobutton $w.f.mixed -value mixed -variable resettype -justify left \
+ -text "Mixed: Leave working tree untouched, reset index"
+ grid $w.f.mixed -sticky w
+ radiobutton $w.f.hard -value hard -variable resettype -justify left \
+ -text "Hard: Reset working tree and index\n(discard ALL local changes)"
+ grid $w.f.hard -sticky w
+ pack $w.f -side top -fill x
+ button $w.ok -text OK -command "set confirm_ok 1; destroy $w"
+ pack $w.ok -side left -fill x -padx 20 -pady 20
+ button $w.cancel -text Cancel -command "destroy $w"
+ pack $w.cancel -side right -fill x -padx 20 -pady 20
+ bind $w <Visibility> "grab $w; focus $w"
+ tkwait window $w
+ if {!$confirm_ok} return
+ if {[catch {set fd [open \
+ [list | sh -c "git reset --$resettype $rowmenuid 2>&1"] r]} err]} {
+ error_popup $err
+ } else {
+ dohidelocalchanges
+ set w ".resetprogress"
+ filerun $fd [list readresetstat $fd $w]
+ toplevel $w
+ wm transient $w
+ wm title $w "Reset progress"
+ message $w.m -text "Reset in progress, please wait..." \
+ -justify center -aspect 1000
+ pack $w.m -side top -fill x -padx 20 -pady 5
+ canvas $w.c -width 150 -height 20 -bg white
+ $w.c create rect 0 0 0 20 -fill green -tags rect
+ pack $w.c -side top -fill x -padx 20 -pady 5 -expand 1
+ nowbusy reset
+ }
+}
+
+proc readresetstat {fd w} {
+ global mainhead mainheadid showlocalchanges
+
+ if {[gets $fd line] >= 0} {
+ if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
+ set x [expr {($m * 150) / $n}]
+ $w.c coords rect 0 0 $x 20
+ }
+ return 1
+ }
+ destroy $w
+ notbusy reset
+ if {[catch {close $fd} err]} {
+ error_popup $err
+ }
+ set oldhead $mainheadid
+ set newhead [exec git rev-parse HEAD]
+ if {$newhead ne $oldhead} {
+ movehead $newhead $mainhead
+ movedhead $newhead $mainhead
+ set mainheadid $newhead
+ redrawtags $oldhead
+ redrawtags $newhead
+ }
+ if {$showlocalchanges} {
+ doshowlocalchanges
+ }
+ return 0
+}
+
# context menu for a head
proc headmenu {x y id head} {
global headmenuid headmenuhead headctxmenu mainhead
proc cobranch {} {
global headmenuid headmenuhead mainhead headids
+ global showlocalchanges mainheadid
# check the tree is clean first??
set oldmainhead $mainhead
nowbusy checkout
update
+ dohidelocalchanges
if {[catch {
exec git checkout -q $headmenuhead
} err]} {
} else {
notbusy checkout
set mainhead $headmenuhead
+ set mainheadid $headmenuid
if {[info exists headids($oldmainhead)]} {
redrawtags $headids($oldmainhead)
}
redrawtags $headmenuid
}
+ if {$showlocalchanges} {
+ dodiffindex
+ }
}
proc rmbranch {} {
global headmenuid headmenuhead mainhead
- global headids idheads
+ global idheads
set head $headmenuhead
set id $headmenuid
return
}
set dheads [descheads $id]
- if {$dheads eq $headids($head)} {
+ if {[llength $dheads] == 1 && $idheads($dheads) eq $head} {
# the stuff on this branch isn't on any other branch
if {![confirm_popup "The commits on branch $head aren't on any other\
branch.\nReally delete branch $head?"]} return
redrawtags $id
notbusy rmbranch
dispneartags 0
+ run refill_reflist
+}
+
+# Display a list of tags and heads
+proc showrefs {} {
+ global showrefstop bgcolor fgcolor selectbgcolor mainfont
+ global bglist fglist uifont reflistfilter reflist maincursor
+
+ set top .showrefs
+ set showrefstop $top
+ if {[winfo exists $top]} {
+ raise $top
+ refill_reflist
+ return
+ }
+ toplevel $top
+ wm title $top "Tags and heads: [file tail [pwd]]"
+ text $top.list -background $bgcolor -foreground $fgcolor \
+ -selectbackground $selectbgcolor -font $mainfont \
+ -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
+ -width 30 -height 20 -cursor $maincursor \
+ -spacing1 1 -spacing3 1 -state disabled
+ $top.list tag configure highlight -background $selectbgcolor
+ lappend bglist $top.list
+ lappend fglist $top.list
+ scrollbar $top.ysb -command "$top.list yview" -orient vertical
+ scrollbar $top.xsb -command "$top.list xview" -orient horizontal
+ grid $top.list $top.ysb -sticky nsew
+ grid $top.xsb x -sticky ew
+ frame $top.f
+ label $top.f.l -text "Filter: " -font $uifont
+ entry $top.f.e -width 20 -textvariable reflistfilter -font $uifont
+ set reflistfilter "*"
+ trace add variable reflistfilter write reflistfilter_change
+ pack $top.f.e -side right -fill x -expand 1
+ pack $top.f.l -side left
+ grid $top.f - -sticky ew -pady 2
+ button $top.close -command [list destroy $top] -text "Close" \
+ -font $uifont
+ grid $top.close -
+ grid columnconfigure $top 0 -weight 1
+ grid rowconfigure $top 0 -weight 1
+ bind $top.list <1> {break}
+ bind $top.list <B1-Motion> {break}
+ bind $top.list <ButtonRelease-1> {sel_reflist %W %x %y; break}
+ set reflist {}
+ refill_reflist
+}
+
+proc sel_reflist {w x y} {
+ global showrefstop reflist headids tagids otherrefids
+
+ if {![winfo exists $showrefstop]} return
+ set l [lindex [split [$w index "@$x,$y"] "."] 0]
+ set ref [lindex $reflist [expr {$l-1}]]
+ set n [lindex $ref 0]
+ switch -- [lindex $ref 1] {
+ "H" {selbyid $headids($n)}
+ "T" {selbyid $tagids($n)}
+ "o" {selbyid $otherrefids($n)}
+ }
+ $showrefstop.list tag add highlight $l.0 "$l.0 lineend"
+}
+
+proc unsel_reflist {} {
+ global showrefstop
+
+ if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
+ $showrefstop.list tag remove highlight 0.0 end
+}
+
+proc reflistfilter_change {n1 n2 op} {
+ global reflistfilter
+
+ after cancel refill_reflist
+ after 200 refill_reflist
+}
+
+proc refill_reflist {} {
+ global reflist reflistfilter showrefstop headids tagids otherrefids
+ global commitrow curview commitinterest
+
+ if {![info exists showrefstop] || ![winfo exists $showrefstop]} return
+ set refs {}
+ foreach n [array names headids] {
+ if {[string match $reflistfilter $n]} {
+ if {[info exists commitrow($curview,$headids($n))]} {
+ lappend refs [list $n H]
+ } else {
+ set commitinterest($headids($n)) {run refill_reflist}
+ }
+ }
+ }
+ foreach n [array names tagids] {
+ if {[string match $reflistfilter $n]} {
+ if {[info exists commitrow($curview,$tagids($n))]} {
+ lappend refs [list $n T]
+ } else {
+ set commitinterest($tagids($n)) {run refill_reflist}
+ }
+ }
+ }
+ foreach n [array names otherrefids] {
+ if {[string match $reflistfilter $n]} {
+ if {[info exists commitrow($curview,$otherrefids($n))]} {
+ lappend refs [list $n o]
+ } else {
+ set commitinterest($otherrefids($n)) {run refill_reflist}
+ }
+ }
+ }
+ set refs [lsort -index 0 $refs]
+ if {$refs eq $reflist} return
+
+ # Update the contents of $showrefstop.list according to the
+ # differences between $reflist (old) and $refs (new)
+ $showrefstop.list conf -state normal
+ $showrefstop.list insert end "\n"
+ set i 0
+ set j 0
+ while {$i < [llength $reflist] || $j < [llength $refs]} {
+ if {$i < [llength $reflist]} {
+ if {$j < [llength $refs]} {
+ set cmp [string compare [lindex $reflist $i 0] \
+ [lindex $refs $j 0]]
+ if {$cmp == 0} {
+ set cmp [string compare [lindex $reflist $i 1] \
+ [lindex $refs $j 1]]
+ }
+ } else {
+ set cmp -1
+ }
+ } else {
+ set cmp 1
+ }
+ switch -- $cmp {
+ -1 {
+ $showrefstop.list delete "[expr {$j+1}].0" "[expr {$j+2}].0"
+ incr i
+ }
+ 0 {
+ incr i
+ incr j
+ }
+ 1 {
+ set l [expr {$j + 1}]
+ $showrefstop.list image create $l.0 -align baseline \
+ -image reficon-[lindex $refs $j 1] -padx 2
+ $showrefstop.list insert $l.1 "[lindex $refs $j 0]\n"
+ incr j
+ }
+ }
+ }
+ set reflist $refs
+ # delete last newline
+ $showrefstop.list delete end-2c end-1c
+ $showrefstop.list conf -state disabled
}
# Stuff for finding nearby tags
proc getallcommits {} {
global allcommits allids nbmp nextarc seeds
- set allids {}
- set nbmp 0
- set nextarc 0
- set allcommits 0
- set seeds {}
- regetallcommits
-}
-
-# Called when the graph might have changed
-proc regetallcommits {} {
- global allcommits seeds
+ if {![info exists allcommits]} {
+ set allids {}
+ set nbmp 0
+ set nextarc 0
+ set allcommits 0
+ set seeds {}
+ }
set cmd [concat | git rev-list --all --parents]
foreach id $seeds {
# coming from descendents, and "outgoing" means going towards ancestors.
proc getallclines {fd} {
- global allids allparents allchildren idtags nextarc nbmp
+ global allids allparents allchildren idtags idheads nextarc nbmp
global arcnos arcids arctags arcout arcend arcstart archeads growing
global seeds allcommits
}
set arcout($id) $ao
}
+ if {$nid > 0} {
+ global cached_dheads cached_dtags cached_atags
+ catch {unset cached_dheads}
+ catch {unset cached_dtags}
+ catch {unset cached_atags}
+ }
if {![eof $fd]} {
return [expr {$nid >= 1000? 2: 1}]
}
proc addnewchild {id p} {
global allids allparents allchildren idtags nextarc nbmp
global arcnos arcids arctags arcout arcend arcstart archeads growing
- global seeds
+ global seeds allcommits
+ if {![info exists allcommits] || ![info exists arcnos($p)]} return
lappend allids $id
set allparents($id) [list $p]
set allchildren($id) {}
# Both are on the same arc(s); either both are the same BMP,
# or if one is not a BMP, the other is also not a BMP or is
# the BMP at end of the arc (and it only has 1 incoming arc).
- if {$a eq $b} {
+ # Or both can be BMPs with no incoming arcs.
+ if {$a eq $b || $arcnos($a) eq {}} {
return 0
}
# assert {[llength $arcnos($a)] == 1}
if {![info exists allparents($id)]} {
return {}
}
- set ret {}
+ set aret {}
if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
# part-way along an arc; check it first
set a [lindex $arcnos($id) 0]
foreach t $archeads($a) {
set j [lsearch -exact $arcids($a) $t]
if {$j > $i} break
- lappend $ret $t
+ lappend aret $t
}
}
set id $arcstart($a)
set origid $id
set todo [list $id]
set seen($id) 1
+ set ret {}
for {set i 0} {$i < [llength $todo]} {incr i} {
set id [lindex $todo $i]
if {[info exists cached_dheads($id)]} {
}
foreach a $arcnos($id) {
if {$archeads($a) ne {}} {
- set ret [concat $ret $archeads($a)]
+ validate_archeads $a
+ if {$archeads($a) ne {}} {
+ set ret [concat $ret $archeads($a)]
+ }
}
set d $arcstart($a)
if {![info exists seen($d)]} {
}
set ret [lsort -unique $ret]
set cached_dheads($origid) $ret
+ return [concat $ret $aret]
}
proc addedtag {id} {
redrawtags $id
}
}
+ run refill_reflist
}
proc listrefs {id} {
}
proc showtag {tag isnew} {
- global ctext tagcontents tagids linknum
+ global ctext tagcontents tagids linknum tagobjid
if {$isnew} {
addtohistory [list showtag $tag 0]
$ctext conf -state normal
clear_ctext
set linknum 0
+ if {![info exists tagcontents($tag)]} {
+ catch {
+ set tagcontents($tag) [exec git cat-file tag $tagobjid($tag)]
+ }
+ }
if {[info exists tagcontents($tag)]} {
set text $tagcontents($tag)
} else {
proc doprefs {} {
global maxwidth maxgraphpct diffopts
- global oldprefs prefstop showneartags
+ global oldprefs prefstop showneartags showlocalchanges
global bgcolor fgcolor ctext diffcolors selectbgcolor
global uifont tabstop
raise $top
return
}
- foreach v {maxwidth maxgraphpct diffopts showneartags} {
+ foreach v {maxwidth maxgraphpct diffopts showneartags showlocalchanges} {
set oldprefs($v) [set $v]
}
toplevel $top
-font optionfont
spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
grid x $top.maxpctl $top.maxpct -sticky w
+ frame $top.showlocal
+ label $top.showlocal.l -text "Show local changes" -font optionfont
+ checkbutton $top.showlocal.b -variable showlocalchanges
+ pack $top.showlocal.b $top.showlocal.l -side left
+ grid x $top.showlocal -sticky w
label $top.ddisp -text "Diff display options"
$top.ddisp configure -font $uifont
pack $top.ntag.b $top.ntag.l -side left
grid x $top.ntag -sticky w
label $top.tabstopl -text "tabstop" -font optionfont
- entry $top.tabstop -width 10 -textvariable tabstop
+ spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
grid x $top.tabstopl $top.tabstop -sticky w
label $top.cdisp -text "Colors: press to choose"
grid x $top.hunksepbut $top.hunksep -sticky w
label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
button $top.selbgbut -text "Select bg" -font optionfont \
- -command [list choosecolor selectbgcolor 0 $top.bg background setselbg]
+ -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg]
grid x $top.selbgbut $top.selbgsep -sticky w
frame $top.buts
proc prefscan {} {
global maxwidth maxgraphpct diffopts
- global oldprefs prefstop showneartags
+ global oldprefs prefstop showneartags showlocalchanges
- foreach v {maxwidth maxgraphpct diffopts showneartags} {
+ foreach v {maxwidth maxgraphpct diffopts showneartags showlocalchanges} {
set $v $oldprefs($v)
}
catch {destroy $prefstop}
proc prefsok {} {
global maxwidth maxgraphpct
- global oldprefs prefstop showneartags
+ global oldprefs prefstop showneartags showlocalchanges
global charspc ctext tabstop
catch {destroy $prefstop}
unset prefstop
$ctext configure -tabs "[expr {$tabstop * $charspc}]"
+ if {$showlocalchanges != $oldprefs(showlocalchanges)} {
+ if {$showlocalchanges} {
+ doshowlocalchanges
+ } else {
+ dohidelocalchanges
+ }
+ }
if {$maxwidth != $oldprefs(maxwidth)
|| $maxgraphpct != $oldprefs(maxgraphpct)} {
redisplay
}
proc formatdate {d} {
- return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+ global datetimeformat
+ if {$d ne {}} {
+ set d [clock format $d -format $datetimeformat]
+ }
+ return $d
}
# This list of encoding names and aliases is distilled from
return {}
}
+# First check that Tcl/Tk is recent enough
+if {[catch {package require Tk 8.4} err]} {
+ show_error {} . "Sorry, gitk cannot run with this version of Tcl/Tk.\n\
+ Gitk requires at least Tcl/Tk 8.4."
+ exit 1
+}
+
# defaults...
set datemode 0
set diffopts "-U 5 -p"
set wrapcomment "none"
set showneartags 1
set maxrefs 20
+set maxlinelen 200
+set showlocalchanges 1
+set datetimeformat "%Y-%m-%d %H:%M:%S"
set colors {green red blue magenta darkgrey brown orange}
set bgcolor white
set fgcolor black
set diffcolors {red "#00a000" blue}
+set diffcontext 3
set selectbgcolor gray85
catch {source ~/.gitk}
font create optionfont -family sans-serif -size -12
+# check that we can find a .git directory somewhere...
+if {[catch {set gitdir [gitdir]}]} {
+ show_error {} . "Cannot find a git repository here."
+ exit 1
+}
+if {![file isdirectory $gitdir]} {
+ show_error {} . "Cannot find the git directory \"$gitdir\"."
+ exit 1
+}
+
set revtreeargs {}
+set cmdline_files {}
+set i 0
foreach arg $argv {
- switch -regexp -- $arg {
- "^$" { }
- "^-d" { set datemode 1 }
+ switch -- $arg {
+ "" { }
+ "-d" { set datemode 1 }
+ "--" {
+ set cmdline_files [lrange $argv [expr {$i + 1}] end]
+ break
+ }
default {
lappend revtreeargs $arg
}
}
+ incr i
}
-# check that we can find a .git directory somewhere...
-set gitdir [gitdir]
-if {![file isdirectory $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 {$i >= [llength $argv] && $revtreeargs ne {}} {
+ # no -- on command line, but some arguments (other than -d)
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]
+ # Unfortunately git rev-parse doesn't produce an error when
+ # something is both a revision and a filename. To be consistent
+ # with git log and git rev-list, check revtreeargs for filenames.
+ foreach arg $revtreeargs {
+ if {[file exists $arg]} {
+ show_error {} . "Ambiguous argument '$arg': both revision\
+ and filename"
+ exit 1
+ }
+ }
} err]} {
# unfortunately we get both stdout and stderr in $err,
# so look for "fatal:".
}
}
+set nullid "0000000000000000000000000000000000000000"
+set nullid2 "0000000000000000000000000000000000000001"
+
+
set runq {}
set history {}
set historyindex 0
set boldrows {}
set boldnamerows {}
set diffelide {0 0}
+set markingmatches 0
set optim_delay 16
set stopped 0
set stuffsaved 0
set patchnum 0
+set lookingforhead 0
+set localirow -1
+set localfrow -1
+set lserial 0
setcoords
makewindow
+# wait for the window to become visible
+tkwait visibility .
wm title . "[file tail $argv0]: [file tail [pwd]]"
readrefs