summaryrefslogtreecommitdiff
path: root/src/pkg/go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2010-03-04 17:37:15 -0800
committerRobert Griesemer <gri@golang.org>2010-03-04 17:37:15 -0800
commit7a4de4f0ba2bc1f9acbb5eb0c7a4b2536f447ffd (patch)
treee01e75d7edaa8806e69aea495e5efc95ba3c282c /src/pkg/go
parent129633b0a8c9a014d0863014057007d410c48e9e (diff)
downloadgolang-7a4de4f0ba2bc1f9acbb5eb0c7a4b2536f447ffd.tar.gz
gofmt: modified algorithm for alignment of multi-line composite/list entries
- only manual changes are in src/pkg/go/printer/nodes.go - use a heuristic to determine "outliers" such that not entire composites are forced to align with them - improves several places that were not unligned before due too simple heuristic - unalignes some cases that contain "outliers" - gofmt -w src misc Fixes issue 644. R=rsc, r CC=golang-dev http://codereview.appspot.com/241041
Diffstat (limited to 'src/pkg/go')
-rw-r--r--src/pkg/go/printer/nodes.go93
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden24
-rw-r--r--src/pkg/go/printer/testdata/declarations.input24
3 files changed, 117 insertions, 24 deletions
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 3045300aa..d4f6d9d0e 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -109,10 +109,15 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
}
-// isOneLineExpr returns true if x is "small enough" to fit onto a single line.
-func (p *printer) isOneLineExpr(x ast.Expr) bool {
- const maxSize = 60 // aproximate value, excluding space for comments
- return p.nodeSize(x, maxSize) <= maxSize
+// Compute the key size of a key:value expression.
+// Returns 0 if the expression doesn't fit onto a single line.
+func (p *printer) keySize(pair *ast.KeyValueExpr) int {
+ const infinity = 1e6 // larger than any source line
+ if p.nodeSize(pair, infinity) <= infinity {
+ // entire expression fits on one line - return key size
+ return p.nodeSize(pair.Key, infinity)
+ }
+ return 0
}
@@ -120,6 +125,10 @@ func (p *printer) isOneLineExpr(x ast.Expr) bool {
// source lines, the original line breaks are respected between
// expressions. Sets multiLine to true if the list spans multiple
// lines.
+//
+// TODO(gri) Consider rewriting this to be independent of []ast.Expr
+// so that we can use the algorithm for any kind of list
+// (e.g., pass list via a channel over which to range).
func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next token.Position) {
if len(list) == 0 {
return
@@ -165,30 +174,69 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
ws = indent
}
- oneLiner := false // true if the previous expression fit on a single line
- prevBreak := -1 // index of last expression that was followed by a linebreak
-
// the first linebreak is always a formfeed since this section must not
// depend on any previous formatting
+ prevBreak := -1 // index of last expression that was followed by a linebreak
if prev.IsValid() && prev.Line < line && p.linebreak(line, 1, 2, ws, true) {
ws = ignore
*multiLine = true
prevBreak = 0
}
+ // initialize expression/key size: a zero value indicates expr/key doesn't fit on a single line
+ size := 0
+
+ // print all list elements
for i, x := range list {
- prev := line
+ prevLine := line
line = x.Pos().Line
+
+ // determine if the next linebreak, if any, needs to use formfeed:
+ // in general, use the entire node size to make the decision; for
+ // key:value expressions, use the key size
+ // TODO(gri) for a better result, should probably incorporate both
+ // the key and the node size into the decision process
+ useFF := true
+
+ // determine size
+ prevSize := size
+ const infinity = 1e6 // larger than any source line
+ size = p.nodeSize(x, infinity)
+ pair, isPair := x.(*ast.KeyValueExpr)
+ if size <= infinity {
+ // x fits on a single line
+ if isPair {
+ size = p.nodeSize(pair.Key, infinity) // size <= infinity
+ }
+ } else {
+ size = 0
+ }
+
+ // if the previous line and the current line had single-
+ // line-expressions and the key sizes are small or the
+ // the ratio between the key sizes does not exceed a
+ // threshold, align columns and do not use formfeed
+ if prevSize > 0 && size > 0 {
+ const smallSize = 20
+ if prevSize <= smallSize && size <= smallSize {
+ useFF = false
+ } else {
+ const r = 4 // threshold
+ ratio := float(size) / float(prevSize)
+ useFF = ratio <= 1/r || r <= ratio
+ }
+ }
+
if i > 0 {
if mode&commaSep != 0 {
p.print(token.COMMA)
}
- if prev < line && prev > 0 && line > 0 {
- // lines are broken using newlines so comments remain aligned,
- // but if an expression is not a "one-line" expression, or if
- // multiple expressions are on the same line, the section is
+ if prevLine < line && prevLine > 0 && line > 0 {
+ // lines are broken using newlines so comments remain aligned
+ // 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, 1, 2, ws, !oneLiner || prevBreak+1 < i) {
+ if p.linebreak(line, 1, 2, ws, useFF || prevBreak+1 < i) {
ws = ignore
*multiLine = true
prevBreak = i
@@ -197,17 +245,14 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
p.print(blank)
}
}
- // determine if x satisfies the "one-liner" criteria
- // TODO(gri): determine if the multiline information returned
- // from p.expr0 is precise enough so it could be
- // used instead
- oneLiner = p.isOneLineExpr(x)
- if t, isPair := x.(*ast.KeyValueExpr); isPair && oneLiner && len(list) > 1 {
- // we have a key:value expression that fits onto one line, and
- // is a list with more then one entry: align all the values
- p.expr(t.Key, multiLine)
- p.print(t.Colon, token.COLON, vtab)
- p.expr(t.Value, multiLine)
+
+ if isPair && size > 0 && len(list) > 1 {
+ // we have a key:value expression that fits onto one line and
+ // is in a list with more then one entry: use a column for the
+ // key such that consecutive entries can align if possible
+ p.expr(pair.Key, multiLine)
+ p.print(pair.Colon, token.COLON, vtab)
+ p.expr(pair.Value, multiLine)
} else {
p.expr0(x, depth, multiLine)
}
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index c19b90c20..2fe518e96 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -540,6 +540,30 @@ func _() {
}
+// alignment of map composite entries
+var _ = map[int]int{
+ // small key sizes: always align even if size ratios are large
+ a: a,
+ abcdefghabcdefgh: a,
+ ab: a,
+ abc: a,
+ abcdefgabcdefg: a,
+ abcd: a,
+ abcde: a,
+ abcdef: a,
+
+ // mixed key sizes: align when key sizes change within accepted ratio
+ abcdefgh: a,
+ abcdefghabcdefg: a,
+ abcdefghij: a,
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+ ab: a, // do not align with previous line
+ abcde: a, // align with previous line
+}
+
+
func _() {
var _ = T{
a, // must introduce trailing comma
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index 67dac0da6..8d63ab7b4 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -534,6 +534,30 @@ func _() {
}
+// alignment of map composite entries
+var _ = map[int]int{
+ // small key sizes: always align even if size ratios are large
+ a: a,
+ abcdefghabcdefgh: a,
+ ab: a,
+ abc: a,
+ abcdefgabcdefg: a,
+ abcd: a,
+ abcde: a,
+ abcdef: a,
+
+ // mixed key sizes: align when key sizes change within accepted ratio
+ abcdefgh: a,
+ abcdefghabcdefg: a,
+ abcdefghij: a,
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+ ab: a, // do not align with previous line
+ abcde: a, // align with previous line
+}
+
+
func _() {
var _ = T{
a, // must introduce trailing comma