mirror of
https://github.com/golang/go
synced 2024-11-05 15:06:09 -07:00
godoc: Fix commandline mode output.
Fix output of packages with multiple files. Remove extra output when filter is requested. Fixes golang/go#7115. R=bradfitz, adg CC=golang-codereviews https://golang.org/cl/52750044
This commit is contained in:
parent
bf4d636dc9
commit
2ca2bfc172
@ -4,11 +4,9 @@
|
||||
package godoc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/printer"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
@ -106,7 +104,8 @@ func CommandLine(w io.Writer, fs vfs.NameSpace, pres *Presentation, args []strin
|
||||
|
||||
// If we have more than one argument, use the remaining arguments for filtering.
|
||||
if len(args) > 1 {
|
||||
filterInfo(pres, args[1:], info)
|
||||
info.IsFiltered = true
|
||||
filterInfo(args[1:], info)
|
||||
}
|
||||
|
||||
packageText := pres.PackageText
|
||||
@ -145,7 +144,9 @@ func paths(fs vfs.NameSpace, pres *Presentation, path string) (string, string) {
|
||||
return pathpkg.Join(pres.PkgFSRoot(), path), path
|
||||
}
|
||||
|
||||
func filterInfo(pres *Presentation, args []string, info *PageInfo) {
|
||||
// filterInfo updates info to include only the nodes that match the given
|
||||
// filter args.
|
||||
func filterInfo(args []string, info *PageInfo) {
|
||||
rx, err := makeRx(args)
|
||||
if err != nil {
|
||||
log.Fatalf("illegal regular expression from %v: %v", args, err)
|
||||
@ -154,29 +155,21 @@ func filterInfo(pres *Presentation, args []string, info *PageInfo) {
|
||||
filter := func(s string) bool { return rx.MatchString(s) }
|
||||
switch {
|
||||
case info.PAst != nil:
|
||||
cmap := ast.NewCommentMap(info.FSet, info.PAst, info.PAst.Comments)
|
||||
ast.FilterFile(info.PAst, filter)
|
||||
// Special case: Don't use templates for printing
|
||||
// so we only get the filtered declarations without
|
||||
// package clause or extra whitespace.
|
||||
for i, d := range info.PAst.Decls {
|
||||
// determine the comments associated with d only
|
||||
comments := cmap.Filter(d).Comments()
|
||||
cn := &printer.CommentedNode{Node: d, Comments: comments}
|
||||
if i > 0 {
|
||||
fmt.Println()
|
||||
newPAst := map[string]*ast.File{}
|
||||
for name, a := range info.PAst {
|
||||
cmap := ast.NewCommentMap(info.FSet, a, a.Comments)
|
||||
a.Comments = []*ast.CommentGroup{} // remove all comments.
|
||||
ast.FilterFile(a, filter)
|
||||
if len(a.Decls) > 0 {
|
||||
newPAst[name] = a
|
||||
}
|
||||
if pres.HTMLMode {
|
||||
var buf bytes.Buffer
|
||||
pres.WriteNode(&buf, info.FSet, cn)
|
||||
FormatText(os.Stdout, buf.Bytes(), -1, true, "", nil)
|
||||
} else {
|
||||
pres.WriteNode(os.Stdout, info.FSet, cn)
|
||||
for _, d := range a.Decls {
|
||||
// add back the comments associated with d only
|
||||
comments := cmap.Filter(d).Comments()
|
||||
a.Comments = append(a.Comments, comments...)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
return
|
||||
|
||||
info.PAst = newPAst // add only matching files.
|
||||
case info.PDoc != nil:
|
||||
info.PDoc.Filter(filter)
|
||||
}
|
||||
|
@ -157,6 +157,17 @@ func TestCommandLine(t *testing.T) {
|
||||
mfs := mapfs.New(map[string]string{
|
||||
"src/pkg/bar/bar.go": `// Package bar is an example.
|
||||
package bar
|
||||
`,
|
||||
"src/pkg/foo/foo.go": `// Package foo.
|
||||
package foo
|
||||
|
||||
// First function is first.
|
||||
func First() {
|
||||
}
|
||||
|
||||
// Second function is second.
|
||||
func Second() {
|
||||
}
|
||||
`,
|
||||
"src/cmd/go/doc.go": `// The go command
|
||||
package main
|
||||
@ -172,7 +183,10 @@ package main
|
||||
p.cmdHandler = handlerServer{p, c, "/cmd/", "/src/cmd"}
|
||||
p.pkgHandler = handlerServer{p, c, "/pkg/", "/src/pkg"}
|
||||
p.initFuncMap()
|
||||
p.PackageText = template.Must(template.New("PackageText").Funcs(p.FuncMap()).Parse(`{{with .PAst}}{{node $ .}}{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND {{.Doc}}{{else}}PACKAGE {{.Doc}}{{end}}{{end}}`))
|
||||
p.PackageText = template.Must(template.New("PackageText").Funcs(p.FuncMap()).Parse(`{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
|
||||
{{node $ $ast}}{{end}}{{end}}{{with .PDoc}}{{if $.IsMain}}COMMAND {{.Doc}}{{else}}PACKAGE {{.Doc}}{{end}}{{with .Funcs}}
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}{{end}}{{end}}{{end}}`))
|
||||
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
@ -190,10 +204,20 @@ package main
|
||||
args: []string{"bar"},
|
||||
exp: "PACKAGE Package bar is an example.\n",
|
||||
},
|
||||
{
|
||||
desc: "package w. filter",
|
||||
args: []string{"foo", "First"},
|
||||
exp: "PACKAGE \nfunc First()\n First function is first.\n",
|
||||
},
|
||||
{
|
||||
desc: "source mode",
|
||||
args: []string{"src/bar"},
|
||||
exp: "// Package bar is an example.\npackage bar\n",
|
||||
exp: "bar/bar.go:\n// Package bar is an example.\npackage bar\n",
|
||||
},
|
||||
{
|
||||
desc: "source mode w. filter",
|
||||
args: []string{"src/foo", "Second"},
|
||||
exp: "// Second function is second.\nfunc Second() {\n}",
|
||||
},
|
||||
{
|
||||
desc: "command",
|
||||
|
@ -219,12 +219,13 @@ type PageInfo struct {
|
||||
Err error // error or nil
|
||||
|
||||
// package info
|
||||
FSet *token.FileSet // nil if no package documentation
|
||||
PDoc *doc.Package // nil if no package documentation
|
||||
Examples []*doc.Example // nil if no example code
|
||||
Notes map[string][]*doc.Note // nil if no package Notes
|
||||
PAst *ast.File // nil if no AST with package exports
|
||||
IsMain bool // true for package main
|
||||
FSet *token.FileSet // nil if no package documentation
|
||||
PDoc *doc.Package // nil if no package documentation
|
||||
Examples []*doc.Example // nil if no example code
|
||||
Notes map[string][]*doc.Note // nil if no package Notes
|
||||
PAst map[string]*ast.File // nil if no AST with package exports
|
||||
IsMain bool // true for package main
|
||||
IsFiltered bool // true if results were filtered
|
||||
|
||||
// directory info
|
||||
Dirs *DirList // nil if no directory information
|
||||
|
@ -24,7 +24,7 @@ func (c *Corpus) parseFile(fset *token.FileSet, filename string, mode parser.Mod
|
||||
return parser.ParseFile(fset, filename, src, mode)
|
||||
}
|
||||
|
||||
func (c *Corpus) parseFiles(fset *token.FileSet, abspath string, localnames []string) (map[string]*ast.File, error) {
|
||||
func (c *Corpus) parseFiles(fset *token.FileSet, relpath string, abspath string, localnames []string) (map[string]*ast.File, error) {
|
||||
files := make(map[string]*ast.File)
|
||||
for _, f := range localnames {
|
||||
absname := pathpkg.Join(abspath, f)
|
||||
@ -32,7 +32,7 @@ func (c *Corpus) parseFiles(fset *token.FileSet, abspath string, localnames []st
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files[absname] = file
|
||||
files[pathpkg.Join(relpath, f)] = file
|
||||
}
|
||||
|
||||
return files, nil
|
||||
|
@ -97,7 +97,7 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode)
|
||||
if len(pkgfiles) > 0 {
|
||||
// build package AST
|
||||
fset := token.NewFileSet()
|
||||
files, err := h.c.parseFiles(fset, abspath, pkgfiles)
|
||||
files, err := h.c.parseFiles(fset, relpath, abspath, pkgfiles)
|
||||
if err != nil {
|
||||
info.Err = err
|
||||
return info
|
||||
@ -128,7 +128,7 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode)
|
||||
|
||||
// collect examples
|
||||
testfiles := append(pkginfo.TestGoFiles, pkginfo.XTestGoFiles...)
|
||||
files, err = h.c.parseFiles(fset, abspath, testfiles)
|
||||
files, err = h.c.parseFiles(fset, relpath, abspath, testfiles)
|
||||
if err != nil {
|
||||
log.Println("parsing examples:", err)
|
||||
}
|
||||
@ -156,7 +156,7 @@ func (h *handlerServer) GetPageInfo(abspath, relpath string, mode PageInfoMode)
|
||||
if mode&NoFiltering == 0 {
|
||||
packageExports(fset, pkg)
|
||||
}
|
||||
info.PAst = ast.MergePackageFiles(pkg, 0)
|
||||
info.PAst = files
|
||||
}
|
||||
info.IsMain = pkgname == "main"
|
||||
}
|
||||
@ -218,7 +218,10 @@ func (h *handlerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var tabtitle, title, subtitle string
|
||||
switch {
|
||||
case info.PAst != nil:
|
||||
tabtitle = info.PAst.Name.Name
|
||||
for _, ast := range info.PAst {
|
||||
tabtitle = ast.Name.Name
|
||||
break
|
||||
}
|
||||
case info.PDoc != nil:
|
||||
tabtitle = info.PDoc.Name
|
||||
default:
|
||||
|
@ -1,51 +1,56 @@
|
||||
{{with .PAst}}{{node $ .}}{{end}}{{/*
|
||||
{{$info := .}}{{$filtered := .IsFiltered}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
|
||||
{{node $ $ast}}{{end}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION
|
||||
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{else}}PACKAGE DOCUMENTATION
|
||||
{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION
|
||||
|
||||
package {{.Name}}
|
||||
import "{{.ImportPath}}"
|
||||
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ "" " "}}{{/*
|
||||
{{example_text $ "" " "}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Consts}}
|
||||
*/}}{{with .Consts}}{{if not $filtered}}
|
||||
CONSTANTS
|
||||
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Vars}}
|
||||
*/}}{{with .Vars}}{{if not $filtered}}
|
||||
VARIABLES
|
||||
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Funcs}}
|
||||
*/}}{{with .Funcs}}{{if not $filtered}}
|
||||
FUNCTIONS
|
||||
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ .Name " "}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Types}}
|
||||
*/}}{{with .Types}}{{if not $filtered}}
|
||||
TYPES
|
||||
|
||||
{{range .}}{{$tname := .Name}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{range .Consts}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
|
@ -751,54 +751,59 @@ $(document).ready(function() {
|
||||
{{end}}
|
||||
{{end}}
|
||||
`,
|
||||
"package.txt": `{{with .PAst}}{{node $ .}}{{end}}{{/*
|
||||
"package.txt": `{{$info := .}}{{$filtered := .IsFiltered}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{if $filtered}}{{range .PAst}}{{range .Decls}}{{node $info .}}{{end}}{{end}}{{else}}{{with .PAst}}{{range $filename, $ast := .}}{{$filename}}:
|
||||
{{node $ $ast}}{{end}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .PDoc}}{{if $.IsMain}}COMMAND DOCUMENTATION
|
||||
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{else}}PACKAGE DOCUMENTATION
|
||||
{{else}}{{if not $filtered}}PACKAGE DOCUMENTATION
|
||||
|
||||
package {{.Name}}
|
||||
import "{{.ImportPath}}"
|
||||
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ "" " "}}{{/*
|
||||
{{example_text $ "" " "}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Consts}}
|
||||
*/}}{{with .Consts}}{{if not $filtered}}
|
||||
CONSTANTS
|
||||
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Vars}}
|
||||
*/}}{{with .Vars}}{{if not $filtered}}
|
||||
VARIABLES
|
||||
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Funcs}}
|
||||
*/}}{{with .Funcs}}{{if not $filtered}}
|
||||
FUNCTIONS
|
||||
|
||||
{{range .}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{example_text $ .Name " "}}{{end}}{{end}}{{/*
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*/}}{{with .Types}}
|
||||
*/}}{{with .Types}}{{if not $filtered}}
|
||||
TYPES
|
||||
|
||||
{{range .}}{{$tname := .Name}}{{node $ .Decl}}
|
||||
{{end}}{{range .}}{{$tname := .Name}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
{{range .Consts}}{{node $ .Decl}}
|
||||
{{comment_text .Doc " " "\t"}}
|
||||
|
Loading…
Reference in New Issue
Block a user