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]
if {$stuff == {}} {
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
}
$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
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 rowchk
global selectedline currentid canv canvy0
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
stopfindproc
if {$curview >= 0} {
set vparentlist($curview) $parentlist
- set vchildlist($curview) $childlist
set vdisporder($curview) $displayorder
set vcmitlisted($curview) $commitlisted
if {$phase ne {}} {
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]
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
}
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 selectfirst
set displayorder {}
set commitlisted {}
set parentlist {}
- set childlist {}
set rowrangelist {}
set nextcolor 0
set rowidlist {{}}
proc showstuff {canshow last} {
global numcommits commitrow pending_select selectedline curview
global lookingforhead mainheadid displayorder nullid selectfirst
+ global lastscrollset
if {$numcommits == 0} {
global phase
allcanvs delete all
}
set r0 $numcommits
+ set prev $numcommits
set numcommits $canshow
- setcanvscroll
+ set t [clock clicks -milliseconds]
+ if {$prev < 100 || $last || $t - $lastscrollset > 500} {
+ set lastscrollset $t
+ setcanvscroll
+ }
set rows [visiblerows]
set r1 [lindex $rows 1]
if {$r1 >= $canshow} {
proc layoutrows {row endrow last} {
global rowidlist rowoffsets displayorder
global uparrowlen downarrowlen maxwidth mingaplen
- global childlist parentlist
+ global children parentlist
global idrowranges
global commitidx curview
global idinlist rowchk rowrangelist
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)
}
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 {} {
# 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 children
+ global displayorder parentlist commitlisted children
global commitrow curview rowidlist rowoffsets numcommits
global rowrangelist rowlaidout rowoptim numcommits
global selectedline rowchk commitidx
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} {
# Remove a commit that was inserted with insertrow on row $row.
proc removerow {row} {
- global displayorder parentlist childlist commitlisted children
+ global displayorder parentlist commitlisted children
global commitrow curview rowidlist rowoffsets numcommits
global rowrangelist idrowranges rowlaidout rowoptim numcommits
global linesegends selectedline rowchk commitidx
set p [lindex $parentlist $row]
set displayorder [lreplace $displayorder $row $row]
set parentlist [lreplace $parentlist $row $row]
- set childlist [lreplace $childlist $row $row]
set commitlisted [lreplace $commitlisted $row $row]
- set kids [lindex $childlist $row]
+ set kids $children($curview,$p)
set i [lsearch -exact $kids $id]
if {$i >= 0} {
set kids [lreplace $kids $i $i]
- lset childlist $row $kids
set children($curview,$p) $kids
}
set l [llength $displayorder]
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
}
}
- 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"]
set nl 0
while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
if {$diffids ne $nullid} {
- 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 {[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]
}
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}]
}
proc getblobdiffs {ids} {
- global diffopts blobdifffd diffids env curdifftag curtagstart
+ global diffopts blobdifffd diffids env
global diffinhdr treediffs
set env(GIT_DIFF_OPTS) $diffopts
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
+ 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" 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
}
- if {$newname ne $fname} {
- set i [lsearch -exact $treediffs($ids) $newname]
- if {$i >= 0} {
- setinlist difffilestart $i $here
- }
+ # 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}]]
}
- 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]+) @@(.*)} \
+ 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 12 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 "]} {
+ set fname [string range $line 10 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 rowmenu {x y id} {
- global rowctxmenu commitrow selectedline rowmenuid curview nullid
- global fakerowmenu
+ global rowctxmenu commitrow selectedline rowmenuid curview
+ global nullid fakerowmenu mainhead
set rowmenuid $id
if {![info exists selectedline]
}
if {$id ne $nullid} {
set menu $rowctxmenu
+ $menu entryconfigure 7 -label "Reset $mainhead branch to here"
} else {
set menu $fakerowmenu
}
$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]
}
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
redrawtags $headids($oldmainhead)
}
redrawtags $headmenuid
- if {$showlocalchanges} {
- dodiffindex
- }
+ }
+ if {$showlocalchanges} {
+ dodiffindex
}
}
# 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}]
}
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} {
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