From 283d441c19d5bafa01a7df24db277a6b08a86c00 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Sun, 30 Aug 2020 10:35:18 +1000 Subject: [PATCH 01/11] zig fmt: fix #3978, fix #2748 --- lib/std/zig/parser_test.zig | 53 +++++++++++++++++++++++++++++++++++++ lib/std/zig/render.zig | 15 ++++++++--- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 36ceb400dc..1aec1c3567 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3321,6 +3321,59 @@ 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, + \\}; + \\ + ); +} + 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..4432d08787 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -522,8 +522,12 @@ 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.pushIndentOneShot(); + { + try ais.pushIndent(); + defer ais.popIndent(); + try renderToken(tree, ais, infix_op_node.op_token, after_op_space); + } + try ais.pushIndentOneShot(); return renderExpression(allocator, ais, tree, infix_op_node.rhs, space); }, @@ -1873,7 +1877,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); // ) + + { + try 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); From 601331833a148ff3a1ab5cb4bba8bc63f4850e13 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Sun, 30 Aug 2020 10:34:44 +1000 Subject: [PATCH 02/11] Add passing test. close #5343 --- lib/std/zig/parser_test.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 1aec1c3567..6b8734c9d4 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3374,6 +3374,24 @@ test "zig fmt: test comments in field access chain" { ); } +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, + \\ ); + \\} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; From ea6181aaf6c3e22ced8b8ac202c5fc93a8e90674 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Fri, 11 Sep 2020 13:02:06 +1000 Subject: [PATCH 03/11] zig fmt: Add test for nesting if expressions --- lib/std/zig/parser_test.zig | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 6b8734c9d4..fe32a371e9 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3392,6 +3392,43 @@ test "zig fmt: Indent comma correctly after multiline string literals in arg lis ); } +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; + \\} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; From 9f0821e68836a495c726e0aae13e62c5235c5446 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Sun, 30 Aug 2020 15:02:05 +1000 Subject: [PATCH 04/11] zig fmt: Fix erroneously commented out code, add passing test case to close #5722 --- lib/std/zig/parser_test.zig | 15 +++++++++++++++ lib/std/zig/render.zig | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index fe32a371e9..50208582dc 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3429,6 +3429,21 @@ test "zig fmt: Control flow statement as body of blockless if" { ); } +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; + \\ }; + \\} + \\ + ); +} + 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 4432d08787..522be107b0 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1762,7 +1762,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); } From e1bd27119220c59211509f65c39fbb89c69b939b Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Sun, 30 Aug 2020 18:25:04 +1000 Subject: [PATCH 05/11] zig fmt: Allow trailing comments to do manual array formatting. close #5948 --- lib/std/zig/parser_test.zig | 44 ++++++- lib/std/zig/render.zig | 229 ++++++++++++++++++++++-------------- 2 files changed, 182 insertions(+), 91 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 50208582dc..20cafed5d3 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, @@ -3444,6 +3446,44 @@ test "zig fmt: " { ); } +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, + \\ }); + \\} + \\ + ); +} + 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 522be107b0..3594cd5ca9 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -523,11 +523,11 @@ fn renderExpression( }; { - try ais.pushIndent(); + ais.pushIndent(); defer ais.popIndent(); try renderToken(tree, ais, infix_op_node.op_token, after_op_space); } - try ais.pushIndentOneShot(); + ais.pushIndentOneShot(); return renderExpression(allocator, ais, tree, infix_op_node.rhs, space); }, @@ -746,109 +746,130 @@ fn renderExpression( } // 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, false) != 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); + var expr_index: usize = 0; + while (rowSize(tree, exprs[expr_index..], rtoken, true)) |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); - const comma = tree.nextToken(expr.*.lastToken()); + var expr_widths = widths[0 .. widths.len - row_size]; + var column_widths = widths[widths.len - row_size ..]; - if (col != row_size) { - try renderToken(tree, ais, comma, Space.Space); // , + // Null stream 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()); - const padding = column_widths[i % row_size] - expr_widths[i]; - try ais.writer().writeByteNTimes(' ', padding); - - col += 1; - continue; + // Find next row with trailing comment (if any) to end the current section then + var section_end = sec_end: { + var this_line_first_expr: usize = 0; + var this_line_size = rowSize(tree, row_exprs, rtoken, true); + 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, true); + } + if (expr.lastToken() + 2 < tree.token_ids.len) { + if (tree.token_ids[expr.lastToken() + 1] == .Comma and + tree.token_ids[expr.lastToken() + 2] == .LineComment and + tree.tokensOnSameLine(expr.lastToken(), expr.lastToken() + 2)) + { + var comment_token_loc = tree.token_locs[expr.lastToken() + 2]; + 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; - if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) { - try renderToken(tree, ais, comma, Space.Newline); // , - } else { - try renderToken(tree, ais, comma, Space.None); // , - } + const section_exprs = row_exprs[0..section_end]; - try renderExtraNewline(tree, ais, next_expr); - } else { - try renderExpression(allocator, ais, tree, expr, Space.Comma); // , + // Calculate size of columns in current section + for (section_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; + } + + // Render exprs in current section + var col: usize = 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 (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; + } + col = 1; + + if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) { + try renderToken(tree, ais, comma, Space.Newline); // , + } else { + try renderToken(tree, ais, comma, Space.None); // , + } + + try renderExtraNewline(tree, ais, next_expr); + } else { + 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); // , + } + } + } + + 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 => { @@ -1879,7 +1900,7 @@ fn renderExpression( const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space; { - try ais.pushIndent(); + ais.pushIndent(); defer ais.popIndent(); try renderToken(tree, ais, rparen, after_rparen_space); // ) } @@ -2567,3 +2588,33 @@ 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, force: bool) ?usize { + 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) return count; + count += 1; + } else { + if (force) return count; + 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) { + return 1; // force row size 1 + } else { + return null; // no newlines + } + } + return count; + } + } + unreachable; +} From 291482a0310312fa3d84b3a967fa3f2d5b71b165 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Mon, 9 Mar 2020 14:04:31 +1100 Subject: [PATCH 06/11] zig fmt: Don't consider width of expressions containing multiline string literals when calculating padding for array initializers. fixes #3739 Changes some of the special casing for multiline string literals. --- lib/std/zig/ast.zig | 9 +++ lib/std/zig/parser_test.zig | 59 +++++++++++++++ lib/std/zig/render.zig | 145 +++++++++++++++++++++--------------- 3 files changed, 155 insertions(+), 58 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 20cafed5d3..78443afe7a 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3484,6 +3484,65 @@ test "zig fmt: allow trailing line comments to do manual array formatting" { ); } +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 + \\ }); + \\} + \\ + ); +} + 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 3594cd5ca9..b2687ada98 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -714,37 +714,24 @@ 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); - } - - return renderToken(tree, ais, rtoken, space); - } - if (exprs.len == 1 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), } + if (exprs.len == 0) { + try renderToken(tree, ais, lbrace, Space.None); + return renderToken(tree, ais, rtoken, space); + } + + if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) { + const expr = exprs[0]; + + try renderToken(tree, ais, lbrace, Space.None); + try renderExpression(allocator, ais, tree, expr, Space.None); + return renderToken(tree, ais, rtoken, space); + } + // scan to find row size if (rowSize(tree, exprs, rtoken, false) != null) { { @@ -763,11 +750,7 @@ fn renderExpression( var expr_widths = widths[0 .. widths.len - row_size]; var column_widths = widths[widths.len - row_size ..]; - // Null stream 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()); - - // Find next row with trailing comment (if any) to end the current section then + // 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, true); @@ -779,12 +762,15 @@ fn renderExpression( this_line_first_expr = i; this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken, true); } - if (expr.lastToken() + 2 < tree.token_ids.len) { - if (tree.token_ids[expr.lastToken() + 1] == .Comma and - tree.token_ids[expr.lastToken() + 2] == .LineComment and - tree.tokensOnSameLine(expr.lastToken(), expr.lastToken() + 2)) + + 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[expr.lastToken() + 2]; + 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 @@ -799,18 +785,56 @@ fn renderExpression( 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 c: usize = 0; + var single_line = true; for (section_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 (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; + + if (!line_find_stream.byte_found) { + const col = c % row_size; + column_widths[col] = std.math.max(column_widths[col], 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) { + c += 1; + } else { + single_line = false; + c = 0; + } + } else { + single_line = false; + c = 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; + + if (!line_find_stream.byte_found) { + const col = c % row_size; + column_widths[col] = std.math.max(column_widths[col], width); + } + break; + } } // Render exprs in current section - var col: usize = 1; + c = 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]; @@ -818,23 +842,28 @@ fn renderExpression( const comma = tree.nextToken(expr.*.lastToken()); - if (col != row_size) { + if (c != last_col_index) { + line_find_stream.byte_found = false; + try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None); + try renderExpression(allocator, &auto_indenting_stream, tree, next_expr, Space.None); + if (!line_find_stream.byte_found) { + // Neither the current or next expression is multiline + try renderToken(tree, ais, comma, Space.Space); // , + assert(column_widths[c % row_size] >= expr_widths[i]); + const padding = column_widths[c % row_size] - expr_widths[i]; + try ais.writer().writeByteNTimes(' ', padding); + + c += 1; + continue; + } + } + if (single_line) { 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; } - col = 1; - - if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) { - try renderToken(tree, ais, comma, Space.Newline); // , - } else { - try renderToken(tree, ais, comma, Space.None); // , - } + c = 0; + try renderToken(tree, ais, comma, Space.Newline); // , try renderExtraNewline(tree, ais, next_expr); } else { const maybe_comma = tree.nextToken(expr.*.lastToken()); @@ -2594,13 +2623,13 @@ fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex, force: b 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()); + const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, exprs[i + 1].firstToken()); if (loc.line != 0) return count; count += 1; } else { if (force) return count; const expr_last_token = expr.lastToken(); - const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken); + const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, rtoken); if (loc.line == 0) { // all on one line const src_has_trailing_comma = trailblk: { From 206a8cf6709df51213252b03bf3ba4a9b8b52b6f Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Wed, 9 Sep 2020 21:45:05 +1000 Subject: [PATCH 07/11] zig fmt: fix comments and multiline literals in function args --- lib/std/zig/parser_test.zig | 40 +++++++++++++++++++++++ lib/std/zig/render.zig | 63 +++++++++++++++++++++---------------- 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 78443afe7a..d6dd9c1a73 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3543,6 +3543,46 @@ test "zig fmt: multiline string literals should play nice with array initializer ); } +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, + \\}); + \\ + ); +} + 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 b2687ada98..319788546e 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1058,21 +1058,22 @@ 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); + 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); @@ -1082,7 +1083,10 @@ 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; + if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) { + ais.pushIndentOneShot(); + } try renderExpression(allocator, ais, tree, param_node, Space.None); @@ -1092,7 +1096,7 @@ fn renderExpression( try renderToken(tree, ais, comma, Space.Space); } } - return renderToken(tree, ais, call.rtoken, space); + return renderToken(tree, ais, call.rtoken, space); // ) }, .ArrayAccess => { @@ -1497,6 +1501,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) { @@ -1548,19 +1556,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: { From c06674e701fdd74165778dd46b72cc469ba29140 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Wed, 9 Sep 2020 22:58:13 +1000 Subject: [PATCH 08/11] zig fmt: Small cleanup --- lib/std/zig/render.zig | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 319788546e..78f8ddb022 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -747,6 +747,10 @@ fn renderExpression( 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 ..]; @@ -791,7 +795,7 @@ fn renderExpression( var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer()); // Calculate size of columns in current section - var c: usize = 0; + var column_counter: usize = 0; var single_line = true; for (section_exprs) |expr, i| { if (i + 1 < section_exprs.len) { @@ -800,40 +804,42 @@ fn renderExpression( 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 col = c % row_size; - column_widths[col] = std.math.max(column_widths[col], width); + 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) { - c += 1; + column_counter += 1; } else { single_line = false; - c = 0; + column_counter = 0; } } else { single_line = false; - c = 0; + 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 col = c % row_size; - column_widths[col] = std.math.max(column_widths[col], width); + const column = column_counter % row_size; + column_widths[column] = std.math.max(column_widths[column], width); } break; } } // Render exprs in current section - c = 0; + column_counter = 0; var last_col_index: usize = row_size - 1; for (section_exprs) |expr, i| { if (i + 1 < section_exprs.len) { @@ -842,18 +848,15 @@ fn renderExpression( const comma = tree.nextToken(expr.*.lastToken()); - if (c != last_col_index) { - line_find_stream.byte_found = false; - try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None); - try renderExpression(allocator, &auto_indenting_stream, tree, next_expr, Space.None); - if (!line_find_stream.byte_found) { + 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[c % row_size] >= expr_widths[i]); - const padding = column_widths[c % row_size] - expr_widths[i]; + 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); - c += 1; + column_counter += 1; continue; } } @@ -862,7 +865,7 @@ fn renderExpression( continue; } - c = 0; + column_counter = 0; try renderToken(tree, ais, comma, Space.Newline); // , try renderExtraNewline(tree, ais, next_expr); } else { @@ -1091,7 +1094,6 @@ fn renderExpression( 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); } From 40b6e86a999ce80b9f71c7a88df6186400f151ac Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Thu, 10 Sep 2020 20:32:40 +1000 Subject: [PATCH 09/11] zig fmt: fix #6171 --- lib/std/zig/parser_test.zig | 18 ++++++++++++++++++ lib/std/zig/render.zig | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index d6dd9c1a73..f3cfe811a4 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3583,6 +3583,24 @@ test "zig fmt: use of comments and Multiline string literals may force the param ); } +test "zig fmt: single argument trailing commas in @builtins()" { + try testCanonical( + \\pub fn foo(qzz: []u8) i1 { + \\ @panic( + \\ foo, + \\ ); + \\ panic( + \\ foo, + \\ ); + \\ @panic( + \\ foo, + \\ bar, + \\ ); + \\} + \\ + ); +} + 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 78f8ddb022..fbf2139b42 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1489,7 +1489,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; From 1aacedf6e197ea212025dccad622894a44eb5461 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Thu, 10 Sep 2020 23:35:18 +1000 Subject: [PATCH 10/11] zig fmt: Fix regression in ArrayInitializers --- lib/std/zig/parser_test.zig | 41 ++++++++++++++++++++++++++++++++++--- lib/std/zig/render.zig | 39 +++++++++++++++-------------------- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index f3cfe811a4..c7d64bc513 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -3516,9 +3516,13 @@ test "zig fmt: multiline string literals should play nice with array initializer \\ .{( \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \\ )}, - \\ .{ "xxxxxxx", "xxx", ( - \\ \\ xxx - \\ ), "xxx", "xxx" }, + \\ .{ + \\ "xxxxxxx", "xxx", + \\ ( + \\ \\ xxx + \\ ), + \\ "xxx", "xxx", + \\ }, \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" }, \\ "aaaaaaa", "bbbbbb", "ccccc", // - \\ "dddd", ("eee"), ("fff"), @@ -3601,6 +3605,37 @@ test "zig fmt: single argument trailing commas in @builtins()" { ); } +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 fbf2139b42..30f739aaef 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -733,14 +733,14 @@ fn renderExpression( } // scan to find row size - if (rowSize(tree, exprs, rtoken, false) != null) { + if (rowSize(tree, exprs, rtoken) != null) { { ais.pushIndentNextLine(); defer ais.popIndent(); try renderToken(tree, ais, lbrace, Space.Newline); var expr_index: usize = 0; - while (rowSize(tree, exprs[expr_index..], rtoken, true)) |row_size| { + 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); @@ -757,14 +757,14 @@ fn renderExpression( // 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, true); + 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, true); + this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken); } const maybe_comma = expr.lastToken() + 1; @@ -860,7 +860,7 @@ fn renderExpression( continue; } } - if (single_line) { + if (single_line and row_size != 1) { try renderToken(tree, ais, comma, Space.Space); // , continue; } @@ -1087,7 +1087,8 @@ fn renderExpression( const params = 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) { + const maybe_multiline_string = param_node.firstToken(); + if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) { ais.pushIndentOneShot(); } @@ -2629,7 +2630,16 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo }; } -fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex, force: bool) ?usize { +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) { @@ -2638,21 +2648,6 @@ fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex, force: b if (loc.line != 0) return count; count += 1; } else { - if (force) return count; - const expr_last_token = expr.lastToken(); - const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, 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) { - return 1; // force row size 1 - } else { - return null; // no newlines - } - } return count; } } From 4496a6c9cccbd6a9c82b5d4ca7f533b18ebeab32 Mon Sep 17 00:00:00 2001 From: Lachlan Easton Date: Tue, 15 Sep 2020 18:49:59 +1000 Subject: [PATCH 11/11] zig fmt: Special case un-indent comma after multiline string in param list --- lib/std/zig/parser_test.zig | 11 +++++++++-- lib/std/zig/render.zig | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index c7d64bc513..994ad6d5d1 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1374,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), @@ -3385,10 +3385,17 @@ test "zig fmt: Indent comma correctly after multiline string literals in arg lis \\ \\------------ \\ \\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); \\} \\ ); diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 30f739aaef..67afbb77d9 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1071,6 +1071,13 @@ fn renderExpression( 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);