Commits

Anonymous committed 887c996

gitk: Add a window to list branches, tags and other references

This adds an entry to the File menu labelled "List references" which
pops up a window showing a sorted list of branches, tags, and other
references, with a little icon beside each to indicate what sort it
is. The list only shows refs that point to a commit that is included
in the graph, and if you click on a ref, the corresponding commit
is selected in the main window. The list of refs gets updated
dynamically.

Signed-off-by: Paul Mackerras <paulus@samba.org>

Comments (0)

Files changed (1)

     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
        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
 
     } elseif {$numcommits == 0} {
 	show_status "No commits selected"
     }
+    run refill_reflist
 }
 
 # Stuff relating to the highlighting facility
 proc showstuff {canshow last} {
     global numcommits commitrow pending_select selectedline curview
     global lookingforhead mainheadid displayorder selectfirst
-    global lastscrollset
+    global lastscrollset commitinterest
 
     if {$numcommits == 0} {
 	global phase
 	set phase "incrdraw"
 	allcanvs delete all
     }
+    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)
+	}
+    }
     set r0 $numcommits
     set prev $numcommits
     set numcommits $canshow
     $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]
 }
 
 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
 }
 
     lappend idtags($id) $tag
     redrawtags $id
     addedtag $id
+    dispneartags 0
+    run refill_reflist
 }
 
 proc redrawtags {id} {
 	notbusy newbranch
 	redrawtags $id
 	dispneartags 0
+	run refill_reflist
     }
 }
 
     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
 	    redrawtags $id
 	}
     }
+    run refill_reflist
 }
 
 proc listrefs {id} {