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 {...@@ -823,6 +823,15 @@ pub const Node = struct {
823 }823 }
824 }824 }
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
826 pub fn dump(self: *Node, indent: usize) void {835 pub fn dump(self: *Node, indent: usize) void {
827 {836 {
828 var i: usize = 0;837 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" {...@@ -3484,6 +3484,65 @@ test "zig fmt: allow trailing line comments to do manual array formatting" {
3484 );3484 );
3485}3485}
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
3487const std = @import("std");3546const std = @import("std");
3488const mem = std.mem;3547const mem = std.mem;
3489const warn = std.debug.warn;3548const warn = std.debug.warn;
lib/std/zig/render.zig+82-53
...@@ -714,37 +714,24 @@ fn renderExpression(...@@ -714,37 +714,24 @@ fn renderExpression(
714 .node => |node| tree.nextToken(node.lastToken()),714 .node => |node| tree.nextToken(node.lastToken()),
715 };715 };
716716
717 if (exprs.len == 0) {717 switch (lhs) {
718 switch (lhs) {718 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
719 .dot => |dot| try renderToken(tree, ais, dot, Space.None),719 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
720 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),720 }
721 }
722
723 {
724 ais.pushIndent();
725 defer ais.popIndent();
726 try renderToken(tree, ais, lbrace, Space.None);
727 }
728721
722 if (exprs.len == 0) {
723 try renderToken(tree, ais, lbrace, Space.None);
729 return renderToken(tree, ais, rtoken, space);724 return renderToken(tree, ais, rtoken, space);
730 }725 }
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) {
732 const expr = exprs[0];728 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 }
738 try renderToken(tree, ais, lbrace, Space.None);730 try renderToken(tree, ais, lbrace, Space.None);
739 try renderExpression(allocator, ais, tree, expr, Space.None);731 try renderExpression(allocator, ais, tree, expr, Space.None);
740 return renderToken(tree, ais, rtoken, space);732 return renderToken(tree, ais, rtoken, space);
741 }733 }
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
748 // scan to find row size735 // scan to find row size
749 if (rowSize(tree, exprs, rtoken, false) != null) {736 if (rowSize(tree, exprs, rtoken, false) != null) {
750 {737 {
...@@ -763,11 +750,7 @@ fn renderExpression(...@@ -763,11 +750,7 @@ fn renderExpression(
763 var expr_widths = widths[0 .. widths.len - row_size];750 var expr_widths = widths[0 .. widths.len - row_size];
764 var column_widths = widths[widths.len - row_size ..];751 var column_widths = widths[widths.len - row_size ..];
765752
766 // Null stream for counting the printed length of each expression753 // Find next row with trailing comment (if any) to end the current section
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
771 var section_end = sec_end: {754 var section_end = sec_end: {
772 var this_line_first_expr: usize = 0;755 var this_line_first_expr: usize = 0;
773 var this_line_size = rowSize(tree, row_exprs, rtoken, true);756 var this_line_size = rowSize(tree, row_exprs, rtoken, true);
...@@ -779,12 +762,15 @@ fn renderExpression(...@@ -779,12 +762,15 @@ fn renderExpression(
779 this_line_first_expr = i;762 this_line_first_expr = i;
780 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken, true);763 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken, true);
781 }764 }
782 if (expr.lastToken() + 2 < tree.token_ids.len) {765
783 if (tree.token_ids[expr.lastToken() + 1] == .Comma and766 const maybe_comma = expr.lastToken() + 1;
784 tree.token_ids[expr.lastToken() + 2] == .LineComment and767 const maybe_comment = expr.lastToken() + 2;
785 tree.tokensOnSameLine(expr.lastToken(), 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))
786 {772 {
787 var comment_token_loc = tree.token_locs[expr.lastToken() + 2];773 var comment_token_loc = tree.token_locs[maybe_comment];
788 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;774 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
789 if (!comment_is_empty) {775 if (!comment_is_empty) {
790 // Found row ending in comment776 // Found row ending in comment
...@@ -799,18 +785,56 @@ fn renderExpression(...@@ -799,18 +785,56 @@ fn renderExpression(
799785
800 const section_exprs = row_exprs[0..section_end];786 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
802 // Calculate size of columns in current section793 // Calculate size of columns in current section
794 var c: usize = 0;
795 var single_line = true;
803 for (section_exprs) |expr, i| {796 for (section_exprs) |expr, i| {
804 counting_stream.bytes_written = 0;797 if (i + 1 < section_exprs.len) {
805 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);798 counting_stream.bytes_written = 0;
806 const width = @intCast(usize, counting_stream.bytes_written);799 line_find_stream.byte_found = false;
807 const col = i % row_size;800 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
808 column_widths[col] = std.math.max(column_widths[col], width);801 const width = @intCast(usize, counting_stream.bytes_written);
809 expr_widths[i] = width;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 }
810 }833 }
811834
812 // Render exprs in current section835 // Render exprs in current section
813 var col: usize = 1;836 c = 0;
837 var last_col_index: usize = row_size - 1;
814 for (section_exprs) |expr, i| {838 for (section_exprs) |expr, i| {
815 if (i + 1 < section_exprs.len) {839 if (i + 1 < section_exprs.len) {
816 const next_expr = section_exprs[i + 1];840 const next_expr = section_exprs[i + 1];
...@@ -818,23 +842,28 @@ fn renderExpression(...@@ -818,23 +842,28 @@ fn renderExpression(
818842
819 const comma = tree.nextToken(expr.*.lastToken());843 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) {
822 try renderToken(tree, ais, comma, Space.Space); // ,861 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;
828 continue;862 continue;
829 }863 }
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); // ,
838 try renderExtraNewline(tree, ais, next_expr);867 try renderExtraNewline(tree, ais, next_expr);
839 } else {868 } else {
840 const maybe_comma = tree.nextToken(expr.*.lastToken());869 const maybe_comma = tree.nextToken(expr.*.lastToken());
...@@ -2594,13 +2623,13 @@ fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex, force: b...@@ -2594,13 +2623,13 @@ fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex, force: b
2594 for (exprs) |expr, i| {2623 for (exprs) |expr, i| {
2595 if (i + 1 < exprs.len) {2624 if (i + 1 < exprs.len) {
2596 const expr_last_token = expr.lastToken() + 1;2625 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());
2598 if (loc.line != 0) return count;2627 if (loc.line != 0) return count;
2599 count += 1;2628 count += 1;
2600 } else {2629 } else {
2601 if (force) return count;2630 if (force) return count;
2602 const expr_last_token = expr.lastToken();2631 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);
2604 if (loc.line == 0) {2633 if (loc.line == 0) {
2605 // all on one line2634 // all on one line
2606 const src_has_trailing_comma = trailblk: {2635 const src_has_trailing_comma = trailblk: {