X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=gitk;h=9be10a43e603fcda952fde03254076f17275ed05;hb=7612a1efdb0c0806b43db10ce784707aae874340;hp=7c8ad595c04537369b4c13e94fa0eadb93ea05be;hpb=4e7d677949e8ee7617e42f10c1ddf5cd2adee3a1;p=git.git diff --git a/gitk b/gitk index 7c8ad595..9be10a43 100755 --- a/gitk +++ b/gitk @@ -34,10 +34,10 @@ proc start_rev_list {view} { set order "--date-order" } if {[catch { - set fd [open [concat | git-rev-list --header $order \ + set fd [open [concat | git rev-list --header $order \ --parents --boundary --default HEAD $args] r] } err]} { - puts stderr "Error executing git-rev-list: $err" + puts stderr "Error executing git rev-list: $err" exit 1 } set commfd($view) $fd @@ -94,10 +94,10 @@ proc getcommitlines {fd view} { } if {[string range $err 0 4] == "usage"} { set err "Gitk: error reading commits$fv:\ - bad arguments to git-rev-list." + bad arguments to git rev-list." if {$viewname($view) eq "Command line"} { append err \ - " (Note: arguments to gitk are passed to git-rev-list\ + " (Note: arguments to gitk are passed to git rev-list\ to allow selection of commits to be displayed.)" } } else { @@ -148,7 +148,7 @@ proc getcommitlines {fd view} { if {[string length $shortcmit] > 80} { set shortcmit "[string range $shortcmit 0 80]..." } - error_popup "Can't parse git-rev-list output: {$shortcmit}" + error_popup "Can't parse git rev-list output: {$shortcmit}" exit 1 } set id [lindex $ids 0] @@ -217,7 +217,7 @@ proc doupdate {} { } proc readcommit {id} { - if {[catch {set contents [exec git-cat-file commit $id]}]} return + if {[catch {set contents [exec git cat-file commit $id]}]} return parsecommit $id $contents 0 } @@ -238,6 +238,7 @@ proc updatecommits {} { catch {unset selectedline} catch {unset thickerline} catch {unset viewdata($n)} + discardallcommits readrefs showview $n } @@ -278,8 +279,8 @@ proc parsecommit {id contents listed} { set headline $comment } if {!$listed} { - # git-rev-list indents the comment by 4 spaces; - # if we got this via git-cat-file, add the indentation + # git rev-list indents the comment by 4 spaces; + # if we got this via git cat-file, add the indentation set newcomment {} foreach line [split $comment "\n"] { append newcomment " " @@ -339,14 +340,14 @@ proc readrefs {} { set type {} set tag {} catch { - set commit [exec git-rev-parse "$id^0"] + set commit [exec git rev-parse "$id^0"] if {"$commit" != "$id"} { set tagids($name) $commit lappend idtags($commit) $name } } catch { - set tagcontents($name) [exec git-cat-file tag "$id"] + set tagcontents($name) [exec git cat-file tag "$id"] } } elseif { $type == "heads" } { set headids($name) $id @@ -359,21 +360,21 @@ proc readrefs {} { close $refd } -proc show_error {w msg} { +proc show_error {w top msg} { message $w.m -text $msg -justify center -aspect 400 pack $w.m -side top -fill x -padx 20 -pady 20 - button $w.ok -text OK -command "destroy $w" + button $w.ok -text OK -command "destroy $top" pack $w.ok -side bottom -fill x - bind $w "grab $w; focus $w" - bind $w "destroy $w" - tkwait window $w + bind $top "grab $top; focus $top" + bind $top "destroy $top" + tkwait window $top } proc error_popup msg { set w .error toplevel $w wm transient $w . - show_error $w $msg + show_error $w $w $msg } proc makewindow {} { @@ -382,7 +383,7 @@ proc makewindow {} { global findtype findtypemenu findloc findstring fstring geometry global entries sha1entry sha1string sha1but global maincursor textcursor curtextcursor - global rowctxmenu mergemax + global rowctxmenu mergemax wrapcomment global highlight_files gdttype global searchstring sstring @@ -570,6 +571,7 @@ proc makewindow {} { pack $ctext -side left -fill both -expand 1 .ctop.cdet add .ctop.cdet.left + $ctext tag conf comment -wrap $wrapcomment $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa" $ctext tag conf hunksep -fore blue $ctext tag conf d0 -fore red @@ -742,9 +744,9 @@ proc click {w} { proc savestuff {w} { global canv canv2 canv3 ctext cflist mainfont textfont uifont global stuffsaved findmergefiles maxgraphpct - global maxwidth + global maxwidth showneartags global viewname viewfiles viewargs viewperm nextviewnum - global cmitmode + global cmitmode wrapcomment if {$stuffsaved} return if {![winfo viewable .]} return @@ -757,6 +759,8 @@ proc savestuff {w} { puts $f [list set maxgraphpct $maxgraphpct] puts $f [list set maxwidth $maxwidth] puts $f [list set cmitmode $cmitmode] + puts $f [list set wrapcomment $wrapcomment] + puts $f [list set showneartags $showneartags] puts $f "set geometry(width) [winfo width .ctop]" puts $f "set geometry(height) [winfo height .ctop]" puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]" @@ -1388,7 +1392,7 @@ proc vieweditor {top n title} { checkbutton $top.perm -text "Remember this view" -variable newviewperm($n) grid $top.perm - -pady 5 -sticky w message $top.al -aspect 1000 -font $uifont \ - -text "Commits to include (arguments to git-rev-list):" + -text "Commits to include (arguments to git rev-list):" grid $top.al - -sticky w -pady 5 entry $top.args -width 50 -textvariable newviewargs($n) \ -background white @@ -3521,17 +3525,16 @@ proc commit_descriptor {p} { if {[llength $commitinfo($p)] > 1} { set l [lindex $commitinfo($p) 0] } - return "$p ($l)" + return "$p ($l)\n" } # append some text to the ctext widget, and make any SHA1 ID # that we know about be a clickable link. -proc appendwithlinks {text} { +proc appendwithlinks {text tags} { global ctext commitrow linknum curview set start [$ctext index "end - 1c"] - $ctext insert end $text - $ctext insert end "\n" + $ctext insert end $text $tags set links [regexp -indices -all -inline {[0-9a-f]{40}} $text] foreach l $links { set s [lindex $l 0] @@ -3566,6 +3569,64 @@ proc viewnextline {dir} { allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}] } +# add a list of tag or branch names at position pos +# returns the number of names inserted +proc appendrefs {pos l var} { + global ctext commitrow linknum curview idtags $var + + if {[catch {$ctext index $pos}]} { + return 0 + } + set tags {} + foreach id $l { + foreach tag [set $var\($id\)] { + lappend tags [concat $tag $id] + } + } + set tags [lsort -index 1 $tags] + set sep {} + foreach tag $tags { + set name [lindex $tag 0] + set id [lindex $tag 1] + set lk link$linknum + incr linknum + $ctext insert $pos $sep + $ctext insert $pos $name $lk + $ctext tag conf $lk -foreground blue + if {[info exists commitrow($curview,$id)]} { + $ctext tag bind $lk <1> \ + [list selectline $commitrow($curview,$id) 1] + $ctext tag conf $lk -underline 1 + $ctext tag bind $lk { %W configure -cursor hand2 } + $ctext tag bind $lk { %W configure -cursor $curtextcursor } + } + set sep ", " + } + return [llength $tags] +} + +# called when we have finished computing the nearby tags +proc dispneartags {} { + global selectedline currentid ctext anc_tags desc_tags showneartags + global desc_heads + + if {![info exists selectedline] || !$showneartags} return + set id $currentid + $ctext conf -state normal + if {[info exists desc_heads($id)]} { + if {[appendrefs branch $desc_heads($id) idheads] > 1} { + $ctext insert "branch -2c" "es" + } + } + if {[info exists anc_tags($id)]} { + appendrefs follows $anc_tags($id) idtags + } + if {[info exists desc_tags($id)]} { + appendrefs precedes $desc_tags($id) idtags + } + $ctext conf -state disabled +} + proc selectline {l isnew} { global canv canv2 canv3 ctext commitinfo selectedline global displayorder linehtag linentag linedtag @@ -3573,7 +3634,7 @@ proc selectline {l isnew} { global currentid sha1entry global commentend idtags linknum global mergemax numcommits pending_select - global cmitmode + global cmitmode desc_tags anc_tags showneartags allcommits desc_heads catch {unset pending_select} $canv delete hover @@ -3660,7 +3721,7 @@ proc selectline {l isnew} { $ctext insert end "\n" } - set comment {} + set headers {} set olds [lindex $parentlist $l] if {[llength $olds] > 1} { set np 0 @@ -3671,23 +3732,50 @@ proc selectline {l isnew} { set tag m$np } $ctext insert end "Parent: " $tag - appendwithlinks [commit_descriptor $p] + appendwithlinks [commit_descriptor $p] {} incr np } } else { foreach p $olds { - append comment "Parent: [commit_descriptor $p]\n" + append headers "Parent: [commit_descriptor $p]" } } foreach c [lindex $childlist $l] { - append comment "Child: [commit_descriptor $c]\n" + append headers "Child: [commit_descriptor $c]" } - append comment "\n" - append comment [lindex $info 5] # make anything that looks like a SHA1 ID be a clickable link - appendwithlinks $comment + appendwithlinks $headers {} + if {$showneartags} { + if {![info exists allcommits]} { + getallcommits + } + $ctext insert end "Branch: " + $ctext mark set branch "end -1c" + $ctext mark gravity branch left + if {[info exists desc_heads($id)]} { + if {[appendrefs branch $desc_heads($id) idheads] > 1} { + # turn "Branch" into "Branches" + $ctext insert "branch -2c" "es" + } + } + $ctext insert end "\nFollows: " + $ctext mark set follows "end -1c" + $ctext mark gravity follows left + if {[info exists anc_tags($id)]} { + appendrefs follows $anc_tags($id) idtags + } + $ctext insert end "\nPrecedes: " + $ctext mark set precedes "end -1c" + $ctext mark gravity precedes left + if {[info exists desc_tags($id)]} { + appendrefs precedes $desc_tags($id) idtags + } + $ctext insert end "\n" + } + $ctext insert end "\n" + appendwithlinks [lindex $info 5] {comment} $ctext tag delete Comments $ctext tag remove found 1.0 end @@ -3830,7 +3918,7 @@ proc gettree {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 {[catch {set gtf [open [concat | git ls-tree -r $id] r]}]} { return } set treepending $id @@ -3878,7 +3966,7 @@ proc showfile {f} { return } set blob [lindex $treeidlist($diffids) $i] - if {[catch {set bf [open [concat | git-cat-file blob $blob] r]} err]} { + if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} { puts "oops, error reading blob $blob: $err" return } @@ -3920,7 +4008,7 @@ proc mergediff {id l} { set diffids $id # this doesn't seem to actually affect anything... set env(GIT_DIFF_OPTS) $diffopts - set cmd [concat | git-diff-tree --no-commit-id --cc $id] + set cmd [concat | git diff-tree --no-commit-id --cc $id] if {[catch {set mdf [open $cmd r]} err]} { error_popup "Error getting merge diffs: $err" return @@ -4032,7 +4120,7 @@ proc gettreediffs {ids} { set treepending $ids set treediff {} if {[catch \ - {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]} \ + {set gdtf [open [concat | git diff-tree --no-commit-id -r $ids] r]} \ ]} return fconfigure $gdtf -blocking 0 fileevent $gdtf readable [list gettreediffline $gdtf $ids] @@ -4068,7 +4156,7 @@ proc getblobdiffs {ids} { global nextupdate diffinhdr treediffs set env(GIT_DIFF_OPTS) $diffopts - set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids] + set cmd [concat | git diff-tree --no-commit-id -r -p -C $ids] if {[catch {set bdf [open $cmd r]} err]} { puts "error getting diffs: $err" return @@ -4737,7 +4825,7 @@ proc mkpatchgo {} { set oldid [$patchtop.fromsha1 get] set newid [$patchtop.tosha1 get] set fname [$patchtop.fname get] - if {[catch {exec git-diff-tree -p $oldid $newid >$fname &} err]} { + if {[catch {exec git diff-tree -p $oldid $newid >$fname &} err]} { error_popup "Error creating patch: $err" } catch {destroy $patchtop} @@ -4813,12 +4901,19 @@ proc domktag {} { proc redrawtags {id} { global canv linehtag commitrow idpos selectedline curview + global mainfont if {![info exists commitrow($curview,$id)]} return drawcmitrow $commitrow($curview,$id) $canv delete tag.$id set xt [eval drawtags $id $idpos($id)] $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2] + set text [$canv itemcget $linehtag($commitrow($curview,$id)) -text] + set xr [expr {$xt + [font measure $mainfont $text]}] + if {$xr > $canvxmax} { + set canvxmax $xr + setcanvscroll + } if {[info exists selectedline] && $selectedline == $commitrow($curview,$id)} { selectline $selectedline 0 @@ -4892,22 +4987,192 @@ proc wrcomcan {} { unset wrcomtop } -proc listrefs {id} { - global idtags idheads idotherrefs +# Stuff for finding nearby tags +proc getallcommits {} { + global allcstart allcommits allcfd - set x {} - if {[info exists idtags($id)]} { - set x $idtags($id) + set fd [open [concat | git rev-list --all --topo-order --parents] r] + set allcfd $fd + fconfigure $fd -blocking 0 + set allcommits "reading" + nowbusy allcommits + restartgetall $fd +} + +proc discardallcommits {} { + global allparents allchildren allcommits allcfd + global desc_tags anc_tags alldtags tagisdesc allids desc_heads + + if {![info exists allcommits]} return + if {$allcommits eq "reading"} { + catch {close $allcfd} } - set y {} - if {[info exists idheads($id)]} { - set y $idheads($id) + foreach v {allcommits allchildren allparents allids desc_tags anc_tags + alldtags tagisdesc desc_heads} { + catch {unset $v} } - set z {} - if {[info exists idotherrefs($id)]} { - set z $idotherrefs($id) +} + +proc restartgetall {fd} { + global allcstart + + fileevent $fd readable [list getallclines $fd] + set allcstart [clock clicks -milliseconds] +} + +proc combine_dtags {l1 l2} { + global tagisdesc notfirstd + + set res [lsort -unique [concat $l1 $l2]] + for {set i 0} {$i < [llength $res]} {incr i} { + set x [lindex $res $i] + for {set j [expr {$i+1}]} {$j < [llength $res]} {} { + set y [lindex $res $j] + if {[info exists tagisdesc($x,$y)]} { + if {$tagisdesc($x,$y) > 0} { + # x is a descendent of y, exclude x + set res [lreplace $res $i $i] + incr i -1 + break + } else { + # y is a descendent of x, exclude y + set res [lreplace $res $j $j] + } + } else { + # no relation, keep going + incr j + } + } + } + return $res +} + +proc combine_atags {l1 l2} { + global tagisdesc + + set res [lsort -unique [concat $l1 $l2]] + for {set i 0} {$i < [llength $res]} {incr i} { + set x [lindex $res $i] + for {set j [expr {$i+1}]} {$j < [llength $res]} {} { + set y [lindex $res $j] + if {[info exists tagisdesc($x,$y)]} { + if {$tagisdesc($x,$y) < 0} { + # x is an ancestor of y, exclude x + set res [lreplace $res $i $i] + incr i -1 + break + } else { + # y is an ancestor of x, exclude y + set res [lreplace $res $j $j] + } + } else { + # no relation, keep going + incr j + } + } + } + return $res +} + +proc getallclines {fd} { + global allparents allchildren allcommits allcstart + global desc_tags anc_tags idtags alldtags tagisdesc allids + global desc_heads idheads + + while {[gets $fd line] >= 0} { + set id [lindex $line 0] + lappend allids $id + set olds [lrange $line 1 end] + set allparents($id) $olds + if {![info exists allchildren($id)]} { + set allchildren($id) {} + } + foreach p $olds { + lappend allchildren($p) $id + } + # compute nearest tagged descendents as we go + # also compute descendent heads + set dtags {} + set dheads {} + foreach child $allchildren($id) { + if {[info exists idtags($child)]} { + set ctags [list $child] + } else { + set ctags $desc_tags($child) + } + if {$dtags eq {}} { + set dtags $ctags + } elseif {$ctags ne $dtags} { + set dtags [combine_dtags $dtags $ctags] + } + set cheads $desc_heads($child) + if {$dheads eq {}} { + set dheads $cheads + } elseif {$cheads ne $dheads} { + set dheads [lsort -unique [concat $dheads $cheads]] + } + } + set desc_tags($id) $dtags + if {[info exists idtags($id)]} { + set adt $dtags + foreach tag $dtags { + set adt [concat $adt $alldtags($tag)] + } + set adt [lsort -unique $adt] + set alldtags($id) $adt + foreach tag $adt { + set tagisdesc($id,$tag) -1 + set tagisdesc($tag,$id) 1 + } + } + if {[info exists idheads($id)]} { + lappend dheads $id + } + set desc_heads($id) $dheads + if {[clock clicks -milliseconds] - $allcstart >= 50} { + fileevent $fd readable {} + after idle restartgetall $fd + return + } + } + if {[eof $fd]} { + after idle restartatags [llength $allids] + if {[catch {close $fd} err]} { + error_popup "Error reading full commit graph: $err.\n\ + Results may be incomplete." + } + } +} + +# walk backward through the tree and compute nearest tagged ancestors +proc restartatags {i} { + global allids allparents idtags anc_tags t0 + + set t0 [clock clicks -milliseconds] + while {[incr i -1] >= 0} { + set id [lindex $allids $i] + set atags {} + foreach p $allparents($id) { + if {[info exists idtags($p)]} { + set ptags [list $p] + } else { + set ptags $anc_tags($p) + } + if {$atags eq {}} { + set atags $ptags + } elseif {$ptags ne $atags} { + set atags [combine_atags $atags $ptags] + } + } + set anc_tags($id) $atags + if {[clock clicks -milliseconds] - $t0 >= 50} { + after idle restartatags $i + return + } } - return [list $x $y $z] + set allcommits "done" + notbusy allcommits + dispneartags } proc rereadrefs {} { @@ -4945,7 +5210,7 @@ proc showtag {tag isnew} { } else { set text "Tag: $tag\nId: $tagids($tag)" } - appendwithlinks $text + appendwithlinks $text {} $ctext conf -state disabled init_flist {} } @@ -4958,7 +5223,7 @@ proc doquit {} { proc doprefs {} { global maxwidth maxgraphpct diffopts - global oldprefs prefstop + global oldprefs prefstop showneartags set top .gitkprefs set prefstop $top @@ -4966,7 +5231,7 @@ proc doprefs {} { raise $top return } - foreach v {maxwidth maxgraphpct diffopts} { + foreach v {maxwidth maxgraphpct diffopts showneartags} { set oldprefs($v) [set $v] } toplevel $top @@ -4988,6 +5253,11 @@ proc doprefs {} { -font optionfont entry $top.diffopt -width 20 -textvariable diffopts grid x $top.diffoptl $top.diffopt -sticky w + frame $top.ntag + label $top.ntag.l -text "Display nearby tags" -font optionfont + checkbutton $top.ntag.b -variable showneartags + pack $top.ntag.b $top.ntag.l -side left + grid x $top.ntag -sticky w frame $top.buts button $top.buts.ok -text "OK" -command prefsok button $top.buts.can -text "Cancel" -command prefscan @@ -4999,9 +5269,9 @@ proc doprefs {} { proc prefscan {} { global maxwidth maxgraphpct diffopts - global oldprefs prefstop + global oldprefs prefstop showneartags - foreach v {maxwidth maxgraphpct diffopts} { + foreach v {maxwidth maxgraphpct diffopts showneartags} { set $v $oldprefs($v) } catch {destroy $prefstop} @@ -5010,13 +5280,15 @@ proc prefscan {} { proc prefsok {} { global maxwidth maxgraphpct - global oldprefs prefstop + global oldprefs prefstop showneartags catch {destroy $prefstop} unset prefstop if {$maxwidth != $oldprefs(maxwidth) || $maxgraphpct != $oldprefs(maxgraphpct)} { redisplay + } elseif {$showneartags != $oldprefs(showneartags)} { + reselectline } } @@ -5300,11 +5572,11 @@ proc tcl_encoding {enc} { # defaults... set datemode 0 set diffopts "-U 5 -p" -set wrcomcmd "git-diff-tree --stdin -p --pretty" +set wrcomcmd "git diff-tree --stdin -p --pretty" set gitencoding {} catch { - set gitencoding [exec git-repo-config --get i18n.commitencoding] + set gitencoding [exec git repo-config --get i18n.commitencoding] } if {$gitencoding == ""} { set gitencoding "utf-8" @@ -5326,6 +5598,8 @@ set uparrowlen 7 set downarrowlen 7 set mingaplen 30 set cmitmode "patch" +set wrapcomment "none" +set showneartags 1 set colors {green red blue magenta darkgrey brown orange} @@ -5347,7 +5621,7 @@ foreach arg $argv { # check that we can find a .git directory somewhere... set gitdir [gitdir] if {![file isdirectory $gitdir]} { - show_error . "Cannot find the git directory \"$gitdir\"." + show_error {} . "Cannot find the git directory \"$gitdir\"." exit 1 } @@ -5358,7 +5632,7 @@ if {$i >= 0} { set revtreeargs [lrange $revtreeargs 0 [expr {$i - 1}]] } elseif {$revtreeargs ne {}} { if {[catch { - set f [eval exec git-rev-parse --no-revs --no-flags $revtreeargs] + set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs] set cmdline_files [split $f "\n"] set n [llength $cmdline_files] set revtreeargs [lrange $revtreeargs 0 end-$n] @@ -5367,9 +5641,9 @@ if {$i >= 0} { # so look for "fatal:". set i [string first "fatal:" $err] if {$i > 0} { - set err [string range [expr {$i + 6}] end] + set err [string range $err [expr {$i + 6}] end] } - show_error . "Bad arguments to gitk:\n$err" + show_error {} . "Bad arguments to gitk:\n$err" exit 1 } }