| ... | @@ -596,6 +596,28 @@ fn renderExpression( | ... | @@ -596,6 +596,28 @@ fn renderExpression( |
| 596 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | 596 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 597 | } | 597 | } |
| 598 | | 598 | |
| | 599 | const src_has_trailing_comma = blk: { |
| | 600 | const maybe_comma = tree.prevToken(suffix_op.rtoken); |
| | 601 | break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma; |
| | 602 | }; |
| | 603 | |
| | 604 | const src_same_line = blk: { |
| | 605 | const loc = tree.tokenLocation(tree.tokens.at(lbrace).end, suffix_op.rtoken); |
| | 606 | break :blk loc.line == 0; |
| | 607 | }; |
| | 608 | |
| | 609 | const expr_outputs_one_line = blk: { |
| | 610 | // render field expressions until a LF is found |
| | 611 | var it = field_inits.iterator(0); |
| | 612 | while (it.next()) |field_init| { |
| | 613 | var find_stream = FindByteOutStream.init('\n'); |
| | 614 | var dummy_col: usize = 0; |
| | 615 | try renderExpression(allocator, &find_stream.stream, tree, 0, &dummy_col, field_init.*, Space.None); |
| | 616 | if (find_stream.byte_found) break :blk false; |
| | 617 | } |
| | 618 | break :blk true; |
| | 619 | }; |
| | 620 | |
| 599 | if (field_inits.len == 1) blk: { | 621 | if (field_inits.len == 1) blk: { |
| 600 | const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?; | 622 | const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?; |
| 601 | | 623 | |
| ... | @@ -605,23 +627,18 @@ fn renderExpression( | ... | @@ -605,23 +627,18 @@ fn renderExpression( |
| 605 | } | 627 | } |
| 606 | } | 628 | } |
| 607 | | 629 | |
| | 630 | // if the expression outputs to multiline, make this struct multiline |
| | 631 | if (!expr_outputs_one_line or src_has_trailing_comma) { |
| | 632 | break :blk; |
| | 633 | } |
| | 634 | |
| 608 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | 635 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 609 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | 636 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| 610 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); | 637 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); |
| 611 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | 638 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); |
| 612 | } | 639 | } |
| 613 | | 640 | |
| 614 | const src_has_trailing_comma = blk: { | 641 | if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { |
| 615 | const maybe_comma = tree.prevToken(suffix_op.rtoken); | | |
| 616 | break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma; | | |
| 617 | }; | | |
| 618 | | | |
| 619 | const src_same_line = blk: { | | |
| 620 | const loc = tree.tokenLocation(tree.tokens.at(lbrace).end, suffix_op.rtoken); | | |
| 621 | break :blk loc.line == 0; | | |
| 622 | }; | | |
| 623 | | | |
| 624 | if (!src_has_trailing_comma and src_same_line) { | | |
| 625 | // render all on one line, no trailing comma | 642 | // render all on one line, no trailing comma |
| 626 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); | 643 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 627 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | 644 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| ... | @@ -2092,3 +2109,33 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool { | ... | @@ -2092,3 +2109,33 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool { |
| 2092 | else => true, | 2109 | else => true, |
| 2093 | }; | 2110 | }; |
| 2094 | } | 2111 | } |
| | 2112 | |
| | 2113 | // An OutStream that returns whether the given character has been written to it. |
| | 2114 | // The contents are not written to anything. |
| | 2115 | const FindByteOutStream = struct { |
| | 2116 | const Self = FindByteOutStream; |
| | 2117 | pub const Error = error{}; |
| | 2118 | pub const Stream = std.io.OutStream(Error); |
| | 2119 | |
| | 2120 | pub stream: Stream, |
| | 2121 | pub byte_found: bool, |
| | 2122 | byte: u8, |
| | 2123 | |
| | 2124 | pub fn init(byte: u8) Self { |
| | 2125 | return Self{ |
| | 2126 | .stream = Stream{ .writeFn = writeFn }, |
| | 2127 | .byte = byte, |
| | 2128 | .byte_found = false, |
| | 2129 | }; |
| | 2130 | } |
| | 2131 | |
| | 2132 | fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void { |
| | 2133 | const self = @fieldParentPtr(Self, "stream", out_stream); |
| | 2134 | if (self.byte_found) return; |
| | 2135 | self.byte_found = blk: { |
| | 2136 | for (bytes) |b| |
| | 2137 | if (b == self.byte) break :blk true; |
| | 2138 | break :blk false; |
| | 2139 | }; |
| | 2140 | } |
| | 2141 | }; |