Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classic if/then/else formatting. #12

Open
jordwalke opened this issue May 3, 2016 · 9 comments
Open

Classic if/then/else formatting. #12

jordwalke opened this issue May 3, 2016 · 9 comments

Comments

@jordwalke
Copy link
Collaborator

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)
}
@mjambon
Copy link
Member

mjambon commented May 3, 2016

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.

@pieterv
Copy link

pieterv commented Dec 28, 2016

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 :/

@jordwalke
Copy link
Collaborator Author

Can you show the case where "half the breaks still happen one level down"?

@pieterv
Copy link

pieterv commented Dec 28, 2016

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 :/

@jordwalke
Copy link
Collaborator Author

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!

@jordwalke
Copy link
Collaborator Author

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.

@pieterv
Copy link

pieterv commented Dec 28, 2016

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

@pieterv
Copy link

pieterv commented Dec 29, 2016

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",
  "};",
]

@jordwalke
Copy link
Collaborator Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants