func parseArgs(args []string) (pkg *build.Package, path, symbol string, more bool) {
	wd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}
	if len(args) == 0 {
		return importDir(wd), "", "", false
	}
	arg := args[0]
	if isDotSlash(arg) {
		arg = filepath.Join(wd, arg)
	}
	switch len(args) {
	default:
		usage()
	case 1:
	case 2:
		pkg, err := build.Import(args[0], wd, build.ImportComment)
		if err == nil {
			return pkg, args[0], args[1], false
		}
		for {
			packagePath, ok := findNextPackage(arg)
			if !ok {
				break
			}
			if pkg, err := build.ImportDir(packagePath, build.ImportComment); err == nil {
				return pkg, arg, args[1], true
			}
		}
		return nil, args[0], args[1], false
	}
	pkg, err = build.Import(arg, wd, build.ImportComment)
	if err == nil {
		return pkg, arg, "", false
	}
	if token.IsExported(arg) {
		pkg, err := build.ImportDir(".", build.ImportComment)
		if err == nil {
			return pkg, "", arg, false
		}
	}
	slash := strings.LastIndex(arg, "/")
	var period int
	for start := slash + 1; start < len(arg); start = period + 1 {
		period = strings.Index(arg[start:], ".")
		symbol := ""
		if period < 0 {
			period = len(arg)
		} else {
			period += start
			symbol = arg[period+1:]
		}
		pkg, err := build.Import(arg[0:period], wd, build.ImportComment)
		if err == nil {
			return pkg, arg[0:period], symbol, false
		}
		pkgName := arg[:period]
		for {
			path, ok := findNextPackage(pkgName)
			if !ok {
				break
			}
			if pkg, err = build.ImportDir(path, build.ImportComment); err == nil {
				return pkg, arg[0:period], symbol, true
			}
		}
		dirs.Reset()  
	}
	if slash >= 0 {
		log.Fatalf("no such package %s", arg[0:period])
	}
	return importDir(wd), "", arg, false
}
parseArgs analyzes the arguments (if any) and returns the package
it represents, the part of the argument the user used to identify
the path (or "" if it's the current package) and the symbol
(possibly with a .method) within that package.
parseSymbol is used to analyze the symbol itself.
The boolean final argument reports whether it is possible that
there may be more directories worth looking at. It will only
be true if the package path is a partial match for some directory
and there may be more matches. For example, if the argument
is rand.Float64, we must scan both crypto/rand and math/rand
to find the symbol, and the first call will return crypto/rand, true.
package main
import (
	"bytes"
	"flag"
	"fmt"
	"github.com/mattn/go-colorable"
	"go/build"
	"go/token"
	"io"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
)
var (
	unexported bool    
	matchCase  bool    
	showAll    bool    
	showCmd    bool    
	showSrc    bool    
	style      string  
)
func usage() {
	fmt.Fprintf(os.Stderr, "Usage of [go] doc:\n")
	fmt.Fprintf(os.Stderr, "\tgo doc\n")
	fmt.Fprintf(os.Stderr, "\tgo doc <pkg>\n")
	fmt.Fprintf(os.Stderr, "\tgo doc <sym>[.<method>]\n")
	fmt.Fprintf(os.Stderr, "\tgo doc [<pkg>].<sym>[.<method>]\n")
	fmt.Fprintf(os.Stderr, "\tgo doc <pkg> <sym>[.<method>]\n")
	fmt.Fprintf(os.Stderr, "For more information run\n")
	fmt.Fprintf(os.Stderr, "\tgo help doc\n\n")
	fmt.Fprintf(os.Stderr, "Flags:\n")
	flag.PrintDefaults()
	os.Exit(2)
}
func main() {
	log.SetFlags(0)
	log.SetPrefix("doc: ")
	dirsInit()
	err := do(colorable.NewColorableStdout(), flag.CommandLine, os.Args[1:])
	if err != nil {
		log.Fatal(err)
	}
}
func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
	flagSet.Usage = usage
	unexported = false
	matchCase = false
	flagSet.BoolVar(&unexported, "u", false, "show unexported symbols as well as exported")
	flagSet.BoolVar(&matchCase, "c", false, "symbol matching honors case (paths not affected)")
	flagSet.BoolVar(&showAll, "all", false, "show all documentation for package")
	flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command")
	flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol")
	flagSet.StringVar(&style, "style", "", "change chroma's style (can also set GDOC_STYLE environment variable, default is 'vim')")
	flagSet.Parse(args)
	var paths []string
	var symbol, method string
	dirs.Reset()
	for i := 0; ; i++ {
		buildPackage, userPath, sym, more := parseArgs(flagSet.Args())
		if i > 0 && !more {  
			return failMessage(paths, symbol, method)
		}
		if buildPackage == nil {
			return fmt.Errorf("no such package: %s", userPath)
		}
		symbol, method = parseSymbol(sym)
		pkg := parsePackage(writer, buildPackage, userPath)
		paths = append(paths, pkg.prettyPath())
		defer func() {
			pkg.flush()
			e := recover()
			if e == nil {
				return
			}
			pkgError, ok := e.(PackageError)
			if ok {
				err = pkgError
				return
			}
			panic(e)
		}()
		if pkg.build.ImportPath == "builtin" {
			unexported = true
		}
		if showAll && symbol == "" {
			pkg.allDoc()
			return
		}
		switch {
		case symbol == "":
			pkg.packageDoc()  
			return
		case method == "":
			if pkg.symbolDoc(symbol) {
				return
			}
		default:
			if pkg.methodDoc(symbol, method) {
				return
			}
			if pkg.fieldDoc(symbol, method) {
				return
			}
		}
	}
}
func failMessage(paths []string, symbol, method string) error {
	var b bytes.Buffer
	if len(paths) > 1 {
		b.WriteString("s")
	}
	b.WriteString(" ")
	for i, path := range paths {
		if i > 0 {
			b.WriteString(", ")
		}
		b.WriteString(path)
	}
	if method == "" {
		return fmt.Errorf("no symbol %s in package%s", symbol, &b)
	}
	return fmt.Errorf("no method or field %s.%s in package%s", symbol, method, &b)
}