on master help sign in
Do not hang record constructors

Previously we hanged record constructors but not record updates. It looks like unlike other hanging constructions (lambdas, case expressions, and do-blocks), record constructors and updates should rather be placed normally. Indeed, when we stop hanging them, many constructions start to look more reasonable and predictable (see the updated test cases). Yet the change is not enough to fix the problem in general case: it is enough to replace the record with a e.g. do-block to get the same failure. To correct that we adjust what should fit in one line for hanging placement to fire: now we consider the span between beginning of function and the start of potentially-hanging construction.

commit1eefa97cc23b92b50d2a27c04cdb552b6833cd91 authorMark Karpov <mark.karpov@tweag.io> dateThu 9 Jan 2020, 19:26 (7 years ago) parentf7dc5bb
13 files changed+123−72
CHANGELOG.md+4 data/examples/declaration/value/function/overindentation-out.hs+11−9 data/examples/declaration/value/function/record-constructors-out.hs+17−13 data/examples/declaration/value/function/record-inter-comments-out.hs+13 data/examples/declaration/value/function/record-inter-comments.hs+11 data/examples/declaration/value/function/record-wildcards-out.hs+7−6 data/examples/other/comment-before-hanging-out.hs+5 data/examples/other/comment-before-hanging.hs+5 src/GHC/DynFlags.hs+9−8 src/Ormolu/Config.hs+8−7 src/Ormolu/Parser.hs+9−8 src/Ormolu/Printer/Internal.hs+20−18 src/Ormolu/Printer/Meat/Declaration/Value.hs+4−3
CHANGELOG.md+4
@@ -11,6 +11,10 @@
1111* Added support for record dot pre-processor when used via the plugin.
1212 [Issue 486](https://github.com/tweag/ormolu/issues/486).
1313
14+* Stopped hanging record constructors and improved placing
15+ potentially-hanging consturctions in the presence of comments. [Issue
16+ 447](https://github.com/tweag/ormolu/issues/447).
17+
1418## Ormolu 0.0.2.0
1519
1620* Switched to `ghc-lib-parser` instead of depending on the `ghc` package
data/examples/declaration/value/function/overindentation-out.hs+11−9
@@ -1,9 +1,11 @@
1−reallyincrediblyLongName = f
2− a
3− A
4− { reallyincrediblyLongName = f
5− a
6− A
7− { reallyincrediblyLongName
8− }
9− }
1+reallyincrediblyLongName =
2+ f
3+ a
4+ A
5+ { reallyincrediblyLongName =
6+ f
7+ a
8+ A
9+ { reallyincrediblyLongName
10+ }
11+ }
data/examples/declaration/value/function/record-constructors-out.hs+17−13
@@ -1,9 +1,10 @@
11foo = Foo {a = 3}
22
3−bar = Bar
4− { abc = foo,
5− def = Foo {a = 10}
6− }
3+bar =
4+ Bar
5+ { abc = foo,
6+ def = Foo {a = 10}
7+ }
78
89baz = Baz {}
910
@@ -12,15 +13,18 @@ sym = Foo {(+) = 3}
1213aLongVariableName =
1314 ALongRecordName
1415 { short = baz,
15− aLongRecordFieldName = YetAnotherLongRecordName
16− { yetAnotherLongRecordFieldName = "a long string"
17− },
18− aLongRecordFieldName2 = Just YetAnotherLongRecordName
19− { yetAnotherLongRecordFieldName = "a long string",
20− yetAnotherLongRecordFieldName =
21− Just
22− "a long string"
23− },
16+ aLongRecordFieldName =
17+ YetAnotherLongRecordName
18+ { yetAnotherLongRecordFieldName = "a long string"
19+ },
20+ aLongRecordFieldName2 =
21+ Just
22+ YetAnotherLongRecordName
23+ { yetAnotherLongRecordFieldName = "a long string",
24+ yetAnotherLongRecordFieldName =
25+ Just
26+ "a long string"
27+ },
2428 aLongRecordFieldName3 = do
2529 foo
2630 bar
data/examples/declaration/value/function/record-inter-comments-out.hsnew file+13
@@ -0,0 +1,13 @@
1+x =
2+ Just
3+ -- comment
4+ A
5+ { x
6+ }
7+
8+x =
9+ Just
10+ -- comment
11+ a
12+ { x
13+ }
data/examples/declaration/value/function/record-inter-comments.hsnew file+11
@@ -0,0 +1,11 @@
1+x = Just
2+ -- comment
3+ A
4+ { x
5+ }
6+
7+x = Just
8+ -- comment
9+ a
10+ { x
11+ }
data/examples/declaration/value/function/record-wildcards-out.hs+7−6
@@ -3,11 +3,12 @@
33
44foo x y = Foo {x, y}
55
6−bar x y z = Bar
7− { x,
8− y,
9− z,
10− ..
11− }
6+bar x y z =
7+ Bar
8+ { x,
9+ y,
10+ z,
11+ ..
12+ }
1213
1314baz = Baz {..}
data/examples/other/comment-before-hanging-out.hsnew file+5
@@ -0,0 +1,5 @@
1+x = Just
2+ -- comment
3+ do
4+ foo
5+ bar
data/examples/other/comment-before-hanging.hsnew file+5
@@ -0,0 +1,5 @@
1+x = Just
2+ -- comment
3+ do
4+ foo
5+ bar
src/GHC/DynFlags.hs+9−8
@@ -12,14 +12,15 @@ import Platform
1212
1313-- | Taken from HLint.
1414fakeSettings :: Settings
15−fakeSettings = Settings
16− { sTargetPlatform = platform,
17− sPlatformConstants = platformConstants,
18− sProjectVersion = cProjectVersion,
19− sProgramName = "ghc",
20− sOpt_P_fingerprint = fingerprint0,
21− sPgm_F = ""
22− }
15+fakeSettings =
16+ Settings
17+ { sTargetPlatform = platform,
18+ sPlatformConstants = platformConstants,
19+ sProjectVersion = cProjectVersion,
20+ sProgramName = "ghc",
21+ sOpt_P_fingerprint = fingerprint0,
22+ sPgm_F = ""
23+ }
2324 where
2425 platform =
2526 Platform
src/Ormolu/Config.hs+8−7
@@ -29,13 +29,14 @@ data Config
2929
3030-- | Default 'Config'.
3131defaultConfig :: Config
32−defaultConfig = Config
33− { cfgDynOptions = [],
34− cfgUnsafe = False,
35− cfgDebug = False,
36− cfgTolerateCpp = False,
37− cfgCheckIdempotency = False
38− }
32+defaultConfig =
33+ Config
34+ { cfgDynOptions = [],
35+ cfgUnsafe = False,
36+ cfgDebug = False,
37+ cfgTolerateCpp = False,
38+ cfgCheckIdempotency = False
39+ }
3940
4041-- | A wrapper for dynamic options.
4142newtype DynOption
src/Ormolu/Parser.hs+9−8
@@ -78,14 +78,15 @@ parseModule Config {..} path input' = liftIO $ do
7878 Left (ss, GHC.showSDoc dynFlags m)
7979 GHC.POk pstate pmod ->
8080 let (comments, exts, shebangs) = mkCommentStream extraComments pstate
81− in Right ParseResult
82− { prParsedSource = pmod,
83− prAnns = mkAnns pstate,
84− prCommentStream = comments,
85− prExtensions = exts,
86− prShebangs = shebangs,
87− prUseRecordDot = useRecordDot
88− }
81+ in Right
82+ ParseResult
83+ { prParsedSource = pmod,
84+ prAnns = mkAnns pstate,
85+ prCommentStream = comments,
86+ prExtensions = exts,
87+ prShebangs = shebangs,
88+ prUseRecordDot = useRecordDot
89+ }
8990 return (warnings, r)
9091
9192-- | Extensions that are not enabled automatically and should be activated
src/Ormolu/Printer/Internal.hs+20−18
@@ -160,24 +160,26 @@ runR ::
160160runR (R m) sstream cstream anns recDot =
161161 TL.toStrict . toLazyText . scBuilder $ execState (runReaderT m rc) sc
162162 where
163− rc = RC
164− { rcIndent = 0,
165− rcLayout = MultiLine,
166− rcEnclosingSpans = [],
167− rcAnns = anns,
168− rcCanUseBraces = False,
169− rcUseRecDot = recDot
170− }
171− sc = SC
172− { scColumn = 0,
173− scBuilder = mempty,
174− scSpanStream = sstream,
175− scCommentStream = cstream,
176− scPendingComments = [],
177− scDirtyLine = False,
178− scRequestedDelimiter = VeryBeginning,
179− scLastCommentSpan = Nothing
180− }
163+ rc =
164+ RC
165+ { rcIndent = 0,
166+ rcLayout = MultiLine,
167+ rcEnclosingSpans = [],
168+ rcAnns = anns,
169+ rcCanUseBraces = False,
170+ rcUseRecDot = recDot
171+ }
172+ sc =
173+ SC
174+ { scColumn = 0,
175+ scBuilder = mempty,
176+ scSpanStream = sstream,
177+ scCommentStream = cstream,
178+ scPendingComments = [],
179+ scDirtyLine = False,
180+ scRequestedDelimiter = VeryBeginning,
181+ scLastCommentSpan = Nothing
182+ }
181183
182184----------------------------------------------------------------------------
183185-- Internal functions
src/Ormolu/Printer/Meat/Declaration/Value.hs+4−3
@@ -542,8 +542,10 @@ p_hsExpr' s = \case
542542 -- We need to handle the last argument specially if it is a
543543 -- hanging construct, so separate it from the rest.
544544 (initp, lastp) = (NE.init args, NE.last args)
545− initSpan = combineSrcSpans' $ getLoc f :| map getLoc initp
546− -- Hang the last argument only if the initial arguments spans one
545+ initSpan =
546+ combineSrcSpans' $
547+ getLoc f :| [(srcLocSpan . srcSpanStart . getLoc) lastp]
548+ -- Hang the last argument only if the initial arguments span one
547549 -- line.
548550 placement =
549551 if isOneLineSpan initSpan
@@ -1211,7 +1213,6 @@ exprPlacement = \case
12111213 HsCase NoExt _ _ -> Hanging
12121214 HsDo NoExt DoExpr _ -> Hanging
12131215 HsDo NoExt MDoExpr _ -> Hanging
1214− RecordCon NoExt _ _ -> Hanging
12151216 -- If the rightmost expression in an operator chain is hanging, make the
12161217 -- whole block hanging; so that we can use the common @f = foo $ do@
12171218 -- style.