mirror of
https://github.com/golang/go
synced 2024-11-22 04:04:40 -07:00
go/printer, godoc: print comments in example code
- go/printer: support for printing CommentedNodes - go/doc: collect comments from examples Fixes #2429. R=adg, rsc CC=golang-dev https://golang.org/cl/5482052
This commit is contained in:
parent
fe746335aa
commit
5fb7e5b482
@ -8,6 +8,7 @@ package doc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/printer"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
|
|
||||||
type Example struct {
|
type Example struct {
|
||||||
Name string // name of the item being demonstrated
|
Name string // name of the item being demonstrated
|
||||||
Body *ast.BlockStmt // code
|
Body *printer.CommentedNode // code
|
||||||
Output string // expected output
|
Output string // expected output
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ func Examples(pkg *ast.Package) []*Example {
|
|||||||
}
|
}
|
||||||
examples = append(examples, &Example{
|
examples = append(examples, &Example{
|
||||||
Name: name[len("Example"):],
|
Name: name[len("Example"):],
|
||||||
Body: f.Body,
|
Body: &printer.CommentedNode{f.Body, src.Comments},
|
||||||
Output: CommentText(f.Doc),
|
Output: CommentText(f.Doc),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -807,13 +807,75 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getNode returns the ast.CommentGroup associated with n, if any.
|
||||||
|
func getDoc(n ast.Node) *ast.CommentGroup {
|
||||||
|
switch n := n.(type) {
|
||||||
|
// *ast.Fields cannot be printed separately - ignore for now
|
||||||
|
case *ast.ImportSpec:
|
||||||
|
return n.Doc
|
||||||
|
case *ast.ValueSpec:
|
||||||
|
return n.Doc
|
||||||
|
case *ast.TypeSpec:
|
||||||
|
return n.Doc
|
||||||
|
case *ast.GenDecl:
|
||||||
|
return n.Doc
|
||||||
|
case *ast.FuncDecl:
|
||||||
|
return n.Doc
|
||||||
|
case *ast.File:
|
||||||
|
return n.Doc
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *printer) printNode(node interface{}) error {
|
func (p *printer) printNode(node interface{}) error {
|
||||||
|
// unpack *CommentedNode, if any
|
||||||
|
var comments []*ast.CommentGroup
|
||||||
|
if cnode, ok := node.(*CommentedNode); ok {
|
||||||
|
node = cnode.Node
|
||||||
|
comments = cnode.Comments
|
||||||
|
}
|
||||||
|
|
||||||
|
if comments != nil {
|
||||||
|
// commented node - restrict comment list to relevant range
|
||||||
|
n, ok := node.(ast.Node)
|
||||||
|
if !ok {
|
||||||
|
goto unsupported
|
||||||
|
}
|
||||||
|
beg := n.Pos()
|
||||||
|
end := n.End()
|
||||||
|
// if the node has associated documentation,
|
||||||
|
// include that commentgroup in the range
|
||||||
|
// (the comment list is sorted in the order
|
||||||
|
// of the comment appearance in the source code)
|
||||||
|
if doc := getDoc(n); doc != nil {
|
||||||
|
beg = doc.Pos()
|
||||||
|
}
|
||||||
|
// token.Pos values are global offsets, we can
|
||||||
|
// compare them directly
|
||||||
|
i := 0
|
||||||
|
for i < len(comments) && comments[i].End() < beg {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
j := i
|
||||||
|
for j < len(comments) && comments[j].Pos() < end {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if i < j {
|
||||||
|
p.comments = comments[i:j]
|
||||||
|
}
|
||||||
|
} else if n, ok := node.(*ast.File); ok {
|
||||||
|
// use ast.File comments, if any
|
||||||
|
p.comments = n.Comments
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there are no comments, use node comments
|
||||||
|
p.useNodeComments = p.comments == nil
|
||||||
|
|
||||||
|
// format node
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case ast.Expr:
|
case ast.Expr:
|
||||||
p.useNodeComments = true
|
|
||||||
p.expr(n, ignoreMultiLine)
|
p.expr(n, ignoreMultiLine)
|
||||||
case ast.Stmt:
|
case ast.Stmt:
|
||||||
p.useNodeComments = true
|
|
||||||
// A labeled statement will un-indent to position the
|
// A labeled statement will un-indent to position the
|
||||||
// label. Set indent to 1 so we don't get indent "underflow".
|
// label. Set indent to 1 so we don't get indent "underflow".
|
||||||
if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
|
if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
|
||||||
@ -821,19 +883,19 @@ func (p *printer) printNode(node interface{}) error {
|
|||||||
}
|
}
|
||||||
p.stmt(n, false, ignoreMultiLine)
|
p.stmt(n, false, ignoreMultiLine)
|
||||||
case ast.Decl:
|
case ast.Decl:
|
||||||
p.useNodeComments = true
|
|
||||||
p.decl(n, ignoreMultiLine)
|
p.decl(n, ignoreMultiLine)
|
||||||
case ast.Spec:
|
case ast.Spec:
|
||||||
p.useNodeComments = true
|
|
||||||
p.spec(n, 1, false, ignoreMultiLine)
|
p.spec(n, 1, false, ignoreMultiLine)
|
||||||
case *ast.File:
|
case *ast.File:
|
||||||
p.comments = n.Comments
|
|
||||||
p.useNodeComments = n.Comments == nil
|
|
||||||
p.file(n)
|
p.file(n)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("go/printer: unsupported node type %T", n)
|
goto unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
unsupported:
|
||||||
|
return fmt.Errorf("go/printer: unsupported node type %T", node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -1001,10 +1063,18 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A CommentedNode bundles an AST node and corresponding comments.
|
||||||
|
// It may be provided as argument to any of the FPrint functions.
|
||||||
|
//
|
||||||
|
type CommentedNode struct {
|
||||||
|
Node interface{} // *ast.File, or ast.Expr, ast.Decl, ast.Spec, or ast.Stmt
|
||||||
|
Comments []*ast.CommentGroup
|
||||||
|
}
|
||||||
|
|
||||||
// Fprint "pretty-prints" an AST node to output for a given configuration cfg.
|
// Fprint "pretty-prints" an AST node to output for a given configuration cfg.
|
||||||
// Position information is interpreted relative to the file set fset.
|
// Position information is interpreted relative to the file set fset.
|
||||||
// The node type must be *ast.File, or assignment-compatible to ast.Expr,
|
// The node type must be *ast.File, *CommentedNode, or assignment-compatible
|
||||||
// ast.Decl, ast.Spec, or ast.Stmt.
|
// to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
|
||||||
//
|
//
|
||||||
func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
|
func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
|
||||||
return cfg.fprint(output, fset, node, make(map[ast.Node]int))
|
return cfg.fprint(output, fset, node, make(map[ast.Node]int))
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
// [1 2 3 4 5 6]
|
// [1 2 3 4 5 6]
|
||||||
func ExampleInts() {
|
func ExampleInts() {
|
||||||
s := []int{5, 2, 6, 3, 1, 4}
|
s := []int{5, 2, 6, 3, 1, 4} // unsorted
|
||||||
sort.Ints(s)
|
sort.Ints(s)
|
||||||
fmt.Println(s)
|
fmt.Println(s)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user