authorgravatar for lachlan@lakebythewoods.xyzLachlan Easton <lachlan@lakebythewoods.xyz> 2020-03-09 14:04:31+11:00
committergravatar for lachlan@lakebythewoods.xyzLachlan Easton <lachlan@lakebythewoods.xyz> 2020-09-18 20:34:00+10:00
log291482a0310312fa3d84b3a967fa3f2d5b71b165
treef6e8805d3cc197de449da1ab6c39b6cc2916cbd0
parente1bd27119220c59211509f65c39fbb89c69b939b

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.

3 files changed, 150 insertions(+), 53 deletions(-)

lib/std/zig/ast.zig+9
......@@ -823,6 +823,15 @@ pub const Node = struct {
823823 }
824824 }
825825
826 pub fn findFirstWithId(self: *Node, id: Id) ?*Node {
827 if (self.id == id) return self;
828 var child_i: usize = 0;
829 while (self.iterate(child_i)) |child| : (child_i += 1) {
830 if (child.findFirstWithId(id)) |result| return result;
831 }
832 return null;
833 }
834
826835 pub fn dump(self: *Node, indent: usize) void {
827836 {
828837 var i: usize = 0;
lib/std/zig/parser_test.zig+59
......@@ -3484,6 +3484,65 @@ test "zig fmt: allow trailing line comments to do manual array formatting" {
34843484 );
34853485}
34863486
3487test "zig fmt: multiline string literals should play nice with array initializers" {
3488 try testCanonical(
3489 \\fn main() void {
3490 \\ var a = .{.{.{.{.{.{.{.{
3491 \\ 0,
3492 \\ }}}}}}}};
3493 \\ myFunc(.{
3494 \\ "aaaaaaa", "bbbbbb", "ccccc",
3495 \\ "dddd", ("eee"), ("fff"),
3496 \\ ("gggg"),
3497 \\ // Line comment
3498 \\ \\Multiline String Literals can be quite long
3499 \\ ,
3500 \\ \\Multiline String Literals can be quite long
3501 \\ \\Multiline String Literals can be quite long
3502 \\ ,
3503 \\ \\Multiline String Literals can be quite long
3504 \\ \\Multiline String Literals can be quite long
3505 \\ \\Multiline String Literals can be quite long
3506 \\ \\Multiline String Literals can be quite long
3507 \\ ,
3508 \\ (
3509 \\ \\Multiline String Literals can be quite long
3510 \\ ),
3511 \\ .{
3512 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3513 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3514 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3515 \\ },
3516 \\ .{(
3517 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3518 \\ )},
3519 \\ .{ "xxxxxxx", "xxx", (
3520 \\ \\ xxx
3521 \\ ), "xxx", "xxx" },
3522 \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
3523 \\ "aaaaaaa", "bbbbbb", "ccccc", // -
3524 \\ "dddd", ("eee"), ("fff"),
3525 \\ .{
3526 \\ "xxx", "xxx",
3527 \\ (
3528 \\ \\ xxx
3529 \\ ),
3530 \\ "xxxxxxxxxxxxxx", "xxx",
3531 \\ },
3532 \\ .{
3533 \\ (
3534 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3535 \\ ),
3536 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3537 \\ },
3538 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3539 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3540 \\ });
3541 \\}
3542 \\
3543 );
3544}
3545
34873546const std = @import("std");
34883547const mem = std.mem;
34893548const warn = std.debug.warn;
lib/std/zig/render.zig+82-53
......@@ -714,37 +714,24 @@ fn renderExpression(
714714 .node => |node| tree.nextToken(node.lastToken()),
715715 };
716716
717 if (exprs.len == 0) {
718 switch (lhs) {
719 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
720 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
721 }
722
723 {
724 ais.pushIndent();
725 defer ais.popIndent();
726 try renderToken(tree, ais, lbrace, Space.None);
727 }
717 switch (lhs) {
718 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
719 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
720 }
728721
722 if (exprs.len == 0) {
723 try renderToken(tree, ais, lbrace, Space.None);
729724 return renderToken(tree, ais, rtoken, space);
730725 }
731 if (exprs.len == 1 and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
726
727 if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
732728 const expr = exprs[0];
733729
734 switch (lhs) {
735 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
736 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
737 }
738730 try renderToken(tree, ais, lbrace, Space.None);
739731 try renderExpression(allocator, ais, tree, expr, Space.None);
740732 return renderToken(tree, ais, rtoken, space);
741733 }
742734
743 switch (lhs) {
744 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
745 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
746 }
747
748735 // scan to find row size
749736 if (rowSize(tree, exprs, rtoken, false) != null) {
750737 {
......@@ -763,11 +750,7 @@ fn renderExpression(
763750 var expr_widths = widths[0 .. widths.len - row_size];
764751 var column_widths = widths[widths.len - row_size ..];
765752
766 // Null stream for counting the printed length of each expression
767 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
768 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
769
770 // Find next row with trailing comment (if any) to end the current section then
753 // Find next row with trailing comment (if any) to end the current section
771754 var section_end = sec_end: {
772755 var this_line_first_expr: usize = 0;
773756 var this_line_size = rowSize(tree, row_exprs, rtoken, true);
......@@ -779,12 +762,15 @@ fn renderExpression(
779762 this_line_first_expr = i;
780763 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken, true);
781764 }
782 if (expr.lastToken() + 2 < tree.token_ids.len) {
783 if (tree.token_ids[expr.lastToken() + 1] == .Comma and
784 tree.token_ids[expr.lastToken() + 2] == .LineComment and
785 tree.tokensOnSameLine(expr.lastToken(), expr.lastToken() + 2))
765
766 const maybe_comma = expr.lastToken() + 1;
767 const maybe_comment = expr.lastToken() + 2;
768 if (maybe_comment < tree.token_ids.len) {
769 if (tree.token_ids[maybe_comma] == .Comma and
770 tree.token_ids[maybe_comment] == .LineComment and
771 tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
786772 {
787 var comment_token_loc = tree.token_locs[expr.lastToken() + 2];
773 var comment_token_loc = tree.token_locs[maybe_comment];
788774 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
789775 if (!comment_is_empty) {
790776 // Found row ending in comment
......@@ -799,18 +785,56 @@ fn renderExpression(
799785
800786 const section_exprs = row_exprs[0..section_end];
801787
788 // Null stream for counting the printed length of each expression
789 var line_find_stream = std.io.findByteOutStream('\n', std.io.null_out_stream);
790 var counting_stream = std.io.countingOutStream(line_find_stream.writer());
791 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
792
802793 // Calculate size of columns in current section
794 var c: usize = 0;
795 var single_line = true;
803796 for (section_exprs) |expr, i| {
804 counting_stream.bytes_written = 0;
805 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
806 const width = @intCast(usize, counting_stream.bytes_written);
807 const col = i % row_size;
808 column_widths[col] = std.math.max(column_widths[col], width);
809 expr_widths[i] = width;
797 if (i + 1 < section_exprs.len) {
798 counting_stream.bytes_written = 0;
799 line_find_stream.byte_found = false;
800 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
801 const width = @intCast(usize, counting_stream.bytes_written);
802 expr_widths[i] = width;
803
804 if (!line_find_stream.byte_found) {
805 const col = c % row_size;
806 column_widths[col] = std.math.max(column_widths[col], width);
807
808 const expr_last_token = expr.*.lastToken() + 1;
809 const next_expr = section_exprs[i + 1];
810 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
811 if (loc.line == 0) {
812 c += 1;
813 } else {
814 single_line = false;
815 c = 0;
816 }
817 } else {
818 single_line = false;
819 c = 0;
820 }
821 } else {
822 counting_stream.bytes_written = 0;
823 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
824 const width = @intCast(usize, counting_stream.bytes_written);
825 expr_widths[i] = width;
826
827 if (!line_find_stream.byte_found) {
828 const col = c % row_size;
829 column_widths[col] = std.math.max(column_widths[col], width);
830 }
831 break;
832 }
810833 }
811834
812835 // Render exprs in current section
813 var col: usize = 1;
836 c = 0;
837 var last_col_index: usize = row_size - 1;
814838 for (section_exprs) |expr, i| {
815839 if (i + 1 < section_exprs.len) {
816840 const next_expr = section_exprs[i + 1];
......@@ -818,23 +842,28 @@ fn renderExpression(
818842
819843 const comma = tree.nextToken(expr.*.lastToken());
820844
821 if (col != row_size) {
845 if (c != last_col_index) {
846 line_find_stream.byte_found = false;
847 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
848 try renderExpression(allocator, &auto_indenting_stream, tree, next_expr, Space.None);
849 if (!line_find_stream.byte_found) {
850 // Neither the current or next expression is multiline
851 try renderToken(tree, ais, comma, Space.Space); // ,
852 assert(column_widths[c % row_size] >= expr_widths[i]);
853 const padding = column_widths[c % row_size] - expr_widths[i];
854 try ais.writer().writeByteNTimes(' ', padding);
855
856 c += 1;
857 continue;
858 }
859 }
860 if (single_line) {
822861 try renderToken(tree, ais, comma, Space.Space); // ,
823
824 const padding = column_widths[i % row_size] - expr_widths[i];
825 try ais.writer().writeByteNTimes(' ', padding);
826
827 col += 1;
828862 continue;
829863 }
830 col = 1;
831
832 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
833 try renderToken(tree, ais, comma, Space.Newline); // ,
834 } else {
835 try renderToken(tree, ais, comma, Space.None); // ,
836 }
837864
865 c = 0;
866 try renderToken(tree, ais, comma, Space.Newline); // ,
838867 try renderExtraNewline(tree, ais, next_expr);
839868 } else {
840869 const maybe_comma = tree.nextToken(expr.*.lastToken());
......@@ -2594,13 +2623,13 @@ fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex, force: b
25942623 for (exprs) |expr, i| {
25952624 if (i + 1 < exprs.len) {
25962625 const expr_last_token = expr.lastToken() + 1;
2597 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i + 1].firstToken());
2626 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, exprs[i + 1].firstToken());
25982627 if (loc.line != 0) return count;
25992628 count += 1;
26002629 } else {
26012630 if (force) return count;
26022631 const expr_last_token = expr.lastToken();
2603 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
2632 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, rtoken);
26042633 if (loc.line == 0) {
26052634 // all on one line
26062635 const src_has_trailing_comma = trailblk: {