git-fetch-pack: Support multi_ack extension
[git.git] / gitk
diff --git a/gitk b/gitk
index 0767695..a9d37d9 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -1,6 +1,6 @@
 #!/bin/sh
 # Tcl ignores the next line -*- tcl -*- \
 #!/bin/sh
 # Tcl ignores the next line -*- tcl -*- \
-exec wish "$0" -- "${1+$@}"
+exec wish "$0" -- "$@"
 
 # Copyright (C) 2005 Paul Mackerras.  All rights reserved.
 # This program is free software; it may be used, copied, modified
 
 # Copyright (C) 2005 Paul Mackerras.  All rights reserved.
 # This program is free software; it may be used, copied, modified
@@ -238,7 +238,8 @@ proc parsecommit {id contents listed olds} {
 }
 
 proc readrefs {} {
 }
 
 proc readrefs {} {
-    global tagids idtags headids idheads
+    global tagids idtags headids idheads tagcontents
+
     set tags [glob -nocomplain -types f [gitdir]/refs/tags/*]
     foreach f $tags {
        catch {
     set tags [glob -nocomplain -types f [gitdir]/refs/tags/*]
     foreach f $tags {
        catch {
@@ -248,7 +249,8 @@ proc readrefs {} {
                set direct [file tail $f]
                set tagids($direct) $id
                lappend idtags($id) $direct
                set direct [file tail $f]
                set tagids($direct) $id
                lappend idtags($id) $direct
-               set contents [split [exec git-cat-file tag $id] "\n"]
+               set tagblob [exec git-cat-file tag $id]
+               set contents [split $tagblob "\n"]
                set obj {}
                set type {}
                set tag {}
                set obj {}
                set type {}
                set tag {}
@@ -263,6 +265,7 @@ proc readrefs {} {
                if {$obj != {} && $type == "commit" && $tag != {}} {
                    set tagids($tag) $obj
                    lappend idtags($obj) $tag
                if {$obj != {} && $type == "commit" && $tag != {}} {
                    set tagids($tag) $obj
                    lappend idtags($obj) $tag
+                   set tagcontents($tag) $tagblob
                }
            }
            close $fd
                }
            }
            close $fd
@@ -281,6 +284,32 @@ proc readrefs {} {
            close $fd
        }
     }
            close $fd
        }
     }
+    readotherrefs refs {} {tags heads}
+}
+
+proc readotherrefs {base dname excl} {
+    global otherrefids idotherrefs
+
+    set git [gitdir]
+    set files [glob -nocomplain -types f [file join $git $base *]]
+    foreach f $files {
+       catch {
+           set fd [open $f r]
+           set line [read $fd 40]
+           if {[regexp {^[0-9a-f]{40}} $line id]} {
+               set name "$dname[file tail $f]"
+               set otherrefids($name) $id
+               lappend idotherrefs($id) $name
+           }
+           close $fd
+       }
+    }
+    set dirs [glob -nocomplain -types d [file join $git $base *]]
+    foreach d $dirs {
+       set dir [file tail $d]
+       if {[lsearch -exact $excl $dir] >= 0} continue
+       readotherrefs [file join $base $dir] "$dname$dir/" {}
+    }
 }
 
 proc error_popup msg {
 }
 
 proc error_popup msg {
@@ -305,6 +334,7 @@ proc makewindow {} {
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
+    .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.file add command -label "Quit" -command doquit
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
@@ -456,6 +486,8 @@ proc makewindow {} {
     bindall <B2-Motion> "allcanvs scan dragto 0 %y"
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
     bindall <B2-Motion> "allcanvs scan dragto 0 %y"
     bind . <Key-Up> "selnextline -1"
     bind . <Key-Down> "selnextline 1"
+    bind . <Key-Right> "goforw"
+    bind . <Key-Left> "goback"
     bind . <Key-Prior> "allcanvs yview scroll -1 pages"
     bind . <Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
     bind . <Key-Prior> "allcanvs yview scroll -1 pages"
     bind . <Key-Next> "allcanvs yview scroll 1 pages"
     bindkey <Key-Delete> "$ctext yview scroll -1 pages"
@@ -463,6 +495,12 @@ proc makewindow {} {
     bindkey <Key-space> "$ctext yview scroll 1 pages"
     bindkey p "selnextline -1"
     bindkey n "selnextline 1"
     bindkey <Key-space> "$ctext yview scroll 1 pages"
     bindkey p "selnextline -1"
     bindkey n "selnextline 1"
+    bindkey z "goback"
+    bindkey x "goforw"
+    bindkey i "selnextline -1"
+    bindkey k "selnextline 1"
+    bindkey j "goback"
+    bindkey l "goforw"
     bindkey b "$ctext yview scroll -1 pages"
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
     bindkey b "$ctext yview scroll -1 pages"
     bindkey d "$ctext yview scroll 18 units"
     bindkey u "$ctext yview scroll -18 units"
@@ -528,6 +566,7 @@ proc click {w} {
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
     global stuffsaved findmergefiles gaudydiff maxgraphpct
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
     global stuffsaved findmergefiles gaudydiff maxgraphpct
+    global maxwidth
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -538,6 +577,7 @@ proc savestuff {w} {
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set gaudydiff $gaudydiff]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set gaudydiff $gaudydiff]
        puts $f [list set maxgraphpct $maxgraphpct]
+       puts $f [list set maxwidth $maxwidth]
        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]"
        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]"
@@ -743,13 +783,39 @@ proc bindline {t id} {
     $canv bind $t <Button-1> "lineclick %x %y $id 1"
 }
 
     $canv bind $t <Button-1> "lineclick %x %y $id 1"
 }
 
+proc drawlines {id xtra} {
+    global mainline mainlinearrow sidelines lthickness colormap canv
+
+    $canv delete lines.$id
+    if {[info exists mainline($id)]} {
+       set t [$canv create line $mainline($id) \
+                  -width [expr {($xtra + 1) * $lthickness}] \
+                  -fill $colormap($id) -tags lines.$id \
+                  -arrow $mainlinearrow($id)]
+       $canv lower $t
+       bindline $t $id
+    }
+    if {[info exists sidelines($id)]} {
+       foreach ls $sidelines($id) {
+           set coords [lindex $ls 0]
+           set thick [lindex $ls 1]
+           set arrow [lindex $ls 2]
+           set t [$canv create line $coords -fill $colormap($id) \
+                      -width [expr {($thick + $xtra) * $lthickness}] \
+                      -arrow $arrow -tags lines.$id]
+           $canv lower $t
+           bindline $t $id
+       }
+    }
+}
+
 # level here is an index in displist
 proc drawcommitline {level} {
     global parents children nparents displist
     global canv canv2 canv3 mainfont namefont canvy linespc
     global lineid linehtag linentag linedtag commitinfo
     global colormap numcommits currentparents dupparents
 # level here is an index in displist
 proc drawcommitline {level} {
     global parents children nparents displist
     global canv canv2 canv3 mainfont namefont canvy linespc
     global lineid linehtag linentag linedtag commitinfo
     global colormap numcommits currentparents dupparents
-    global idtags idline idheads
+    global idtags idline idheads idotherrefs
     global lineno lthickness mainline mainlinearrow sidelines
     global commitlisted rowtextx idpos lastuse displist
     global oldnlines olddlevel olddisplist
     global lineno lthickness mainline mainlinearrow sidelines
     global commitlisted rowtextx idpos lastuse displist
     global oldnlines olddlevel olddisplist
@@ -791,23 +857,8 @@ proc drawcommitline {level} {
        if {$mainlinearrow($id) ne "none"} {
            set mainline($id) [trimdiagstart $mainline($id)]
        }
        if {$mainlinearrow($id) ne "none"} {
            set mainline($id) [trimdiagstart $mainline($id)]
        }
-       set t [$canv create line $mainline($id) \
-                  -width $lthickness -fill $colormap($id) \
-                  -arrow $mainlinearrow($id)]
-       $canv lower $t
-       bindline $t $id
-    }
-    if {[info exists sidelines($id)]} {
-       foreach ls $sidelines($id) {
-           set coords [lindex $ls 0]
-           set thick [lindex $ls 1]
-           set arrow [lindex $ls 2]
-           set t [$canv create line $coords -fill $colormap($id) \
-                      -width [expr {$thick * $lthickness}] -arrow $arrow]
-           $canv lower $t
-           bindline $t $id
-       }
     }
     }
+    drawlines $id 0
     set orad [expr {$linespc / 3}]
     set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
               [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
     set orad [expr {$linespc / 3}]
     set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
               [expr $x + $orad - 1] [expr $y1 + $orad - 1] \
@@ -820,7 +871,8 @@ proc drawcommitline {level} {
     }
     set rowtextx($lineno) $xt
     set idpos($id) [list $x $xt $y1]
     }
     set rowtextx($lineno) $xt
     set idpos($id) [list $x $xt $y1]
-    if {[info exists idtags($id)] || [info exists idheads($id)]} {
+    if {[info exists idtags($id)] || [info exists idheads($id)]
+       || [info exists idotherrefs($id)]} {
        set xt [drawtags $id $x $xt $y1]
     }
     set headline [lindex $commitinfo($id) 0]
        set xt [drawtags $id $x $xt $y1]
     }
     set headline [lindex $commitinfo($id) 0]
@@ -840,18 +892,23 @@ proc drawcommitline {level} {
 }
 
 proc drawtags {id x xt y1} {
 }
 
 proc drawtags {id x xt y1} {
-    global idtags idheads
+    global idtags idheads idotherrefs
     global linespc lthickness
     global linespc lthickness
-    global canv mainfont
+    global canv mainfont idline rowtextx
 
     set marks {}
     set ntags 0
 
     set marks {}
     set ntags 0
+    set nheads 0
     if {[info exists idtags($id)]} {
        set marks $idtags($id)
        set ntags [llength $marks]
     }
     if {[info exists idheads($id)]} {
        set marks [concat $marks $idheads($id)]
     if {[info exists idtags($id)]} {
        set marks $idtags($id)
        set ntags [llength $marks]
     }
     if {[info exists idheads($id)]} {
        set marks [concat $marks $idheads($id)]
+       set nheads [llength $idheads($id)]
+    }
+    if {[info exists idotherrefs($id)]} {
+       set marks [concat $marks $idotherrefs($id)]
     }
     if {$marks eq {}} {
        return $xt
     }
     if {$marks eq {}} {
        return $xt
@@ -876,17 +933,27 @@ proc drawtags {id x xt y1} {
        set xr [expr $x + $delta + $wid + $lthickness]
        if {[incr ntags -1] >= 0} {
            # draw a tag
        set xr [expr $x + $delta + $wid + $lthickness]
        if {[incr ntags -1] >= 0} {
            # draw a tag
-           $canv create polygon $x [expr $yt + $delta] $xl $yt\
-               $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
-               -width 1 -outline black -fill yellow -tags tag.$id
+           set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
+                      $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
+                      -width 1 -outline black -fill yellow -tags tag.$id]
+           $canv bind $t <1> [list showtag $tag 1]
+           set rowtextx($idline($id)) [expr {$xr + $linespc}]
        } else {
        } else {
-           # draw a head
+           # draw a head or other ref
+           if {[incr nheads -1] >= 0} {
+               set col green
+           } else {
+               set col "#ddddff"
+           }
            set xl [expr $xl - $delta/2]
            $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
            set xl [expr $xl - $delta/2]
            $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
-               -width 1 -outline black -fill green -tags tag.$id
+               -width 1 -outline black -fill $col -tags tag.$id
+       }
+       set t [$canv create text $xl $y1 -anchor w -text $tag \
+                  -font $mainfont -tags tag.$id]
+       if {$ntags >= 0} {
+           $canv bind $t <1> [list showtag $tag 1]
        }
        }
-       $canv create text $xl $y1 -anchor w -text $tag \
-           -font $mainfont -tags tag.$id
     }
     return $xt
 }
     }
     return $xt
 }
@@ -1456,7 +1523,7 @@ proc drawrest {} {
     global phase stopped redisplaying selectedline
     global datemode todo displayorder
     global numcommits ncmupdate
     global phase stopped redisplaying selectedline
     global datemode todo displayorder
     global numcommits ncmupdate
-    global nextupdate startmsecs idline
+    global nextupdate startmsecs
 
     set level [decidenext]
     if {$level >= 0} {
 
     set level [decidenext]
     if {$level >= 0} {
@@ -1978,14 +2045,40 @@ proc commit_descriptor {p} {
     return "$p ($l)"
 }
 
     return "$p ($l)"
 }
 
+# append some text to the ctext widget, and make any SHA1 ID
+# that we know about be a clickable link.
+proc appendwithlinks {text} {
+    global ctext idline linknum
+
+    set start [$ctext index "end - 1c"]
+    $ctext insert end $text
+    $ctext insert end "\n"
+    set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
+    foreach l $links {
+       set s [lindex $l 0]
+       set e [lindex $l 1]
+       set linkid [string range $text $s $e]
+       if {![info exists idline($linkid)]} continue
+       incr e
+       $ctext tag add link "$start + $s c" "$start + $e c"
+       $ctext tag add link$linknum "$start + $s c" "$start + $e c"
+       $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1]
+       incr linknum
+    }
+    $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 }
+}
+
 proc selectline {l isnew} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global lineid linehtag linentag linedtag
     global canvy0 linespc parents nparents children
     global cflist currentid sha1entry
 proc selectline {l isnew} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global lineid linehtag linentag linedtag
     global canvy0 linespc parents nparents children
     global cflist currentid sha1entry
-    global commentend idtags idline
+    global commentend idtags idline linknum
 
     $canv delete hover
 
     $canv delete hover
+    normalline
     if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
     $canv delete secsel
     set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
     if {![info exists lineid($l)] || ![info exists linehtag($l)]} return
     $canv delete secsel
     set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \
@@ -2049,6 +2142,7 @@ proc selectline {l isnew} {
 
     $ctext conf -state normal
     $ctext delete 0.0 end
 
     $ctext conf -state normal
     $ctext delete 0.0 end
+    set linknum 0
     $ctext mark set fmark.0 0.0
     $ctext mark gravity fmark.0 left
     set info $commitinfo($id)
     $ctext mark set fmark.0 0.0
     $ctext mark gravity fmark.0 left
     set info $commitinfo($id)
@@ -2062,7 +2156,6 @@ proc selectline {l isnew} {
        $ctext insert end "\n"
     }
  
        $ctext insert end "\n"
     }
  
-    set commentstart [$ctext index "end - 1c"]
     set comment {}
     if {[info exists parents($id)]} {
        foreach p $parents($id) {
     set comment {}
     if {[info exists parents($id)]} {
        foreach p $parents($id) {
@@ -2076,26 +2169,9 @@ proc selectline {l isnew} {
     }
     append comment "\n"
     append comment [lindex $info 5]
     }
     append comment "\n"
     append comment [lindex $info 5]
-    $ctext insert end $comment
-    $ctext insert end "\n"
 
     # make anything that looks like a SHA1 ID be a clickable link
 
     # 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 }
+    appendwithlinks $comment
 
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
 
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
@@ -2730,7 +2806,7 @@ proc gettreediffs {ids} {
     set treediff {}
     set id [lindex $ids 0]
     set p [lindex $ids 1]
     set treediff {}
     set id [lindex $ids 0]
     set p [lindex $ids 1]
-    if [catch {set gdtf [open "|git-diff-tree -r $p $id" r]}] return
+    if [catch {set gdtf [open "|git-diff-tree -r $id" r]}] return
     fconfigure $gdtf -blocking 0
     fileevent $gdtf readable [list gettreediffline $gdtf $ids]
 }
     fconfigure $gdtf -blocking 0
     fileevent $gdtf readable [list gettreediffline $gdtf $ids]
 }
@@ -2766,7 +2842,7 @@ proc getblobdiffs {ids} {
     set id [lindex $ids 0]
     set p [lindex $ids 1]
     set env(GIT_DIFF_OPTS) $diffopts
     set id [lindex $ids 0]
     set p [lindex $ids 1]
     set env(GIT_DIFF_OPTS) $diffopts
-    set cmd [list | git-diff-tree -r -p -C $p $id]
+    set cmd [list | git-diff-tree -r -p -C $id]
     if {[catch {set bdf [open $cmd r]} err]} {
        puts "error getting diffs: $err"
        return
     if {[catch {set bdf [open $cmd r]} err]} {
        puts "error getting diffs: $err"
        return
@@ -3071,15 +3147,102 @@ proc linehover {} {
     $canv raise $t
 }
 
     $canv raise $t
 }
 
+proc clickisonarrow {id y} {
+    global mainline mainlinearrow sidelines lthickness
+
+    set thresh [expr {2 * $lthickness + 6}]
+    if {[info exists mainline($id)]} {
+       if {$mainlinearrow($id) ne "none"} {
+           if {abs([lindex $mainline($id) 1] - $y) < $thresh} {
+               return "up"
+           }
+       }
+    }
+    if {[info exists sidelines($id)]} {
+       foreach ls $sidelines($id) {
+           set coords [lindex $ls 0]
+           set arrow [lindex $ls 2]
+           if {$arrow eq "first" || $arrow eq "both"} {
+               if {abs([lindex $coords 1] - $y) < $thresh} {
+                   return "up"
+               }
+           }
+           if {$arrow eq "last" || $arrow eq "both"} {
+               if {abs([lindex $coords end] - $y) < $thresh} {
+                   return "down"
+               }
+           }
+       }
+    }
+    return {}
+}
+
+proc arrowjump {id dirn y} {
+    global mainline sidelines canv
+
+    set yt {}
+    if {$dirn eq "down"} {
+       if {[info exists mainline($id)]} {
+           set y1 [lindex $mainline($id) 1]
+           if {$y1 > $y} {
+               set yt $y1
+           }
+       }
+       if {[info exists sidelines($id)]} {
+           foreach ls $sidelines($id) {
+               set y1 [lindex $ls 0 1]
+               if {$y1 > $y && ($yt eq {} || $y1 < $yt)} {
+                   set yt $y1
+               }
+           }
+       }
+    } else {
+       if {[info exists sidelines($id)]} {
+           foreach ls $sidelines($id) {
+               set y1 [lindex $ls 0 end]
+               if {$y1 < $y && ($yt eq {} || $y1 > $yt)} {
+                   set yt $y1
+               }
+           }
+       }
+    }
+    if {$yt eq {}} return
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    if {$ymax eq {} || $ymax <= 0} return
+    set view [$canv yview]
+    set yspan [expr {[lindex $view 1] - [lindex $view 0]}]
+    set yfrac [expr {$yt / $ymax - $yspan / 2}]
+    if {$yfrac < 0} {
+       set yfrac 0
+    }
+    $canv yview moveto $yfrac
+}
+
 proc lineclick {x y id isnew} {
 proc lineclick {x y id isnew} {
-    global ctext commitinfo children cflist canv
+    global ctext commitinfo children cflist canv thickerline
 
     unmarkmatches
     unselectline
 
     unmarkmatches
     unselectline
+    normalline
+    $canv delete hover
+    # draw this line thicker than normal
+    drawlines $id 1
+    set thickerline $id
+    if {$isnew} {
+       set ymax [lindex [$canv cget -scrollregion] 3]
+       if {$ymax eq {}} return
+       set yfrac [lindex [$canv yview] 0]
+       set y [expr {$y + $yfrac * $ymax}]
+    }
+    set dirn [clickisonarrow $id $y]
+    if {$dirn ne {}} {
+       arrowjump $id $dirn $y
+       return
+    }
+
     if {$isnew} {
     if {$isnew} {
-       addtohistory [list lineclick $x $x $id 0]
+       addtohistory [list lineclick $x $y $id 0]
     }
     }
-    $canv delete hover
     # fill the details pane with info about this line
     $ctext conf -state normal
     $ctext delete 0.0 end
     # fill the details pane with info about this line
     $ctext conf -state normal
     $ctext delete 0.0 end
@@ -3112,6 +3275,14 @@ proc lineclick {x y id isnew} {
     $cflist delete 0 end
 }
 
     $cflist delete 0 end
 }
 
+proc normalline {} {
+    global thickerline
+    if {[info exists thickerline]} {
+       drawlines $thickerline 0
+       unset thickerline
+    }
+}
+
 proc selbyid {id} {
     global idline
     if {[info exists idline($id)]} {
 proc selbyid {id} {
     global idline
     if {[info exists idline($id)]} {
@@ -3305,7 +3476,6 @@ proc mktag {} {
 
 proc domktag {} {
     global mktagtop env tagids idtags
 
 proc domktag {} {
     global mktagtop env tagids idtags
-    global idpos idline linehtag canv selectedline
 
     set id [$mktagtop.sha1 get]
     set tag [$mktagtop.tag get]
 
     set id [$mktagtop.sha1 get]
     set tag [$mktagtop.tag get]
@@ -3330,6 +3500,13 @@ proc domktag {} {
 
     set tagids($tag) $id
     lappend idtags($id) $tag
 
     set tagids($tag) $id
     lappend idtags($id) $tag
+    redrawtags $id
+}
+
+proc redrawtags {id} {
+    global canv linehtag idline idpos selectedline
+
+    if {![info exists idline($id)]} return
     $canv delete tag.$id
     set xt [eval drawtags $id $idpos($id)]
     $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
     $canv delete tag.$id
     set xt [eval drawtags $id $idpos($id)]
     $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2]
@@ -3405,6 +3582,68 @@ proc wrcomcan {} {
     unset wrcomtop
 }
 
     unset wrcomtop
 }
 
+proc listrefs {id} {
+    global idtags idheads idotherrefs
+
+    set x {}
+    if {[info exists idtags($id)]} {
+       set x $idtags($id)
+    }
+    set y {}
+    if {[info exists idheads($id)]} {
+       set y $idheads($id)
+    }
+    set z {}
+    if {[info exists idotherrefs($id)]} {
+       set z $idotherrefs($id)
+    }
+    return [list $x $y $z]
+}
+
+proc rereadrefs {} {
+    global idtags idheads idotherrefs
+    global tagids headids otherrefids
+
+    set refids [concat [array names idtags] \
+                   [array names idheads] [array names idotherrefs]]
+    foreach id $refids {
+       if {![info exists ref($id)]} {
+           set ref($id) [listrefs $id]
+       }
+    }
+    foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
+       catch {unset $v}
+    }
+    readrefs
+    set refids [lsort -unique [concat $refids [array names idtags] \
+                       [array names idheads] [array names idotherrefs]]]
+    foreach id $refids {
+       set v [listrefs $id]
+       if {![info exists ref($id)] || $ref($id) != $v} {
+           redrawtags $id
+       }
+    }
+}
+
+proc showtag {tag isnew} {
+    global ctext cflist tagcontents tagids linknum
+
+    if {$isnew} {
+       addtohistory [list showtag $tag 0]
+    }
+    $ctext conf -state normal
+    $ctext delete 0.0 end
+    set linknum 0
+    if {[info exists tagcontents($tag)]} {
+       set text $tagcontents($tag)
+    } else {
+       set text "Tag: $tag\nId:  $tagids($tag)"
+    }
+    appendwithlinks $text
+    $ctext conf -state disabled
+    $cflist delete 0 end
+}
+
 proc doquit {} {
     global stopped
     set stopped 100
 proc doquit {} {
     global stopped
     set stopped 100