diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go
index 2a855a1..c9c70c6 100644
--- a/src/cmd/go/internal/doc/doc.go
+++ b/src/cmd/go/internal/doc/doc.go
@@ -8,7 +8,6 @@
import (
"bytes"
"context"
- "flag"
"fmt"
"go/build"
"go/token"
@@ -22,14 +21,13 @@
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/work"
"cmd/internal/telemetry/counter"
)
var CmdDoc = &base.Command{
- Run: runDoc,
- UsageLine: "go doc [doc flags] [package|[package.]symbol[.methodOrField]]",
- CustomFlags: true,
- Short: "show documentation for package or symbol",
+ UsageLine: "go doc [doc flags] [package|[package.]symbol[.methodOrField]]",
+ Short: "show documentation for package or symbol",
Long: `
Doc prints the documentation comments associated with the item identified by its
arguments (a package, const, func, type, var, method, or struct field)
@@ -141,6 +139,9 @@
the body), type declaration or enclosing const
block. The output may therefore include unexported
details.
+ -tags
+ Show the documentation with when the given build tags
+ are active.
-u
Show documentation for unexported as well as exported
symbols, methods, and fields.
@@ -151,26 +152,32 @@
log.SetFlags(0)
log.SetPrefix("doc: ")
dirsInit()
- var flagSet flag.FlagSet
- err := do(os.Stdout, &flagSet, args)
+ err := do(os.Stdout, args)
if err != nil {
log.Fatal(err)
}
}
var (
- unexported bool // -u flag
- matchCase bool // -c flag
- chdir string // -C flag
- showAll bool // -all flag
- showCmd bool // -cmd flag
- showSrc bool // -src flag
- short bool // -short flag
- serveHTTP bool // -http flag
+ chdir = CmdDoc.Flag.String("C", "", "change to `dir` before running command")
+ unexported = CmdDoc.Flag.Bool("u", false, "show unexported symbols as well as exported")
+ matchCase = CmdDoc.Flag.Bool("c", false, "symbol matching honors case (paths not affected)")
+ showAll = CmdDoc.Flag.Bool("all", false, "show all documentation for package")
+ showCmd = CmdDoc.Flag.Bool("cmd", false, "show symbols with package docs even if package is a command")
+ showSrc = CmdDoc.Flag.Bool("src", false, "show source code for symbol")
+ short = CmdDoc.Flag.Bool("short", false, "one-line representation for each symbol")
+ serveHTTP = CmdDoc.Flag.Bool("http", false, "serve HTML docs over HTTP")
)
+func init() {
+ CmdDoc.Run = runDoc
+
+ CmdDoc.Flag.Var((*work.TagsFlag)(&cfg.BuildContext.BuildTags), "tags", "show documentation matching the build tags")
+ CmdDoc.Flag.Usage = usage
+}
+
// usage is a replacement usage function for the flags package.
-func usage(flagSet *flag.FlagSet) {
+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")
@@ -181,35 +188,24 @@
fmt.Fprintf(os.Stderr, "For more information run\n")
fmt.Fprintf(os.Stderr, "\tgo help doc\n\n")
fmt.Fprintf(os.Stderr, "Flags:\n")
- flagSet.PrintDefaults()
+ CmdDoc.Flag.PrintDefaults()
os.Exit(2)
}
// do is the workhorse, broken out of runDoc to make testing easier.
-func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
- flagSet.Usage = func() { usage(flagSet) }
- unexported = false
- matchCase = false
- flagSet.StringVar(&chdir, "C", "", "change to `dir` before running command")
- 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.BoolVar(&short, "short", false, "one-line representation for each symbol")
- flagSet.BoolVar(&serveHTTP, "http", false, "serve HTML docs over HTTP")
- flagSet.Parse(args)
- counter.CountFlags("doc/flag:", *flag.CommandLine)
- if chdir != "" {
- if err := os.Chdir(chdir); err != nil {
+func do(writer io.Writer, args []string) (err error) {
+ base.SetFromGOFLAGS(&CmdDoc.Flag)
+ counter.CountFlags("doc/flag:", CmdDoc.Flag)
+ if *chdir != "" {
+ if err := os.Chdir(*chdir); err != nil {
return err
}
}
- if serveHTTP {
+ if *serveHTTP {
// Special case: if there are no arguments, try to go to an appropriate page
// depending on whether we're in a module or workspace. The pkgsite homepage
// is often not the most useful page.
- if len(flagSet.Args()) == 0 {
+ if len(args) == 0 {
mod, err := runCmd(append(os.Environ(), "GOWORK=off"), "go", "list", "-m")
if err == nil && mod != "" && mod != "command-line-arguments" {
// If there's a module, go to the module's doc page.
@@ -235,7 +231,7 @@
// Loop until something is printed.
dirs.Reset()
for i := 0; ; i++ {
- buildPackage, userPath, sym, more := parseArgs(flagSet, flagSet.Args())
+ buildPackage, userPath, sym, more := parseArgs(args)
if i > 0 && !more { // Ignore the "more" bit on the first iteration.
return failMessage(paths, symbol, method)
}
@@ -246,10 +242,11 @@
// The builtin package needs special treatment: its symbols are lower
// case but we want to see them, always.
if buildPackage.ImportPath == "builtin" {
- unexported = true
+ t := true
+ unexported = &t
}
- symbol, method = parseSymbol(flagSet, sym)
+ symbol, method = parseSymbol(sym)
pkg := parsePackage(writer, buildPackage, userPath)
paths = append(paths, pkg.prettyPath())
@@ -282,7 +279,7 @@
found = true
}
if found {
- if serveHTTP {
+ if *serveHTTP {
path, fragment, err := objectPath(userPath, pkg, symbol, method)
if err != nil {
return err
@@ -357,7 +354,7 @@
// 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.
-func parseArgs(flagSet *flag.FlagSet, args []string) (pkg *build.Package, path, symbol string, more bool) {
+func parseArgs(args []string) (pkg *build.Package, path, symbol string, more bool) {
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
@@ -375,7 +372,7 @@
}
switch len(args) {
default:
- usage(flagSet)
+ usage()
case 1:
// Done below.
case 2:
@@ -518,7 +515,7 @@
// parseSymbol breaks str apart into a symbol and method.
// Both may be missing or the method may be missing.
// If present, each must be a valid Go identifier.
-func parseSymbol(flagSet *flag.FlagSet, str string) (symbol, method string) {
+func parseSymbol(str string) (symbol, method string) {
if str == "" {
return
}
@@ -529,7 +526,7 @@
method = elem[1]
default:
log.Printf("too many periods in symbol specification")
- usage(flagSet)
+ usage()
}
symbol = elem[0]
return
@@ -539,7 +536,7 @@
// If the unexported flag (-u) is true, isExported returns true because
// it means that we treat the name as if it is exported.
func isExported(name string) bool {
- return unexported || token.IsExported(name)
+ return *unexported || token.IsExported(name)
}
// findNextPackage returns the next full file name path that matches the
diff --git a/src/cmd/go/internal/doc/pkg.go b/src/cmd/go/internal/doc/pkg.go
index 8020807..f1528a8 100644
--- a/src/cmd/go/internal/doc/pkg.go
+++ b/src/cmd/go/internal/doc/pkg.go
@@ -68,7 +68,7 @@
if !pb.printed {
pb.printed = true
// Only show package clause for commands if requested explicitly.
- if pb.pkg.pkg.Name != "main" || showCmd {
+ if pb.pkg.pkg.Name != "main" || *showCmd {
pb.pkg.packageClause()
}
}
@@ -177,7 +177,7 @@
// should fix it in go/doc.
// A similar story applies to factory functions.
mode := doc.AllDecls
- if showSrc {
+ if *showSrc {
mode |= doc.PreserveAST // See comment for Package.emit.
}
docPkg := doc.New(astPkg, pkg.ImportPath, mode)
@@ -245,7 +245,7 @@
func (pkg *Package) emit(comment string, node ast.Node) {
if node != nil {
var arg any = node
- if showSrc {
+ if *showSrc {
// Need an extra little dance to get internal comments to appear.
arg = &printer.CommentedNode{
Node: node,
@@ -256,7 +256,7 @@
if err != nil {
log.Fatal(err)
}
- if comment != "" && !showSrc {
+ if comment != "" && !*showSrc {
pkg.newlines(1)
pkg.ToText(&pkg.buf, comment, indent, indent+indent)
pkg.newlines(2) // Blank line after comment to separate from next item.
@@ -543,25 +543,25 @@
// packageDoc prints the docs for the package.
func (pkg *Package) packageDoc() {
pkg.Printf("") // Trigger the package clause; we know the package exists.
- if showAll || !short {
+ if *showAll || !*short {
pkg.ToText(&pkg.buf, pkg.doc.Doc, "", indent)
pkg.newlines(1)
}
switch {
- case showAll:
+ case *showAll:
printed := make(map[*ast.GenDecl]bool) // valueDoc registry
pkg.constsDoc(printed)
pkg.varsDoc(printed)
pkg.funcsDoc()
pkg.typesDoc()
- case pkg.pkg.Name == "main" && !showCmd:
+ case pkg.pkg.Name == "main" && !*showCmd:
// Show only package docs for commands.
return
default:
- if !short {
+ if !*short {
pkg.newlines(2) // Guarantee blank line before the components.
}
pkg.valueSummary(pkg.doc.Consts, false)
@@ -570,14 +570,14 @@
pkg.typeSummary()
}
- if !short {
+ if !*short {
pkg.bugs()
}
}
// packageClause prints the package clause.
func (pkg *Package) packageClause() {
- if short {
+ if *short {
return
}
importPath := pkg.build.ImportComment
@@ -802,7 +802,7 @@
}
for _, ident := range vspec.Names {
- if showSrc || isExported(ident.Name) {
+ if *showSrc || isExported(ident.Name) {
if vspec.Type == nil && vspec.Values == nil && typ != nil {
// This a standalone identifier, as in the case of iota usage.
// Thus, assume the type comes from the previous type.
@@ -839,7 +839,7 @@
pkg.emit(typ.Doc, decl)
pkg.newlines(2)
// Show associated methods, constants, etc.
- if showAll {
+ if *showAll {
printed := make(map[*ast.GenDecl]bool) // valueDoc registry
// We can use append here to print consts, then vars. Ditto for funcs and methods.
values := typ.Consts
@@ -874,7 +874,7 @@
// structs and methods from interfaces (unless the unexported flag is set or we
// are asked to show the original source).
func trimUnexportedElems(spec *ast.TypeSpec) {
- if showSrc {
+ if *showSrc {
return
}
switch typ := spec.Type.(type) {
@@ -970,7 +970,7 @@
}
// Trims if any is unexported. Good enough in practice.
ok := true
- if !unexported {
+ if !*unexported {
for _, name := range names {
if !isExported(name.Name) {
trimmed = true
@@ -1137,7 +1137,7 @@
if !isExported(program) {
return false
}
- if matchCase {
+ if *matchCase {
return user == program
}
for _, u := range user {
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index 75d05d6..4b22260 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -348,7 +348,7 @@
cmd.Flag.StringVar(&cfg.BuildPGO, "pgo", "auto", "")
cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "")
cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "")
- cmd.Flag.Var((*tagsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
+ cmd.Flag.Var((*TagsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
cmd.Flag.BoolVar(&cfg.BuildTrimpath, "trimpath", false, "")
cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
@@ -371,10 +371,10 @@
}
}
-// tagsFlag is the implementation of the -tags flag.
-type tagsFlag []string
+// TagsFlag is the implementation of the -tags flag.
+type TagsFlag []string
-func (v *tagsFlag) Set(s string) error {
+func (v *TagsFlag) Set(s string) error {
// For compatibility with Go 1.12 and earlier, allow "-tags='a b c'" or even just "-tags='a'".
if strings.Contains(s, " ") || strings.Contains(s, "'") {
return (*base.StringsFlag)(v).Set(s)
@@ -390,7 +390,7 @@
return nil
}
-func (v *tagsFlag) String() string {
+func (v *TagsFlag) String() string {
return "<TagsFlag>"
}