Have dumbindent break after some '{' and ';'s
diff --git a/cmd/dumbindent/main.go b/cmd/dumbindent/main.go
index d01652f..b171d5c 100644
--- a/cmd/dumbindent/main.go
+++ b/cmd/dumbindent/main.go
@@ -24,10 +24,10 @@
//
// It is similar in concept to pretty-printers like `indent` or `clang-format`.
// It is much dumber (it will not add line breaks or otherwise re-flow lines of
-// code, not to fit within an 80 character limit nor for any other reason) but
-// it can therefore be much, much faster at the basic task of automatically
-// indenting nested blocks. The output isn't 'perfect', but it's usually
-// sufficiently readable if the input already has sensible line breaks.
+// code just to fit within an 80 character limit) but it can therefore be much,
+// much faster at the basic task of automatically indenting nested blocks. The
+// output isn't 'perfect', but it's usually sufficiently readable if the input
+// already has sensible line breaks.
//
// An example of "much, much faster", 80 times faster than clang-format:
// ----
diff --git a/internal/cgen/cgen.go b/internal/cgen/cgen.go
index 2db9c38..b06f000 100644
--- a/internal/cgen/cgen.go
+++ b/internal/cgen/cgen.go
@@ -131,7 +131,6 @@
for _, n := range builtin.Interfaces {
buf.printf("const char* wuffs_base__%s__vtable_name = "+
"\"{vtable}wuffs_base__%s\";\n", n, n)
-
}
return nil
},
@@ -1383,10 +1382,10 @@
}
b.printf("{\n")
- b.printf("wuffs_base__status z = %s%s__initialize("+
+ b.printf("wuffs_base__status z = %s%s__initialize(\n"+
"&self->private_data.%s%s, sizeof(self->private_data.%s%s), WUFFS_VERSION, initialize_flags);\n",
prefix, qid[1].Str(g.tm), fPrefix, f.Name().Str(g.tm), fPrefix, f.Name().Str(g.tm))
- b.printf("if (z.repr) { return z; }\n")
+ b.printf("if (z.repr) {\nreturn z;\n}\n")
b.printf("}\n")
}
diff --git a/lib/dumbindent/dumbindent.go b/lib/dumbindent/dumbindent.go
index f1657f6..5b3fd36 100644
--- a/lib/dumbindent/dumbindent.go
+++ b/lib/dumbindent/dumbindent.go
@@ -18,10 +18,10 @@
//
// It is similar in concept to pretty-printers like `indent` or `clang-format`.
// It is much dumber (it will not add line breaks or otherwise re-flow lines of
-// code, not to fit within an 80 character limit nor for any other reason) but
-// it can therefore be much, much faster at the basic task of automatically
-// indenting nested blocks. The output isn't 'perfect', but it's usually
-// sufficiently readable if the input already has sensible line breaks.
+// code just to fit within an 80 character limit) but it can therefore be much,
+// much faster at the basic task of automatically indenting nested blocks. The
+// output isn't 'perfect', but it's usually sufficiently readable if the input
+// already has sensible line breaks.
//
// See `cmd/dumbindent/main.go` in this repository for an example where
// `dumbindent` was 80 times faster than `clang-format`.
@@ -50,10 +50,11 @@
// FormatBytes formats the C (or C-like) program in src, appending the result
// to dst, and returns that longer slice.
//
-// It is valid to pass a dst slice (such as nil) whose spare capacity (not
-// including its existing elements) is too short to hold the formatted program.
-// In this case, a new slice will be allocated and returned.
+// It is valid to pass a dst slice (such as nil) whose unused capacity
+// (cap(dst) - len(dst)) is too short to hold the formatted program. In this
+// case, a new slice will be allocated and returned.
func FormatBytes(dst []byte, src []byte) []byte {
+ src = trimLeadingWhiteSpaceAndNewLines(src)
if len(src) == 0 {
return dst
} else if len(dst) == 0 {
@@ -66,6 +67,7 @@
hanging := false // Whether the previous non-blank line ends with '=' or '\\'.
blankLine := false // Whether the previous line was blank.
+outer:
for line, remaining := src, []byte(nil); len(src) > 0; src = remaining {
src = trimLeadingWhiteSpace(src)
line, remaining = src, nil
@@ -137,12 +139,23 @@
// Adjust the state according to the braces and parentheses within the
// line (except for those in comments and strings).
last := lastNonWhiteSpace(line)
- loop:
+ inner:
for {
for i, c := range line {
switch c {
case '{':
nBraces++
+ if l := lastNonWhiteSpace(line[:i]); (l != '=') && (l != ':') {
+ if breakAfterBrace(line[i+1:]) {
+ dst = append(dst, line[:i+1]...)
+ dst = append(dst, '\n')
+ restOfLine := line[i+1:]
+ remaining = src[lineLength-len(restOfLine):]
+ openBrace = true
+ hanging = false
+ continue outer
+ }
+ }
case '}':
nBraces--
case '(':
@@ -150,6 +163,17 @@
case ')':
nParens--
+ case ';':
+ if (nParens == 0) && (breakAfterSemicolon(line[i+1:])) {
+ dst = append(dst, line[:i+1]...)
+ dst = append(dst, '\n')
+ restOfLine := line[i+1:]
+ remaining = src[lineLength-len(restOfLine):]
+ openBrace = false
+ hanging = false
+ continue outer
+ }
+
case '/':
if (i + 1) >= len(line) {
break
@@ -157,7 +181,7 @@
if line[i+1] == '/' {
// A slash-slash comment. Skip the rest of the line.
last = lastNonWhiteSpace(line[:i])
- break loop
+ break inner
} else if line[i+1] == '*' {
// A slash-star comment.
dst = append(dst, line[:i+2]...)
@@ -165,7 +189,7 @@
restOfSrc := src[lineLength-len(restOfLine):]
dst, line, remaining = handleRaw(dst, restOfSrc, starSlash)
last = lastNonWhiteSpace(line)
- continue loop
+ continue inner
}
case '"', '\'':
@@ -173,7 +197,7 @@
suffix := skipCooked(line[i+1:], c)
dst = append(dst, line[:len(line)-len(suffix)]...)
line = suffix
- continue loop
+ continue inner
case '`':
// A raw string.
@@ -182,10 +206,10 @@
restOfSrc := src[lineLength-len(restOfLine):]
dst, line, remaining = handleRaw(dst, restOfSrc, backTick)
last = lastNonWhiteSpace(line)
- continue loop
+ continue inner
}
}
- break loop
+ break inner
}
openBrace = last == '{'
hanging = hangingBytes[last]
@@ -198,7 +222,15 @@
return dst
}
-// trimLeadingWhiteSpace converts "\t foo bar " to "foo bar ".
+// trimLeadingWhiteSpaceAndNewLines converts "\t\n foo bar " to "foo bar ".
+func trimLeadingWhiteSpaceAndNewLines(s []byte) []byte {
+ for (len(s) > 0) && ((s[0] == ' ') || (s[0] == '\t') || (s[0] == '\n')) {
+ s = s[1:]
+ }
+ return s
+}
+
+// trimLeadingWhiteSpace converts "\t\t foo bar " to "foo bar ".
func trimLeadingWhiteSpace(s []byte) []byte {
for (len(s) > 0) && ((s[0] == ' ') || (s[0] == '\t')) {
s = s[1:]
@@ -206,7 +238,7 @@
return s
}
-// trimTrailingWhiteSpace converts "\t foo bar " to "\t foo bar".
+// trimTrailingWhiteSpace converts "\t\t foo bar " to "\t\t foo bar".
func trimTrailingWhiteSpace(s []byte) []byte {
for (len(s) > 0) && ((s[len(s)-1] == ' ') || (s[len(s)-1] == '\t')) {
s = s[:len(s)-1]
@@ -257,3 +289,25 @@
}
return dst, line, remaining
}
+
+// breakAfterBrace returns whether the first non-space non-tab byte of s (if
+// any) does not look like a comment or another open-brace.
+func breakAfterBrace(s []byte) bool {
+ for _, c := range s {
+ if (c != ' ') && (c != '\t') {
+ return (c != '/') && (c != '{')
+ }
+ }
+ return false
+}
+
+// breakAfterBrace returns whether the first non-space non-tab byte of s (if
+// any) does not look like a comment.
+func breakAfterSemicolon(s []byte) bool {
+ for _, c := range s {
+ if (c != ' ') && (c != '\t') {
+ return c != '/'
+ }
+ }
+ return false
+}
diff --git a/lib/dumbindent/dumbindent_test.go b/lib/dumbindent/dumbindent_test.go
index 45de5bf..b54a64c 100644
--- a/lib/dumbindent/dumbindent_test.go
+++ b/lib/dumbindent/dumbindent_test.go
@@ -15,6 +15,7 @@
package dumbindent
import (
+ "os"
"testing"
)
@@ -66,6 +67,14 @@
// Nested blocks with label.
src: "if (b) {\nlabel:\nswitch (i) {\ncase 0:\nj = k\nbreak;\n}\n}\n",
want: "if (b) {\n label:\n switch (i) {\n case 0:\n j = k\n break;\n }\n}\n",
+ }, {
+ // Inserted line breaks.
+ src: "if (x) { goto fail; }\n",
+ want: "if (x) {\n goto fail;\n}\n",
+ }, {
+ // Leading blank lines.
+ src: "\n\n\n x = y;",
+ want: "x = y;\n",
}}
for i, tc := range testCases {
@@ -74,3 +83,29 @@
}
}
}
+
+func ExampleFormatBytes() {
+ const src = `
+// Blah blah blah.
+
+
+for (i = 0; i < 3; i++) {
+j = 0; j < 4; j++;
+if (i < j) { foo(); }
+}
+`
+
+ os.Stdout.Write(FormatBytes(nil, []byte(src)))
+
+ // Output:
+ // // Blah blah blah.
+ //
+ // for (i = 0; i < 3; i++) {
+ // j = 0;
+ // j < 4;
+ // j++;
+ // if (i < j) {
+ // foo();
+ // }
+ // }
+}
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index ac55550..af8aab7 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -17003,8 +17003,11 @@
}
{
- wuffs_base__status z = wuffs_lzw__decoder__initialize(&self->private_data.f_lzw, sizeof(self->private_data.f_lzw), WUFFS_VERSION, initialize_flags);
- if (z.repr) { return z; }
+ wuffs_base__status z = wuffs_lzw__decoder__initialize(
+ &self->private_data.f_lzw, sizeof(self->private_data.f_lzw), WUFFS_VERSION, initialize_flags);
+ if (z.repr) {
+ return z;
+ }
}
self->private_impl.magic = WUFFS_BASE__MAGIC;
self->private_impl.vtable_for__wuffs_base__image_decoder.vtable_name =
@@ -21193,12 +21196,18 @@
}
{
- wuffs_base__status z = wuffs_crc32__ieee_hasher__initialize(&self->private_data.f_checksum, sizeof(self->private_data.f_checksum), WUFFS_VERSION, initialize_flags);
- if (z.repr) { return z; }
+ wuffs_base__status z = wuffs_crc32__ieee_hasher__initialize(
+ &self->private_data.f_checksum, sizeof(self->private_data.f_checksum), WUFFS_VERSION, initialize_flags);
+ if (z.repr) {
+ return z;
+ }
}
{
- wuffs_base__status z = wuffs_deflate__decoder__initialize(&self->private_data.f_flate, sizeof(self->private_data.f_flate), WUFFS_VERSION, initialize_flags);
- if (z.repr) { return z; }
+ wuffs_base__status z = wuffs_deflate__decoder__initialize(
+ &self->private_data.f_flate, sizeof(self->private_data.f_flate), WUFFS_VERSION, initialize_flags);
+ if (z.repr) {
+ return z;
+ }
}
self->private_impl.magic = WUFFS_BASE__MAGIC;
self->private_impl.vtable_for__wuffs_base__io_transformer.vtable_name =
@@ -24667,16 +24676,25 @@
}
{
- wuffs_base__status z = wuffs_adler32__hasher__initialize(&self->private_data.f_checksum, sizeof(self->private_data.f_checksum), WUFFS_VERSION, initialize_flags);
- if (z.repr) { return z; }
+ wuffs_base__status z = wuffs_adler32__hasher__initialize(
+ &self->private_data.f_checksum, sizeof(self->private_data.f_checksum), WUFFS_VERSION, initialize_flags);
+ if (z.repr) {
+ return z;
+ }
}
{
- wuffs_base__status z = wuffs_adler32__hasher__initialize(&self->private_data.f_dict_id_hasher, sizeof(self->private_data.f_dict_id_hasher), WUFFS_VERSION, initialize_flags);
- if (z.repr) { return z; }
+ wuffs_base__status z = wuffs_adler32__hasher__initialize(
+ &self->private_data.f_dict_id_hasher, sizeof(self->private_data.f_dict_id_hasher), WUFFS_VERSION, initialize_flags);
+ if (z.repr) {
+ return z;
+ }
}
{
- wuffs_base__status z = wuffs_deflate__decoder__initialize(&self->private_data.f_flate, sizeof(self->private_data.f_flate), WUFFS_VERSION, initialize_flags);
- if (z.repr) { return z; }
+ wuffs_base__status z = wuffs_deflate__decoder__initialize(
+ &self->private_data.f_flate, sizeof(self->private_data.f_flate), WUFFS_VERSION, initialize_flags);
+ if (z.repr) {
+ return z;
+ }
}
self->private_impl.magic = WUFFS_BASE__MAGIC;
self->private_impl.vtable_for__wuffs_base__io_transformer.vtable_name =