Source

gotags / gotags.go

Full commit
//  gotags generates a tags file for the Go Programming Language in the format used by exuberant-ctags.
//  Copyright (C) 2009  Michael R. Elkins <me@sigpipe.org>
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Date: 2009-11-12
// Updated: 2010-08-21
// Updated: 2011-06-23
//    Sean E. Russell <seanerussell@gmail.com>
//    Fixed numerous compilation errors; the go APIs probably changed since the
//    last time Michael updated it.
// Updated: 2012-03-29
//    Erno Hopearuoho <erno.hopearuoho@cs.helsinki.fi>
//    Updated to work with Go 1.

//
// usage: gotags filename [ filename... ] > tags
//

package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"sort"
)

var (
	tags []string = make([]string, 0, 20)
)

func output_tag(fset *token.FileSet, name *ast.Ident, kind byte) {
	position := fset.Position(name.NamePos)
	tags = append(tags, fmt.Sprintf("%s\t%s\t%d;\"\t%c",
		name.Name, position.Filename, position.Line, kind))
}

func main() {
	if len(os.Args) <= 1 {
		fmt.Println("usage: gotags filename [ filename... ] > tags")
		os.Exit(1)
	}
	parse_files()

	fmt.Println("!_TAG_FILE_SORTED\t1\t")
	sort.Strings(tags)
	for _, s := range tags {
		fmt.Println(s)
	}
}

const FUNC, TYPE, VAR = 'f', 't', 'v'

func parse_files() {
	for _, f := range os.Args[1:] {
		fileset := token.NewFileSet()
		fi, err := os.Lstat(f)
		if err != nil {
			log.Fatalf("error opening file %s: %s", f, err.Error())
		}
		fileset.AddFile(f, fileset.Base(), int(fi.Size()))
		tree, err := parser.ParseFile(fileset, f, nil, 0)
		if err != nil {
		}

		for _, node := range tree.Decls {
			switch n := node.(type) {
			case *ast.FuncDecl:
				output_tag(fileset, n.Name, FUNC)
			case *ast.GenDecl:
				do_gen_decl(fileset, n)
			}
		}
	}

}

func do_gen_decl(fset *token.FileSet, node *ast.GenDecl) {
	for _, v := range node.Specs {
		switch n := v.(type) {
		case *ast.TypeSpec:
			output_tag(fset, n.Name, TYPE)

		case *ast.ValueSpec:
			for _, vv := range n.Names {
				output_tag(fset, vv, VAR)
			}
		}
	}
}