fourmolu 0.8.2.0 → 0.9.0.0
raw patch · 67 files changed
+3307/−322 lines, 67 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Ormolu.Printer.Combinators: inciByExact :: Int -> R () -> R ()
- Ormolu.Printer.Combinators: leadingArrowType :: R ()
- Ormolu.Printer.Combinators: trailingArrowType :: R ()
- Ormolu.Printer.Internal: TypeCtxArgument :: PrevTypeCtx
- Ormolu.Printer.Internal: TypeCtxContext :: PrevTypeCtx
- Ormolu.Printer.Internal: TypeCtxForall :: PrevTypeCtx
- Ormolu.Printer.Internal: TypeCtxStart :: PrevTypeCtx
- Ormolu.Printer.Internal: data PrevTypeCtx
- Ormolu.Printer.Internal: getPrevTypeCtx :: R PrevTypeCtx
- Ormolu.Printer.Internal: inciByExact :: Int -> R () -> R ()
- Ormolu.Printer.Internal: instance GHC.Classes.Eq Ormolu.Printer.Internal.PrevTypeCtx
- Ormolu.Printer.Internal: instance GHC.Show.Show Ormolu.Printer.Internal.PrevTypeCtx
- Ormolu.Printer.Internal: setPrevTypeCtx :: PrevTypeCtx -> R ()
- Ormolu.Printer.Meat.ImportExport: breakIfNotDiffFriendly :: R ()
+ Ormolu: [poInStyle] :: PrinterOpts f -> f InStyle
+ Ormolu: [poLetStyle] :: PrinterOpts f -> f LetStyle
+ Ormolu: [poUnicode] :: PrinterOpts f -> f Unicode
+ Ormolu.Config: InLeftAlign :: InStyle
+ Ormolu.Config: InRightAlign :: InStyle
+ Ormolu.Config: LetAuto :: LetStyle
+ Ormolu.Config: LetInline :: LetStyle
+ Ormolu.Config: LetMixed :: LetStyle
+ Ormolu.Config: LetNewline :: LetStyle
+ Ormolu.Config: [poInStyle] :: PrinterOpts f -> f InStyle
+ Ormolu.Config: [poLetStyle] :: PrinterOpts f -> f LetStyle
+ Ormolu.Config: [poUnicode] :: PrinterOpts f -> f Unicode
+ Ormolu.Config: data InStyle
+ Ormolu.Config: data LetStyle
+ Ormolu.Config: instance Ormolu.Config.PrinterOptsFieldType Ormolu.Config.Types.InStyle
+ Ormolu.Config: instance Ormolu.Config.PrinterOptsFieldType Ormolu.Config.Types.LetStyle
+ Ormolu.Config: instance Ormolu.Config.PrinterOptsFieldType Ormolu.Config.Types.Unicode
+ Ormolu.Exception: printOrmoluException :: OrmoluException -> Term ()
+ Ormolu.Printer: [poInStyle] :: PrinterOpts f -> f InStyle
+ Ormolu.Printer: [poLetStyle] :: PrinterOpts f -> f LetStyle
+ Ormolu.Printer: [poUnicode] :: PrinterOpts f -> f Unicode
+ Ormolu.Printer.Combinators: closeQuote :: R ()
+ Ormolu.Printer.Combinators: cparenbar :: R ()
+ Ormolu.Printer.Combinators: darrow :: R ()
+ Ormolu.Printer.Combinators: dcolon :: R ()
+ Ormolu.Printer.Combinators: forall :: R ()
+ Ormolu.Printer.Combinators: larrow :: R ()
+ Ormolu.Printer.Combinators: larrowtail :: R ()
+ Ormolu.Printer.Combinators: llarrowtail :: R ()
+ Ormolu.Printer.Combinators: lolly :: R ()
+ Ormolu.Printer.Combinators: oparenbar :: R ()
+ Ormolu.Printer.Combinators: openExpQuote :: R ()
+ Ormolu.Printer.Combinators: rarrow :: R ()
+ Ormolu.Printer.Combinators: rarrowtail :: R ()
+ Ormolu.Printer.Combinators: rrarrowtail :: R ()
+ Ormolu.Printer.Combinators: star :: R ()
+ Ormolu.Printer.Combinators: whenUnicodeOtherwise :: Text -> Text -> R ()
+ Ormolu.Printer.Meat.Type: startTypeAnnotation :: HasSrcSpan l => GenLocated l a -> (a -> R ()) -> R ()
+ Ormolu.Printer.Meat.Type: startTypeAnnotationDecl :: HasSrcSpan l => GenLocated l a -> (a -> HsType GhcPs) -> (a -> R ()) -> R ()
- Ormolu: PrinterOpts :: f Int -> f FunctionArrowsStyle -> f CommaStyle -> f ImportExportStyle -> f Bool -> f Bool -> f Int -> f HaddockPrintStyle -> f Bool -> PrinterOpts f
+ Ormolu: PrinterOpts :: f Int -> f FunctionArrowsStyle -> f CommaStyle -> f ImportExportStyle -> f Bool -> f Bool -> f Int -> f HaddockPrintStyle -> f LetStyle -> f InStyle -> f Unicode -> f Bool -> PrinterOpts f
- Ormolu.Config: PrinterOpts :: f Int -> f FunctionArrowsStyle -> f CommaStyle -> f ImportExportStyle -> f Bool -> f Bool -> f Int -> f HaddockPrintStyle -> f Bool -> PrinterOpts f
+ Ormolu.Config: PrinterOpts :: f Int -> f FunctionArrowsStyle -> f CommaStyle -> f ImportExportStyle -> f Bool -> f Bool -> f Int -> f HaddockPrintStyle -> f LetStyle -> f InStyle -> f Unicode -> f Bool -> PrinterOpts f
- Ormolu.Printer: PrinterOpts :: f Int -> f FunctionArrowsStyle -> f CommaStyle -> f ImportExportStyle -> f Bool -> f Bool -> f Int -> f HaddockPrintStyle -> f Bool -> PrinterOpts f
+ Ormolu.Printer: PrinterOpts :: f Int -> f FunctionArrowsStyle -> f CommaStyle -> f ImportExportStyle -> f Bool -> f Bool -> f Int -> f HaddockPrintStyle -> f LetStyle -> f InStyle -> f Unicode -> f Bool -> PrinterOpts f
Files
- CHANGELOG.md +14/−0
- README.md +23/−12
- data/examples/declaration/data/gadt/multiline-four-out.hs +2/−6
- data/examples/declaration/data/gadt/multiline-out.hs +2/−6
- data/examples/declaration/data/gadt/multiple-declaration-four-out.hs +2/−4
- data/examples/declaration/data/gadt/multiple-declaration-out.hs +2/−4
- data/examples/declaration/type/promotion-1-four-out.hs +1/−1
- data/examples/declaration/type/promotion-1-out.hs +1/−1
- data/examples/declaration/value/function/arrow/proc-do-complex-four-out.hs +4/−2
- data/examples/declaration/value/function/arrow/proc-lets-four-out.hs +4/−2
- data/examples/declaration/value/function/blank-lines-let-four-out.hs +4/−2
- data/examples/fourmolu/type-app-promoted-four-out.hs +1/−0
- data/examples/fourmolu/type-app-promoted-out.hs +1/−0
- data/examples/fourmolu/type-app-promoted.hs +1/−0
- data/examples/module-header/multiline-with-comments-four-out.hs +2/−1
- data/examples/module-header/named-section-four-out.hs +2/−1
- data/examples/module-header/warning-pragma-list-multiline-four-out.hs +3/−3
- data/examples/module-header/warning-pragma-singleton-list-four-out.hs +1/−2
- data/examples/other/empty-haddock-four-out.hs +2/−1
- data/fourmolu/function-arrows/input.hs +43/−0
- data/fourmolu/function-arrows/output-LeadingArrows.hs +40/−0
- data/fourmolu/function-arrows/output-TrailingArrows.hs +40/−0
- data/fourmolu/import-export/output-ImportExportDiffFriendly.hs +2/−1
- data/fourmolu/let-style/input.hs +92/−0
- data/fourmolu/let-style/output-LetAuto-InLeftAlign-indent=2.hs +92/−0
- data/fourmolu/let-style/output-LetAuto-InLeftAlign-indent=4.hs +92/−0
- data/fourmolu/let-style/output-LetAuto-InRightAlign-indent=2.hs +92/−0
- data/fourmolu/let-style/output-LetAuto-InRightAlign-indent=4.hs +92/−0
- data/fourmolu/let-style/output-LetInline-InLeftAlign-indent=2.hs +88/−0
- data/fourmolu/let-style/output-LetInline-InLeftAlign-indent=4.hs +88/−0
- data/fourmolu/let-style/output-LetInline-InRightAlign-indent=2.hs +88/−0
- data/fourmolu/let-style/output-LetInline-InRightAlign-indent=4.hs +88/−0
- data/fourmolu/let-style/output-LetMixed-InLeftAlign-indent=2.hs +100/−0
- data/fourmolu/let-style/output-LetMixed-InLeftAlign-indent=4.hs +100/−0
- data/fourmolu/let-style/output-LetMixed-InRightAlign-indent=2.hs +100/−0
- data/fourmolu/let-style/output-LetMixed-InRightAlign-indent=4.hs +100/−0
- data/fourmolu/let-style/output-LetNewline-InLeftAlign-indent=2.hs +113/−0
- data/fourmolu/let-style/output-LetNewline-InLeftAlign-indent=4.hs +113/−0
- data/fourmolu/let-style/output-LetNewline-InRightAlign-indent=2.hs +113/−0
- data/fourmolu/let-style/output-LetNewline-InRightAlign-indent=4.hs +113/−0
- data/fourmolu/respectful-module-where/input-multi.hs +63/−0
- data/fourmolu/respectful-module-where/output-respectful=False-ImportExportDiffFriendly.hs +59/−0
- data/fourmolu/respectful-module-where/output-respectful=False-ImportExportLeading.hs +63/−0
- data/fourmolu/respectful-module-where/output-respectful=False-ImportExportTrailing.hs +63/−0
- data/fourmolu/respectful-module-where/output-respectful=True-ImportExportDiffFriendly.hs +65/−0
- data/fourmolu/respectful-module-where/output-respectful=True-ImportExportLeading.hs +65/−0
- data/fourmolu/respectful-module-where/output-respectful=True-ImportExportTrailing.hs +65/−0
- data/fourmolu/unicode-syntax/input.hs +94/−0
- data/fourmolu/unicode-syntax/output-UnicodeAlways.hs +94/−0
- data/fourmolu/unicode-syntax/output-UnicodeDetect.hs +94/−0
- data/fourmolu/unicode-syntax/output-UnicodeNever.hs +94/−0
- fourmolu.cabal +1/−1
- fourmolu.yaml +3/−0
- src/Ormolu/Config.hs +74/−0
- src/Ormolu/Config/Types.hs +27/−0
- src/Ormolu/Exception.hs +1/−0
- src/Ormolu/Printer/Combinators.hs +94/−27
- src/Ormolu/Printer/Internal.hs +2/−37
- src/Ormolu/Printer/Meat/Declaration/Class.hs +2/−2
- src/Ormolu/Printer/Meat/Declaration/Data.hs +3/−10
- src/Ormolu/Printer/Meat/Declaration/Signature.hs +9/−18
- src/Ormolu/Printer/Meat/Declaration/TypeFamily.hs +2/−5
- src/Ormolu/Printer/Meat/Declaration/Value.hs +110/−32
- src/Ormolu/Printer/Meat/ImportExport.hs +0/−1
- src/Ormolu/Printer/Meat/Module.hs +50/−24
- src/Ormolu/Printer/Meat/Type.hs +86/−88
- tests/Ormolu/Config/PrinterOptsSpec.hs +163/−28
CHANGELOG.md view
@@ -1,3 +1,17 @@+## Fourmolu 0.9.0.0++New configuration options:++* Add `let-style` and `in-style` configuration options ([#229](https://github.com/fourmolu/fourmolu/pull/229)). The default is set to `let-style: auto` and `in-style: right-align`, which should not reformat already formatted files, but allows users to format with `newline` without additional configuration.+* Add `unicode` configuration ([#206](https://github.com/fourmolu/fourmolu/pull/206))++Bug fixes:++* Fix some edge cases with function arrows ([#247](https://github.com/fourmolu/fourmolu/pull/247))+* Fix formatting of module header + export lists when `WARNING` or `DEPRECATED` pragma is present ([#244](https://github.com/fourmolu/fourmolu/pull/244))+* Fixed a bug where an extra space was inserted before promoted types (e.g. `foo @'True`) ([#211](https://github.com/fourmolu/fourmolu/pull/211))+* When `--respectful` is enabled, a `where` keyword on the line after the export list will not be moved up to the end of the previous line. ([#167](https://github.com/fourmolu/fourmolu/issues/167))+ ## Fourmolu 0.8.2.0 * Add `multi-line-compact` option to `haddock-style` that will output `{-|` for multiline haddocks instead of `{- |` ([#130](https://github.com/fourmolu/fourmolu/pull/130))
README.md view
@@ -41,19 +41,24 @@ ### Available options -| Configuration option | Valid options | Description |-|--------------------------|-----------------|-------------|-| `indentation` | any integer | Number of spaces to use as indentation |-| `function-arrows` | `trailing`, `leading`| How to format arrows in type signatures |-| `comma-style` | `leading`, `trailing` | Where to put the comma in lists, tuples, etc. |-| `import-export-style` | `leading`, `trailing`, `diff-friendly` | How to format multiline import/export lists (`diff-friendly` lists have trailing commas but keep the open-parentheses on the same line as the `import` line) |-| `indent-wheres` | `true`, `false` | `false` means save space by only half-indenting the `where` keyword |-| `record-brace-space` | `true`, `false` | `rec {x = 1}` vs `rec{x = 1}` |-| `newlines-between-decls` | any integer | number of newlines between top-level declarations |-| `haddock-style` | `single-line`, `multi-line`, `multi-line-compact` | Whether multiline haddocks should use `-- \|`, `{- \|`, or `{-\|` (single-line haddocks will always use `--` for now) |-| `respectful` | `true`, `false` | Whether to respect user-specified newlines, e.g. in import groupings |-| `fixities` | A list of strings | See the "Language extensions, dependencies, and fixities" section below |+Defaults are in bold. +| Configuration option | Valid options | Description+|--------------------------|-------------------------------------------------------|-------------+| `indentation` | any non-negative integer (**`4`**) | How many spaces to use as an indent+| `function-arrows` | **`trailing`**, `leading` | Where to place arrows in type signatures+| `comma-style` | **`leading`**, `trailing` | Where to place commas in lists, tuples, etc.+| `import-export-style` | `leading`, `trailing`, **`diff-friendly`** | How to format multiline import/export lists (`diff-friendly` lists have trailing commas but keep the opening parenthesis on the same line as `import`)+| `indent-wheres` | `true`, **`false`** | Use an extra level of indentation _vs_ only half-indent the `where` keyword+| `record-brace-space` | `true`, **`false`** | `rec {x = 1}` _vs_ `rec{x = 1}`+| `newlines-between-decls` | any integer (**`1`**) | Number of newlines between top-level declarations+| `haddock-style` | `single-line`, **`multi-line`**, `multi-line-compact` | Use `-- \|`, `{- \|`, or `{-\|` for multiline haddocks (single-line haddocks always use `--`)+| `let-style` | `inline`, `newline`, **`auto`**, `mixed` | How to style `let` blocks (`auto` uses `newline` if there's a newline in the input and `inline` otherwise, and `mixed` uses `inline` only when the `let` has exactly one binding)+| `in-style` | `left-align`, **`right-align`** | How to align the `in` keyword with respect to `let`+| `unicode` | `always`, `detect`, **`never`** | Output Unicode syntax. With `detect` we output Unicode syntax exactly when the extension is seen to be enabled.+| `respectful` | **`true`**, `false` | Be less aggressive in reformatting input, e.g. keep empty lines in import list+| `fixities` | list of strings (**`[]`**) | See the "Language extensions, dependencies, and fixities" section below+ For examples of each of these options, see the [test files](https://github.com/fourmolu/fourmolu/tree/main/data/fourmolu/). ### Specifying configuration@@ -71,8 +76,11 @@ record-brace-space: false newlines-between-decls: 1 haddock-style: multi-line+let-style: auto+in-style: right-align respectful: true fixities: []+unicode: never ``` The configuration that most closely matches Ormolu's styling is:@@ -86,8 +94,11 @@ record-brace-space: true newlines-between-decls: 1 haddock-style: single-line+let-style: inline+in-style: right-align respectful: false fixities: []+unicode: never ``` Command-line options override options in a configuration file. Run `fourmolu --help` to see all options.
data/examples/declaration/data/gadt/multiline-four-out.hs view
@@ -14,12 +14,8 @@ Foo 'Int -- | But 'Bar' is also not too bad. Bar ::- Int ->- Maybe Text ->- Foo 'Bool+ Int -> Maybe Text -> Foo 'Bool -- | So is 'Baz'. Baz ::- forall a.- a ->- Foo 'String+ forall a. a -> Foo 'String (:~>) :: Foo a -> Foo a -> Foo a
data/examples/declaration/data/gadt/multiline-out.hs view
@@ -14,12 +14,8 @@ Foo 'Int -- | But 'Bar' is also not too bad. Bar ::- Int ->- Maybe Text ->- Foo 'Bool+ Int -> Maybe Text -> Foo 'Bool -- | So is 'Baz'. Baz ::- forall a.- a ->- Foo 'String+ forall a. a -> Foo 'String (:~>) :: Foo a -> Foo a -> Foo a
data/examples/declaration/data/gadt/multiple-declaration-four-out.hs view
@@ -4,12 +4,10 @@ data GADT1 a where GADT11 , GADT12 ::- Int ->- GADT1 a+ Int -> GADT1 a data GADT2 a where GADT21 , GADT21 , GADT22 ::- Int ->- GADT2 a+ Int -> GADT2 a
data/examples/declaration/data/gadt/multiple-declaration-out.hs view
@@ -4,12 +4,10 @@ data GADT1 a where GADT11, GADT12 ::- Int ->- GADT1 a+ Int -> GADT1 a data GADT2 a where GADT21, GADT21, GADT22 ::- Int ->- GADT2 a+ Int -> GADT2 a
data/examples/declaration/type/promotion-1-four-out.hs view
@@ -5,7 +5,7 @@ type S7 = Proxy ('( 'a, 'b)) type S8 = Proxy ('[Int, Bool]) -type E = TypeError ( 'Text "Some text")+type E = TypeError ('Text "Some text") type G = '[ '( 'Just, 'Bool)] type X = () '`PromotedInfix` ()
data/examples/declaration/type/promotion-1-out.hs view
@@ -10,7 +10,7 @@ type S8 = Proxy ('[Int, Bool]) -type E = TypeError ( 'Text "Some text")+type E = TypeError ('Text "Some text") type G = '[ '( 'Just, 'Bool)]
data/examples/declaration/value/function/arrow/proc-do-complex-four-out.hs view
@@ -31,10 +31,12 @@ , w ) -> \u -> -- Procs can have lambdas- let v =+ let+ v = u -- Actually never used ^ 2- in ( returnA+ in+ ( returnA -< -- Just do the calculation (x + y * z)
data/examples/declaration/value/function/arrow/proc-lets-four-out.hs view
@@ -3,10 +3,12 @@ foo f = proc a -> let b = a in f -< b bar f g = proc a ->- let h =+ let+ h = f . g a j = g . h- in id -< (h, j)+ in+ id -< (h, j)
data/examples/declaration/value/function/blank-lines-let-four-out.hs view
@@ -1,6 +1,8 @@ foo =- let x = 10+ let+ x = 10 y = 11 z = 12- in x + y + z+ in+ x + y + z
+ data/examples/fourmolu/type-app-promoted-four-out.hs view
@@ -0,0 +1,1 @@+x = foo @'True
+ data/examples/fourmolu/type-app-promoted-out.hs view
@@ -0,0 +1,1 @@+x = foo @'True
+ data/examples/fourmolu/type-app-promoted.hs view
@@ -0,0 +1,1 @@+x = foo @'True
data/examples/module-header/multiline-with-comments-four-out.hs view
@@ -16,6 +16,7 @@ -- the second line bar3, module Foo.Bar.Baz,-) where+)+where -- Wow
data/examples/module-header/named-section-four-out.hs view
@@ -5,7 +5,8 @@ -- ** Another level foo, bar,-) where+)+where {- $explanation
data/examples/module-header/warning-pragma-list-multiline-four-out.hs view
@@ -3,9 +3,9 @@ [ "This module is deprecated." , "Please use OtherModule instead." ]- #-}- (+ #-} ( foo, bar, baz,-) where+)+where
data/examples/module-header/warning-pragma-singleton-list-four-out.hs view
@@ -1,2 +1,1 @@-module Test {-# WARNING "There's only one line here." #-}-where+module Test {-# WARNING "There's only one line here." #-} where
data/examples/other/empty-haddock-four-out.hs view
@@ -1,6 +1,7 @@ module Test ( test,-) where+)+where test :: test
data/fourmolu/function-arrows/input.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE LinearTypes #-}+ module Main where -- | Something else.@@ -77,9 +79,50 @@ (c -> d) -> (a, b, c, d) +functionWithInterleavedCommentsTrailing ::+ -- arg+ Int ->+ -- result+ Bool++functionWithInterleavedCommentsLeading+ -- arg+ :: Int+ -- result+ -> Bool++multilineExprSig = do+ bar+ ( x ::+ Int ->+ Bool+ )+ bar+ ( x ::+ -- arg+ Int ->+ -- result+ Bool+ )+ bar+ ( x+ -- arg+ :: Int+ -- result+ -> Bool+ )+ data Record = Record { recFun :: forall a. (C1, C2) => Int -> Int -> Bool , recOther :: Bool }++foo ::+ Int %1 ->+ Bool+foo ::+ forall x.+ Int %Many ->+ Bool
data/fourmolu/function-arrows/output-LeadingArrows.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE LinearTypes #-} module Main where @@ -77,7 +78,38 @@ ) -> (c -> d) -> (a, b, c, d)+functionWithInterleavedCommentsTrailing+ -- arg+ :: Int+ -- result+ -> Bool+functionWithInterleavedCommentsLeading+ -- arg+ :: Int+ -- result+ -> Bool +multilineExprSig = do+ bar+ ( x+ :: Int+ -> Bool+ )+ bar+ ( x+ -- arg+ :: Int+ -- result+ -> Bool+ )+ bar+ ( x+ -- arg+ :: Int+ -- result+ -> Bool+ )+ data Record = Record { recFun :: forall a@@ -87,3 +119,11 @@ -> Bool , recOther :: Bool }++foo+ :: Int+ %1 -> Bool+foo+ :: forall x+ . Int+ %Many -> Bool
data/fourmolu/function-arrows/output-TrailingArrows.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE LinearTypes #-} module Main where @@ -77,7 +78,38 @@ ) -> (c -> d) -> (a, b, c, d)+functionWithInterleavedCommentsTrailing ::+ -- arg+ Int ->+ -- result+ Bool+functionWithInterleavedCommentsLeading ::+ -- arg+ Int ->+ -- result+ Bool +multilineExprSig = do+ bar+ ( x ::+ Int ->+ Bool+ )+ bar+ ( x ::+ -- arg+ Int ->+ -- result+ Bool+ )+ bar+ ( x ::+ -- arg+ Int ->+ -- result+ Bool+ )+ data Record = Record { recFun :: forall a.@@ -87,3 +119,11 @@ Bool , recOther :: Bool }++foo ::+ Int %1 ->+ Bool+foo ::+ forall x.+ Int %Many ->+ Bool
data/fourmolu/import-export/output-ImportExportDiffFriendly.hs view
@@ -12,7 +12,8 @@ class1, class2 ),-) where+)+where import qualified MegaModule as M ( Either,
+ data/fourmolu/let-style/input.hs view
@@ -0,0 +1,92 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetAuto-InLeftAlign-indent=2.hs view
@@ -0,0 +1,92 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetAuto-InLeftAlign-indent=4.hs view
@@ -0,0 +1,92 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetAuto-InRightAlign-indent=2.hs view
@@ -0,0 +1,92 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetAuto-InRightAlign-indent=4.hs view
@@ -0,0 +1,92 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetInline-InLeftAlign-indent=2.hs view
@@ -0,0 +1,88 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let a = 1+ b = 2+ in a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetInline-InLeftAlign-indent=4.hs view
@@ -0,0 +1,88 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let a = 1+ b = 2+ in a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetInline-InRightAlign-indent=2.hs view
@@ -0,0 +1,88 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let a = 1+ b = 2+ in a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetInline-InRightAlign-indent=4.hs view
@@ -0,0 +1,88 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let a :: Int+ a = 1+ in a + 2++let_multi =+ let a = 1+ b = 2+ in a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let a = 1+ b = 2+ in a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let b = 2+ c = 3++ let d = "hello"+ in print d++ let d = "hello"+ e = "world"+ in print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetMixed-InLeftAlign-indent=2.hs view
@@ -0,0 +1,100 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let+ b = 2+ c = 3++ let d = "hello"+ in print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetMixed-InLeftAlign-indent=4.hs view
@@ -0,0 +1,100 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let+ b = 2+ c = 3++ let d = "hello"+ in print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetMixed-InRightAlign-indent=2.hs view
@@ -0,0 +1,100 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let+ b = 2+ c = 3++ let d = "hello"+ in print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetMixed-InRightAlign-indent=4.hs view
@@ -0,0 +1,100 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let a = 1+ in a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let a = 1+ in a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let a = 1++ let+ b = 2+ c = 3++ let d = "hello"+ in print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let+ , let a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetNewline-InLeftAlign-indent=2.hs view
@@ -0,0 +1,113 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let+ a = 1+ in+ a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let+ a = 1++ let+ b = 2+ c = 3++ let+ d = "hello"+ in+ print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetNewline-InLeftAlign-indent=4.hs view
@@ -0,0 +1,113 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let+ a = 1+ in+ a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let+ a = 1++ let+ b = 2+ c = 3++ let+ d = "hello"+ in+ print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetNewline-InRightAlign-indent=2.hs view
@@ -0,0 +1,113 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let+ a = 1+ in+ a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let+ a = 1++ let+ b = 2+ c = 3++ let+ d = "hello"+ in+ print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/let-style/output-LetNewline-InRightAlign-indent=4.hs view
@@ -0,0 +1,113 @@+{-- should be the same in every option --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_oneline_empty =+-- let in 10++let_oneline_single =+ let a = 1 in a + 2++let_oneline_multi =+ let a = 1; b = 2 in a + b++{-- pure let expressions --}++-- TODO: https://github.com/tweag/ormolu/issues/917+-- let_empty =+-- let+-- in 10++let_single =+ let+ a = 1+ in+ a + 2++let_single_sig =+ let+ a :: Int+ a = 1+ in+ a + 2++let_multi =+ let+ a = 1+ b = 2+ in+ a + b++let_single_newline =+ let+ a = 1+ in+ a + 2++let_multi_newline =+ let+ a = 1+ b = 2+ in+ a + b++{-- do-block --}++test_do = do+ -- TODO: https://github.com/tweag/ormolu/issues/917+ -- let++ let+ a = 1++ let+ b = 2+ c = 3++ let+ d = "hello"+ in+ print d++ let+ d = "hello"+ e = "world"+ in+ print (d ++ e)++{-- list comprehension --}++test_list =+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 2+ ]++test_list_do = do+ x <-+ [ x + a + b + c+ | x <- xs+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]++ [ x + y + a + b + c+ | y <- ys+ , let++ , let+ a = 1+ , let+ b = 2+ c = 3+ ]
+ data/fourmolu/respectful-module-where/input-multi.hs view
@@ -0,0 +1,63 @@+module Foo where++{- // -}++module Foo+where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b)+where++{- // -}++module Foo (+ a,+ b,+) where++{- // -}++module Foo (+ a,+ b,+)+where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-}+where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b)+where++{- // -}++module Foo {-# WARNING "foo" #-} (+ a,+ b,+) where++{- // -}++module Foo {-# WARNING "foo" #-} (+ a,+ b,+)+where
+ data/fourmolu/respectful-module-where/output-respectful=False-ImportExportDiffFriendly.hs view
@@ -0,0 +1,59 @@+module Foo where++{- // -}++module Foo where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (+ a,+ b,+) where++{- // -}++module Foo (+ a,+ b,+) where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo+ {-# WARNING "foo" #-} (+ a,+ b,+) where++{- // -}++module Foo+ {-# WARNING "foo" #-} (+ a,+ b,+) where
+ data/fourmolu/respectful-module-where/output-respectful=False-ImportExportLeading.hs view
@@ -0,0 +1,63 @@+module Foo where++{- // -}++module Foo where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b) where++{- // -}++module Foo+ ( a+ , b+ )+where++{- // -}++module Foo+ ( a+ , b+ )+where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a+ , b+ )+where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a+ , b+ )+where
+ data/fourmolu/respectful-module-where/output-respectful=False-ImportExportTrailing.hs view
@@ -0,0 +1,63 @@+module Foo where++{- // -}++module Foo where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b) where++{- // -}++module Foo+ ( a,+ b,+ )+where++{- // -}++module Foo+ ( a,+ b,+ )+where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a,+ b,+ )+where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a,+ b,+ )+where
+ data/fourmolu/respectful-module-where/output-respectful=True-ImportExportDiffFriendly.hs view
@@ -0,0 +1,65 @@+module Foo where++{- // -}++module Foo+where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b)+where++{- // -}++module Foo (+ a,+ b,+) where++{- // -}++module Foo (+ a,+ b,+)+where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-}+where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b)+where++{- // -}++module Foo+ {-# WARNING "foo" #-} (+ a,+ b,+) where++{- // -}++module Foo+ {-# WARNING "foo" #-} (+ a,+ b,+)+where
+ data/fourmolu/respectful-module-where/output-respectful=True-ImportExportLeading.hs view
@@ -0,0 +1,65 @@+module Foo where++{- // -}++module Foo+where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b)+where++{- // -}++module Foo+ ( a+ , b+ ) where++{- // -}++module Foo+ ( a+ , b+ )+where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-}+where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b)+where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a+ , b+ ) where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a+ , b+ )+where
+ data/fourmolu/respectful-module-where/output-respectful=True-ImportExportTrailing.hs view
@@ -0,0 +1,65 @@+module Foo where++{- // -}++module Foo+where++{- // -}++module Foo (a, b) where++{- // -}++module Foo (a, b)+where++{- // -}++module Foo+ ( a,+ b,+ ) where++{- // -}++module Foo+ ( a,+ b,+ )+where++{- // -}++module Foo {-# WARNING "foo" #-} where++{- // -}++module Foo {-# WARNING "foo" #-}+where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b) where++{- // -}++module Foo {-# WARNING "foo" #-} (a, b)+where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a,+ b,+ ) where++{- // -}++module Foo+ {-# WARNING "foo" #-}+ ( a,+ b,+ )+where
+ data/fourmolu/unicode-syntax/input.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UnicodeSyntax #-}++module UnicodeExample where++import Control.Arrow+import Data.Kind+import Language.Haskell.TH (Exp, Quote)+import Prelude hiding (elem)++data T = MkT {foo :: Int}++data Term a where+ Lit :: Int -> Term Int+ Succ :: Term Int -> Term Int+ IsZero :: Term Int -> Term Bool+ If :: Term Bool -> Term a -> Term a -> Term a+ Pair :: Term a -> Term b -> Term (a, b)++newtype Swizzle = MkSwizzle (forall a. Ord a => [a] -> [a])++data family GMap k :: Type -> Type++data instance GMap (Either a b) v = GMapEither (GMap a v) (GMap b v)++type family F a where+ F Int = Double+ F Bool = Char+ F a = String++type family Id a = r | r -> a++type instance Id Int = Int++type instance Id Bool = Bool++type family Elem c :: Type++type instance Elem [e] = e++data T1 a = MkT1 a++construct :: a %1 -> T1 a+construct x = MkT1 x++deconstruct :: T1 a %1 -> a+deconstruct (MkT1 x) = x++pattern HeadC x <- x : xs+ where+ HeadC x = [x]++pattern Point :: Int -> Int -> (Int, Int)+pattern Point {x, y} = (x, y)++class (Monad m, Monad (t m)) => Transform t m where+ lift :: m a -> (t m) a++data Tree a = Leaf a | Branch (Tree a) (Tree a)++instance (Eq a) => Eq (Tree a) where+ Leaf a == Leaf b = a == b+ (Branch l1 r1) == (Branch l2 r2) = (l1 == l2) && (r1 == r2)+ _ == _ = False++add1 :: Quote m => Int -> m Exp+add1 x = [|x + 1|]++monad = do+ putStr "x: "+ l <- getLine+ return (words l)++arrow f g h = proc x -> do+ y <- f -< x + 1+ g -< 2 * y+ let z = x + y+ t <- h -< x * z+ returnA -< t + z++elem :: (Eq a) => a -> [a] -> Bool+x `elem` [] = False+x `elem` (y : ys) = x == y || (x `elem` ys)++h :: (forall a. a -> a) -> (Bool, Char)+h f = (f True, f 'c')
+ data/fourmolu/unicode-syntax/output-UnicodeAlways.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UnicodeSyntax #-}++module UnicodeExample where++import Control.Arrow+import Data.Kind+import Language.Haskell.TH (Exp, Quote)+import Prelude hiding (elem)++data T = MkT {foo ∷ Int}++data Term a where+ Lit ∷ Int → Term Int+ Succ ∷ Term Int → Term Int+ IsZero ∷ Term Int → Term Bool+ If ∷ Term Bool → Term a → Term a → Term a+ Pair ∷ Term a → Term b → Term (a, b)++newtype Swizzle = MkSwizzle (∀ a. Ord a ⇒ [a] → [a])++data family GMap k ∷ Type → Type++data instance GMap (Either a b) v = GMapEither (GMap a v) (GMap b v)++type family F a where+ F Int = Double+ F Bool = Char+ F a = String++type family Id a = r | r → a++type instance Id Int = Int++type instance Id Bool = Bool++type family Elem c ∷ Type++type instance Elem [e] = e++data T1 a = MkT1 a++construct ∷ a ⊸ T1 a+construct x = MkT1 x++deconstruct ∷ T1 a ⊸ a+deconstruct (MkT1 x) = x++pattern HeadC x ← x : xs+ where+ HeadC x = [x]++pattern Point ∷ Int → Int → (Int, Int)+pattern Point{x, y} = (x, y)++class (Monad m, Monad (t m)) ⇒ Transform t m where+ lift ∷ m a → (t m) a++data Tree a = Leaf a | Branch (Tree a) (Tree a)++instance (Eq a) ⇒ Eq (Tree a) where+ Leaf a == Leaf b = a == b+ (Branch l1 r1) == (Branch l2 r2) = (l1 == l2) && (r1 == r2)+ _ == _ = False++add1 ∷ Quote m ⇒ Int → m Exp+add1 x = [|x + 1|]++monad = do+ putStr "x: "+ l ← getLine+ return (words l)++arrow f g h = proc x → do+ y ← f ⤙ x + 1+ g ⤙ 2 * y+ let z = x + y+ t ← h ⤙ x * z+ returnA ⤙ t + z++elem ∷ (Eq a) ⇒ a → [a] → Bool+x `elem` [] = False+x `elem` (y : ys) = x == y || (x `elem` ys)++h ∷ (∀ a. a → a) → (Bool, Char)+h f = (f True, f 'c')
+ data/fourmolu/unicode-syntax/output-UnicodeDetect.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UnicodeSyntax #-}++module UnicodeExample where++import Control.Arrow+import Data.Kind+import Language.Haskell.TH (Exp, Quote)+import Prelude hiding (elem)++data T = MkT {foo ∷ Int}++data Term a where+ Lit ∷ Int → Term Int+ Succ ∷ Term Int → Term Int+ IsZero ∷ Term Int → Term Bool+ If ∷ Term Bool → Term a → Term a → Term a+ Pair ∷ Term a → Term b → Term (a, b)++newtype Swizzle = MkSwizzle (∀ a. Ord a ⇒ [a] → [a])++data family GMap k ∷ Type → Type++data instance GMap (Either a b) v = GMapEither (GMap a v) (GMap b v)++type family F a where+ F Int = Double+ F Bool = Char+ F a = String++type family Id a = r | r → a++type instance Id Int = Int++type instance Id Bool = Bool++type family Elem c ∷ Type++type instance Elem [e] = e++data T1 a = MkT1 a++construct ∷ a ⊸ T1 a+construct x = MkT1 x++deconstruct ∷ T1 a ⊸ a+deconstruct (MkT1 x) = x++pattern HeadC x ← x : xs+ where+ HeadC x = [x]++pattern Point ∷ Int → Int → (Int, Int)+pattern Point{x, y} = (x, y)++class (Monad m, Monad (t m)) ⇒ Transform t m where+ lift ∷ m a → (t m) a++data Tree a = Leaf a | Branch (Tree a) (Tree a)++instance (Eq a) ⇒ Eq (Tree a) where+ Leaf a == Leaf b = a == b+ (Branch l1 r1) == (Branch l2 r2) = (l1 == l2) && (r1 == r2)+ _ == _ = False++add1 ∷ Quote m ⇒ Int → m Exp+add1 x = [|x + 1|]++monad = do+ putStr "x: "+ l ← getLine+ return (words l)++arrow f g h = proc x → do+ y ← f ⤙ x + 1+ g ⤙ 2 * y+ let z = x + y+ t ← h ⤙ x * z+ returnA ⤙ t + z++elem ∷ (Eq a) ⇒ a → [a] → Bool+x `elem` [] = False+x `elem` (y : ys) = x == y || (x `elem` ys)++h ∷ (∀ a. a → a) → (Bool, Char)+h f = (f True, f 'c')
+ data/fourmolu/unicode-syntax/output-UnicodeNever.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE Arrows #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE UnicodeSyntax #-}++module UnicodeExample where++import Control.Arrow+import Data.Kind+import Language.Haskell.TH (Exp, Quote)+import Prelude hiding (elem)++data T = MkT {foo :: Int}++data Term a where+ Lit :: Int -> Term Int+ Succ :: Term Int -> Term Int+ IsZero :: Term Int -> Term Bool+ If :: Term Bool -> Term a -> Term a -> Term a+ Pair :: Term a -> Term b -> Term (a, b)++newtype Swizzle = MkSwizzle (forall a. Ord a => [a] -> [a])++data family GMap k :: Type -> Type++data instance GMap (Either a b) v = GMapEither (GMap a v) (GMap b v)++type family F a where+ F Int = Double+ F Bool = Char+ F a = String++type family Id a = r | r -> a++type instance Id Int = Int++type instance Id Bool = Bool++type family Elem c :: Type++type instance Elem [e] = e++data T1 a = MkT1 a++construct :: a %1 -> T1 a+construct x = MkT1 x++deconstruct :: T1 a %1 -> a+deconstruct (MkT1 x) = x++pattern HeadC x <- x : xs+ where+ HeadC x = [x]++pattern Point :: Int -> Int -> (Int, Int)+pattern Point{x, y} = (x, y)++class (Monad m, Monad (t m)) => Transform t m where+ lift :: m a -> (t m) a++data Tree a = Leaf a | Branch (Tree a) (Tree a)++instance (Eq a) => Eq (Tree a) where+ Leaf a == Leaf b = a == b+ (Branch l1 r1) == (Branch l2 r2) = (l1 == l2) && (r1 == r2)+ _ == _ = False++add1 :: Quote m => Int -> m Exp+add1 x = [|x + 1|]++monad = do+ putStr "x: "+ l <- getLine+ return (words l)++arrow f g h = proc x -> do+ y <- f -< x + 1+ g -< 2 * y+ let z = x + y+ t <- h -< x * z+ returnA -< t + z++elem :: (Eq a) => a -> [a] -> Bool+x `elem` [] = False+x `elem` (y : ys) = x == y || (x `elem` ys)++h :: (forall a. a -> a) -> (Bool, Char)+h f = (f True, f 'c')
fourmolu.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: fourmolu-version: 0.8.2.0+version: 0.9.0.0 license: BSD-3-Clause license-file: LICENSE.md maintainer:
fourmolu.yaml view
@@ -7,5 +7,8 @@ record-brace-space: true newlines-between-decls: 1 haddock-style: single-line+let-style: inline+in-style: right-align+unicode: never respectful: false fixities: []
src/Ormolu/Config.hs view
@@ -35,6 +35,8 @@ CommaStyle (..), HaddockPrintStyle (..), ImportExportStyle (..),+ LetStyle (..),+ InStyle (..), -- ** Loading Fourmolu configuration loadConfigFile,@@ -225,6 +227,9 @@ poRecordBraceSpace <- f poRecordBraceSpace0 poNewlinesBetweenDecls <- f poNewlinesBetweenDecls0 poHaddockStyle <- f poHaddockStyle0+ poLetStyle <- f poLetStyle0+ poInStyle <- f poInStyle0+ poUnicode <- f poUnicode0 poRespectful <- f poRespectful0 return PrinterOpts {..} @@ -339,6 +344,33 @@ (showAllValues haddockPrintStyleMap), metaDefault = HaddockMultiLine },+ poLetStyle =+ PrinterOptsFieldMeta+ { metaName = "let-style",+ metaGetField = poLetStyle,+ metaPlaceholder = "STYLE",+ metaHelp =+ printf+ "Styling of let blocks (choices: %s)"+ (showAllValues letStyleMap),+ metaDefault = LetAuto+ },+ poInStyle =+ PrinterOptsFieldMeta+ { metaName = "in-style",+ metaGetField = poInStyle,+ metaPlaceholder = "STYLE",+ metaHelp = "How to align the 'in' keyword with respect to the 'let' keyword",+ metaDefault = InRightAlign+ },+ poUnicode =+ PrinterOptsFieldMeta+ { metaName = "unicode",+ metaGetField = poUnicode,+ metaPlaceholder = "UNICODE",+ metaHelp = printf "Output Unicode syntax (choices: %s)" (showAllValues unicodePreferenceMap),+ metaDefault = UnicodeNever+ }, poRespectful = PrinterOptsFieldMeta { metaName = "respectful",@@ -408,6 +440,33 @@ ] ) +letStyleMap :: BijectiveMap LetStyle+letStyleMap =+ $( mkBijectiveMap+ [ ('LetAuto, "auto"),+ ('LetInline, "inline"),+ ('LetNewline, "newline"),+ ('LetMixed, "mixed")+ ]+ )++inStyleMap :: BijectiveMap InStyle+inStyleMap =+ $( mkBijectiveMap+ [ ('InLeftAlign, "left-align"),+ ('InRightAlign, "right-align")+ ]+ )++unicodePreferenceMap :: BijectiveMap Unicode+unicodePreferenceMap =+ $( mkBijectiveMap+ [ ('UnicodeDetect, "detect"),+ ('UnicodeAlways, "always"),+ ('UnicodeNever, "never")+ ]+ )+ instance PrinterOptsFieldType CommaStyle where parseJSON = parseJSONWith commaStyleMap "CommaStyle" parseText = parseTextWith commaStyleMap@@ -427,6 +486,21 @@ parseJSON = parseJSONWith importExportStyleMap "ImportExportStyle" parseText = parseTextWith importExportStyleMap showText = show . showTextWith importExportStyleMap++instance PrinterOptsFieldType LetStyle where+ parseJSON = parseJSONWith letStyleMap "LetStyle"+ parseText = parseTextWith letStyleMap+ showText = show . showTextWith letStyleMap++instance PrinterOptsFieldType InStyle where+ parseJSON = parseJSONWith inStyleMap "InStyle"+ parseText = parseTextWith inStyleMap+ showText = show . showTextWith inStyleMap++instance PrinterOptsFieldType Unicode where+ parseJSON = parseJSONWith unicodePreferenceMap "UnicodePreference"+ parseText = parseTextWith unicodePreferenceMap+ showText = show . showTextWith unicodePreferenceMap ---------------------------------------------------------------------------- -- BijectiveMap helpers
src/Ormolu/Config/Types.hs view
@@ -7,6 +7,9 @@ FunctionArrowsStyle (..), HaddockPrintStyle (..), ImportExportStyle (..),+ LetStyle (..),+ InStyle (..),+ Unicode (..), ) where @@ -30,6 +33,12 @@ poNewlinesBetweenDecls :: f Int, -- | How to print doc comments poHaddockStyle :: f HaddockPrintStyle,+ -- | Styling of let blocks+ poLetStyle :: f LetStyle,+ -- | How to align in keyword+ poInStyle :: f InStyle,+ -- | Output Unicode syntax+ poUnicode :: f Unicode, -- | Be less opinionated about spaces/newlines etc. poRespectful :: f Bool }@@ -55,4 +64,22 @@ = ImportExportLeading | ImportExportTrailing | ImportExportDiffFriendly+ deriving (Eq, Show, Enum, Bounded)++data LetStyle+ = LetAuto+ | LetInline+ | LetNewline+ | LetMixed+ deriving (Eq, Show, Enum, Bounded)++data InStyle+ = InLeftAlign+ | InRightAlign+ deriving (Eq, Show, Enum, Bounded)++data Unicode+ = UnicodeDetect+ | UnicodeAlways+ | UnicodeNever deriving (Eq, Show, Enum, Bounded)
src/Ormolu/Exception.hs view
@@ -4,6 +4,7 @@ -- | 'OrmoluException' type and surrounding definitions. module Ormolu.Exception ( OrmoluException (..),+ printOrmoluException, withPrettyOrmoluExceptions, ) where
src/Ormolu/Printer/Combinators.hs view
@@ -29,7 +29,6 @@ askSourceType, askFixityOverrides, askFixityMap,- inciByExact, located, located', switchLayout,@@ -39,6 +38,7 @@ breakpoint, breakpoint', getPrinterOpt,+ whenUnicodeOtherwise, -- ** Formatting lists sep,@@ -64,6 +64,21 @@ commaDel, commaDelImportExport, equals,+ llarrowtail,+ rrarrowtail,+ darrow,+ dcolon,+ larrow,+ larrowtail,+ rarrow,+ rarrowtail,+ star,+ forall,+ oparenbar,+ cparenbar,+ openExpQuote,+ closeQuote,+ lolly, -- ** Stateful markers SpanMark (..),@@ -75,19 +90,16 @@ -- ** Placement Placement (..), placeHanging,-- -- ** Helpers for leading/trailing arrows- leadingArrowType,- trailingArrowType, ) where import Control.Monad import Data.List (intersperse) import Data.Text (Text)+import GHC.LanguageExtensions.Type import GHC.Types.SrcLoc import Ormolu.Config-import Ormolu.Config.Types (FunctionArrowsStyle (..))+import Ormolu.Config.Types import Ormolu.Printer.Comments import Ormolu.Printer.Internal import Ormolu.Utils (HasSrcSpan (..))@@ -171,6 +183,17 @@ breakpoint' :: R () breakpoint' = vlayout (return ()) newline +-- | Write the one text or the other depending on whether Unicode is enabled.+whenUnicodeOtherwise :: Text -> Text -> R ()+unicodeText `whenUnicodeOtherwise` asciiText = do+ unicodePrinterOption <- getPrinterOpt poUnicode+ unicodeExtensionIsEnabled <- isExtensionEnabled UnicodeSyntax+ txt $ case unicodePrinterOption of+ UnicodeDetect | unicodeExtensionIsEnabled -> unicodeText+ UnicodeDetect | otherwise -> asciiText+ UnicodeAlways -> unicodeText+ UnicodeNever -> asciiText+ ---------------------------------------------------------------------------- -- Formatting lists @@ -342,6 +365,71 @@ equals :: R () equals = interferingTxt "=" +-- The names of the following literals are from GHC's+-- @compiler/GHC/Parser/Lexer.x@.++llarrowtail,+ rrarrowtail,+ darrow,+ dcolon,+ larrow,+ larrowtail,+ rarrow,+ rarrowtail,+ star,+ forall,+ oparenbar,+ cparenbar,+ openExpQuote,+ closeQuote,+ lolly ::+ R ()++-- | Print @⤛@ or @-<<@ as appropriate.+llarrowtail = "⤛" `whenUnicodeOtherwise` "-<<"++-- | Print @⤜@ or @>>-@ as appropriate.+rrarrowtail = "⤜" `whenUnicodeOtherwise` ">>-"++-- | Print @⇒@ or @=>@ as appropriate.+darrow = "⇒" `whenUnicodeOtherwise` "=>"++-- | Print @∷@ or @::@ as appropriate.+dcolon = "∷" `whenUnicodeOtherwise` "::"++-- | Print @←@ or @<-@ as appropriate.+larrow = "←" `whenUnicodeOtherwise` "<-"++-- | Print @⤙@ or @-<@ as appropriate.+larrowtail = "⤙" `whenUnicodeOtherwise` "-<"++-- | Print @→@ or @->@ as appropriate.+rarrow = "→" `whenUnicodeOtherwise` "->"++-- | Print @⤚@ or @>-@ as appropriate.+rarrowtail = "⤚" `whenUnicodeOtherwise` ">-"++-- | Print @★@ or @*@ as appropriate.+star = "★" `whenUnicodeOtherwise` "*"++-- | Print @∀@ or @forall@ as appropriate.+forall = "∀" `whenUnicodeOtherwise` "forall"++-- | Print @⦇@ or @(|@ as appropriate.+oparenbar = "⦇" `whenUnicodeOtherwise` "(|"++-- | Print @⦈@ or @|)@ as appropriate.+cparenbar = "⦈" `whenUnicodeOtherwise` "|)"++-- | Print @⟦@ or @[|@ as appropriate.+openExpQuote = "⟦" `whenUnicodeOtherwise` "[|"++-- | Print @⟧@ or @|]@ as appropriate.+closeQuote = "⟧" `whenUnicodeOtherwise` "|]"++-- | Print @⊸@ or @%1 ->@ as appropriate.+lolly = "⊸" `whenUnicodeOtherwise` "%1 ->"+ ---------------------------------------------------------------------------- -- Placement @@ -370,24 +458,3 @@ Normal -> do breakpoint inci m--------------------------------------------------------------------------------- Arrow style---- | Output @space >> txt "::"@ when we are printing with trailing arrows-trailingArrowType :: R ()-trailingArrowType =- getPrinterOpt poFunctionArrows >>= \case- TrailingArrows -> do- space- txt "::"- LeadingArrows -> pure ()---- | Output @txt "::" >> space@ when we are printing with leading arrows-leadingArrowType :: R ()-leadingArrowType =- getPrinterOpt poFunctionArrows >>= \case- LeadingArrows -> do- txt "::"- space- TrailingArrows -> pure ()
src/Ormolu/Printer/Internal.hs view
@@ -26,7 +26,6 @@ inciBy, inciByFrac, inciHalf,- inciByExact, sitcc, sitccIfTrailing, Layout (..),@@ -59,9 +58,6 @@ -- * Extensions isExtensionEnabled,- PrevTypeCtx (..),- getPrevTypeCtx,- setPrevTypeCtx, ) where @@ -139,9 +135,7 @@ -- | Whether to output a space before the next output scRequestedDelimiter :: !RequestedDelimiter, -- | An auxiliary marker for keeping track of last output element- scSpanMark :: !(Maybe SpanMark),- -- | What (if any) precedes the current type on the same line- scPrevTypeCtx :: PrevTypeCtx+ scSpanMark :: !(Maybe SpanMark) } -- | Make sure next output is delimited by one of the following.@@ -218,8 +212,7 @@ scCommentStream = cstream, scPendingComments = [], scRequestedDelimiter = VeryBeginning,- scSpanMark = Nothing,- scPrevTypeCtx = TypeCtxStart+ scSpanMark = Nothing } ----------------------------------------------------------------------------@@ -450,15 +443,6 @@ inciHalf :: R () -> R () inciHalf = inciByFrac 2 --- | Like 'inci', but indents by exactly the given number of spaces.-inciByExact :: Int -> R () -> R ()-inciByExact spaces (R m) = R (local modRC m)- where- modRC rc =- rc- { rcIndent = rcIndent rc + spaces- }- -- | Set indentation level for the inner computation equal to current -- column. This makes sure that the entire inner block is uniformly -- \"shifted\" to the right.@@ -654,22 +638,3 @@ isExtensionEnabled :: Extension -> R Bool isExtensionEnabled ext = R . asks $ EnumSet.member ext . rcExtensions--------------------------------------------------------------------------------- Previous type context---- | What (if anything) precedes the current type on the same line--- Only used for the `function-arrows` setting-data PrevTypeCtx- = TypeCtxStart- | TypeCtxForall- | TypeCtxContext- | TypeCtxArgument- deriving (Eq, Show)--getPrevTypeCtx :: R PrevTypeCtx-getPrevTypeCtx = R (gets scPrevTypeCtx)--setPrevTypeCtx :: PrevTypeCtx -> R ()-setPrevTypeCtx prevTypeCtx =- R $ modify (\sc -> sc {scPrevTypeCtx = prevTypeCtx})
src/Ormolu/Printer/Meat/Declaration/Class.hs view
@@ -78,7 +78,7 @@ p_classContext ctx = unless (null (unLoc ctx)) $ do located ctx p_hsContext space- txt "=>"+ darrow breakpoint p_classFundeps :: [LHsFunDep GhcPs] -> R ()@@ -97,7 +97,7 @@ p_funDep (FunDep _ before after) = do sep space p_rdrName before space- txt "->"+ rarrow space sep space p_rdrName after
src/Ormolu/Printer/Meat/Declaration/Data.hs view
@@ -66,7 +66,7 @@ (p_lhsTypeArg <$> tpats) forM_ dd_kindSig $ \k -> do space- txt "::"+ dcolon breakpoint inci $ located k p_hsType let gadt = isJust dd_kindSig || any (isGadt . unLoc) dd_cons@@ -126,13 +126,6 @@ commaDel sep commaDel p_rdrName cs inci $ do- trailingArrowType- let interArgBreak =- if hasDocStrings (unLoc con_res_ty)- then newline- else breakpoint- interArgBreak- leadingArrowType let conTy = case con_g_args of PrefixConGADT xs -> let go (HsScaled a b) t = addCLocAA t b (HsFunTy EpAnnNotUsed a b t)@@ -152,7 +145,7 @@ quantifiedTy = addCLocAA con_bndrs qualTy $ hsOuterTyVarBndrsToHsType (unLoc con_bndrs) qualTy- p_hsType (unLoc quantifiedTy)+ startTypeAnnotationDecl quantifiedTy id p_hsType ConDeclH98 {..} -> do mapM_ (p_hsDocString Pipe True) con_doc let conDeclWithContextSpn =@@ -200,7 +193,7 @@ ctx -> do located ctx p_hsContext space- txt "=>"+ darrow breakpoint isGadt :: ConDecl GhcPs -> Bool
src/Ormolu/Printer/Meat/Declaration/Signature.hs view
@@ -59,13 +59,8 @@ p_typeAscription :: LHsSigType GhcPs -> R ()-p_typeAscription sigType = inci $ do- trailingArrowType- if hasDocStrings (unLoc . sig_body . unLoc $ sigType)- then newline- else breakpoint- leadingArrowType- located sigType p_hsSigType+p_typeAscription lsigType =+ inci $ startTypeAnnotationDecl lsigType (unLoc . sig_body) p_hsSigType p_patSynSig :: [LocatedN RdrName] ->@@ -137,11 +132,10 @@ p_activation inl_act space p_rdrName name- trailingArrowType- inci $ do- leadingArrowType- breakpoint- sep commaDel (located' p_hsSigType) ts+ space+ dcolon+ breakpoint+ inci $ sep commaDel (located' p_hsSigType) ts p_inlineSpec :: InlineSpec -> R () p_inlineSpec = \case@@ -208,9 +202,9 @@ pragma "COMPLETE" . inci $ do sep commaDel p_rdrName cs forM_ mty $ \ty -> do- trailingArrowType+ space+ dcolon breakpoint- leadingArrowType inci (p_rdrName ty) p_sccSig :: LocatedN RdrName -> Maybe (Located StringLiteral) -> R ()@@ -226,7 +220,4 @@ inci $ do space p_rdrName name- trailingArrowType- breakpoint- leadingArrowType- located sigTy p_hsSigType+ startTypeAnnotation sigTy p_hsSigType
src/Ormolu/Printer/Meat/Declaration/TypeFamily.hs view
@@ -63,10 +63,7 @@ p_familyResultSigL (L _ a) = case a of NoSig NoExtField -> Nothing KindSig NoExtField k -> Just $ do- trailingArrowType- breakpoint- leadingArrowType- located k p_hsType+ startTypeAnnotation k p_hsType TyVarSig NoExtField bndr -> Just $ do equals breakpoint@@ -78,7 +75,7 @@ space p_rdrName a space- txt "->"+ rarrow space sep space p_rdrName bs
src/Ormolu/Printer/Meat/Declaration/Value.hs view
@@ -26,7 +26,7 @@ import Data.Function (on) import Data.Functor ((<&>)) import Data.Generics.Schemes (everything)-import Data.List (intersperse, sortBy)+import Data.List (find, intersperse, sortBy) import Data.List.NonEmpty (NonEmpty (..), (<|)) import qualified Data.List.NonEmpty as NE import Data.Maybe@@ -273,7 +273,7 @@ Function _ -> space >> inci equals PatternBind -> space >> inci equals s | isCase s && hasGuards -> return ()- _ -> space >> txt "->"+ _ -> space >> rarrow switchLayout [patGrhssSpan] $ placeHanging placement p_body inci p_where@@ -301,7 +301,7 @@ space inci $ case style of EqualSign -> equals- RightArrow -> txt "->"+ RightArrow -> rarrow -- If we have a sequence of guards and it is placed in the normal way, -- then we indent one level more for readability. Otherwise (all -- guards are on the same line) we do not need to indent, as it would@@ -333,10 +333,10 @@ breakpoint inci $ do case (arrType, rightToLeft) of- (HsFirstOrderApp, True) -> txt "-<"- (HsHigherOrderApp, True) -> txt "-<<"- (HsFirstOrderApp, False) -> txt ">-"- (HsHigherOrderApp, False) -> txt ">>-"+ (HsFirstOrderApp, True) -> larrowtail+ (HsHigherOrderApp, True) -> llarrowtail+ (HsFirstOrderApp, False) -> rarrowtail+ (HsHigherOrderApp, False) -> rrarrowtail placeHanging (exprPlacement (unLoc input)) $ located r p_hsExpr HsCmdArrForm _ form Prefix _ cmds -> banana s $ do@@ -364,8 +364,8 @@ p_lamcase cmdPlacement p_hsCmd mgroup HsCmdIf _ _ if' then' else' -> p_if cmdPlacement p_hsCmd if' then' else'- HsCmdLet _ localBinds c ->- p_let p_hsCmd localBinds c+ HsCmdLet epAnnLet localBinds c ->+ p_let (s == S) p_hsCmd epAnnLet localBinds c HsCmdDo _ es -> do txt "do" p_stmts cmdPlacement (p_hsCmd' S) es@@ -422,7 +422,7 @@ BindStmt _ p f@(getLocA -> l) -> do located p p_pat space- txt "<-"+ larrow let loc = getLocA p placement | isOneLineSpan (mkSrcSpan (srcSpanEnd loc) (srcSpanStart l)) = placer (unLoc f)@@ -431,10 +431,13 @@ placeHanging placement (located f render) ApplicativeStmt {} -> notImplemented "ApplicativeStmt" -- generated by renamer BodyStmt _ body _ _ -> located body render- LetStmt _ binds -> do- txt "let"- space- sitcc $ p_hsLocalBinds binds+ LetStmt epAnnLet binds -> do+ let letLoc =+ fmap (\(AddEpAnn _ loc) -> loc)+ . find (\(AddEpAnn ann _) -> ann == AnnLet)+ . epAnnAnns+ $ epAnnLet+ p_let' True letLoc binds Nothing ParStmt {} -> -- 'ParStmt' should always be eliminated in 'gatherStmt' already, such -- that it never occurs in 'p_stmt''. Consequently, handling it here@@ -744,8 +747,8 @@ txt "if" breakpoint inci . inci $ sep newline (located' (p_grhs RightArrow)) guards- HsLet _ localBinds e ->- p_let p_hsExpr localBinds e+ HsLet epAnnLet localBinds e ->+ p_let (s == S) p_hsExpr epAnnLet localBinds e HsDo _ ctx es -> do let doBody moduleName header = do forM_ moduleName $ \m -> atom m *> txt "."@@ -817,10 +820,7 @@ p_fieldLabels (NE.toList proj_flds) ExprWithTySig _ x HsWC {hswc_body} -> sitcc $ do located x p_hsExpr- trailingArrowType- breakpoint- leadingArrowType- inci $ located hswc_body p_hsSigType+ inci $ startTypeAnnotation hswc_body p_hsSigType ArithSeq _ _ x -> case x of From from -> brackets s $ do@@ -853,7 +853,7 @@ breakpoint inci (p_pat x) breakpoint- txt "->"+ rarrow placeHanging (cmdTopPlacement (unLoc e)) $ located e (p_hsCmdTop N) HsStatic _ e -> do@@ -878,7 +878,7 @@ case psb_dir of Unidirectional -> switchLayout pattern_def_spans $ do- txt "<-"+ larrow breakpoint located psb_def p_pat ImplicitBidirectional ->@@ -888,7 +888,7 @@ located psb_def p_pat ExplicitBidirectional mgroup -> do switchLayout pattern_def_spans $ do- txt "<-"+ larrow breakpoint located psb_def p_pat breakpoint@@ -996,20 +996,98 @@ placeHanging (placer x) (render x) p_let ::+ -- | True if in do-block+ Bool -> -- | Render (body -> R ()) ->+ -- | Annotation for the `let` block+ EpAnn AnnsLet -> HsLocalBinds GhcPs -> LocatedA body -> R ()-p_let render localBinds e = sitcc $ do- txt "let"- space- dontUseBraces $ sitcc (p_hsLocalBinds localBinds)- vlayout space (newline >> txt " ")- txt "in"- space- sitcc (located e render)+p_let inDo render epAnnLet localBinds e = p_let' inDo letLoc localBinds $ Just (located e render)+ where+ letLoc =+ case epAnnLet of+ EpAnn {anns} -> Just (alLet anns)+ EpAnnNotUsed -> Nothing +p_let' ::+ -- | True if in do-block+ Bool ->+ -- | Annotation for the `let` block+ Maybe EpaLocation ->+ -- | Let bindings+ HsLocalBinds GhcPs ->+ -- | Optional 'in' body+ Maybe (R ()) ->+ R ()+p_let' inDo letLoc localBinds mBody = do+ letStyle <- getPrinterOpt poLetStyle+ inStyle <- getPrinterOpt poInStyle+ layout <- getLayout+ -- isAllInline = True if whole "let ... in ..." is one line+ let isAllInline = not inDo && layout == SingleLine+ -- isBlockInline = True if each "let ..." + "in ..." block is one line+ let isBlockInline =+ case letStyle of+ _ | isAllInline -> True+ LetAuto ->+ -- check if local binds are on the same line as the "let" keyword;+ -- if we can't figure out the positions, just fallback to `inline` style+ fromMaybe True $ do+ letStartLine <- srcSpanStartLine . epaLocationRealSrcSpan <$> letLoc+ localBindsStartLine <- localBindsEpAnns localBinds >>= epAnnsStartLine+ pure $+ -- special case when let has zero local binds+ if localBindsStartLine == -1+ then True+ else letStartLine == localBindsStartLine+ LetInline -> True+ LetNewline -> False+ LetMixed -> numLocalBinds <= 1+ -- isInShifted = True if "in" is right-aligned with "let"+ let isInShifted = inDo || inStyle == InRightAlign++ -- helpers+ let block keyword body = do+ txt keyword+ if isBlockInline+ then space >> sitcc body+ else newline >> inci body++ sitcc $ do+ block "let" (p_hsLocalBinds localBinds)++ case mBody of+ Just body+ | isAllInline -> do+ space+ block "in" body+ | otherwise -> do+ newline+ let in_+ | isInShifted = " in"+ | isBlockInline = "in "+ | otherwise = "in"+ block in_ body+ Nothing -> pure ()+ where+ numLocalBinds =+ case localBinds of+ HsValBinds _ (ValBinds _ binds sigs) -> length binds + length sigs+ HsValBinds _ (XValBindsLR (NValBinds binds sigs)) -> length binds + length sigs+ HsIPBinds _ (IPBinds _ binds) -> length binds+ EmptyLocalBinds _ -> 0++ localBindsEpAnns = \case+ HsValBinds epanns _ -> Just epanns+ HsIPBinds epanns _ -> Just epanns+ EmptyLocalBinds _ -> Nothing+ epAnnsStartLine = \case+ EpAnn {entry} -> Just (srcSpanStartLine . anchor $ entry)+ EpAnnNotUsed -> Nothing+ p_pat :: Pat GhcPs -> R () p_pat = \case WildPat _ -> txt "_"@@ -1066,7 +1144,7 @@ ViewPat _ expr pat -> sitcc $ do located expr p_hsExpr space- txt "->"+ rarrow breakpoint inci (located pat p_pat) SplicePat _ splice -> p_hsSplice splice
src/Ormolu/Printer/Meat/ImportExport.hs view
@@ -6,7 +6,6 @@ module Ormolu.Printer.Meat.ImportExport ( p_hsmodExports, p_hsmodImport,- breakIfNotDiffFriendly, ) where
src/Ormolu/Printer/Meat/Module.hs view
@@ -11,6 +11,8 @@ import Control.Monad import GHC.Hs hiding (comment) import GHC.Types.SrcLoc+import GHC.Unit.Module.Name+import GHC.Utils.Outputable (ppr, showSDocUnsafe) import Ormolu.Config import Ormolu.Imports (normalizeImports) import Ormolu.Parser.CommentStream@@ -33,7 +35,7 @@ -- | AST to print HsModule -> R ()-p_hsModule mstackHeader pragmas HsModule {..} = do+p_hsModule mstackHeader pragmas hsmod@HsModule {..} = do let deprecSpan = maybe [] (pure . getLocA) hsmodDeprecMessage exportSpans = maybe [] (pure . getLocA) hsmodExports switchLayout (deprecSpan <> exportSpans) $ do@@ -43,29 +45,7 @@ newline p_pragmas pragmas newline- case hsmodName of- Nothing -> return ()- Just hsmodName' -> do- located hsmodName' $ \name -> do- forM_ hsmodHaddockModHeader (p_hsDocString Pipe True)- p_hsmodName name- forM_ hsmodDeprecMessage $ \w -> do- breakpoint- located' p_moduleWarning w- breakIfNotDiffFriendly-- -- This works around an awkward idempotency bug with deprecation messages.- diffFriendly <- (==) ImportExportDiffFriendly <$> getPrinterOpt poImportExportStyle- when (diffFriendly && not (null hsmodDeprecMessage)) newline-- case hsmodExports of- Nothing -> return ()- Just l -> do- located l $ \exports -> do- inci (p_hsmodExports exports)- breakIfNotDiffFriendly- txt "where"- newline+ mapM_ (p_hsModuleHeader hsmod) hsmodName newline preserveGroups <- getPrinterOpt poRespectful forM_ (normalizeImports preserveGroups hsmodImports) $ \importGroup -> do@@ -77,3 +57,49 @@ (if preserveSpacing then p_hsDeclsRespectGrouping else p_hsDecls) Free hsmodDecls newline spitRemainingComments++p_hsModuleHeader :: HsModule -> LocatedA ModuleName -> R ()+p_hsModuleHeader HsModule {..} moduleName = do+ located moduleName $ \name -> do+ forM_ hsmodHaddockModHeader (p_hsDocString Pipe True)+ p_hsmodName name++ forM_ hsmodDeprecMessage $ \w -> do+ breakpoint+ located' p_moduleWarning w++ isRespectful <- getPrinterOpt poRespectful+ isDiffFriendly <- (== ImportExportDiffFriendly) <$> getPrinterOpt poImportExportStyle+ let breakpointBeforeExportList =+ case (hsmodDeprecMessage, hsmodExports) of+ _ | not isDiffFriendly -> breakpoint+ (Nothing, _) -> space+ (Just _, Just exports) | (not . isOneLineSpan) (getLocA exports) -> space+ _ -> breakpoint+ breakpointBeforeWhere+ | not isRespectful = breakpointBeforeExportList+ | isOnSameLine moduleKeyword whereKeyword = space+ | Just closeParen <- exportClosePSpan, isOnSameLine closeParen whereKeyword = space+ | otherwise = newline++ case hsmodExports of+ Nothing -> return ()+ Just l -> do+ breakpointBeforeExportList+ located l $ \exports -> do+ inci (p_hsmodExports exports)++ breakpointBeforeWhere+ txt "where"+ newline+ where+ (moduleKeyword, whereKeyword) =+ case am_main (anns hsmodAnn) of+ -- [AnnModule, AnnWhere] or [AnnSignature, AnnWhere]+ [AddEpAnn _ moduleLoc, AddEpAnn AnnWhere whereLoc] ->+ (epaLocationRealSrcSpan moduleLoc, epaLocationRealSrcSpan whereLoc)+ anns -> error $ "Module had unexpected annotations: " ++ showSDocUnsafe (ppr anns)+ exportClosePSpan = do+ AddEpAnn AnnCloseP loc <- al_close . anns . ann . getLoc =<< hsmodExports+ Just $ epaLocationRealSrcSpan loc+ isOnSameLine token1 token2 = srcSpanEndLine token1 == srcSpanStartLine token2
src/Ormolu/Printer/Meat/Type.hs view
@@ -8,6 +8,8 @@ module Ormolu.Printer.Meat.Type ( p_hsType, p_hsTypePostDoc,+ startTypeAnnotation,+ startTypeAnnotationDecl, hasDocStrings, p_hsContext, p_hsTyVarBndr,@@ -23,7 +25,6 @@ where import Control.Monad-import Data.Bool (bool) import Data.Foldable (for_) import GHC.Hs import GHC.Types.Basic hiding (isPromoted)@@ -33,24 +34,12 @@ import Ormolu.Config import Ormolu.Config.Types (FunctionArrowsStyle (..)) import Ormolu.Printer.Combinators-import Ormolu.Printer.Internal (PrevTypeCtx (..), enterLayout, getPrevTypeCtx, setPrevTypeCtx) import Ormolu.Printer.Meat.Common import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration.OpTree (p_tyOpTree, tyOpTree) import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration.Value (p_hsSplice, p_stringLit) import Ormolu.Printer.Operators import Ormolu.Utils --- | Render an "PrevTypeCtx" infix-p_after :: Bool -> R ()-p_after multilineArgs =- getPrevTypeCtx >>= \case- TypeCtxStart -> pure ()- TypeCtxForall | multilineArgs -> txt " ." >> space- TypeCtxForall -> txt "." >> space- TypeCtxContext -> txt "=>" >> space- TypeCtxArgument -> txt "->" >> space---- | Like 'p_hsType' but indent properly following a forall p_hsType :: HsType GhcPs -> R () p_hsType t = do s <-@@ -71,28 +60,20 @@ p_hsType' :: Bool -> TypeDocStyle -> HsType GhcPs -> R () p_hsType' multilineArgs docStyle = \case HsForAllTy _ tele t -> do- case tele of- HsForAllInvis _ bndrs -> p_forallBndrs' ForAllInvis p_hsTyVarBndr bndrs- HsForAllVis _ bndrs -> p_forallBndrs' ForAllVis p_hsTyVarBndr bndrs+ vis <-+ case tele of+ HsForAllInvis _ bndrs -> p_forallBndrsStart p_hsTyVarBndr bndrs >> pure ForAllInvis+ HsForAllVis _ bndrs -> p_forallBndrsStart p_hsTyVarBndr bndrs >> pure ForAllVis getPrinterOpt poFunctionArrows >>= \case- LeadingArrows | multilineArgs -> pure ()- _ -> p_after False >> setPrevTypeCtx TypeCtxStart- interArgBreak+ LeadingArrows | multilineArgs -> interArgBreak >> txt " " >> p_forallBndrsEnd vis+ _ -> p_forallBndrsEnd vis >> interArgBreak p_hsTypeR (unLoc t) HsQualTy _ qs' t -> do- getPrinterOpt poFunctionArrows >>= \case- LeadingArrows -> do- after <- getPrevTypeCtx- bool id (inciByExact 3) (after == TypeCtxForall) $ for_ qs' $ \qs -> do- located qs p_hsContext- interArgBreak- TrailingArrows -> do- for_ qs' $ \qs -> do- located qs p_hsContext- space- txt "=>"- interArgBreak- setPrevTypeCtx TypeCtxContext+ for_ qs' $ \qs -> do+ located qs p_hsContext+ getPrinterOpt poFunctionArrows >>= \case+ LeadingArrows -> interArgBreak >> darrow >> space+ TrailingArrows -> space >> darrow >> interArgBreak case unLoc t of HsQualTy {} -> p_hsTypeR (unLoc t) HsFunTy {} -> p_hsTypeR (unLoc t)@@ -100,7 +81,6 @@ HsTyVar _ p n -> do case p of IsPromoted -> do- space txt "'" case showOutputable (unLoc n) of _ : '\'' : _ -> space@@ -130,32 +110,20 @@ inci $ do txt "@" located kd p_hsType- HsFunTy _ arrow x y@(L _ y') -> do+ HsFunTy _ arrow x y -> do+ let p_arrow =+ case arrow of+ HsUnrestrictedArrow _ -> rarrow+ HsLinearArrow _ _ -> lolly+ HsExplicitMult _ _ mult -> do+ txt "%"+ p_hsTypeR (unLoc mult)+ space+ rarrow+ located x p_hsType getPrinterOpt poFunctionArrows >>= \case- LeadingArrows -> do- after <- getPrevTypeCtx- bool id (inciByExact 3) (after == TypeCtxForall) (located x p_hsType)- interArgBreak- TrailingArrows -> do- located x p_hsType- space- case arrow of- HsUnrestrictedArrow _ -> txt "->"- HsLinearArrow _ _ -> txt "%1 ->"- HsExplicitMult _ _ mult -> do- txt "%"- setPrevTypeCtx TypeCtxContext- p_hsTypeR (unLoc mult)- space- txt "->"- interArgBreak- setPrevTypeCtx TypeCtxArgument- case y' of- HsFunTy {} -> do- layout <- getLayout- -- Render the comments properly, but keep the existing layout- located y (enterLayout layout . p_hsTypeR)- _ -> located y p_hsTypeR+ LeadingArrows -> interArgBreak >> located y (\y' -> p_arrow >> space >> p_hsTypeR y')+ TrailingArrows -> space >> p_arrow >> interArgBreak >> located y p_hsTypeR HsListTy _ t -> located t (brackets N . p_hsType) HsTupleTy _ tsort xs ->@@ -177,17 +145,11 @@ parens N $ sitcc $ located t p_hsType HsIParamTy _ n t -> sitcc $ do located n atom- trailingArrowType- breakpoint- leadingArrowType- inci (located t p_hsType)- HsStarTy _ _ -> txt "*"+ inci $ startTypeAnnotation t p_hsType+ HsStarTy _ _ -> star HsKindSig _ t k -> sitcc $ do located t p_hsType- trailingArrowType- breakpoint- leadingArrowType- inci (located k p_hsType)+ inci $ startTypeAnnotation k p_hsType HsSpliceTy _ splice -> p_hsSplice splice HsDocTy _ t str -> case docStyle of@@ -245,12 +207,51 @@ if multilineArgs then newline else breakpoint- p_hsTypeR m = do- getPrinterOpt poFunctionArrows >>= \case- TrailingArrows -> pure ()- LeadingArrows -> p_after multilineArgs- p_hsType' multilineArgs docStyle m+ p_hsTypeR m = p_hsType' multilineArgs docStyle m +startTypeAnnotation ::+ HasSrcSpan l =>+ GenLocated l a ->+ (a -> R ()) ->+ R ()+startTypeAnnotation = startTypeAnnotation' breakpoint breakpoint++startTypeAnnotationDecl ::+ HasSrcSpan l =>+ GenLocated l a ->+ (a -> HsType GhcPs) ->+ (a -> R ()) ->+ R ()+startTypeAnnotationDecl lItem getType =+ startTypeAnnotation'+ ( if hasDocStrings $ getType $ unLoc lItem+ then newline+ else breakpoint+ )+ breakpoint+ lItem++startTypeAnnotation' ::+ HasSrcSpan l =>+ R () ->+ R () ->+ GenLocated l a ->+ (a -> R ()) ->+ R ()+startTypeAnnotation' breakTrailing breakLeading lItem renderItem =+ getPrinterOpt poFunctionArrows >>= \case+ TrailingArrows -> do+ space+ dcolon+ breakTrailing+ located lItem renderItem+ LeadingArrows -> do+ breakLeading+ located lItem $ \item -> do+ dcolon+ space+ renderItem item+ -- | Return 'True' if at least one argument in 'HsType' has a doc string -- attached to it. hasDocStrings :: HsType GhcPs -> Bool@@ -284,32 +285,29 @@ (if isInferred flag then braces N else id) $ p_rdrName x KindedTyVar _ flag l k -> (if isInferred flag then braces else parens) N . sitcc $ do located l atom- trailingArrowType- breakpoint- leadingArrowType- inci (located k p_hsType)+ inci $ startTypeAnnotation k p_hsType data ForAllVisibility = ForAllInvis | ForAllVis -- | Render several @forall@-ed variables. p_forallBndrs :: ForAllVisibility -> (a -> R ()) -> [LocatedA a] -> R () p_forallBndrs vis p tyvars = do- p_forallBndrs' vis p tyvars- p_after False+ p_forallBndrsStart p tyvars+ p_forallBndrsEnd vis -p_forallBndrs' :: ForAllVisibility -> (a -> R ()) -> [LocatedA a] -> R ()-p_forallBndrs' ForAllInvis _ [] = txt "forall" >> setPrevTypeCtx TypeCtxForall-p_forallBndrs' ForAllVis _ [] = txt "forall" >> space >> setPrevTypeCtx TypeCtxArgument-p_forallBndrs' vis p tyvars = do+p_forallBndrsStart :: (a -> R ()) -> [LocatedA a] -> R ()+p_forallBndrsStart _ [] = forall+p_forallBndrsStart p tyvars = do switchLayout (getLocA <$> tyvars) $ do- txt "forall"+ forall breakpoint inci $ do sitcc $ sep breakpoint (sitcc . located' p) tyvars- case vis of- ForAllInvis -> setPrevTypeCtx TypeCtxForall- ForAllVis -> space >> setPrevTypeCtx TypeCtxArgument +p_forallBndrsEnd :: ForAllVisibility -> R ()+p_forallBndrsEnd ForAllInvis = txt "." >> space+p_forallBndrsEnd ForAllVis = space >> rarrow+ p_conDeclFields :: [LConDeclField GhcPs] -> R () p_conDeclFields xs = braces N $ sep commaDel (sitcc . located' p_conDeclField) xs@@ -327,12 +325,12 @@ getPrinterOpt poFunctionArrows >>= \case LeadingArrows -> inci $ do breakpoint- txt "::"+ dcolon space p_hsType (unLoc cd_fld_type) TrailingArrows -> do space- txt "::"+ dcolon breakpoint sitcc . inci $ p_hsType (unLoc cd_fld_type) when (commaStyle == Leading) $
tests/Ormolu/Config/PrinterOptsSpec.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} @@ -9,11 +10,15 @@ -- testing. module Ormolu.Config.PrinterOptsSpec (spec) where +import Control.Exception (catch) import Control.Monad (forM_, when) import Data.Algorithm.DiffContext (getContextDiff, prettyContextDiff)+import Data.Char (isSpace)+import qualified Data.List.NonEmpty as NE import Data.Maybe (isJust) import Data.Text (Text) import qualified Data.Text as T+import GHC.Stack (withFrozenCallStack) import Ormolu ( Config (..), PrinterOpts (..),@@ -23,10 +28,13 @@ detectSourceType, ormolu, )+import Ormolu.Exception (OrmoluException, printOrmoluException)+import Ormolu.Terminal (ColorMode (..), runTerm) import Ormolu.Utils.IO (readFileUtf8, writeFileUtf8) import Path ( File, Path,+ Rel, fromRelFile, parseRelDir, parseRelFile,@@ -35,9 +43,12 @@ ) import Path.IO (doesFileExist) import System.Environment (lookupEnv)+import System.IO (hClose)+import System.IO.Temp (withSystemTempFile) import System.IO.Unsafe (unsafePerformIO) import Test.Hspec import qualified Text.PrettyPrint as Doc+import Text.Printf (printf) data TestGroup = forall a. TestGroup@@ -50,8 +61,17 @@ spec :: Spec spec =+ sequence_+ [ singleTests,+ multiTests+ ]++-- Tests where each test group is a directory with an `input.hs` file and multiple `output-*.hs`+-- files that could be regenerated with ORMOLU_REGENERATE_EXAMPLES.+singleTests :: Spec+singleTests = mapM_- runTestGroup+ (runTestGroup False) [ TestGroup { label = "indentation", testCases = (,) <$> [2, 3, 4] <*> allOptions,@@ -116,6 +136,27 @@ testCaseSuffix = suffix1 }, TestGroup+ { label = "let-style",+ testCases = (,,) <$> allOptions <*> allOptions <*> [2, 4],+ updateConfig = \(letStyle, inStyle, indent) opts ->+ opts+ { poIndentation = pure indent,+ poLetStyle = pure letStyle,+ poInStyle = pure inStyle+ },+ showTestCase = \(letStyle, inStyle, indent) ->+ printf "%s + %s (indent=%d)" (show letStyle) (show inStyle) indent,+ testCaseSuffix = \(letStyle, inStyle, indent) ->+ suffixWith [show letStyle, show inStyle, "indent=" ++ show indent]+ },+ TestGroup+ { label = "unicode-syntax",+ testCases = allOptions,+ updateConfig = \unicodePreference options -> options {poUnicode = pure unicodePreference},+ showTestCase = show,+ testCaseSuffix = suffix1+ },+ TestGroup { label = "respectful", testCases = allOptions, updateConfig = \respectful opts -> opts {poRespectful = pure respectful},@@ -123,42 +164,45 @@ testCaseSuffix = suffix1 } ]- where- allOptions :: (Enum a, Bounded a) => [a]- allOptions = [minBound .. maxBound] - suffixWith xs = concatMap ('-' :) . filter (not . null) $ xs- suffix1 a1 = suffixWith [show a1]+-- Same as 'singleTests', except with input taken from 'input-multi.hs', where sections+-- delimited by `{- // -}` will be formatted as separate Haskell files. Useful for testing+-- combinations of module headers, which is normally only allowed once.+multiTests :: Spec+multiTests =+ mapM_+ (runTestGroup True)+ [ TestGroup+ { label = "respectful-module-where",+ testCases = (,) <$> allOptions <*> allOptions,+ updateConfig = \(respectful, importExportStyle) opts ->+ opts+ { poRespectful = pure respectful,+ poImportExportStyle = pure importExportStyle+ },+ showTestCase = \(respectful, importExportStyle) ->+ (if respectful then "respectful" else "not respectful") ++ " + " ++ show importExportStyle,+ testCaseSuffix = \(respectful, importExportStyle) ->+ suffixWith ["respectful=" ++ show respectful, show importExportStyle]+ }+ ] -runTestGroup :: TestGroup -> Spec-runTestGroup TestGroup {..} =+runTestGroup :: Bool -> TestGroup -> Spec+runTestGroup isMulti TestGroup {..} = describe label $ forM_ testCases $ \testCase -> it ("generates the correct output for: " ++ showTestCase testCase) $ do- let inputFile = testDir </> toRelFile "input.hs"+ let inputFile = testDir </> toRelFile (if isMulti then "input-multi.hs" else "input.hs") inputPath = fromRelFile inputFile outputFile = testDir </> toRelFile ("output" ++ testCaseSuffix testCase ++ ".hs")- outputPath = fromRelFile outputFile- config =- defaultConfig- { cfgPrinterOpts = updateConfig testCase defaultPrinterOpts,- cfgSourceType = detectSourceType inputPath,- cfgCheckIdempotence = True- }- runOrmolu path = ormolu config path . T.unpack+ opts = updateConfig testCase defaultPrinterOpts input <- readFileUtf8 inputPath- actual <- runOrmolu inputPath input- mExpected <- getFileContents outputFile- case (shouldRegenerateOutput, mExpected) of- (False, Nothing) ->- expectationFailure "Output does not exist. Try running with ORMOLU_REGENERATE_EXAMPLES=1"- (False, Just expected) ->- when (actual /= expected) $- expectationFailure . T.unpack $- getDiff ("actual", actual) ("expected", expected)- (True, _) ->- writeFileUtf8 outputPath actual+ actual <-+ if isMulti+ then overSectionsM (T.pack "{- // -}") (runOrmolu opts inputPath) input+ else runOrmolu opts inputPath input+ checkResult outputFile actual where testDir = toRelDir $ "data/fourmolu/" ++ label toRelDir name =@@ -170,8 +214,48 @@ Just path -> path Nothing -> error $ "Not a valid file name: " ++ show name +runOrmolu :: PrinterOptsTotal -> FilePath -> Text -> IO Text+runOrmolu opts inputPath input =+ ormolu config inputPath (T.unpack input) `catch` \e -> do+ msg <- renderOrmoluException e+ expectationFailure' $ unlines ["Got ormolu exception:", "", msg]+ where+ config =+ defaultConfig+ { cfgPrinterOpts = opts,+ cfgSourceType = detectSourceType inputPath,+ cfgCheckIdempotence = True+ }++checkResult :: Path Rel File -> Text -> Expectation+checkResult outputFile actual+ | shouldRegenerateOutput = writeFileUtf8 (fromRelFile outputFile) actual+ | otherwise =+ getFileContents outputFile >>= \case+ Nothing ->+ expectationFailure "Output does not exist. Try running with ORMOLU_REGENERATE_EXAMPLES=1"+ Just expected ->+ when (actual /= expected) $+ expectationFailure . T.unpack $+ getDiff ("actual", actual) ("expected", expected)+ {--- Helpers ---} +allOptions :: (Enum a, Bounded a) => [a]+allOptions = [minBound .. maxBound]++suffixWith :: [String] -> String+suffixWith xs = concatMap ('-' :) . filter (not . null) $ xs++suffix1 :: Show a => a -> String+suffix1 a1 = suffixWith [show a1]++overSectionsM :: Monad m => Text -> (Text -> m Text) -> Text -> m Text+overSectionsM delim f =+ fmap T.concat+ . mapM (\(s, isDelim) -> if isDelim then pure s else f s)+ . splitOnDelim delim+ getFileContents :: Path b File -> IO (Maybe Text) getFileContents path = do fileExists <- doesFileExist path@@ -185,8 +269,59 @@ prettyContextDiff (Doc.text s1Name) (Doc.text s2Name) (Doc.text . T.unpack) $ getContextDiff 2 (T.lines s1) (T.lines s2) +renderOrmoluException :: OrmoluException -> IO String+renderOrmoluException e =+ withSystemTempFile "PrinterOptsSpec" $ \fp handle -> do+ runTerm (printOrmoluException e) Never handle+ hClose handle+ readFile fp++expectationFailure' :: HasCallStack => String -> IO a+expectationFailure' msg = do+ withFrozenCallStack $ expectationFailure msg+ -- satisfy type-checker, since hspec's expectationFailure is IO ()+ error "unreachable"+ shouldRegenerateOutput :: Bool shouldRegenerateOutput = -- Use same env var as PrinterSpec.hs, to make it easy to regenerate everything at once unsafePerformIO $ isJust <$> lookupEnv "ORMOLU_REGENERATE_EXAMPLES" {-# NOINLINE shouldRegenerateOutput #-}++{--- Utilities ---}++-- | Group delimiter (including surrounding whitespace) and non-delimiter lines+-- and annotate lines with a Bool indicating if the group is a delimiter group+-- or not.+splitOnDelim :: Text -> Text -> [(Text, Bool)]+splitOnDelim delim =+ map (\(lineGroup, delimType) -> (T.unlines lineGroup, isDelim delimType))+ . collapseSpaces NonDelim+ . collapseSpaces Delim+ . groupWith toLineType+ . T.lines+ where+ toLineType line+ | T.all isSpace line = Space+ | line == delim = Delim+ | otherwise = NonDelim++ collapseSpaces delimType = \case+ (xs, Space) : (ys, ysType) : rest | ysType == delimType -> collapseSpaces delimType $ (xs ++ ys, delimType) : rest+ (xs, xsType) : (ys, Space) : rest | xsType == delimType -> collapseSpaces delimType $ (xs ++ ys, delimType) : rest+ x : rest -> x : collapseSpaces delimType rest+ [] -> []++ isDelim = \case+ Delim -> True+ NonDelim -> False+ Space -> error "isDelim called on Space, but all Spaces should've been eliminated at this point"++ -- Like 'NE.groupWith', except annotates group with comparator+ groupWith :: Eq b => (a -> b) -> [a] -> [([a], b)]+ groupWith f =+ let liftComparator xs = (map fst $ NE.toList xs, snd $ NE.head xs)+ in map liftComparator . NE.groupWith snd . map (\a -> (a, f a))++data LineType = Space | Delim | NonDelim+ deriving (Eq)