mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/doc: add -all flag to print all documentation for package
Unlike the one for the old godoc, you need the -u flag to see unexported symbols. This seems like the right behavior: it's consistent. For now at least, the argument must be a package, not a symbol. This is also different from old godoc. Required a little refactoring but also cleaned up a few things. Update #25595 Leaving the bug open for now until we tackle go doc -all symbol Change-Id: Ibc1975bfa592cb1e92513eb2e5e9e11e01a60095 Reviewed-on: https://go-review.googlesource.com/c/141977 Run-TryBot: Rob Pike <r@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
ee76992200
commit
101a677ebf
5 changed files with 327 additions and 92 deletions
|
|
@ -147,6 +147,69 @@ var tests = []test{
|
|||
`type T1 T2`, // Type alias does not display as type declaration.
|
||||
},
|
||||
},
|
||||
// Package dump -all
|
||||
{
|
||||
"full package",
|
||||
[]string{"-all", p},
|
||||
[]string{
|
||||
`package pkg .*import`,
|
||||
`Package comment`,
|
||||
`CONSTANTS`,
|
||||
`Comment before ConstOne`,
|
||||
`ConstOne = 1`,
|
||||
`ConstTwo = 2 // Comment on line with ConstTwo`,
|
||||
`ConstFive`,
|
||||
`ConstSix`,
|
||||
`Const block where first entry is unexported`,
|
||||
`ConstLeft2, constRight2 uint64`,
|
||||
`constLeft3, ConstRight3`,
|
||||
`ConstLeft4, ConstRight4`,
|
||||
`Duplicate = iota`,
|
||||
`const CaseMatch = 1`,
|
||||
`const Casematch = 2`,
|
||||
`const ExportedConstant = 1`,
|
||||
`const MultiLineConst = `,
|
||||
`MultiLineString1`,
|
||||
`VARIABLES`,
|
||||
`Comment before VarOne`,
|
||||
`VarOne = 1`,
|
||||
`Comment about block of variables`,
|
||||
`VarFive = 5`,
|
||||
`var ExportedVariable = 1`,
|
||||
`var LongLine = newLongLine\(`,
|
||||
`var MultiLineVar = map\[struct {`,
|
||||
`FUNCTIONS`,
|
||||
`func ExportedFunc\(a int\) bool`,
|
||||
`Comment about exported function`,
|
||||
`func MultiLineFunc\(x interface`,
|
||||
`func ReturnUnexported\(\) unexportedType`,
|
||||
`TYPES`,
|
||||
`type ExportedInterface interface`,
|
||||
`type ExportedStructOneField struct`,
|
||||
`type ExportedType struct`,
|
||||
`Comment about exported type`,
|
||||
`const ConstGroup4 ExportedType = ExportedType`,
|
||||
`ExportedTypedConstant ExportedType = iota`,
|
||||
`Constants tied to ExportedType`,
|
||||
`func ExportedTypeConstructor\(\) \*ExportedType`,
|
||||
`Comment about constructor for exported type`,
|
||||
`func ReturnExported\(\) ExportedType`,
|
||||
`func \(ExportedType\) ExportedMethod\(a int\) bool`,
|
||||
`Comment about exported method`,
|
||||
`type T1 = T2`,
|
||||
`type T2 int`,
|
||||
},
|
||||
[]string{
|
||||
`constThree`,
|
||||
`_, _ uint64 = 2 \* iota, 1 << iota`,
|
||||
`constLeft1, constRight1`,
|
||||
`duplicate`,
|
||||
`varFour`,
|
||||
`func internalFunc`,
|
||||
`unexportedField`,
|
||||
`func \(unexportedType\)`,
|
||||
},
|
||||
},
|
||||
// Package dump -u
|
||||
{
|
||||
"full package with u",
|
||||
|
|
@ -164,6 +227,58 @@ var tests = []test{
|
|||
`MultiLine(String|Method|Field)`, // No data from multi line portions.
|
||||
},
|
||||
},
|
||||
// Package dump -u -all
|
||||
{
|
||||
"full package",
|
||||
[]string{"-u", "-all", p},
|
||||
[]string{
|
||||
`package pkg .*import`,
|
||||
`Package comment`,
|
||||
`CONSTANTS`,
|
||||
`Comment before ConstOne`,
|
||||
`ConstOne += 1`,
|
||||
`ConstTwo += 2 // Comment on line with ConstTwo`,
|
||||
`constThree = 3 // Comment on line with constThree`,
|
||||
`ConstFive`,
|
||||
`const internalConstant += 2`,
|
||||
`Comment about internal constant`,
|
||||
`VARIABLES`,
|
||||
`Comment before VarOne`,
|
||||
`VarOne += 1`,
|
||||
`Comment about block of variables`,
|
||||
`varFour += 4`,
|
||||
`VarFive += 5`,
|
||||
`varSix += 6`,
|
||||
`var ExportedVariable = 1`,
|
||||
`var LongLine = newLongLine\(`,
|
||||
`var MultiLineVar = map\[struct {`,
|
||||
`var internalVariable = 2`,
|
||||
`Comment about internal variable`,
|
||||
`FUNCTIONS`,
|
||||
`func ExportedFunc\(a int\) bool`,
|
||||
`Comment about exported function`,
|
||||
`func MultiLineFunc\(x interface`,
|
||||
`func internalFunc\(a int\) bool`,
|
||||
`Comment about internal function`,
|
||||
`func newLongLine\(ss .*string\)`,
|
||||
`TYPES`,
|
||||
`type ExportedType struct`,
|
||||
`type T1 = T2`,
|
||||
`type T2 int`,
|
||||
`type unexportedType int`,
|
||||
`Comment about unexported type`,
|
||||
`ConstGroup1 unexportedType = iota`,
|
||||
`ConstGroup2`,
|
||||
`ConstGroup3`,
|
||||
`ExportedTypedConstant_unexported unexportedType = iota`,
|
||||
`Constants tied to unexportedType`,
|
||||
`const unexportedTypedConstant unexportedType = 1`,
|
||||
`func ReturnUnexported\(\) unexportedType`,
|
||||
`func \(unexportedType\) ExportedMethod\(\) bool`,
|
||||
`func \(unexportedType\) unexportedMethod\(\) bool`,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
|
||||
// Single constant.
|
||||
{
|
||||
|
|
@ -361,7 +476,6 @@ var tests = []test{
|
|||
`io.Reader.*Comment on line with embedded Reader`,
|
||||
},
|
||||
[]string{
|
||||
`int.*embedded`, // No unexported embedded field.
|
||||
`Comment about exported method`, // No comment about exported method.
|
||||
`unexportedMethod`, // No unexported method.
|
||||
`unexportedTypedConstant`, // No unexported constant.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
// The -src flag causes doc to print the full source code for the symbol, such
|
||||
// as the body of a struct, function or method.
|
||||
//
|
||||
// The -all flag causes doc to print all documentation for the package and
|
||||
// all its visible symbols. The argument must identify a package.
|
||||
//
|
||||
// For complete documentation, run "go help doc".
|
||||
package main
|
||||
|
||||
|
|
@ -52,6 +55,7 @@ import (
|
|||
var (
|
||||
unexported bool // -u flag
|
||||
matchCase bool // -c flag
|
||||
showAll bool // -all flag
|
||||
showCmd bool // -cmd flag
|
||||
showSrc bool // -src flag
|
||||
)
|
||||
|
|
@ -88,6 +92,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
|
|||
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.Parse(args)
|
||||
|
|
@ -127,6 +132,15 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
|
|||
unexported = true
|
||||
}
|
||||
|
||||
// We have a package.
|
||||
if showAll {
|
||||
if symbol != "" {
|
||||
return fmt.Errorf("-all valid only for package, not symbol: %s", symbol)
|
||||
}
|
||||
pkg.allDoc()
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case symbol == "":
|
||||
pkg.packageDoc() // The package exists, so we got some output.
|
||||
|
|
|
|||
|
|
@ -29,15 +29,18 @@ const (
|
|||
)
|
||||
|
||||
type Package struct {
|
||||
writer io.Writer // Destination for output.
|
||||
name string // Package name, json for encoding/json.
|
||||
userPath string // String the user used to find this package.
|
||||
pkg *ast.Package // Parsed package.
|
||||
file *ast.File // Merged from all files in the package
|
||||
doc *doc.Package
|
||||
build *build.Package
|
||||
fs *token.FileSet // Needed for printing.
|
||||
buf bytes.Buffer
|
||||
writer io.Writer // Destination for output.
|
||||
name string // Package name, json for encoding/json.
|
||||
userPath string // String the user used to find this package.
|
||||
pkg *ast.Package // Parsed package.
|
||||
file *ast.File // Merged from all files in the package
|
||||
doc *doc.Package
|
||||
build *build.Package
|
||||
typedValue map[*doc.Value]bool // Consts and vars related to types.
|
||||
constructor map[*doc.Func]bool // Constructors.
|
||||
packageClausePrinted bool // Prevent repeated package clauses.
|
||||
fs *token.FileSet // Needed for printing.
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
type PackageError string // type returned by pkg.Fatalf.
|
||||
|
|
@ -142,21 +145,38 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
|
|||
mode |= doc.PreserveAST // See comment for Package.emit.
|
||||
}
|
||||
docPkg := doc.New(astPkg, pkg.ImportPath, mode)
|
||||
typedValue := make(map[*doc.Value]bool)
|
||||
constructor := make(map[*doc.Func]bool)
|
||||
for _, typ := range docPkg.Types {
|
||||
docPkg.Consts = append(docPkg.Consts, typ.Consts...)
|
||||
for _, value := range typ.Consts {
|
||||
typedValue[value] = true
|
||||
}
|
||||
docPkg.Vars = append(docPkg.Vars, typ.Vars...)
|
||||
for _, value := range typ.Vars {
|
||||
typedValue[value] = true
|
||||
}
|
||||
docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
|
||||
for _, fun := range typ.Funcs {
|
||||
// We don't count it as a constructor bound to the type
|
||||
// if the type itself is not exported.
|
||||
if isExported(typ.Name) {
|
||||
constructor[fun] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &Package{
|
||||
writer: writer,
|
||||
name: pkg.Name,
|
||||
userPath: userPath,
|
||||
pkg: astPkg,
|
||||
file: ast.MergePackageFiles(astPkg, 0),
|
||||
doc: docPkg,
|
||||
build: pkg,
|
||||
fs: fs,
|
||||
writer: writer,
|
||||
name: pkg.Name,
|
||||
userPath: userPath,
|
||||
pkg: astPkg,
|
||||
file: ast.MergePackageFiles(astPkg, 0),
|
||||
doc: docPkg,
|
||||
typedValue: typedValue,
|
||||
constructor: constructor,
|
||||
build: pkg,
|
||||
fs: fs,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -390,6 +410,68 @@ func joinStrings(ss []string) string {
|
|||
return strings.Join(ss, ", ")
|
||||
}
|
||||
|
||||
// allDoc prints all the docs for the package.
|
||||
func (pkg *Package) allDoc() {
|
||||
defer pkg.flush()
|
||||
if pkg.showInternals() {
|
||||
pkg.packageClause(false)
|
||||
}
|
||||
|
||||
doc.ToText(&pkg.buf, pkg.doc.Doc, "", indent, indentedWidth)
|
||||
pkg.newlines(1)
|
||||
|
||||
printed := make(map[*ast.GenDecl]bool)
|
||||
|
||||
hdr := ""
|
||||
printHdr := func(s string) {
|
||||
if hdr != s {
|
||||
pkg.Printf("\n%s\n\n", s)
|
||||
}
|
||||
}
|
||||
|
||||
// Constants.
|
||||
for _, value := range pkg.doc.Consts {
|
||||
// Constants and variables come in groups, and valueDoc prints
|
||||
// all the items in the group. We only need to find one exported symbol.
|
||||
for _, name := range value.Names {
|
||||
if isExported(name) && !pkg.typedValue[value] {
|
||||
printHdr("CONSTANTS")
|
||||
pkg.valueDoc(value, printed)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Variables.
|
||||
for _, value := range pkg.doc.Vars {
|
||||
// Constants and variables come in groups, and valueDoc prints
|
||||
// all the items in the group. We only need to find one exported symbol.
|
||||
for _, name := range value.Names {
|
||||
if isExported(name) && !pkg.typedValue[value] {
|
||||
printHdr("VARIABLES")
|
||||
pkg.valueDoc(value, printed)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Functions.
|
||||
for _, fun := range pkg.doc.Funcs {
|
||||
if isExported(fun.Name) && !pkg.constructor[fun] {
|
||||
printHdr("FUNCTIONS")
|
||||
pkg.emit(fun.Doc, fun.Decl)
|
||||
}
|
||||
}
|
||||
|
||||
// Types.
|
||||
for _, typ := range pkg.doc.Types {
|
||||
if isExported(typ.Name) {
|
||||
printHdr("TYPES")
|
||||
pkg.typeDoc(typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
|
||||
func (pkg *Package) packageDoc() {
|
||||
defer pkg.flush()
|
||||
|
|
@ -426,6 +508,10 @@ func (pkg *Package) showInternals() bool {
|
|||
// 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 pkg.packageClausePrinted {
|
||||
return
|
||||
}
|
||||
|
||||
if checkUserPath {
|
||||
if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
|
||||
return
|
||||
|
|
@ -463,6 +549,7 @@ func (pkg *Package) packageClause(checkUserPath bool) {
|
|||
if !usingModules && importPath != pkg.build.ImportPath {
|
||||
pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
|
||||
}
|
||||
pkg.packageClausePrinted = true
|
||||
}
|
||||
|
||||
// valueSummary prints a one-line summary for each set of values and constants.
|
||||
|
|
@ -497,22 +584,10 @@ func (pkg *Package) valueSummary(values []*doc.Value, showGrouped bool) {
|
|||
// funcSummary prints a one-line summary for each function. Constructors
|
||||
// are printed by typeSummary, below, and so can be suppressed here.
|
||||
func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
|
||||
// First, identify the constructors. Don't bother figuring out if they're exported.
|
||||
var isConstructor map[*doc.Func]bool
|
||||
if !showConstructors {
|
||||
isConstructor = make(map[*doc.Func]bool)
|
||||
for _, typ := range pkg.doc.Types {
|
||||
if isExported(typ.Name) {
|
||||
for _, f := range typ.Funcs {
|
||||
isConstructor[f] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, fun := range funcs {
|
||||
// Exported functions only. The go/doc package does not include methods here.
|
||||
if isExported(fun.Name) {
|
||||
if !isConstructor[fun] {
|
||||
if showConstructors || !pkg.constructor[fun] {
|
||||
pkg.Printf("%s\n", pkg.oneLineNode(fun.Decl))
|
||||
}
|
||||
}
|
||||
|
|
@ -629,71 +704,12 @@ func (pkg *Package) symbolDoc(symbol string) bool {
|
|||
// So we remember which declarations we've printed to avoid duplication.
|
||||
printed := make(map[*ast.GenDecl]bool)
|
||||
for _, value := range values {
|
||||
// Print each spec only if there is at least one exported symbol in it.
|
||||
// (See issue 11008.)
|
||||
// TODO: Should we elide unexported symbols from a single spec?
|
||||
// It's an unlikely scenario, probably not worth the trouble.
|
||||
// TODO: Would be nice if go/doc did this for us.
|
||||
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
|
||||
var typ ast.Expr
|
||||
for _, spec := range value.Decl.Specs {
|
||||
vspec := spec.(*ast.ValueSpec)
|
||||
|
||||
// The type name may carry over from a previous specification in the
|
||||
// case of constants and iota.
|
||||
if vspec.Type != nil {
|
||||
typ = vspec.Type
|
||||
}
|
||||
|
||||
for _, ident := range vspec.Names {
|
||||
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.
|
||||
vspec.Type = &ast.Ident{
|
||||
Name: pkg.oneLineNode(typ),
|
||||
NamePos: vspec.End() - 1,
|
||||
}
|
||||
}
|
||||
|
||||
specs = append(specs, vspec)
|
||||
typ = nil // Only inject type on first exported identifier
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(specs) == 0 || printed[value.Decl] {
|
||||
continue
|
||||
}
|
||||
value.Decl.Specs = specs
|
||||
if !found {
|
||||
pkg.packageClause(true)
|
||||
}
|
||||
pkg.emit(value.Doc, value.Decl)
|
||||
printed[value.Decl] = true
|
||||
pkg.valueDoc(value, printed)
|
||||
found = true
|
||||
}
|
||||
// Types.
|
||||
for _, typ := range pkg.findTypes(symbol) {
|
||||
if !found {
|
||||
pkg.packageClause(true)
|
||||
}
|
||||
decl := typ.Decl
|
||||
spec := pkg.findTypeSpec(decl, typ.Name)
|
||||
trimUnexportedElems(spec)
|
||||
// If there are multiple types defined, reduce to just this one.
|
||||
if len(decl.Specs) > 1 {
|
||||
decl.Specs = []ast.Spec{spec}
|
||||
}
|
||||
pkg.emit(typ.Doc, decl)
|
||||
// Show associated methods, constants, etc.
|
||||
if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
|
||||
pkg.Printf("\n")
|
||||
}
|
||||
pkg.valueSummary(typ.Consts, true)
|
||||
pkg.valueSummary(typ.Vars, true)
|
||||
pkg.funcSummary(typ.Funcs, true)
|
||||
pkg.funcSummary(typ.Methods, true)
|
||||
pkg.typeDoc(typ)
|
||||
found = true
|
||||
}
|
||||
if !found {
|
||||
|
|
@ -705,6 +721,93 @@ func (pkg *Package) symbolDoc(symbol string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// valueDoc prints the docs for a constant or variable.
|
||||
func (pkg *Package) valueDoc(value *doc.Value, printed map[*ast.GenDecl]bool) {
|
||||
if printed[value.Decl] {
|
||||
return
|
||||
}
|
||||
// Print each spec only if there is at least one exported symbol in it.
|
||||
// (See issue 11008.)
|
||||
// TODO: Should we elide unexported symbols from a single spec?
|
||||
// It's an unlikely scenario, probably not worth the trouble.
|
||||
// TODO: Would be nice if go/doc did this for us.
|
||||
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
|
||||
var typ ast.Expr
|
||||
for _, spec := range value.Decl.Specs {
|
||||
vspec := spec.(*ast.ValueSpec)
|
||||
|
||||
// The type name may carry over from a previous specification in the
|
||||
// case of constants and iota.
|
||||
if vspec.Type != nil {
|
||||
typ = vspec.Type
|
||||
}
|
||||
|
||||
for _, ident := range vspec.Names {
|
||||
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.
|
||||
vspec.Type = &ast.Ident{
|
||||
Name: pkg.oneLineNode(typ),
|
||||
NamePos: vspec.End() - 1,
|
||||
}
|
||||
}
|
||||
|
||||
specs = append(specs, vspec)
|
||||
typ = nil // Only inject type on first exported identifier
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(specs) == 0 {
|
||||
return
|
||||
}
|
||||
value.Decl.Specs = specs
|
||||
pkg.emit(value.Doc, value.Decl)
|
||||
printed[value.Decl] = true
|
||||
}
|
||||
|
||||
// typeDoc prints the docs for a type, including constructors and other items
|
||||
// related to it.
|
||||
func (pkg *Package) typeDoc(typ *doc.Type) {
|
||||
decl := typ.Decl
|
||||
spec := pkg.findTypeSpec(decl, typ.Name)
|
||||
trimUnexportedElems(spec)
|
||||
// If there are multiple types defined, reduce to just this one.
|
||||
if len(decl.Specs) > 1 {
|
||||
decl.Specs = []ast.Spec{spec}
|
||||
}
|
||||
pkg.emit(typ.Doc, decl)
|
||||
pkg.newlines(2)
|
||||
// Show associated methods, constants, etc.
|
||||
if showAll {
|
||||
printed := make(map[*ast.GenDecl]bool)
|
||||
// We can use append here to print consts, then vars. Ditto for funcs and methods.
|
||||
values := typ.Consts
|
||||
values = append(values, typ.Vars...)
|
||||
for _, value := range values {
|
||||
for _, name := range value.Names {
|
||||
if isExported(name) {
|
||||
pkg.valueDoc(value, printed)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
funcs := typ.Funcs
|
||||
funcs = append(funcs, typ.Methods...)
|
||||
for _, fun := range funcs {
|
||||
if isExported(fun.Name) {
|
||||
pkg.emit(fun.Doc, fun.Decl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pkg.valueSummary(typ.Consts, true)
|
||||
pkg.valueSummary(typ.Vars, true)
|
||||
pkg.funcSummary(typ.Funcs, true)
|
||||
pkg.funcSummary(typ.Methods, true)
|
||||
}
|
||||
}
|
||||
|
||||
// trimUnexportedElems modifies spec in place to elide unexported fields from
|
||||
// structs and methods from interfaces (unless the unexported flag is set or we
|
||||
// are asked to show the original source).
|
||||
|
|
|
|||
|
|
@ -342,6 +342,8 @@
|
|||
// cd go/src/encoding/json; go doc decode
|
||||
//
|
||||
// Flags:
|
||||
// -all
|
||||
// Show all the documentation for the package.
|
||||
// -c
|
||||
// Respect case when matching symbols.
|
||||
// -cmd
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ Examples:
|
|||
cd go/src/encoding/json; go doc decode
|
||||
|
||||
Flags:
|
||||
-all
|
||||
Show all the documentation for the package.
|
||||
-c
|
||||
Respect case when matching symbols.
|
||||
-cmd
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue