easy-format
easy-format copied to clipboard
Classic if/then/else formatting.
This is one pattern that I've had a hard time figuring out how to accomplish with the formatting primitives in Eeasy_format:
if (x) {itemHere(a, b, c)} else {itemThere(x, y, z)}
Where if for any reason the "if braces" had broken, then the "else braces" should also break.
if (x) {
itemHere (
a,
b,
c
)
} else {
itemThere(x, y, z)
}
I think you can accomplish this with a list of 2 elements, using else
as separator, like the comma in a tuple. For a tuple we'd get the following structures:
(aaaaaa,
bbbbbb)
(aaaaaa, bbbbbb)
The opening and closing parens become `""`, the comma becomes `"else"` (or `" else"`).
That's what I would try because lists (boxes) that are either horizontal or vertical (but not mixed) are built in.
I was having similar problems implementing if/else if/else breaks since if you use Labels to implement it will break in the wrong order, as per below:
if (x) { itemHere(a); } else if (x) { itemThere(x, y, z); }
/* 1 */
if (x) { itemHere(a); } else if (x) {
itemThere(x, y, z);
}
/* 2 */
if (x) { itemHere(a); } else if (
x
) {
itemThere(x, y, z);
}
/* 3 */
if (x) {
itemHere(a);
} else if (
x
) {
itemThere(x, y, z);
}
By changing it to a list and manually adding splitting {
and }
across list items i think i have found a nice (but hacky solution), it at least covers all the JS if/else printing cases well. Here is a simplified version:
let string s => Atom s atom;
let inline_list indent::indent=false items =>
List
("", "", "", {
...list,
indent_body: indent ? 2 : 0,
space_after_opening: false,
space_after_separator: false,
space_before_closing: false,
wrap_body: `Force_breaks_rec,
align_closing: false
})
items;
inline_list [
Label
(string "if (a) {", {...label, label_break: `Always_rec})
(inline_list indent::true [string "line one;", string "line two;"]),
Label
(string "} else if (a) {", {...label, label_break: `Always_rec})
(inline_list indent::true [string "line one;", string "line two;"]),
string "}"
]
@jordwalke it won't quite solve the problem since half the breaks still happen one level down, but it's closer :/
Can you show the case where "half the breaks still happen one level down"?
The list inserts the newline for the trailing "}" whereas the statement list is separated onto a newline via the Label within the list, like so:
[
"if () { statement",
^ breaks here via the label
"}"
^ breaks here via list
]
Thinking about this more we could potentially remove the Label
between the if
and statements
and just put it on a newline:
let string s => Atom s atom;
let inline_list indent::indent=false items =>
List
("", "", "", {
...list,
indent_body: indent ? 2 : 0,
space_after_opening: false,
space_after_separator: false,
space_before_closing: false,
wrap_body: `Force_breaks_rec,
align_closing: false
})
items;
inline_list [
string "if (a) {",
inline_list indent::true [string "line one;", string "line two;"],
string "} else if (a) {",
inline_list indent::true [string "line one;", string "line two;"]),
string "}"
]
I haven't tried it but in theory it could work :/
The only problem with the last suggestion (I think) is that you indent even if the if/else
doesn't break. But then again, if we force if/else
to break as we often do, maybe that will work well!
I guess it depends on how bad you want to allow people to configure the formatter to output:
let x = if (something) {thenThis} else {thenThat};
Since in ES6, ifs aren't expressions, it's probably much less important to support the non-breaking if/else scenario.
The only problem with the last suggestion (I think) is that you indent even if the if/else doesn't break.
Not sure if this would work but may be able to use Format.pp_print_if_newline
to inject the indentation if the list breaks. Im looking into doing this for trailing commas, i'll let you know how it goes :P
let x = if (something) {thenThis} else {thenThat};
Potentially should work if you output like this (apart from the inner indentation):
[
"let x = if (something) {",
"thenThis",
"} else {",
"thenThat",
"};",
]
Yes, that sounds wonderful. We were discussing the same proposal for trailing commas. It would perhaps make a nice PR to Easy_format
as a new primitive. breakAwareAtom "ifNoNewline" "ifNewline"
.
It would also be cool if we could have something even more advanced than switching between two atoms (two complete Easy_format
trees) but I don't yet see a user for it and I don't know if it's possible.