| ... | ... | @@ -82,6 +82,7 @@ const Render = struct { |
| 82 | 82 | pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!void { |
| 83 | 83 | assert(tree.errors.len == 0); // Cannot render an invalid tree. |
| 84 | 84 | var auto_indenting_stream = Ais.init(buffer, indent_delta); |
| 85 | defer auto_indenting_stream.deinit(); |
| 85 | 86 | var r: Render = .{ |
| 86 | 87 | .gpa = buffer.allocator, |
| 87 | 88 | .ais = &auto_indenting_stream, |
| ... | ... | @@ -195,7 +196,7 @@ fn renderMember( |
| 195 | 196 | try renderExpression(r, fn_proto, .space); |
| 196 | 197 | const body_node = datas[decl].rhs; |
| 197 | 198 | if (r.fixups.gut_functions.contains(decl)) { |
| 198 | | ais.pushIndent(); |
| 199 | try ais.pushIndent(.normal); |
| 199 | 200 | const lbrace = tree.nodes.items(.main_token)[body_node]; |
| 200 | 201 | try renderToken(r, lbrace, .newline); |
| 201 | 202 | try discardAllParams(r, fn_proto); |
| ... | ... | @@ -204,7 +205,7 @@ fn renderMember( |
| 204 | 205 | try ais.insertNewline(); |
| 205 | 206 | try renderToken(r, tree.lastToken(body_node), space); // rbrace |
| 206 | 207 | } else if (r.fixups.unused_var_decls.count() != 0) { |
| 207 | | ais.pushIndentNextLine(); |
| 208 | try ais.pushIndent(.normal); |
| 208 | 209 | const lbrace = tree.nodes.items(.main_token)[body_node]; |
| 209 | 210 | try renderToken(r, lbrace, .newline); |
| 210 | 211 | |
| ... | ... | @@ -358,13 +359,16 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 358 | 359 | => return renderToken(r, main_tokens[node], space), |
| 359 | 360 | |
| 360 | 361 | .multiline_string_literal => { |
| 361 | | var locked_indents = ais.lockOneShotIndent(); |
| 362 | 362 | try ais.maybeInsertNewline(); |
| 363 | 363 | |
| 364 | 364 | var i = datas[node].lhs; |
| 365 | 365 | while (i <= datas[node].rhs) : (i += 1) try renderToken(r, i, .newline); |
| 366 | 366 | |
| 367 | | while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent(); |
| 367 | // dedent the next thing that comes after a multiline string literal |
| 368 | if (!ais.indentStackEmpty()) { |
| 369 | ais.popIndent(); |
| 370 | try ais.pushIndent(.normal); |
| 371 | } |
| 368 | 372 | |
| 369 | 373 | switch (space) { |
| 370 | 374 | .none, .space, .newline, .skip => {}, |
| ... | ... | @@ -442,6 +446,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 442 | 446 | |
| 443 | 447 | try renderExpression(r, datas[node].lhs, .space); // target |
| 444 | 448 | |
| 449 | try ais.pushIndent(.normal); |
| 445 | 450 | if (token_tags[fallback_first - 1] == .pipe) { |
| 446 | 451 | try renderToken(r, main_token, .space); // catch keyword |
| 447 | 452 | try renderToken(r, main_token + 1, .none); // pipe |
| ... | ... | @@ -451,38 +456,27 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 451 | 456 | assert(token_tags[fallback_first - 1] == .keyword_catch); |
| 452 | 457 | try renderToken(r, main_token, after_op_space); // catch keyword |
| 453 | 458 | } |
| 454 | | |
| 455 | | ais.pushIndentOneShot(); |
| 456 | 459 | try renderExpression(r, datas[node].rhs, space); // fallback |
| 460 | ais.popIndent(); |
| 457 | 461 | }, |
| 458 | 462 | |
| 459 | 463 | .field_access => { |
| 460 | 464 | const main_token = main_tokens[node]; |
| 461 | 465 | const field_access = datas[node]; |
| 462 | 466 | |
| 467 | try ais.pushIndent(.normal); |
| 463 | 468 | try renderExpression(r, field_access.lhs, .none); |
| 464 | 469 | |
| 465 | 470 | // Allow a line break between the lhs and the dot if the lhs and rhs |
| 466 | 471 | // are on different lines. |
| 467 | 472 | const lhs_last_token = tree.lastToken(field_access.lhs); |
| 468 | 473 | const same_line = tree.tokensOnSameLine(lhs_last_token, main_token + 1); |
| 469 | | if (!same_line) { |
| 470 | | if (!hasComment(tree, lhs_last_token, main_token)) try ais.insertNewline(); |
| 471 | | ais.pushIndentOneShot(); |
| 472 | | } |
| 474 | if (!same_line and !hasComment(tree, lhs_last_token, main_token)) try ais.insertNewline(); |
| 473 | 475 | |
| 474 | 476 | try renderToken(r, main_token, .none); // . |
| 475 | 477 | |
| 476 | | // This check ensures that zag() is indented in the following example: |
| 477 | | // const x = foo |
| 478 | | // .bar() |
| 479 | | // . // comment |
| 480 | | // zag(); |
| 481 | | if (!same_line and hasComment(tree, main_token, main_token + 1)) { |
| 482 | | ais.pushIndentOneShot(); |
| 483 | | } |
| 484 | | |
| 485 | | return renderIdentifier(r, field_access.rhs, space, .eagerly_unquote); // field |
| 478 | try renderIdentifier(r, field_access.rhs, space, .eagerly_unquote); // field |
| 479 | ais.popIndent(); |
| 486 | 480 | }, |
| 487 | 481 | |
| 488 | 482 | .error_union, |
| ... | ... | @@ -555,15 +549,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 555 | 549 | const infix = datas[node]; |
| 556 | 550 | try renderExpression(r, infix.lhs, .space); |
| 557 | 551 | const op_token = main_tokens[node]; |
| 552 | try ais.pushIndent(.normal); |
| 558 | 553 | if (tree.tokensOnSameLine(op_token, op_token + 1)) { |
| 559 | 554 | try renderToken(r, op_token, .space); |
| 560 | 555 | } else { |
| 561 | | ais.pushIndent(); |
| 562 | 556 | try renderToken(r, op_token, .newline); |
| 563 | | ais.popIndent(); |
| 564 | 557 | } |
| 565 | | ais.pushIndentOneShot(); |
| 566 | | return renderExpression(r, infix.rhs, space); |
| 558 | try renderExpression(r, infix.rhs, space); |
| 559 | ais.popIndent(); |
| 567 | 560 | }, |
| 568 | 561 | |
| 569 | 562 | .assign_destructure => { |
| ... | ... | @@ -585,15 +578,14 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 585 | 578 | else => try renderExpression(r, variable_node, variable_space), |
| 586 | 579 | } |
| 587 | 580 | } |
| 581 | try ais.pushIndent(.normal); |
| 588 | 582 | if (tree.tokensOnSameLine(full.ast.equal_token, full.ast.equal_token + 1)) { |
| 589 | 583 | try renderToken(r, full.ast.equal_token, .space); |
| 590 | 584 | } else { |
| 591 | | ais.pushIndent(); |
| 592 | 585 | try renderToken(r, full.ast.equal_token, .newline); |
| 593 | | ais.popIndent(); |
| 594 | 586 | } |
| 595 | | ais.pushIndentOneShot(); |
| 596 | | return renderExpression(r, full.ast.value_expr, space); |
| 587 | try renderExpression(r, full.ast.value_expr, space); |
| 588 | ais.popIndent(); |
| 597 | 589 | }, |
| 598 | 590 | |
| 599 | 591 | .bit_not, |
| ... | ... | @@ -671,7 +663,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 671 | 663 | const one_line = tree.tokensOnSameLine(lbracket, rbracket); |
| 672 | 664 | const inner_space = if (one_line) Space.none else Space.newline; |
| 673 | 665 | try renderExpression(r, suffix.lhs, .none); |
| 674 | | ais.pushIndentNextLine(); |
| 666 | try ais.pushIndent(.normal); |
| 675 | 667 | try renderToken(r, lbracket, inner_space); // [ |
| 676 | 668 | try renderExpression(r, suffix.rhs, inner_space); |
| 677 | 669 | ais.popIndent(); |
| ... | ... | @@ -723,8 +715,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 723 | 715 | |
| 724 | 716 | .grouped_expression => { |
| 725 | 717 | try renderToken(r, main_tokens[node], .none); // lparen |
| 726 | | ais.pushIndentOneShot(); |
| 718 | try ais.pushIndent(.normal); |
| 727 | 719 | try renderExpression(r, datas[node].lhs, .none); |
| 720 | ais.popIndent(); |
| 728 | 721 | return renderToken(r, datas[node].rhs, space); // rparen |
| 729 | 722 | }, |
| 730 | 723 | |
| ... | ... | @@ -764,7 +757,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 764 | 757 | return renderToken(r, rbrace, space); |
| 765 | 758 | } else if (token_tags[rbrace - 1] == .comma) { |
| 766 | 759 | // There is a trailing comma so render each member on a new line. |
| 767 | | ais.pushIndentNextLine(); |
| 760 | try ais.pushIndent(.normal); |
| 768 | 761 | try renderToken(r, lbrace, .newline); |
| 769 | 762 | var i = lbrace + 1; |
| 770 | 763 | while (i < rbrace) : (i += 1) { |
| ... | ... | @@ -845,7 +838,7 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 845 | 838 | try renderExpression(r, full.ast.condition, .none); // condition expression |
| 846 | 839 | try renderToken(r, rparen, .space); // ) |
| 847 | 840 | |
| 848 | | ais.pushIndentNextLine(); |
| 841 | try ais.pushIndent(.normal); |
| 849 | 842 | if (full.ast.cases.len == 0) { |
| 850 | 843 | try renderToken(r, rparen + 1, .none); // { |
| 851 | 844 | } else { |
| ... | ... | @@ -920,7 +913,7 @@ fn renderArrayType( |
| 920 | 913 | const rbracket = tree.firstToken(array_type.ast.elem_type) - 1; |
| 921 | 914 | const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket); |
| 922 | 915 | const inner_space = if (one_line) Space.none else Space.newline; |
| 923 | | ais.pushIndentNextLine(); |
| 916 | try ais.pushIndent(.normal); |
| 924 | 917 | try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket |
| 925 | 918 | try renderExpression(r, array_type.ast.elem_count, inner_space); |
| 926 | 919 | if (array_type.ast.sentinel != 0) { |
| ... | ... | @@ -1236,13 +1229,10 @@ fn renderVarDeclWithoutFixups( |
| 1236 | 1229 | |
| 1237 | 1230 | const eq_token = tree.firstToken(var_decl.ast.init_node) - 1; |
| 1238 | 1231 | const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; |
| 1239 | | { |
| 1240 | | ais.pushIndent(); |
| 1241 | | try renderToken(r, eq_token, eq_space); // = |
| 1242 | | ais.popIndent(); |
| 1243 | | } |
| 1244 | | ais.pushIndentOneShot(); |
| 1245 | | return renderExpression(r, var_decl.ast.init_node, space); // ; |
| 1232 | try ais.pushIndent(.normal); |
| 1233 | try renderToken(r, eq_token, eq_space); // = |
| 1234 | try renderExpression(r, var_decl.ast.init_node, space); // ; |
| 1235 | ais.popIndent(); |
| 1246 | 1236 | } |
| 1247 | 1237 | |
| 1248 | 1238 | fn renderIf(r: *Render, if_node: Ast.full.If, space: Space) Error!void { |
| ... | ... | @@ -1342,23 +1332,28 @@ fn renderThenElse( |
| 1342 | 1332 | const then_expr_is_block = nodeIsBlock(node_tags[then_expr]); |
| 1343 | 1333 | const indent_then_expr = !then_expr_is_block and |
| 1344 | 1334 | !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(then_expr)); |
| 1345 | | if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) { |
| 1346 | | ais.pushIndentNextLine(); |
| 1335 | |
| 1336 | if (indent_then_expr) try ais.pushIndent(.normal); |
| 1337 | |
| 1338 | if (then_expr_is_block and ais.isLineOverIndented()) { |
| 1339 | ais.disableIndentCommitting(); |
| 1340 | try renderToken(r, last_prefix_token, .newline); |
| 1341 | ais.enableIndentCommitting(); |
| 1342 | } else if (indent_then_expr) { |
| 1347 | 1343 | try renderToken(r, last_prefix_token, .newline); |
| 1348 | | ais.popIndent(); |
| 1349 | 1344 | } else { |
| 1350 | 1345 | try renderToken(r, last_prefix_token, .space); |
| 1351 | 1346 | } |
| 1352 | 1347 | |
| 1353 | 1348 | if (else_expr != 0) { |
| 1354 | 1349 | if (indent_then_expr) { |
| 1355 | | ais.pushIndent(); |
| 1356 | 1350 | try renderExpression(r, then_expr, .newline); |
| 1357 | | ais.popIndent(); |
| 1358 | 1351 | } else { |
| 1359 | 1352 | try renderExpression(r, then_expr, .space); |
| 1360 | 1353 | } |
| 1361 | 1354 | |
| 1355 | if (indent_then_expr) ais.popIndent(); |
| 1356 | |
| 1362 | 1357 | var last_else_token = else_token; |
| 1363 | 1358 | |
| 1364 | 1359 | if (maybe_error_token) |error_token| { |
| ... | ... | @@ -1372,20 +1367,17 @@ fn renderThenElse( |
| 1372 | 1367 | !nodeIsBlock(node_tags[else_expr]) and |
| 1373 | 1368 | !nodeIsIfForWhileSwitch(node_tags[else_expr]); |
| 1374 | 1369 | if (indent_else_expr) { |
| 1375 | | ais.pushIndentNextLine(); |
| 1370 | try ais.pushIndent(.normal); |
| 1376 | 1371 | try renderToken(r, last_else_token, .newline); |
| 1372 | try renderExpression(r, else_expr, space); |
| 1377 | 1373 | ais.popIndent(); |
| 1378 | | try renderExpressionIndented(r, else_expr, space); |
| 1379 | 1374 | } else { |
| 1380 | 1375 | try renderToken(r, last_else_token, .space); |
| 1381 | 1376 | try renderExpression(r, else_expr, space); |
| 1382 | 1377 | } |
| 1383 | 1378 | } else { |
| 1384 | | if (indent_then_expr) { |
| 1385 | | try renderExpressionIndented(r, then_expr, space); |
| 1386 | | } else { |
| 1387 | | try renderExpression(r, then_expr, space); |
| 1388 | | } |
| 1379 | try renderExpression(r, then_expr, space); |
| 1380 | if (indent_then_expr) ais.popIndent(); |
| 1389 | 1381 | } |
| 1390 | 1382 | } |
| 1391 | 1383 | |
| ... | ... | @@ -1411,7 +1403,7 @@ fn renderFor(r: *Render, for_node: Ast.full.For, space: Space) Error!void { |
| 1411 | 1403 | var cur = for_node.payload_token; |
| 1412 | 1404 | const pipe = std.mem.indexOfScalarPos(std.zig.Token.Tag, token_tags, cur, .pipe).?; |
| 1413 | 1405 | if (token_tags[pipe - 1] == .comma) { |
| 1414 | | ais.pushIndentNextLine(); |
| 1406 | try ais.pushIndent(.normal); |
| 1415 | 1407 | try renderToken(r, cur - 1, .newline); // | |
| 1416 | 1408 | while (true) { |
| 1417 | 1409 | if (token_tags[cur] == .asterisk) { |
| ... | ... | @@ -1540,7 +1532,7 @@ fn renderContainerField( |
| 1540 | 1532 | const eq_token = tree.firstToken(field.ast.value_expr) - 1; |
| 1541 | 1533 | const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline; |
| 1542 | 1534 | { |
| 1543 | | ais.pushIndent(); |
| 1535 | try ais.pushIndent(.normal); |
| 1544 | 1536 | try renderToken(r, eq_token, eq_space); // = |
| 1545 | 1537 | ais.popIndent(); |
| 1546 | 1538 | } |
| ... | ... | @@ -1552,12 +1544,12 @@ fn renderContainerField( |
| 1552 | 1544 | const maybe_comma = tree.lastToken(field.ast.value_expr) + 1; |
| 1553 | 1545 | |
| 1554 | 1546 | if (token_tags[maybe_comma] == .comma) { |
| 1555 | | ais.pushIndent(); |
| 1547 | try ais.pushIndent(.normal); |
| 1556 | 1548 | try renderExpression(r, field.ast.value_expr, .none); // value |
| 1557 | 1549 | ais.popIndent(); |
| 1558 | 1550 | try renderToken(r, maybe_comma, .newline); |
| 1559 | 1551 | } else { |
| 1560 | | ais.pushIndent(); |
| 1552 | try ais.pushIndent(.normal); |
| 1561 | 1553 | try renderExpression(r, field.ast.value_expr, space); // value |
| 1562 | 1554 | ais.popIndent(); |
| 1563 | 1555 | } |
| ... | ... | @@ -1614,9 +1606,12 @@ fn renderBuiltinCall( |
| 1614 | 1606 | if (token_tags[first_param_token] == .multiline_string_literal_line or |
| 1615 | 1607 | hasSameLineComment(tree, first_param_token - 1)) |
| 1616 | 1608 | { |
| 1617 | | ais.pushIndentOneShot(); |
| 1609 | try ais.pushIndent(.normal); |
| 1610 | try renderExpression(r, param_node, .none); |
| 1611 | ais.popIndent(); |
| 1612 | } else { |
| 1613 | try renderExpression(r, param_node, .none); |
| 1618 | 1614 | } |
| 1619 | | try renderExpression(r, param_node, .none); |
| 1620 | 1615 | |
| 1621 | 1616 | if (i + 1 < params.len) { |
| 1622 | 1617 | const comma_token = tree.lastToken(param_node) + 1; |
| ... | ... | @@ -1626,7 +1621,7 @@ fn renderBuiltinCall( |
| 1626 | 1621 | return renderToken(r, after_last_param_token, space); // ) |
| 1627 | 1622 | } else { |
| 1628 | 1623 | // Render one param per line. |
| 1629 | | ais.pushIndent(); |
| 1624 | try ais.pushIndent(.normal); |
| 1630 | 1625 | try renderToken(r, builtin_token + 1, Space.newline); // ( |
| 1631 | 1626 | |
| 1632 | 1627 | for (params) |param_node| { |
| ... | ... | @@ -1752,7 +1747,7 @@ fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!voi |
| 1752 | 1747 | } |
| 1753 | 1748 | } else { |
| 1754 | 1749 | // One param per line. |
| 1755 | | ais.pushIndent(); |
| 1750 | try ais.pushIndent(.normal); |
| 1756 | 1751 | try renderToken(r, lparen, .newline); // ( |
| 1757 | 1752 | |
| 1758 | 1753 | var param_i: usize = 0; |
| ... | ... | @@ -1933,7 +1928,7 @@ fn renderBlock( |
| 1933 | 1928 | try renderIdentifier(r, lbrace - 2, .none, .eagerly_unquote); // identifier |
| 1934 | 1929 | try renderToken(r, lbrace - 1, .space); // : |
| 1935 | 1930 | } |
| 1936 | | ais.pushIndentNextLine(); |
| 1931 | try ais.pushIndent(.normal); |
| 1937 | 1932 | if (statements.len == 0) { |
| 1938 | 1933 | try renderToken(r, lbrace, .none); |
| 1939 | 1934 | ais.popIndent(); |
| ... | ... | @@ -1986,7 +1981,7 @@ fn renderStructInit( |
| 1986 | 1981 | try renderExpression(r, struct_init.ast.type_expr, .none); // T |
| 1987 | 1982 | } |
| 1988 | 1983 | if (struct_init.ast.fields.len == 0) { |
| 1989 | | ais.pushIndentNextLine(); |
| 1984 | try ais.pushIndent(.normal); |
| 1990 | 1985 | try renderToken(r, struct_init.ast.lbrace, .none); // lbrace |
| 1991 | 1986 | ais.popIndent(); |
| 1992 | 1987 | return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace |
| ... | ... | @@ -1996,7 +1991,7 @@ fn renderStructInit( |
| 1996 | 1991 | const trailing_comma = token_tags[rbrace - 1] == .comma; |
| 1997 | 1992 | if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) { |
| 1998 | 1993 | // Render one field init per line. |
| 1999 | | ais.pushIndentNextLine(); |
| 1994 | try ais.pushIndent(.normal); |
| 2000 | 1995 | try renderToken(r, struct_init.ast.lbrace, .newline); |
| 2001 | 1996 | |
| 2002 | 1997 | try renderToken(r, struct_init.ast.lbrace + 1, .none); // . |
| ... | ... | @@ -2054,7 +2049,7 @@ fn renderArrayInit( |
| 2054 | 2049 | } |
| 2055 | 2050 | |
| 2056 | 2051 | if (array_init.ast.elements.len == 0) { |
| 2057 | | ais.pushIndentNextLine(); |
| 2052 | try ais.pushIndent(.normal); |
| 2058 | 2053 | try renderToken(r, array_init.ast.lbrace, .none); // lbrace |
| 2059 | 2054 | ais.popIndent(); |
| 2060 | 2055 | return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace |
| ... | ... | @@ -2096,7 +2091,7 @@ fn renderArrayInit( |
| 2096 | 2091 | return renderToken(r, last_elem_token + 1, space); // rbrace |
| 2097 | 2092 | } |
| 2098 | 2093 | |
| 2099 | | ais.pushIndentNextLine(); |
| 2094 | try ais.pushIndent(.normal); |
| 2100 | 2095 | try renderToken(r, array_init.ast.lbrace, .newline); |
| 2101 | 2096 | |
| 2102 | 2097 | var expr_index: usize = 0; |
| ... | ... | @@ -2149,7 +2144,8 @@ fn renderArrayInit( |
| 2149 | 2144 | const sub_expr_buffer_starts = try gpa.alloc(usize, section_exprs.len + 1); |
| 2150 | 2145 | defer gpa.free(sub_expr_buffer_starts); |
| 2151 | 2146 | |
| 2152 | | var auto_indenting_stream = Ais.init(sub_expr_buffer, indent_delta); |
| 2147 | var auto_indenting_stream = Ais.init(&sub_expr_buffer, indent_delta); |
| 2148 | defer auto_indenting_stream.deinit(); |
| 2153 | 2149 | var sub_render: Render = .{ |
| 2154 | 2150 | .gpa = r.gpa, |
| 2155 | 2151 | .ais = &auto_indenting_stream, |
| ... | ... | @@ -2312,7 +2308,7 @@ fn renderContainerDecl( |
| 2312 | 2308 | |
| 2313 | 2309 | const rbrace = tree.lastToken(container_decl_node); |
| 2314 | 2310 | if (container_decl.ast.members.len == 0) { |
| 2315 | | ais.pushIndentNextLine(); |
| 2311 | try ais.pushIndent(.normal); |
| 2316 | 2312 | if (token_tags[lbrace + 1] == .container_doc_comment) { |
| 2317 | 2313 | try renderToken(r, lbrace, .newline); // lbrace |
| 2318 | 2314 | try renderContainerDocComments(r, lbrace + 1); |
| ... | ... | @@ -2354,7 +2350,7 @@ fn renderContainerDecl( |
| 2354 | 2350 | } |
| 2355 | 2351 | |
| 2356 | 2352 | // One member per line. |
| 2357 | | ais.pushIndentNextLine(); |
| 2353 | try ais.pushIndent(.normal); |
| 2358 | 2354 | try renderToken(r, lbrace, .newline); // lbrace |
| 2359 | 2355 | if (token_tags[lbrace + 1] == .container_doc_comment) { |
| 2360 | 2356 | try renderContainerDocComments(r, lbrace + 1); |
| ... | ... | @@ -2395,7 +2391,7 @@ fn renderAsm( |
| 2395 | 2391 | } |
| 2396 | 2392 | |
| 2397 | 2393 | if (asm_node.ast.items.len == 0) { |
| 2398 | | ais.pushIndent(); |
| 2394 | try ais.pushIndent(.normal); |
| 2399 | 2395 | if (asm_node.first_clobber) |first_clobber| { |
| 2400 | 2396 | // asm ("foo" ::: "a", "b") |
| 2401 | 2397 | // asm ("foo" ::: "a", "b",) |
| ... | ... | @@ -2433,7 +2429,7 @@ fn renderAsm( |
| 2433 | 2429 | } |
| 2434 | 2430 | } |
| 2435 | 2431 | |
| 2436 | | ais.pushIndent(); |
| 2432 | try ais.pushIndent(.normal); |
| 2437 | 2433 | try renderExpression(r, asm_node.ast.template, .newline); |
| 2438 | 2434 | ais.setIndentDelta(asm_indent_delta); |
| 2439 | 2435 | const colon1 = tree.lastToken(asm_node.ast.template) + 1; |
| ... | ... | @@ -2444,7 +2440,7 @@ fn renderAsm( |
| 2444 | 2440 | } else colon2: { |
| 2445 | 2441 | try renderToken(r, colon1, .space); // : |
| 2446 | 2442 | |
| 2447 | | ais.pushIndent(); |
| 2443 | try ais.pushIndent(.normal); |
| 2448 | 2444 | for (asm_node.outputs, 0..) |asm_output, i| { |
| 2449 | 2445 | if (i + 1 < asm_node.outputs.len) { |
| 2450 | 2446 | const next_asm_output = asm_node.outputs[i + 1]; |
| ... | ... | @@ -2476,7 +2472,7 @@ fn renderAsm( |
| 2476 | 2472 | break :colon3 colon2 + 1; |
| 2477 | 2473 | } else colon3: { |
| 2478 | 2474 | try renderToken(r, colon2, .space); // : |
| 2479 | | ais.pushIndent(); |
| 2475 | try ais.pushIndent(.normal); |
| 2480 | 2476 | for (asm_node.inputs, 0..) |asm_input, i| { |
| 2481 | 2477 | if (i + 1 < asm_node.inputs.len) { |
| 2482 | 2478 | const next_asm_input = asm_node.inputs[i + 1]; |
| ... | ... | @@ -2558,7 +2554,7 @@ fn renderParamList( |
| 2558 | 2554 | const token_tags = tree.tokens.items(.tag); |
| 2559 | 2555 | |
| 2560 | 2556 | if (params.len == 0) { |
| 2561 | | ais.pushIndentNextLine(); |
| 2557 | try ais.pushIndent(.normal); |
| 2562 | 2558 | try renderToken(r, lparen, .none); |
| 2563 | 2559 | ais.popIndent(); |
| 2564 | 2560 | return renderToken(r, lparen + 1, space); // ) |
| ... | ... | @@ -2567,22 +2563,15 @@ fn renderParamList( |
| 2567 | 2563 | const last_param = params[params.len - 1]; |
| 2568 | 2564 | const after_last_param_tok = tree.lastToken(last_param) + 1; |
| 2569 | 2565 | if (token_tags[after_last_param_tok] == .comma) { |
| 2570 | | ais.pushIndentNextLine(); |
| 2566 | try ais.pushIndent(.normal); |
| 2571 | 2567 | try renderToken(r, lparen, .newline); // ( |
| 2572 | 2568 | for (params, 0..) |param_node, i| { |
| 2573 | 2569 | if (i + 1 < params.len) { |
| 2574 | 2570 | try renderExpression(r, param_node, .none); |
| 2575 | 2571 | |
| 2576 | | // Unindent the comma for multiline string literals. |
| 2577 | | const is_multiline_string = |
| 2578 | | token_tags[tree.firstToken(param_node)] == .multiline_string_literal_line; |
| 2579 | | if (is_multiline_string) ais.popIndent(); |
| 2580 | | |
| 2581 | 2572 | const comma = tree.lastToken(param_node) + 1; |
| 2582 | 2573 | try renderToken(r, comma, .newline); // , |
| 2583 | 2574 | |
| 2584 | | if (is_multiline_string) ais.pushIndent(); |
| 2585 | | |
| 2586 | 2575 | try renderExtraNewline(r, params[i + 1]); |
| 2587 | 2576 | } else { |
| 2588 | 2577 | try renderExpression(r, param_node, .comma); |
| ... | ... | @@ -2599,9 +2588,12 @@ fn renderParamList( |
| 2599 | 2588 | if (token_tags[first_param_token] == .multiline_string_literal_line or |
| 2600 | 2589 | hasSameLineComment(tree, first_param_token - 1)) |
| 2601 | 2590 | { |
| 2602 | | ais.pushIndentOneShot(); |
| 2591 | try ais.pushIndent(.normal); |
| 2592 | try renderExpression(r, param_node, .none); |
| 2593 | ais.popIndent(); |
| 2594 | } else { |
| 2595 | try renderExpression(r, param_node, .none); |
| 2603 | 2596 | } |
| 2604 | | try renderExpression(r, param_node, .none); |
| 2605 | 2597 | |
| 2606 | 2598 | if (i + 1 < params.len) { |
| 2607 | 2599 | const comma = tree.lastToken(param_node) + 1; |
| ... | ... | @@ -2615,66 +2607,6 @@ fn renderParamList( |
| 2615 | 2607 | return renderToken(r, after_last_param_tok, space); // ) |
| 2616 | 2608 | } |
| 2617 | 2609 | |
| 2618 | | /// Renders the given expression indented, popping the indent before rendering |
| 2619 | | /// any following line comments |
| 2620 | | fn renderExpressionIndented(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 2621 | | const tree = r.tree; |
| 2622 | | const ais = r.ais; |
| 2623 | | const token_starts = tree.tokens.items(.start); |
| 2624 | | const token_tags = tree.tokens.items(.tag); |
| 2625 | | |
| 2626 | | ais.pushIndent(); |
| 2627 | | |
| 2628 | | var last_token = tree.lastToken(node); |
| 2629 | | const punctuation = switch (space) { |
| 2630 | | .none, .space, .newline, .skip => false, |
| 2631 | | .comma => true, |
| 2632 | | .comma_space => token_tags[last_token + 1] == .comma, |
| 2633 | | .semicolon => token_tags[last_token + 1] == .semicolon, |
| 2634 | | }; |
| 2635 | | |
| 2636 | | try renderExpression(r, node, if (punctuation) .none else .skip); |
| 2637 | | |
| 2638 | | switch (space) { |
| 2639 | | .none, .space, .newline, .skip => {}, |
| 2640 | | .comma => { |
| 2641 | | if (token_tags[last_token + 1] == .comma) { |
| 2642 | | try renderToken(r, last_token + 1, .skip); |
| 2643 | | last_token += 1; |
| 2644 | | } else { |
| 2645 | | try ais.writer().writeByte(','); |
| 2646 | | } |
| 2647 | | }, |
| 2648 | | .comma_space => if (token_tags[last_token + 1] == .comma) { |
| 2649 | | try renderToken(r, last_token + 1, .skip); |
| 2650 | | last_token += 1; |
| 2651 | | }, |
| 2652 | | .semicolon => if (token_tags[last_token + 1] == .semicolon) { |
| 2653 | | try renderToken(r, last_token + 1, .skip); |
| 2654 | | last_token += 1; |
| 2655 | | }, |
| 2656 | | } |
| 2657 | | |
| 2658 | | ais.popIndent(); |
| 2659 | | |
| 2660 | | if (space == .skip) return; |
| 2661 | | |
| 2662 | | const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len; |
| 2663 | | const comment = try renderComments(r, comment_start, token_starts[last_token + 1]); |
| 2664 | | |
| 2665 | | if (!comment) switch (space) { |
| 2666 | | .none => {}, |
| 2667 | | .space, |
| 2668 | | .comma_space, |
| 2669 | | => try ais.writer().writeByte(' '), |
| 2670 | | .newline, |
| 2671 | | .comma, |
| 2672 | | .semicolon, |
| 2673 | | => try ais.insertNewline(), |
| 2674 | | .skip => unreachable, |
| 2675 | | }; |
| 2676 | | } |
| 2677 | | |
| 2678 | 2610 | /// Render an expression, and the comma that follows it, if it is present in the source. |
| 2679 | 2611 | /// If a comma is present, and `space` is `Space.comma`, render only a single comma. |
| 2680 | 2612 | fn renderExpressionComma(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| ... | ... | @@ -3315,6 +3247,14 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3315 | 3247 | pub const WriteError = UnderlyingWriter.Error; |
| 3316 | 3248 | pub const Writer = std.io.Writer(*Self, WriteError, write); |
| 3317 | 3249 | |
| 3250 | pub const IndentType = enum { |
| 3251 | normal, |
| 3252 | }; |
| 3253 | const StackElem = struct { |
| 3254 | indent_type: IndentType, |
| 3255 | realized: bool, |
| 3256 | }; |
| 3257 | |
| 3318 | 3258 | underlying_writer: UnderlyingWriter, |
| 3319 | 3259 | |
| 3320 | 3260 | /// Offset into the source at which formatting has been disabled with |
| ... | ... | @@ -3327,21 +3267,24 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3327 | 3267 | |
| 3328 | 3268 | indent_count: usize = 0, |
| 3329 | 3269 | indent_delta: usize, |
| 3270 | indent_stack: std.ArrayList(StackElem), |
| 3271 | disable_indent_committing: usize = 0, |
| 3330 | 3272 | current_line_empty: bool = true, |
| 3331 | | /// automatically popped when applied |
| 3332 | | indent_one_shot_count: usize = 0, |
| 3333 | 3273 | /// the most recently applied indent |
| 3334 | 3274 | applied_indent: usize = 0, |
| 3335 | | /// not used until the next line |
| 3336 | | indent_next_line: usize = 0, |
| 3337 | 3275 | |
| 3338 | | pub fn init(buffer: *std.ArrayList(u8), indent_delta: usize) Self { |
| 3276 | pub fn init(buffer: *std.ArrayList(u8), indent_delta_: usize) Self { |
| 3339 | 3277 | return .{ |
| 3340 | 3278 | .underlying_writer = buffer.writer(), |
| 3341 | | .indent_delta = indent_delta, |
| 3279 | .indent_delta = indent_delta_, |
| 3280 | .indent_stack = std.ArrayList(StackElem).init(buffer.allocator), |
| 3342 | 3281 | }; |
| 3343 | 3282 | } |
| 3344 | 3283 | |
| 3284 | pub fn deinit(self: *Self) void { |
| 3285 | self.indent_stack.deinit(); |
| 3286 | } |
| 3287 | |
| 3345 | 3288 | pub fn writer(self: *Self) Writer { |
| 3346 | 3289 | return .{ .context = self }; |
| 3347 | 3290 | } |
| ... | ... | @@ -3385,7 +3328,23 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3385 | 3328 | |
| 3386 | 3329 | fn resetLine(self: *Self) void { |
| 3387 | 3330 | self.current_line_empty = true; |
| 3388 | | self.indent_next_line = 0; |
| 3331 | if (self.disable_indent_committing > 0) return; |
| 3332 | if (self.indent_stack.items.len > 0) { |
| 3333 | // Only realize last pushed indent |
| 3334 | if (!self.indent_stack.items[self.indent_stack.items.len - 1].realized) { |
| 3335 | self.indent_stack.items[self.indent_stack.items.len - 1].realized = true; |
| 3336 | self.indent_count += 1; |
| 3337 | } |
| 3338 | } |
| 3339 | } |
| 3340 | |
| 3341 | pub fn disableIndentCommitting(self: *Self) void { |
| 3342 | self.disable_indent_committing += 1; |
| 3343 | } |
| 3344 | |
| 3345 | pub fn enableIndentCommitting(self: *Self) void { |
| 3346 | assert(self.disable_indent_committing > 0); |
| 3347 | self.disable_indent_committing -= 1; |
| 3389 | 3348 | } |
| 3390 | 3349 | |
| 3391 | 3350 | /// Insert a newline unless the current line is blank |
| ... | ... | @@ -3397,36 +3356,19 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3397 | 3356 | /// Push default indentation |
| 3398 | 3357 | /// Doesn't actually write any indentation. |
| 3399 | 3358 | /// Just primes the stream to be able to write the correct indentation if it needs to. |
| 3400 | | pub fn pushIndent(self: *Self) void { |
| 3401 | | self.indent_count += 1; |
| 3402 | | } |
| 3403 | | |
| 3404 | | /// Push an indent that is automatically popped after being applied |
| 3405 | | pub fn pushIndentOneShot(self: *Self) void { |
| 3406 | | self.indent_one_shot_count += 1; |
| 3407 | | self.pushIndent(); |
| 3408 | | } |
| 3409 | | |
| 3410 | | /// Turns all one-shot indents into regular indents |
| 3411 | | /// Returns number of indents that must now be manually popped |
| 3412 | | pub fn lockOneShotIndent(self: *Self) usize { |
| 3413 | | const locked_count = self.indent_one_shot_count; |
| 3414 | | self.indent_one_shot_count = 0; |
| 3415 | | return locked_count; |
| 3416 | | } |
| 3417 | | |
| 3418 | | /// Push an indent that should not take effect until the next line |
| 3419 | | pub fn pushIndentNextLine(self: *Self) void { |
| 3420 | | self.indent_next_line += 1; |
| 3421 | | self.pushIndent(); |
| 3359 | pub fn pushIndent(self: *Self, indent_type: IndentType) !void { |
| 3360 | try self.indent_stack.append(.{ .indent_type = indent_type, .realized = false }); |
| 3422 | 3361 | } |
| 3423 | 3362 | |
| 3424 | 3363 | pub fn popIndent(self: *Self) void { |
| 3425 | | assert(self.indent_count != 0); |
| 3426 | | self.indent_count -= 1; |
| 3364 | if (self.indent_stack.pop().realized) { |
| 3365 | assert(self.indent_count > 0); |
| 3366 | self.indent_count -= 1; |
| 3367 | } |
| 3368 | } |
| 3427 | 3369 | |
| 3428 | | if (self.indent_next_line > 0) |
| 3429 | | self.indent_next_line -= 1; |
| 3370 | pub fn indentStackEmpty(self: *Self) bool { |
| 3371 | return self.indent_stack.items.len == 0; |
| 3430 | 3372 | } |
| 3431 | 3373 | |
| 3432 | 3374 | /// Writes ' ' bytes if the current line is empty |
| ... | ... | @@ -3438,9 +3380,6 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3438 | 3380 | } |
| 3439 | 3381 | self.applied_indent = current_indent; |
| 3440 | 3382 | } |
| 3441 | | |
| 3442 | | self.indent_count -= self.indent_one_shot_count; |
| 3443 | | self.indent_one_shot_count = 0; |
| 3444 | 3383 | self.current_line_empty = false; |
| 3445 | 3384 | } |
| 3446 | 3385 | |
| ... | ... | @@ -3451,12 +3390,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type { |
| 3451 | 3390 | } |
| 3452 | 3391 | |
| 3453 | 3392 | fn currentIndent(self: *Self) usize { |
| 3454 | | var indent_current: usize = 0; |
| 3455 | | if (self.indent_count > 0) { |
| 3456 | | const indent_count = self.indent_count - self.indent_next_line; |
| 3457 | | indent_current = indent_count * self.indent_delta; |
| 3458 | | } |
| 3459 | | return indent_current; |
| 3393 | return self.indent_count * self.indent_delta; |
| 3460 | 3394 | } |
| 3461 | 3395 | }; |
| 3462 | 3396 | } |