-
Notifications
You must be signed in to change notification settings - Fork 429
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
Intelligent whitespace interleaving (WIP) #1876
Intelligent whitespace interleaving (WIP) #1876
Conversation
This is awesome! Are you considering doing the break-if-over-multiple-lines thing you mentioned here in the future as well? I remember thinking that was a great idea. |
e919681
to
72b1a83
Compare
@Schmavery Hey, sorry for the late response. Managed to implement the "intelligent" whitespace interleaving inside modules, i.e. more than one newline between "items" will collapse into one newline that will be preserved. Since whitespace is a tool for us programmers to organise our code, I don't think we should let an algorithm/heuristic interfere with our human newlines atm. That might change in the future, but I think it's the best way forward atm. I like to error on the side of not producing ugly formatted code at this stage 😄 |
8f2456f
to
24d5f2d
Compare
Introduces an extra layout primitive Whitespace, that can be used to interleave blank lines.
24d5f2d
to
70c2a28
Compare
70c2a28
to
be2050a
Compare
99fdd2b
to
6e6a207
Compare
8489b46
to
31340f1
Compare
@chenglou @jordwalke ready for review |
Tada! |
Intelligent Whitespace interleaving
What does this mean?
Whitespace inserted by the user will be tracked and preserved by refmt in certain places.
Amount of newlines interleaved (or lack thereof) is now deducted from whitespace
interleaved in the source instead of hard coded defaults in the printer.
More than one newline will be collapsed into one newline.
Example:
Where is whitespace inserted by the user preserved?
.re
file & insidemodule X = { ... }
).rei
file & insidemodule type Y = { ... }
)How does it work?
Preserving whitespace can be split into two parts:
Computation of whitespace
The Ocaml-AST doesn't contain whitespace. This isn't a problem, since whitespace
between two items can easily be computed based on the location diff between two items.
Imagine the following source code:
We can easily determine if there's whitespace between
let a
andlet b
,by substracting the linenumber of the start of
let b
by the linenumber of the endof
let a
. If the diff is equal to or greater than 1, we know that there's whitespace.In practise the computation is a little bit more complex because of comments.
Here the location diff indicates whitespace, but the comment fills up the space between
the two items. The correct diff is:
Formatting computed whitespace (without disrupting comment insertion)
Once we know we need to interleave whitespace between two items, we can't just
print an
atom "\n"
node. This would clash with the comment interleavingalgorithm. Without inspecting every atom for possible
\n
text, we would getthe following scenario
To circumvent this problem, whitespace needs to be interleaved after all
comments have been inserted into the layout.
In order to postpone the insertion of whitespace to the last moment,
the following layout made its way into existence:
Whitespace
is a specific type of layout. It conveys an"intent to interleave whitespace". It decorates a layout with information
for whitespace insertion above that node.
WhitespaceRegion.t
contains specific infoabout the region where whitespace should be interleaved.
The info is used for correct comment interleaving inside of the region
designated for whitespace.
Perfomance implications
To compute if a range in the source code contains whitespace,
we need the comments for that range. Every time the whitespace computation
happens, we need to traverse all comments to find the comments that overlap.
The traversal of comments can be improved by storing the comments inside a
interval-(Red/Black or AVL)tree for cheaper lookup.
As a benchmark reference: there's a slowdown of around 50ms with this diff,
on a 10000 line file. Reason_pprint_ast.ml (formatted in Reason) was taken
as reference point on a MacBook Pro 2015 i5.
The comment interleaving algorithm in general is very slow, for every comment
we create a create/travers the/a whole new tree.
There is definitely room for improvement here. The performance will be adressed
in a separate PR.