]> Cypherpunks repositories - gostls13.git/commitdiff
gofmt: fix some linebreak issues
authorRobert Griesemer <gri@golang.org>
Tue, 20 Jul 2010 16:29:31 +0000 (09:29 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 20 Jul 2010 16:29:31 +0000 (09:29 -0700)
- don't lose empty lines after labels
- canonicalize number of line breaks
- gofmt src misc, fixes a couple of irregular breaks

R=rsc
CC=golang-dev
https://golang.org/cl/1843044

src/pkg/compress/flate/huffman_code.go
src/pkg/compress/flate/inflate.go
src/pkg/go/doc/comment.go
src/pkg/go/printer/nodes.go
src/pkg/go/printer/printer.go
src/pkg/go/printer/testdata/statements.golden
src/pkg/go/printer/testdata/statements.input
src/pkg/nntp/nntp_test.go

index 38cbf439688dbfcea855756c52c43f552b896e17..6be605f0a59a981913f704d9de9366b11d71a4eb 100644 (file)
@@ -270,7 +270,6 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
                }
        }
 
-
        // Somethings is wrong if at the end, the top level is null or hasn't used
        // all of the leaves.
        if top.lastChain.leafCount != n {
index f0bd005318d4812800f61f85808b9d2338464327..e46cbeff653b7e22951a4a30a9d7a18c360dad2c 100644 (file)
@@ -102,7 +102,6 @@ func (h *huffmanDecoder) init(bits []int) bool {
        h.min = min
        h.max = max
 
-
        // For each code range, compute
        // nextcode (first code of that length),
        // limit (last code of that length), and
index bbbc6a3c2595c17f9c6a6b520249dca50524c4b7..55ddf8b7557b06ab9e5481205c6e317716d00ef2 100644 (file)
@@ -224,7 +224,6 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
                        italics = false // don't italicize URLs
                }
 
-
                // write match
                if len(url) > 0 {
                        w.Write(html_a)
index a98af4a2afacd5d8c06cdf38cd7938ac0f3db90c..132c52073e75c2c0e0ad035b5251469a4841f9fb 100644 (file)
@@ -28,32 +28,30 @@ import (
 // ----------------------------------------------------------------------------
 // Common AST nodes.
 
-// Print as many newlines as necessary (but at least min and and at most
-// max newlines) to get to the current line. ws is printed before the first
-// line break. If newSection is set, the first line break is printed as
-// formfeed. Returns true if any line break was printed; returns false otherwise.
+// Print as many newlines as necessary (but at least min newlines) to get to
+// the current line. ws is printed before the first line break. If newSection
+// is set, the first line break is printed as formfeed. Returns true if any
+// line break was printed; returns false otherwise.
 //
-// TODO(gri): Reconsider signature (provide position instead of line)
+// TODO(gri): linebreak may add too many lines if the next statement at "line"
+//            is preceeded by comments because the computation of n assumes
+//            the current position before the comment and the target position
+//            after the comment. Thus, after interspersing such comments, the
+//            space taken up by them is not considered to reduce the number of
+//            linebreaks. At the moment there is no easy way to know about
+//            future (not yet interspersed) comments in this function.
 //
-func (p *printer) linebreak(line, min, max int, ws whiteSpace, newSection bool) (printedBreak bool) {
-       n := line - p.pos.Line
-       switch {
-       case n < min:
-               n = min
-       case n > max:
-               n = max
-       }
-
+func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
+       n := p.nlines(line-p.pos.Line, min)
        if n > 0 {
                p.print(ws)
                if newSection {
                        p.print(formfeed)
                        n--
-                       printedBreak = true
                }
-       }
-       for ; n > 0; n-- {
-               p.print(newline)
+               for ; n > 0; n-- {
+                       p.print(newline)
+               }
                printedBreak = true
        }
        return
@@ -190,7 +188,7 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
                // lines for them.
                linebreakMin = 0
        }
-       if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, 2, ws, true) {
+       if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) {
                ws = ignore
                *multiLine = true
                prevBreak = 0
@@ -252,7 +250,7 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
                                // unless forceFF is set or there are multiple expressions on
                                // the same line in which case formfeed is used
                                // broken with a formfeed
-                               if p.linebreak(line, linebreakMin, 2, ws, useFF || prevBreak+1 < i) {
+                               if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) {
                                        ws = ignore
                                        *multiLine = true
                                        prevBreak = i
@@ -371,6 +369,11 @@ func (p *printer) setLineComment(text string) {
 
 
 func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprContext) {
+       p.nesting++
+       defer func() {
+               p.nesting--
+       }()
+
        lbrace := fields.Opening
        list := fields.List
        rbrace := fields.Closing
@@ -413,7 +416,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
                var ml bool
                for i, f := range list {
                        if i > 0 {
-                               p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
+                               p.linebreak(f.Pos().Line, 1, ignore, ml)
                        }
                        ml = false
                        extraTabs := 0
@@ -457,7 +460,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
                var ml bool
                for i, f := range list {
                        if i > 0 {
-                               p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
+                               p.linebreak(f.Pos().Line, 1, ignore, ml)
                        }
                        ml = false
                        p.setComment(f.Doc)
@@ -648,7 +651,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
        if xline != yline && xline > 0 && yline > 0 {
                // at least one line break, but respect an extra empty line
                // in the source
-               if p.linebreak(yline, 1, 2, ws, true) {
+               if p.linebreak(yline, 1, ws, true) {
                        ws = ignore
                        *multiLine = true
                        printBlank = false // no blank after line break
@@ -917,8 +920,6 @@ func (p *printer) expr(x ast.Expr, multiLine *bool) {
 // ----------------------------------------------------------------------------
 // Statements
 
-const maxStmtNewlines = 2 // maximum number of newlines between statements
-
 // Print the statement list indented, but without a newline after the last statement.
 // Extra line breaks between statements in the source are respected but at most one
 // empty line is printed between statements.
@@ -931,7 +932,7 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
        for i, s := range list {
                // _indent == 0 only for lists of switch/select case clauses;
                // in those cases each clause is a new section
-               p.linebreak(s.Pos().Line, 1, maxStmtNewlines, ignore, i == 0 || _indent == 0 || multiLine)
+               p.linebreak(s.Pos().Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
                multiLine = false
                p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
        }
@@ -945,7 +946,7 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
 func (p *printer) block(s *ast.BlockStmt, indent int) {
        p.print(s.Pos(), token.LBRACE)
        p.stmtList(s.List, indent, true)
-       p.linebreak(s.Rbrace.Line, 1, maxStmtNewlines, ignore, true)
+       p.linebreak(s.Rbrace.Line, 1, ignore, true)
        p.print(s.Rbrace, token.RBRACE)
 }
 
@@ -1039,7 +1040,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
                                break
                        }
                } else {
-                       p.print(newline)
+                       p.linebreak(s.Stmt.Pos().Line, 1, ignore, true)
                }
                p.stmt(s.Stmt, nextIsRBrace, multiLine)
 
@@ -1271,7 +1272,7 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
                        var ml bool
                        for i, s := range d.Specs {
                                if i > 0 {
-                                       p.linebreak(s.Pos().Line, 1, 2, ignore, ml)
+                                       p.linebreak(s.Pos().Line, 1, ignore, ml)
                                }
                                ml = false
                                p.spec(s, len(d.Specs), false, &ml)
@@ -1345,6 +1346,11 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
                return
        }
 
+       p.nesting++
+       defer func() {
+               p.nesting--
+       }()
+
        if p.isOneLineFunc(b, headerSize) {
                sep := vtab
                if isLit {
@@ -1414,8 +1420,6 @@ func (p *printer) decl(decl ast.Decl, multiLine *bool) {
 // ----------------------------------------------------------------------------
 // Files
 
-const maxDeclNewlines = 3 // maximum number of newlines between declarations
-
 func declToken(decl ast.Decl) (tok token.Token) {
        tok = token.ILLEGAL
        switch d := decl.(type) {
@@ -1444,7 +1448,7 @@ func (p *printer) file(src *ast.File) {
                        if prev != tok {
                                min = 2
                        }
-                       p.linebreak(d.Pos().Line, min, maxDeclNewlines, ignore, false)
+                       p.linebreak(d.Pos().Line, min, ignore, false)
                        p.decl(d, ignoreMultiLine)
                }
        }
index 53632c83dd641f0b0a4251f719b9437f0ca0103b..9adc540b95892de112bf224fd763f5f66d200ad6 100644 (file)
@@ -18,10 +18,7 @@ import (
 )
 
 
-const (
-       debug       = false // enable for debugging
-       maxNewlines = 3     // maximum vertical white space
-)
+const debug = false // enable for debugging
 
 
 type whiteSpace int
@@ -41,8 +38,8 @@ var (
        esc       = []byte{tabwriter.Escape}
        htab      = []byte{'\t'}
        htabs     = []byte("\t\t\t\t\t\t\t\t")
-       newlines  = []byte("\n\n\n\n\n\n\n\n") // more than maxNewlines
-       formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than maxNewlines
+       newlines  = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
+       formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
 
        esc_quot = []byte("&#34;") // shorter than "&quot;"
        esc_apos = []byte("&#39;") // shorter than "&apos;"
@@ -68,6 +65,7 @@ type printer struct {
        errors chan os.Error
 
        // Current state
+       nesting int  // nesting level (0: top-level (package scope), >0: functions/decls.)
        written int  // number of bytes written
        indent  int  // current indentation
        escape  bool // true if in escape sequence
@@ -112,6 +110,25 @@ func (p *printer) internalError(msg ...interface{}) {
 }
 
 
+// nlines returns the adjusted number of linebreaks given the desired number
+// of breaks n such that min <= result <= max where max depends on the current
+// nesting level.
+//
+func (p *printer) nlines(n, min int) int {
+       if n < min {
+               return min
+       }
+       max := 3 // max. number of newlines at the top level (p.nesting == 0)
+       if p.nesting > 0 {
+               max = 2 // max. number of newlines everywhere else
+       }
+       if n > max {
+               return max
+       }
+       return n
+}
+
+
 // write0 writes raw (uninterpreted) data to p.output and handles errors.
 // write0 does not indent after newlines, and does not HTML-escape or update p.pos.
 //
@@ -207,9 +224,7 @@ func (p *printer) write(data []byte) {
 
 func (p *printer) writeNewlines(n int, useFF bool) {
        if n > 0 {
-               if n > maxNewlines {
-                       n = maxNewlines
-               }
+               n = p.nlines(n, 0)
                if useFF {
                        p.write(formfeeds[0:n])
                } else {
@@ -292,8 +307,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
        }
 
        if pos.IsValid() && pos.Filename != p.last.Filename {
-               // comment in a different file - separate with newlines
-               p.writeNewlines(maxNewlines, true)
+               // comment in a different file - separate with newlines (writeNewlines will limit the number)
+               p.writeNewlines(10, true)
                return
        }
 
@@ -1004,9 +1019,11 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
        go func() {
                switch n := node.(type) {
                case ast.Expr:
+                       p.nesting = 1
                        p.useNodeComments = true
                        p.expr(n, ignoreMultiLine)
                case ast.Stmt:
+                       p.nesting = 1
                        p.useNodeComments = true
                        // A labeled statement will un-indent to position the
                        // label. Set indent to 1 so we don't get indent "underflow".
@@ -1015,12 +1032,15 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
                        }
                        p.stmt(n, false, ignoreMultiLine)
                case ast.Decl:
+                       p.nesting = 1
                        p.useNodeComments = true
                        p.decl(n, ignoreMultiLine)
                case ast.Spec:
+                       p.nesting = 1
                        p.useNodeComments = true
                        p.spec(n, 1, false, ignoreMultiLine)
                case *ast.File:
+                       p.nesting = 0
                        p.comments = n.Comments
                        p.useNodeComments = n.Comments == nil
                        p.file(n)
index 73a3e123683dc5c27d027b9f12658d7716045e42..461fd13f95611bc453c88ac703de408dedd4abe5 100644 (file)
@@ -227,7 +227,8 @@ func _() {
        var x = 1
 
        // Each use(x) call below should have at most one empty line before and after.
-
+       // Known bug: The first use call may have more than one empty line before
+       //            (see go/printer/nodes.go, func linebreak).
 
 
        use(x)
@@ -336,3 +337,49 @@ AnOverlongLabel:
 L:
        _ = 0
 }
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:     // A comment on the same line as the label, followed by a single empty line.
+       // Known bug: There may be more than one empty line before MoreCode()
+       //            (see go/printer/nodes.go, func linebreak).
+
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto AVeryLongLabelThatShouldNotAffectFormatting
+       }
+AVeryLongLabelThatShouldNotAffectFormatting:
+       // There should be a single empty line after this comment.
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
index 53f16c050a8fbca305056c70fd0da8491f27f248..5437eb5f19164d2618d75e486ead61e77839e56f 100644 (file)
@@ -164,6 +164,8 @@ func _() {
        var x = 1
 
        // Each use(x) call below should have at most one empty line before and after.
+       // Known bug: The first use call may have more than one empty line before
+       //            (see go/printer/nodes.go, func linebreak).
 
 
 
@@ -266,3 +268,54 @@ AnOverlongLabel:
 
 L:     _ = 0
 }
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:     // A comment on the same line as the label, followed by a single empty line.
+       // Known bug: There may be more than one empty line before MoreCode()
+       //            (see go/printer/nodes.go, func linebreak).
+
+
+
+
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto L
+       }
+L:
+
+
+
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
+
+
+func _() {
+       for {
+               goto AVeryLongLabelThatShouldNotAffectFormatting
+       }
+AVeryLongLabelThatShouldNotAffectFormatting:
+       // There should be a single empty line after this comment.
+
+       // There should be a single empty line before this comment.
+       MoreCode()
+}
index bca18572246e37404c61d7b75ff0d312553e338c..8f5032c6a054ec3b234be9c7dd9a2a83e97cd872 100644 (file)
@@ -154,7 +154,6 @@ Body.
                t.Fatal("newnews should work: " + err.String())
        }
 
-
        // NewGroups
        if _, err = conn.NewGroups(tt); err != nil {
                t.Fatal("newgroups shouldn't error " + err.String())