authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-27 05:49:38-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-27 05:49:38-04:00
log8794ce6f79886e5ebbf0476d56917e219b52c561
treeb844b039b4a92be26a80175715b12551ca0fa8f4
parenteab51b7785ce0989f90a5cdde4b1110f40875ddb
parent4496a6c9cccbd6a9c82b5d4ca7f533b18ebeab32
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6293 from LakeByTheWoods/fmt_fixes

zig fmt fixes

3 files changed, 575 insertions(+), 142 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+325-3
...@@ -1301,8 +1301,10 @@ test "zig fmt: array literal with hint" {...@@ -1301,8 +1301,10 @@ test "zig fmt: array literal with hint" {
1301 \\const a = []u8{1301 \\const a = []u8{
1302 \\ 1, 2,1302 \\ 1, 2,
1303 \\ 3, 4,1303 \\ 3, 4,
1304 \\ 5, 6, // blah1304 \\ 5,
1305 \\ 7, 8,1305 \\ 6, // blah
1306 \\ 7,
1307 \\ 8,
1306 \\};1308 \\};
1307 \\const a = []u8{1309 \\const a = []u8{
1308 \\ 1, 2,1310 \\ 1, 2,
...@@ -1372,7 +1374,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {...@@ -1372,7 +1374,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
1372 \\ \\ZIG_C_HEADER_FILES {}1374 \\ \\ZIG_C_HEADER_FILES {}
1373 \\ \\ZIG_DIA_GUIDS_LIB {}1375 \\ \\ZIG_DIA_GUIDS_LIB {}
1374 \\ \\1376 \\ \\
1375 \\ ,1377 \\ ,
1376 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),1378 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
1377 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),1379 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
1378 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),1380 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
...@@ -3321,6 +3323,326 @@ test "zig fmt: Don't add extra newline after if" {...@@ -3321,6 +3323,326 @@ test "zig fmt: Don't add extra newline after if" {
3321 );3323 );
3322}3324}
33233325
3326test "zig fmt: comments in ternary ifs" {
3327 try testCanonical(
3328 \\const x = if (true) {
3329 \\ 1;
3330 \\} else if (false)
3331 \\ // Comment
3332 \\ 0;
3333 \\const y = if (true)
3334 \\ // Comment
3335 \\ 1
3336 \\else
3337 \\ 0;
3338 \\
3339 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3340 \\
3341 );
3342}
3343
3344test "zig fmt: test comments in field access chain" {
3345 try testCanonical(
3346 \\pub const str = struct {
3347 \\ pub const Thing = more.more //
3348 \\ .more() //
3349 \\ .more().more() //
3350 \\ .more() //
3351 \\ // .more() //
3352 \\ .more() //
3353 \\ .more();
3354 \\ data: Data,
3355 \\};
3356 \\
3357 \\pub const str = struct {
3358 \\ pub const Thing = more.more //
3359 \\ .more() //
3360 \\ // .more() //
3361 \\ // .more() //
3362 \\ // .more() //
3363 \\ .more() //
3364 \\ .more();
3365 \\ data: Data,
3366 \\};
3367 \\
3368 \\pub const str = struct {
3369 \\ pub const Thing = more //
3370 \\ .more //
3371 \\ .more() //
3372 \\ .more();
3373 \\ data: Data,
3374 \\};
3375 \\
3376 );
3377}
3378
3379test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" {
3380 try testCanonical(
3381 \\fn foo() void {
3382 \\ z.display_message_dialog(
3383 \\ *const [323:0]u8,
3384 \\ \\Message Text
3385 \\ \\------------
3386 \\ \\xxxxxxxxxxxx
3387 \\ \\xxxxxxxxxxxx
3388 \\ ,
3389 \\ g.GtkMessageType.GTK_MESSAGE_WARNING,
3390 \\ null,
3391 \\ );
3392 \\
3393 \\ z.display_message_dialog(*const [323:0]u8,
3394 \\ \\Message Text
3395 \\ \\------------
3396 \\ \\xxxxxxxxxxxx
3397 \\ \\xxxxxxxxxxxx
3398 \\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null);
3399 \\}
3400 \\
3401 );
3402}
3403
3404test "zig fmt: Control flow statement as body of blockless if" {
3405 try testCanonical(
3406 \\pub fn main() void {
3407 \\ const zoom_node = if (focused_node == layout_first)
3408 \\ if (it.next()) {
3409 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3410 \\ } else null
3411 \\ else
3412 \\ focused_node;
3413 \\
3414 \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3415 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3416 \\ } else null else
3417 \\ focused_node;
3418 \\
3419 \\ const zoom_node = if (focused_node == layout_first)
3420 \\ if (it.next()) {
3421 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3422 \\ } else null;
3423 \\
3424 \\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
3425 \\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
3426 \\ };
3427 \\
3428 \\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| {
3429 \\ break node;
3430 \\ };
3431 \\
3432 \\ const zoom_node = if (focused_node == layout_first) switch (nodes) {
3433 \\ 0 => 0,
3434 \\ } else
3435 \\ focused_node;
3436 \\}
3437 \\
3438 );
3439}
3440
3441test "zig fmt: " {
3442 try testCanonical(
3443 \\pub fn sendViewTags(self: Self) void {
3444 \\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
3445 \\ while (it.next()) |node|
3446 \\ view_tags.append(node.view.current_tags) catch {
3447 \\ c.wl_resource_post_no_memory(self.wl_resource);
3448 \\ log.crit(.river_status, "out of memory", .{});
3449 \\ return;
3450 \\ };
3451 \\}
3452 \\
3453 );
3454}
3455
3456test "zig fmt: allow trailing line comments to do manual array formatting" {
3457 try testCanonical(
3458 \\fn foo() void {
3459 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3460 \\ 0x55, // push rbp
3461 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3462 \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3463 \\ });
3464 \\
3465 \\ di_buf.appendAssumeCapacity(&[_]u8{
3466 \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
3467 \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
3468 \\ DW.AT_low_pc, DW_FORM_addr,
3469 \\ DW.AT_high_pc, DW_FORM_addr,
3470 \\ DW.AT_name, DW_FORM_strp,
3471 \\ DW.AT_comp_dir, DW_FORM_strp,
3472 \\ DW.AT_producer, DW_FORM_strp,
3473 \\ DW.AT_language, DW_FORM_data2,
3474 \\ 0, 0, // sentinel
3475 \\ });
3476 \\
3477 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3478 \\ 0x55, // push rbp
3479 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3480 \\ // How do we handle this?
3481 \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3482 \\ // Here's a blank line, should that be allowed?
3483 \\
3484 \\ 0x48, 0x89, 0xe5,
3485 \\ 0x33, 0x45,
3486 \\ // Now the comment breaks a single line -- how do we handle this?
3487 \\ 0x88,
3488 \\ });
3489 \\}
3490 \\
3491 );
3492}
3493
3494test "zig fmt: multiline string literals should play nice with array initializers" {
3495 try testCanonical(
3496 \\fn main() void {
3497 \\ var a = .{.{.{.{.{.{.{.{
3498 \\ 0,
3499 \\ }}}}}}}};
3500 \\ myFunc(.{
3501 \\ "aaaaaaa", "bbbbbb", "ccccc",
3502 \\ "dddd", ("eee"), ("fff"),
3503 \\ ("gggg"),
3504 \\ // Line comment
3505 \\ \\Multiline String Literals can be quite long
3506 \\ ,
3507 \\ \\Multiline String Literals can be quite long
3508 \\ \\Multiline String Literals can be quite long
3509 \\ ,
3510 \\ \\Multiline String Literals can be quite long
3511 \\ \\Multiline String Literals can be quite long
3512 \\ \\Multiline String Literals can be quite long
3513 \\ \\Multiline String Literals can be quite long
3514 \\ ,
3515 \\ (
3516 \\ \\Multiline String Literals can be quite long
3517 \\ ),
3518 \\ .{
3519 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3520 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3521 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3522 \\ },
3523 \\ .{(
3524 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3525 \\ )},
3526 \\ .{
3527 \\ "xxxxxxx", "xxx",
3528 \\ (
3529 \\ \\ xxx
3530 \\ ),
3531 \\ "xxx", "xxx",
3532 \\ },
3533 \\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
3534 \\ "aaaaaaa", "bbbbbb", "ccccc", // -
3535 \\ "dddd", ("eee"), ("fff"),
3536 \\ .{
3537 \\ "xxx", "xxx",
3538 \\ (
3539 \\ \\ xxx
3540 \\ ),
3541 \\ "xxxxxxxxxxxxxx", "xxx",
3542 \\ },
3543 \\ .{
3544 \\ (
3545 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3546 \\ ),
3547 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3548 \\ },
3549 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3550 \\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3551 \\ });
3552 \\}
3553 \\
3554 );
3555}
3556
3557test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
3558 try testCanonical(
3559 \\pub fn makeMemUndefined(qzz: []u8) i1 {
3560 \\ cases.add( // fixed bug #2032
3561 \\ "compile diagnostic string for top level decl type",
3562 \\ \\export fn entry() void {
3563 \\ \\ var foo: u32 = @This(){};
3564 \\ \\}
3565 \\ , &[_][]const u8{
3566 \\ "tmp.zig:2:27: error: type 'u32' does not support array initialization",
3567 \\ });
3568 \\ @compileError(
3569 \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3570 \\ \\ Consider providing your own hash function.
3571 \\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
3572 \\ \\ Consider providing your own hash function.
3573 \\ );
3574 \\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
3575 \\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
3576 \\}
3577 \\
3578 \\// This looks like garbage don't do this
3579 \\const rparen = tree.prevToken(
3580 \\// the first token for the annotation expressions is the left
3581 \\// parenthesis, hence the need for two prevToken
3582 \\ if (fn_proto.getAlignExpr()) |align_expr|
3583 \\ tree.prevToken(tree.prevToken(align_expr.firstToken()))
3584 \\else if (fn_proto.getSectionExpr()) |section_expr|
3585 \\ tree.prevToken(tree.prevToken(section_expr.firstToken()))
3586 \\else if (fn_proto.getCallconvExpr()) |callconv_expr|
3587 \\ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
3588 \\else switch (fn_proto.return_type) {
3589 \\ .Explicit => |node| node.firstToken(),
3590 \\ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
3591 \\ .Invalid => unreachable,
3592 \\});
3593 \\
3594 );
3595}
3596
3597test "zig fmt: single argument trailing commas in @builtins()" {
3598 try testCanonical(
3599 \\pub fn foo(qzz: []u8) i1 {
3600 \\ @panic(
3601 \\ foo,
3602 \\ );
3603 \\ panic(
3604 \\ foo,
3605 \\ );
3606 \\ @panic(
3607 \\ foo,
3608 \\ bar,
3609 \\ );
3610 \\}
3611 \\
3612 );
3613}
3614
3615test "zig fmt: trailing comma should force multiline 1 column" {
3616 try testTransform(
3617 \\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,};
3618 \\
3619 ,
3620 \\pub const UUID_NULL: uuid_t = [16]u8{
3621 \\ 0,
3622 \\ 0,
3623 \\ 0,
3624 \\ 0,
3625 \\};
3626 \\
3627 );
3628}
3629
3630test "zig fmt: function params should align nicely" {
3631 try testCanonical(
3632 \\pub fn foo() void {
3633 \\ cases.addRuntimeSafety("slicing operator with sentinel",
3634 \\ \\const std = @import("std");
3635 \\ ++ check_panic_msg ++
3636 \\ \\pub fn main() void {
3637 \\ \\ var buf = [4]u8{'a','b','c',0};
3638 \\ \\ const slice = buf[0..:0];
3639 \\ \\}
3640 \\ );
3641 \\}
3642 \\
3643 );
3644}
3645
3324const std = @import("std");3646const std = @import("std");
3325const mem = std.mem;3647const mem = std.mem;
3326const warn = std.debug.warn;3648const warn = std.debug.warn;
lib/std/zig/render.zig+241-139
...@@ -522,7 +522,11 @@ fn renderExpression(...@@ -522,7 +522,11 @@ fn renderExpression(
522 break :blk if (loc.line == 0) op_space else Space.Newline;522 break :blk if (loc.line == 0) op_space else Space.Newline;
523 };523 };
524524
525 try renderToken(tree, ais, infix_op_node.op_token, after_op_space);525 {
526 ais.pushIndent();
527 defer ais.popIndent();
528 try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
529 }
526 ais.pushIndentOneShot();530 ais.pushIndentOneShot();
527 return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);531 return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
528 },532 },
...@@ -710,141 +714,194 @@ fn renderExpression(...@@ -710,141 +714,194 @@ fn renderExpression(
710 .node => |node| tree.nextToken(node.lastToken()),714 .node => |node| tree.nextToken(node.lastToken()),
711 };715 };
712716
713 if (exprs.len == 0) {717 switch (lhs) {
714 switch (lhs) {718 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
715 .dot => |dot| try renderToken(tree, ais, dot, Space.None),719 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
716 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),720 }
717 }
718
719 {
720 ais.pushIndent();
721 defer ais.popIndent();
722 try renderToken(tree, ais, lbrace, Space.None);
723 }
724721
722 if (exprs.len == 0) {
723 try renderToken(tree, ais, lbrace, Space.None);
725 return renderToken(tree, ais, rtoken, space);724 return renderToken(tree, ais, rtoken, space);
726 }725 }
727 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) {
728 const expr = exprs[0];728 const expr = exprs[0];
729729
730 switch (lhs) {
731 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
732 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
733 }
734 try renderToken(tree, ais, lbrace, Space.None);730 try renderToken(tree, ais, lbrace, Space.None);
735 try renderExpression(allocator, ais, tree, expr, Space.None);731 try renderExpression(allocator, ais, tree, expr, Space.None);
736 return renderToken(tree, ais, rtoken, space);732 return renderToken(tree, ais, rtoken, space);
737 }733 }
738734
739 switch (lhs) {
740 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
741 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
742 }
743
744 // scan to find row size735 // scan to find row size
745 const maybe_row_size: ?usize = blk: {736 if (rowSize(tree, exprs, rtoken) != null) {
746 var count: usize = 1;
747 for (exprs) |expr, i| {
748 if (i + 1 < exprs.len) {
749 const expr_last_token = expr.lastToken() + 1;
750 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i + 1].firstToken());
751 if (loc.line != 0) break :blk count;
752 count += 1;
753 } else {
754 const expr_last_token = expr.lastToken();
755 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
756 if (loc.line == 0) {
757 // all on one line
758 const src_has_trailing_comma = trailblk: {
759 const maybe_comma = tree.prevToken(rtoken);
760 break :trailblk tree.token_ids[maybe_comma] == .Comma;
761 };
762 if (src_has_trailing_comma) {
763 break :blk 1; // force row size 1
764 } else {
765 break :blk null; // no newlines
766 }
767 }
768 break :blk count;
769 }
770 }
771 unreachable;
772 };
773
774 if (maybe_row_size) |row_size| {
775 // A place to store the width of each expression and its column's maximum
776 var widths = try allocator.alloc(usize, exprs.len + row_size);
777 defer allocator.free(widths);
778 mem.set(usize, widths, 0);
779
780 var expr_widths = widths[0 .. widths.len - row_size];
781 var column_widths = widths[widths.len - row_size ..];
782
783 // Null ais for counting the printed length of each expression
784 var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
785 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
786
787 for (exprs) |expr, i| {
788 counting_stream.bytes_written = 0;
789 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
790 const width = @intCast(usize, counting_stream.bytes_written);
791 const col = i % row_size;
792 column_widths[col] = std.math.max(column_widths[col], width);
793 expr_widths[i] = width;
794 }
795
796 {737 {
797 ais.pushIndentNextLine();738 ais.pushIndentNextLine();
798 defer ais.popIndent();739 defer ais.popIndent();
799 try renderToken(tree, ais, lbrace, Space.Newline);740 try renderToken(tree, ais, lbrace, Space.Newline);
800741
801 var col: usize = 1;742 var expr_index: usize = 0;
802 for (exprs) |expr, i| {743 while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
803 if (i + 1 < exprs.len) {744 const row_exprs = exprs[expr_index..];
804 const next_expr = exprs[i + 1];745 // A place to store the width of each expression and its column's maximum
805 try renderExpression(allocator, ais, tree, expr, Space.None);746 var widths = try allocator.alloc(usize, row_exprs.len + row_size);
806747 defer allocator.free(widths);
807 const comma = tree.nextToken(expr.*.lastToken());748 mem.set(usize, widths, 0);
808749
809 if (col != row_size) {750 var expr_newlines = try allocator.alloc(bool, row_exprs.len);
810 try renderToken(tree, ais, comma, Space.Space); // ,751 defer allocator.free(expr_newlines);
811752 mem.set(bool, expr_newlines, false);
812 const padding = column_widths[i % row_size] - expr_widths[i];753
813 try ais.writer().writeByteNTimes(' ', padding);754 var expr_widths = widths[0 .. widths.len - row_size];
814755 var column_widths = widths[widths.len - row_size ..];
815 col += 1;756
816 continue;757 // Find next row with trailing comment (if any) to end the current section
758 var section_end = sec_end: {
759 var this_line_first_expr: usize = 0;
760 var this_line_size = rowSize(tree, row_exprs, rtoken);
761 for (row_exprs) |expr, i| {
762 // Ignore comment on first line of this section
763 if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
764 // Track start of line containing comment
765 if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
766 this_line_first_expr = i;
767 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
768 }
769
770 const maybe_comma = expr.lastToken() + 1;
771 const maybe_comment = expr.lastToken() + 2;
772 if (maybe_comment < tree.token_ids.len) {
773 if (tree.token_ids[maybe_comma] == .Comma and
774 tree.token_ids[maybe_comment] == .LineComment and
775 tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
776 {
777 var comment_token_loc = tree.token_locs[maybe_comment];
778 const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
779 if (!comment_is_empty) {
780 // Found row ending in comment
781 break :sec_end i - this_line_size.? + 1;
782 }
783 }
784 }
817 }785 }
818 col = 1;786 break :sec_end row_exprs.len;
787 };
788 expr_index += section_end;
789
790 const section_exprs = row_exprs[0..section_end];
791
792 // Null stream for counting the printed length of each expression
793 var line_find_stream = std.io.findByteOutStream('\n', std.io.null_out_stream);
794 var counting_stream = std.io.countingOutStream(line_find_stream.writer());
795 var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
796
797 // Calculate size of columns in current section
798 var column_counter: usize = 0;
799 var single_line = true;
800 for (section_exprs) |expr, i| {
801 if (i + 1 < section_exprs.len) {
802 counting_stream.bytes_written = 0;
803 line_find_stream.byte_found = false;
804 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
805 const width = @intCast(usize, counting_stream.bytes_written);
806 expr_widths[i] = width;
807 expr_newlines[i] = line_find_stream.byte_found;
808
809 if (!line_find_stream.byte_found) {
810 const column = column_counter % row_size;
811 column_widths[column] = std.math.max(column_widths[column], width);
812
813 const expr_last_token = expr.*.lastToken() + 1;
814 const next_expr = section_exprs[i + 1];
815 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
816 if (loc.line == 0) {
817 column_counter += 1;
818 } else {
819 single_line = false;
820 column_counter = 0;
821 }
822 } else {
823 single_line = false;
824 column_counter = 0;
825 }
826 } else {
827 counting_stream.bytes_written = 0;
828 try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
829 const width = @intCast(usize, counting_stream.bytes_written);
830 expr_widths[i] = width;
831 expr_newlines[i] = line_find_stream.byte_found;
832
833 if (!line_find_stream.byte_found) {
834 const column = column_counter % row_size;
835 column_widths[column] = std.math.max(column_widths[column], width);
836 }
837 break;
838 }
839 }
819840
820 if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {841 // Render exprs in current section
842 column_counter = 0;
843 var last_col_index: usize = row_size - 1;
844 for (section_exprs) |expr, i| {
845 if (i + 1 < section_exprs.len) {
846 const next_expr = section_exprs[i + 1];
847 try renderExpression(allocator, ais, tree, expr, Space.None);
848
849 const comma = tree.nextToken(expr.*.lastToken());
850
851 if (column_counter != last_col_index) {
852 if (!expr_newlines[i] and !expr_newlines[i + 1]) {
853 // Neither the current or next expression is multiline
854 try renderToken(tree, ais, comma, Space.Space); // ,
855 assert(column_widths[column_counter % row_size] >= expr_widths[i]);
856 const padding = column_widths[column_counter % row_size] - expr_widths[i];
857 try ais.writer().writeByteNTimes(' ', padding);
858
859 column_counter += 1;
860 continue;
861 }
862 }
863 if (single_line and row_size != 1) {
864 try renderToken(tree, ais, comma, Space.Space); // ,
865 continue;
866 }
867
868 column_counter = 0;
821 try renderToken(tree, ais, comma, Space.Newline); // ,869 try renderToken(tree, ais, comma, Space.Newline); // ,
870 try renderExtraNewline(tree, ais, next_expr);
822 } else {871 } else {
823 try renderToken(tree, ais, comma, Space.None); // ,872 const maybe_comma = tree.nextToken(expr.*.lastToken());
873 if (tree.token_ids[maybe_comma] == .Comma) {
874 try renderExpression(allocator, ais, tree, expr, Space.None); // ,
875 try renderToken(tree, ais, maybe_comma, Space.Newline); // ,
876 } else {
877 try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
878 }
824 }879 }
880 }
825881
826 try renderExtraNewline(tree, ais, next_expr);882 if (expr_index == exprs.len) {
827 } else {883 break;
828 try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
829 }884 }
830 }885 }
831 }886 }
832 return renderToken(tree, ais, rtoken, space);
833 } else {
834 try renderToken(tree, ais, lbrace, Space.Space);
835 for (exprs) |expr, i| {
836 if (i + 1 < exprs.len) {
837 const next_expr = exprs[i + 1];
838 try renderExpression(allocator, ais, tree, expr, Space.None);
839 const comma = tree.nextToken(expr.*.lastToken());
840 try renderToken(tree, ais, comma, Space.Space); // ,
841 } else {
842 try renderExpression(allocator, ais, tree, expr, Space.Space);
843 }
844 }
845887
846 return renderToken(tree, ais, rtoken, space);888 return renderToken(tree, ais, rtoken, space);
847 }889 }
890
891 // Single line
892 try renderToken(tree, ais, lbrace, Space.Space);
893 for (exprs) |expr, i| {
894 if (i + 1 < exprs.len) {
895 const next_expr = exprs[i + 1];
896 try renderExpression(allocator, ais, tree, expr, Space.None);
897 const comma = tree.nextToken(expr.*.lastToken());
898 try renderToken(tree, ais, comma, Space.Space); // ,
899 } else {
900 try renderExpression(allocator, ais, tree, expr, Space.Space);
901 }
902 }
903
904 return renderToken(tree, ais, rtoken, space);
848 },905 },
849906
850 .StructInitializer, .StructInitializerDot => {907 .StructInitializer, .StructInitializerDot => {
...@@ -1004,21 +1061,29 @@ fn renderExpression(...@@ -1004,21 +1061,29 @@ fn renderExpression(
1004 };1061 };
10051062
1006 if (src_has_trailing_comma) {1063 if (src_has_trailing_comma) {
1007 try renderToken(tree, ais, lparen, Space.Newline);1064 {
1008
1009 const params = call.params();
1010 for (params) |param_node, i| {
1011 ais.pushIndent();1065 ais.pushIndent();
1012 defer ais.popIndent();1066 defer ais.popIndent();
10131067
1014 if (i + 1 < params.len) {1068 try renderToken(tree, ais, lparen, Space.Newline); // (
1015 const next_node = params[i + 1];1069 const params = call.params();
1016 try renderExpression(allocator, ais, tree, param_node, Space.None);1070 for (params) |param_node, i| {
1017 const comma = tree.nextToken(param_node.lastToken());1071 if (i + 1 < params.len) {
1018 try renderToken(tree, ais, comma, Space.Newline); // ,1072 const next_node = params[i + 1];
1019 try renderExtraNewline(tree, ais, next_node);1073 try renderExpression(allocator, ais, tree, param_node, Space.None);
1020 } else {1074
1021 try renderExpression(allocator, ais, tree, param_node, Space.Comma);1075 // Unindent the comma for multiline string literals
1076 const maybe_multiline_string = param_node.firstToken();
1077 const is_multiline_string = tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine;
1078 if (is_multiline_string) ais.popIndent();
1079 defer if (is_multiline_string) ais.pushIndent();
1080
1081 const comma = tree.nextToken(param_node.lastToken());
1082 try renderToken(tree, ais, comma, Space.Newline); // ,
1083 try renderExtraNewline(tree, ais, next_node);
1084 } else {
1085 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1086 }
1022 }1087 }
1023 }1088 }
1024 return renderToken(tree, ais, call.rtoken, space);1089 return renderToken(tree, ais, call.rtoken, space);
...@@ -1028,17 +1093,20 @@ fn renderExpression(...@@ -1028,17 +1093,20 @@ fn renderExpression(
10281093
1029 const params = call.params();1094 const params = call.params();
1030 for (params) |param_node, i| {1095 for (params) |param_node, i| {
1031 if (param_node.*.tag == .MultilineStringLiteral) ais.pushIndentOneShot();1096 const maybe_comment = param_node.firstToken() - 1;
1097 const maybe_multiline_string = param_node.firstToken();
1098 if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) {
1099 ais.pushIndentOneShot();
1100 }
10321101
1033 try renderExpression(allocator, ais, tree, param_node, Space.None);1102 try renderExpression(allocator, ais, tree, param_node, Space.None);
10341103
1035 if (i + 1 < params.len) {1104 if (i + 1 < params.len) {
1036 const next_param = params[i + 1];
1037 const comma = tree.nextToken(param_node.lastToken());1105 const comma = tree.nextToken(param_node.lastToken());
1038 try renderToken(tree, ais, comma, Space.Space);1106 try renderToken(tree, ais, comma, Space.Space);
1039 }1107 }
1040 }1108 }
1041 return renderToken(tree, ais, call.rtoken, space);1109 return renderToken(tree, ais, call.rtoken, space); // )
1042 },1110 },
10431111
1044 .ArrayAccess => {1112 .ArrayAccess => {
...@@ -1429,7 +1497,7 @@ fn renderExpression(...@@ -1429,7 +1497,7 @@ fn renderExpression(
1429 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name1497 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
14301498
1431 const src_params_trailing_comma = blk: {1499 const src_params_trailing_comma = blk: {
1432 if (builtin_call.params_len < 2) break :blk false;1500 if (builtin_call.params_len == 0) break :blk false;
1433 const last_node = builtin_call.params()[builtin_call.params_len - 1];1501 const last_node = builtin_call.params()[builtin_call.params_len - 1];
1434 const maybe_comma = tree.nextToken(last_node.lastToken());1502 const maybe_comma = tree.nextToken(last_node.lastToken());
1435 break :blk tree.token_ids[maybe_comma] == .Comma;1503 break :blk tree.token_ids[maybe_comma] == .Comma;
...@@ -1443,6 +1511,10 @@ fn renderExpression(...@@ -1443,6 +1511,10 @@ fn renderExpression(
1443 // render all on one line, no trailing comma1511 // render all on one line, no trailing comma
1444 const params = builtin_call.params();1512 const params = builtin_call.params();
1445 for (params) |param_node, i| {1513 for (params) |param_node, i| {
1514 const maybe_comment = param_node.firstToken() - 1;
1515 if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) {
1516 ais.pushIndentOneShot();
1517 }
1446 try renderExpression(allocator, ais, tree, param_node, Space.None);1518 try renderExpression(allocator, ais, tree, param_node, Space.None);
14471519
1448 if (i + 1 < params.len) {1520 if (i + 1 < params.len) {
...@@ -1494,19 +1566,20 @@ fn renderExpression(...@@ -1494,19 +1566,20 @@ fn renderExpression(
1494 assert(tree.token_ids[lparen] == .LParen);1566 assert(tree.token_ids[lparen] == .LParen);
14951567
1496 const rparen = tree.prevToken(1568 const rparen = tree.prevToken(
1497 // the first token for the annotation expressions is the left1569 // the first token for the annotation expressions is the left
1498 // parenthesis, hence the need for two prevToken1570 // parenthesis, hence the need for two prevToken
1499 if (fn_proto.getAlignExpr()) |align_expr|1571 if (fn_proto.getAlignExpr()) |align_expr|
1500 tree.prevToken(tree.prevToken(align_expr.firstToken()))1572 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1501 else if (fn_proto.getSectionExpr()) |section_expr|1573 else if (fn_proto.getSectionExpr()) |section_expr|
1502 tree.prevToken(tree.prevToken(section_expr.firstToken()))1574 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1503 else if (fn_proto.getCallconvExpr()) |callconv_expr|1575 else if (fn_proto.getCallconvExpr()) |callconv_expr|
1504 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))1576 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1505 else switch (fn_proto.return_type) {1577 else switch (fn_proto.return_type) {
1506 .Explicit => |node| node.firstToken(),1578 .Explicit => |node| node.firstToken(),
1507 .InferErrorSet => |node| tree.prevToken(node.firstToken()),1579 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1508 .Invalid => unreachable,1580 .Invalid => unreachable,
1509 });1581 },
1582 );
1510 assert(tree.token_ids[rparen] == .RParen);1583 assert(tree.token_ids[rparen] == .RParen);
15111584
1512 const src_params_trailing_comma = blk: {1585 const src_params_trailing_comma = blk: {
...@@ -1758,7 +1831,7 @@ fn renderExpression(...@@ -1758,7 +1831,7 @@ fn renderExpression(
1758 }1831 }
17591832
1760 if (while_node.payload) |payload| {1833 if (while_node.payload) |payload| {
1761 const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;1834 const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
1762 try renderExpression(allocator, ais, tree, payload, payload_space);1835 try renderExpression(allocator, ais, tree, payload, payload_space);
1763 }1836 }
17641837
...@@ -1873,7 +1946,12 @@ fn renderExpression(...@@ -1873,7 +1946,12 @@ fn renderExpression(
18731946
1874 if (src_has_newline) {1947 if (src_has_newline) {
1875 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;1948 const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
1876 try renderToken(tree, ais, rparen, after_rparen_space); // )1949
1950 {
1951 ais.pushIndent();
1952 defer ais.popIndent();
1953 try renderToken(tree, ais, rparen, after_rparen_space); // )
1954 }
18771955
1878 if (if_node.payload) |payload| {1956 if (if_node.payload) |payload| {
1879 try renderExpression(allocator, ais, tree, payload, Space.Newline);1957 try renderExpression(allocator, ais, tree, payload, Space.Newline);
...@@ -2558,3 +2636,27 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo...@@ -2558,3 +2636,27 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
2558 else => try ais.writer().writeByte(byte),2636 else => try ais.writer().writeByte(byte),
2559 };2637 };
2560}2638}
2639
2640fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize {
2641 const first_token = exprs[0].firstToken();
2642 const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken);
2643 if (first_loc.line == 0) {
2644 const maybe_comma = tree.prevToken(rtoken);
2645 if (tree.token_ids[maybe_comma] == .Comma)
2646 return 1;
2647 return null; // no newlines
2648 }
2649
2650 var count: usize = 1;
2651 for (exprs) |expr, i| {
2652 if (i + 1 < exprs.len) {
2653 const expr_last_token = expr.lastToken() + 1;
2654 const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, exprs[i + 1].firstToken());
2655 if (loc.line != 0) return count;
2656 count += 1;
2657 } else {
2658 return count;
2659 }
2660 }
2661 unreachable;
2662}