aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-09-27 05:49:38 -0400
committerGitHub <noreply@github.com>2020-09-27 05:49:38 -0400
commit8794ce6f79886e5ebbf0476d56917e219b52c561 (patch)
treeb844b039b4a92be26a80175715b12551ca0fa8f4 /lib/std
parenteab51b7785ce0989f90a5cdde4b1110f40875ddb (diff)
parent4496a6c9cccbd6a9c82b5d4ca7f533b18ebeab32 (diff)
downloadzig-8794ce6f79886e5ebbf0476d56917e219b52c561.tar.gz
zig-8794ce6f79886e5ebbf0476d56917e219b52c561.zip
Merge pull request #6293 from LakeByTheWoods/fmt_fixes
zig fmt fixes
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/zig/ast.zig9
-rw-r--r--lib/std/zig/parser_test.zig328
-rw-r--r--lib/std/zig/render.zig380
3 files changed, 575 insertions, 142 deletions
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 404e8c413a..d8943adde0 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -823,6 +823,15 @@ pub const Node = struct {
}
}
+ pub fn findFirstWithId(self: *Node, id: Id) ?*Node {
+ if (self.id == id) return self;
+ var child_i: usize = 0;
+ while (self.iterate(child_i)) |child| : (child_i += 1) {
+ if (child.findFirstWithId(id)) |result| return result;
+ }
+ return null;
+ }
+
pub fn dump(self: *Node, indent: usize) void {
{
var i: usize = 0;
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index 36ceb400dc..994ad6d5d1 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -1301,8 +1301,10 @@ test "zig fmt: array literal with hint" {
\\const a = []u8{
\\ 1, 2,
\\ 3, 4,
- \\ 5, 6, // blah
- \\ 7, 8,
+ \\ 5,
+ \\ 6, // blah
+ \\ 7,
+ \\ 8,
\\};
\\const a = []u8{
\\ 1, 2,
@@ -1372,7 +1374,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
\\ \\ZIG_C_HEADER_FILES {}
\\ \\ZIG_DIA_GUIDS_LIB {}
\\ \\
- \\ ,
+ \\ ,
\\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
\\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
\\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
@@ -3321,6 +3323,326 @@ test "zig fmt: Don't add extra newline after if" {
);
}
+test "zig fmt: comments in ternary ifs" {
+ try testCanonical(
+ \\const x = if (true) {
+ \\ 1;
+ \\} else if (false)
+ \\ // Comment
+ \\ 0;
+ \\const y = if (true)
+ \\ // Comment
+ \\ 1
+ \\else
+ \\ 0;
+ \\
+ \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
+ \\
+ );
+}
+
+test "zig fmt: test comments in field access chain" {
+ try testCanonical(
+ \\pub const str = struct {
+ \\ pub const Thing = more.more //
+ \\ .more() //
+ \\ .more().more() //
+ \\ .more() //
+ \\ // .more() //
+ \\ .more() //
+ \\ .more();
+ \\ data: Data,
+ \\};
+ \\
+ \\pub const str = struct {
+ \\ pub const Thing = more.more //
+ \\ .more() //
+ \\ // .more() //
+ \\ // .more() //
+ \\ // .more() //
+ \\ .more() //
+ \\ .more();
+ \\ data: Data,
+ \\};
+ \\
+ \\pub const str = struct {
+ \\ pub const Thing = more //
+ \\ .more //
+ \\ .more() //
+ \\ .more();
+ \\ data: Data,
+ \\};
+ \\
+ );
+}
+
+test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" {
+ try testCanonical(
+ \\fn foo() void {
+ \\ z.display_message_dialog(
+ \\ *const [323:0]u8,
+ \\ \\Message Text
+ \\ \\------------
+ \\ \\xxxxxxxxxxxx
+ \\ \\xxxxxxxxxxxx
+ \\ ,
+ \\ g.GtkMessageType.GTK_MESSAGE_WARNING,
+ \\ null,
+ \\ );
+ \\
+ \\ z.display_message_dialog(*const [323:0]u8,
+ \\ \\Message Text
+ \\ \\------------
+ \\ \\xxxxxxxxxxxx
+ \\ \\xxxxxxxxxxxx
+ \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null);
+ \\}
+ \\
+ );
+}
+
+test "zig fmt: Control flow statement as body of blockless if" {
+ try testCanonical(
+ \\pub fn main() void {
+ \\ const zoom_node = if (focused_node == layout_first)
+ \\ if (it.next()) {
+ \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
+ \\ } else null
+ \\ else
+ \\ focused_node;
+ \\
+ \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
+ \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
+ \\ } else null else
+ \\ focused_node;
+ \\
+ \\ const zoom_node = if (focused_node == layout_first)
+ \\ if (it.next()) {
+ \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
+ \\ } else null;
+ \\
+ \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
+ \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
+ \\ };
+ \\
+ \\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| {
+ \\ break node;
+ \\ };
+ \\
+ \\ const zoom_node = if (focused_node == layout_first) switch (nodes) {
+ \\ 0 => 0,
+ \\ } else
+ \\ focused_node;
+ \\}
+ \\
+ );
+}
+
+test "zig fmt: " {
+ try testCanonical(
+ \\pub fn sendViewTags(self: Self) void {
+ \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
+ \\ while (it.next()) |node|
+ \\ view_tags.append(node.view.current_tags) catch {
+ \\ c.wl_resource_post_no_memory(self.wl_resource);
+ \\ log.crit(.river_status, "out of memory", .{});
+ \\ return;
+ \\ };
+ \\}
+ \\
+ );
+}
+
+test "zig fmt: allow trailing line comments to do manual array formatting" {
+ try testCanonical(
+ \\fn foo() void {
+ \\ self.code.appendSliceAssumeCapacity(&[_]u8{
+ \\ 0x55, // push rbp
+ \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
+ \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
+ \\ });
+ \\
+ \\ di_buf.appendAssumeCapacity(&[_]u8{
+ \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
+ \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
+ \\ DW.AT_low_pc, DW_FORM_addr,
+ \\ DW.AT_high_pc, DW_FORM_addr,
+ \\ DW.AT_name, DW_FORM_strp,
+ \\ DW.AT_comp_dir, DW_FORM_strp,
+ \\ DW.AT_producer, DW_FORM_strp,
+ \\ DW.AT_language, DW_FORM_data2,
+ \\ 0, 0, // sentinel
+ \\ });
+ \\
+ \\ self.code.appendSliceAssumeCapacity(&[_]u8{
+ \\ 0x55, // push rbp
+ \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
+ \\ // How do we handle this?
+ \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
+ \\ // Here's a blank line, should that be allowed?
+ \\
+ \\ 0x48, 0x89, 0xe5,
+ \\ 0x33, 0x45,
+ \\ // Now the comment breaks a single line -- how do we handle this?
+ \\ 0x88,
+ \\ });
+ \\}
+ \\
+ );
+}
+
+test "zig fmt: multiline string literals should play nice with array initializers" {
+ try testCanonical(
+ \\fn main() void {
+ \\ var a = .{.{.{.{.{.{.{.{
+ \\ 0,
+ \\ }}}}}}}};
+ \\ myFunc(.{
+ \\ "aaaaaaa", "bbbbbb", "ccccc",
+ \\ "dddd", ("eee"), ("fff"),
+ \\ ("gggg"),
+ \\ // Line comment
+ \\ \\Multiline String Literals can be quite long
+ \\ ,
+ \\ \\Multiline String Literals can be quite long
+ \\ \\Multiline String Literals can be quite long
+ \\ ,
+ \\ \\Multiline String Literals can be quite long
+ \\ \\Multiline String Literals can be quite long
+ \\ \\Multiline String Literals can be quite long
+ \\ \\Multiline String Literals can be quite long
+ \\ ,
+ \\ (
+ \\ \\Multiline String Literals can be quite long
+ \\ ),
+ \\ .{
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ },
+ \\ .{(
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ )},
+ \\ .{
+ \\ "xxxxxxx", "xxx",
+ \\ (
+ \\ \\ xxx
+ \\ ),
+ \\ "xxx", "xxx",
+ \\ },
+ \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
+ \\ "aaaaaaa", "bbbbbb", "ccccc", // -
+ \\ "dddd", ("eee"), ("fff"),
+ \\ .{
+ \\ "xxx", "xxx",
+ \\ (
+ \\ \\ xxx
+ \\ ),
+ \\ "xxxxxxxxxxxxxx", "xxx",
+ \\ },
+ \\ .{
+ \\ (
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ ),
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ },
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ \\ });
+ \\}
+ \\
+ );
+}
+
+test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
+ try testCanonical(
+ \\pub fn makeMemUndefined(qzz: []u8) i1 {
+ \\ cases.add( // fixed bug #2032
+ \\ "compile diagnostic string for top level decl type",
+ \\ \\export fn entry() void {
+ \\ \\ var foo: u32 = @This(){};
+ \\ \\}
+ \\ , &[_][]const u8{
+ \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization",
+ \\ });
+ \\ @compileError(
+ \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
+ \\ \\ Consider providing your own hash function.
+ \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
+ \\ \\ Consider providing your own hash function.
+ \\ );
+ \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
+ \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
+ \\}
+ \\
+ \\// This looks like garbage don't do this
+ \\const rparen = tree.prevToken(
+ \\// the first token for the annotation expressions is the left
+ \\// parenthesis, hence the need for two prevToken
+ \\ if (fn_proto.getAlignExpr()) |align_expr|
+ \\ tree.prevToken(tree.prevToken(align_expr.firstToken()))
+ \\else if (fn_proto.getSectionExpr()) |section_expr|
+ \\ tree.prevToken(tree.prevToken(section_expr.firstToken()))
+ \\else if (fn_proto.getCallconvExpr()) |callconv_expr|
+ \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
+ \\else switch (fn_proto.return_type) {
+ \\ .Explicit => |node| node.firstToken(),
+ \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
+ \\ .Invalid => unreachable,
+ \\});
+ \\
+ );
+}
+
+test "zig fmt: single argument trailing commas in @builtins()" {
+ try testCanonical(
+ \\pub fn foo(qzz: []u8) i1 {
+ \\ @panic(
+ \\ foo,
+ \\ );
+ \\ panic(
+ \\ foo,
+ \\ );
+ \\ @panic(
+ \\ foo,
+ \\ bar,
+ \\ );
+ \\}
+ \\
+ );
+}
+
+test "zig fmt: trailing comma should force multiline 1 column" {
+ try testTransform(
+ \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,};
+ \\
+ ,
+ \\pub const UUID_NULL: uuid_t = [16]u8{
+ \\ 0,
+ \\ 0,
+ \\ 0,
+ \\ 0,
+ \\};
+ \\
+ );
+}
+
+test "zig fmt: function params should align nicely" {
+ try testCanonical(
+ \\pub fn foo() void {
+ \\ cases.addRuntimeSafety("slicing operator with sentinel",
+ \\ \\const std = @import("std");
+ \\ ++ check_panic_msg ++
+ \\ \\pub fn main() void {
+ \\ \\ var buf = [4]u8{'a','b','c',0};
+ \\ \\ const slice = buf[0..:0];
+ \\ \\}
+ \\ );
+ \\}
+ \\
+ );
+}
+
const std = @import("std");
const mem = std.mem;
const warn = std.debug.warn;
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index 237ca07d2b..67afbb77d9 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -522,7 +522,11 @@ fn renderExpression(
break :blk if (loc.line == 0) op_space else Space.Newline;
};
- try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
+ {
+ ais.pushIndent();
+ defer ais.popIndent();
+ try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
+ }
ais.pushIndentOneShot();
return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
},
@@ -710,141 +714,194 @@ fn renderExpression(
.node => |node| tree.nextToken(node.lastToken()),
};
- if (exprs.len == 0) {
- switch (lhs) {
- .dot => |dot| try renderToken(tree, ais, dot, Space.None),
- .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
- }
-
- {
- ais.pushIndent();
- defer ais.popIndent();
- try renderToken(tree, ais, lbrace, Space.None);
- }
+ switch (lhs) {
+ .dot => |dot| try renderToken(tree, ais, dot, Space.None),
+ .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
+ }
+ if (exprs.len == 0) {
+ try renderToken(tree, ais, lbrace, Space.None);
return renderToken(tree, ais, rtoken, space);
}
- if (exprs.len == 1 and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
+
+ if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
const expr = exprs[0];
- switch (lhs) {
- .dot => |dot| try renderToken(tree, ais, dot, Space.None),
- .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
- }
try renderToken(tree, ais, lbrace, Space.None);
try renderExpression(allocator, ais, tree, expr, Space.None);
return renderToken(tree, ais, rtoken, space);
}
- switch (lhs) {
- .dot => |dot| try renderToken(tree, ais, dot, Space.None),
- .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
- }
-
// scan to find row size
- const maybe_row_size: ?usize = blk: {
- var count: usize = 1;
- for (exprs) |expr, i| {
- if (i + 1 < exprs.len) {
- const expr_last_token = expr.lastToken() + 1;
- const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i + 1].firstToken());
- if (loc.line != 0) break :blk count;
- count += 1;
- } else {
- const expr_last_token = expr.lastToken();
- const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
- if (loc.line == 0) {
- // all on one line
- const src_has_trailing_comma = trailblk: {
- const maybe_comma = tree.prevToken(rtoken);
- break :trailblk tree.token_ids[maybe_comma] == .Comma;
- };
- if (src_has_trailing_comma) {
- break :blk 1; // force row size 1
- } else {
- break :blk null; // no newlines
- }
- }
- break :blk count;
- }
- }
- unreachable;
- };
-
- if (maybe_row_size) |row_size| {
- // A place to store the width of each expression and its column's maximum
- var widths = try allocator.alloc(usize, exprs.len + row_size);
- defer allocator.free(widths);
- mem.set(usize, widths, 0);
-
- var expr_widths = widths[0 .. widths.len - row_size];
- var column_widths = widths[widths.len - row_size ..];
-
- // Null ais for counting the printed length of each expression
- var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
- var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
-
- for (exprs) |expr, i| {
- counting_stream.bytes_written = 0;
- try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
- const width = @intCast(usize, counting_stream.bytes_written);
- const col = i % row_size;
- column_widths[col] = std.math.max(column_widths[col], width);
- expr_widths[i] = width;
- }
-
+ if (rowSize(tree, exprs, rtoken) != null) {
{
ais.pushIndentNextLine();
defer ais.popIndent();
try renderToken(tree, ais, lbrace, Space.Newline);
- var col: usize = 1;
- for (exprs) |expr, i| {
- if (i + 1 < exprs.len) {
- const next_expr = exprs[i + 1];
- try renderExpression(allocator, ais, tree, expr, Space.None);
-
- const comma = tree.nextToken(expr.*.lastToken());
-
- if (col != row_size) {
- try renderToken(tree, ais, comma, Space.Space); // ,
-
- const padding = column_widths[i % row_size] - expr_widths[i];
- try ais.writer().writeByteNTimes(' ', padding);
-
- col += 1;
- continue;
+ var expr_index: usize = 0;
+ while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
+ const row_exprs = exprs[expr_index..];
+ // A place to store the width of each expression and its column's maximum
+ var widths = try allocator.alloc(usize, row_exprs.len + row_size);
+ defer allocator.free(widths);
+ mem.set(usize, widths, 0);
+
+ var expr_newlines = try allocator.alloc(bool, row_exprs.len);
+ defer allocator.free(expr_newlines);
+ mem.set(bool, expr_newlines, false);
+
+ var expr_widths = widths[0 .. widths.len - row_size];
+ var column_widths = widths[widths.len - row_size ..];
+
+ // Find next row with trailing comment (if any) to end the current section
+ var section_end = sec_end: {
+ var this_line_first_expr: usize = 0;
+ var this_line_size = rowSize(tree, row_exprs, rtoken);
+ for (row_exprs) |expr, i| {
+ // Ignore comment on first line of this section
+ if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
+ // Track start of line containing comment
+ if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
+ this_line_first_expr = i;
+ this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
+ }
+
+ const maybe_comma = expr.lastToken() + 1;
+ const maybe_comment = expr.lastToken() + 2;
+ if (maybe_comment < tree.token_ids.len) {
+ if (tree.token_ids[maybe_comma] == .Comma and
+ tree.token_ids[maybe_comment] == .LineComment and
+ tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
+ {
+ var comment_token_loc = tree.token_locs[maybe_comment];
+ const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
+ if (!comment_is_empty) {
+ // Found row ending in comment
+ break :sec_end i - this_line_size.? + 1;
+ }
+ }
+ }
}
- col = 1;
+ break :sec_end row_exprs.len;
+ };
+ expr_index += section_end;
+
+ const section_exprs = row_exprs[0..section_end];
+
+ // Null stream for counting the printed length of each expression
+ var line_find_stream = std.io.findByteOutStream('\n', std.io.null_out_stream);
+ var counting_stream = std.io.countingOutStream(line_find_stream.writer());
+ var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
+
+ // Calculate size of columns in current section
+ var column_counter: usize = 0;
+ var single_line = true;
+ for (section_exprs) |expr, i| {
+ if (i + 1 < section_exprs.len) {
+ counting_stream.bytes_written = 0;
+ line_find_stream.byte_found = false;
+ try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
+ const width = @intCast(usize, counting_stream.bytes_written);
+ expr_widths[i] = width;
+ expr_newlines[i] = line_find_stream.byte_found;
+
+ if (!line_find_stream.byte_found) {
+ const column = column_counter % row_size;
+ column_widths[column] = std.math.max(column_widths[column], width);
+
+ const expr_last_token = expr.*.lastToken() + 1;
+ const next_expr = section_exprs[i + 1];
+ const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
+ if (loc.line == 0) {
+ column_counter += 1;
+ } else {
+ single_line = false;
+ column_counter = 0;
+ }
+ } else {
+ single_line = false;
+ column_counter = 0;
+ }
+ } else {
+ counting_stream.bytes_written = 0;
+ try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
+ const width = @intCast(usize, counting_stream.bytes_written);
+ expr_widths[i] = width;
+ expr_newlines[i] = line_find_stream.byte_found;
+
+ if (!line_find_stream.byte_found) {
+ const column = column_counter % row_size;
+ column_widths[column] = std.math.max(column_widths[column], width);
+ }
+ break;
+ }
+ }
- if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
+ // Render exprs in current section
+ column_counter = 0;
+ var last_col_index: usize = row_size - 1;
+ for (section_exprs) |expr, i| {
+ if (i + 1 < section_exprs.len) {
+ const next_expr = section_exprs[i + 1];
+ try renderExpression(allocator, ais, tree, expr, Space.None);
+
+ const comma = tree.nextToken(expr.*.lastToken());
+
+ if (column_counter != last_col_index) {
+ if (!expr_newlines[i] and !expr_newlines[i + 1]) {
+ // Neither the current or next expression is multiline
+ try renderToken(tree, ais, comma, Space.Space); // ,
+ assert(column_widths[column_counter % row_size] >= expr_widths[i]);
+ const padding = column_widths[column_counter % row_size] - expr_widths[i];
+ try ais.writer().writeByteNTimes(' ', padding);
+
+ column_counter += 1;
+ continue;
+ }
+ }
+ if (single_line and row_size != 1) {
+ try renderToken(tree, ais, comma, Space.Space); // ,
+ continue;
+ }
+
+ column_counter = 0;
try renderToken(tree, ais, comma, Space.Newline); // ,
+ try renderExtraNewline(tree, ais, next_expr);
} else {
- try renderToken(tree, ais, comma, Space.None); // ,
+ const maybe_comma = tree.nextToken(expr.*.lastToken());
+ if (tree.token_ids[maybe_comma] == .Comma) {
+ try renderExpression(allocator, ais, tree, expr, Space.None); // ,
+ try renderToken(tree, ais, maybe_comma, Space.Newline); // ,
+ } else {
+ try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
+ }
}
+ }
- try renderExtraNewline(tree, ais, next_expr);
- } else {
- try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
+ if (expr_index == exprs.len) {
+ break;
}
}
}
- return renderToken(tree, ais, rtoken, space);
- } else {
- try renderToken(tree, ais, lbrace, Space.Space);
- for (exprs) |expr, i| {
- if (i + 1 < exprs.len) {
- const next_expr = exprs[i + 1];
- try renderExpression(allocator, ais, tree, expr, Space.None);
- const comma = tree.nextToken(expr.*.lastToken());
- try renderToken(tree, ais, comma, Space.Space); // ,
- } else {
- try renderExpression(allocator, ais, tree, expr, Space.Space);
- }
- }
return renderToken(tree, ais, rtoken, space);
}
+
+ // Single line
+ try renderToken(tree, ais, lbrace, Space.Space);
+ for (exprs) |expr, i| {
+ if (i + 1 < exprs.len) {
+ const next_expr = exprs[i + 1];
+ try renderExpression(allocator, ais, tree, expr, Space.None);
+ const comma = tree.nextToken(expr.*.lastToken());
+ try renderToken(tree, ais, comma, Space.Space); // ,
+ } else {
+ try renderExpression(allocator, ais, tree, expr, Space.Space);
+ }
+ }
+
+ return renderToken(tree, ais, rtoken, space);
},
.StructInitializer, .StructInitializerDot => {
@@ -1004,21 +1061,29 @@ fn renderExpression(
};
if (src_has_trailing_comma) {
- try renderToken(tree, ais, lparen, Space.Newline);
-
- const params = call.params();
- for (params) |param_node, i| {
+ {
ais.pushIndent();
defer ais.popIndent();
- if (i + 1 < params.len) {
- const next_node = params[i + 1];
- try renderExpression(allocator, ais, tree, param_node, Space.None);
- const comma = tree.nextToken(param_node.lastToken());
- try renderToken(tree, ais, comma, Space.Newline); // ,
- try renderExtraNewline(tree, ais, next_node);
- } else {
- try renderExpression(allocator, ais, tree, param_node, Space.Comma);
+ try renderToken(tree, ais, lparen, Space.Newline); // (
+ const params = call.params();
+ for (params) |param_node, i| {
+ if (i + 1 < params.len) {
+ const next_node = params[i + 1];
+ try renderExpression(allocator, ais, tree, param_node, Space.None);
+
+ // Unindent the comma for multiline string literals
+ const maybe_multiline_string = param_node.firstToken();
+ const is_multiline_string = tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine;
+ if (is_multiline_string) ais.popIndent();
+ defer if (is_multiline_string) ais.pushIndent();
+
+ const comma = tree.nextToken(param_node.lastToken());
+ try renderToken(tree, ais, comma, Space.Newline); // ,
+ try renderExtraNewline(tree, ais, next_node);
+ } else {
+ try renderExpression(allocator, ais, tree, param_node, Space.Comma);
+ }
}
}
return renderToken(tree, ais, call.rtoken, space);
@@ -1028,17 +1093,20 @@ fn renderExpression(
const params = call.params();
for (params) |param_node, i| {
- if (param_node.*.tag == .MultilineStringLiteral) ais.pushIndentOneShot();
+ const maybe_comment = param_node.firstToken() - 1;
+ const maybe_multiline_string = param_node.firstToken();
+ if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) {
+ ais.pushIndentOneShot();
+ }
try renderExpression(allocator, ais, tree, param_node, Space.None);
if (i + 1 < params.len) {
- const next_param = params[i + 1];
const comma = tree.nextToken(param_node.lastToken());
try renderToken(tree, ais, comma, Space.Space);
}
}
- return renderToken(tree, ais, call.rtoken, space);
+ return renderToken(tree, ais, call.rtoken, space); // )
},
.ArrayAccess => {
@@ -1429,7 +1497,7 @@ fn renderExpression(
try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
const src_params_trailing_comma = blk: {
- if (builtin_call.params_len < 2) break :blk false;
+ if (builtin_call.params_len == 0) break :blk false;
const last_node = builtin_call.params()[builtin_call.params_len - 1];
const maybe_comma = tree.nextToken(last_node.lastToken());
break :blk tree.token_ids[maybe_comma] == .Comma;
@@ -1443,6 +1511,10 @@ fn renderExpression(
// render all on one line, no trailing comma
const params = builtin_call.params();
for (params) |param_node, i| {
+ const maybe_comment = param_node.firstToken() - 1;
+ if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) {
+ ais.pushIndentOneShot();
+ }
try renderExpression(allocator, ais, tree, param_node, Space.None);
if (i + 1 < params.len) {
@@ -1494,19 +1566,20 @@ fn renderExpression(
assert(tree.token_ids[lparen] == .LParen);
const rparen = tree.prevToken(
- // the first token for the annotation expressions is the left
- // parenthesis, hence the need for two prevToken
- if (fn_proto.getAlignExpr()) |align_expr|
- tree.prevToken(tree.prevToken(align_expr.firstToken()))
- else if (fn_proto.getSectionExpr()) |section_expr|
- tree.prevToken(tree.prevToken(section_expr.firstToken()))
- else if (fn_proto.getCallconvExpr()) |callconv_expr|
- tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
- else switch (fn_proto.return_type) {
- .Explicit => |node| node.firstToken(),
- .InferErrorSet => |node| tree.prevToken(node.firstToken()),
- .Invalid => unreachable,
- });
+ // the first token for the annotation expressions is the left
+ // parenthesis, hence the need for two prevToken
+ if (fn_proto.getAlignExpr()) |align_expr|
+ tree.prevToken(tree.prevToken(align_expr.firstToken()))
+ else if (fn_proto.getSectionExpr()) |section_expr|
+ tree.prevToken(tree.prevToken(section_expr.firstToken()))
+ else if (fn_proto.getCallconvExpr()) |callconv_expr|
+ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
+ else switch (fn_proto.return_type) {
+ .Explicit => |node| node.firstToken(),
+ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
+ .Invalid => unreachable,
+ },
+ );
assert(tree.token_ids[rparen] == .RParen);
const src_params_trailing_comma = blk: {
@@ -1758,7 +1831,7 @@ fn renderExpression(
}
if (while_node.payload) |payload| {
- const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;
+ const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
try renderExpression(allocator, ais, tree, payload, payload_space);
}
@@ -1873,7 +1946,12 @@ fn renderExpression(
if (src_has_newline) {
const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
- try renderToken(tree, ais, rparen, after_rparen_space); // )
+
+ {
+ ais.pushIndent();
+ defer ais.popIndent();
+ try renderToken(tree, ais, rparen, after_rparen_space); // )
+ }
if (if_node.payload) |payload| {
try renderExpression(allocator, ais, tree, payload, Space.Newline);
@@ -2558,3 +2636,27 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
else => try ais.writer().writeByte(byte),
};
}
+
+fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize {
+ const first_token = exprs[0].firstToken();
+ const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken);
+ if (first_loc.line == 0) {
+ const maybe_comma = tree.prevToken(rtoken);
+ if (tree.token_ids[maybe_comma] == .Comma)
+ return 1;
+ return null; // no newlines
+ }
+
+ var count: usize = 1;
+ for (exprs) |expr, i| {
+ if (i + 1 < exprs.len) {
+ const expr_last_token = expr.lastToken() + 1;
+ const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, exprs[i + 1].firstToken());
+ if (loc.line != 0) return count;
+ count += 1;
+ } else {
+ return count;
+ }
+ }
+ unreachable;
+}