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

Implement "intelligent" breaking for records & objects. #1697

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

IwanKaramazow
Copy link
Contributor

Fixes #1620 #1207
The idea is that a line break in input should signify an intent to format a record/object with line breaks. Refmt "relaxes" its hard coded rules in favour of checking the input for possible breaks. Since the start & begin location are part of the ast, we simply have to check if the line height of start & end loc are the same. If they are, then everything was on one line.

This has the benefit that type point = {x: int, y: int}, can be printed one line if desired.

On the other hand:

type point = {
    x: int, y: int};

type point = {x: int,
  y: int};

type point = {x: int, y: int
};

Since the structures above have been put on multiple lines,
everything will be formatted as:

type point = {
  x: int,
  y: int
};

This behaviour is the same as in Prettier.

@IwanKaramazow
Copy link
Contributor Author

@andreypopp @jordwalke circleci seems to have problems with esy, any hints on what might be wrong?

@andreypopp
Copy link
Contributor

@IwanKaramazow esy.lock should be removed an re-generated using recent esy version. We had an update to Esy metadata format but esy.lock isn't being versioned currently (fix pending).

@chenglou
Copy link
Member

Nice! Does this logic help e.g. not removing braces for functions?

@jordwalke
Copy link
Member

If you rebase, and update the diff the tests should pass now (I updated master branch of Reason).

The idea is that a line break in input should signify an intent to format a record/object with line breaks.  Refmt "relaxes" its hard coded rules in favour of checking the input for possible breaks. Since the start & begin location are part of the ast, we simply have to check if the line height of start & end loc are the same. If they are, then everything was on one line.

This has the benefit that `type point = {x: int, y: int}`, can be
printed one line.

type t = {
    a: int, b: int};

type t = {a: int,
  b: int};

type t = {a: int, b: int
};

=> Since the structures above have been put on multiple lines,
everything will be formatted as:

type t = {
  a: int,
  b: int
};
@IwanKaramazow
Copy link
Contributor Author

Rebased, thanks for the pr.
@chenglou will send a separate PR for function braces, the idea of this pr could be easily extended to print function braces when the body of function has been put on the next line.

@IwanKaramazow
Copy link
Contributor Author

@jordwalke if we follow the same idea of this PR, then we probably don't need the regex hack for function braces. It's just a matter of printing a letList with braces, I think.

If the programmer put the fun body on a separate line, he wants braces:

/* a + b sits on line 2*/
let f = (a, b) =>
  a + b;

/* becomes */
let f = (a, b) => {
  a + b;
};

vs

/* same line */
let f = (a,b) => a + b;

/* becomes */
let f = (a,b) => a + b;

@rauschma
Copy link

@IwanKaramazow switch would be the one exception where you don’t want braces even if the expression starts in a new line (right?).

@IwanKaramazow
Copy link
Contributor Author

@rauschma Yes this woudn't apply to switch, I was referring to function expressions as

let f = (a, b) => {
  a + b;
};

@rauschma
Copy link

@IwanKaramazow I meant that the following function expression should stay as is (no braces should be wrapped around the switch). I was wondering whether you accounted for this case.

let f = (a) =>
  switch a {
  | Foo => 1
  | Bar => 2
  };

@IwanKaramazow
Copy link
Contributor Author

Ah yes, good catch 😄 I'll address the function expr in a different PR.

@jordwalke
Copy link
Member

One question I have:

Suppose someone has a record like this:

type point = {
  x: int,
  y: int,
  reallyLongNameHere: int
};

And then someone refactors to delete the long final item:

type point = {
  x: int,
  y: int
};

What if I want these to be automatically reprinted on one line? In this case, the presence of newlines doesn't convey my intent. How can we distinguish between additional newlines that we want the printer to clean up, and ones that we don't?

@IwanKaramazow
Copy link
Contributor Author

When was the last time you removed a row from a record?

@hcarty
Copy link
Contributor

hcarty commented Dec 28, 2017

@IwanKaramazow About a week ago! While refactoring some code to work with a new version of an external API.

@jordwalke
Copy link
Member

Perhaps it's not always removing a row, but more commonly changing the name of one or more fields to be significantly shorter (so my whole code base becomes more concise). A change like that can bring the text size under the breaking threshold.
Perhaps that downside is still worth the benefits but I'm just curious if you've considered how to distinguish between intentional breaks and breaks the programmer wants refmt to automatically clean up. For example, I want to be able to run refmt and have refmt remove all the breaks that are no longer needed. Is it possible to have both? Or would this be a per-project setting?

@rauschma
Copy link

I get the feeling that a more systematic process may make sense for refmt. Maybe collect code examples that reflect the preferred style and then extract rules? I have collected a few examples myself where refmt seemed off.

@janicduplessis
Copy link

janicduplessis commented Feb 2, 2018

I prefer this behaviour over the current one, I find it a lot clearer to be able to control if each items are on a separate line, especially when working with something like RN StyleSheets or CSS in JS libs. Of course it won't format back to one line automatically when removing fields or renaming like it was mentioned before but I still think it's a good tradeoff. It's also easy to reformat it back to a single line when refactoring if you really want to.

This is also the same behaviour as pretty which is somewhat popular / proven.

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

Successfully merging this pull request may close these issues.

None yet

8 participants