mirror of
https://github.com/golang/go.git
synced 2025-05-31 23:25:39 +00:00
cmd/go: better UI for go doc
Print it out much like godoc so there isn't a single block of text. Print the symbol before its comment and indent the comment so individual symbols separate visually. Buffer the output. Add a -c option to force case-sensitive matching. Allow two arguments, like godoc, to help disambiguate cases where path and symbol may be confused. Improve the documentation printed by go help doc. Change-Id: If687aad04bbacdf7dbe4bf7636de9fe96f756fd0 Reviewed-on: https://go-review.googlesource.com/9471 Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
c26fc88d56
commit
06946aad19
@ -2,14 +2,26 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Doc (usually run as go doc) accepts zero or one argument, interpreted as:
|
// Doc (usually run as go doc) accepts zero, one or two arguments.
|
||||||
|
//
|
||||||
|
// Zero arguments:
|
||||||
// go doc
|
// go doc
|
||||||
|
// Show the documentation for the package in the current directory.
|
||||||
|
//
|
||||||
|
// One argument:
|
||||||
// go doc <pkg>
|
// go doc <pkg>
|
||||||
// go doc <sym>[.<method>]
|
// go doc <sym>[.<method>]
|
||||||
// go doc [<pkg>].<sym>[.<method>]
|
// go doc [<pkg>].<sym>[.<method>]
|
||||||
// The first item in this list that succeeds is the one whose documentation
|
// The first item in this list that succeeds is the one whose documentation
|
||||||
// is printed. If there is no argument, the package in the current directory
|
// is printed. If there is a symbol but no package, the package in the current
|
||||||
// is chosen.
|
// directory is chosen.
|
||||||
|
//
|
||||||
|
// Two arguments:
|
||||||
|
// go doc <pkg> <sym>[.<method>]
|
||||||
|
//
|
||||||
|
// Show the documentation for the package, symbol, and method. The
|
||||||
|
// first argument must be a full package path. This is similar to the
|
||||||
|
// command-line usage for the godoc command.
|
||||||
//
|
//
|
||||||
// For complete documentation, run "go help doc".
|
// For complete documentation, run "go help doc".
|
||||||
package main
|
package main
|
||||||
@ -28,14 +40,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
unexported bool
|
unexported = flag.Bool("u", false, "show unexported symbols as well as exported")
|
||||||
|
matchCase = flag.Bool("c", false, "symbol matching honors case (paths not affected)")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.BoolVar(&unexported, "unexported", false, "show unexported symbols as well as exported")
|
|
||||||
flag.BoolVar(&unexported, "u", false, "shorthand for -unexported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// usage is a replacement usage function for the flags package.
|
// usage is a replacement usage function for the flags package.
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage of [go] doc:\n")
|
fmt.Fprintf(os.Stderr, "Usage of [go] doc:\n")
|
||||||
@ -43,6 +51,7 @@ func usage() {
|
|||||||
fmt.Fprintf(os.Stderr, "\tgo doc <pkg>\n")
|
fmt.Fprintf(os.Stderr, "\tgo doc <pkg>\n")
|
||||||
fmt.Fprintf(os.Stderr, "\tgo doc <sym>[.<method>]\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, "\tgo doc <pkg> <sym>[.<method>]\n")
|
||||||
fmt.Fprintf(os.Stderr, "For more information run\n")
|
fmt.Fprintf(os.Stderr, "For more information run\n")
|
||||||
fmt.Fprintf(os.Stderr, "\tgo help doc\n\n")
|
fmt.Fprintf(os.Stderr, "\tgo help doc\n\n")
|
||||||
fmt.Fprintf(os.Stderr, "Flags:\n")
|
fmt.Fprintf(os.Stderr, "Flags:\n")
|
||||||
@ -55,9 +64,9 @@ func main() {
|
|||||||
log.SetPrefix("doc: ")
|
log.SetPrefix("doc: ")
|
||||||
flag.Usage = usage
|
flag.Usage = usage
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
buildPackage, symbol := parseArg()
|
buildPackage, userPath, symbol := parseArgs()
|
||||||
symbol, method := parseSymbol(symbol)
|
symbol, method := parseSymbol(symbol)
|
||||||
pkg := parsePackage(buildPackage)
|
pkg := parsePackage(buildPackage, userPath)
|
||||||
switch {
|
switch {
|
||||||
case symbol == "":
|
case symbol == "":
|
||||||
pkg.packageDoc()
|
pkg.packageDoc()
|
||||||
@ -69,18 +78,27 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseArg analyzes the argument (if any) and returns the package
|
// parseArgs analyzes the arguments (if any) and returns the package
|
||||||
// it represents and the symbol (possibly with a .method) within that
|
// it represents, the part of the argument the user used to identify
|
||||||
// package. parseSymbol is used to analyze the symbol itself.
|
// the path (or "" if it's the current package) and the symbol
|
||||||
func parseArg() (*build.Package, string) {
|
// (possibly with a .method) within that package.
|
||||||
|
// parseSymbol is used to analyze the symbol itself.
|
||||||
|
func parseArgs() (*build.Package, string, string) {
|
||||||
switch flag.NArg() {
|
switch flag.NArg() {
|
||||||
default:
|
default:
|
||||||
usage()
|
usage()
|
||||||
case 0:
|
case 0:
|
||||||
// Easy: current directory.
|
// Easy: current directory.
|
||||||
return importDir("."), ""
|
return importDir("."), "", ""
|
||||||
case 1:
|
case 1:
|
||||||
// Done below.
|
// Done below.
|
||||||
|
case 2:
|
||||||
|
// Package must be importable.
|
||||||
|
pkg, err := build.Import(flag.Arg(0), "", build.ImportComment)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return pkg, flag.Arg(0), flag.Arg(1)
|
||||||
}
|
}
|
||||||
// Usual case: one argument.
|
// Usual case: one argument.
|
||||||
arg := flag.Arg(0)
|
arg := flag.Arg(0)
|
||||||
@ -90,17 +108,16 @@ func parseArg() (*build.Package, string) {
|
|||||||
// package paths as their prefix.
|
// package paths as their prefix.
|
||||||
pkg, err := build.Import(arg, "", build.ImportComment)
|
pkg, err := build.Import(arg, "", build.ImportComment)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return pkg, ""
|
return pkg, arg, ""
|
||||||
}
|
}
|
||||||
// Another disambiguator: If the symbol starts with an upper
|
// Another disambiguator: If the symbol starts with an upper
|
||||||
// case letter, it can only be a symbol in the current directory.
|
// case letter, it can only be a symbol in the current directory.
|
||||||
// Kills the problem caused by case-insensitive file systems
|
// Kills the problem caused by case-insensitive file systems
|
||||||
// matching an upper case name as a package name.
|
// matching an upper case name as a package name.
|
||||||
if isUpper(arg) {
|
if isUpper(arg) {
|
||||||
println("HERE", arg)
|
|
||||||
pkg, err := build.ImportDir(".", build.ImportComment)
|
pkg, err := build.ImportDir(".", build.ImportComment)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return pkg, arg
|
return pkg, "", arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If it has a slash, it must be a package path but there is a symbol.
|
// If it has a slash, it must be a package path but there is a symbol.
|
||||||
@ -125,16 +142,13 @@ func parseArg() (*build.Package, string) {
|
|||||||
// Have we identified a package already?
|
// Have we identified a package already?
|
||||||
pkg, err := build.Import(arg[0:period], "", build.ImportComment)
|
pkg, err := build.Import(arg[0:period], "", build.ImportComment)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return pkg, symbol
|
return pkg, arg[0:period], symbol
|
||||||
}
|
}
|
||||||
// See if we have the basename or tail of a package, as in json for encoding/json
|
// See if we have the basename or tail of a package, as in json for encoding/json
|
||||||
// or ivy/value for robpike.io/ivy/value.
|
// or ivy/value for robpike.io/ivy/value.
|
||||||
path := findPackage(arg[0:period])
|
path := findPackage(arg[0:period])
|
||||||
if path != "" {
|
if path != "" {
|
||||||
return importDir(path), symbol
|
return importDir(path), arg[0:period], symbol
|
||||||
}
|
|
||||||
if path != "" {
|
|
||||||
return importDir(path), symbol
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If it has a slash, we've failed.
|
// If it has a slash, we've failed.
|
||||||
@ -142,7 +156,7 @@ func parseArg() (*build.Package, string) {
|
|||||||
log.Fatalf("no such package %s", arg[0:period])
|
log.Fatalf("no such package %s", arg[0:period])
|
||||||
}
|
}
|
||||||
// Guess it's a symbol in the current directory.
|
// Guess it's a symbol in the current directory.
|
||||||
return importDir("."), arg
|
return importDir("."), "", arg
|
||||||
}
|
}
|
||||||
|
|
||||||
// importDir is just an error-catching wrapper for build.ImportDir.
|
// importDir is just an error-catching wrapper for build.ImportDir.
|
||||||
@ -194,7 +208,7 @@ func isIdentifier(name string) {
|
|||||||
// If the unexported flag (-u) is true, isExported returns true because
|
// If the unexported flag (-u) is true, isExported returns true because
|
||||||
// it means that we treat the name as if it is exported.
|
// it means that we treat the name as if it is exported.
|
||||||
func isExported(name string) bool {
|
func isExported(name string) bool {
|
||||||
return unexported || isUpper(name)
|
return *unexported || isUpper(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isUpper reports whether the name starts with an upper case letter.
|
// isUpper reports whether the name starts with an upper case letter.
|
||||||
|
@ -20,17 +20,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
name string // Package name, json for encoding/json.
|
name string // Package name, json for encoding/json.
|
||||||
pkg *ast.Package // Parsed package.
|
userPath string // String the user used to find this package.
|
||||||
file *ast.File // Merged from all files in the package
|
pkg *ast.Package // Parsed package.
|
||||||
doc *doc.Package
|
file *ast.File // Merged from all files in the package
|
||||||
build *build.Package
|
doc *doc.Package
|
||||||
fs *token.FileSet // Needed for printing.
|
build *build.Package
|
||||||
|
fs *token.FileSet // Needed for printing.
|
||||||
|
buf bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsePackage turns the build package we found into a parsed package
|
// parsePackage turns the build package we found into a parsed package
|
||||||
// we can then use to generate documentation.
|
// we can then use to generate documentation.
|
||||||
func parsePackage(pkg *build.Package) *Package {
|
func parsePackage(pkg *build.Package, userPath string) *Package {
|
||||||
fs := token.NewFileSet()
|
fs := token.NewFileSet()
|
||||||
// include tells parser.ParseDir which files to include.
|
// include tells parser.ParseDir which files to include.
|
||||||
// That means the file must be in the build package's GoFiles or CgoFiles
|
// That means the file must be in the build package's GoFiles or CgoFiles
|
||||||
@ -73,35 +75,54 @@ func parsePackage(pkg *build.Package) *Package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Package{
|
return &Package{
|
||||||
name: pkg.Name,
|
name: pkg.Name,
|
||||||
pkg: astPkg,
|
userPath: userPath,
|
||||||
file: ast.MergePackageFiles(astPkg, 0),
|
pkg: astPkg,
|
||||||
doc: docPkg,
|
file: ast.MergePackageFiles(astPkg, 0),
|
||||||
build: pkg,
|
doc: docPkg,
|
||||||
fs: fs,
|
build: pkg,
|
||||||
|
fs: fs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var formatBuf bytes.Buffer // One instance to minimize allocation. TODO: Buffer all output.
|
func (pkg *Package) Printf(format string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(&pkg.buf, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pkg *Package) flush() {
|
||||||
|
_, err := os.Stdout.Write(pkg.buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
pkg.buf.Reset() // Not needed, but it's a flush.
|
||||||
|
}
|
||||||
|
|
||||||
|
var newlineBytes = []byte("\n\n") // We never ask for more than 2.
|
||||||
|
|
||||||
|
// newlines guarantees there are n newlines at the end of the buffer.
|
||||||
|
func (pkg *Package) newlines(n int) {
|
||||||
|
for !bytes.HasSuffix(pkg.buf.Bytes(), newlineBytes[:n]) {
|
||||||
|
pkg.buf.WriteRune('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// emit prints the node.
|
// emit prints the node.
|
||||||
func (pkg *Package) emit(comment string, node ast.Node) {
|
func (pkg *Package) emit(comment string, node ast.Node) {
|
||||||
if node != nil {
|
if node != nil {
|
||||||
formatBuf.Reset()
|
err := format.Node(&pkg.buf, pkg.fs, node)
|
||||||
if comment != "" {
|
|
||||||
doc.ToText(&formatBuf, comment, "", "\t", 80)
|
|
||||||
}
|
|
||||||
err := format.Node(&formatBuf, pkg.fs, node)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
if formatBuf.Len() > 0 && formatBuf.Bytes()[formatBuf.Len()-1] != '\n' {
|
if comment != "" {
|
||||||
formatBuf.WriteRune('\n')
|
pkg.newlines(1)
|
||||||
|
doc.ToText(&pkg.buf, comment, " ", "\t", 80)
|
||||||
}
|
}
|
||||||
os.Stdout.Write(formatBuf.Bytes())
|
pkg.newlines(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var formatBuf bytes.Buffer // Reusable to avoid allocation.
|
||||||
|
|
||||||
// formatNode is a helper function for printing.
|
// formatNode is a helper function for printing.
|
||||||
func (pkg *Package) formatNode(node ast.Node) []byte {
|
func (pkg *Package) formatNode(node ast.Node) []byte {
|
||||||
formatBuf.Reset()
|
formatBuf.Reset()
|
||||||
@ -137,7 +158,7 @@ func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) {
|
|||||||
if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
|
if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
|
||||||
val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
|
val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
|
||||||
}
|
}
|
||||||
fmt.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
|
pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,28 +169,21 @@ func (pkg *Package) oneLineTypeDecl(spec *ast.TypeSpec) {
|
|||||||
spec.Comment = nil
|
spec.Comment = nil
|
||||||
switch spec.Type.(type) {
|
switch spec.Type.(type) {
|
||||||
case *ast.InterfaceType:
|
case *ast.InterfaceType:
|
||||||
fmt.Printf("type %s interface { ... }\n", spec.Name)
|
pkg.Printf("type %s interface { ... }\n", spec.Name)
|
||||||
case *ast.StructType:
|
case *ast.StructType:
|
||||||
fmt.Printf("type %s struct { ... }\n", spec.Name)
|
pkg.Printf("type %s struct { ... }\n", spec.Name)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("type %s %s\n", spec.Name, pkg.formatNode(spec.Type))
|
pkg.Printf("type %s %s\n", spec.Name, pkg.formatNode(spec.Type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
|
// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
|
||||||
// TODO: Sort the output.
|
|
||||||
func (pkg *Package) packageDoc() {
|
func (pkg *Package) packageDoc() {
|
||||||
// Package comment.
|
defer pkg.flush()
|
||||||
importPath := pkg.build.ImportComment
|
pkg.packageClause(false)
|
||||||
if importPath == "" {
|
|
||||||
importPath = pkg.build.ImportPath
|
doc.ToText(&pkg.buf, pkg.doc.Doc, "", "\t", 80)
|
||||||
}
|
pkg.newlines(2)
|
||||||
fmt.Printf("package %s // import %q\n\n", pkg.name, importPath)
|
|
||||||
if importPath != pkg.build.ImportPath {
|
|
||||||
fmt.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
|
|
||||||
}
|
|
||||||
doc.ToText(os.Stdout, pkg.doc.Doc, "", "\t", 80)
|
|
||||||
fmt.Print("\n")
|
|
||||||
|
|
||||||
pkg.valueSummary(pkg.doc.Consts)
|
pkg.valueSummary(pkg.doc.Consts)
|
||||||
pkg.valueSummary(pkg.doc.Vars)
|
pkg.valueSummary(pkg.doc.Vars)
|
||||||
@ -177,6 +191,26 @@ func (pkg *Package) packageDoc() {
|
|||||||
pkg.typeSummary()
|
pkg.typeSummary()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// packageClause prints the package clause.
|
||||||
|
// The argument boolean, if true, suppresses the output if the
|
||||||
|
// user's argument is identical to the actual package path or
|
||||||
|
// is empty, meaning it's the current directory.
|
||||||
|
func (pkg *Package) packageClause(checkUserPath bool) {
|
||||||
|
if checkUserPath {
|
||||||
|
if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
importPath := pkg.build.ImportComment
|
||||||
|
if importPath == "" {
|
||||||
|
importPath = pkg.build.ImportPath
|
||||||
|
}
|
||||||
|
pkg.Printf("package %s // import %q\n\n", pkg.name, importPath)
|
||||||
|
if importPath != pkg.build.ImportPath {
|
||||||
|
pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// valueSummary prints a one-line summary for each set of values and constants.
|
// valueSummary prints a one-line summary for each set of values and constants.
|
||||||
func (pkg *Package) valueSummary(values []*doc.Value) {
|
func (pkg *Package) valueSummary(values []*doc.Value) {
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
@ -265,9 +299,13 @@ func (pkg *Package) findTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec
|
|||||||
// symbolDoc prints the docs for symbol. There may be multiple matches.
|
// symbolDoc prints the docs for symbol. There may be multiple matches.
|
||||||
// If symbol matches a type, output includes its methods factories and associated constants.
|
// If symbol matches a type, output includes its methods factories and associated constants.
|
||||||
func (pkg *Package) symbolDoc(symbol string) {
|
func (pkg *Package) symbolDoc(symbol string) {
|
||||||
|
defer pkg.flush()
|
||||||
found := false
|
found := false
|
||||||
// Functions.
|
// Functions.
|
||||||
for _, fun := range pkg.findFuncs(symbol) {
|
for _, fun := range pkg.findFuncs(symbol) {
|
||||||
|
if !found {
|
||||||
|
pkg.packageClause(true)
|
||||||
|
}
|
||||||
// Symbol is a function.
|
// Symbol is a function.
|
||||||
decl := fun.Decl
|
decl := fun.Decl
|
||||||
decl.Body = nil
|
decl.Body = nil
|
||||||
@ -278,11 +316,17 @@ func (pkg *Package) symbolDoc(symbol string) {
|
|||||||
values := pkg.findValues(symbol, pkg.doc.Consts)
|
values := pkg.findValues(symbol, pkg.doc.Consts)
|
||||||
values = append(values, pkg.findValues(symbol, pkg.doc.Vars)...)
|
values = append(values, pkg.findValues(symbol, pkg.doc.Vars)...)
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
|
if !found {
|
||||||
|
pkg.packageClause(true)
|
||||||
|
}
|
||||||
pkg.emit(value.Doc, value.Decl)
|
pkg.emit(value.Doc, value.Decl)
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
// Types.
|
// Types.
|
||||||
for _, typ := range pkg.findTypes(symbol) {
|
for _, typ := range pkg.findTypes(symbol) {
|
||||||
|
if !found {
|
||||||
|
pkg.packageClause(true)
|
||||||
|
}
|
||||||
decl := typ.Decl
|
decl := typ.Decl
|
||||||
spec := pkg.findTypeSpec(decl, typ.Name)
|
spec := pkg.findTypeSpec(decl, typ.Name)
|
||||||
trimUnexportedFields(spec)
|
trimUnexportedFields(spec)
|
||||||
@ -306,7 +350,7 @@ func (pkg *Package) symbolDoc(symbol string) {
|
|||||||
// trimUnexportedFields modifies spec in place to elide unexported fields (unless
|
// trimUnexportedFields modifies spec in place to elide unexported fields (unless
|
||||||
// the unexported flag is set). If spec is not a structure declartion, nothing happens.
|
// the unexported flag is set). If spec is not a structure declartion, nothing happens.
|
||||||
func trimUnexportedFields(spec *ast.TypeSpec) {
|
func trimUnexportedFields(spec *ast.TypeSpec) {
|
||||||
if unexported {
|
if *unexported {
|
||||||
// We're printing all fields.
|
// We're printing all fields.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -349,6 +393,7 @@ func trimUnexportedFields(spec *ast.TypeSpec) {
|
|||||||
|
|
||||||
// methodDoc prints the docs for matches of symbol.method.
|
// methodDoc prints the docs for matches of symbol.method.
|
||||||
func (pkg *Package) methodDoc(symbol, method string) {
|
func (pkg *Package) methodDoc(symbol, method string) {
|
||||||
|
defer pkg.flush()
|
||||||
types := pkg.findTypes(symbol)
|
types := pkg.findTypes(symbol)
|
||||||
if types == nil {
|
if types == nil {
|
||||||
log.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
|
log.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
|
||||||
@ -376,6 +421,9 @@ func match(user, program string) bool {
|
|||||||
if !isExported(program) {
|
if !isExported(program) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if *matchCase {
|
||||||
|
return user == program
|
||||||
|
}
|
||||||
for _, u := range user {
|
for _, u := range user {
|
||||||
p, w := utf8.DecodeRuneInString(program)
|
p, w := utf8.DecodeRuneInString(program)
|
||||||
program = program[w:]
|
program = program[w:]
|
||||||
|
@ -188,41 +188,52 @@ Show documentation for package or symbol
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
go doc [-u] [package|[package.]symbol[.method]]
|
go doc [-u] [-c] [package|[package.]symbol[.method]]
|
||||||
|
|
||||||
Doc accepts at most one argument, indicating either a package, a symbol within a
|
Doc prints the documentation comments associated with the item identified by its
|
||||||
package, or a method of a symbol.
|
arguments (a package, const, func, type, var, or method) followed by a one-line
|
||||||
|
summary of each of the first-level items "under" that item (package-level declarations
|
||||||
|
for a package, methods for a type, etc.).
|
||||||
|
|
||||||
|
Doc accepts zero, one, or two arguments.
|
||||||
|
|
||||||
|
Given no arguments, that is, when run as
|
||||||
|
|
||||||
go doc
|
go doc
|
||||||
|
|
||||||
|
it prints the package documentation for the package in the current directory.
|
||||||
|
|
||||||
|
When run with one argument, the argument is treated as a Go-syntax-like representation
|
||||||
|
of the item to be documented. What the argument selects depends on what is installed
|
||||||
|
in GOROOT and GOPATH, as well as the form of the argument, which is schematically
|
||||||
|
one of these:
|
||||||
|
|
||||||
go doc <pkg>
|
go doc <pkg>
|
||||||
go doc <sym>[.<method>]
|
go doc <sym>[.<method>]
|
||||||
go doc [<pkg>].<sym>[.<method>]
|
go doc [<pkg>].<sym>[.<method>]
|
||||||
|
|
||||||
Doc interprets the argument to see what it represents, determined by its syntax
|
The first item in this list matched by the argument is the one whose documentation
|
||||||
and which packages and symbols are present in the source directories of GOROOT and
|
is printed. (See the examples below.) For packages, the order of scanning is
|
||||||
GOPATH.
|
determined lexically, but the GOROOT tree is always scanned before GOPATH.
|
||||||
|
|
||||||
The first item in this list that succeeds is the one whose documentation is printed.
|
|
||||||
For packages, the order of scanning is determined lexically, however the GOROOT
|
|
||||||
tree is always scanned before GOPATH.
|
|
||||||
|
|
||||||
If there is no package specified or matched, the package in the current directory
|
If there is no package specified or matched, the package in the current directory
|
||||||
is selected, so "go doc" shows the documentation for the current package and
|
is selected, so "go doc Foo" shows the documentation for symbol Foo in the current
|
||||||
"go doc Foo" shows the documentation for symbol Foo in the current package.
|
package.
|
||||||
|
|
||||||
Doc prints the documentation comments associated with the top-level item the
|
The package path must be either a qualified path or a proper suffix of a path. The
|
||||||
argument identifies (package, type, method) followed by a one-line summary of each
|
go tool's usual package mechanism does not apply: package path elements like . and
|
||||||
of the first-level items "under" that item (package-level declarations for a
|
... are not implemented by go doc.
|
||||||
package, methods for a type, etc.).
|
|
||||||
|
|
||||||
The package paths must be either a qualified path or a proper suffix of a path
|
When run with two arguments, the first must be a full package path (not just a
|
||||||
(see examples below). The go tool's usual package mechanism does not apply: package
|
suffix), and the second is a symbol or symbol and method; this is similar to the
|
||||||
path elements like . and ... are not implemented by go doc.
|
syntax accepted by godoc:
|
||||||
|
|
||||||
When matching symbols, lower-case letters match either case but upper-case letters
|
go doc <pkg> <sym>[.<method>]
|
||||||
match exactly. This means that there may be multiple matches in a package if
|
|
||||||
different symbols have different cases. If this occurs, documentation for all
|
In all forms, when matching symbols, lower-case letters in the argument match
|
||||||
matches is printed.
|
either case but upper-case letters match exactly. This means that there may be
|
||||||
|
multiple matches of a lower-case argument in a package if different symbols have
|
||||||
|
different cases. If this occurs, documentation for all matches is printed.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
go doc
|
go doc
|
||||||
@ -238,8 +249,17 @@ Examples:
|
|||||||
Show documentation and method summary for json.Number.
|
Show documentation and method summary for json.Number.
|
||||||
go doc json.Number.Int64 (or go doc json.number.int64)
|
go doc json.Number.Int64 (or go doc json.number.int64)
|
||||||
Show documentation for json.Number's Int64 method.
|
Show documentation for json.Number's Int64 method.
|
||||||
|
go doc template.new
|
||||||
|
Show documentation for html/template's New function.
|
||||||
|
(html/template is lexically before text/template)
|
||||||
|
go doc text/template.new # One argument
|
||||||
|
Show documentation for text/template's New function.
|
||||||
|
go doc text/template new # Two arguments
|
||||||
|
Show documentation for text/template's New function.
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
-c
|
||||||
|
Respect case when matching symbols.
|
||||||
-u
|
-u
|
||||||
Show documentation for unexported as well as exported
|
Show documentation for unexported as well as exported
|
||||||
symbols and methods.
|
symbols and methods.
|
||||||
|
@ -6,43 +6,55 @@ package main
|
|||||||
|
|
||||||
var cmdDoc = &Command{
|
var cmdDoc = &Command{
|
||||||
Run: runDoc,
|
Run: runDoc,
|
||||||
UsageLine: "doc [-u] [package|[package.]symbol[.method]]",
|
UsageLine: "doc [-u] [-c] [package|[package.]symbol[.method]]",
|
||||||
CustomFlags: true,
|
CustomFlags: true,
|
||||||
Short: "show documentation for package or symbol",
|
Short: "show documentation for package or symbol",
|
||||||
Long: `
|
Long: `
|
||||||
Doc accepts at most one argument, indicating either a package, a symbol within a
|
|
||||||
package, or a method of a symbol.
|
Doc prints the documentation comments associated with the item identified by its
|
||||||
|
arguments (a package, const, func, type, var, or method) followed by a one-line
|
||||||
|
summary of each of the first-level items "under" that item (package-level declarations
|
||||||
|
for a package, methods for a type, etc.).
|
||||||
|
|
||||||
|
Doc accepts zero, one, or two arguments.
|
||||||
|
|
||||||
|
Given no arguments, that is, when run as
|
||||||
|
|
||||||
go doc
|
go doc
|
||||||
|
|
||||||
|
it prints the package documentation for the package in the current directory.
|
||||||
|
|
||||||
|
When run with one argument, the argument is treated as a Go-syntax-like representation
|
||||||
|
of the item to be documented. What the argument selects depends on what is installed
|
||||||
|
in GOROOT and GOPATH, as well as the form of the argument, which is schematically
|
||||||
|
one of these:
|
||||||
|
|
||||||
go doc <pkg>
|
go doc <pkg>
|
||||||
go doc <sym>[.<method>]
|
go doc <sym>[.<method>]
|
||||||
go doc [<pkg>].<sym>[.<method>]
|
go doc [<pkg>].<sym>[.<method>]
|
||||||
|
|
||||||
Doc interprets the argument to see what it represents, determined by its syntax
|
The first item in this list matched by the argument is the one whose documentation
|
||||||
and which packages and symbols are present in the source directories of GOROOT and
|
is printed. (See the examples below.) For packages, the order of scanning is
|
||||||
GOPATH.
|
determined lexically, but the GOROOT tree is always scanned before GOPATH.
|
||||||
|
|
||||||
The first item in this list that succeeds is the one whose documentation is printed.
|
|
||||||
For packages, the order of scanning is determined lexically, however the GOROOT
|
|
||||||
tree is always scanned before GOPATH.
|
|
||||||
|
|
||||||
If there is no package specified or matched, the package in the current directory
|
If there is no package specified or matched, the package in the current directory
|
||||||
is selected, so "go doc" shows the documentation for the current package and
|
is selected, so "go doc Foo" shows the documentation for symbol Foo in the current
|
||||||
"go doc Foo" shows the documentation for symbol Foo in the current package.
|
package.
|
||||||
|
|
||||||
Doc prints the documentation comments associated with the top-level item the
|
The package path must be either a qualified path or a proper suffix of a path. The
|
||||||
argument identifies (package, type, method) followed by a one-line summary of each
|
go tool's usual package mechanism does not apply: package path elements like . and
|
||||||
of the first-level items "under" that item (package-level declarations for a
|
... are not implemented by go doc.
|
||||||
package, methods for a type, etc.).
|
|
||||||
|
|
||||||
The package paths must be either a qualified path or a proper suffix of a path
|
When run with two arguments, the first must be a full package path (not just a
|
||||||
(see examples below). The go tool's usual package mechanism does not apply: package
|
suffix), and the second is a symbol or symbol and method; this is similar to the
|
||||||
path elements like . and ... are not implemented by go doc.
|
syntax accepted by godoc:
|
||||||
|
|
||||||
When matching symbols, lower-case letters match either case but upper-case letters
|
go doc <pkg> <sym>[.<method>]
|
||||||
match exactly. This means that there may be multiple matches in a package if
|
|
||||||
different symbols have different cases. If this occurs, documentation for all
|
In all forms, when matching symbols, lower-case letters in the argument match
|
||||||
matches is printed.
|
either case but upper-case letters match exactly. This means that there may be
|
||||||
|
multiple matches of a lower-case argument in a package if different symbols have
|
||||||
|
different cases. If this occurs, documentation for all matches is printed.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
go doc
|
go doc
|
||||||
@ -58,8 +70,17 @@ Examples:
|
|||||||
Show documentation and method summary for json.Number.
|
Show documentation and method summary for json.Number.
|
||||||
go doc json.Number.Int64 (or go doc json.number.int64)
|
go doc json.Number.Int64 (or go doc json.number.int64)
|
||||||
Show documentation for json.Number's Int64 method.
|
Show documentation for json.Number's Int64 method.
|
||||||
|
go doc template.new
|
||||||
|
Show documentation for html/template's New function.
|
||||||
|
(html/template is lexically before text/template)
|
||||||
|
go doc text/template.new # One argument
|
||||||
|
Show documentation for text/template's New function.
|
||||||
|
go doc text/template new # Two arguments
|
||||||
|
Show documentation for text/template's New function.
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
-c
|
||||||
|
Respect case when matching symbols.
|
||||||
-u
|
-u
|
||||||
Show documentation for unexported as well as exported
|
Show documentation for unexported as well as exported
|
||||||
symbols and methods.
|
symbols and methods.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user