mirror of
https://github.com/golang/go
synced 2024-11-12 09:50:21 -07: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:
parent
a093f3d5a0
commit
157cd6ef3a
@ -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 {
|
||||||
|
@ -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()
|
||||||
|
6
src/pkg/go/printer/testdata/comments.golden
vendored
6
src/pkg/go/printer/testdata/comments.golden
vendored
@ -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.
|
||||||
|
6
src/pkg/go/printer/testdata/comments.input
vendored
6
src/pkg/go/printer/testdata/comments.input
vendored
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user