mirror of
https://github.com/golang/go
synced 2024-11-25 03:07:56 -07:00
go/printer: use general comment intersperse mechanism everywhere
- remove several TODOs - as a side-effect, comment stylers are now used always and comments will be properly colored in godoc pkg documentation pages (and not only when looking at source text) R=rsc CC=golang-dev https://golang.org/cl/222041
This commit is contained in:
parent
16192c2d10
commit
228903c5da
@ -12,6 +12,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -59,43 +60,25 @@ func (p *printer) linebreak(line, min, max int, ws whiteSpace, newSection bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(gri): The code for printing lead and line comments
|
// setComment sets g as the next comment if g != nil and if node comments
|
||||||
// should be eliminated in favor of reusing the
|
// are enabled - this mode is used when printing source code fragments such
|
||||||
// comment intersperse mechanism above somehow.
|
// as exports only. It assumes that there are no other pending comments to
|
||||||
|
// intersperse.
|
||||||
// Print a list of individual comments.
|
func (p *printer) setComment(g *ast.CommentGroup) {
|
||||||
func (p *printer) commentList(list []*ast.Comment) {
|
if g == nil || !p.useNodeComments {
|
||||||
for i, c := range list {
|
return
|
||||||
t := c.Text
|
|
||||||
// TODO(gri): this needs to be styled like normal comments
|
|
||||||
p.print(c.Pos(), t)
|
|
||||||
if t[1] == '/' && i+1 < len(list) {
|
|
||||||
//-style comment which is not at the end; print a newline
|
|
||||||
p.print(newline)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if p.comments == nil {
|
||||||
|
// initialize p.comments lazily
|
||||||
|
p.comments = make([]*ast.CommentGroup, 1)
|
||||||
// Print a lead comment followed by a newline.
|
} else if p.cindex < len(p.comments) {
|
||||||
func (p *printer) leadComment(d *ast.CommentGroup) {
|
// for some reason there are pending comments; this
|
||||||
// Ignore the comment if we have comments interspersed (p.comment != nil).
|
// should never happen - handle gracefully and flush
|
||||||
if p.comments == nil && d != nil {
|
// all comments up to g, ignore anything after that
|
||||||
p.commentList(d.List)
|
p.flush(g.List[0].Pos(), false)
|
||||||
p.print(newline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Print a tab followed by a line comment.
|
|
||||||
// A newline must be printed afterwards since
|
|
||||||
// the comment may be a //-style comment.
|
|
||||||
func (p *printer) lineComment(d *ast.CommentGroup) {
|
|
||||||
// Ignore the comment if we have comments interspersed (p.comment != nil).
|
|
||||||
if p.comments == nil && d != nil {
|
|
||||||
p.print(vtab)
|
|
||||||
p.commentList(d.List)
|
|
||||||
}
|
}
|
||||||
|
p.comments[0] = g
|
||||||
|
p.cindex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -307,6 +290,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (p *printer) setLineComment(text string) {
|
||||||
|
p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{noPos, strings.Bytes(text)}}})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete bool, ctxt exprContext) {
|
func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete bool, ctxt exprContext) {
|
||||||
if !isIncomplete && !p.commentBefore(rbrace) {
|
if !isIncomplete && !p.commentBefore(rbrace) {
|
||||||
// possibly a one-line struct/interface
|
// possibly a one-line struct/interface
|
||||||
@ -350,7 +338,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
|
|||||||
}
|
}
|
||||||
ml = false
|
ml = false
|
||||||
extraTabs := 0
|
extraTabs := 0
|
||||||
p.leadComment(f.Doc)
|
p.setComment(f.Doc)
|
||||||
if len(f.Names) > 0 {
|
if len(f.Names) > 0 {
|
||||||
// named fields
|
// named fields
|
||||||
p.identList(f.Names, &ml)
|
p.identList(f.Names, &ml)
|
||||||
@ -372,17 +360,17 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
|
|||||||
}
|
}
|
||||||
if f.Comment != nil {
|
if f.Comment != nil {
|
||||||
for ; extraTabs > 0; extraTabs-- {
|
for ; extraTabs > 0; extraTabs-- {
|
||||||
p.print(vtab)
|
p.print(sep)
|
||||||
}
|
}
|
||||||
p.lineComment(f.Comment)
|
p.setComment(f.Comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isIncomplete {
|
if isIncomplete {
|
||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
p.print(formfeed)
|
p.print(formfeed)
|
||||||
}
|
}
|
||||||
// TODO(gri): this needs to be styled like normal comments
|
p.flush(rbrace, false) // make sure we don't loose the last line comment
|
||||||
p.print("// contains unexported fields")
|
p.setLineComment("// contains unexported fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // interface
|
} else { // interface
|
||||||
@ -393,7 +381,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
|
|||||||
p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
|
p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
|
||||||
}
|
}
|
||||||
ml = false
|
ml = false
|
||||||
p.leadComment(f.Doc)
|
p.setComment(f.Doc)
|
||||||
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
|
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
|
||||||
// method
|
// method
|
||||||
p.expr(f.Names[0], &ml)
|
p.expr(f.Names[0], &ml)
|
||||||
@ -402,14 +390,14 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
|
|||||||
// embedded interface
|
// embedded interface
|
||||||
p.expr(f.Type, &ml)
|
p.expr(f.Type, &ml)
|
||||||
}
|
}
|
||||||
p.lineComment(f.Comment)
|
p.setComment(f.Comment)
|
||||||
}
|
}
|
||||||
if isIncomplete {
|
if isIncomplete {
|
||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
p.print(formfeed)
|
p.print(formfeed)
|
||||||
}
|
}
|
||||||
// TODO(gri): this needs to be styled like normal comments
|
p.flush(rbrace, false) // make sure we don't loose the last line comment
|
||||||
p.print("// contains unexported methods")
|
p.setLineComment("// contains unexported methods")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1052,7 +1040,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
|
|||||||
|
|
||||||
switch s := spec.(type) {
|
switch s := spec.(type) {
|
||||||
case *ast.ImportSpec:
|
case *ast.ImportSpec:
|
||||||
p.leadComment(s.Doc)
|
p.setComment(s.Doc)
|
||||||
if s.Name != nil {
|
if s.Name != nil {
|
||||||
p.expr(s.Name, multiLine)
|
p.expr(s.Name, multiLine)
|
||||||
p.print(blank)
|
p.print(blank)
|
||||||
@ -1061,7 +1049,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
|
|||||||
comment = s.Comment
|
comment = s.Comment
|
||||||
|
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
p.leadComment(s.Doc)
|
p.setComment(s.Doc)
|
||||||
p.identList(s.Names, multiLine) // always present
|
p.identList(s.Names, multiLine) // always present
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
if s.Type != nil {
|
if s.Type != nil {
|
||||||
@ -1091,7 +1079,7 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
|
|||||||
comment = s.Comment
|
comment = s.Comment
|
||||||
|
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
p.leadComment(s.Doc)
|
p.setComment(s.Doc)
|
||||||
p.expr(s.Name, multiLine)
|
p.expr(s.Name, multiLine)
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
p.print(blank)
|
p.print(blank)
|
||||||
@ -1109,14 +1097,14 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo
|
|||||||
for ; extraTabs > 0; extraTabs-- {
|
for ; extraTabs > 0; extraTabs-- {
|
||||||
p.print(vtab)
|
p.print(vtab)
|
||||||
}
|
}
|
||||||
p.lineComment(comment)
|
p.setComment(comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Sets multiLine to true if the declaration spans multiple lines.
|
// Sets multiLine to true if the declaration spans multiple lines.
|
||||||
func (p *printer) genDecl(d *ast.GenDecl, context declContext, multiLine *bool) {
|
func (p *printer) genDecl(d *ast.GenDecl, context declContext, multiLine *bool) {
|
||||||
p.leadComment(d.Doc)
|
p.setComment(d.Doc)
|
||||||
p.print(d.Pos(), d.Tok, blank)
|
p.print(d.Pos(), d.Tok, blank)
|
||||||
|
|
||||||
if d.Lparen.IsValid() {
|
if d.Lparen.IsValid() {
|
||||||
@ -1225,7 +1213,7 @@ func distance(from, to token.Position) int {
|
|||||||
|
|
||||||
// Sets multiLine to true if the declaration spans multiple lines.
|
// Sets multiLine to true if the declaration spans multiple lines.
|
||||||
func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
|
func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
|
||||||
p.leadComment(d.Doc)
|
p.setComment(d.Doc)
|
||||||
p.print(d.Pos(), token.FUNC, blank)
|
p.print(d.Pos(), token.FUNC, blank)
|
||||||
if recv := d.Recv; recv != nil {
|
if recv := d.Recv; recv != nil {
|
||||||
// method: print receiver
|
// method: print receiver
|
||||||
@ -1276,7 +1264,7 @@ func declToken(decl ast.Decl) (tok token.Token) {
|
|||||||
|
|
||||||
|
|
||||||
func (p *printer) file(src *ast.File) {
|
func (p *printer) file(src *ast.File) {
|
||||||
p.leadComment(src.Doc)
|
p.setComment(src.Doc)
|
||||||
p.print(src.Pos(), token.PACKAGE, blank)
|
p.print(src.Pos(), token.PACKAGE, blank)
|
||||||
p.expr(src.Name, ignoreMultiLine)
|
p.expr(src.Name, ignoreMultiLine)
|
||||||
|
|
||||||
|
@ -89,8 +89,9 @@ type printer struct {
|
|||||||
lastTaggedLine int // last line for which a line tag was written
|
lastTaggedLine int // last line for which a line tag was written
|
||||||
|
|
||||||
// The list of all source comments, in order of appearance.
|
// The list of all source comments, in order of appearance.
|
||||||
comments []*ast.CommentGroup // may be nil
|
comments []*ast.CommentGroup // may be nil
|
||||||
cindex int // current comment index
|
cindex int // current comment index
|
||||||
|
useNodeComments bool // if not set, ignore lead and line comments of nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -246,7 +247,10 @@ func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) {
|
|||||||
// immediately following the data.
|
// immediately following the data.
|
||||||
//
|
//
|
||||||
func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
|
func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
|
||||||
p.pos = pos
|
if pos.IsValid() {
|
||||||
|
// continue with previous position if we don't have a valid pos
|
||||||
|
p.pos = pos
|
||||||
|
}
|
||||||
if debug {
|
if debug {
|
||||||
// do not update p.pos - use write0
|
// do not update p.pos - use write0
|
||||||
p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)))
|
p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)))
|
||||||
@ -734,14 +738,6 @@ func (p *printer) print(args ...) {
|
|||||||
}
|
}
|
||||||
p.buffer = p.buffer[0 : i+1]
|
p.buffer = p.buffer[0 : i+1]
|
||||||
p.buffer[i] = x
|
p.buffer[i] = x
|
||||||
case []byte:
|
|
||||||
// TODO(gri): remove this case once commentList
|
|
||||||
// handles comments correctly
|
|
||||||
data = x
|
|
||||||
case string:
|
|
||||||
// TODO(gri): remove this case once fieldList
|
|
||||||
// handles comments correctly
|
|
||||||
data = strings.Bytes(x)
|
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
if p.Styler != nil {
|
if p.Styler != nil {
|
||||||
data, tag = p.Styler.Ident(x)
|
data, tag = p.Styler.Ident(x)
|
||||||
@ -976,13 +972,17 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
|
|||||||
go func() {
|
go func() {
|
||||||
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
|
||||||
p.stmt(n, ignoreMultiLine)
|
p.stmt(n, ignoreMultiLine)
|
||||||
case ast.Decl:
|
case ast.Decl:
|
||||||
|
p.useNodeComments = true
|
||||||
p.decl(n, atTop, ignoreMultiLine)
|
p.decl(n, atTop, ignoreMultiLine)
|
||||||
case *ast.File:
|
case *ast.File:
|
||||||
p.comments = n.Comments
|
p.comments = n.Comments
|
||||||
|
p.useNodeComments = n.Comments == nil
|
||||||
p.file(n)
|
p.file(n)
|
||||||
default:
|
default:
|
||||||
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
|
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
|
||||||
|
9
src/pkg/go/printer/testdata/comments.golden
vendored
9
src/pkg/go/printer/testdata/comments.golden
vendored
@ -59,6 +59,15 @@ type I2 interface {
|
|||||||
G(x float) float // exported method
|
G(x float) float // exported method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The S3 struct; all comments except for the last one must appear in the export.
|
||||||
|
type S3 struct {
|
||||||
|
// lead comment for F1
|
||||||
|
F1 int // line comment for F1
|
||||||
|
// lead comment for F2
|
||||||
|
F2 int // line comment for F2
|
||||||
|
f3 int // f3 is not exported
|
||||||
|
}
|
||||||
|
|
||||||
// This comment group should be separated
|
// This comment group should be separated
|
||||||
// with a newline from the next comment
|
// with a newline from the next comment
|
||||||
// group.
|
// group.
|
||||||
|
9
src/pkg/go/printer/testdata/comments.input
vendored
9
src/pkg/go/printer/testdata/comments.input
vendored
@ -59,6 +59,15 @@ type I2 interface {
|
|||||||
G(x float) float // exported method
|
G(x float) float // exported method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The S3 struct; all comments except for the last one must appear in the export.
|
||||||
|
type S3 struct {
|
||||||
|
// lead comment for F1
|
||||||
|
F1 int // line comment for F1
|
||||||
|
// lead comment for F2
|
||||||
|
F2 int // line comment for F2
|
||||||
|
f3 int // f3 is not exported
|
||||||
|
}
|
||||||
|
|
||||||
// This comment group should be separated
|
// This comment group should be separated
|
||||||
// with a newline from the next comment
|
// with a newline from the next comment
|
||||||
// group.
|
// group.
|
||||||
|
16
src/pkg/go/printer/testdata/comments.x
vendored
16
src/pkg/go/printer/testdata/comments.x
vendored
@ -6,13 +6,11 @@ package main
|
|||||||
// The SZ struct; it is empty.
|
// The SZ struct; it is empty.
|
||||||
type SZ struct{}
|
type SZ struct{}
|
||||||
|
|
||||||
|
|
||||||
// The S0 struct; no field is exported.
|
// The S0 struct; no field is exported.
|
||||||
type S0 struct {
|
type S0 struct {
|
||||||
// contains unexported fields
|
// contains unexported fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The S1 struct; some fields are not exported.
|
// The S1 struct; some fields are not exported.
|
||||||
type S1 struct {
|
type S1 struct {
|
||||||
S0
|
S0
|
||||||
@ -21,24 +19,20 @@ type S1 struct {
|
|||||||
// contains unexported fields
|
// contains unexported fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The S2 struct; all fields are exported.
|
// The S2 struct; all fields are exported.
|
||||||
type S2 struct {
|
type S2 struct {
|
||||||
S1
|
S1
|
||||||
A, B, C float // 3 exported fields
|
A, B, C float // 3 exported fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The IZ interface; it is empty.
|
// The IZ interface; it is empty.
|
||||||
type SZ interface{}
|
type SZ interface{}
|
||||||
|
|
||||||
|
|
||||||
// The I0 interface; no method is exported.
|
// The I0 interface; no method is exported.
|
||||||
type I0 interface {
|
type I0 interface {
|
||||||
// contains unexported methods
|
// contains unexported methods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The I1 interface; some methods are not exported.
|
// The I1 interface; some methods are not exported.
|
||||||
type I1 interface {
|
type I1 interface {
|
||||||
I0
|
I0
|
||||||
@ -46,10 +40,18 @@ type I1 interface {
|
|||||||
// contains unexported methods
|
// contains unexported methods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The I2 interface; all methods are exported.
|
// The I2 interface; all methods are exported.
|
||||||
type I2 interface {
|
type I2 interface {
|
||||||
I0
|
I0
|
||||||
F(x float) float // exported method
|
F(x float) float // exported method
|
||||||
G(x float) float // exported method
|
G(x float) float // exported method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The S3 struct; all comments except for the last one must appear in the export.
|
||||||
|
type S3 struct {
|
||||||
|
// lead comment for F1
|
||||||
|
F1 int // line comment for F1
|
||||||
|
// lead comment for F2
|
||||||
|
F2 int // line comment for F2
|
||||||
|
// contains unexported fields
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user