mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 00:35:10 +00:00
commit
8794ce6f79
@ -823,6 +823,15 @@ pub const Node = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn findFirstWithId(self: *Node, id: Id) ?*Node {
|
||||
if (self.id == id) return self;
|
||||
var child_i: usize = 0;
|
||||
while (self.iterate(child_i)) |child| : (child_i += 1) {
|
||||
if (child.findFirstWithId(id)) |result| return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn dump(self: *Node, indent: usize) void {
|
||||
{
|
||||
var i: usize = 0;
|
||||
|
||||
@ -1301,8 +1301,10 @@ test "zig fmt: array literal with hint" {
|
||||
\\const a = []u8{
|
||||
\\ 1, 2,
|
||||
\\ 3, 4,
|
||||
\\ 5, 6, // blah
|
||||
\\ 7, 8,
|
||||
\\ 5,
|
||||
\\ 6, // blah
|
||||
\\ 7,
|
||||
\\ 8,
|
||||
\\};
|
||||
\\const a = []u8{
|
||||
\\ 1, 2,
|
||||
@ -1372,7 +1374,7 @@ test "zig fmt: multiline string parameter in fn call with trailing comma" {
|
||||
\\ \\ZIG_C_HEADER_FILES {}
|
||||
\\ \\ZIG_DIA_GUIDS_LIB {}
|
||||
\\ \\
|
||||
\\ ,
|
||||
\\ ,
|
||||
\\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),
|
||||
\\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),
|
||||
\\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
|
||||
@ -3321,6 +3323,326 @@ test "zig fmt: Don't add extra newline after if" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comments in ternary ifs" {
|
||||
try testCanonical(
|
||||
\\const x = if (true) {
|
||||
\\ 1;
|
||||
\\} else if (false)
|
||||
\\ // Comment
|
||||
\\ 0;
|
||||
\\const y = if (true)
|
||||
\\ // Comment
|
||||
\\ 1
|
||||
\\else
|
||||
\\ 0;
|
||||
\\
|
||||
\\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: test comments in field access chain" {
|
||||
try testCanonical(
|
||||
\\pub const str = struct {
|
||||
\\ pub const Thing = more.more //
|
||||
\\ .more() //
|
||||
\\ .more().more() //
|
||||
\\ .more() //
|
||||
\\ // .more() //
|
||||
\\ .more() //
|
||||
\\ .more();
|
||||
\\ data: Data,
|
||||
\\};
|
||||
\\
|
||||
\\pub const str = struct {
|
||||
\\ pub const Thing = more.more //
|
||||
\\ .more() //
|
||||
\\ // .more() //
|
||||
\\ // .more() //
|
||||
\\ // .more() //
|
||||
\\ .more() //
|
||||
\\ .more();
|
||||
\\ data: Data,
|
||||
\\};
|
||||
\\
|
||||
\\pub const str = struct {
|
||||
\\ pub const Thing = more //
|
||||
\\ .more //
|
||||
\\ .more() //
|
||||
\\ .more();
|
||||
\\ data: Data,
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: Indent comma correctly after multiline string literals in arg list (trailing comma)" {
|
||||
try testCanonical(
|
||||
\\fn foo() void {
|
||||
\\ z.display_message_dialog(
|
||||
\\ *const [323:0]u8,
|
||||
\\ \\Message Text
|
||||
\\ \\------------
|
||||
\\ \\xxxxxxxxxxxx
|
||||
\\ \\xxxxxxxxxxxx
|
||||
\\ ,
|
||||
\\ g.GtkMessageType.GTK_MESSAGE_WARNING,
|
||||
\\ null,
|
||||
\\ );
|
||||
\\
|
||||
\\ z.display_message_dialog(*const [323:0]u8,
|
||||
\\ \\Message Text
|
||||
\\ \\------------
|
||||
\\ \\xxxxxxxxxxxx
|
||||
\\ \\xxxxxxxxxxxx
|
||||
\\ , g.GtkMessageType.GTK_MESSAGE_WARNING, null);
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: Control flow statement as body of blockless if" {
|
||||
try testCanonical(
|
||||
\\pub fn main() void {
|
||||
\\ const zoom_node = if (focused_node == layout_first)
|
||||
\\ if (it.next()) {
|
||||
\\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
|
||||
\\ } else null
|
||||
\\ else
|
||||
\\ focused_node;
|
||||
\\
|
||||
\\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
|
||||
\\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
|
||||
\\ } else null else
|
||||
\\ focused_node;
|
||||
\\
|
||||
\\ const zoom_node = if (focused_node == layout_first)
|
||||
\\ if (it.next()) {
|
||||
\\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
|
||||
\\ } else null;
|
||||
\\
|
||||
\\ const zoom_node = if (focused_node == layout_first) while (it.next()) |node| {
|
||||
\\ if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
|
||||
\\ };
|
||||
\\
|
||||
\\ const zoom_node = if (focused_node == layout_first) for (nodes) |node| {
|
||||
\\ break node;
|
||||
\\ };
|
||||
\\
|
||||
\\ const zoom_node = if (focused_node == layout_first) switch (nodes) {
|
||||
\\ 0 => 0,
|
||||
\\ } else
|
||||
\\ focused_node;
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: " {
|
||||
try testCanonical(
|
||||
\\pub fn sendViewTags(self: Self) void {
|
||||
\\ var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
|
||||
\\ while (it.next()) |node|
|
||||
\\ view_tags.append(node.view.current_tags) catch {
|
||||
\\ c.wl_resource_post_no_memory(self.wl_resource);
|
||||
\\ log.crit(.river_status, "out of memory", .{});
|
||||
\\ return;
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: allow trailing line comments to do manual array formatting" {
|
||||
try testCanonical(
|
||||
\\fn foo() void {
|
||||
\\ self.code.appendSliceAssumeCapacity(&[_]u8{
|
||||
\\ 0x55, // push rbp
|
||||
\\ 0x48, 0x89, 0xe5, // mov rbp, rsp
|
||||
\\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
|
||||
\\ });
|
||||
\\
|
||||
\\ di_buf.appendAssumeCapacity(&[_]u8{
|
||||
\\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
|
||||
\\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
|
||||
\\ DW.AT_low_pc, DW_FORM_addr,
|
||||
\\ DW.AT_high_pc, DW_FORM_addr,
|
||||
\\ DW.AT_name, DW_FORM_strp,
|
||||
\\ DW.AT_comp_dir, DW_FORM_strp,
|
||||
\\ DW.AT_producer, DW_FORM_strp,
|
||||
\\ DW.AT_language, DW_FORM_data2,
|
||||
\\ 0, 0, // sentinel
|
||||
\\ });
|
||||
\\
|
||||
\\ self.code.appendSliceAssumeCapacity(&[_]u8{
|
||||
\\ 0x55, // push rbp
|
||||
\\ 0x48, 0x89, 0xe5, // mov rbp, rsp
|
||||
\\ // How do we handle this?
|
||||
\\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
|
||||
\\ // Here's a blank line, should that be allowed?
|
||||
\\
|
||||
\\ 0x48, 0x89, 0xe5,
|
||||
\\ 0x33, 0x45,
|
||||
\\ // Now the comment breaks a single line -- how do we handle this?
|
||||
\\ 0x88,
|
||||
\\ });
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: multiline string literals should play nice with array initializers" {
|
||||
try testCanonical(
|
||||
\\fn main() void {
|
||||
\\ var a = .{.{.{.{.{.{.{.{
|
||||
\\ 0,
|
||||
\\ }}}}}}}};
|
||||
\\ myFunc(.{
|
||||
\\ "aaaaaaa", "bbbbbb", "ccccc",
|
||||
\\ "dddd", ("eee"), ("fff"),
|
||||
\\ ("gggg"),
|
||||
\\ // Line comment
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ ,
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ ,
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ ,
|
||||
\\ (
|
||||
\\ \\Multiline String Literals can be quite long
|
||||
\\ ),
|
||||
\\ .{
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ },
|
||||
\\ .{(
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ )},
|
||||
\\ .{
|
||||
\\ "xxxxxxx", "xxx",
|
||||
\\ (
|
||||
\\ \\ xxx
|
||||
\\ ),
|
||||
\\ "xxx", "xxx",
|
||||
\\ },
|
||||
\\ .{ "xxxxxxx", "xxx", "xxx", "xxx" }, .{ "xxxxxxx", "xxx", "xxx", "xxx" },
|
||||
\\ "aaaaaaa", "bbbbbb", "ccccc", // -
|
||||
\\ "dddd", ("eee"), ("fff"),
|
||||
\\ .{
|
||||
\\ "xxx", "xxx",
|
||||
\\ (
|
||||
\\ \\ xxx
|
||||
\\ ),
|
||||
\\ "xxxxxxxxxxxxxx", "xxx",
|
||||
\\ },
|
||||
\\ .{
|
||||
\\ (
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ ),
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ },
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ \\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
\\ });
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
|
||||
try testCanonical(
|
||||
\\pub fn makeMemUndefined(qzz: []u8) i1 {
|
||||
\\ cases.add( // fixed bug #2032
|
||||
\\ "compile diagnostic string for top level decl type",
|
||||
\\ \\export fn entry() void {
|
||||
\\ \\ var foo: u32 = @This(){};
|
||||
\\ \\}
|
||||
\\ , &[_][]const u8{
|
||||
\\ "tmp.zig:2:27: error: type 'u32' does not support array initialization",
|
||||
\\ });
|
||||
\\ @compileError(
|
||||
\\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
|
||||
\\ \\ Consider providing your own hash function.
|
||||
\\ \\ unknown-length pointers and C pointers cannot be hashed deeply.
|
||||
\\ \\ Consider providing your own hash function.
|
||||
\\ );
|
||||
\\ return @intCast(i1, doMemCheckClientRequestExpr(0, // default return
|
||||
\\ .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
|
||||
\\}
|
||||
\\
|
||||
\\// This looks like garbage don't do this
|
||||
\\const rparen = tree.prevToken(
|
||||
\\// the first token for the annotation expressions is the left
|
||||
\\// parenthesis, hence the need for two prevToken
|
||||
\\ if (fn_proto.getAlignExpr()) |align_expr|
|
||||
\\ tree.prevToken(tree.prevToken(align_expr.firstToken()))
|
||||
\\else if (fn_proto.getSectionExpr()) |section_expr|
|
||||
\\ tree.prevToken(tree.prevToken(section_expr.firstToken()))
|
||||
\\else if (fn_proto.getCallconvExpr()) |callconv_expr|
|
||||
\\ tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
|
||||
\\else switch (fn_proto.return_type) {
|
||||
\\ .Explicit => |node| node.firstToken(),
|
||||
\\ .InferErrorSet => |node| tree.prevToken(node.firstToken()),
|
||||
\\ .Invalid => unreachable,
|
||||
\\});
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: single argument trailing commas in @builtins()" {
|
||||
try testCanonical(
|
||||
\\pub fn foo(qzz: []u8) i1 {
|
||||
\\ @panic(
|
||||
\\ foo,
|
||||
\\ );
|
||||
\\ panic(
|
||||
\\ foo,
|
||||
\\ );
|
||||
\\ @panic(
|
||||
\\ foo,
|
||||
\\ bar,
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: trailing comma should force multiline 1 column" {
|
||||
try testTransform(
|
||||
\\pub const UUID_NULL: uuid_t = [16]u8{0,0,0,0,};
|
||||
\\
|
||||
,
|
||||
\\pub const UUID_NULL: uuid_t = [16]u8{
|
||||
\\ 0,
|
||||
\\ 0,
|
||||
\\ 0,
|
||||
\\ 0,
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: function params should align nicely" {
|
||||
try testCanonical(
|
||||
\\pub fn foo() void {
|
||||
\\ cases.addRuntimeSafety("slicing operator with sentinel",
|
||||
\\ \\const std = @import("std");
|
||||
\\ ++ check_panic_msg ++
|
||||
\\ \\pub fn main() void {
|
||||
\\ \\ var buf = [4]u8{'a','b','c',0};
|
||||
\\ \\ const slice = buf[0..:0];
|
||||
\\ \\}
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const warn = std.debug.warn;
|
||||
|
||||
@ -522,7 +522,11 @@ fn renderExpression(
|
||||
break :blk if (loc.line == 0) op_space else Space.Newline;
|
||||
};
|
||||
|
||||
try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
|
||||
{
|
||||
ais.pushIndent();
|
||||
defer ais.popIndent();
|
||||
try renderToken(tree, ais, infix_op_node.op_token, after_op_space);
|
||||
}
|
||||
ais.pushIndentOneShot();
|
||||
return renderExpression(allocator, ais, tree, infix_op_node.rhs, space);
|
||||
},
|
||||
@ -710,141 +714,194 @@ fn renderExpression(
|
||||
.node => |node| tree.nextToken(node.lastToken()),
|
||||
};
|
||||
|
||||
if (exprs.len == 0) {
|
||||
switch (lhs) {
|
||||
.dot => |dot| try renderToken(tree, ais, dot, Space.None),
|
||||
.node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
|
||||
}
|
||||
|
||||
{
|
||||
ais.pushIndent();
|
||||
defer ais.popIndent();
|
||||
try renderToken(tree, ais, lbrace, Space.None);
|
||||
}
|
||||
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
}
|
||||
if (exprs.len == 1 and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
|
||||
const expr = exprs[0];
|
||||
|
||||
switch (lhs) {
|
||||
.dot => |dot| try renderToken(tree, ais, dot, Space.None),
|
||||
.node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
|
||||
}
|
||||
try renderToken(tree, ais, lbrace, Space.None);
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None);
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
}
|
||||
|
||||
switch (lhs) {
|
||||
.dot => |dot| try renderToken(tree, ais, dot, Space.None),
|
||||
.node => |node| try renderExpression(allocator, ais, tree, node, Space.None),
|
||||
}
|
||||
|
||||
if (exprs.len == 0) {
|
||||
try renderToken(tree, ais, lbrace, Space.None);
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
}
|
||||
|
||||
if (exprs.len == 1 and exprs[0].tag != .MultilineStringLiteral and tree.token_ids[exprs[0].*.lastToken() + 1] == .RBrace) {
|
||||
const expr = exprs[0];
|
||||
|
||||
try renderToken(tree, ais, lbrace, Space.None);
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None);
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
}
|
||||
|
||||
// scan to find row size
|
||||
const maybe_row_size: ?usize = blk: {
|
||||
var count: usize = 1;
|
||||
for (exprs) |expr, i| {
|
||||
if (i + 1 < exprs.len) {
|
||||
const expr_last_token = expr.lastToken() + 1;
|
||||
const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i + 1].firstToken());
|
||||
if (loc.line != 0) break :blk count;
|
||||
count += 1;
|
||||
} else {
|
||||
const expr_last_token = expr.lastToken();
|
||||
const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken);
|
||||
if (loc.line == 0) {
|
||||
// all on one line
|
||||
const src_has_trailing_comma = trailblk: {
|
||||
const maybe_comma = tree.prevToken(rtoken);
|
||||
break :trailblk tree.token_ids[maybe_comma] == .Comma;
|
||||
};
|
||||
if (src_has_trailing_comma) {
|
||||
break :blk 1; // force row size 1
|
||||
} else {
|
||||
break :blk null; // no newlines
|
||||
}
|
||||
}
|
||||
break :blk count;
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
};
|
||||
|
||||
if (maybe_row_size) |row_size| {
|
||||
// A place to store the width of each expression and its column's maximum
|
||||
var widths = try allocator.alloc(usize, exprs.len + row_size);
|
||||
defer allocator.free(widths);
|
||||
mem.set(usize, widths, 0);
|
||||
|
||||
var expr_widths = widths[0 .. widths.len - row_size];
|
||||
var column_widths = widths[widths.len - row_size ..];
|
||||
|
||||
// Null ais for counting the printed length of each expression
|
||||
var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
|
||||
|
||||
for (exprs) |expr, i| {
|
||||
counting_stream.bytes_written = 0;
|
||||
try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
|
||||
const width = @intCast(usize, counting_stream.bytes_written);
|
||||
const col = i % row_size;
|
||||
column_widths[col] = std.math.max(column_widths[col], width);
|
||||
expr_widths[i] = width;
|
||||
}
|
||||
|
||||
if (rowSize(tree, exprs, rtoken) != null) {
|
||||
{
|
||||
ais.pushIndentNextLine();
|
||||
defer ais.popIndent();
|
||||
try renderToken(tree, ais, lbrace, Space.Newline);
|
||||
|
||||
var col: usize = 1;
|
||||
for (exprs) |expr, i| {
|
||||
if (i + 1 < exprs.len) {
|
||||
const next_expr = exprs[i + 1];
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None);
|
||||
var expr_index: usize = 0;
|
||||
while (rowSize(tree, exprs[expr_index..], rtoken)) |row_size| {
|
||||
const row_exprs = exprs[expr_index..];
|
||||
// A place to store the width of each expression and its column's maximum
|
||||
var widths = try allocator.alloc(usize, row_exprs.len + row_size);
|
||||
defer allocator.free(widths);
|
||||
mem.set(usize, widths, 0);
|
||||
|
||||
const comma = tree.nextToken(expr.*.lastToken());
|
||||
var expr_newlines = try allocator.alloc(bool, row_exprs.len);
|
||||
defer allocator.free(expr_newlines);
|
||||
mem.set(bool, expr_newlines, false);
|
||||
|
||||
if (col != row_size) {
|
||||
try renderToken(tree, ais, comma, Space.Space); // ,
|
||||
var expr_widths = widths[0 .. widths.len - row_size];
|
||||
var column_widths = widths[widths.len - row_size ..];
|
||||
|
||||
const padding = column_widths[i % row_size] - expr_widths[i];
|
||||
try ais.writer().writeByteNTimes(' ', padding);
|
||||
// Find next row with trailing comment (if any) to end the current section
|
||||
var section_end = sec_end: {
|
||||
var this_line_first_expr: usize = 0;
|
||||
var this_line_size = rowSize(tree, row_exprs, rtoken);
|
||||
for (row_exprs) |expr, i| {
|
||||
// Ignore comment on first line of this section
|
||||
if (i == 0 or tree.tokensOnSameLine(row_exprs[0].firstToken(), expr.lastToken())) continue;
|
||||
// Track start of line containing comment
|
||||
if (!tree.tokensOnSameLine(row_exprs[this_line_first_expr].firstToken(), expr.lastToken())) {
|
||||
this_line_first_expr = i;
|
||||
this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rtoken);
|
||||
}
|
||||
|
||||
col += 1;
|
||||
continue;
|
||||
const maybe_comma = expr.lastToken() + 1;
|
||||
const maybe_comment = expr.lastToken() + 2;
|
||||
if (maybe_comment < tree.token_ids.len) {
|
||||
if (tree.token_ids[maybe_comma] == .Comma and
|
||||
tree.token_ids[maybe_comment] == .LineComment and
|
||||
tree.tokensOnSameLine(expr.lastToken(), maybe_comment))
|
||||
{
|
||||
var comment_token_loc = tree.token_locs[maybe_comment];
|
||||
const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(comment_token_loc), " ").len == 2;
|
||||
if (!comment_is_empty) {
|
||||
// Found row ending in comment
|
||||
break :sec_end i - this_line_size.? + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
col = 1;
|
||||
break :sec_end row_exprs.len;
|
||||
};
|
||||
expr_index += section_end;
|
||||
|
||||
if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) {
|
||||
try renderToken(tree, ais, comma, Space.Newline); // ,
|
||||
const section_exprs = row_exprs[0..section_end];
|
||||
|
||||
// Null stream for counting the printed length of each expression
|
||||
var line_find_stream = std.io.findByteOutStream('\n', std.io.null_out_stream);
|
||||
var counting_stream = std.io.countingOutStream(line_find_stream.writer());
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, counting_stream.writer());
|
||||
|
||||
// Calculate size of columns in current section
|
||||
var column_counter: usize = 0;
|
||||
var single_line = true;
|
||||
for (section_exprs) |expr, i| {
|
||||
if (i + 1 < section_exprs.len) {
|
||||
counting_stream.bytes_written = 0;
|
||||
line_find_stream.byte_found = false;
|
||||
try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
|
||||
const width = @intCast(usize, counting_stream.bytes_written);
|
||||
expr_widths[i] = width;
|
||||
expr_newlines[i] = line_find_stream.byte_found;
|
||||
|
||||
if (!line_find_stream.byte_found) {
|
||||
const column = column_counter % row_size;
|
||||
column_widths[column] = std.math.max(column_widths[column], width);
|
||||
|
||||
const expr_last_token = expr.*.lastToken() + 1;
|
||||
const next_expr = section_exprs[i + 1];
|
||||
const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, next_expr.*.firstToken());
|
||||
if (loc.line == 0) {
|
||||
column_counter += 1;
|
||||
} else {
|
||||
single_line = false;
|
||||
column_counter = 0;
|
||||
}
|
||||
} else {
|
||||
single_line = false;
|
||||
column_counter = 0;
|
||||
}
|
||||
} else {
|
||||
try renderToken(tree, ais, comma, Space.None); // ,
|
||||
}
|
||||
counting_stream.bytes_written = 0;
|
||||
try renderExpression(allocator, &auto_indenting_stream, tree, expr, Space.None);
|
||||
const width = @intCast(usize, counting_stream.bytes_written);
|
||||
expr_widths[i] = width;
|
||||
expr_newlines[i] = line_find_stream.byte_found;
|
||||
|
||||
try renderExtraNewline(tree, ais, next_expr);
|
||||
} else {
|
||||
try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
|
||||
if (!line_find_stream.byte_found) {
|
||||
const column = column_counter % row_size;
|
||||
column_widths[column] = std.math.max(column_widths[column], width);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Render exprs in current section
|
||||
column_counter = 0;
|
||||
var last_col_index: usize = row_size - 1;
|
||||
for (section_exprs) |expr, i| {
|
||||
if (i + 1 < section_exprs.len) {
|
||||
const next_expr = section_exprs[i + 1];
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None);
|
||||
|
||||
const comma = tree.nextToken(expr.*.lastToken());
|
||||
|
||||
if (column_counter != last_col_index) {
|
||||
if (!expr_newlines[i] and !expr_newlines[i + 1]) {
|
||||
// Neither the current or next expression is multiline
|
||||
try renderToken(tree, ais, comma, Space.Space); // ,
|
||||
assert(column_widths[column_counter % row_size] >= expr_widths[i]);
|
||||
const padding = column_widths[column_counter % row_size] - expr_widths[i];
|
||||
try ais.writer().writeByteNTimes(' ', padding);
|
||||
|
||||
column_counter += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (single_line and row_size != 1) {
|
||||
try renderToken(tree, ais, comma, Space.Space); // ,
|
||||
continue;
|
||||
}
|
||||
|
||||
column_counter = 0;
|
||||
try renderToken(tree, ais, comma, Space.Newline); // ,
|
||||
try renderExtraNewline(tree, ais, next_expr);
|
||||
} else {
|
||||
const maybe_comma = tree.nextToken(expr.*.lastToken());
|
||||
if (tree.token_ids[maybe_comma] == .Comma) {
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None); // ,
|
||||
try renderToken(tree, ais, maybe_comma, Space.Newline); // ,
|
||||
} else {
|
||||
try renderExpression(allocator, ais, tree, expr, Space.Comma); // ,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (expr_index == exprs.len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
} else {
|
||||
try renderToken(tree, ais, lbrace, Space.Space);
|
||||
for (exprs) |expr, i| {
|
||||
if (i + 1 < exprs.len) {
|
||||
const next_expr = exprs[i + 1];
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None);
|
||||
const comma = tree.nextToken(expr.*.lastToken());
|
||||
try renderToken(tree, ais, comma, Space.Space); // ,
|
||||
} else {
|
||||
try renderExpression(allocator, ais, tree, expr, Space.Space);
|
||||
}
|
||||
}
|
||||
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
}
|
||||
|
||||
// Single line
|
||||
try renderToken(tree, ais, lbrace, Space.Space);
|
||||
for (exprs) |expr, i| {
|
||||
if (i + 1 < exprs.len) {
|
||||
const next_expr = exprs[i + 1];
|
||||
try renderExpression(allocator, ais, tree, expr, Space.None);
|
||||
const comma = tree.nextToken(expr.*.lastToken());
|
||||
try renderToken(tree, ais, comma, Space.Space); // ,
|
||||
} else {
|
||||
try renderExpression(allocator, ais, tree, expr, Space.Space);
|
||||
}
|
||||
}
|
||||
|
||||
return renderToken(tree, ais, rtoken, space);
|
||||
},
|
||||
|
||||
.StructInitializer, .StructInitializerDot => {
|
||||
@ -1004,21 +1061,29 @@ fn renderExpression(
|
||||
};
|
||||
|
||||
if (src_has_trailing_comma) {
|
||||
try renderToken(tree, ais, lparen, Space.Newline);
|
||||
|
||||
const params = call.params();
|
||||
for (params) |param_node, i| {
|
||||
{
|
||||
ais.pushIndent();
|
||||
defer ais.popIndent();
|
||||
|
||||
if (i + 1 < params.len) {
|
||||
const next_node = params[i + 1];
|
||||
try renderExpression(allocator, ais, tree, param_node, Space.None);
|
||||
const comma = tree.nextToken(param_node.lastToken());
|
||||
try renderToken(tree, ais, comma, Space.Newline); // ,
|
||||
try renderExtraNewline(tree, ais, next_node);
|
||||
} else {
|
||||
try renderExpression(allocator, ais, tree, param_node, Space.Comma);
|
||||
try renderToken(tree, ais, lparen, Space.Newline); // (
|
||||
const params = call.params();
|
||||
for (params) |param_node, i| {
|
||||
if (i + 1 < params.len) {
|
||||
const next_node = params[i + 1];
|
||||
try renderExpression(allocator, ais, tree, param_node, Space.None);
|
||||
|
||||
// Unindent the comma for multiline string literals
|
||||
const maybe_multiline_string = param_node.firstToken();
|
||||
const is_multiline_string = tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine;
|
||||
if (is_multiline_string) ais.popIndent();
|
||||
defer if (is_multiline_string) ais.pushIndent();
|
||||
|
||||
const comma = tree.nextToken(param_node.lastToken());
|
||||
try renderToken(tree, ais, comma, Space.Newline); // ,
|
||||
try renderExtraNewline(tree, ais, next_node);
|
||||
} else {
|
||||
try renderExpression(allocator, ais, tree, param_node, Space.Comma);
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderToken(tree, ais, call.rtoken, space);
|
||||
@ -1028,17 +1093,20 @@ fn renderExpression(
|
||||
|
||||
const params = call.params();
|
||||
for (params) |param_node, i| {
|
||||
if (param_node.*.tag == .MultilineStringLiteral) ais.pushIndentOneShot();
|
||||
const maybe_comment = param_node.firstToken() - 1;
|
||||
const maybe_multiline_string = param_node.firstToken();
|
||||
if (tree.token_ids[maybe_multiline_string] == .MultilineStringLiteralLine or tree.token_ids[maybe_comment] == .LineComment) {
|
||||
ais.pushIndentOneShot();
|
||||
}
|
||||
|
||||
try renderExpression(allocator, ais, tree, param_node, Space.None);
|
||||
|
||||
if (i + 1 < params.len) {
|
||||
const next_param = params[i + 1];
|
||||
const comma = tree.nextToken(param_node.lastToken());
|
||||
try renderToken(tree, ais, comma, Space.Space);
|
||||
}
|
||||
}
|
||||
return renderToken(tree, ais, call.rtoken, space);
|
||||
return renderToken(tree, ais, call.rtoken, space); // )
|
||||
},
|
||||
|
||||
.ArrayAccess => {
|
||||
@ -1429,7 +1497,7 @@ fn renderExpression(
|
||||
try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
|
||||
|
||||
const src_params_trailing_comma = blk: {
|
||||
if (builtin_call.params_len < 2) break :blk false;
|
||||
if (builtin_call.params_len == 0) break :blk false;
|
||||
const last_node = builtin_call.params()[builtin_call.params_len - 1];
|
||||
const maybe_comma = tree.nextToken(last_node.lastToken());
|
||||
break :blk tree.token_ids[maybe_comma] == .Comma;
|
||||
@ -1443,6 +1511,10 @@ fn renderExpression(
|
||||
// render all on one line, no trailing comma
|
||||
const params = builtin_call.params();
|
||||
for (params) |param_node, i| {
|
||||
const maybe_comment = param_node.firstToken() - 1;
|
||||
if (param_node.*.tag == .MultilineStringLiteral or tree.token_ids[maybe_comment] == .LineComment) {
|
||||
ais.pushIndentOneShot();
|
||||
}
|
||||
try renderExpression(allocator, ais, tree, param_node, Space.None);
|
||||
|
||||
if (i + 1 < params.len) {
|
||||
@ -1494,19 +1566,20 @@ fn renderExpression(
|
||||
assert(tree.token_ids[lparen] == .LParen);
|
||||
|
||||
const rparen = tree.prevToken(
|
||||
// the first token for the annotation expressions is the left
|
||||
// parenthesis, hence the need for two prevToken
|
||||
if (fn_proto.getAlignExpr()) |align_expr|
|
||||
tree.prevToken(tree.prevToken(align_expr.firstToken()))
|
||||
else if (fn_proto.getSectionExpr()) |section_expr|
|
||||
tree.prevToken(tree.prevToken(section_expr.firstToken()))
|
||||
else if (fn_proto.getCallconvExpr()) |callconv_expr|
|
||||
tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
|
||||
else switch (fn_proto.return_type) {
|
||||
.Explicit => |node| node.firstToken(),
|
||||
.InferErrorSet => |node| tree.prevToken(node.firstToken()),
|
||||
.Invalid => unreachable,
|
||||
});
|
||||
// the first token for the annotation expressions is the left
|
||||
// parenthesis, hence the need for two prevToken
|
||||
if (fn_proto.getAlignExpr()) |align_expr|
|
||||
tree.prevToken(tree.prevToken(align_expr.firstToken()))
|
||||
else if (fn_proto.getSectionExpr()) |section_expr|
|
||||
tree.prevToken(tree.prevToken(section_expr.firstToken()))
|
||||
else if (fn_proto.getCallconvExpr()) |callconv_expr|
|
||||
tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
|
||||
else switch (fn_proto.return_type) {
|
||||
.Explicit => |node| node.firstToken(),
|
||||
.InferErrorSet => |node| tree.prevToken(node.firstToken()),
|
||||
.Invalid => unreachable,
|
||||
},
|
||||
);
|
||||
assert(tree.token_ids[rparen] == .RParen);
|
||||
|
||||
const src_params_trailing_comma = blk: {
|
||||
@ -1758,7 +1831,7 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
if (while_node.payload) |payload| {
|
||||
const payload_space = Space.Space; //if (while_node.continue_expr != null) Space.Space else block_start_space;
|
||||
const payload_space = if (while_node.continue_expr != null) Space.Space else block_start_space;
|
||||
try renderExpression(allocator, ais, tree, payload, payload_space);
|
||||
}
|
||||
|
||||
@ -1873,7 +1946,12 @@ fn renderExpression(
|
||||
|
||||
if (src_has_newline) {
|
||||
const after_rparen_space = if (if_node.payload == null) Space.Newline else Space.Space;
|
||||
try renderToken(tree, ais, rparen, after_rparen_space); // )
|
||||
|
||||
{
|
||||
ais.pushIndent();
|
||||
defer ais.popIndent();
|
||||
try renderToken(tree, ais, rparen, after_rparen_space); // )
|
||||
}
|
||||
|
||||
if (if_node.payload) |payload| {
|
||||
try renderExpression(allocator, ais, tree, payload, Space.Newline);
|
||||
@ -2558,3 +2636,27 @@ fn copyFixingWhitespace(ais: anytype, slice: []const u8) @TypeOf(ais.*).Error!vo
|
||||
else => try ais.writer().writeByte(byte),
|
||||
};
|
||||
}
|
||||
|
||||
fn rowSize(tree: *ast.Tree, exprs: []*ast.Node, rtoken: ast.TokenIndex) ?usize {
|
||||
const first_token = exprs[0].firstToken();
|
||||
const first_loc = tree.tokenLocation(tree.token_locs[first_token].start, rtoken);
|
||||
if (first_loc.line == 0) {
|
||||
const maybe_comma = tree.prevToken(rtoken);
|
||||
if (tree.token_ids[maybe_comma] == .Comma)
|
||||
return 1;
|
||||
return null; // no newlines
|
||||
}
|
||||
|
||||
var count: usize = 1;
|
||||
for (exprs) |expr, i| {
|
||||
if (i + 1 < exprs.len) {
|
||||
const expr_last_token = expr.lastToken() + 1;
|
||||
const loc = tree.tokenLocation(tree.token_locs[expr_last_token].start, exprs[i + 1].firstToken());
|
||||
if (loc.line != 0) return count;
|
||||
count += 1;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user