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 {
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+325-3
......@@ -1301,8 +1301,10 @@ test "zig fmt: array literal with hint" {
13011301 \\const a = []u8{
13021302 \\ 1, 2,
13031303 \\ 3, 4,
1304 \\ 5, 6, // blah
1305 \\ 7, 8,
1304 \\ 5,
1305 \\ 6, // blah
1306 \\ 7,
1307 \\ 8,
13061308 \\};
13071309 \\const a = []u8{
13081310 \\ 1, 2,
......@@ -1372,7 +1374,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
13721374 \\ \\ZIG_C_HEADER_FILES {}
13731375 \\ \\ZIG_DIA_GUIDS_LIB {}
13741376 \\ \\
1375 \\ ,
1377 \\ ,
13761378 \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
13771379 \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
13781380 \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
......@@ -3321,6 +3323,326 @@ test "zig fmt: Don't add extra newline after if" {
33213323 );
33223324}
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
33243646const std = @import("std");
33253647const mem = std.mem;
33263648const warn = std.debug.warn;
lib/std/zig/render.zig+241-139
......@@ -522,7 +522,11 @@ fn renderExpression(
522522 break :blk if (loc.line == 0) op_space else Space.Newline;
523523 };
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 }
526530 ais.pushIndentOneShot();
527531 return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
528532 },
......@@ -710,141 +714,194 @@ fn renderExpression(
710714 .node => |node| tree.nextToken(node.lastToken()),
711715 };
712716
713 if (exprs.len == 0) {
714 switch (lhs) {
715 .dot => |dot| try renderToken(tree, ais, dot, Space.None),
716 .node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
717 }
718
719 {
720 ais.pushIndent();
721 defer ais.popIndent();
722 try renderToken(tree, ais, lbrace, Space.None);
723 }
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 }
724721
722 if (exprs.len == 0) {
723 try renderToken(tree, ais, lbrace, Space.None);
725724 return renderToken(tree, ais, rtoken, space);
726725 }
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) {
728728 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 }
734730 try renderToken(tree, ais, lbrace, Space.None);
735731 try renderExpression(allocator, ais, tree, expr, Space.None);
736732 return renderToken(tree, ais, rtoken, space);
737733 }
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
744735 // scan to find row size
745 const maybe_row_size: ?usize = blk: {
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
736 if (rowSize(tree, exprs, rtoken) != null) {
796737 {
797738 ais.pushIndentNextLine();
798739 defer ais.popIndent();
799740 try renderToken(tree, ais, lbrace, Space.Newline);
800741
801 var col: usize = 1;
802 for (exprs) |expr, i| {
803 if (i + 1 < exprs.len) {
804 const next_expr = exprs[i + 1];
805 try renderExpression(allocator, ais, tree, expr, Space.None);
806
807 const comma = tree.nextToken(expr.*.lastToken());
808
809 if (col != row_size) {
810 try renderToken(tree, ais, comma, Space.Space); // ,
811
812 const padding = column_widths[i % row_size] - expr_widths[i];
813 try ais.writer().writeByteNTimes(' ', padding);
814
815 col += 1;
816 continue;
742 var expr_index: usize = 0;
743 while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
744 const row_exprs = exprs[expr_index..];
745 // A place to store the width of each expression and its column's maximum
746 var widths = try allocator.alloc(usize, row_exprs.len + row_size);
747 defer allocator.free(widths);
748 mem.set(usize, widths, 0);
749
750 var expr_newlines = try allocator.alloc(bool, row_exprs.len);
751 defer allocator.free(expr_newlines);
752 mem.set(bool, expr_newlines, false);
753
754 var expr_widths = widths[0 .. widths.len - row_size];
755 var column_widths = widths[widths.len - row_size ..];
756
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 }
817785 }
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;
821869 try renderToken(tree, ais, comma, Space.Newline); // ,
870 try renderExtraNewline(tree, ais, next_expr);
822871 } 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 }
824879 }
880 }
825881
826 try renderExtraNewline(tree, ais, next_expr);
827 } else {
828 try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
882 if (expr_index == exprs.len) {
883 break;
829884 }
830885 }
831886 }
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
846888 return renderToken(tree, ais, rtoken, space);
847889 }
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);
848905 },
849906
850907 .StructInitializer, .StructInitializerDot => {
......@@ -1004,21 +1061,29 @@ fn renderExpression(
10041061 };
10051062
10061063 if (src_has_trailing_comma) {
1007 try renderToken(tree, ais, lparen, Space.Newline);
1008
1009 const params = call.params();
1010 for (params) |param_node, i| {
1064 {
10111065 ais.pushIndent();
10121066 defer ais.popIndent();
10131067
1014 if (i + 1 < params.len) {
1015 const next_node = params[i + 1];
1016 try renderExpression(allocator, ais, tree, param_node, Space.None);
1017 const comma = tree.nextToken(param_node.lastToken());
1018 try renderToken(tree, ais, comma, Space.Newline); // ,
1019 try renderExtraNewline(tree, ais, next_node);
1020 } else {
1021 try renderExpression(allocator, ais, tree, param_node, Space.Comma);
1068 try renderToken(tree, ais, lparen, Space.Newline); // (
1069 const params = call.params();
1070 for (params) |param_node, i| {
1071 if (i + 1 < params.len) {
1072 const next_node = params[i + 1];
1073 try renderExpression(allocator, ais, tree, param_node, Space.None);
1074
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 }
10221087 }
10231088 }
10241089 return renderToken(tree, ais, call.rtoken, space);
......@@ -1028,17 +1093,20 @@ fn renderExpression(
10281093
10291094 const params = call.params();
10301095 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
10331102 try renderExpression(allocator, ais, tree, param_node, Space.None);
10341103
10351104 if (i + 1 < params.len) {
1036 const next_param = params[i + 1];
10371105 const comma = tree.nextToken(param_node.lastToken());
10381106 try renderToken(tree, ais, comma, Space.Space);
10391107 }
10401108 }
1041 return renderToken(tree, ais, call.rtoken, space);
1109 return renderToken(tree, ais, call.rtoken, space); // )
10421110 },
10431111
10441112 .ArrayAccess => {
......@@ -1429,7 +1497,7 @@ fn renderExpression(
14291497 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
14301498
14311499 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;
14331501 const last_node = builtin_call.params()[builtin_call.params_len - 1];
14341502 const maybe_comma = tree.nextToken(last_node.lastToken());
14351503 break :blk tree.token_ids[maybe_comma] == .Comma;
......@@ -1443,6 +1511,10 @@ fn renderExpression(
14431511 // render all on one line, no trailing comma
14441512 const params = builtin_call.params();
14451513 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 }
14461518 try renderExpression(allocator, ais, tree, param_node, Space.None);
14471519
14481520 if (i + 1 < params.len) {
......@@ -1494,19 +1566,20 @@ fn renderExpression(
14941566 assert(tree.token_ids[lparen] == .LParen);
14951567
14961568 const rparen = tree.prevToken(
1497 // the first token for the annotation expressions is the left
1498 // parenthesis, hence the need for two prevToken
1499 if (fn_proto.getAlignExpr()) |align_expr|
1500 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1501 else if (fn_proto.getSectionExpr()) |section_expr|
1502 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1503 else if (fn_proto.getCallconvExpr()) |callconv_expr|
1504 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1505 else switch (fn_proto.return_type) {
1506 .Explicit => |node| node.firstToken(),
1507 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1508 .Invalid => unreachable,
1509 });
1569 // the first token for the annotation expressions is the left
1570 // parenthesis, hence the need for two prevToken
1571 if (fn_proto.getAlignExpr()) |align_expr|
1572 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1573 else if (fn_proto.getSectionExpr()) |section_expr|
1574 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1575 else if (fn_proto.getCallconvExpr()) |callconv_expr|
1576 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
1577 else switch (fn_proto.return_type) {
1578 .Explicit => |node| node.firstToken(),
1579 .InferErrorSet => |node| tree.prevToken(node.firstToken()),
1580 .Invalid => unreachable,
1581 },
1582 );
15101583 assert(tree.token_ids[rparen] == .RParen);
15111584
15121585 const src_params_trailing_comma = blk: {
......@@ -1758,7 +1831,7 @@ fn renderExpression(
17581831 }
17591832
17601833 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;
17621835 try renderExpression(allocator, ais, tree, payload, payload_space);
17631836 }
17641837
......@@ -1873,7 +1946,12 @@ fn renderExpression(
18731946
18741947 if (src_has_newline) {
18751948 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
18781956 if (if_node.payload) |payload| {
18791957 try renderExpression(allocator, ais, tree, payload, Space.Newline);
......@@ -2558,3 +2636,27 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
25582636 else => try ais.writer().writeByte(byte),
25592637 };
25602638}
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}