1
0
mirror of https://github.com/golang/go synced 2024-09-25 13:20:13 -06:00

gofmt, go/printer: do not insert extra linebreaks where they may break the code

Introduced a printer mode (pmode) type and corresponding
pmode values which permit easy toggling of the current
printer mode for fine-tuning of layout.

Use the printer mode to disable potential introduction of
line breaks before a closing '}' in composite literals.

Added extra test case. Applied gofmt to src and misc.

Fixes #1365.

R=r2
CC=golang-dev
https://golang.org/cl/4008041
This commit is contained in:
Robert Griesemer 2011-01-14 09:42:37 -08:00
parent a093f3d5a0
commit 157cd6ef3a
4 changed files with 46 additions and 15 deletions

View File

@ -872,7 +872,10 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
} }
p.print(x.Lbrace, token.LBRACE) p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace) p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
p.print(x.Rbrace, token.RBRACE) // do not insert extra line breaks because of comments before
// the closing '}' as it might break the code if there is no
// trailing ','
p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
case *ast.Ellipsis: case *ast.Ellipsis:
p.print(token.ELLIPSIS) p.print(token.ELLIPSIS)
@ -1388,7 +1391,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
if isLit { if isLit {
sep = blank sep = blank
} }
p.print(sep, b.Pos(), token.LBRACE) p.print(sep, b.Lbrace, token.LBRACE)
if len(b.List) > 0 { if len(b.List) > 0 {
p.print(blank) p.print(blank)
for i, s := range b.List { for i, s := range b.List {

View File

@ -58,6 +58,15 @@ var infinity = 1 << 30
var ignoreMultiLine = new(bool) var ignoreMultiLine = new(bool)
// A pmode value represents the current printer mode.
type pmode int
const (
inLiteral pmode = 1 << iota
noExtraLinebreak
)
type printer struct { type printer struct {
// Configuration (does not change after initialization) // Configuration (does not change after initialization)
output io.Writer output io.Writer
@ -69,7 +78,7 @@ type printer struct {
nesting int // nesting level (0: top-level (package scope), >0: functions/decls.) nesting int // nesting level (0: top-level (package scope), >0: functions/decls.)
written int // number of bytes written written int // number of bytes written
indent int // current indentation indent int // current indentation
escape bool // true if in escape sequence mode pmode // current printer mode
lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace) lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
// Buffered whitespace // Buffered whitespace
@ -162,7 +171,7 @@ func (p *printer) write(data []byte) {
p.pos.Line++ p.pos.Line++
p.pos.Column = 1 p.pos.Column = 1
if !p.escape { if p.mode&inLiteral == 0 {
// write indentation // write indentation
// use "hard" htabs - indentation columns // use "hard" htabs - indentation columns
// must not be discarded by the tabwriter // must not be discarded by the tabwriter
@ -211,7 +220,7 @@ func (p *printer) write(data []byte) {
} }
case tabwriter.Escape: case tabwriter.Escape:
p.escape = !p.escape p.mode ^= inLiteral
// ignore escape chars introduced by printer - they are // ignore escape chars introduced by printer - they are
// invisible and must not affect p.pos (was issue #1089) // invisible and must not affect p.pos (was issue #1089)
@ -272,7 +281,7 @@ func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
// (used when printing merged ASTs of different files // (used when printing merged ASTs of different files
// e.g., the result of ast.MergePackageFiles) // e.g., the result of ast.MergePackageFiles)
p.indent = 0 p.indent = 0
p.escape = false p.mode = 0
p.buffer = p.buffer[0:0] p.buffer = p.buffer[0:0]
fileChanged = true fileChanged = true
} }
@ -683,9 +692,13 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
// follows on the same line: separate with an extra blank // follows on the same line: separate with an extra blank
p.write([]byte{' '}) p.write([]byte{' '})
} }
// ensure that there is a newline after a //-style comment // ensure that there is a line break after a //-style comment,
// or if we are before a closing '}' or at the end of a file // before a closing '}' unless explicitly disabled, or at eof
return p.writeCommentSuffix(last.Text[1] == '/' || tok == token.RBRACE || tok == token.EOF) needsLinebreak :=
last.Text[1] == '/' ||
tok == token.RBRACE && p.mode&noExtraLinebreak == 0 ||
tok == token.EOF
return p.writeCommentSuffix(needsLinebreak)
} }
// no comment was written - we should never reach here since // no comment was written - we should never reach here since
@ -787,6 +800,9 @@ func (p *printer) print(args ...interface{}) {
var tok token.Token var tok token.Token
switch x := f.(type) { switch x := f.(type) {
case pmode:
// toggle printer mode
p.mode ^= x
case whiteSpace: case whiteSpace:
if x == ignore { if x == ignore {
// don't add ignore's to the buffer; they // don't add ignore's to the buffer; they
@ -818,10 +834,14 @@ func (p *printer) print(args ...interface{}) {
data = x.Value data = x.Value
} }
// escape all literals so they pass through unchanged // escape all literals so they pass through unchanged
// (note that valid Go programs cannot contain esc ('\xff') // (note that valid Go programs cannot contain
// bytes since they do not appear in legal UTF-8 sequences) // tabwriter.Escape bytes since they do not appear in
// TODO(gri): do this more efficiently. // legal UTF-8 sequences)
data = []byte("\xff" + string(data) + "\xff") escData := make([]byte, 0, len(data)+2)
escData = append(escData, tabwriter.Escape)
escData = append(escData, data...)
escData = append(escData, tabwriter.Escape)
data = escData
tok = x.Kind tok = x.Kind
case token.Token: case token.Token:
s := x.String() s := x.String()

View File

@ -422,7 +422,7 @@ func _() {
func ( /* comment1 */ T /* comment2 */ ) _() {} func ( /* comment1 */ T /* comment2 */ ) _() {}
func _() { /* one-liner */ func _() { /* one-line functions with comments are formatted as multi-line functions */
} }
func _() { func _() {
@ -430,6 +430,10 @@ func _() {
/* closing curly brace should be on new line */ /* closing curly brace should be on new line */
} }
func _() {
_ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
}
// Comments immediately adjacent to punctuation (for which the go/printer // Comments immediately adjacent to punctuation (for which the go/printer
// may obly have estimated position information) must remain after the punctuation. // may obly have estimated position information) must remain after the punctuation.

View File

@ -422,12 +422,16 @@ func _() {
func (/* comment1 */ T /* comment2 */) _() {} func (/* comment1 */ T /* comment2 */) _() {}
func _() { /* one-liner */ } func _() { /* one-line functions with comments are formatted as multi-line functions */ }
func _() { func _() {
_ = 0 _ = 0
/* closing curly brace should be on new line */ } /* closing curly brace should be on new line */ }
func _() {
_ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
}
// Comments immediately adjacent to punctuation (for which the go/printer // Comments immediately adjacent to punctuation (for which the go/printer
// may obly have estimated position information) must remain after the punctuation. // may obly have estimated position information) must remain after the punctuation.