Skip to content

Preserve grouping of do statements#536

Closed
utdemir wants to merge 1 commit intomasterfrom
preserve-newlines-in-do-blocks
Closed

Preserve grouping of do statements#536
utdemir wants to merge 1 commit intomasterfrom
preserve-newlines-in-do-blocks

Conversation

@utdemir
Copy link
Copy Markdown
Contributor

@utdemir utdemir commented Apr 9, 2020

Related: #74

Work in progress.

This PR puts a newline between do statements if they were more than one line apart.

I found that there's one unintuitive case:

main = do
  foo
  -- some comment
  bar

Becomes:

main = do
  foo

  -- some comment
  bar

This is not ideal, so I'm planning to change it so that it inserts the newline only if there is at least one empty line between the statements. However this requires accessing comment spans which is a bit harder. I have to spend some more time on it.

@utdemir utdemir added the wip Work in progress. Remove the label when your PR is ready for review. label Apr 9, 2020
@cdsmith
Copy link
Copy Markdown

cdsmith commented Apr 9, 2020

I'm not sure that comment behavior is so bad, as long as the newline is added before the comment. I cannot recall seeing a reasonable coding style that has comments lines on the next line after a statement, without a blank line separating them. A comment with a block of code right and no newline should apply to that block of code, and that means it's the first thing in the block, so it should be separated by a newline from any previous block.

@utdemir utdemir force-pushed the preserve-newlines-in-do-blocks branch from 368fcfe to 191f4e2 Compare April 9, 2020 05:05
@utdemir
Copy link
Copy Markdown
Contributor Author

utdemir commented Apr 9, 2020

That makes sense @cdsmith . I also don't think a comment squashed between two lines of code is common.

What do you think @mrkkrp? If you like the current behavior, you can merge the PR as-is, or let me know and and I'll modify the PR.

@mboes
Copy link
Copy Markdown
Contributor

mboes commented Apr 9, 2020

FWIW there is some precedent here. The Starlark formatter does exactly the same thing: it always puts a newline before a comment, even when it wasn't there before. It takes some getting used to at first.

splitGroups xs =
concatMap
( \(prev, curr) ->
let prevEnd = fmap srcSpanEndLine . unSrcSpan . getLoc =<< prev
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better if you used a custom one-off data type isomorphic to Maybe here.

@mrkkrp
Copy link
Copy Markdown
Member

mrkkrp commented Apr 9, 2020

I think we should follow spacing decisions made by the original author of the source code. That means that we should only insert newlines before comments when there were one or more blank lines in the input. How to do it? That's a good question.

To be able to tell whether a line is blank or not, we'd need access to the original input or to the comment stream. Introducing something to keep original input just for this purpose seems overkill given that we managed to go so far without it. With comment stream it is also tricky because it is an ordered list which is "consumed" as we go and you seem to do the analysis before the statements are printed.

I'd try to go in a different direction with respect to the implementation. We've solved almost exactly the same problem but with narrower scope: we know how to insert blank lines between comments. This is done by using low-level stateful setLastCommentSpan and getLastCommentSpan functions. See how we use them in Ormolu.Printer.Comments. The idea is that whenever we print a comment we register its span and then we check this info to decide if we should add a newline before next comment. When something other than a comment is printed this info is reset automatically.

I think we could do something similar just for statements in a do-block. Maybe exactly the same part of state of the R monad can be extended to remember not just comments but also position of last printed lexeme? Then implementing insertion of blank lines is a matter of adding a couple of conditionals.

At any rate, this is not the simplest issue.

@utdemir
Copy link
Copy Markdown
Contributor Author

utdemir commented Apr 11, 2020

With comment stream it is also tricky because it is an ordered list which is "consumed" as we go and you seem to do the analysis before the statements are printed.

I feel like traversing the comment stream before printing the do statement might be an easy solution here, don't you think? It has the advantage of not adding a stateful internal state. I'll try if it works.

@utdemir
Copy link
Copy Markdown
Contributor Author

utdemir commented Apr 12, 2020

Thinking about it, I think just preserving a list of empty lines from the source code is a better approach.

It conceptually makes sense. Since by definition of this issue we're adding a meaning to the empty lines, and it makes sense to just store that information instead of trying to infer it indirectly by looking at the source locations of expressions and comments.

@utdemir utdemir force-pushed the preserve-newlines-in-do-blocks branch from 191f4e2 to e2cf34e Compare April 12, 2020 07:39
-- c4
f3

-- c5
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an issue in the comment placement logic where we never associate a comment with the previous line. Happens regardless of do notation, in cases like:

foo = foo
-- some comment

bar = bar

@utdemir
Copy link
Copy Markdown
Contributor Author

utdemir commented Apr 12, 2020

@mrkkrp I tried another approach (traversing the comment stream to figure out if there are comments), now it formats the comments as you suggested. What do you think?

@utdemir utdemir force-pushed the preserve-newlines-in-do-blocks branch from e2cf34e to 86dd4da Compare April 12, 2020 22:11
@mrkkrp mrkkrp force-pushed the preserve-newlines-in-do-blocks branch from 86dd4da to 3b8e32d Compare April 15, 2020 15:10
@mrkkrp
Copy link
Copy Markdown
Member

mrkkrp commented Apr 15, 2020

Indeed, this appears to work. Still, the solution feels a bit hacky and not entirely straightforward. I'd like to try to implement it using the approach I described earlier and compare the results.

@mrkkrp mrkkrp closed this in #551 Apr 16, 2020
@mrkkrp mrkkrp deleted the preserve-newlines-in-do-blocks branch April 26, 2020 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wip Work in progress. Remove the label when your PR is ready for review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants