Tags for Vi/ViM editing

Pavel Hampl - I use ViM to edit my Tcl/Tk scripts. From my work with C-code I am used to working with tags, which allowed me to jump quickly among different files and find a procedure or function or class declaration. Unfortunately the program ctags recognizes only C, Fortran and similar languages. Therefore I have prepared one shell script and one awk script do create an equal 'tags' file that allows me to access proc definitions quickly. The main shell script finds all proc definitions in the directory:

 egrep -n '^[ \t]*proc[ ]+[a-zA-Z][a-zA-Z0-9]*[ ]+\{.+\}[ ]+\{[ ]*$' *tcl >tcltags
 awk -f tags.awk tcltags |sort >tags

The awk script tags.awk transforms the grep output into a valid 'tags' file, which then has to be sorted. This is the awk script:

  {
   printf("%s",$2)
   split($1,a,":")
   printf("\t./%s\t%s;\"\tf\n",a[1],a[2])
   }                                                                     

Of course, all commands of the shell script can be connected into a piped single line. You then won't have to take care of the 'tcltags' file.

Now vim works fine for me; it takes me less time to find the correct proc. Seems to me that these tags should be useful for Emacs users, too.


glennj: the egrep regex contains some errors:

 egrep -n '^[ \t]*proc[ \t]+[^ \t]+[ \t]+{.*}[ \t]+{[ \t]*$' *tcl

is better. But it's still lacking:

  • The {args} argument to proc can be empty, and it does not require braces.
  • A procname does not have to look like [a-zA-Z][a-zA-Z0-9]*, as in
 ; proc {::namespace::my procedure} oneArg \
 "
 statement1 ; statement2
 "

Here's a Tcl script that mirrors your egrep|awk

    proc process fileName {
        set inProc false
        set lineNo 0
        set fid [open $fileName]
        while {[gets $fid line] != -1} {
            incr lineNo
            if {$inProc} {
                append procBody \n $line
                if {[info complete $procBody]} {
                    emit $fileName $procLineNo $procBody
                    set inProc false
                    unset procBody
                }
            } else {
                set trimmed [string trimleft $line " \t;"]
                if {[regexp {^proc\M} $trimmed]} {
                    set procBody $trimmed
                    set procLineNo $lineNo
                    if {[info complete $procBody]} {
                        emit $fileName $procLineNo $procBody
                        unset procBody
                    } else {
                        set inProc true
                    }
                }
            }
        }
        close $fid
    }

    proc emit {fileName lineNo body} {
        # treat the $body string as a list, in case procName contains whitespace
        set procName [lindex $body 1]
        puts [format "%s\t./%s\t%s;\"\tf" $procName $fileName $lineNo]
    }

    # MAIN
    #
    foreach file $argv {
        process $file
    }

escargo 2 May 2003 - There are many versions of the ctags program around. What do you get when you run ctags --version? I get Exuberant Ctags 5.5..., and it has a command, ctags --list-languages, that outputs the languages it recognizes, including Tcl.

For more utility, it might make sense to code a recognizer that understands the different object-oriented extensions to Tcl so that method or instproc or whatever might be used in different extensions could be easily added.

US 9. Dec. 2003 - For Exuberant Ctags put the following lines into your .ctags file (or /etc/ctags.conf for systemwide usage):

 --langmap=tcl:+.ws3.test
 --regex-tcl=/^[ \t]*(::)?web::command[ \t]+([^ \t]+)[ \t]+\{/\2/c,command/
 --regex-tcl=/^[ \t]*(::)?web::command[ \t]+\{/default/c,command/
 --regex-tcl=/^[ \t]*((::)?tcltest::)?test[ \t]+([^ \t]+)[ \t]+\{/\3/t,tests/
 --regex-tcl=/^(set|variable)[ \t]+([^ \t]+)[ \t]+(.+)/\2/Globals/ 

See also Exuberant Ctags, Tcl etags program (Dunning), Tcl etags program (Emacs), tcltags