zig fmt: implement multiline string literals

This commit is contained in:
Isaac Freund
2021-02-13 15:23:24 +01:00
committed by Andrew Kelley
parent 75ba8d8db6
commit 24798b84ad
2 changed files with 116 additions and 81 deletions

View File

@@ -50,35 +50,35 @@ test "zig fmt: respect line breaks after var declarations" {
);
}
//test "zig fmt: multiline string mixed with comments" {
// try testCanonical(
// \\const s1 =
// \\ //\\one
// \\ \\two)
// \\ \\three
// \\;
// \\const s2 =
// \\ \\one
// \\ \\two)
// \\ //\\three
// \\;
// \\const s3 =
// \\ \\one
// \\ //\\two)
// \\ \\three
// \\;
// \\const s4 =
// \\ \\one
// \\ //\\two
// \\ \\three
// \\ //\\four
// \\ \\five
// \\;
// \\const a =
// \\ 1;
// \\
// );
//}
test "zig fmt: multiline string mixed with comments" {
try testCanonical(
\\const s1 =
\\ //\\one
\\ \\two)
\\ \\three
\\;
\\const s2 =
\\ \\one
\\ \\two)
\\ //\\three
\\;
\\const s3 =
\\ \\one
\\ //\\two)
\\ \\three
\\;
\\const s4 =
\\ \\one
\\ //\\two
\\ \\three
\\ //\\four
\\ \\five
\\;
\\const a =
\\ 1;
\\
);
}
test "zig fmt: empty file" {
try testCanonical(
@@ -974,25 +974,25 @@ test "zig fmt: character literal larger than u8" {
);
}
//test "zig fmt: infix operator and then multiline string literal" {
// try testCanonical(
// \\const x = "" ++
// \\ \\ hi
// \\;
// \\
// );
//}
//
//test "zig fmt: infix operator and then multiline string literal" {
// try testCanonical(
// \\const x = "" ++
// \\ \\ hi0
// \\ \\ hi1
// \\ \\ hi2
// \\;
// \\
// );
//}
test "zig fmt: infix operator and then multiline string literal" {
try testCanonical(
\\const x = "" ++
\\ \\ hi
\\;
\\
);
}
test "zig fmt: infix operator and then multiline string literal" {
try testCanonical(
\\const x = "" ++
\\ \\ hi0
\\ \\ hi1
\\ \\ hi2
\\;
\\
);
}
test "zig fmt: C pointers" {
try testCanonical(
@@ -1725,35 +1725,35 @@ test "zig fmt: struct literal no trailing comma" {
// \\
// );
//}
//
//test "zig fmt: multiline string with backslash at end of line" {
// try testCanonical(
// \\comptime {
// \\ err(
// \\ \\\
// \\ );
// \\}
// \\
// );
//}
//
//test "zig fmt: multiline string parameter in fn call with trailing comma" {
// try testCanonical(
// \\fn foo() void {
// \\ try stdout.print(
// \\ \\ZIG_CMAKE_BINARY_DIR {}
// \\ \\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),
// \\ );
// \\}
// \\
// );
//}
test "zig fmt: multiline string with backslash at end of line" {
try testCanonical(
\\comptime {
\\ err(
\\ \\\
\\ );
\\}
\\
);
}
test "zig fmt: multiline string parameter in fn call with trailing comma" {
try testCanonical(
\\fn foo() void {
\\ try stdout.print(
\\ \\ZIG_CMAKE_BINARY_DIR {}
\\ \\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),
\\ );
\\}
\\
);
}
test "zig fmt: trailing comma on fn call" {
try testCanonical(

View File

@@ -146,7 +146,6 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
.identifier,
.integer_literal,
.float_literal,
.string_literal,
.char_literal,
.true_literal,
.false_literal,
@@ -156,6 +155,29 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
.anyframe_literal,
=> return renderToken(ais, tree, main_tokens[node], space),
.string_literal => switch (token_tags[main_tokens[node]]) {
.string_literal => try renderToken(ais, tree, main_tokens[node], space),
.multiline_string_literal_line => {
var locked_indents = ais.lockOneShotIndent();
try ais.maybeInsertNewline();
var i = datas[node].lhs;
while (i <= datas[node].rhs) : (i += 1) try renderToken(ais, tree, i, .newline);
while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();
switch (space) {
.none => {},
.semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline),
.comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline),
.comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space),
else => unreachable,
}
},
else => unreachable,
},
.error_value => {
try renderToken(ais, tree, main_tokens[node], .none);
try renderToken(ais, tree, main_tokens[node] + 1, .none);
@@ -1821,7 +1843,7 @@ fn renderCall(
const last_param = params[params.len - 1];
const after_last_param_tok = tree.lastToken(last_param) + 1;
if (token_tags[after_last_param_tok] == .comma) {
ais.pushIndent();
ais.pushIndentNextLine();
try renderToken(ais, tree, lparen, Space.newline); // (
for (params) |param_node, i| {
if (i + 1 < params.len) {
@@ -1846,6 +1868,7 @@ fn renderCall(
return renderToken(ais, tree, after_last_param_tok + 1, space); // )
}
ais.pushIndentNextLine();
try renderToken(ais, tree, lparen, Space.none); // (
for (params) |param_node, i| {
@@ -1856,6 +1879,8 @@ fn renderCall(
try renderToken(ais, tree, comma, Space.space);
}
}
ais.popIndent();
return renderToken(ais, tree, after_last_param_tok, space); // )
}
@@ -1907,7 +1932,8 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
const token_starts = tree.tokens.items(.start);
const token_start = token_starts[token_index];
const lexeme = tree.tokenSlice(token_index);
const lexeme = tokenSliceForRender(tree, token_index);
try ais.writer().writeAll(lexeme);
if (space == .no_comment) return;
@@ -1991,7 +2017,7 @@ fn renderExtraNewlineToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenInde
const prev_token_end = if (token_index == 0)
0
else
token_starts[token_index - 1] + tree.tokenSlice(token_index - 1).len;
token_starts[token_index - 1] + tokenSliceForRender(tree, token_index - 1).len;
// If there is a comment present, it will handle the empty line
if (mem.indexOf(u8, tree.source[prev_token_end..token_start], "//") != null) return;
@@ -2034,6 +2060,15 @@ fn renderDocComments(ais: *Ais, tree: ast.Tree, end_token: ast.TokenIndex) Error
}
}
fn tokenSliceForRender(tree: ast.Tree, token_index: ast.TokenIndex) []const u8 {
var ret = tree.tokenSlice(token_index);
if (tree.tokens.items(.tag)[token_index] == .multiline_string_literal_line) {
assert(ret[ret.len - 1] == '\n');
ret.len -= 1;
}
return ret;
}
fn nodeIsBlock(tag: ast.Node.Tag) bool {
return switch (tag) {
.block,