Skip to content

Commit 118d41e

Browse files
committed
zig fmt: support array literal row size hint
See #1003
1 parent 349365d commit 118d41e

File tree

3 files changed

+167
-8
lines changed

3 files changed

+167
-8
lines changed

std/mem.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
177177
return true;
178178
}
179179

180+
/// Returns true if all elements in a slice are equal to the scalar value provided
181+
pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
182+
for (slice) |item| {
183+
if (item != scalar) return false;
184+
}
185+
return true;
186+
}
187+
180188
/// Copies ::m to newly allocated memory. Caller is responsible to free it.
181189
pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
182190
const new_buf = try allocator.alloc(T, m.len);

std/zig/parser_test.zig

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,62 @@
1+
test "zig fmt: array literal with hint" {
2+
try testTransform(
3+
\\const a = []u8{
4+
\\ 1, 2, //
5+
\\ 3,
6+
\\ 4,
7+
\\ 5,
8+
\\ 6,
9+
\\ 7 };
10+
\\const a = []u8{
11+
\\ 1, 2, //
12+
\\ 3,
13+
\\ 4,
14+
\\ 5,
15+
\\ 6,
16+
\\ 7, 8 };
17+
\\const a = []u8{
18+
\\ 1, 2, //
19+
\\ 3,
20+
\\ 4,
21+
\\ 5,
22+
\\ 6, // blah
23+
\\ 7, 8 };
24+
\\const a = []u8{
25+
\\ 1, 2, //
26+
\\ 3, //
27+
\\ 4,
28+
\\ 5,
29+
\\ 6,
30+
\\ 7 };
31+
,
32+
\\const a = []u8{
33+
\\ 1, 2, //
34+
\\ 3, 4, //
35+
\\ 5, 6, //
36+
\\ 7,
37+
\\};
38+
\\const a = []u8{
39+
\\ 1, 2, //
40+
\\ 3, 4, //
41+
\\ 5, 6, //
42+
\\ 7, 8, //
43+
\\};
44+
\\const a = []u8{
45+
\\ 1, 2, //
46+
\\ 3, 4, //
47+
\\ 5, 6, // blah
48+
\\ 7, 8, //
49+
\\};
50+
\\const a = []u8{
51+
\\ 1, 2, //
52+
\\ 3, 4, //
53+
\\ 5, 6, //
54+
\\ 7,
55+
\\};
56+
\\
57+
);
58+
}
59+
160
test "zig fmt: multiline string with backslash at end of line" {
261
try testCanonical(
362
\\comptime {

std/zig/render.zig

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(
1919
var tok_it = tree.tokens.iterator(0);
2020
while (tok_it.next()) |token| {
2121
if (token.id != Token.Id.LineComment) break;
22-
try stream.print("{}\n", tree.tokenSlicePtr(token));
22+
try stream.print("{}\n", mem.trimRight(u8, tree.tokenSlicePtr(token), " "));
2323
if (tok_it.peek()) |next_token| {
2424
const loc = tree.tokenLocationPtr(token.end, next_token);
2525
if (loc.line >= 2) {
@@ -532,12 +532,73 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
532532

533533
try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
534534

535+
// scan to find row size
536+
const maybe_row_size: ?usize = blk: {
537+
var count: usize = 0;
538+
var it = exprs.iterator(0);
539+
var prev_token = (??it.peek()).*.lastToken() + 1;
540+
while (it.next()) |expr| {
541+
const expr_last_token = expr.*.lastToken() + 1;
542+
const next_token = tree.tokens.at(expr_last_token + 1);
543+
const loc = tree.tokenLocationPtr(tree.tokens.at(prev_token).end, next_token);
544+
if (loc.line != 0) break :blk null;
545+
if (next_token.id == Token.Id.LineComment) {
546+
const trimmed = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ");
547+
if (trimmed.len == 2) {
548+
break :blk count;
549+
} else {
550+
break :blk null;
551+
}
552+
}
553+
prev_token = expr_last_token;
554+
count += 1;
555+
}
556+
break :blk null;
557+
};
558+
559+
535560
const new_indent = indent + indent_delta;
536561
try renderToken(tree, stream, lbrace, new_indent, Space.Newline);
562+
try stream.writeByteNTimes(' ', new_indent);
563+
564+
if (maybe_row_size) |row_size| {
565+
var it = exprs.iterator(0);
566+
var i: usize = 0;
567+
while (it.next()) |expr| {
568+
if (it.peek()) |next_expr| {
569+
try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
570+
571+
const comma = tree.nextToken(expr.*.lastToken());
572+
573+
if (i != row_size) {
574+
try renderToken(tree, stream, comma, new_indent, Space.IgnoreEmptyComment); // ,
575+
i += 1;
576+
continue;
577+
}
578+
i = 0;
579+
580+
try renderToken(tree, stream, comma, new_indent, Space.NoIndent); // ,
581+
582+
const next_token = tree.tokens.at(comma + 1);
583+
if (next_token.id != Token.Id.LineComment) {
584+
try stream.print(" //\n");
585+
}
586+
587+
try renderExtraNewline(tree, stream, next_expr.*);
588+
try stream.writeByteNTimes(' ', new_indent);
589+
} else if (i == row_size) {
590+
try renderTrailingCommaAndEmptyComment(allocator, stream, tree, new_indent, expr.*); // , //
591+
} else {
592+
try renderTrailingComma(allocator, stream, tree, new_indent, expr.*, Space.Newline); // ,
593+
}
594+
}
595+
try stream.writeByteNTimes(' ', indent);
596+
try renderToken(tree, stream, suffix_op.rtoken, indent, space);
597+
return;
598+
}
537599

538600
var it = exprs.iterator(0);
539601
while (it.next()) |expr| {
540-
try stream.writeByteNTimes(' ', new_indent);
541602

542603
if (it.peek()) |next_expr| {
543604
try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
@@ -546,6 +607,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
546607
try renderToken(tree, stream, comma, new_indent, Space.Newline); // ,
547608

548609
try renderExtraNewline(tree, stream, next_expr.*);
610+
try stream.writeByteNTimes(' ', new_indent);
549611
} else {
550612
try renderTrailingComma(allocator, stream, tree, new_indent, expr.*, Space.Newline);
551613
}
@@ -1496,11 +1558,12 @@ const Space = enum {
14961558
NoNewline,
14971559
NoIndent,
14981560
NoComment,
1561+
IgnoreEmptyComment,
14991562
};
15001563

15011564
fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, space: Space) (@typeOf(stream).Child.Error || Error)!void {
15021565
var token = tree.tokens.at(token_index);
1503-
try stream.write(tree.tokenSlicePtr(token));
1566+
try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(token), " "));
15041567

15051568
if (space == Space.NoComment) return;
15061569

@@ -1515,15 +1578,19 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
15151578
return stream.write("\n");
15161579
}
15171580
},
1518-
Space.Space => return stream.writeByte(' '),
1581+
Space.Space, Space.IgnoreEmptyComment => return stream.writeByte(' '),
15191582
Space.NoComment => unreachable,
15201583
}
15211584
}
15221585

1586+
if (space == Space.IgnoreEmptyComment and mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2) {
1587+
return stream.writeByte(' ');
1588+
}
1589+
15231590
var loc = tree.tokenLocationPtr(token.end, next_token);
15241591
var offset: usize = 1;
15251592
if (loc.line == 0) {
1526-
try stream.print(" {}", tree.tokenSlicePtr(next_token));
1593+
try stream.print(" {}", mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
15271594
offset = 2;
15281595
token = next_token;
15291596
next_token = tree.tokens.at(token_index + offset);
@@ -1546,7 +1613,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
15461613
}
15471614
},
15481615
Space.NoNewline => {},
1549-
Space.NoComment => unreachable,
1616+
Space.NoComment, Space.IgnoreEmptyComment => unreachable,
15501617
}
15511618
return;
15521619
}
@@ -1558,7 +1625,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
15581625
const newline_count = if (loc.line == 1) u8(1) else u8(2);
15591626
try stream.writeByteNTimes('\n', newline_count);
15601627
try stream.writeByteNTimes(' ', indent);
1561-
try stream.write(tree.tokenSlicePtr(next_token));
1628+
try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
15621629

15631630
offset += 1;
15641631
token = next_token;
@@ -1583,7 +1650,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
15831650
try stream.writeByteNTimes(' ', next_line_indent);
15841651
},
15851652
Space.NoNewline => {},
1586-
Space.NoComment => unreachable,
1653+
Space.NoComment, Space.IgnoreEmptyComment => unreachable,
15871654
}
15881655
return;
15891656
}
@@ -1621,3 +1688,28 @@ fn renderTrailingComma(allocator: &mem.Allocator, stream: var, tree: &ast.Tree,
16211688
},
16221689
}
16231690
}
1691+
1692+
fn renderTrailingCommaAndEmptyComment(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void
1693+
{
1694+
const end_token = base.lastToken() + 1;
1695+
switch (tree.tokens.at(end_token).id) {
1696+
Token.Id.Comma => {
1697+
try renderExpression(allocator, stream, tree, indent, base, Space.None);
1698+
try renderToken(tree, stream, end_token, indent, Space.Space); // ,
1699+
1700+
const next_token = tree.tokens.at(end_token + 1);
1701+
if (next_token.id != Token.Id.LineComment) {
1702+
try stream.print("//\n");
1703+
}
1704+
},
1705+
Token.Id.LineComment => {
1706+
try renderExpression(allocator, stream, tree, indent, base, Space.NoComment);
1707+
try stream.write(", ");
1708+
try renderToken(tree, stream, end_token, indent, Space.Newline);
1709+
},
1710+
else => {
1711+
try renderExpression(allocator, stream, tree, indent, base, Space.None);
1712+
try stream.write(", //\n");
1713+
},
1714+
}
1715+
}

0 commit comments

Comments
 (0)