proc getcommits {rargs} {
global commits commfd phase canv mainfont env
- global startmsecs nextupdate
+ global startmsecs nextupdate ncmupdate
global ctext maincursor textcursor leftover
# check that we can find a .git directory somewhere...
set phase getcommits
set startmsecs [clock clicks -milliseconds]
set nextupdate [expr $startmsecs + 100]
+ set ncmupdate 0
if [catch {
set parse_args [concat --default HEAD $rargs]
set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
exit 1
}
set leftover {}
- fconfigure $commfd -blocking 0 -translation binary
- fileevent $commfd readable "getcommitlines $commfd"
+ fconfigure $commfd -blocking 0 -translation lf
+ fileevent $commfd readable [list getcommitlines $commfd]
$canv delete all
$canv create text 3 3 -anchor nw -text "Reading commits..." \
-font $mainfont -tags textitems
. config -cursor watch
- $ctext config -cursor watch
+ settextcursor watch
}
proc getcommitlines {commfd} {
global commits parents cdate children nchildren
global commitlisted phase commitinfo nextupdate
global stopped redisplaying leftover
+ global numcommits ncmupdate
set stuff [read $commfd]
if {$stuff == {}} {
set commitlisted($id) 1
parsecommit $id $cmit 1
drawcommit $id
- if {[clock clicks -milliseconds] >= $nextupdate} {
+ if {[clock clicks -milliseconds] >= $nextupdate
+ && $numcommits >= $ncmupdate + 100} {
doupdate
+ set ncmupdate $numcommits
}
while {$redisplaying} {
set redisplaying 0
foreach id $commits {
drawcommit $id
if {$stopped} break
- if {[clock clicks -milliseconds] >= $nextupdate} {
+ if {[clock clicks -milliseconds] >= $nextupdate
+ && $numcommits >= $ncmupdate + 100} {
doupdate
+ set ncmupdate $numcommits
}
}
}
incr nextupdate 100
fileevent $commfd readable {}
update
- fileevent $commfd readable "getcommitlines $commfd"
+ fileevent $commfd readable [list getcommitlines $commfd]
}
proc readcommit {id} {
global canv canv2 canv3 linespc charspc ctext cflist textfont
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
- global maincursor textcursor
+ global maincursor textcursor curtextcursor
global rowctxmenu gaudydiff mergemax
menu .bar
entry $sha1entry -width 40 -font $textfont -textvariable sha1string
trace add variable sha1string write sha1change
pack $sha1entry -side left -pady 2
+
+ image create bitmap bm-left -data {
+ #define left_width 16
+ #define left_height 16
+ static unsigned char left_bits[] = {
+ 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
+ 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
+ 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
+ }
+ image create bitmap bm-right -data {
+ #define right_width 16
+ #define right_height 16
+ static unsigned char right_bits[] = {
+ 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
+ 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
+ 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
+ }
+ button .ctop.top.bar.leftbut -image bm-left -command goback \
+ -state disabled -width 26
+ pack .ctop.top.bar.leftbut -side left -fill y
+ button .ctop.top.bar.rightbut -image bm-right -command goforw \
+ -state disabled -width 26
+ pack .ctop.top.bar.rightbut -side left -fill y
+
button .ctop.top.bar.findbut -text "Find" -command dofind
pack .ctop.top.bar.findbut -side left
set findstring {}
set ctext .ctop.cdet.left.ctext
text $ctext -bg white -state disabled -font $textfont \
-width $geometry(ctextw) -height $geometry(ctexth) \
- -yscrollcommand ".ctop.cdet.left.sb set"
+ -yscrollcommand ".ctop.cdet.left.sb set" -wrap none
scrollbar .ctop.cdet.left.sb -command "$ctext yview"
pack .ctop.cdet.left.sb -side right -fill y
pack $ctext -side left -fill both -expand 1
set maincursor [. cget -cursor]
set textcursor [$ctext cget -cursor]
+ set curtextcursor $textcursor
set rowctxmenu .rowctxmenu
menu $rowctxmenu -tearoff 0
$canv bind $t <Enter> "lineenter %x %y $id"
$canv bind $t <Motion> "linemotion %x %y $id"
$canv bind $t <Leave> "lineleave $id"
- $canv bind $t <Button-1> "lineclick %x %y $id"
+ $canv bind $t <Button-1> "lineclick %x %y $id 1"
}
proc drawcommitline {level} {
proc drawcommit {id} {
global phase todo nchildren datemode nextupdate
- global startcommits
+ global startcommits numcommits ncmupdate
if {$phase != "incrdraw"} {
set phase incrdraw
if {![info exists commitlisted($id)]} {
break
}
- if {[clock clicks -milliseconds] >= $nextupdate} {
+ if {[clock clicks -milliseconds] >= $nextupdate
+ && $numcommits >= $ncmupdate} {
doupdate
+ set ncmupdate $numcommits
if {$stopped} break
}
}
drawrest $level [llength $startcommits]
}
. config -cursor $maincursor
- $ctext config -cursor $textcursor
+ settextcursor $textcursor
+}
+
+# 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} {
+ global ctext curtextcursor
+
+ if {[$ctext cget -cursor] == $curtextcursor} {
+ $ctext config -cursor $c
+ }
+ set curtextcursor $c
}
proc drawgraph {} {
- global nextupdate startmsecs startcommits todo
+ global nextupdate startmsecs startcommits todo ncmupdate
if {$startcommits == {}} return
set startmsecs [clock clicks -milliseconds]
set nextupdate [expr $startmsecs + 100]
+ set ncmupdate 0
initgraph
set todo [lindex $startcommits 0]
drawrest 0 1
proc drawrest {level startix} {
global phase stopped redisplaying selectedline
global datemode currentparents todo
- global numcommits
+ global numcommits ncmupdate
global nextupdate startmsecs startcommits idline
if {$level >= 0} {
if {$level < 0} break
drawslants $level
}
- if {[clock clicks -milliseconds] >= $nextupdate} {
+ if {[clock clicks -milliseconds] >= $nextupdate
+ && $numcommits >= $ncmupdate + 100} {
update
incr nextupdate 100
+ set ncmupdate $numcommits
}
}
}
#puts "overall $drawmsecs ms for $numcommits commits"
if {$redisplaying} {
if {$stopped == 0 && [info exists selectedline]} {
- selectline $selectedline
+ selectline $selectedline 0
}
if {$stopped == 1} {
set stopped 0
proc findselectline {l} {
global findloc commentend ctext
- selectline $l
+ selectline $l 1
if {$findloc == "All fields" || $findloc == "Comments"} {
# highlight the matches in the comments
set f [$ctext get 1.0 $commentend]
unset findinprogress
if {$phase != "incrdraw"} {
. config -cursor $maincursor
- $ctext config -cursor $textcursor
+ settextcursor $textcursor
}
}
}
fileevent $f readable readfindproc
set finddidsel 0
. config -cursor watch
- $ctext config -cursor watch
+ settextcursor watch
set findinprogress 1
}
set id $lineid($l)
set p [lindex $parents($id) 0]
. config -cursor watch
- $ctext config -cursor watch
+ settextcursor watch
set findinprogress 1
findcont [list $id $p]
update
}
proc selcanvline {w x y} {
- global canv canvy0 ctext linespc selectedline
+ global canv canvy0 ctext linespc
global lineid linehtag linentag linedtag rowtextx
set ymax [lindex [$canv cget -scrollregion] 3]
if {$ymax == {}} return
if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return
}
unmarkmatches
- selectline $l
+ selectline $l 1
+}
+
+proc commit_descriptor {p} {
+ global commitinfo
+ set l "..."
+ if {[info exists commitinfo($p)]} {
+ set l [lindex $commitinfo($p) 0]
+ }
+ return "$p ($l)"
}
-proc selectline {l} {
+proc selectline {l isnew} {
global canv canv2 canv3 ctext commitinfo selectedline
global lineid linehtag linentag linedtag
- global canvy0 linespc parents nparents
+ global canvy0 linespc parents nparents children nchildren
global cflist currentid sha1entry
- global commentend idtags
+ global commentend idtags idline
+
$canv delete hover
if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
$canv delete secsel
}
allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
}
+
+ if {$isnew} {
+ addtohistory [list selectline $l 0]
+ }
+
set selectedline $l
set id $lineid($l)
}
$ctext insert end "\n"
}
+
+ set commentstart [$ctext index "end - 1c"]
+ set comment {}
+ if {[info exists parents($id)]} {
+ foreach p $parents($id) {
+ append comment "Parent: [commit_descriptor $p]\n"
+ }
+ }
+ if {[info exists children($id)]} {
+ foreach c $children($id) {
+ append comment "Child: [commit_descriptor $c]\n"
+ }
+ }
+ append comment "\n"
+ append comment [lindex $info 5]
+ $ctext insert end $comment
$ctext insert end "\n"
- $ctext insert end [lindex $info 5]
- $ctext insert end "\n"
+
+ # make anything that looks like a SHA1 ID be a clickable link
+ set links [regexp -indices -all -inline {[0-9a-f]{40}} $comment]
+ set i 0
+ foreach l $links {
+ set s [lindex $l 0]
+ set e [lindex $l 1]
+ set linkid [string range $comment $s $e]
+ if {![info exists idline($linkid)]} continue
+ incr e
+ $ctext tag add link "$commentstart + $s c" "$commentstart + $e c"
+ $ctext tag add link$i "$commentstart + $s c" "$commentstart + $e c"
+ $ctext tag bind link$i <1> [list selectline $idline($linkid) 1]
+ incr i
+ }
+ $ctext tag conf link -foreground blue -underline 1
+ $ctext tag bind link <Enter> { %W configure -cursor hand2 }
+ $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
+
$ctext tag delete Comments
$ctext tag remove found 1.0 end
$ctext conf -state disabled
if {![info exists selectedline]} return
set l [expr $selectedline + $dir]
unmarkmatches
- selectline $l
+ selectline $l 1
+}
+
+proc unselectline {} {
+ global selectedline
+
+ catch {unset selectedline}
+ allcanvs delete secsel
+}
+
+proc addtohistory {cmd} {
+ global history historyindex
+
+ if {$historyindex > 0
+ && [lindex $history [expr {$historyindex - 1}]] == $cmd} {
+ return
+ }
+
+ if {$historyindex < [llength $history]} {
+ set history [lreplace $history $historyindex end $cmd]
+ } else {
+ lappend history $cmd
+ }
+ incr historyindex
+ if {$historyindex > 1} {
+ .ctop.top.bar.leftbut conf -state normal
+ } else {
+ .ctop.top.bar.leftbut conf -state disabled
+ }
+ .ctop.top.bar.rightbut conf -state disabled
+}
+
+proc goback {} {
+ global history historyindex
+
+ if {$historyindex > 1} {
+ incr historyindex -1
+ set cmd [lindex $history [expr {$historyindex - 1}]]
+ eval $cmd
+ .ctop.top.bar.rightbut conf -state normal
+ }
+ if {$historyindex <= 1} {
+ .ctop.top.bar.leftbut conf -state disabled
+ }
+}
+
+proc goforw {} {
+ global history historyindex
+
+ if {$historyindex < [llength $history]} {
+ set cmd [lindex $history $historyindex]
+ incr historyindex
+ eval $cmd
+ .ctop.top.bar.leftbut conf -state normal
+ }
+ if {$historyindex >= [llength $history]} {
+ .ctop.top.bar.rightbut conf -state disabled
+ }
}
proc mergediff {id} {
}
proc redisplay {} {
- global selectedline stopped redisplaying phase
+ global stopped redisplaying phase
if {$stopped > 1} return
if {$phase == "getcommits"} return
set redisplaying 1
}
proc incrfont {inc} {
- global mainfont namefont textfont selectedline ctext canv phase
+ global mainfont namefont textfont ctext canv phase
global stopped entries
unmarkmatches
set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
}
}
if {[info exists idline($id)]} {
- selectline $idline($id)
+ selectline $idline($id) 1
return
}
if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
$canv raise $t
}
-proc lineclick {x y id} {
+proc lineclick {x y id isnew} {
global ctext commitinfo children cflist canv
unmarkmatches
+ unselectline
+ if {$isnew} {
+ addtohistory [list lineclick $x $x $id 0]
+ }
$canv delete hover
# fill the details pane with info about this line
$ctext conf -state normal
$ctext delete 0.0 end
- $ctext insert end "Parent:\n "
- catch {destroy $ctext.$id}
- button $ctext.$id -text "Go:" -command "selbyid $id" \
- -padx 4 -pady 0
- $ctext window create end -window $ctext.$id -align center
+ $ctext tag conf link -foreground blue -underline 1
+ $ctext tag bind link <Enter> { %W configure -cursor hand2 }
+ $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
+ $ctext insert end "Parent:\t"
+ $ctext insert end $id [list link link0]
+ $ctext tag bind link0 <1> [list selbyid $id]
set info $commitinfo($id)
- $ctext insert end "\t[lindex $info 0]\n"
+ $ctext insert end "\n\t[lindex $info 0]\n"
$ctext insert end "\tAuthor:\t[lindex $info 1]\n"
$ctext insert end "\tDate:\t[lindex $info 2]\n"
- $ctext insert end "\tID:\t$id\n"
if {[info exists children($id)]} {
$ctext insert end "\nChildren:"
+ set i 0
foreach child $children($id) {
- $ctext insert end "\n "
- catch {destroy $ctext.$child}
- button $ctext.$child -text "Go:" -command "selbyid $child" \
- -padx 4 -pady 0
- $ctext window create end -window $ctext.$child -align center
+ incr i
set info $commitinfo($child)
- $ctext insert end "\t[lindex $info 0]"
+ $ctext insert end "\n\t"
+ $ctext insert end $child [list link link$i]
+ $ctext tag bind link$i <1> [list selbyid $child]
+ $ctext insert end "\n\t[lindex $info 0]"
+ $ctext insert end "\n\tAuthor:\t[lindex $info 1]"
+ $ctext insert end "\n\tDate:\t[lindex $info 2]\n"
}
}
$ctext conf -state disabled
proc selbyid {id} {
global idline
if {[info exists idline($id)]} {
- selectline $idline($id)
+ selectline $idline($id) 1
}
}
proc diffvssel {dirn} {
global rowmenuid selectedline lineid
- global ctext cflist
- global commitinfo
if {![info exists selectedline]} return
if {$dirn} {
set oldid $rowmenuid
set newid $lineid($selectedline)
}
+ addtohistory [list doseldiff $oldid $newid]
+ doseldiff $oldid $newid
+}
+
+proc doseldiff {oldid newid} {
+ global ctext cflist
+ global commitinfo
+
$ctext conf -state normal
$ctext delete 0.0 end
$ctext mark set fmark.0 0.0
$ctext mark gravity fmark.0 left
$cflist delete 0 end
$cflist insert end "Top"
- $ctext insert end "From $oldid\n "
+ $ctext insert end "From "
+ $ctext tag conf link -foreground blue -underline 1
+ $ctext tag bind link <Enter> { %W configure -cursor hand2 }
+ $ctext tag bind link <Leave> { %W configure -cursor $curtextcursor }
+ $ctext tag bind link0 <1> [list selbyid $oldid]
+ $ctext insert end $oldid [list link link0]
+ $ctext insert end "\n "
$ctext insert end [lindex $commitinfo($oldid) 0]
- $ctext insert end "\n\nTo $newid\n "
+ $ctext insert end "\n\nTo "
+ $ctext tag bind link1 <1> [list selbyid $newid]
+ $ctext insert end $newid [list link link1]
+ $ctext insert end "\n "
$ctext insert end [lindex $commitinfo($newid) 0]
$ctext insert end "\n"
$ctext conf -state disabled
set xt [eval drawtags $id $idpos($id)]
$canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
if {[info exists selectedline] && $selectedline == $idline($id)} {
- selectline $selectedline
+ selectline $selectedline 0
}
}
}
}
+set history {}
+set historyindex 0
+
set stopped 0
set redisplaying 0
set stuffsaved 0