Automatic line breaking at specific limit#102
Automatic line breaking at specific limit#102gustavoavena wants to merge 8 commits intofourmolu:mainfrom
Conversation
src/Ormolu/Config.hs
Outdated
| poNewlinesBetweenDecls :: f Int | ||
| poNewlinesBetweenDecls :: f Int, | ||
| -- | Max line length for automatic line breaking | ||
| poMaxLineLength :: f (Maybe Int) |
There was a problem hiding this comment.
I would create a new datatype for clarity:
data ColumnLimit = ColumnLimit Natural | NoLimit
There was a problem hiding this comment.
Good idea. Just did that and pushed the changes. Yaml config file is still not working though, so I'll look into that.
f745856 to
1e85b2e
Compare
|
Friendly ping for @georgefst. Would you mind doing an initial review when you have some time? 🙂 |
1e85b2e to
e7d7596
Compare
|
Fixed the YAML config file parsing for my new option. AFAIK, the only remaining work (besides comments from review) is to add another test case in a 3rd commit. |
|
When writing some test cases I ended up finding a bug in the implementation. Apparently, it can't properly break function arguments when they're over 80 characters long. Here are some examples of what works and what doesn't work (i.e. I get an error because the AST changed after formatting). -- ------------------------ These work ------------------------
-- ---------------------------------------------------------------80 characters|
longFunction0 :: String -> String -> String -> Maybe Int -> Maybe Int -> Maybe Int -> String -> [String]
longFunction0 veryLongArg1 a b c d e f = ["a list", "of strings", "that will break the", "column limit"]
longFunction1 :: String -> String -> String -> Maybe Int -> Maybe Int -> Maybe Int -> String
longFunction1
veryLongArg1 veryLongArg2 veryLongArg3 veryLongArg4 veryLongArgument5 veryLongArg6 = undefined
longFunction12 veryLongArg1 veryLongArg2 veryLongArg3 veryLongArg4 veryLongArgument5
longFunction12 :: String -> String -> String -> Maybe Int -> Maybe Int -> Maybe Int -> String -> String
veryLongArg6 veryLongArg6 = undefined
-- If the arguments stop right at 80 characters, it works.
longFunction2 :: String -> String -> String -> Maybe Int -> Maybe Int -> Maybe Int -> String
longFunction2 veryLongArg1 veryLongArg2 veryLongArg3 veryLongArg4 a veryLongArg6 =
let aVeryLongLine = ["list one", "list one", "list one", "list one", "list one", "list one"]
in undefined
-- ------------------------ Below here doesn't work ------------------------
longFunction3 :: String -> String -> String -> Maybe Int -> Maybe Int -> Maybe Int -> String
longFunction3 veryLongArg1 veryLongArg2 veryLongArg3 veryLongArg4 veryLongArgument5 veryLongArg6 = undefinedI formatted this using the longFunction3 ::
String -> String -> String -> Maybe Int -> Maybe Int -> Maybe Int -> String
longFunction3
veryLongArg1
veryLongArg2
veryLongArg3
veryLongArg4
veryLongArgument5
veryLongArg6 = undefinedI think that if the user doesn't break the arguments themselves, fourmolu can't distinguish the function name from the arguments... My only idea to make this work would be to disable this check for this specific case (function arguments). That would probably involve adding an argument to @expipiplus @parsonsmatt Could you maybe help me with that? Any code pointers that I could go over to disable the column limit in the |
|
I was actually able to find the place that I think |
ebab3cb to
66414db
Compare
|
I actually found a bug in this implementation that breaks idempotence in some cases... Since idempotence is an important property for a formatter, I don't want to ship this without a fix... @georgefst, in one of your comments in #6 you said that "idempotence is a rather fragile thing". Were there any other features/improvements in the past that broke idempotence? If so, how were they fixed? I would appreciate anything that could help me debug and fix this issue. Thanks! Original code: testFund :: Maybe Int
testFund =
firstTest oneFunctionArgument abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde $ do
result <- aRandomResultAfter formatting with column limit set to 80: testFund :: Maybe Int
testFund =
firstTest
oneFunctionArgument
abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde $ do
result <- aRandomResultAfter formatting the output again: testFund :: Maybe Int
testFund =
firstTest
oneFunctionArgument
abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde
$ do
result <- aRandomResultOf course, formatting this snippet with the |
|
I tested fourmolu with this option in thousands of files and found out that this isn't a big idempotence issue because it has a stopping point. i.e. the formatter won't undo something it did and get into a vicious cycle of doing/undoing (e.g. adding/removing a line break). Also, this feature doesn't introduce any major issue that breaks the files (e.g. by changing their AST). Considering what I've listed above and the fact that idempotence seems to be a very fragile property (IIRC, initial versions of Ormolu were not idempotent and it was still released and used with this known limitation), I was wondering if we could consider releasing this feature as long as it's clear that it has the limitation of affecting idempotence. @kukimik, @brandonchinn178, I've seen you engage in other issues/PRs so I'm wondering if you have any thoughts about this? Any feedback would be very welcome! 🙂 |
|
I'm alright with the idempotence issue seeing as:
|
|
Are you saying its not idempotent? As in, running fourmolu multiple times could iteratively format line breaks? Can you give an example? In general, though, I'm generally in favor of this. Specifically with regards to breaking import statements. |
|
Thank you @georgefst @brandonchinn178 for your responses and feedback! @georgefst, I'm happy to hear that! I just pushed one more commit where I add an example in the test files, update the test runner and add a line to the README making the @brandonchinn178 yes, in some cases the formatter will not be idempotent. I just added an example here. In practice though, it doesn't look like the file will change when formatted for a 3rd time and the changes between the first and second formatting are very minor (e.g. indentation of statements nested inside a |
|
@georgefst LMK if there's anything else I need to add/change to merge this! |
|
Is this ready to merge @brandonchinn178 @georgefst ? |
5f6ab52 to
999b658
Compare
|
Hey @georgefst! I noticed that there has been some significant changes committed in the past week, which is great! I already rebased this PR and tested everything, so I'm wondering if we could get this merged? |
999b658 to
b000385
Compare
|
Hi. What is needed for getting this merged? I want it :) |
c7364ed to
40bcc74
Compare
|
👋 @gustavoavena If you haven't noticed, we finally merged in a new testing framework for configuration options (#169)! This means we can finally address the backlog of open PRs. Please do the following steps
You can use #135 as a reference for this checklist. |
|
@brandonchinn178 Thank you for the update and for all the you've been putting in recently. Unfortunately I haven't had the bandwidth to get back to this, but once I have some more time, I'll work on rebasing and writing test to ship this :) |
|
Gentle ping - will work on getting this PR merged resume? |
|
@arybczak no ones currently working on this PR. feel free to branch off and start a new PR |
|
I took up on the offer and branched off on this work in the attempt to revive the feature in #305. Thank you for your work, @gustavoavena! |
|
This work has been merged via #305! |
Discussed in #71. @georgefst this is the "hack" you suggested, so I would love to get your feedback if you have some time!
What
Provide an option to break lines automatically when they're over N characters long, where N is an optional integer provided in the config.
How
Fourmolu already has logic for how to break lines, since it does so when the user breaks some lines themselves. This PR adds a small hack in
src/Ormolu/Printer/Combinators.hsto use the MultiLine Layout for a span if it's over N characters long.Testing
Will add a file with some test cases in the next commit, but before putting up this PR I ran
cabal testand./format.sh, as instructed in theContributingsection. The./format.shscript made some changes to thefourmolu.cabalfile.