packages feed

fourmolu 0.3.0.0 → 0.4.0.0

raw patch · 288 files changed

+4627/−1394 lines, 288 filesdep +Cabaldep +Diffdep +ansi-terminaldep ~aesondep ~bytestringdep ~directoryPVP ok

version bump matches the API change (PVP)

Dependencies added: Cabal, Diff, ansi-terminal, temporary

Dependency ranges changed: aeson, bytestring, directory, filepath, ghc-lib-parser, path

API changes (from Hackage documentation)

- Ormolu.Diff: Different :: [SrcSpan] -> Diff
- Ormolu.Diff: Same :: Diff
- Ormolu.Diff: data Diff
- Ormolu.Diff: diffParseResult :: ParseResult -> ParseResult -> Diff
- Ormolu.Diff: diffText :: Text -> Text -> FilePath -> Maybe (RealSrcLoc, Text, Text)
- Ormolu.Diff: instance GHC.Base.Monoid Ormolu.Diff.Diff
- Ormolu.Diff: instance GHC.Base.Semigroup Ormolu.Diff.Diff
- Ormolu.Parser.Result: [prImportQualifiedPost] :: ParseResult -> Bool
- Ormolu.Parser.Result: [prLiteralPrefix] :: ParseResult -> Text
- Ormolu.Parser.Result: [prLiteralSuffix] :: ParseResult -> Text
- Ormolu.Parser.Result: [prShebangs] :: ParseResult -> [Shebang]
- Ormolu.Parser.Result: prettyPrintParseResult :: ParseResult -> String
- Ormolu.Parser.Shebang: Shebang :: Located String -> Shebang
- Ormolu.Parser.Shebang: extractShebangs :: [Located String] -> ([Shebang], [Located String])
- Ormolu.Parser.Shebang: instance Data.Data.Data Ormolu.Parser.Shebang.Shebang
- Ormolu.Parser.Shebang: instance GHC.Classes.Eq Ormolu.Parser.Shebang.Shebang
- Ormolu.Parser.Shebang: isShebang :: String -> Bool
- Ormolu.Parser.Shebang: newtype Shebang
- Ormolu.Printer.Combinators: inciBy :: Int -> R () -> R ()
- Ormolu.Processing.Common: OrmoluDisabled :: OrmoluState
- Ormolu.Processing.Common: OrmoluEnabled :: OrmoluState
- Ormolu.Processing.Common: data OrmoluState
- Ormolu.Processing.Common: endDisabling :: IsString s => s
- Ormolu.Processing.Common: instance GHC.Classes.Eq Ormolu.Processing.Common.OrmoluState
- Ormolu.Processing.Common: instance GHC.Show.Show Ormolu.Processing.Common.OrmoluState
- Ormolu.Processing.Common: startDisabling :: IsString s => s
- Ormolu.Processing.Cpp: InConditional :: State
- Ormolu.Processing.Cpp: InContinuation :: State
- Ormolu.Processing.Cpp: Outside :: State
- Ormolu.Processing.Cpp: data State
- Ormolu.Processing.Cpp: processLine :: String -> State -> (String, State)
- Ormolu.Processing.Cpp: unmaskLine :: Text -> Text
- Ormolu.Processing.Postprocess: postprocess :: Int -> Text -> Text
- Ormolu.Utils: removeIndentation :: String -> (String, Int)
- Ormolu.Utils: typeArgToType :: LHsTypeArg p -> LHsType p
+ Ormolu: Always :: ColorMode
+ Ormolu: Auto :: ColorMode
+ Ormolu: Never :: ColorMode
+ Ormolu: OrmoluCabalFileParsingFailed :: FilePath -> OrmoluException
+ Ormolu: OrmoluMissingStdinInputFile :: OrmoluException
+ Ormolu: [cfgColorMode] :: Config region -> !ColorMode
+ Ormolu: data ColorMode
+ Ormolu.Config: Always :: ColorMode
+ Ormolu.Config: Auto :: ColorMode
+ Ormolu.Config: Never :: ColorMode
+ Ormolu.Config: [cfgColorMode] :: Config region -> !ColorMode
+ Ormolu.Config: data ColorMode
+ Ormolu.Diff.ParseResult: Different :: [SrcSpan] -> ParseResultDiff
+ Ormolu.Diff.ParseResult: Same :: ParseResultDiff
+ Ormolu.Diff.ParseResult: data ParseResultDiff
+ Ormolu.Diff.ParseResult: diffParseResult :: ParseResult -> ParseResult -> ParseResultDiff
+ Ormolu.Diff.ParseResult: instance GHC.Base.Monoid Ormolu.Diff.ParseResult.ParseResultDiff
+ Ormolu.Diff.ParseResult: instance GHC.Base.Semigroup Ormolu.Diff.ParseResult.ParseResultDiff
+ Ormolu.Diff.Text: data TextDiff
+ Ormolu.Diff.Text: diffText :: Text -> Text -> FilePath -> Maybe TextDiff
+ Ormolu.Diff.Text: instance GHC.Classes.Eq Ormolu.Diff.Text.TextDiff
+ Ormolu.Diff.Text: instance GHC.Show.Show Ormolu.Diff.Text.TextDiff
+ Ormolu.Diff.Text: printTextDiff :: TextDiff -> Term ()
+ Ormolu.Exception: OrmoluCabalFileParsingFailed :: FilePath -> OrmoluException
+ Ormolu.Exception: OrmoluMissingStdinInputFile :: OrmoluException
+ Ormolu.Parser.Result: ParsedSnippet :: ParseResult -> SourceSnippet
+ Ormolu.Parser.Result: RawSnippet :: Text -> SourceSnippet
+ Ormolu.Parser.Result: [prExtensions] :: ParseResult -> EnumSet Extension
+ Ormolu.Parser.Result: data SourceSnippet
+ Ormolu.Printer.Combinators: inciByFrac :: Int -> R () -> R ()
+ Ormolu.Printer.Combinators: inciHalf :: R () -> R ()
+ Ormolu.Printer.Combinators: isExtensionEnabled :: Extension -> R Bool
+ Ormolu.Printer.Combinators: realLocated :: RealLocated a -> (a -> R ()) -> R ()
+ Ormolu.Printer.Combinators: recordDotBraces :: R () -> R ()
+ Ormolu.Printer.Internal: inciByFrac :: Int -> R () -> R ()
+ Ormolu.Printer.Internal: inciHalf :: R () -> R ()
+ Ormolu.Printer.Internal: isExtensionEnabled :: Extension -> R Bool
+ Ormolu.Printer.Meat.Common: p_sourceText :: SourceText -> R ()
+ Ormolu.Printer.Meat.Type: ForAllInvis :: ForAllVisibility
+ Ormolu.Printer.Meat.Type: ForAllVis :: ForAllVisibility
+ Ormolu.Printer.Meat.Type: data ForAllVisibility
+ Ormolu.Printer.Meat.Type: instance Ormolu.Printer.Meat.Type.IsInferredTyVarBndr ()
+ Ormolu.Printer.Meat.Type: instance Ormolu.Printer.Meat.Type.IsInferredTyVarBndr GHC.Types.Var.Specificity
+ Ormolu.Printer.Meat.Type: p_lhsTypeArg :: LHsTypeArg GhcPs -> R ()
+ Ormolu.Printer.Meat.Type: tyVarsToTyPats :: LHsQTyVars GhcPs -> HsTyPats GhcPs
+ Ormolu.Processing.Common: intSetToRegions :: Int -> IntSet -> [RegionDeltas]
+ Ormolu.Processing.Common: linesInRegion :: RegionDeltas -> String -> String
+ Ormolu.Processing.Common: regionInbetween :: Int -> RegionDeltas -> RegionDeltas -> RegionDeltas
+ Ormolu.Processing.Common: reindent :: Int -> Text -> Text
+ Ormolu.Processing.Common: removeIndentation :: String -> (String, Int)
+ Ormolu.Processing.Cpp: cppLines :: String -> IntSet
+ Ormolu.Processing.Preprocess: instance GHC.Classes.Eq Ormolu.Processing.Preprocess.OrmoluState
+ Ormolu.Processing.Preprocess: instance GHC.Show.Show Ormolu.Processing.Preprocess.OrmoluState
+ Ormolu.Terminal: Always :: ColorMode
+ Ormolu.Terminal: Auto :: ColorMode
+ Ormolu.Terminal: Never :: ColorMode
+ Ormolu.Terminal: bold :: Term a -> Term a
+ Ormolu.Terminal: cyan :: Term a -> Term a
+ Ormolu.Terminal: data ColorMode
+ Ormolu.Terminal: data Term a
+ Ormolu.Terminal: green :: Term a -> Term a
+ Ormolu.Terminal: instance GHC.Base.Applicative Ormolu.Terminal.Term
+ Ormolu.Terminal: instance GHC.Base.Functor Ormolu.Terminal.Term
+ Ormolu.Terminal: instance GHC.Base.Monad Ormolu.Terminal.Term
+ Ormolu.Terminal: instance GHC.Classes.Eq Ormolu.Terminal.ColorMode
+ Ormolu.Terminal: instance GHC.Enum.Bounded Ormolu.Terminal.ColorMode
+ Ormolu.Terminal: instance GHC.Enum.Enum Ormolu.Terminal.ColorMode
+ Ormolu.Terminal: instance GHC.Show.Show Ormolu.Terminal.ColorMode
+ Ormolu.Terminal: newline :: Term ()
+ Ormolu.Terminal: put :: Text -> Term ()
+ Ormolu.Terminal: putS :: String -> Term ()
+ Ormolu.Terminal: putSrcSpan :: SrcSpan -> Term ()
+ Ormolu.Terminal: red :: Term a -> Term a
+ Ormolu.Terminal: runTerm :: Term a -> ColorMode -> Handle -> IO a
+ Ormolu.Utils.Extensions: DisableExtension :: KnownExtension -> Extension
+ Ormolu.Utils.Extensions: EnableExtension :: KnownExtension -> Extension
+ Ormolu.Utils.Extensions: UnknownExtension :: String -> Extension
+ Ormolu.Utils.Extensions: data Extension
+ Ormolu.Utils.Extensions: findCabalFile :: MonadIO m => FilePath -> m (Maybe FilePath)
+ Ormolu.Utils.Extensions: getCabalExtensionDynOptions :: MonadIO m => FilePath -> m [DynOption]
+ Ormolu.Utils.Extensions: getExtensionsFromCabalFile :: MonadIO m => FilePath -> m (Map FilePath [DynOption])
+ Ormolu.Utils.IO: readFileUtf8 :: MonadIO m => FilePath -> m Text
+ Ormolu.Utils.IO: writeFileUtf8 :: MonadIO m => FilePath -> Text -> m ()
- Ormolu: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !region -> !PrinterOptsTotal -> Config region
+ Ormolu: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !ColorMode -> !region -> !PrinterOptsTotal -> Config region
- Ormolu: OrmoluNonIdempotentOutput :: RealSrcLoc -> Text -> Text -> OrmoluException
+ Ormolu: OrmoluNonIdempotentOutput :: TextDiff -> OrmoluException
- Ormolu: withPrettyOrmoluExceptions :: IO a -> IO a
+ Ormolu: withPrettyOrmoluExceptions :: ColorMode -> IO ExitCode -> IO ExitCode
- Ormolu.Config: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !region -> !PrinterOptsTotal -> Config region
+ Ormolu.Config: Config :: ![DynOption] -> !Bool -> !Bool -> !Bool -> !ColorMode -> !region -> !PrinterOptsTotal -> Config region
- Ormolu.Exception: OrmoluNonIdempotentOutput :: RealSrcLoc -> Text -> Text -> OrmoluException
+ Ormolu.Exception: OrmoluNonIdempotentOutput :: TextDiff -> OrmoluException
- Ormolu.Exception: withPrettyOrmoluExceptions :: IO a -> IO a
+ Ormolu.Exception: withPrettyOrmoluExceptions :: ColorMode -> IO ExitCode -> IO ExitCode
- Ormolu.Parser: parseModule :: MonadIO m => Config RegionDeltas -> FilePath -> String -> m ([Warn], Either (SrcSpan, String) ParseResult)
+ Ormolu.Parser: parseModule :: MonadIO m => Config RegionDeltas -> FilePath -> String -> m ([Warn], Either (SrcSpan, String) [SourceSnippet])
- Ormolu.Parser.CommentStream: mkCommentStream :: String -> [Located String] -> PState -> (Maybe (RealLocated Comment), [Shebang], [([RealLocated Comment], Pragma)], CommentStream)
+ Ormolu.Parser.CommentStream: mkCommentStream :: String -> PState -> (Maybe (RealLocated Comment), [([RealLocated Comment], Pragma)], CommentStream)
- Ormolu.Parser.Result: ParseResult :: HsModule GhcPs -> Anns -> Maybe (RealLocated Comment) -> [Shebang] -> [([RealLocated Comment], Pragma)] -> CommentStream -> Bool -> Bool -> Text -> Text -> Int -> ParseResult
+ Ormolu.Parser.Result: ParseResult :: HsModule -> Anns -> Maybe (RealLocated Comment) -> [([RealLocated Comment], Pragma)] -> CommentStream -> Bool -> EnumSet Extension -> Int -> ParseResult
- Ormolu.Parser.Result: [prParsedSource] :: ParseResult -> HsModule GhcPs
+ Ormolu.Parser.Result: [prParsedSource] :: ParseResult -> HsModule
- Ormolu.Printer: printModule :: ParseResult -> PrinterOptsTotal -> Text
+ Ormolu.Printer: printModule :: [SourceSnippet] -> PrinterOptsTotal -> Text
- Ormolu.Printer.Combinators: banana :: R () -> R ()
+ Ormolu.Printer.Combinators: banana :: BracketStyle -> R () -> R ()
- Ormolu.Printer.Combinators: runR :: R () -> SpanStream -> CommentStream -> Anns -> PrinterOptsTotal -> Bool -> Text
+ Ormolu.Printer.Combinators: runR :: R () -> SpanStream -> CommentStream -> Anns -> PrinterOptsTotal -> Bool -> EnumSet Extension -> Text
- Ormolu.Printer.Internal: runR :: R () -> SpanStream -> CommentStream -> Anns -> PrinterOptsTotal -> Bool -> Text
+ Ormolu.Printer.Internal: runR :: R () -> SpanStream -> CommentStream -> Anns -> PrinterOptsTotal -> Bool -> EnumSet Extension -> Text
- Ormolu.Printer.Meat.Declaration.Data: p_dataDecl :: FamilyStyle -> Located RdrName -> [LHsType GhcPs] -> LexicalFixity -> HsDataDefn GhcPs -> R ()
+ Ormolu.Printer.Meat.Declaration.Data: p_dataDecl :: FamilyStyle -> Located RdrName -> HsTyPats GhcPs -> LexicalFixity -> HsDataDefn GhcPs -> R ()
- Ormolu.Printer.Meat.ImportExport: p_hsmodImport :: Bool -> ImportDecl GhcPs -> R ()
+ Ormolu.Printer.Meat.ImportExport: p_hsmodImport :: ImportDecl GhcPs -> R ()
- Ormolu.Printer.Meat.Module: p_hsModule :: Maybe (RealLocated Comment) -> [Shebang] -> [([RealLocated Comment], Pragma)] -> Bool -> HsModule GhcPs -> R ()
+ Ormolu.Printer.Meat.Module: p_hsModule :: Maybe (RealLocated Comment) -> [([RealLocated Comment], Pragma)] -> HsModule -> R ()
- Ormolu.Printer.Meat.Type: p_forallBndrs :: Data a => ForallVisFlag -> (a -> R ()) -> [Located a] -> R ()
+ Ormolu.Printer.Meat.Type: p_forallBndrs :: Data a => ForAllVisibility -> (a -> R ()) -> [Located a] -> R ()
- Ormolu.Printer.Meat.Type: p_hsTyVarBndr :: HsTyVarBndr GhcPs -> R ()
+ Ormolu.Printer.Meat.Type: p_hsTyVarBndr :: IsInferredTyVarBndr flag => HsTyVarBndr flag GhcPs -> R ()
- Ormolu.Processing.Preprocess: preprocess :: FilePath -> String -> RegionDeltas -> (String, String, String, [Located String])
+ Ormolu.Processing.Preprocess: preprocess :: Bool -> RegionDeltas -> String -> [Either Text RegionDeltas]

Files

CHANGELOG.md view
@@ -1,3 +1,162 @@+## Fourmolu 0.4.0.0++* Write "Loaded config from" message to `stderr` instead of `stdout` ([#42](https://github.com/fourmolu/fourmolu/pull/42))+* Fixed issue with multiline haddocks in indented contexts ([#64](https://github.com/fourmolu/fourmolu/pull/64))+* Avoid renaming magic comments ([#90](https://github.com/fourmolu/fourmolu/pull/90))++### Upstream changes:++#### Ormolu 0.3.0.1++* Improvements to `.cabal` file handling:+   * When looking for a `.cabal` file, directories were previously+     erroneously also considered. [Issue 781](+     https://github.com/tweag/ormolu/issues/781).+   * We now print a note if Ormolu was told to consider+     `.cabal` files, but no suitable one could be found.+   * Handle an empty `hs-source-dirs` correctly.+   * Also consider modules which are only conditionally listed+     in the `.cabal` file.++* The special handling of CPP is now only applied if CPP is+  actually enabled. [Issue 782](https://github.com/tweag/ormolu/issues/782).++* The left hand side of the `:` operator now uses braces if+  necessary. [Issue 780](https://github.com/tweag/ormolu/issues/780).++#### Ormolu 0.3.0.0++* Data declarations with multiline kind signatures are now formatted+  correctly. [Issue 749](https://github.com/tweag/ormolu/issues/749).++* Infix arrow command formations are formatted like usual operators.+  This fixes [Issue 748](https://github.com/tweag/ormolu/issues/748).++* `do` arrow commands are formatted more flexibly. Fixes [Issue+  753](https://github.com/tweag/ormolu/issues/753).++* Source code is always read and written using UTF8 and ignoring the native+  line ending conventions. [Issue+  717](https://github.com/tweag/ormolu/issues/717).++* Opt-in support to respect default-extensions and default-language+  from .cabal files. [Issue 517](https://github.com/tweag/ormolu/issues/517).++* Empty case expressions are now rendered with braces. [Issue+  765](https://github.com/tweag/ormolu/issues/765).++* Omit braces on repeated application of `do` blocks. [Issue+  735](https://github.com/tweag/ormolu/issues/735).++* Improved handling of disabled regions. [PR 773](+  https://github.com/tweag/ormolu/pull/773).+   * Disabled regions are now exactly preserved, in particular+     empty lines and trailing spaces. [Issue+     673](https://github.com/tweag/ormolu/issues/673).+   * Strings like `-}` can now be present in disabled regions.+     [Issue 708](https://github.com/tweag/ormolu/issues/708).++  This means that using CPP or magic comments in certain ways which+  were only supported as a side effect previously (like in+  [Issue 601](https://github.com/tweag/ormolu/issues/601))+  will now result in formatting failures. Also see [Issue 774](+  https://github.com/tweag/ormolu/issues/774).++#### Ormolu 0.2.0.0++* Now standalone kind signatures are grouped with type synonyms. [Issue+  683](https://github.com/tweag/ormolu/issues/683).++* `TemplateHaskell` is not enabled by default anymore. [Issue+  699](https://github.com/tweag/ormolu/issues/699).++* Made record dot pre-processor rendering idempotent in certain specific+  cases. [Issue 701](https://github.com/tweag/ormolu/issues/701).++* Added support for arrow command application. [Issue+  716](https://github.com/tweag/ormolu/issues/716).++* Switched to `ghc-lib-parser-9.0.1`. [PR+  722](https://github.com/tweag/ormolu/pull/722).+   * Support for the new language extensions:+      * `LexicalNegation`, `LinearTypes`: disabled by default+      * `QualifiedDo`: enabled by default+   * Due to [upstream changes in whitespace sensitity](+     https://gitlab.haskell.org/ghc/ghc/-/wikis/migration/9.0#whitespace-sensitive-and-),+     `TypeApplications` is now *enabled* by default. [Issue+     452](https://github.com/tweag/ormolu/issues/452).+   * Haddocks on declarations in files without a `module` header are no longer+     deleted. [Issue 480](https://github.com/tweag/ormolu/issues/480).+   * Due to a change in Haddock parsing, empty Haddock comments on function+     arguments now get deleted.++* CTYPE pragmas are now preserved. [Issue 689](+  https://github.com/tweag/ormolu/issues/689).++* `TypeApplications` in data/type family instances are now supported. [Issue+  698](https://github.com/tweag/ormolu/issues/698).++* Formatting infix arrow command formations now preserves the AST. [Issue+  718](https://github.com/tweag/ormolu/issues/718).++* Surround code in brackets with spaces if it contains a `StarIsType` `*` to+  prevent unparseable output. [Issue 704](https://github.com/tweag/ormolu/issues/704).++* Formatting applied multiline constructs in do blocks now preserves the AST.+  [Issue 707](https://github.com/tweag/ormolu/issues/707).++  This will sometimes result in odd indentations, e.g. this snippet is a+  fixed point:+  ```haskell+  foo = do+    do+      (+1)+     1+  ```++* GHC options passed in via the CLI can now be overridden in local files.+  Previously, if an extension was disabled via the CLI, it could not be+  re-enabled per file.++* `NegativeLiterals` is no longer enabled by default. Also, spaces after+  negation via `-` are removed where possible. [Issue+  694](https://github.com/tweag/ormolu/issues/694).++* Minus signs in literal patterns are now preserved in all cases. [Issue+  733](https://github.com/tweag/ormolu/issues/733).++* Added support for left-to-right arrow application. [Issue+  737](https://github.com/tweag/ormolu/issues/737).++* Now `--mode check` fails on missing trailing blank lines. [Issue+  743](https://github.com/tweag/ormolu/issues/743).++* Fixed indentation of arrow forms in do blocks. [Issue+  739](https://github.com/tweag/ormolu/issues/739).++#### Ormolu 0.1.4.1++* Added command line option `--color` to control how diffs are printed.+  Standardized the way errors are printed.++#### Ormolu 0.1.4.0++* Added support for monad comprehensions. [Issue+  665](https://github.com/tweag/ormolu/issues/665).++* Fixed a bug when a space was inserted in front of promoted types even when+  it wasn't strictly necessary. [Issue+  668](https://github.com/tweag/ormolu/issues/668).++* Now the checking mode displays diffs per file when unformatted files are+  found. The rendering of the diffs is also improved. [Issue+  656](https://github.com/tweag/ormolu/issues/656).++#### Ormolu 0.1.3.1++* Fixed a problem with multiline record updates using the record dot+  preprocessor. [Issue 658](https://github.com/tweag/ormolu/issues/658).+ ## Fourmolu 0.3.0.0  * New config option `newlines-between-decls`, to choose the number of blank lines between top-level declarations.
README.md view
@@ -3,6 +3,17 @@ [![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause) [![Hackage](https://img.shields.io/hackage/v/fourmolu.svg?style=flat)](https://hackage.haskell.org/package/fourmolu) +* [Configuration](#configuration)+* [Building and installation](#building-and-installation)+* [Usage](#usage)+    * [Editor integration](#editor-integration)+    * [Magic comments](#magic-comments)+    * [Account for .cabal files](#account-for-cabal-files)+    * [Exit codes](#exit-codes)+* [Limitations](#limitations)+* [Contributing](#contributing)+* [License](#license)+ Fourmolu is a formatter for Haskell source code. It is a fork of [Ormolu](https://github.com/tweag/ormolu), with the intention to continue to merge upstream improvements.  We share all bar one of Ormolu's goals:@@ -11,18 +22,17 @@   [`haskell-src-exts`](https://hackage.haskell.org/package/haskell-src-exts). * Let some whitespace be programmable. The layout of the input influences   the layout choices in the output. This means that the choices between-  single-line/multi-line layouts in each particular situation are made by-  the user, not by an algorithm. This makes the implementation simpler and-  leaves some control to the user while still guaranteeing that the-  formatted code is stylistically consistent.+  single-line/multi-line layouts in certain situations are made by the user,+  not by an algorithm. This makes the implementation simpler and leaves some+  control to the user while still guaranteeing that the formatted code is+  stylistically consistent. * Writing code in such a way so it's easy to modify and maintain.-* That formatting style aims to result in minimal diffs while still-  remaining very close to “conventional” Haskell formatting people use.+* That formatting style aims to result in minimal diffs. * Choose a style compatible with modern dialects of Haskell. As new Haskell   extensions enter broad use, we may change the style to accommodate them. * Idempotence: formatting already formatted code doesn't change it.-* Be well-tested and robust to the point that it can be used in large-  projects without exposing unfortunate, disappointing bugs here and there.+* Be well-tested and robust so that the formatter can be used in large+  projects. * ~~Implementing one “true” formatting style which admits no configuration.~~ We allow configuration of various parameters, via CLI options or config files. We encourage any contributions which add further flexibility.  ## Configuration@@ -44,7 +54,7 @@  These options can also be set on the command line (which takes precedence over config files). Run `fourmolu -h` to see all options. -## Building+## Building and installation  Simply run `cabal v2-install fourmolu`, to install the latest release from Hackage. @@ -70,9 +80,23 @@ $ fourmolu -i $(find . -name '*.hs') ``` +Or find all files in a project with `git ls-files`:++```console+$ fourmolu --mode inplace $(git ls-files '*.hs')+```++To check if files are are already formatted (useful on CI):++```console+$ fourmolu --mode check $(find . -name '*.hs')+```++### Editor integration+ Fourmolu can be integrated with your editor via the [Haskell Language Server](https://github.com/haskell/haskell-language-server). -## Magic comments+### Magic comments  Fourmolu understands two magic comments: @@ -89,19 +113,50 @@ This allows us to disable formatting selectively for code between these markers or disable it for the entire file. To achieve the latter, just put `{- FOURMOLU_DISABLE -}` at the very top. Note that for Fourmolu to work the-source code must still be parseable even when the disabled regions are-omitted. Because of that the magic comments cannot be placed arbitrarily,-but rather must enclose independent top-level definitions.+fragments where Ormolu is enabled must be parseable on their own. Because of+that the magic comments cannot be placed arbitrarily, but rather must+enclose independent top-level definitions. -`{- ORMOLU_DISABLE -}` and `{- ORMOLU_ENABLE -}`, respectively, can be used to the same effect.+`{- ORMOLU_DISABLE -}` and `{- ORMOLU_ENABLE -}`, respectively, can be used to the same effect,+and the two styles of magic comments can be mixed. -## Current limitations+### Account for .cabal files +Many cabal and stack projects use `default-extensions` to enable GHC+language extensions in all source files. With the+`--cabal-default-extensions` flag, Ormolu will take them into consideration+during formatting.++When you format input from stdin, you can pass `--stdin-input-file` which+will give Ormolu the location of the Haskell source file that should be used+as the starting point for searching for a suitable .cabal file.++### Exit codes++Exit code | Meaning+----------|-----------------------------------------------+0         | Success+1         | General problem+2         | CPP used (deprecated)+3         | Parsing of original input failed+4         | Parsing of formatted code failed+5         | AST of original and formatted code differs+6         | Formatting is not idempotent+7         | Unrecognized GHC options+8         | Cabal file parsing failed+9         | Missing input file path when using stdin input and accounting for .cabal files+100       | In checking mode: unformatted files+101       | Inplace and check modes do not work with stdin+102       | Other issue (with multiple input files)+400       | Failed to load Fourmolu configuration file++## Limitations+ * CPP support is experimental. CPP is virtually impossible to handle   correctly, so we process them as a sort of unchangeable snippets. This   works only in simple cases when CPP conditionals surround top-level-  declarations. See the [CPP](https://github.com/tweag/ormolu/blob/master/DESIGN.md#cpp) section in the design notes for-  a discussion of the dangers.+  declarations. See the [CPP](https://github.com/tweag/ormolu/blob/master/DESIGN.md#cpp) section in the design notes for a+  discussion of the dangers. * Input modules should be parsable by Haddock, which is a bit stricter   criterion than just being valid Haskell modules. * Various minor idempotence issues, most of them are related to comments.
app/Main.hs view
@@ -10,98 +10,134 @@  module Main (main) where -import Control.Exception (SomeException, displayException, try)+import Control.Exception (throwIO) import Control.Monad import Data.Bool (bool)-import Data.Either (lefts) import Data.Functor.Identity (Identity (..)) import Data.List (intercalate, sort)-import Data.Maybe (fromMaybe)+import Data.Maybe (fromMaybe, mapMaybe) import qualified Data.Text.IO as TIO import Data.Version (showVersion) import Development.GitRev import Options.Applicative import Ormolu import Ormolu.Config+import Ormolu.Diff.Text (diffText, printTextDiff) import Ormolu.Parser (manualExts)+import Ormolu.Terminal import Ormolu.Utils (showOutputable)+import Ormolu.Utils.Extensions (getCabalExtensionDynOptions)+import Ormolu.Utils.IO import Paths_fourmolu (version) import System.Directory (getCurrentDirectory) import System.Exit (ExitCode (..), exitWith)+import qualified System.FilePath as FP import System.IO (hPutStrLn, stderr)  -- | Entry point of the program. main :: IO ()-main = withPrettyOrmoluExceptions $ do+main = do   opts@Opts {..} <- execParser optsParserInfo-  let formatStdIn = do-        cur <- getCurrentDirectory-        cfg <- mkConfig cur opts-        formatOne optMode cfg Nothing-  case optInputFiles of-    [] -> formatStdIn-    ["-"] -> formatStdIn-    [x] -> flip (formatOne optMode) (Just x) =<< mkConfig x opts-    xs@(x : _) -> do-      cfg <- mkConfig x opts-      -- It is possible to get IOException, error's and 'OrmoluException's-      -- from 'formatOne', so we just catch everything.-      errs <--        lefts-          <$> mapM-            (try @SomeException . formatOne optMode cfg . Just)-            (sort xs)-      unless (null errs) $ do-        mapM_ (hPutStrLn stderr . displayException) errs-        exitWith (ExitFailure 102) +  cfg <- case optInputFiles of+    [] -> mkConfigFromCWD opts+    ["-"] -> mkConfigFromCWD opts+    file : _ -> mkConfig file opts+  let formatOne' = formatOne optCabalDefaultExtensions optMode cfg++  exitCode <- case optInputFiles of+    [] -> formatOne' Nothing+    ["-"] -> formatOne' Nothing+    [x] -> formatOne' (Just x)+    xs -> do+      let selectFailure = \case+            ExitSuccess -> Nothing+            ExitFailure n -> Just n+      errorCodes <-+        mapMaybe selectFailure <$> mapM (formatOne' . Just) (sort xs)+      return $+        if null errorCodes+          then ExitSuccess+          else+            ExitFailure $+              if all (== 100) errorCodes+                then 100+                else 102+  exitWith exitCode+ -- | Format a single input. formatOne ::+  -- | Whether to respect default-extensions from .cabal files+  CabalDefaultExtensionsOpts ->   -- | Mode of operation   Mode ->   -- | Configuration   Config RegionIndices ->   -- | File to format or stdin as 'Nothing'   Maybe FilePath ->-  IO ()-formatOne mode config = \case-  Nothing -> do-    r <- ormoluStdin config-    case mode of-      Stdout -> TIO.putStr r-      _ -> do-        hPutStrLn-          stderr-          "This feature is not supported when input comes from stdin."-        -- 101 is different from all the other exit codes we already use.-        exitWith (ExitFailure 101)-  Just inputFile -> do-    originalInput <- TIO.readFile inputFile-    formattedInput <- ormoluFile config inputFile-    case mode of-      Stdout ->-        TIO.putStr formattedInput-      InPlace -> do-        -- Only write when the contents have changed, in order to avoid-        -- updating the modified timestamp if the file was already correctly-        -- formatted.-        when (formattedInput /= originalInput) $-          TIO.writeFile inputFile formattedInput-      Check -> do-        when (formattedInput /= originalInput) $-          -- 100 is different to all the other exit code that are emitted-          -- either from an 'OrmoluException' or from 'error' and-          -- 'notImplemented'.-          exitWith (ExitFailure 100)+  IO ExitCode+formatOne CabalDefaultExtensionsOpts {..} mode config mpath =+  withPrettyOrmoluExceptions (cfgColorMode config) $+    case FP.normalise <$> mpath of+      Nothing -> do+        extraDynOptions <-+          if optUseCabalDefaultExtensions+            then case optStdinInputFile of+              Just stdinInputFile ->+                getCabalExtensionDynOptions stdinInputFile+              Nothing -> throwIO OrmoluMissingStdinInputFile+            else pure []+        r <- ormoluStdin (configPlus extraDynOptions)+        case mode of+          Stdout -> do+            TIO.putStr r+            return ExitSuccess+          _ -> do+            hPutStrLn+              stderr+              "This feature is not supported when input comes from stdin."+            -- 101 is different from all the other exit codes we already use.+            return (ExitFailure 101)+      Just inputFile -> do+        extraDynOptions <-+          if optUseCabalDefaultExtensions+            then getCabalExtensionDynOptions inputFile+            else pure []+        originalInput <- readFileUtf8 inputFile+        formattedInput <- ormoluFile (configPlus extraDynOptions) inputFile+        case mode of+          Stdout -> do+            TIO.putStr formattedInput+            return ExitSuccess+          InPlace -> do+            -- Only write when the contents have changed, in order to avoid+            -- updating the modified timestamp if the file was already correctly+            -- formatted.+            when (formattedInput /= originalInput) $+              writeFileUtf8 inputFile formattedInput+            return ExitSuccess+          Check ->+            case diffText originalInput formattedInput inputFile of+              Nothing -> return ExitSuccess+              Just diff -> do+                runTerm (printTextDiff diff) (cfgColorMode config) stderr+                -- 100 is different to all the other exit code that are emitted+                -- either from an 'OrmoluException' or from 'error' and+                -- 'notImplemented'.+                return (ExitFailure 100)+  where+    configPlus dynOpts = config {cfgDynOptions = cfgDynOptions config ++ dynOpts}  ------------------------------------------------------------------------------- Command line options parsing.+-- Command line options parsing  data Opts = Opts   { -- | Mode of operation     optMode :: !Mode,     -- | Ormolu 'Config'     optConfig :: !(Config RegionIndices),+    -- | Options for respecting default-extensions from .cabal files+    optCabalDefaultExtensions :: CabalDefaultExtensionsOpts,     -- | Fourmolu-specific options     optPrinterOpts :: !PrinterOptsPartial,     -- | Haskell source files to format or stdin (when the list is empty)@@ -119,13 +155,21 @@     Check   deriving (Eq, Show, Bounded, Enum) +-- | Configuration for how to account for default-extension+-- from .cabal files+data CabalDefaultExtensionsOpts = CabalDefaultExtensionsOpts+  { -- | Account for default-extensions from .cabal files+    optUseCabalDefaultExtensions :: Bool,+    -- | Optional path to a file which will be used to+    -- find a .cabal file when using input from stdin+    optStdinInputFile :: Maybe FilePath+  }+  deriving (Show)+ optsParserInfo :: ParserInfo Opts optsParserInfo =   info (helper <*> ver <*> exts <*> optsParser) . mconcat $-    [ fullDesc,-      progDesc "",-      header ""-    ]+    [fullDesc]   where     ver :: Parser (a -> a)     ver =@@ -165,16 +209,30 @@                 short 'm',                 metavar "MODE",                 value Stdout,-                help "Mode of operation: 'stdout' (default), 'inplace', or 'check'"+                help "Mode of operation: 'stdout' (the default), 'inplace', or 'check'"               ]         )     <*> configParser+    <*> cabalDefaultExtensionsParser     <*> printerOptsParser     <*> (many . strArgument . mconcat)       [ metavar "FILE",-        help "Haskell source files to format or stdin (default)"+        help "Haskell source files to format or stdin (the default)"       ] +cabalDefaultExtensionsParser :: Parser CabalDefaultExtensionsOpts+cabalDefaultExtensionsParser =+  CabalDefaultExtensionsOpts+    <$> (switch . mconcat)+      [ short 'e',+        long "cabal-default-extensions",+        help "Account for default-extensions from .cabal files"+      ]+    <*> (optional . strOption . mconcat)+      [ long "stdin-input-file",+        help "Path which will be used to find the .cabal file when using input from stdin"+      ]+ configParser :: Parser (Config RegionIndices) configParser =   Config@@ -199,6 +257,12 @@         short 'c',         help "Fail if formatting is not idempotent"       ]+    <*> (option parseBoundedEnum . mconcat)+      [ long "color",+        metavar "WHEN",+        value Auto,+        help "Colorize the output; WHEN can be 'never', 'always', or 'auto' (the default)"+      ]     <*> ( RegionIndices             <$> (optional . option auto . mconcat)               [ long "start-line",@@ -279,7 +343,9 @@     (optional . option auto . mconcat)       [ long "newlines-between-decls",         metavar "HEIGHT",-        help "Number of spaces between top-level declarations (default 1)"+        help $+          "Number of spaces between top-level declarations"+            <> showDefaultValue poNewlinesBetweenDecls       ]   pure PrinterOpts {..} @@ -340,6 +406,11 @@   toCLIArgument InPlace = "inplace"   toCLIArgument Check = "check" +instance ToCLIArgument ColorMode where+  toCLIArgument Never = "never"+  toCLIArgument Always = "always"+  toCLIArgument Auto = "auto"+ showAllValues :: forall a. (Enum a, Bounded a, ToCLIArgument a) => String showAllValues = format (map toCLIArgument' [(minBound :: a) ..])   where@@ -393,3 +464,8 @@       }   where     printDebug = when (cfgDebug optConfig) . hPutStrLn stderr++mkConfigFromCWD :: Opts -> IO (Config RegionIndices)+mkConfigFromCWD opts = do+  cwd <- getCurrentDirectory+  mkConfig cwd opts
+ data/diff-tests/inputs/empty.hs view
+ data/diff-tests/inputs/main-and-bar-v2.hs view
@@ -0,0 +1,11 @@+module Main (main) where++main :: IO ()+main = pure ()++foo :: Int+foo =+  5++bar :: Int+bar = 7
+ data/diff-tests/inputs/main-and-bar.hs view
@@ -0,0 +1,11 @@+module Main (main) where++main :: IO ()+main = return ()++foo :: Int+foo =+  5++bar :: Int+bar = 6
+ data/diff-tests/inputs/main-and-baz-v2.hs view
@@ -0,0 +1,12 @@+module Main (main) where++main :: IO ()+main = pure ()++foo :: Int+foo =+  5+   + 5++bar :: Int+bar = 7
+ data/diff-tests/inputs/main-and-baz.hs view
@@ -0,0 +1,12 @@+module Main (main) where++main :: IO ()+main = return ()++foo :: Int+foo =+  5+   + 5++bar :: Int+bar = 6
+ data/diff-tests/inputs/main-and-foo-v2.hs view
@@ -0,0 +1,7 @@+module Main (main) where++main :: IO ()+main = pure ()++foo :: Int+foo = 5
+ data/diff-tests/inputs/main-and-foo.hs view
@@ -0,0 +1,7 @@+module Main (main) where++main :: IO ()+main = return ()++foo :: Int+foo = 5
+ data/diff-tests/inputs/main-foo.hs view
@@ -0,0 +1,4 @@+module Main (foo) where++main :: IO ()+main = return ()
+ data/diff-tests/inputs/main-v2.hs view
@@ -0,0 +1,4 @@+module Main (main) where++main :: IO ()+main = pure ()
+ data/diff-tests/inputs/main.hs view
@@ -0,0 +1,4 @@+module Main (main) where++main :: IO ()+main = return ()
+ data/diff-tests/inputs/no-trailing-blank-line.hs view
@@ -0,0 +1,1 @@+data Test = Test
+ data/diff-tests/inputs/one-line.hs view
@@ -0,0 +1,1 @@+module Main (main) where
+ data/diff-tests/inputs/spaced-v2.hs view
@@ -0,0 +1,16 @@+module Main (main) where++++++main :: IO ()+main = pure ()+++++++foo :: Int+foo = 5
+ data/diff-tests/inputs/spaced.hs view
@@ -0,0 +1,16 @@+module Main (main) where++++++main :: IO ()+main = return ()+++++++foo :: Int+foo = 5
+ data/diff-tests/inputs/with-trailing-blank-line.hs view
@@ -0,0 +1,1 @@+data Test = Test
+ data/diff-tests/outputs/joined-hunk.txt view
@@ -0,0 +1,15 @@+TEST+@@ -1,11 +1,11 @@+  module Main (main) where++  main :: IO ()+- main = return ()++ main = pure ()++  foo :: Int+  foo =+    5++  bar :: Int+- bar = 6++ bar = 7
+ data/diff-tests/outputs/no-following.txt view
@@ -0,0 +1,7 @@+TEST+@@ -1,4 +1,4 @@+  module Main (main) where++  main :: IO ()+- main = return ()++ main = pure ()
+ data/diff-tests/outputs/no-preceding.txt view
@@ -0,0 +1,6 @@+TEST+@@ -1,3 +1,3 @@+- module Main (foo) where++ module Main (main) where+  main :: IO ()+  main = return ()
+ data/diff-tests/outputs/one-line-added.txt view
@@ -0,0 +1,3 @@+TEST+@@ -1,0 +1,1 @@++ module Main (main) where
+ data/diff-tests/outputs/one-line-removed.txt view
@@ -0,0 +1,3 @@+TEST+@@ -1,1 +1,0 @@+- module Main (main) where
+ data/diff-tests/outputs/simple-hunk.txt view
@@ -0,0 +1,9 @@+TEST+@@ -1,6 +1,6 @@+  module Main (main) where++  main :: IO ()+- main = return ()++ main = pure ()+  foo :: Int+  foo = 5
+ data/diff-tests/outputs/trailing-blank-line.txt view
@@ -0,0 +1,4 @@+TEST+@@ -1,1 +1,2 @@+  data Test = Test++
+ data/diff-tests/outputs/trimming.txt view
@@ -0,0 +1,5 @@+TEST+@@ -7,2 +7,2 @@+  main :: IO ()+- main = return ()++ main = pure ()
+ data/diff-tests/outputs/two-hunks.txt view
@@ -0,0 +1,16 @@+TEST+@@ -1,7 +1,7 @@+  module Main (main) where++  main :: IO ()+- main = return ()++ main = pure ()++  foo :: Int+  foo =+@@ -9,4 +9,4 @@+     + 5++  bar :: Int+- bar = 6++ bar = 7
data/examples/declaration/class/newlines-and-haddocks-four-out.hs view
@@ -21,3 +21,7 @@      -- | Haddock followed by a blank line     abc :: a++    -- | A multiline+    -- comment here+    multiline :: a
data/examples/declaration/class/newlines-and-haddocks-out.hs view
@@ -21,3 +21,7 @@    -- | Haddock followed by a blank line   abc :: a++  -- | A multiline+  -- comment here+  multiline :: a
data/examples/declaration/class/newlines-and-haddocks.hs view
@@ -17,3 +17,7 @@   -- | Haddock followed by a blank line    abc :: a++  -- | A multiline+  -- comment here+  multiline :: a
+ data/examples/declaration/data/ctype-four-out.hs view
@@ -0,0 +1,1 @@+data {-# CTYPE "unistd.h" "useconds_t" #-} T
+ data/examples/declaration/data/ctype-out.hs view
@@ -0,0 +1,1 @@+data {-# CTYPE "unistd.h" "useconds_t" #-} T
+ data/examples/declaration/data/ctype.hs view
@@ -0,0 +1,1 @@+data    {-# CTYPE "unistd.h" "useconds_t" #-} T
+ data/examples/declaration/data/field-layout/gadt-four-out.hs view
@@ -0,0 +1,11 @@+module Main where++-- | Foo.+data Foo a b where+    -- | Something+    Foo :: Foo Int Int+    -- | Something else+    Bar ::+        Foo+            Char+            Char
+ data/examples/declaration/data/field-layout/gadt-out.hs view
@@ -0,0 +1,11 @@+module Main where++-- | Foo.+data Foo a b where+  -- | Something+  Foo :: Foo Int Int+  -- | Something else+  Bar ::+    Foo+      Char+      Char
+ data/examples/declaration/data/field-layout/gadt.hs view
@@ -0,0 +1,10 @@+module Main where++-- | Foo.++data Foo a b where+  -- | Something+  Foo :: Foo Int Int+  -- | Something else+  Bar :: Foo Char+    Char
+ data/examples/declaration/data/field-layout/record-four-out.hs view
@@ -0,0 +1,12 @@+module Main where++-- | Foo.+data Foo = Foo+    { -- | Something+      foo :: Foo Int Int+    , -- | Something else+      bar ::+        Bar+            Char+            Char+    }
+ data/examples/declaration/data/field-layout/record-out.hs view
@@ -0,0 +1,12 @@+module Main where++-- | Foo.+data Foo = Foo+  { -- | Something+    foo :: Foo Int Int,+    -- | Something else+    bar ::+      Bar+        Char+        Char+  }
+ data/examples/declaration/data/field-layout/record.hs view
@@ -0,0 +1,11 @@+module Main where++-- | Foo.++data Foo = Foo+  { foo :: Foo Int Int+    -- ^ Something+  , bar :: Bar Char+           Char+    -- ^ Something else+  }
+ data/examples/declaration/data/field-layout/variants-four-out.hs view
@@ -0,0 +1,10 @@+module Main where++-- | Foo.+data Foo+    = -- | Something+      Foo Int Int+    | -- | Something else+      Bar+        Char+        Char
+ data/examples/declaration/data/field-layout/variants-out.hs view
@@ -0,0 +1,10 @@+module Main where++-- | Foo.+data Foo+  = -- | Something+    Foo Int Int+  | -- | Something else+    Bar+      Char+      Char
+ data/examples/declaration/data/field-layout/variants.hs view
@@ -0,0 +1,10 @@+module Main where++-- | Foo.++data Foo =+  Foo Int Int+  -- ^ Something+  | Bar Char+        Char+  -- ^ Something else
data/examples/declaration/data/gadt/multiline-where-four-out.hs view
@@ -5,3 +5,26 @@         c     where     Foo :: a -> b -> c -> Foo a b c++data+    Foo ::+        Type ->+        Type ->+        Type+    where+    Foo :: Foo a b++data+    Foo a b c ::+        Type -> Type -> Type -> Type+    where+    Foo :: Foo a b c++data+    Vec ::+        Type ->+        Type ->+        Type+    where+    Nil :: Vec a Ze+    Cons :: a -> Vec a n -> Vec a (Su n)
data/examples/declaration/data/gadt/multiline-where-out.hs view
@@ -5,3 +5,26 @@     c   where   Foo :: a -> b -> c -> Foo a b c++data+  Foo ::+    Type ->+    Type ->+    Type+  where+  Foo :: Foo a b++data+  Foo a b c ::+    Type -> Type -> Type -> Type+  where+  Foo :: Foo a b c++data+  Vec ::+    Type ->+    Type ->+    Type+  where+  Nil :: Vec a Ze+  Cons :: a -> Vec a n -> Vec a (Su n)
data/examples/declaration/data/gadt/multiline-where.hs view
@@ -4,3 +4,20 @@     b     c where   Foo :: a -> b -> c -> Foo a b c++data Foo :: Type+         -> Type+         -> Type where+  Foo :: Foo a b++data Foo a b c ::+  Type -> Type -> Type -> Type where+  Foo :: Foo a b c++data Vec+  :: Type+  -> Type+  -> Type+  where+    Nil  :: Vec a Ze+    Cons :: a -> Vec a n -> Vec a (Su n)
data/examples/declaration/instance/newlines-between-methods-four-out.hs view
@@ -4,7 +4,7 @@     D u dudx * D v dvdx = D (u * v) (u * dvdx + v * dudx)      -- Comment before definition-    negate (D u dudx) = D (- u) (- dudx)+    negate (D u dudx) = D (-u) (-dudx)     negate (Z u dudx) = undefined      -- Comment after definition
data/examples/declaration/instance/newlines-between-methods-out.hs view
@@ -4,7 +4,7 @@   D u dudx * D v dvdx = D (u * v) (u * dvdx + v * dudx)    -- Comment before definition-  negate (D u dudx) = D (- u) (- dudx)+  negate (D u dudx) = D (-u) (-dudx)   negate (Z u dudx) = undefined    -- Comment after definition
+ data/examples/declaration/signature/standalone-kind-four-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE StandaloneKindSignatures #-}++type T ::+    (k -> Type) ->+    k ->+    Type+data T m a = MkT (m a) (T Maybe (m a))++type C1 :: Type -> Constraint+class C1 a++type F :: Type -> Type+type family F++type G :: Type+type G = a
+ data/examples/declaration/signature/standalone-kind-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE StandaloneKindSignatures #-}++type T ::+  (k -> Type) ->+  k ->+  Type+data T m a = MkT (m a) (T Maybe (m a))++type C1 :: Type -> Constraint+class C1 a++type F :: Type -> Type+type family F++type G :: Type+type G = a
+ data/examples/declaration/signature/standalone-kind.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE StandaloneKindSignatures #-}++type T :: (k -> Type)+       -> k+       -> Type++data T m a = MkT (m a) (T Maybe (m a))++type C1 :: Type -> Constraint+class C1 a++type F :: Type -> Type+type family F++type G :: Type++type G = a
data/examples/declaration/splice/bracket-declaration-four-out.hs view
@@ -24,3 +24,12 @@             deriving (Eq, Ord, Enum, Bounded, Show)         |]  )++foo = [d| type X = * |]++foo =+    [d|+        type X = *++        data A+        |]
data/examples/declaration/splice/bracket-declaration-out.hs view
@@ -24,3 +24,12 @@         deriving (Eq, Ord, Enum, Bounded, Show)       |]  )++foo = [d| type X = * |]++foo =+  [d|+    type X = *++    data A+    |]
data/examples/declaration/splice/bracket-declaration.hs view
@@ -20,3 +20,11 @@   data T = T     deriving (Eq, Ord, Enum, Bounded, Show)  |])+++foo = [d|type X = * |]++foo = [d|+  type X = *+  data A+        |]
data/examples/declaration/splice/bracket-four-out.hs view
@@ -16,3 +16,7 @@     [||     foo bar     ||]++foo = [t| * |]++foo = [t| a -> * -> a |]
data/examples/declaration/splice/bracket-out.hs view
@@ -16,3 +16,7 @@   [||   foo bar   ||]++foo = [t| * |]++foo = [t| a -> * -> a |]
data/examples/declaration/splice/bracket.hs view
@@ -10,3 +10,7 @@  foo = [|| foo bar   ||]++foo = [t| * |]++foo = [t|a -> * -> a|]
data/examples/declaration/splice/grouped-splices-four-out.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TemplateHaskell #-}+ $(deriveJSON fieldLabelMod ''A) $(deriveJSON fieldLabelMod ''B) $(deriveJSON fieldLabelMod ''C)
data/examples/declaration/splice/grouped-splices-out.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TemplateHaskell #-}+ $(deriveJSON fieldLabelMod ''A) $(deriveJSON fieldLabelMod ''B) $(deriveJSON fieldLabelMod ''C)
data/examples/declaration/splice/grouped-splices.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TemplateHaskell #-}+ $(deriveJSON fieldLabelMod ''A) $(deriveJSON fieldLabelMod ''B) $(deriveJSON fieldLabelMod ''C)
data/examples/declaration/splice/quasiquote-four-out.hs view
@@ -10,3 +10,7 @@ [d|    foo bar  |]++header =+    [here|+#include foo|]
data/examples/declaration/splice/quasiquote-out.hs view
@@ -10,3 +10,7 @@ [d|    foo bar  |]++header =+  [here|+#include foo|]
data/examples/declaration/splice/quasiquote.hs view
@@ -9,3 +9,6 @@ [d|    foo bar  |]++header = [here|+#include foo|]
+ data/examples/declaration/type-families/closed-type-family/type-arguments-four-out.hs view
@@ -0,0 +1,4 @@+type PickType :: forall k. Nat -> k+type family PickType n where+    PickType @Type 1 = Bool+    PickType @(Type -> Type) 2 = Maybe
+ data/examples/declaration/type-families/closed-type-family/type-arguments-out.hs view
@@ -0,0 +1,4 @@+type PickType :: forall k. Nat -> k+type family PickType n where+  PickType @Type 1 = Bool+  PickType @(Type -> Type) 2 = Maybe
+ data/examples/declaration/type-families/closed-type-family/type-arguments.hs view
@@ -0,0 +1,4 @@+type PickType :: forall k. Nat -> k+type family PickType n where+  PickType @Type 1 = Bool+  PickType @(Type -> Type) 2 = Maybe
+ data/examples/declaration/type-families/data-family/type-arguments-four-out.hs view
@@ -0,0 +1,5 @@+type PickType :: forall k. (k -> Type) -> Type+data family PickType m++data instance PickType @Nat M where+    Foo :: PickType M
+ data/examples/declaration/type-families/data-family/type-arguments-out.hs view
@@ -0,0 +1,5 @@+type PickType :: forall k. (k -> Type) -> Type+data family PickType m++data instance PickType @Nat M where+  Foo :: PickType M
+ data/examples/declaration/type-families/data-family/type-arguments.hs view
@@ -0,0 +1,5 @@+type PickType :: forall k. (k -> Type) -> Type+data family PickType m++data instance PickType @Nat M where+  Foo :: PickType M
data/examples/declaration/type/misc-kind-signatures-four-out.hs view
@@ -3,3 +3,8 @@  b :: (Bool :: *) b = True++unP :: forall {k} (a :: k). P a -> Proxy a++data ProxyKInvis (a :: k) :: forall k. k -> Type+data ProxyKVis k (a :: k) :: forall k -> k -> Type
data/examples/declaration/type/misc-kind-signatures-out.hs view
@@ -3,3 +3,9 @@  b :: (Bool :: *) b = True++unP :: forall {k} (a :: k). P a -> Proxy a++data ProxyKInvis (a :: k) :: forall k. k -> Type++data ProxyKVis k (a :: k) :: forall k -> k -> Type
data/examples/declaration/type/misc-kind-signatures.hs view
@@ -3,3 +3,8 @@  b :: (Bool :: *) b = True++unP :: forall {k} (a :: k). P a -> Proxy a++data ProxyKInvis (a :: k) :: forall k. k -> Type+data ProxyKVis k (a :: k) :: forall k -> k -> Type
+ data/examples/declaration/type/promotion-0-four-out.hs view
@@ -0,0 +1,9 @@+type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge]++type Query = Query '[] '[] DB '[ 'NotNull 'PGint4] (RowPG RawElementData)++data T = T' | T'T++type S0 = ' T'++type S1 = ' T'T
+ data/examples/declaration/type/promotion-0-out.hs view
@@ -0,0 +1,9 @@+type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge]++type Query = Query '[] '[] DB '[ 'NotNull 'PGint4] (RowPG RawElementData)++data T = T' | T'T++type S0 = ' T'++type S1 = ' T'T
+ data/examples/declaration/type/promotion-0.hs view
@@ -0,0 +1,9 @@+type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge ]++type Query = Query '[] '[] DB '[ 'NotNull 'PGint4] (RowPG RawElementData)++data T = T' | T'T++type S0 = ' T'++type S1 = ' T'T
+ data/examples/declaration/type/promotion-1-four-out.hs view
@@ -0,0 +1,9 @@+type S2 = Proxy ('[ '[], '[]])+type S4 = Proxy ('( 'Just, ' T'T))+type S5 = Proxy ('[ 'Just, 'TT'T])+type S6 = Proxy ('( '(), '()))+type S7 = Proxy ('( 'a, 'b))+type S8 = Proxy ('[Int, Bool])++type E = TypeError ( 'Text "Some text")+type G = '[ '( 'Just, 'Bool)]
+ data/examples/declaration/type/promotion-1-out.hs view
@@ -0,0 +1,15 @@+type S2 = Proxy ('[ '[], '[]])++type S4 = Proxy ('( 'Just, ' T'T))++type S5 = Proxy ('[ 'Just, 'TT'T])++type S6 = Proxy ('( '(), '()))++type S7 = Proxy ('( 'a, 'b))++type S8 = Proxy ('[Int, Bool])++type E = TypeError ( 'Text "Some text")++type G = '[ '( 'Just, 'Bool)]
+ data/examples/declaration/type/promotion-1.hs view
@@ -0,0 +1,9 @@+type S2 = Proxy ( '[ '[], '[] ])+type S4 = Proxy ( '( 'Just, ' T'T))+type S5 = Proxy ( '[ 'Just, ' TT'T])+type S6 = Proxy ( '( '(), '() ))+type S7 = Proxy ( '( 'a, 'b ))+type S8 = Proxy ( '[ Int, Bool ])++type E = TypeError ('Text "Some text")+type G = '[ '( 'Just, 'Bool) ]
− data/examples/declaration/type/promotion-four-out.hs
@@ -1,16 +0,0 @@-type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge]--type Query = Query '[] '[] DB '[ 'NotNull 'PGint4] (RowPG RawElementData)--data T = T' | T'T--type S0 = ' T'--type S1 = ' T'T--type S2 = Proxy ('[ '[], '[]])-type S4 = Proxy ('( 'Just, ' T'T))-type S5 = Proxy ('[ 'Just, 'TT'T])-type S6 = Proxy ('( '(), '()))-type S7 = Proxy ('( 'a, 'b))-type S8 = Proxy ('[Int, Bool])
− data/examples/declaration/type/promotion-out.hs
@@ -1,21 +0,0 @@-type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge]--type Query = Query '[] '[] DB '[ 'NotNull 'PGint4] (RowPG RawElementData)--data T = T' | T'T--type S0 = ' T'--type S1 = ' T'T--type S2 = Proxy ('[ '[], '[]])--type S4 = Proxy ('( 'Just, ' T'T))--type S5 = Proxy ('[ 'Just, 'TT'T])--type S6 = Proxy ('( '(), '()))--type S7 = Proxy ('( 'a, 'b))--type S8 = Proxy ('[Int, Bool])
− data/examples/declaration/type/promotion.hs
@@ -1,16 +0,0 @@-type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge ]--type Query = Query '[] '[] DB '[ 'NotNull 'PGint4] (RowPG RawElementData)--data T = T' | T'T--type S0 = ' T'--type S1 = ' T'T--type S2 = Proxy ( '[ '[], '[] ])-type S4 = Proxy ( '( 'Just, ' T'T))-type S5 = Proxy ( '[ 'Just, ' TT'T])-type S6 = Proxy ( '( '(), '() ))-type S7 = Proxy ( '( 'a, 'b ))-type S8 = Proxy ( '[ Int, Bool ])
data/examples/declaration/value/function/application-1-four-out.hs view
@@ -2,18 +2,18 @@     do         x         y-    z+      z  main =     case foo of         x -> a-    foo-    a-    b+      foo+      a+      b  main =     do         if x then y else z-    foo-    a-    b+      foo+      a+      b
data/examples/declaration/value/function/application-1-out.hs view
@@ -2,18 +2,18 @@   do     x     y-  z+   z  main =   case foo of     x -> a-  foo-  a-  b+   foo+   a+   b  main =   do     if x then y else z-  foo-  a-  b+   foo+   a+   b
+ data/examples/declaration/value/function/application-2-four-out.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE TemplateHaskell #-}++foo = do+    $( bar+     )+        baz++foo = do+    $$( bar+      )+        baz++foo = do+    do (+ 1)+      2++foo = do+    do+        (+ 1)+      2++foo = do+    case () of () -> (+ 1)+        2++foo = do+    case () of+        () -> (+ 1)+      2++foo = do+    \case 2 -> 3+        2++foo = do+    \case+        2 -> 3+      2
+ data/examples/declaration/value/function/application-2-out.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE TemplateHaskell #-}++foo = do+  $( bar+   )+    baz++foo = do+  $$( bar+    )+    baz++foo = do+  do (+ 1)+    2++foo = do+  do+    (+ 1)+   2++foo = do+  case () of () -> (+ 1)+    2++foo = do+  case () of+    () -> (+ 1)+   2++foo = do+  \case 2 -> 3+    2++foo = do+  \case+    2 -> 3+   2
+ data/examples/declaration/value/function/application-2.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE TemplateHaskell #-}++foo = do+  $( bar+   ) baz++foo = do+  $$( bar+    ) baz++foo = do+  do (+1)+   2++foo = do+  do+    (+1)+   2++foo = do+  case () of () -> (+1)+   2++foo = do+  case () of+    () -> (+1)+   2++foo = do+  \case 2 -> 3+   2++foo = do+  \case+    2 -> 3+   2
data/examples/declaration/value/function/arrow/proc-applications-four-out.hs view
@@ -2,6 +2,8 @@  foo x = proc a -> a -< x +foolr x = proc a -> x >- a+ bar f x =     proc         ( y@@ -17,3 +19,5 @@                 )  baz x = proc a -> a -<< x++bazlr x = proc a -> x >>- a
data/examples/declaration/value/function/arrow/proc-applications-out.hs view
@@ -2,6 +2,8 @@  foo x = proc a -> a -< x +foolr x = proc a -> x >- a+ bar f x =   proc     ( y,@@ -17,3 +19,5 @@         )  baz x = proc a -> a -<< x++bazlr x = proc a -> x >>- a
data/examples/declaration/value/function/arrow/proc-applications.hs view
@@ -2,6 +2,8 @@  foo x = proc a -> a -< x +foolr x = proc a -> x >- a+ bar f x =     proc (         y,@@ -15,3 +17,5 @@     )  baz x = proc a -> a -<< x++bazlr x = proc a -> x >>- a
+ data/examples/declaration/value/function/arrow/proc-applications2-four-out.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE Arrows #-}++t = proc ys ->+    (| f (\y -> returnA -< y) |) ys++g x = proc (y, z) ->+    ( case compare x y of+        LT -> \a -> returnA -< x + a+        EQ -> \b -> returnA -< y + z + b+        GT -> \c -> returnA -< z + x+    ) 1
+ data/examples/declaration/value/function/arrow/proc-applications2-out.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE Arrows #-}++t = proc ys ->+  (| f (\y -> returnA -< y) |) ys++g x = proc (y, z) ->+  ( case compare x y of+      LT -> \a -> returnA -< x + a+      EQ -> \b -> returnA -< y + z + b+      GT -> \c -> returnA -< z + x+  ) 1
+ data/examples/declaration/value/function/arrow/proc-applications2.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE Arrows #-}++t = proc ys ->+  (| f (\y -> returnA -< y) |) ys++g x = proc (y, z) ->+  ( case compare x y of+      LT -> \a -> returnA -< x + a+      EQ -> \b -> returnA -< y + z + b+      GT -> \c -> returnA -< z + x+  ) 1
data/examples/declaration/value/function/arrow/proc-cases-four-out.hs view
@@ -14,3 +14,8 @@         Right             (Right b) ->                 j -< b++baz = proc x ->+    (f -< x) `catchA` \case+        Right a -> f -< a+        Left e -> h -< e
data/examples/declaration/value/function/arrow/proc-cases-out.hs view
@@ -14,3 +14,8 @@     Right       (Right b) ->         j -< b++baz = proc x ->+  (f -< x) `catchA` \case+    Right a -> f -< a+    Left e -> h -< e
data/examples/declaration/value/function/arrow/proc-cases.hs view
@@ -15,3 +15,8 @@         Right           (Right b) ->             j -< b+++baz = proc x -> (f -< x) `catchA`  \case+                    Right a -> f -< a+                    Left e  -> h -< e
data/examples/declaration/value/function/arrow/proc-do-complex-four-out.hs view
@@ -60,3 +60,6 @@                                 + x                                 * y -- Just do the calculation                             )++traverseA_ f = proc (e, (xs, s)) ->+    (| foldlA' (\() x -> do (e, (x, s)) >- f; () >- returnA) |) () xs
data/examples/declaration/value/function/arrow/proc-do-complex-out.hs view
@@ -60,3 +60,6 @@                   + x                   * y -- Just do the calculation               )++traverseA_ f = proc (e, (xs, s)) ->+  (| foldlA' (\() x -> do (e, (x, s)) >- f; () >- returnA) |) () xs
data/examples/declaration/value/function/arrow/proc-do-complex.hs view
@@ -47,3 +47,6 @@           returnA -< (i +                       x *                       y) -- Just do the calculation++traverseA_ f = proc (e, (xs, s)) ->+  (| foldlA' (\() x -> do { (e, (x, s)) >- f; () >- returnA }) |) () xs
data/examples/declaration/value/function/arrow/proc-do-simple1-four-out.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE Arrows #-} -bar f = proc a -> do-    b <- f -< a+bar f = proc a -> do b <- f -< a  barbar f g = proc a -> do     b <- f -< a
data/examples/declaration/value/function/arrow/proc-do-simple1-out.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE Arrows #-} -bar f = proc a -> do-  b <- f -< a+bar f = proc a -> do b <- f -< a  barbar f g = proc a -> do   b <- f -< a
data/examples/declaration/value/function/arrow/proc-do-simple2-four-out.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE Arrows #-} -foo f = proc a -> do-    f -< a+foo f = proc a -> do f -< a  bazbaz f g h = proc (a, b, c) -> do     x <-@@ -20,3 +19,5 @@     returnA         -<             (x, y, z)++bar f = proc x -> do { f -< x } <+> do f -< x
data/examples/declaration/value/function/arrow/proc-do-simple2-out.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE Arrows #-} -foo f = proc a -> do-  f -< a+foo f = proc a -> do f -< a  bazbaz f g h = proc (a, b, c) -> do   x <-@@ -20,3 +19,5 @@   returnA     -<       (x, y, z)++bar f = proc x -> do { f -< x } <+> do f -< x
data/examples/declaration/value/function/arrow/proc-do-simple2.hs view
@@ -18,3 +18,5 @@        )      returnA -<        (x, y, z)++bar f = proc x -> do {f -< x} <+> do f -< x
+ data/examples/declaration/value/function/arrow/proc-form-do-indent-four-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE Arrows #-}++foo x = proc (y, z) -> do+    (|+        bar+            (bindA -< y)+        |)++foo1 x = proc (y, z) -> do+    (|+        bar+            (bindA -< y)+        |) z
+ data/examples/declaration/value/function/arrow/proc-form-do-indent-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE Arrows #-}++foo x = proc (y, z) -> do+  (|+    bar+      (bindA -< y)+    |)++foo1 x = proc (y, z) -> do+  (|+    bar+      (bindA -< y)+    |) z
+ data/examples/declaration/value/function/arrow/proc-form-do-indent.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE Arrows #-}++foo x = proc (y, z) -> do+  (|+    bar+      (bindA -< y)+    |)++foo1 x = proc (y, z) -> do+  (|+    bar+      (bindA -< y)+    |) z
data/examples/declaration/value/function/arrow/proc-forms2-four-out.hs view
@@ -15,8 +15,32 @@         ( (h f . h g)             -<                 (y x) . y z-        ) |||-            ( (h g . h f)-                -<-                    y z . (y x)-            )+        )+            ||| ( (h g . h f)+                    -<+                        y z . (y x)+                )++bar4 = proc x ->+    case x of+        Just f -> f -< ()+        Nothing -> x -< ()+        <+> do+            g -< x++expr' = proc x ->+    do+        returnA -< x+        <+> do+            symbol Plus -< ()+            y <- term -< ()+            expr' -< x + y+        <+> do+            symbol Minus -< ()+            y <- term -< ()+            expr' -< x - y++bar f = proc (a, b) -> do+    (f a -< b)+        >-> (\y -> f b >- a)+        >-> (\y -> f b >- a)
data/examples/declaration/value/function/arrow/proc-forms2-out.hs view
@@ -15,8 +15,32 @@     ( (h f . h g)         -<           (y x) . y z-    ) |||-      ( (h g . h f)-          -<-            y z . (y x)-      )+    )+      ||| ( (h g . h f)+              -<+                y z . (y x)+          )++bar4 = proc x ->+  case x of+    Just f -> f -< ()+    Nothing -> x -< ()+    <+> do+      g -< x++expr' = proc x ->+  do+    returnA -< x+    <+> do+      symbol Plus -< ()+      y <- term -< ()+      expr' -< x + y+    <+> do+      symbol Minus -< ()+      y <- term -< ()+      expr' -< x - y++bar f = proc (a, b) -> do+  (f a -< b)+    >-> (\y -> f b >- a)+    >-> (\y -> f b >- a)
data/examples/declaration/value/function/arrow/proc-forms2.hs view
@@ -17,3 +17,25 @@   |||     ((h g  .  h f)       -<y z  .  (y x))++bar4 = proc x -> case x of+    Just f -> f -< ()+    Nothing -> x -< ()+ <+> do+         g -< x++expr' = proc x -> do+                returnA -< x+        <+> do+                symbol Plus -< ()+                y <- term -< ()+                expr' -< x + y+        <+> do+                symbol Minus -< ()+                y <- term -< ()+                expr' -< x - y++bar f = proc (a, b) -> do+    (f a -< b)+      >-> (\y -> f b >- a)+      >-> (\y -> f b >- a)
data/examples/declaration/value/function/block-arguments-four-out.hs view
@@ -32,3 +32,5 @@     do a     do b     do c++f11 = do a do b do c do d
data/examples/declaration/value/function/block-arguments-out.hs view
@@ -32,3 +32,5 @@   do a   do b   do c++f11 = do a do b do c do d
data/examples/declaration/value/function/block-arguments.hs view
@@ -28,3 +28,5 @@   do { a }   do { b }   do c++f11 = do a do b do c do d
+ data/examples/declaration/value/function/case-empty-four-out.hs view
@@ -0,0 +1,6 @@+absurd x = case x of {}+absurd = \case {}+absurd x = case x of {}+absurd = \case {}++foo = case () of {} 1
+ data/examples/declaration/value/function/case-empty-out.hs view
@@ -0,0 +1,6 @@+absurd x = case x of {}+absurd = \case {}+absurd x = case x of {}+absurd = \case {}++foo = case () of {} 1
+ data/examples/declaration/value/function/case-empty.hs view
@@ -0,0 +1,6 @@+absurd x = case x of+absurd = \case+absurd x = case x of {}+absurd = \case {}++foo = case () of {} 1
+ data/examples/declaration/value/function/comprehension/transform-monad-four-out.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE MonadComprehensions #-}+{-# LANGUAGE TransformListComp #-}++quux' xs ys =+    [ ( x+      , y+      )+    | x <- xs+    , y <- ys+    , then group by+        -- First comment+        ( x+            + y+        )+      using+        -- Second comment+        groupWith -- Third comment+    ]
+ data/examples/declaration/value/function/comprehension/transform-monad-out.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE MonadComprehensions #-}+{-# LANGUAGE TransformListComp #-}++quux' xs ys =+  [ ( x,+      y+    )+    | x <- xs,+      y <- ys,+      then group by+        -- First comment+        ( x+            + y+        )+      using+        -- Second comment+        groupWith -- Third comment+  ]
+ data/examples/declaration/value/function/comprehension/transform-monad.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE MonadComprehensions #-}+{-# LANGUAGE TransformListComp #-}++quux' xs ys = [+  (x,+    y) |+  x <- xs,+  y <- ys,+  then+  group+  by -- First comment+    (x+      + y)+  using -- Second comment+    groupWith -- Third comment+  ]
data/examples/declaration/value/function/lambda-single-line-four-out.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TemplateHaskell #-}  foo :: a -> a -> a foo x = \y -> x
data/examples/declaration/value/function/lambda-single-line-out.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TemplateHaskell #-}  foo :: a -> a -> a foo x = \y -> x
data/examples/declaration/value/function/lambda-single-line.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TemplateHaskell #-}  foo :: a -> a -> a foo x = \y -> x
+ data/examples/declaration/value/function/lexical-negation-four-out.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE LexicalNegation #-}++foo = -1++foo = -x++weird :: (Int -> Int) -> Int -> Int+weird x y = x -y
+ data/examples/declaration/value/function/lexical-negation-out.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE LexicalNegation #-}++foo = -1++foo = -x++weird :: (Int -> Int) -> Int -> Int+weird x y = x -y
+ data/examples/declaration/value/function/lexical-negation.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE LexicalNegation #-}++foo = -1++foo = -x++weird :: (Int -> Int) -> Int -> Int+weird x y = x -y
data/examples/declaration/value/function/negation-four-out.hs view
@@ -5,4 +5,16 @@ bar = -2  baz :: Int-baz = - 2+baz = -2++neg :: Int -> Int+neg x = (-x)+neg x = -x+neg x = -x++weird :: Int -> Int -> Int+weird x y = x - y++pat = \case -1 -> 1++pat = \case -1 -> 1
data/examples/declaration/value/function/negation-out.hs view
@@ -5,4 +5,16 @@ bar = -2  baz :: Int-baz = - 2+baz = -2++neg :: Int -> Int+neg x = (-x)+neg x = -x+neg x = -x++weird :: Int -> Int -> Int+weird x y = x - y++pat = \case -1 -> 1++pat = \case -1 -> 1
data/examples/declaration/value/function/negation.hs view
@@ -6,3 +6,15 @@  baz :: Int baz = - 2++neg :: Int -> Int+neg x = (- x)+neg x = - x+neg x = -x++weird :: Int -> Int -> Int+weird x y = x -y++pat = \case -1 -> 1++pat = \case - 1 -> 1
+ data/examples/declaration/value/function/negative-literals-four-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE NegativeLiterals #-}++foo = - 1++foo = -1++foo = -x++foo = -x++pat = \case -1 -> 1++pat = \case - 1 -> 1
+ data/examples/declaration/value/function/negative-literals-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE NegativeLiterals #-}++foo = - 1++foo = -1++foo = -x++foo = -x++pat = \case -1 -> 1++pat = \case - 1 -> 1
+ data/examples/declaration/value/function/negative-literals.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE NegativeLiterals #-}++foo = - 1++foo = -1++foo = - x++foo = -x++pat = \case -1 -> 1++pat = \case - 1 -> 1
+ data/examples/declaration/value/function/operators-7-four-out.hs view
@@ -0,0 +1,1 @@+foo c = case c of { _ -> c } : []
+ data/examples/declaration/value/function/operators-7-out.hs view
@@ -0,0 +1,1 @@+foo c = case c of { _ -> c } : []
+ data/examples/declaration/value/function/operators-7.hs view
@@ -0,0 +1,1 @@+foo c = case c of {_->c} : []
data/examples/declaration/value/function/pattern/as-pattern.hs view
@@ -1,3 +1,3 @@ main = case [1] of-  xs @ (x:_) -> print (x, xs)+  xs@(x:_) -> print (x, xs)   xs@[] -> print xs
data/examples/declaration/value/function/pragmas-four-out.hs view
@@ -3,7 +3,9 @@     {-# SCC "barbaz" #-}     "hello" -corefoo = {-# CORE "foo" #-} 1+-- CORE pragma got removed in https://gitlab.haskell.org/ghc/ghc/-/commit/12f9035200424ec8104484f154a040d612fee99d++corefoo = {-# CORE "foo"#-} 1 corebar =-    {-# CORE "bar baz" #-}+    {-# CORE "bar baz"#-}     "hello"
data/examples/declaration/value/function/pragmas-out.hs view
@@ -4,8 +4,10 @@   {-# SCC "barbaz" #-}   "hello" -corefoo = {-# CORE "foo" #-} 1+-- CORE pragma got removed in https://gitlab.haskell.org/ghc/ghc/-/commit/12f9035200424ec8104484f154a040d612fee99d +corefoo = {-# CORE "foo"#-} 1+ corebar =-  {-# CORE "bar baz" #-}+  {-# CORE "bar baz"#-}   "hello"
data/examples/declaration/value/function/pragmas.hs view
@@ -2,6 +2,8 @@ sccbar = {-# SCC "barbaz"#-}   "hello" +-- CORE pragma got removed in https://gitlab.haskell.org/ghc/ghc/-/commit/12f9035200424ec8104484f154a040d612fee99d+ corefoo = {-# CORE "foo"#-}  1 corebar = {-# CORE "bar baz"#-}   "hello"
+ data/examples/declaration/value/function/record/constructors-four-out.hs view
@@ -0,0 +1,27 @@+foo = Foo{a = 3}+bar =+    Bar+        { abc = foo+        , def = Foo{a = 10}+        }+baz = Baz{}+sym = Foo{(+) = 3}+aLongVariableName =+    ALongRecordName+        { short = baz+        , aLongRecordFieldName =+            YetAnotherLongRecordName+                { yetAnotherLongRecordFieldName = "a long string"+                }+        , aLongRecordFieldName2 =+            Just+                YetAnotherLongRecordName+                    { yetAnotherLongRecordFieldName = "a long string"+                    , yetAnotherLongRecordFieldName =+                        Just+                            "a long string"+                    }+        , aLongRecordFieldName3 = do+            foo+            bar+        }
+ data/examples/declaration/value/function/record/constructors-out.hs view
@@ -0,0 +1,31 @@+foo = Foo {a = 3}++bar =+  Bar+    { abc = foo,+      def = Foo {a = 10}+    }++baz = Baz {}++sym = Foo {(+) = 3}++aLongVariableName =+  ALongRecordName+    { short = baz,+      aLongRecordFieldName =+        YetAnotherLongRecordName+          { yetAnotherLongRecordFieldName = "a long string"+          },+      aLongRecordFieldName2 =+        Just+          YetAnotherLongRecordName+            { yetAnotherLongRecordFieldName = "a long string",+              yetAnotherLongRecordFieldName =+                Just+                  "a long string"+            },+      aLongRecordFieldName3 = do+        foo+        bar+    }
+ data/examples/declaration/value/function/record/constructors.hs view
@@ -0,0 +1,22 @@+foo = Foo { a = 3 }+bar = Bar {+    abc = foo,+    def = Foo {a = 10}+}+baz = Baz{ }+sym = Foo { (+) = 3 }+aLongVariableName =+  ALongRecordName+    { short = baz,+      aLongRecordFieldName = YetAnotherLongRecordName+        { yetAnotherLongRecordFieldName = "a long string"+          },+      aLongRecordFieldName2 = Just YetAnotherLongRecordName+                                 { yetAnotherLongRecordFieldName = "a long string",+                                   yetAnotherLongRecordFieldName = Just+                                                                     "a long string"+                                   },+      aLongRecordFieldName3 = do+                               foo+                               bar+      }
+ data/examples/declaration/value/function/record/dot-multiline-four-out.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}++bar' =+    (Foo 1){bar = 2+           }++fooplus'''' f n =+    f{foo = n+      , bar = n+     }++fooplus''''' f n =+    f+        { foo = n+        }
+ data/examples/declaration/value/function/record/dot-multiline-out.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}++bar' =+  (Foo 1){bar = 2+         }++fooplus'''' f n =+  f{foo = n,+    bar = n+   }++fooplus''''' f n =+  f+    { foo = n+    }
+ data/examples/declaration/value/function/record/dot-multiline.hs view
@@ -0,0 +1,10 @@+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}+bar' = (Foo 1){bar = 2+              }++fooplus'''' f n = f{foo = n,+                    bar = n+                   }++fooplus''''' f n = f+                   { foo = n }
+ data/examples/declaration/value/function/record/dot-singleline-four-out.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}++data Foo = Foo {bar :: Int}++mfoo = fmap (.bar) $ Nothing++bar = (Foo 1).bar++fooplus f n = f{foo = f.bar + n}++fooplus' f n = f{foo = f.bar + n}++fooplus'' f n = f{foo = f.bar + n}++fooplus''' f n = f{foo = f.bar + n}
+ data/examples/declaration/value/function/record/dot-singleline-out.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}++data Foo = Foo {bar :: Int}++mfoo = fmap (.bar) $ Nothing++bar = (Foo 1).bar++fooplus f n = f{foo = f.bar + n}++fooplus' f n = f {foo = f.bar + n}++fooplus'' f n = f {foo = f.bar + n}++fooplus''' f n = f {foo = f.bar + n}
+ data/examples/declaration/value/function/record/dot-singleline.hs view
@@ -0,0 +1,14 @@+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}+data Foo = Foo { bar :: Int }++mfoo = fmap (.bar)   $ Nothing++bar = (  Foo 1).bar++fooplus f n = f{foo = f.bar + n}++fooplus' f n = f { foo = f.bar + n}++fooplus'' f n = f {foo = f.bar + n}++fooplus''' f n = f{ foo = f.bar + n}
+ data/examples/declaration/value/function/record/hanging-after-equal-con-four-out.hs view
@@ -0,0 +1,8 @@+foo =+    Foo+        { foo =+            -- Blah blah+            case x of+                Blah -> 1+                Blim -> 2+        }
+ data/examples/declaration/value/function/record/hanging-after-equal-con-out.hs view
@@ -0,0 +1,8 @@+foo =+  Foo+    { foo =+        -- Blah blah+        case x of+          Blah -> 1+          Blim -> 2+    }
+ data/examples/declaration/value/function/record/hanging-after-equal-con.hs view
@@ -0,0 +1,7 @@+foo = Foo+  { foo =+    -- Blah blah+    case x of+      Blah -> 1+      Blim -> 2+  }
+ data/examples/declaration/value/function/record/hanging-after-equal-update-four-out.hs view
@@ -0,0 +1,8 @@+foo =+    foo+        { foo =+            -- Blah blah+            case x of+                Blah -> 1+                Blim -> 2+        }
+ data/examples/declaration/value/function/record/hanging-after-equal-update-out.hs view
@@ -0,0 +1,8 @@+foo =+  foo+    { foo =+        -- Blah blah+        case x of+          Blah -> 1+          Blim -> 2+    }
+ data/examples/declaration/value/function/record/hanging-after-equal-update.hs view
@@ -0,0 +1,7 @@+foo = foo+  { foo =+    -- Blah blah+    case x of+      Blah -> 1+      Blim -> 2+  }
+ data/examples/declaration/value/function/record/inter-comments-four-out.hs view
@@ -0,0 +1,13 @@+x =+    Just+        -- comment+        A+            { x+            }++x =+    Just+        -- comment+        a+            { x+            }
+ data/examples/declaration/value/function/record/inter-comments-out.hs view
@@ -0,0 +1,13 @@+x =+  Just+    -- comment+    A+      { x+      }++x =+  Just+    -- comment+    a+      { x+      }
+ data/examples/declaration/value/function/record/inter-comments.hs view
@@ -0,0 +1,11 @@+x = Just+  -- comment+  A+   { x+   }++x = Just+  -- comment+  a+   { x+   }
+ data/examples/declaration/value/function/record/updaters-four-out.hs view
@@ -0,0 +1,8 @@+foo x = x{a = 3}+bar x =+    x+        { abc = foo+        , def = Foo{a = 10}+        }+baz x = x{}+sym x = x{(+) = 4}
+ data/examples/declaration/value/function/record/updaters-out.hs view
@@ -0,0 +1,11 @@+foo x = x {a = 3}++bar x =+  x+    { abc = foo,+      def = Foo {a = 10}+    }++baz x = x {}++sym x = x {(+) = 4}
+ data/examples/declaration/value/function/record/updaters.hs view
@@ -0,0 +1,7 @@+foo x = x { a = 3 }+bar x = x {+    abc = foo,+    def = Foo {a = 10}+}+baz x = x{ }+sym x = x { (+) = 4 }
+ data/examples/declaration/value/function/record/wildcards-four-out.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}++foo x y = Foo{x, y}++bar x y z =+    Bar+        { x+        , y+        , z+        , ..+        }++baz = Baz{..}
+ data/examples/declaration/value/function/record/wildcards-out.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}++foo x y = Foo {x, y}++bar x y z =+  Bar+    { x,+      y,+      z,+      ..+    }++baz = Baz {..}
+ data/examples/declaration/value/function/record/wildcards.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}++foo x y = Foo { x, y }++bar x y z = Bar {+    x,+    y,+    z,+    ..+}++baz = Baz { .. }
data/examples/module-header/multiline-with-comments-four-out.hs view
@@ -6,6 +6,9 @@     -- * Something     foo,     bar,+    -- | A multiline+    -- comment here+    bar2,      -- * Another thing     (<?>),
data/examples/module-header/multiline-with-comments-out.hs view
@@ -6,6 +6,9 @@   ( -- * Something     foo,     bar,+    -- | A multiline+    -- comment here+    bar2,      -- * Another thing     (<?>),
data/examples/module-header/multiline-with-comments.hs view
@@ -7,6 +7,9 @@   ( -- * Something     foo,     bar,+    -- | A multiline+    -- comment here+    bar2,     -- * Another thing     (<?>),     {- some other thing -} foo2 -- yet another
+ data/examples/other/cpp/continuation-four-out.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-}++foo :: Int+foo = 5++#define  message_for(a, b)  \+   printf(#a " and " #b ": We love you!\n")++bar :: Int+bar = 6
+ data/examples/other/cpp/continuation-out.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-}++foo :: Int+foo = 5++#define  message_for(a, b)  \+   printf(#a " and " #b ": We love you!\n")++bar :: Int+bar = 6
+ data/examples/other/cpp/continuation.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-}++foo :: Int+foo = 5++#define  message_for(a, b)  \+   printf(#a " and " #b ": We love you!\n")++bar :: Int+bar = 6
+ data/examples/other/cpp/lonely-hash-four-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++module Main (main) where++import Data.Void+import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Char++# if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+# endif++main :: IO ()+main = return ()
+ data/examples/other/cpp/lonely-hash-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++module Main (main) where++import Data.Void+import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Char++# if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+# endif++main :: IO ()+main = return ()
+ data/examples/other/cpp/lonely-hash.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++module Main (main) where++import Data.Void+import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Char++# if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+# endif++main :: IO ()+main = return ()
+ data/examples/other/cpp/separation-0a-four-out.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++instance Stream s => Monad (ParsecT e s m) where+    return = pure+    (>>=) = pBind+#if !(MIN_VERSION_base(4,13,0))+  fail   = Fail.fail+#endif
+ data/examples/other/cpp/separation-0a-out.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++instance Stream s => Monad (ParsecT e s m) where+  return = pure+  (>>=) = pBind+#if !(MIN_VERSION_base(4,13,0))+  fail   = Fail.fail+#endif
+ data/examples/other/cpp/separation-0a.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++instance Stream s => Monad (ParsecT e s m) where+  return = pure+  (>>=)  = pBind+#if !(MIN_VERSION_base(4,13,0))+  fail   = Fail.fail+#endif
+ data/examples/other/cpp/separation-0b-four-out.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP #-}++instance Stream s => Monad (ParsecT e s m) where+    return = pure+    (>>=) = pBind+#if !(MIN_VERSION_base(4,13,0))+  fail   = Fail.fail+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-0b-out.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP #-}++instance Stream s => Monad (ParsecT e s m) where+  return = pure+  (>>=) = pBind+#if !(MIN_VERSION_base(4,13,0))+  fail   = Fail.fail+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-0b.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP #-}++instance Stream s => Monad (ParsecT e s m) where+  return = pure+  (>>=)  = pBind+#if !(MIN_VERSION_base(4,13,0))+  fail   = Fail.fail+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-1a-four-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}++decompressingPipe ::+    (PrimMonad m, MonadThrow m, MonadResource m) =>+    CompressionMethod ->+    ConduitT ByteString ByteString m ()+decompressingPipe Store = C.awaitForever C.yield+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)+#ifdef ENABLE_BZIP2+decompressingPipe BZip2   = BZ.bunzip2+#else+decompressingPipe BZip2   = throwM BZip2Unsupported+#endif
+ data/examples/other/cpp/separation-1a-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}++decompressingPipe ::+  (PrimMonad m, MonadThrow m, MonadResource m) =>+  CompressionMethod ->+  ConduitT ByteString ByteString m ()+decompressingPipe Store = C.awaitForever C.yield+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)+#ifdef ENABLE_BZIP2+decompressingPipe BZip2   = BZ.bunzip2+#else+decompressingPipe BZip2   = throwM BZip2Unsupported+#endif
+ data/examples/other/cpp/separation-1a.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}++decompressingPipe+  :: (PrimMonad m, MonadThrow m, MonadResource m)+  => CompressionMethod+  -> ConduitT ByteString ByteString m ()+decompressingPipe Store   = C.awaitForever C.yield+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)+#ifdef ENABLE_BZIP2+decompressingPipe BZip2   = BZ.bunzip2+#else+decompressingPipe BZip2   = throwM BZip2Unsupported+#endif
+ data/examples/other/cpp/separation-1b-four-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++decompressingPipe ::+    (PrimMonad m, MonadThrow m, MonadResource m) =>+    CompressionMethod ->+    ConduitT ByteString ByteString m ()+decompressingPipe Store = C.awaitForever C.yield+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)+#ifdef ENABLE_BZIP2+decompressingPipe BZip2   = BZ.bunzip2+#else+decompressingPipe BZip2   = throwM BZip2Unsupported+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-1b-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++decompressingPipe ::+  (PrimMonad m, MonadThrow m, MonadResource m) =>+  CompressionMethod ->+  ConduitT ByteString ByteString m ()+decompressingPipe Store = C.awaitForever C.yield+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)+#ifdef ENABLE_BZIP2+decompressingPipe BZip2   = BZ.bunzip2+#else+decompressingPipe BZip2   = throwM BZip2Unsupported+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-1b.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++decompressingPipe+  :: (PrimMonad m, MonadThrow m, MonadResource m)+  => CompressionMethod+  -> ConduitT ByteString ByteString m ()+decompressingPipe Store   = C.awaitForever C.yield+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)+#ifdef ENABLE_BZIP2+decompressingPipe BZip2   = BZ.bunzip2+#else+decompressingPipe BZip2   = throwM BZip2Unsupported+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-2a-four-out.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-}++ffff, ffffffff :: Natural+#ifdef HASKELL_ZIP_DEV_MODE+ffff     = 200+ffffffff = 5000+#else+ffff     = 0xffff+ffffffff = 0xffffffff+#endif
+ data/examples/other/cpp/separation-2a-out.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-}++ffff, ffffffff :: Natural+#ifdef HASKELL_ZIP_DEV_MODE+ffff     = 200+ffffffff = 5000+#else+ffff     = 0xffff+ffffffff = 0xffffffff+#endif
+ data/examples/other/cpp/separation-2a.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE CPP #-}++ffff, ffffffff :: Natural+#ifdef HASKELL_ZIP_DEV_MODE+ffff     = 200+ffffffff = 5000+#else+ffff     = 0xffff+ffffffff = 0xffffffff+#endif
+ data/examples/other/cpp/separation-2b-four-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}++ffff, ffffffff :: Natural+#ifdef HASKELL_ZIP_DEV_MODE+ffff     = 200+ffffffff = 5000+#else+ffff     = 0xffff+ffffffff = 0xffffffff+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-2b-out.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}++ffff, ffffffff :: Natural+#ifdef HASKELL_ZIP_DEV_MODE+ffff     = 200+ffffffff = 5000+#else+ffff     = 0xffff+ffffffff = 0xffffffff+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/separation-2b.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}++ffff, ffffffff :: Natural+#ifdef HASKELL_ZIP_DEV_MODE+ffff     = 200+ffffffff = 5000+#else+ffff     = 0xffff+ffffffff = 0xffffffff+#endif++foo :: Int+foo = undefined
+ data/examples/other/cpp/shifted-four-out.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE CPP #-}++sinkData h compression = do+    (uncompressedSize, crc32, compressedSize) <-+        case compression of+            Store ->+                withCompression+                    dataSink+            Deflate ->+                withCompression $+                    Z.compress 9 (Z.WindowBits (-15)) .| dataSink+#ifdef ENABLE_BZIP2+      BZip2   -> withCompression $+        BZ.bzip2 .| dataSink+#else+      BZip2   -> throwM BZip2Unsupported+#endif+  return+      DataDescriptor+          { ddCRC32 = fromIntegral crc32+          , ddCompressedSize = compressedSize+          , ddUncompressedSize = uncompressedSize+          }
+ data/examples/other/cpp/shifted-out.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE CPP #-}++sinkData h compression = do+  (uncompressedSize, crc32, compressedSize) <-+    case compression of+      Store ->+        withCompression+          dataSink+      Deflate ->+        withCompression $+          Z.compress 9 (Z.WindowBits (-15)) .| dataSink+#ifdef ENABLE_BZIP2+      BZip2   -> withCompression $+        BZ.bzip2 .| dataSink+#else+      BZip2   -> throwM BZip2Unsupported+#endif+  return+    DataDescriptor+      { ddCRC32 = fromIntegral crc32,+        ddCompressedSize = compressedSize,+        ddUncompressedSize = uncompressedSize+      }
+ data/examples/other/cpp/shifted.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE CPP #-}++sinkData h compression = do+  (uncompressedSize, crc32, compressedSize) <-+    case compression of+      Store   -> withCompression+        dataSink+      Deflate -> withCompression $+        Z.compress 9 (Z.WindowBits (-15)) .| dataSink+#ifdef ENABLE_BZIP2+      BZip2   -> withCompression $+        BZ.bzip2 .| dataSink+#else+      BZip2   -> throwM BZip2Unsupported+#endif+  return DataDescriptor+    { ddCRC32            = fromIntegral crc32+    , ddCompressedSize   = compressedSize+    , ddUncompressedSize = uncompressedSize }
+ data/examples/other/cpp/simple-import-four-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++module Main (main) where++import Data.Void+import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Char++#if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+#endif++main :: IO ()+main = return ()
+ data/examples/other/cpp/simple-import-out.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++module Main (main) where++import Data.Void+import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Char++#if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+#endif++main :: IO ()+main = return ()
+ data/examples/other/cpp/simple-import.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}++module Main (main) where++import Data.Void+import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Char++#if !MIN_VERSION_base(4,13,0)+import Data.Semigroup ((<>))+#endif++main :: IO ()+main = return ()
+ data/examples/other/disabling/closing-comment-in-disabled-region-four-out.hs view
@@ -0,0 +1,3 @@+{- ORMOLU_DISABLE -}+a::String+a="-}"
+ data/examples/other/disabling/closing-comment-in-disabled-region-out.hs view
@@ -0,0 +1,3 @@+{- ORMOLU_DISABLE -}+a::String+a="-}"
+ data/examples/other/disabling/closing-comment-in-disabled-region.hs view
@@ -0,0 +1,3 @@+{- ORMOLU_DISABLE -}+a::String+a="-}"
+ data/examples/other/disabling/empty-disabled-region-four-out.hs view
@@ -0,0 +1,7 @@+{- ORMOLU_DISABLE -}+{- ORMOLU_ENABLE -}+foo = 0+{- ORMOLU_DISABLE -}+{- ORMOLU_ENABLE -}+bar = 1+{- ORMOLU_DISABLE -}
+ data/examples/other/disabling/empty-disabled-region-out.hs view
@@ -0,0 +1,7 @@+{- ORMOLU_DISABLE -}+{- ORMOLU_ENABLE -}+foo = 0+{- ORMOLU_DISABLE -}+{- ORMOLU_ENABLE -}+bar = 1+{- ORMOLU_DISABLE -}
+ data/examples/other/disabling/empty-disabled-region.hs view
@@ -0,0 +1,7 @@+{- ORMOLU_DISABLE -}+{- ORMOLU_ENABLE -}+foo = 0+{- ORMOLU_DISABLE -}+{- ORMOLU_ENABLE -}+bar = 1+{- ORMOLU_DISABLE -}
+ data/examples/other/disabling/line-pragma-in-disabled-region-four-out.hs view
@@ -0,0 +1,7 @@+module Foo (foo) where++{- ORMOLU_DISABLE -}+foo=+{-# LINE 11 "Abc.hs" #-}+  this . line $ ((is automatically generated) Haskell<>code)+{- ORMOLU_ENABLE -}
+ data/examples/other/disabling/line-pragma-in-disabled-region-out.hs view
@@ -0,0 +1,7 @@+module Foo (foo) where++{- ORMOLU_DISABLE -}+foo=+{-# LINE 11 "Abc.hs" #-}+  this . line $ ((is automatically generated) Haskell<>code)+{- ORMOLU_ENABLE -}
+ data/examples/other/disabling/line-pragma-in-disabled-region.hs view
@@ -0,0 +1,7 @@+module Foo(foo) where ++{- ORMOLU_DISABLE -}+foo=+{-# LINE 11 "Abc.hs" #-}+  this . line $ ((is automatically generated) Haskell<>code)+{- ORMOLU_ENABLE -}
+ data/examples/other/disabling/mixed-styles-four-out.hs view
@@ -0,0 +1,17 @@+module Foo (foo, bar, baz, qux) where++{- ORMOLU_DISABLE -}+foo :: Char+foo =  'a'+{- FOURMOLU_ENABLE -}++bar :: Char+bar = 'b'++{- FOURMOLU_DISABLE -}+baz :: Char+baz =  'c'+{- ORMOLU_ENABLE -}++qux :: Char+qux = 'd'
+ data/examples/other/disabling/mixed-styles-out.hs view
@@ -0,0 +1,17 @@+module Foo (foo, bar, baz, qux) where++{- ORMOLU_DISABLE -}+foo :: Char+foo =  'a'+{- FOURMOLU_ENABLE -}++bar :: Char+bar = 'b'++{- FOURMOLU_DISABLE -}+baz :: Char+baz =  'c'+{- ORMOLU_ENABLE -}++qux :: Char+qux = 'd'
+ data/examples/other/disabling/mixed-styles.hs view
@@ -0,0 +1,17 @@+module Foo (foo, bar, baz, qux) where++{- ORMOLU_DISABLE -}+foo :: Char+foo =  'a'+{- FOURMOLU_ENABLE -}++bar :: Char+bar =  'b'++{- FOURMOLU_DISABLE -}+baz :: Char+baz =  'c'+{- ORMOLU_ENABLE -}++qux :: Char+qux =  'd'
+ data/examples/other/disabling/normalize-magic-comments-four-out.hs view
@@ -0,0 +1,8 @@+{- ORMOLU_DISABLE -}+  {-  ORMOLU_DISABLE   -}+foo=bar+{- ORMOLU_ENABLE -}+{-ORMOLU_ENABLE     -}+bar = baz+{- ORMOLU_DISABLE -}+baz=foo
+ data/examples/other/disabling/normalize-magic-comments-out.hs view
@@ -0,0 +1,8 @@+{- ORMOLU_DISABLE -}+  {-  ORMOLU_DISABLE   -}+foo=bar+{- ORMOLU_ENABLE -}+{-ORMOLU_ENABLE     -}+bar = baz+{- ORMOLU_DISABLE -}+baz=foo
+ data/examples/other/disabling/normalize-magic-comments.hs view
@@ -0,0 +1,8 @@+  {-ORMOLU_DISABLE   -}+  {-  ORMOLU_DISABLE   -}+foo=bar+{-   ORMOLU_ENABLE-}+    {-ORMOLU_ENABLE     -}+bar=baz+{-   ORMOLU_DISABLE-}+baz=foo
+ data/examples/other/disabling/preserve-empty-lines-four-out.hs view
@@ -0,0 +1,11 @@+{- ORMOLU_DISABLE -}+bar :: Int+bar = 2+++baz :: Int+baz = 3+{- ORMOLU_ENABLE -}++foo :: Int+foo = 1
+ data/examples/other/disabling/preserve-empty-lines-out.hs view
@@ -0,0 +1,11 @@+{- ORMOLU_DISABLE -}+bar :: Int+bar = 2+++baz :: Int+baz = 3+{- ORMOLU_ENABLE -}++foo :: Int+foo = 1
+ data/examples/other/disabling/preserve-empty-lines.hs view
@@ -0,0 +1,12 @@+{- ORMOLU_DISABLE -}+bar :: Int+bar = 2+++baz :: Int+baz = 3+{- ORMOLU_ENABLE -}+++foo :: Int+foo = 1
+ data/examples/other/disabling/preserve-trailing-whitespace-four-out.hs view
@@ -0,0 +1,5 @@+foo = 2++{- ORMOLU_DISABLE -}+bar = 3  +{- ORMOLU_ENABLE -}
+ data/examples/other/disabling/preserve-trailing-whitespace-out.hs view
@@ -0,0 +1,5 @@+foo = 2++{- ORMOLU_DISABLE -}+bar = 3  +{- ORMOLU_ENABLE -}
+ data/examples/other/disabling/preserve-trailing-whitespace.hs view
@@ -0,0 +1,5 @@+foo = 2  ++{- ORMOLU_DISABLE -}+bar = 3  +{- ORMOLU_ENABLE -}
+ data/examples/other/disabling/single-definition-four-out.hs view
@@ -0,0 +1,10 @@+module Foo (foo, bar) where++{- ORMOLU_DISABLE -}+foo :: Int -> Int+foo = (+5)+{- ORMOLU_ENABLE -}++bar :: Bool -> Bool+bar True = True+bar False = True
+ data/examples/other/disabling/single-definition-out.hs view
@@ -0,0 +1,10 @@+module Foo (foo, bar) where++{- ORMOLU_DISABLE -}+foo :: Int -> Int+foo = (+5)+{- ORMOLU_ENABLE -}++bar :: Bool -> Bool+bar True = True+bar False = True
+ data/examples/other/disabling/single-definition.hs view
@@ -0,0 +1,10 @@+module Foo (foo,bar) where++{- ORMOLU_DISABLE -}+foo :: Int -> Int+foo = (+5)+{- ORMOLU_ENABLE -}++bar :: Bool -> Bool+bar True  = True+bar False = True
+ data/examples/other/disabling/whole-file-four-out.hs view
@@ -0,0 +1,10 @@+{- ORMOLU_DISABLE -}++module Foo (foo,bar) where++foo :: Int -> Int+foo = (+5)++bar :: Bool -> Bool+bar True  = True+bar False = True
+ data/examples/other/disabling/whole-file-out.hs view
@@ -0,0 +1,10 @@+{- ORMOLU_DISABLE -}++module Foo (foo,bar) where++foo :: Int -> Int+foo = (+5)++bar :: Bool -> Bool+bar True  = True+bar False = True
+ data/examples/other/disabling/whole-file.hs view
@@ -0,0 +1,10 @@+{-    ORMOLU_DISABLE     -}++module Foo (foo,bar) where++foo :: Int -> Int+foo = (+5)++bar :: Bool -> Bool+bar True  = True+bar False = True
+ data/examples/other/haddock-without-module-header-four-out.hs view
@@ -0,0 +1,5 @@+-- | Foo+main = main++-- | Bar+data Bar
+ data/examples/other/haddock-without-module-header-out.hs view
@@ -0,0 +1,5 @@+-- | Foo+main = main++-- | Bar+data Bar
+ data/examples/other/haddock-without-module-header.hs view
@@ -0,0 +1,5 @@+-- | Foo+main =  main++-- | Bar+data Bar
+ data/examples/other/linear-arrows-four-out.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE UnicodeSyntax #-}++type a % b = (a, b)++type Foo a m b = a % m -> b+type Bar a m b = a %m -> b++type Baz = a %1 -> b++type M =+    a %1 ->+    b %m ->+    c %1 ->+    d++test ::+    a %1 ->+    b %1 ->+    c %m ->+    d+test = test
+ data/examples/other/linear-arrows-out.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE UnicodeSyntax #-}++type a % b = (a, b)++type Foo a m b = a % m -> b++type Bar a m b = a %m -> b++type Baz = a %1 -> b++type M =+  a %1 ->+  b %m ->+  c %1 ->+  d++test ::+  a %1 ->+  b %1 ->+  c %m ->+  d+test = test
+ data/examples/other/linear-arrows.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE UnicodeSyntax #-}++type a % b = (a,b)++type Foo a m b = a % m -> b+type Bar a m b = a %m -> b++type Baz = a ⊸ b++type M = a %1+  -> b %m ->+  c+  %1 -> d++test :: a+      ⊸ b+  %1 -> c+  %m -> d+test = test
+ data/examples/other/no-linear-arrows-four-out.hs view
@@ -0,0 +1,4 @@+type a % b = (a, b)++type Foo a m b = a % m -> b+type Bar a m b = a % m -> b
+ data/examples/other/no-linear-arrows-out.hs view
@@ -0,0 +1,5 @@+type a % b = (a, b)++type Foo a m b = a % m -> b++type Bar a m b = a % m -> b
+ data/examples/other/no-linear-arrows.hs view
@@ -0,0 +1,4 @@+type a % b = (a,b)++type Foo a m b = a % m -> b+type Bar a m b = a %m -> b
+ data/parse-failures/disabling-preserves-error-location.hs view
@@ -0,0 +1,11 @@+module Main (main) where++{- ORMOLU_DISABLE -}+foo Int+foo Int+foo 5 EU>>>>++{- ORMOLU_ENABLE -}++main :: IO ()+main = return <<<
+ data/parse-failures/line-pragma.hs view
@@ -0,0 +1,5 @@+module Foo (foo,bar,baz) where+bar = foo+{-# LINE 113 "Abc.hs" #-}+foo = (some <$> ( automatically $ generated ))))))))) invalid Haskell code+baz = bar
fourmolu.cabal view
@@ -1,56 +1,21 @@-cabal-version:   1.18-name:            fourmolu-version:         0.3.0.0-license:         BSD3-license-file:    LICENSE.md+cabal-version:      2.4+name:               fourmolu+version:            0.4.0.0+license:            BSD-3-Clause+license-file:       LICENSE.md maintainer:     Matt Parsons <parsonsmatt@gmail.com>     George Thomas <georgefsthomas@gmail.com>--tested-with:     ghc ==8.6.5 ghc ==8.8.4 ghc ==8.10.1-homepage:        https://github.com/parsonsmatt/fourmolu-bug-reports:     https://github.com/parsonsmatt/fourmolu/issues-synopsis:        A formatter for Haskell source code-description:     A formatter for Haskell source code.-category:        Development, Formatting-build-type:      Simple-data-files:-    data/examples/declaration/annotation/*.hs-    data/examples/declaration/class/*.hs-    data/examples/declaration/data/*.hs-    data/examples/declaration/data/gadt/*.hs-    data/examples/declaration/default/*.hs-    data/examples/declaration/deriving/*.hs-    data/examples/declaration/foreign/*.hs-    data/examples/declaration/instance/*.hs-    data/examples/declaration/rewrite-rule/*.hs-    data/examples/declaration/role-annotation/*.hs-    data/examples/declaration/signature/complete/*.hs-    data/examples/declaration/signature/fixity/*.hs-    data/examples/declaration/signature/inline/*.hs-    data/examples/declaration/signature/minimal/*.hs-    data/examples/declaration/signature/pattern/*.hs-    data/examples/declaration/signature/set-cost-centre/*.hs-    data/examples/declaration/signature/specialize/*.hs-    data/examples/declaration/signature/type/*.hs-    data/examples/declaration/splice/*.hs-    data/examples/declaration/type-families/closed-type-family/*.hs-    data/examples/declaration/type-families/data-family/*.hs-    data/examples/declaration/type-families/type-family/*.hs-    data/examples/declaration/type-synonyms/*.hs-    data/examples/declaration/type/*.hs-    data/examples/declaration/value/function/*.hs-    data/examples/declaration/value/function/arrow/*.hs-    data/examples/declaration/value/function/comprehension/*.hs-    data/examples/declaration/value/function/do/*.hs-    data/examples/declaration/value/function/infix/*.hs-    data/examples/declaration/value/function/pattern/*.hs-    data/examples/declaration/value/other/*.hs-    data/examples/declaration/value/pattern-synonyms/*.hs-    data/examples/declaration/warning/*.hs-    data/examples/import/*.hs-    data/examples/module-header/*.hs-    data/examples/other/*.hs+tested-with:        ghc ==8.8.4 ghc ==8.10.7 ghc ==9.0.1+homepage:           https://github.com/parsonsmatt/fourmolu+bug-reports:        https://github.com/parsonsmatt/fourmolu/issues+synopsis:           A formatter for Haskell source code+description:        A formatter for Haskell source code.+category:           Development, Formatting+build-type:         Simple+extra-source-files:+    data/**/*.hs+    data/**/*.txt  extra-doc-files:     CHANGELOG.md@@ -69,7 +34,8 @@     exposed-modules:         Ormolu         Ormolu.Config-        Ormolu.Diff+        Ormolu.Diff.ParseResult+        Ormolu.Diff.Text         Ormolu.Exception         Ormolu.Imports         Ormolu.Parser@@ -77,7 +43,6 @@         Ormolu.Parser.CommentStream         Ormolu.Parser.Pragma         Ormolu.Parser.Result-        Ormolu.Parser.Shebang         Ormolu.Printer         Ormolu.Printer.Combinators         Ormolu.Printer.Comments@@ -106,31 +71,35 @@         Ormolu.Printer.SpanStream         Ormolu.Processing.Common         Ormolu.Processing.Cpp-        Ormolu.Processing.Postprocess         Ormolu.Processing.Preprocess+        Ormolu.Terminal         Ormolu.Utils+        Ormolu.Utils.Extensions+        Ormolu.Utils.IO      hs-source-dirs:   src-    other-modules:-        GHC-        GHC.DynFlags-+    other-modules:    GHC.DynFlags     default-language: Haskell2010     build-depends:-        aeson >=1.5.2 && <1.6,+        Diff >=0.4 && <1.0,+        aeson >=1.4.0.0 && <1.6,+        ansi-terminal >=0.10 && <1.0,         base >=4.12 && <5.0,-        bytestring >=0.2 && <0.11,+        bytestring >=0.2 && <0.12,         containers >=0.5 && <0.7,         directory >=1.3.3 && <1.4,         dlist >=0.8 && <2.0,         exceptions >=0.6 && <0.11,         filepath >=1.4.2.1 && <1.5,-        ghc-lib-parser >=8.10 && <8.11,+        ghc-lib-parser >=9.0 && <9.1,         HsYAML >=0.2 && <0.3,         HsYAML-aeson >=0.2 && <0.3,         mtl >=2.0 && <3.0,         syb >=0.7 && <0.8,-        text >=0.2 && <1.3+        text >=0.2 && <1.3,+        filepath >=1.2 && <1.5,+        directory ^>=1.3,+        Cabal ^>=3.4      if flag(dev)         ghc-options:@@ -141,16 +110,21 @@     else         ghc-options: -O2 -Wall +    if impl(ghc <8.10.0)+        ghc-options: -fmax-pmcheck-iterations=3000000+ executable fourmolu     main-is:          Main.hs     hs-source-dirs:   app     other-modules:    Paths_fourmolu+    autogen-modules:  Paths_fourmolu     default-language: Haskell2010     build-depends:-        fourmolu -any,+        fourmolu,         base >=4.12 && <5.0,         directory >=1.3.3 && <1.4,-        ghc-lib-parser >=8.10 && <8.11,+        filepath >=1.2 && <1.5,+        ghc-lib-parser >=9.0 && <9.1,         gitrev >=1.3 && <1.4,         optparse-applicative >=0.14 && <0.17,         text >=0.2 && <1.3@@ -165,23 +139,29 @@         ghc-options: -O2 -Wall -rtsopts  test-suite tests-    type:             exitcode-stdio-1.0-    main-is:          Spec.hs-    build-tools:      hspec-discover >=2.0 && <3.0-    hs-source-dirs:   tests+    type:               exitcode-stdio-1.0+    main-is:            Spec.hs+    build-tool-depends: hspec-discover:hspec-discover >=2.0 && <3.0+    hs-source-dirs:     tests     other-modules:+        Ormolu.CabalExtensionsSpec+        Ormolu.Diff.TextSpec+        Ormolu.Parser.OptionsSpec+        Ormolu.Parser.ParseFailureSpec         Ormolu.Parser.PragmaSpec         Ormolu.PrinterSpec -    default-language: Haskell2010+    default-language:   Haskell2010     build-depends:+        fourmolu,         base >=4.12 && <5.0,         containers >=0.5 && <0.7,+        directory ^>=1.3,         filepath >=1.2 && <1.5,         hspec >=2.0 && <3.0,-        fourmolu -any,-        path >=0.6 && <0.8,+        path >=0.6 && <0.10,         path-io >=1.4.2 && <2.0,+        temporary ^>=1.3,         text >=0.2 && <1.3      if flag(dev)
− src/GHC.hs
@@ -1,12 +0,0 @@-module GHC-  ( module X,-  )-where--import ApiAnnotation as X-import BasicTypes as X-import GHC.Hs as X-import GHC.Hs.Instances as X ()-import Module as X-import RdrName as X-import SrcLoc as X
src/GHC/DynFlags.hs view
@@ -7,11 +7,11 @@   ) where -import Config-import DynFlags-import Fingerprint+import GHC.Driver.Session import GHC.Platform-import ToolSettings+import GHC.Settings+import GHC.Settings.Config+import GHC.Utils.Fingerprint  fakeSettings :: Settings fakeSettings =@@ -30,7 +30,14 @@                 { platformMini_arch = ArchUnknown,                   platformMini_os = OSUnknown                 },-            platformUnregisterised = True+            platformUnregisterised = True,+            platformByteOrder = LittleEndian,+            platformHasGnuNonexecStack = False,+            platformHasIdentDirective = False,+            platformHasSubsectionsViaSymbols = False,+            platformIsCrossCompiling = False,+            platformLeadingUnderscore = False,+            platformTablesNextToCode = False           },       sPlatformMisc = PlatformMisc {},       sPlatformConstants =
src/Ormolu.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}  -- | A formatter for Haskell source code. module Ormolu@@ -6,6 +7,7 @@     ormoluFile,     ormoluStdin,     Config (..),+    ColorMode (..),     RegionIndices (..),     defaultConfig,     DynOption (..),@@ -22,21 +24,23 @@   ) where -import qualified CmdLineParser as GHC import Control.Exception import Control.Monad import Control.Monad.IO.Class (MonadIO (..)) import Data.Text (Text) import qualified Data.Text as T import Debug.Trace+import qualified GHC.Driver.CmdLine as GHC+import qualified GHC.Types.SrcLoc as GHC import Ormolu.Config-import Ormolu.Diff+import Ormolu.Diff.ParseResult+import Ormolu.Diff.Text import Ormolu.Exception import Ormolu.Parser import Ormolu.Parser.Result import Ormolu.Printer import Ormolu.Utils (showOutputable)-import qualified SrcLoc as GHC+import Ormolu.Utils.IO  -- | Format a 'String', return formatted version as 'Text'. --@@ -65,35 +69,38 @@   when (cfgDebug cfg) $ do     traceM "warnings:\n"     traceM (concatMap showWarn warnings)-    traceM (prettyPrintParseResult result0)   -- We're forcing 'txt' here because otherwise errors (such as messages   -- about not-yet-supported functionality) will be thrown later when we try   -- to parse the rendered code back, inside of GHC monad wrapper which will   -- lead to error messages presenting the exceptions as GHC bugs.   let !txt = printModule result0 $ cfgPrinterOpts cfgWithIndices   when (not (cfgUnsafe cfg) || cfgCheckIdempotence cfg) $ do-    let pathRendered = path ++ "<rendered>"     -- Parse the result of pretty-printing again and make sure that AST     -- is the same as AST of original snippet module span positions.     (_, result1) <-       parseModule'         cfg         OrmoluOutputParsingFailed-        pathRendered+        path         (T.unpack txt)-    unless (cfgUnsafe cfg) $-      case diffParseResult result0 result1 of-        Same -> return ()-        Different ss -> liftIO $ throwIO (OrmoluASTDiffers path ss)+    unless (cfgUnsafe cfg) $ do+      when (length result0 /= length result1) $+        liftIO $ throwIO (OrmoluASTDiffers path [])+      forM_ (result0 `zip` result1) $ \case+        (ParsedSnippet s, ParsedSnippet s') -> case diffParseResult s s' of+          Same -> return ()+          Different ss -> liftIO $ throwIO (OrmoluASTDiffers path ss)+        (RawSnippet {}, RawSnippet {}) -> pure ()+        _ -> liftIO $ throwIO (OrmoluASTDiffers path [])     -- Try re-formatting the formatted result to check if we get exactly     -- the same output.     when (cfgCheckIdempotence cfg) $       let txt2 = printModule result1 $ cfgPrinterOpts cfgWithIndices-       in case diffText txt txt2 pathRendered of+       in case diffText txt txt2 path of             Nothing -> return ()-            Just (loc, l, r) ->+            Just diff ->               liftIO $-                throwIO (OrmoluNonIdempotentOutput loc l r)+                throwIO (OrmoluNonIdempotentOutput diff)   return txt  -- | Load a file and format it. The file stays intact and the rendered@@ -110,7 +117,7 @@   -- | Resulting rendition   m Text ormoluFile cfg path =-  liftIO (readFile path) >>= ormolu cfg path+  readFileUtf8 path >>= ormolu cfg path . T.unpack  -- | Read input from stdin and format it. --@@ -139,7 +146,7 @@   FilePath ->   -- | Actual input for the parser   String ->-  m ([GHC.Warn], ParseResult)+  m ([GHC.Warn], [SourceSnippet]) parseModule' cfg mkException path str = do   (warnings, r) <- parseModule cfg path str   case r of
src/Ormolu/Config.hs view
@@ -10,6 +10,7 @@ -- | Configuration options used by the tool. module Ormolu.Config   ( Config (..),+    ColorMode (..),     RegionIndices (..),     RegionDeltas (..),     defaultConfig,@@ -43,7 +44,8 @@ import Data.YAML (Pos) import Data.YAML.Aeson (decode1) import GHC.Generics (Generic)-import qualified SrcLoc as GHC+import qualified GHC.Types.SrcLoc as GHC+import Ormolu.Terminal (ColorMode (..)) import System.Directory   ( XdgDirectory (XdgConfig),     findFile,@@ -62,6 +64,8 @@     cfgDebug :: !Bool,     -- | Checks if re-formatting the result is idempotent     cfgCheckIdempotence :: !Bool,+    -- | Whether to use colors and other features of ANSI terminals+    cfgColorMode :: !ColorMode,     -- | Region selection     cfgRegion :: !region,     cfgPrinterOpts :: !PrinterOptsTotal@@ -95,6 +99,7 @@       cfgUnsafe = False,       cfgDebug = False,       cfgCheckIdempotence = False,+      cfgColorMode = Auto,       cfgRegion =         RegionIndices           { regionStartLine = Nothing,
− src/Ormolu/Diff.hs
@@ -1,158 +0,0 @@-{-# LANGUAGE RankNTypes #-}---- | Diffing GHC ASTs modulo span positions.-module Ormolu.Diff-  ( Diff (..),-    diffParseResult,-    diffText,-  )-where--import Data.ByteString (ByteString)-import Data.Generics-import Data.Text (Text)-import qualified Data.Text as T-import qualified FastString as GHC-import GHC-import Ormolu.Imports (normalizeImports)-import Ormolu.Parser.CommentStream-import Ormolu.Parser.Result-import Ormolu.Utils---- | Result of comparing two 'ParseResult's.-data Diff-  = -- | Two parse results are the same-    Same-  | -- | Two parse results differ-    Different [SrcSpan]--instance Semigroup Diff where-  Same <> a = a-  a <> Same = a-  Different xs <> Different ys = Different (xs ++ ys)--instance Monoid Diff where-  mempty = Same---- | Return 'Diff' of two 'ParseResult's.-diffParseResult :: ParseResult -> ParseResult -> Diff-diffParseResult-  ParseResult-    { prCommentStream = cstream0,-      prParsedSource = hs0-    }-  ParseResult-    { prCommentStream = cstream1,-      prParsedSource = hs1-    } =-    matchIgnoringSrcSpans cstream0 cstream1-      <> matchIgnoringSrcSpans-        hs0 {hsmodImports = concat . normalizeImports False $ hsmodImports hs0}-        hs1 {hsmodImports = concat . normalizeImports False $ hsmodImports hs1}---- | Compare two values for equality disregarding differences in 'SrcSpan's--- and the ordering of import lists.-matchIgnoringSrcSpans :: Data a => a -> a -> Diff-matchIgnoringSrcSpans = genericQuery-  where-    genericQuery :: GenericQ (GenericQ Diff)-    genericQuery x y-      -- 'ByteString' implements 'Data' instance manually and does not-      -- implement 'toConstr', so we have to deal with it in a special way.-      | Just x' <- cast x,-        Just y' <- cast y =-        if x' == (y' :: ByteString)-          then Same-          else Different []-      | typeOf x == typeOf y,-        toConstr x == toConstr y =-        mconcat $-          gzipWithQ-            ( genericQuery-                `extQ` srcSpanEq-                `extQ` commentEq-                `extQ` sourceTextEq-                `extQ` hsDocStringEq-                `extQ` importDeclQualifiedStyleEq-                `ext2Q` forLocated-            )-            x-            y-      | otherwise = Different []-    srcSpanEq :: SrcSpan -> GenericQ Diff-    srcSpanEq _ _ = Same-    commentEq :: Comment -> GenericQ Diff-    commentEq (Comment _ x) d =-      case cast d :: Maybe Comment of-        Nothing -> Different []-        Just (Comment _ y) ->-          if x == y-            then Same-            else Different []-    sourceTextEq :: SourceText -> GenericQ Diff-    sourceTextEq _ _ = Same-    importDeclQualifiedStyleEq :: ImportDeclQualifiedStyle -> GenericQ Diff-    importDeclQualifiedStyleEq d0 d1' =-      case (d0, cast d1' :: Maybe ImportDeclQualifiedStyle) of-        (x, Just x') | x == x' -> Same-        (QualifiedPre, Just QualifiedPost) -> Same-        (QualifiedPost, Just QualifiedPre) -> Same-        _ -> Different []-    hsDocStringEq :: HsDocString -> GenericQ Diff-    hsDocStringEq str0 str1' =-      case cast str1' :: Maybe HsDocString of-        Nothing -> Different []-        Just str1 ->-          if splitDocString str0 == splitDocString str1-            then Same-            else Different []-    forLocated ::-      (Data e0, Data e1) =>-      GenLocated e0 e1 ->-      GenericQ Diff-    forLocated x@(L mspn _) y =-      maybe id appendSpan (cast mspn) (genericQuery x y)-    appendSpan :: SrcSpan -> Diff -> Diff-    appendSpan s (Different ss) | fresh && helpful = Different (s : ss)-      where-        fresh = not $ any (`isSubspanOf` s) ss-        helpful = isGoodSrcSpan s-    appendSpan _ d = d---- | Diff two texts and return the location they start to differ, alongside--- with excerpts around that location.-diffText ::-  -- | Text before-  Text ->-  -- | Text after-  Text ->-  -- | Path to use to construct 'GHC.RealSrcLoc'-  FilePath ->-  Maybe (GHC.RealSrcLoc, Text, Text)-diffText left right fp =-  case go (0, 0, 0) left right of-    Nothing -> Nothing-    Just (row, col, loc) ->-      Just-        ( GHC.mkRealSrcLoc (GHC.mkFastString fp) row col,-          getSpan loc left,-          getSpan loc right-        )-  where-    go (row, col, loc) t1 t2 =-      case (T.uncons t1, T.uncons t2) of-        -- both text empty, all good-        (Nothing, Nothing) ->-          Nothing-        -- first chars are the same, adjust position and recurse-        (Just (c1, r1), Just (c2, r2))-          | c1 == c2 ->-            let (row', col', loc') =-                  if c1 == '\n'-                    then (row + 1, 0, loc + 1)-                    else (row, col + 1, loc + 1)-             in go (row', col', loc') r1 r2-        -- something is different, return the position-        _ ->-          Just (row, col, loc)-    getSpan loc = T.take 20 . T.drop (loc - 10)
+ src/Ormolu/Diff/ParseResult.hs view
@@ -0,0 +1,149 @@+{-# LANGUAGE BangPatterns #-}+-- needed on GHC 9.0 due to simplified subsumption+{-# LANGUAGE ImpredicativeTypes #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ViewPatterns #-}++-- | This module allows us to diff two 'ParseResult's.+module Ormolu.Diff.ParseResult+  ( ParseResultDiff (..),+    diffParseResult,+  )+where++import Data.ByteString (ByteString)+import Data.Generics+import GHC.Hs+import GHC.Types.Basic+import GHC.Types.SrcLoc+import Ormolu.Imports (normalizeImports)+import Ormolu.Parser.CommentStream+import Ormolu.Parser.Result+import Ormolu.Utils++-- | Result of comparing two 'ParseResult's.+data ParseResultDiff+  = -- | Two parse results are the same+    Same+  | -- | Two parse results differ+    Different [SrcSpan]++instance Semigroup ParseResultDiff where+  Same <> a = a+  a <> Same = a+  Different xs <> Different ys = Different (xs ++ ys)++instance Monoid ParseResultDiff where+  mempty = Same++-- | Return 'Diff' of two 'ParseResult's.+diffParseResult ::+  ParseResult ->+  ParseResult ->+  ParseResultDiff+diffParseResult+  ParseResult+    { prCommentStream = cstream0,+      prParsedSource = hs0+    }+  ParseResult+    { prCommentStream = cstream1,+      prParsedSource = hs1+    } =+    matchIgnoringSrcSpans cstream0 cstream1+      <> matchIgnoringSrcSpans+        hs0 {hsmodImports = concat . normalizeImports False $ hsmodImports hs0}+        hs1 {hsmodImports = concat . normalizeImports False $ hsmodImports hs1}++-- | Compare two values for equality disregarding the following aspects:+--+--     * 'SrcSpan's+--     * ordering of import lists+--     * style (ASCII vs Unicode) of arrows+--     * LayoutInfo (brace style) in extension fields+matchIgnoringSrcSpans :: Data a => a -> a -> ParseResultDiff+matchIgnoringSrcSpans a = genericQuery a+  where+    genericQuery :: GenericQ (GenericQ ParseResultDiff)+    genericQuery x y+      -- 'ByteString' implements 'Data' instance manually and does not+      -- implement 'toConstr', so we have to deal with it in a special way.+      | Just x' <- cast x,+        Just y' <- cast y =+        if x' == (y' :: ByteString)+          then Same+          else Different []+      | typeOf x == typeOf y,+        toConstr x == toConstr y =+        mconcat $+          gzipWithQ+            ( genericQuery+                `extQ` srcSpanEq+                `extQ` commentEq+                `extQ` sourceTextEq+                `extQ` hsDocStringEq+                `extQ` importDeclQualifiedStyleEq+                `extQ` unicodeArrowStyleEq+                `extQ` layoutInfoEq+                `ext2Q` forLocated+            )+            x+            y+      | otherwise = Different []+    srcSpanEq :: SrcSpan -> GenericQ ParseResultDiff+    srcSpanEq _ _ = Same+    commentEq :: Comment -> GenericQ ParseResultDiff+    commentEq (Comment _ x) d =+      case cast d :: Maybe Comment of+        Nothing -> Different []+        Just (Comment _ y) ->+          if x == y+            then Same+            else Different []+    sourceTextEq :: SourceText -> GenericQ ParseResultDiff+    sourceTextEq _ _ = Same+    importDeclQualifiedStyleEq ::+      ImportDeclQualifiedStyle ->+      GenericQ ParseResultDiff+    importDeclQualifiedStyleEq d0 d1' =+      case (d0, cast d1' :: Maybe ImportDeclQualifiedStyle) of+        (x, Just x') | x == x' -> Same+        (QualifiedPre, Just QualifiedPost) -> Same+        (QualifiedPost, Just QualifiedPre) -> Same+        _ -> Different []+    hsDocStringEq :: HsDocString -> GenericQ ParseResultDiff+    hsDocStringEq str0 str1' =+      case cast str1' :: Maybe HsDocString of+        Nothing -> Different []+        Just str1 ->+          if splitDocString str0 == splitDocString str1+            then Same+            else Different []+    forLocated ::+      (Data e0, Data e1) =>+      GenLocated e0 e1 ->+      GenericQ ParseResultDiff+    forLocated x@(L mspn _) y =+      maybe id appendSpan (cast mspn) (genericQuery x y)+    appendSpan :: SrcSpan -> ParseResultDiff -> ParseResultDiff+    appendSpan s (Different ss) | fresh && helpful = Different (s : ss)+      where+        fresh = not $ any (`isSubspanOf` s) ss+        helpful = isGoodSrcSpan s+    appendSpan _ d = d+    -- as we normalize arrow styles (e.g. -> vs →), we consider them equal here+    unicodeArrowStyleEq :: HsArrow GhcPs -> GenericQ ParseResultDiff+    unicodeArrowStyleEq (HsUnrestrictedArrow _) (castArrow -> Just (HsUnrestrictedArrow _)) = Same+    unicodeArrowStyleEq (HsLinearArrow _) (castArrow -> Just (HsLinearArrow _)) = Same+    unicodeArrowStyleEq (HsExplicitMult _ t) (castArrow -> Just (HsExplicitMult _ t')) = genericQuery t t'+    unicodeArrowStyleEq _ _ = Different []+    castArrow :: Typeable a => a -> Maybe (HsArrow GhcPs)+    castArrow = cast+    -- LayoutInfo ~ XClassDecl GhcPs tracks brace information+    layoutInfoEq :: LayoutInfo -> GenericQ ParseResultDiff+    layoutInfoEq _ (cast -> Just (_ :: LayoutInfo)) = Same+    layoutInfoEq _ _ = Different []
+ src/Ormolu/Diff/Text.hs view
@@ -0,0 +1,286 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}++-- | This module allows us to diff two 'Text' values.+module Ormolu.Diff.Text+  ( TextDiff,+    diffText,+    printTextDiff,+  )+where++import Control.Monad+import qualified Data.Algorithm.Diff as D+import Data.Maybe (listToMaybe)+import Data.Text (Text)+import qualified Data.Text as T+import Ormolu.Terminal++----------------------------------------------------------------------------+-- Types++-- | Result of diffing two 'Text's.+data TextDiff = TextDiff FilePath DiffList+  deriving (Eq)++instance Show TextDiff where+  show (TextDiff path _) = "TextDiff " ++ show path ++ " _"++-- | List of lines tagged by 'D.Both', 'D.First', or 'D.Second'.+type DiffList = [D.Diff [Text]]++-- | Similar to 'DiffList', but with line numbers assigned.+type DiffList' = [D.Diff [(Int, Int, Text)]]++-- | Diff hunk.+data Hunk = Hunk+  { hunkFirstStartLine :: Int,+    hunkFirstLength :: Int,+    hunkSecondStartLine :: Int,+    hunkSecondLength :: Int,+    hunkDiff :: DiffList+  }++----------------------------------------------------------------------------+-- API++-- | Diff two texts and produce a 'TextDiff'.+diffText ::+  -- | Text before+  Text ->+  -- | Text after+  Text ->+  -- | Path to use+  FilePath ->+  -- | The resulting diff or 'Nothing' if the inputs are identical+  Maybe TextDiff+diffText a b path =+  if all isBoth xs+    then Nothing+    else Just (TextDiff path xs)+  where+    xs = D.getGroupedDiff (lines' a) (lines' b)+    isBoth = \case+      D.Both _ _ -> True+      D.First _ -> False+      D.Second _ -> False+    -- T.lines ignores trailing blank lines+    lines' = T.splitOn "\n"++-- | Print the given 'TextDiff' as a 'Term' action. This function tries to+-- mimic the style of @git diff@.+printTextDiff :: TextDiff -> Term ()+printTextDiff (TextDiff path xs) = do+  (bold . putS) path+  newline+  forM_ (toHunks (assignLines xs)) $ \Hunk {..} -> do+    cyan $ do+      put "@@ -"+      putS (show hunkFirstStartLine)+      put ","+      putS (show hunkFirstLength)+      put " +"+      putS (show hunkSecondStartLine)+      put ","+      putS (show hunkSecondLength)+      put " @@"+    newline+    forM_ hunkDiff $ \case+      D.Both ys _ ->+        forM_ ys $ \y -> do+          unless (T.null y) $+            put "  "+          put y+          newline+      D.First ys ->+        forM_ ys $ \y -> red $ do+          put "-"+          unless (T.null y) $+            put " "+          put y+          newline+      D.Second ys ->+        forM_ ys $ \y -> green $ do+          put "+"+          unless (T.null y) $+            put " "+          put y+          newline++----------------------------------------------------------------------------+-- Helpers++-- | Assign lines to a 'DiffList'.+assignLines :: DiffList -> DiffList'+assignLines = go 1 1 id+  where+    go _ _ acc [] = acc []+    go !firstLine !secondLine acc (x : xs) =+      case x of+        D.Both a b ->+          let firstInc = length a+              secondInc = length b+              a' =+                zipWith3+                  (,,)+                  (iterate (+ 1) firstLine)+                  (iterate (+ 1) secondLine)+                  a+           in go+                (firstLine + firstInc)+                (secondLine + secondInc)+                (acc . ((D.Both a' a') :))+                xs+        D.First a ->+          let firstInc = length a+              a' =+                zipWith3+                  (,,)+                  (iterate (+ 1) firstLine)+                  (repeat secondLine)+                  a+           in go+                (firstLine + firstInc)+                secondLine+                (acc . ((D.First a') :))+                xs+        D.Second b ->+          let secondInc = length b+              b' =+                zipWith3+                  (,,)+                  (repeat firstLine)+                  (iterate (+ 1) secondLine)+                  b+           in go+                firstLine+                (secondLine + secondInc)+                (acc . ((D.Second b') :))+                xs++-- | Form 'Hunk's from a 'DiffList''.+toHunks :: DiffList' -> [Hunk]+toHunks = go 0 False id id []+  where+    -- How many lines of context (that is, lines present in both texts) to+    -- show per hunk.+    margin = 3+    go ::+      Int ->+      Bool ->+      ([Hunk] -> [Hunk]) ->+      (DiffList' -> DiffList') ->+      [(Int, Int, Text)] ->+      DiffList' ->+      [Hunk]+    go !n gotChanges hunksAcc currentAcc bothHistory = \case+      [] ->+        if gotChanges+          then+            let p = reverse (take margin bothHistory)+                currentAcc' = addBothAfter p currentAcc+             in case formHunk (currentAcc' []) of+                  Nothing -> hunksAcc []+                  Just hunk -> hunksAcc [hunk]+          else hunksAcc []+      (x : xs) ->+        case x of+          D.Both a _ ->+            let currentAcc' = addBothAfter p currentAcc+                p = reverse (drop (n' - margin) bothHistory')+                hunksAcc' =+                  case formHunk (currentAcc' []) of+                    Nothing -> hunksAcc+                    Just hunk -> hunksAcc . (hunk :)+                bothHistory' = reverse a ++ bothHistory+                lena = length a+                n' = n + lena+             in if gotChanges && n' > margin * 2+                  then go 0 False hunksAcc' id bothHistory' xs+                  else go n' gotChanges hunksAcc currentAcc bothHistory' xs+          piece ->+            if gotChanges+              then+                let p = reverse bothHistory+                    currentAcc' = currentAcc . addBothBefore p (piece :)+                 in go 0 True hunksAcc currentAcc' [] xs+              else+                let p = reverse (take margin bothHistory)+                    currentAcc' = addBothBefore p (piece :)+                 in go 0 True hunksAcc currentAcc' [] xs+    addBothBefore [] acc = acc+    addBothBefore p acc = (D.Both p p :) . acc+    addBothAfter [] acc = acc+    addBothAfter p acc = acc . (D.Both p p :)++-- | Form a 'Hunk'.+formHunk :: DiffList' -> Maybe Hunk+formHunk xsRaw = do+  let xs = trimEmpty xsRaw+  hunkFirstStartLine <- listToMaybe xs >>= firstStartLine+  let hunkFirstLength = firstLength xs+  hunkSecondStartLine <- listToMaybe xs >>= secondStartLine+  let hunkSecondLength = secondLength xs+      hunkDiff = mapDiff (fmap third) xs+  return Hunk {..}++-- | Trim empty “both” lines from beginning and end of a 'DiffList''.+trimEmpty :: DiffList' -> DiffList'+trimEmpty = go True id+  where+    go isFirst acc = \case+      [] -> acc []+      [D.Both x _] ->+        let x' = reverse $ dropWhile (T.null . third) (reverse x)+         in go False (acc . (D.Both x' x' :)) []+      (D.Both x _ : xs) ->+        let x' = dropWhile (T.null . third) x+         in if isFirst+              then go False (acc . (D.Both x' x' :)) xs+              else go False (acc . (D.Both x x :)) xs+      (x : xs) ->+        go False (acc . (x :)) xs++firstStartLine :: D.Diff [(Int, Int, a)] -> Maybe Int+firstStartLine = \case+  D.Both ((x, _, _) : _) _ -> Just x+  D.First ((x, _, _) : _) -> Just x+  D.Second ((x, _, _) : _) -> Just x+  _ -> Nothing++firstLength :: [D.Diff [(Int, Int, a)]] -> Int+firstLength = go 0+  where+    go n [] = n+    go !n (x : xs) = case x of+      D.Both as _ -> go (n + length as) xs+      D.First as -> go (n + length as) xs+      D.Second _ -> go n xs++secondStartLine :: D.Diff [(Int, Int, a)] -> Maybe Int+secondStartLine = \case+  D.Both ((_, x, _) : _) _ -> Just x+  D.First ((_, x, _) : _) -> Just x+  D.Second ((_, x, _) : _) -> Just x+  _ -> Nothing++secondLength :: [D.Diff [(Int, Int, a)]] -> Int+secondLength = go 0+  where+    go n [] = n+    go !n (x : xs) = case x of+      D.Both as _ -> go (n + length as) xs+      D.First _ -> go n xs+      D.Second as -> go (n + length as) xs++mapDiff :: (a -> b) -> [D.Diff a] -> [D.Diff b]+mapDiff f = fmap $ \case+  D.Both a b -> D.Both (f a) (f b)+  D.First a -> D.First (f a)+  D.Second b -> D.Second (f b)++third :: (Int, Int, Text) -> Text+third (_, _, x) = x
src/Ormolu/Exception.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}  -- | 'OrmoluException' type and surrounding definitions. module Ormolu.Exception@@ -8,71 +10,105 @@ where  import Control.Exception+import Control.Monad (forM_) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE-import Data.Text (Text)-import qualified GHC-import Ormolu.Utils (showOutputable)-import qualified Outputable as GHC-import System.Exit (ExitCode (..), exitWith)+import qualified Data.Text as T+import GHC.Types.SrcLoc+import Ormolu.Diff.Text (TextDiff, printTextDiff)+import Ormolu.Terminal+import System.Exit (ExitCode (..)) import System.IO  -- | Ormolu exception representing all cases when Ormolu can fail. data OrmoluException   = -- | Parsing of original source code failed-    OrmoluParsingFailed GHC.SrcSpan String+    OrmoluParsingFailed SrcSpan String   | -- | Parsing of formatted source code failed-    OrmoluOutputParsingFailed GHC.SrcSpan String+    OrmoluOutputParsingFailed SrcSpan String   | -- | Original and resulting ASTs differ-    OrmoluASTDiffers FilePath [GHC.SrcSpan]+    OrmoluASTDiffers FilePath [SrcSpan]   | -- | Formatted source code is not idempotent-    OrmoluNonIdempotentOutput GHC.RealSrcLoc Text Text+    OrmoluNonIdempotentOutput TextDiff   | -- | Some GHC options were not recognized     OrmoluUnrecognizedOpts (NonEmpty String)+  | -- | Cabal file parsing failed+    OrmoluCabalFileParsingFailed FilePath+  | -- | Missing input file path when using stdin input and+    -- accounting for .cabal files+    OrmoluMissingStdinInputFile   deriving (Eq, Show) -instance Exception OrmoluException where-  displayException = \case-    OrmoluParsingFailed s e ->-      showParsingErr "The GHC parser (in Haddock mode) failed:" s [e]-    OrmoluOutputParsingFailed s e ->-      showParsingErr "Parsing of formatted code failed:" s [e]-        ++ "Please, consider reporting the bug.\n"-    OrmoluASTDiffers path ss ->-      unlines $-        [ "AST of input and AST of formatted code differ."-        ]-          ++ fmap-            withIndent-            ( case fmap (\s -> "at " ++ showOutputable s) ss of-                [] -> ["in " ++ path]-                xs -> xs-            )-          ++ ["Please, consider reporting the bug."]-    OrmoluNonIdempotentOutput loc left right ->-      showParsingErr-        "Formatting is not idempotent:"-        loc-        ["before: " ++ show left, "after:  " ++ show right]-        ++ "Please, consider reporting the bug.\n"-    OrmoluUnrecognizedOpts opts ->-      unlines-        [ "The following GHC options were not recognized:",-          (withIndent . unwords . NE.toList) opts-        ]+instance Exception OrmoluException +-- | Print an 'OrmoluException'.+printOrmoluException ::+  OrmoluException ->+  Term ()+printOrmoluException = \case+  OrmoluParsingFailed s e -> do+    bold (putSrcSpan s)+    newline+    put "  The GHC parser (in Haddock mode) failed:"+    newline+    put "  "+    put (T.pack e)+    newline+  OrmoluOutputParsingFailed s e -> do+    bold (putSrcSpan s)+    newline+    put "  Parsing of formatted code failed:"+    put "  "+    put (T.pack e)+    newline+  OrmoluASTDiffers path ss -> do+    putS path+    newline+    put "  AST of input and AST of formatted code differ."+    newline+    forM_ ss $ \s -> do+      put "    at "+      putSrcSpan s+      newline+    put "  Please, consider reporting the bug."+    newline+  OrmoluNonIdempotentOutput diff -> do+    printTextDiff diff+    newline+    put "  Formatting is not idempotent."+    newline+    put "  Please, consider reporting the bug."+    newline+  OrmoluUnrecognizedOpts opts -> do+    put "The following GHC options were not recognized:"+    newline+    put "  "+    (putS . unwords . NE.toList) opts+    newline+  OrmoluCabalFileParsingFailed cabalFile -> do+    put "Parsing this .cabal file failed:"+    newline+    put $ "  " <> T.pack cabalFile+    newline+  OrmoluMissingStdinInputFile -> do+    put "The --stdin-input-file option is necessary when using input"+    newline+    put "from stdin and accounting for .cabal files"+    newline+ -- | Inside this wrapper 'OrmoluException' will be caught and displayed--- nicely using 'displayException'.+-- nicely. withPrettyOrmoluExceptions ::-  -- | Action that may throw the exception-  IO a ->-  IO a-withPrettyOrmoluExceptions m = m `catch` h+  -- | Color mode+  ColorMode ->+  -- | Action that may throw an exception+  IO ExitCode ->+  IO ExitCode+withPrettyOrmoluExceptions colorMode m = m `catch` h   where-    h :: OrmoluException -> IO a     h e = do-      hPutStrLn stderr (displayException e)-      exitWith . ExitFailure $+      runTerm (printOrmoluException e) colorMode stderr+      return . ExitFailure $         case e of           -- Error code 1 is for 'error' or 'notImplemented'           -- 2 used to be for erroring out on CPP@@ -81,19 +117,5 @@           OrmoluASTDiffers {} -> 5           OrmoluNonIdempotentOutput {} -> 6           OrmoluUnrecognizedOpts {} -> 7--------------------------------------------------------------------------------- Helpers---- | Show a parse error.-showParsingErr :: GHC.Outputable a => String -> a -> [String] -> String-showParsingErr msg spn err =-  unlines $-    [ msg,-      withIndent (showOutputable spn)-    ]-      ++ map withIndent err---- | Indent with 2 spaces for readability.-withIndent :: String -> String-withIndent txt = "  " ++ txt+          OrmoluCabalFileParsingFailed {} -> 8+          OrmoluMissingStdinInputFile {} -> 9
src/Ormolu/Imports.hs view
@@ -15,10 +15,14 @@ import Data.List (foldl', nubBy, sortBy, sortOn) import Data.Map.Strict (Map) import qualified Data.Map.Strict as M-import FastString (FastString)-import GHC hiding (GhcPs, IE)+import GHC.Data.FastString (FastString) import GHC.Hs.Extension-import GHC.Hs.ImpExp (IE (..))+import GHC.Hs.ImpExp as GHC+import GHC.Types.Basic+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc+import GHC.Unit.Module.Name+import GHC.Unit.Types import Ormolu.Utils (groupBy', notImplemented, separatedByBlank, showOutputable)  -- | Sort, group and normalize imports. Assumes input list is sorted by source location.@@ -41,7 +45,6 @@           { ideclHiding = second (fmap normalizeLies) <$> ideclHiding,             ..           }-    g _ = notImplemented "XImportDecl"  -- | Combine two import declarations. It should be assumed that 'ImportId's -- are equal.@@ -59,7 +62,6 @@           _ -> Nothing,         ..       }-combineImports _ _ = notImplemented "XImportDecl"  -- | Import id, a collection of all things that justify having a separate -- import entry. This is used for merging of imports. If two imports have@@ -68,7 +70,7 @@   { importIsPrelude :: Bool,     importIdName :: ModuleName,     importPkgQual :: Maybe FastString,-    importSource :: Bool,+    importSource :: IsBootInterface,     importSafe :: Bool,     importQualified :: Bool,     importImplicit :: Bool,@@ -97,7 +99,6 @@   where     isPrelude = moduleNameString moduleName == "Prelude"     moduleName = unLoc ideclName-importId _ = notImplemented "XImportDecl"  -- | Normalize a collection of import\/export items. normalizeLies :: [LIE GhcPs] -> [LIE GhcPs]@@ -146,12 +147,10 @@                         IEGroup NoExtField _ _ -> notImplemented "IEGroup"                         IEDoc NoExtField _ -> notImplemented "IEDoc"                         IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"-                        XIE x -> noExtCon x                     IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"                     IEGroup NoExtField _ _ -> notImplemented "IEGroup"                     IEDoc NoExtField _ -> notImplemented "IEDoc"                     IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"-                    XIE x -> noExtCon x                in Just (f <$> old)        in M.alter alter wname m @@ -174,7 +173,6 @@   IEGroup NoExtField _ _ -> notImplemented "IEGroup"   IEDoc NoExtField _ -> notImplemented "IEDoc"   IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"-  XIE x -> noExtCon x  -- | Like 'compareIewn' for located wrapped names. compareLIewn :: LIEWrappedName RdrName -> LIEWrappedName RdrName -> Ordering
src/Ormolu/Parser.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -9,33 +10,36 @@   ) where -import Bag (bagToList)-import qualified CmdLineParser as GHC import Control.Exception-import Control.Monad.IO.Class+import Control.Monad.Except+import Data.Functor import qualified Data.List as L import qualified Data.List.NonEmpty as NE import Data.Ord (Down (Down))-import qualified Data.Text as T-import DynFlags as GHC-import ErrUtils (Severity (..), errMsgSeverity, errMsgSpan)-import qualified FastString as GHC-import GHC hiding (IE, UnicodeSyntax)+import GHC.Data.Bag (bagToList)+import qualified GHC.Data.EnumSet as EnumSet+import qualified GHC.Data.FastString as GHC+import qualified GHC.Data.StringBuffer as GHC+import qualified GHC.Driver.CmdLine as GHC+import GHC.Driver.Session as GHC+import qualified GHC.Driver.Types as GHC import GHC.DynFlags (baseDynFlags) import GHC.LanguageExtensions.Type (Extension (..))-import qualified HeaderInfo as GHC-import qualified HscTypes as GHC-import qualified Lexer as GHC+import qualified GHC.Parser as GHC+import qualified GHC.Parser.Header as GHC+import qualified GHC.Parser.Lexer as GHC+import GHC.Types.SrcLoc+import GHC.Unit.Module.Name+import GHC.Utils.Error (Severity (..), errMsgSeverity, errMsgSpan)+import qualified GHC.Utils.Panic as GHC import Ormolu.Config import Ormolu.Exception import Ormolu.Parser.Anns import Ormolu.Parser.CommentStream import Ormolu.Parser.Result-import Ormolu.Processing.Preprocess (preprocess)-import Ormolu.Utils (incSpanLine, removeIndentation)-import qualified Panic as GHC-import qualified Parser as GHC-import qualified StringBuffer as GHC+import Ormolu.Processing.Common+import Ormolu.Processing.Preprocess+import Ormolu.Utils (incSpanLine)  -- | Parse a complete module from string. parseModule ::@@ -48,12 +52,9 @@   String ->   m     ( [GHC.Warn],-      Either (SrcSpan, String) ParseResult+      Either (SrcSpan, String) [SourceSnippet]     )-parseModule Config {..} path rawInput = liftIO $ do-  let (literalPrefix, indentedInput, literalSuffix, extraComments) =-        preprocess path rawInput cfgRegion-      (input, indent) = removeIndentation indentedInput+parseModule config@Config {..} path rawInput = liftIO $ do   -- It's important that 'setDefaultExts' is done before   -- 'parsePragmasIntoDynFlags', because otherwise we might enable an   -- extension that was explicitly disabled in the file.@@ -71,6 +72,23 @@                 (mkSrcLoc (GHC.mkFastString path) 1 1)                 (mkSrcLoc (GHC.mkFastString path) 1 1)          in throwIO (OrmoluParsingFailed loc err)+  let cppEnabled = EnumSet.member Cpp (GHC.extensionFlags dynFlags)+  snippets <- runExceptT . forM (preprocess cppEnabled cfgRegion rawInput) $ \case+    Right region ->+      fmap ParsedSnippet . ExceptT $+        parseModuleSnippet (config $> region) dynFlags path rawInput+    Left raw -> pure $ RawSnippet raw+  pure (warnings, snippets)++parseModuleSnippet ::+  MonadIO m =>+  Config RegionDeltas ->+  DynFlags ->+  FilePath ->+  String ->+  m (Either (SrcSpan, String) ParseResult)+parseModuleSnippet Config {..} dynFlags path rawInput = liftIO $ do+  let (input, indent) = removeIndentation . linesInRegion cfgRegion $ rawInput   let useRecordDot =         "record-dot-preprocessor" == pgm_F dynFlags           || any@@ -97,24 +115,20 @@             -- later stages; but we fail in those cases.             Just err -> Left err             Nothing ->-              let (stackHeader, shebangs, pragmas, comments) =-                    mkCommentStream input extraComments pstate+              let (stackHeader, pragmas, comments) =+                    mkCommentStream input pstate                in Right                     ParseResult                       { prParsedSource = hsModule,                         prAnns = mkAnns pstate,                         prStackHeader = stackHeader,-                        prShebangs = shebangs,                         prPragmas = pragmas,                         prCommentStream = comments,                         prUseRecordDot = useRecordDot,-                        prImportQualifiedPost =-                          GHC.xopt ImportQualifiedPost dynFlags,-                        prLiteralPrefix = T.pack literalPrefix,-                        prLiteralSuffix = T.pack literalSuffix,+                        prExtensions = GHC.extensionFlags dynFlags,                         prIndent = indent                       }-  return (warnings, r)+  return r  -- | Enable all language extensions that we think should be enabled by -- default for ease of use.@@ -137,17 +151,20 @@     TransformListComp, -- steals the group keyword     UnboxedTuples, -- breaks (#) lens operator     MagicHash, -- screws {-# these things #-}-    TypeApplications, -- steals (@) operator on some cases     AlternativeLayoutRule,     AlternativeLayoutRuleTransitional,     MonadComprehensions,     UnboxedSums,     UnicodeSyntax, -- gives special meanings to operators like (→)+    TemplateHaskell, -- changes how $foo is parsed     TemplateHaskellQuotes, -- enables TH subset of quasi-quotes, this     -- apparently interferes with QuasiQuotes in     -- weird ways-    ImportQualifiedPost -- affects how Ormolu renders imports, so the+    ImportQualifiedPost, -- affects how Ormolu renders imports, so the     -- decision of enabling this style is left to the user+    NegativeLiterals, -- with this, `- 1` and `-1` have differing AST+    LexicalNegation, -- implies NegativeLiterals+    LinearTypes -- steals the (%) type operator in some cases   ]  -- | Run a 'GHC.P' computation.@@ -164,7 +181,7 @@   GHC.ParseResult a runParser parser flags filename input = GHC.unP parser parseState   where-    location = GHC.mkRealSrcLoc (GHC.mkFastString filename) 1 1+    location = mkRealSrcLoc (GHC.mkFastString filename) 1 1     buffer = GHC.stringToStringBuffer input     parseState = GHC.mkPState flags buffer location @@ -202,9 +219,9 @@   IO (Either String ([GHC.Warn], DynFlags)) parsePragmasIntoDynFlags flags extraOpts filepath str =   catchErrors $ do-    let opts = GHC.getOptions flags (GHC.stringToStringBuffer str) filepath+    let fileOpts = GHC.getOptions flags (GHC.stringToStringBuffer str) filepath     (flags', leftovers, warnings) <--      parseDynamicFilePragma flags (opts <> extraOpts)+      parseDynamicFilePragma flags (extraOpts <> fileOpts)     case NE.nonEmpty leftovers of       Nothing -> return ()       Just unrecognizedOpts ->
src/Ormolu/Parser/Anns.hs view
@@ -9,38 +9,34 @@  import Data.Map.Strict (Map) import qualified Data.Map.Strict as M-import Data.Maybe (mapMaybe)-import qualified GHC-import qualified Lexer as GHC-import SrcLoc+import GHC.Parser.Annotation+import GHC.Parser.Lexer+import GHC.Types.SrcLoc  -- | Ormolu-specific representation of GHC annotations.-newtype Anns = Anns (Map RealSrcSpan [GHC.AnnKeywordId])+newtype Anns = Anns (Map RealSrcSpan [AnnKeywordId])   deriving (Eq)  -- | Empty 'Anns'. emptyAnns :: Anns emptyAnns = Anns M.empty --- | Create 'Anns' from 'GHC.PState'.+-- | Create 'Anns' from 'PState'. mkAnns ::-  GHC.PState ->+  PState ->   Anns mkAnns pstate =   Anns $-    M.fromListWith (++) (mapMaybe f (GHC.annotations pstate))+    M.fromListWith (++) (f <$> annotations pstate)   where-    f ((spn, kid), _) =-      case spn of-        RealSrcSpan rspn -> Just (rspn, [kid])-        UnhelpfulSpan _ -> Nothing+    f ((rspn, kid), _) = (rspn, [kid]) --- | Lookup 'GHC.AnnKeywordId's corresponding to a given 'SrcSpan'.+-- | Lookup 'AnnKeywordId's corresponding to a given 'SrcSpan'. lookupAnns ::   -- | Span to lookup with   SrcSpan ->   -- | Collection of annotations   Anns ->-  [GHC.AnnKeywordId]-lookupAnns (RealSrcSpan rspn) (Anns m) = M.findWithDefault [] rspn m+  [AnnKeywordId]+lookupAnns (RealSrcSpan rspn _) (Anns m) = M.findWithDefault [] rspn m lookupAnns (UnhelpfulSpan _) _ = []
src/Ormolu/Parser/CommentStream.hs view
@@ -23,13 +23,11 @@ import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE import Data.Maybe (mapMaybe)-import qualified GHC-import qualified Lexer as GHC+import qualified GHC.Parser.Annotation as GHC+import qualified GHC.Parser.Lexer as GHC+import GHC.Types.SrcLoc import Ormolu.Parser.Pragma-import Ormolu.Parser.Shebang-import Ormolu.Processing.Common import Ormolu.Utils (onTheSameLine, showOutputable)-import SrcLoc  ---------------------------------------------------------------------------- -- Comment stream@@ -39,25 +37,20 @@ newtype CommentStream = CommentStream [RealLocated Comment]   deriving (Eq, Data, Semigroup, Monoid) --- | Create 'CommentStream' from 'GHC.PState'. The pragmas and shebangs are--- removed from the 'CommentStream'. Shebangs are only extracted from the--- comments that come from the first argument.+-- | Create 'CommentStream' from 'GHC.PState'. The pragmas are+-- removed from the 'CommentStream'. mkCommentStream ::   -- | Original input   String ->-  -- | Extra comments to include-  [Located String] ->   -- | Parser state to use for comment extraction   GHC.PState ->-  -- | Stack header, shebangs, pragmas, and comment stream+  -- | Stack header, pragmas, and comment stream   ( Maybe (RealLocated Comment),-    [Shebang],     [([RealLocated Comment], Pragma)],     CommentStream   )-mkCommentStream input extraComments pstate =+mkCommentStream input pstate =   ( mstackHeader,-    shebangs,     pragmas,     CommentStream comments   )@@ -65,13 +58,11 @@     (comments, pragmas) = extractPragmas input rawComments1     (rawComments1, mstackHeader) = extractStackHeader rawComments0     rawComments0 =-      L.sortOn (realSrcSpanStart . getRealSrcSpan) . mapMaybe toRealSpan $-        otherExtraComments-          ++ mapMaybe (liftMaybe . fmap unAnnotationComment) (GHC.comment_q pstate)+      L.sortOn (realSrcSpanStart . getRealSrcSpan) $+        mapMaybe (liftMaybe . fmap unAnnotationComment) (GHC.comment_q pstate)           ++ concatMap             (mapMaybe (liftMaybe . fmap unAnnotationComment) . snd)             (GHC.annotations_comments pstate)-    (shebangs, otherExtraComments) = extractShebangs extraComments  -- | Pretty-print a 'CommentStream'. showCommentStream :: CommentStream -> String@@ -79,7 +70,7 @@   unlines $     showComment <$> xs   where-    showComment (GHC.L l str) = showOutputable l ++ " " ++ show str+    showComment (L l str) = showOutputable l ++ " " ++ show str  ---------------------------------------------------------------------------- -- Comment@@ -110,15 +101,11 @@             Nothing -> s :| []             Just (x :| xs) ->               let getIndent y =-                    if all isSpace y || y == endDisabling+                    if all isSpace y                       then startIndent                       else length (takeWhile isSpace y)                   n = minimum (startIndent : fmap getIndent xs)-                  removeIndent y =-                    if y == endDisabling-                      then y-                      else drop n y-               in x :| (removeIndent <$> xs)+               in x :| (drop n <$> xs)           else s :| []     (atomsBefore, ls') =       case dropWhile ((< commentLine) . fst) ls of@@ -189,8 +176,8 @@                   (y : ys) ->                     let (ls', y') = mkComment ls y                      in if onTheSameLine-                          (RealSrcSpan (getRealSrcSpan x))-                          (RealSrcSpan (getRealSrcSpan y))+                          (RealSrcSpan (getRealSrcSpan x) Nothing)+                          (RealSrcSpan (getRealSrcSpan y) Nothing)                           then go' ls' [y'] ys                           else go' ls [] xs @@ -205,14 +192,10 @@   GHC.AnnLineComment s -> Just s   GHC.AnnBlockComment s -> Just s -liftMaybe :: Located (Maybe a) -> Maybe (Located a)+liftMaybe :: GenLocated l (Maybe a) -> Maybe (GenLocated l a) liftMaybe = \case   L _ Nothing -> Nothing   L l (Just a) -> Just (L l a)--toRealSpan :: Located a -> Maybe (RealLocated a)-toRealSpan (L (RealSrcSpan l) a) = Just (L l a)-toRealSpan _ = Nothing  -- | Remove consecutive blank lines. removeConseqBlanks :: NonEmpty String -> NonEmpty String
src/Ormolu/Parser/Pragma.hs view
@@ -11,12 +11,12 @@ import Control.Monad import Data.Char (isSpace, toLower) import qualified Data.List as L-import qualified EnumSet as ES-import FastString (mkFastString, unpackFS)-import qualified Lexer as L-import Module (ComponentId (..), newSimpleUnitId)-import SrcLoc-import StringBuffer+import qualified GHC.Data.EnumSet as ES+import GHC.Data.FastString (mkFastString, unpackFS)+import GHC.Data.StringBuffer+import qualified GHC.Parser.Lexer as L+import GHC.Types.SrcLoc+import GHC.Unit.Module (stringToUnitId)  -- | Ormolu's representation of pragmas. data Pragma@@ -72,7 +72,7 @@       L.mkParserFlags'         ES.empty         ES.empty-        (newSimpleUnitId (ComponentId (mkFastString "")))+        (stringToUnitId "")         True         True         True
src/Ormolu/Parser/Result.hs view
@@ -2,50 +2,39 @@  -- | A type for result of parsing. module Ormolu.Parser.Result-  ( ParseResult (..),-    prettyPrintParseResult,+  ( SourceSnippet (..),+    ParseResult (..),   ) where  import Data.Text (Text)-import GHC+import GHC.Data.EnumSet (EnumSet)+import GHC.Hs+import GHC.LanguageExtensions.Type+import GHC.Types.SrcLoc import Ormolu.Parser.Anns import Ormolu.Parser.CommentStream import Ormolu.Parser.Pragma (Pragma)-import Ormolu.Parser.Shebang (Shebang) +-- | Either a 'ParseResult', or a raw snippet.+data SourceSnippet = RawSnippet Text | ParsedSnippet ParseResult+ -- | A collection of data that represents a parsed module in Ormolu. data ParseResult = ParseResult   { -- | 'ParsedSource' from GHC-    prParsedSource :: HsModule GhcPs,+    prParsedSource :: HsModule,     -- | Ormolu-specfic representation of annotations     prAnns :: Anns,     -- | Stack header     prStackHeader :: Maybe (RealLocated Comment),-    -- | Shebangs found in the input-    prShebangs :: [Shebang],     -- | Pragmas and the associated comments     prPragmas :: [([RealLocated Comment], Pragma)],     -- | Comment stream     prCommentStream :: CommentStream,     -- | Whether or not record dot syntax is enabled     prUseRecordDot :: Bool,-    -- | Whether or not ImportQualifiedPost is enabled-    prImportQualifiedPost :: Bool,-    -- | Literal prefix-    prLiteralPrefix :: Text,-    -- | Literal suffix-    prLiteralSuffix :: Text,+    -- | Enabled extensions+    prExtensions :: EnumSet Extension,     -- | Indentation level, can be non-zero in case of region formatting     prIndent :: Int   }---- | Pretty-print a 'ParseResult'.-prettyPrintParseResult :: ParseResult -> String-prettyPrintParseResult ParseResult {..} =-  unlines-    [ "parse result:",-      "  comment stream:",-      showCommentStream prCommentStream-      -- XXX extend as needed-    ]
− src/Ormolu/Parser/Shebang.hs
@@ -1,27 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}---- | A module for dealing with shebangs.-module Ormolu.Parser.Shebang-  ( Shebang (..),-    extractShebangs,-    isShebang,-  )-where--import Data.Data (Data)-import qualified Data.List as L-import SrcLoc---- | A wrapper for a shebang.-newtype Shebang = Shebang (Located String)-  deriving (Eq, Data)---- | Extract shebangs from the beginning of a comment stream.-extractShebangs :: [Located String] -> ([Shebang], [Located String])-extractShebangs comments = (Shebang <$> shebangs, rest)-  where-    (shebangs, rest) = span (isShebang . unLoc) comments---- | Return 'True' if given 'String' is a shebang.-isShebang :: String -> Bool-isShebang str = "#!" `L.isPrefixOf` str
src/Ormolu/Printer.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}  -- | Pretty-printer for Haskell AST.@@ -8,35 +10,36 @@ where  import Data.Text (Text)+import qualified Data.Text as T import Ormolu.Config import Ormolu.Parser.Result import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Module import Ormolu.Printer.SpanStream-import Ormolu.Processing.Postprocess (postprocess)+import Ormolu.Processing.Common  -- | Render a module. printModule ::   -- | Result of parsing-  ParseResult ->+  [SourceSnippet] ->   PrinterOptsTotal ->   -- | Resulting rendition   Text-printModule ParseResult {..} printerOpts =-  prLiteralPrefix <> region <> prLiteralSuffix+printModule snippets printerOpts = T.concat . fmap printSnippet $ snippets   where-    region =-      postprocess prIndent $-        runR-          ( p_hsModule-              prStackHeader-              prShebangs-              prPragmas-              prImportQualifiedPost-              prParsedSource-          )-          (mkSpanStream prParsedSource)-          prCommentStream-          prAnns-          printerOpts-          prUseRecordDot+    printSnippet = \case+      ParsedSnippet ParseResult {..} ->+        reindent prIndent $+          runR+            ( p_hsModule+                prStackHeader+                prPragmas+                prParsedSource+            )+            (mkSpanStream prParsedSource)+            prCommentStream+            prAnns+            printerOpts+            prUseRecordDot+            prExtensions+      RawSnippet r -> r
src/Ormolu/Printer/Combinators.hs view
@@ -12,6 +12,7 @@     runR,     getAnns,     getEnclosingSpan,+    isExtensionEnabled,      -- * Combinators @@ -23,9 +24,11 @@     declNewline,     inci,     inciIf,-    inciBy,+    inciByFrac,+    inciHalf,     located,     located',+    realLocated,     switchLayout,     Layout (..),     vlayout,@@ -47,6 +50,7 @@     backticks,     banana,     braces,+    recordDotBraces,     brackets,     parens,     parensHash,@@ -70,10 +74,10 @@ import Control.Monad import Data.List (intersperse) import Data.Text (Text)+import GHC.Types.SrcLoc import Ormolu.Config import Ormolu.Printer.Comments import Ormolu.Printer.Internal-import SrcLoc  ---------------------------------------------------------------------------- -- Basic@@ -99,10 +103,19 @@   (a -> R ()) ->   R () located (L (UnhelpfulSpan _) a) f = f a-located (L (RealSrcSpan l) a) f = do+located (L (RealSrcSpan l _) a) f = realLocated (L l a) f++-- | See 'located'+realLocated ::+  -- | Thing to enter+  RealLocated a ->+  -- | How to render inner value+  (a -> R ()) ->+  R ()+realLocated (L l a) f = do   spitPrecedingComments l   withEnclosingSpan l $-    switchLayout [RealSrcSpan l] (f a)+    switchLayout [RealSrcSpan l Nothing] (f a)   spitFollowingComments l  -- | A version of 'located' with arguments flipped.@@ -217,12 +230,29 @@   txt "`"  -- | Surround given entity by banana brackets (i.e., from arrow notation.)-banana :: R () -> R ()-banana = brackets_ True "(|" "|)" N+banana :: BracketStyle -> R () -> R ()+banana = brackets_ True "(|" "|)"  -- | Surround given entity by curly braces @{@ and  @}@. braces :: BracketStyle -> R () -> R () braces = brackets_ False "{" "}"++-- | Surround record update fields which use RecordDot plugin entity by+-- curly braces @{@ and @}@.+--+-- @since 0.1.3.1+recordDotBraces :: R () -> R ()+recordDotBraces m = sitcc (vlayout singleLine multiLine)+  where+    singleLine = do+      txt "{"+      m+      txt "}"+    multiLine = do+      txt "{"+      sitcc m+      newline+      txt "}"  -- | Surround given entity by square brackets @[@ and @]@. brackets :: BracketStyle -> R () -> R ()
src/Ormolu/Printer/Comments.hs view
@@ -16,9 +16,9 @@ import qualified Data.List.NonEmpty as NE import Data.Maybe (listToMaybe) import qualified Data.Text as T+import GHC.Types.SrcLoc import Ormolu.Parser.CommentStream import Ormolu.Printer.Internal-import SrcLoc  ---------------------------------------------------------------------------- -- Top-level
src/Ormolu/Printer/Internal.hs view
@@ -22,6 +22,8 @@     useRecordDot,     inci,     inciBy,+    inciByFrac,+    inciHalf,     sitcc,     Layout (..),     enterLayout,@@ -53,6 +55,9 @@      -- * Annotations     getAnns,++    -- * Extensions+    isExtensionEnabled,   ) where @@ -66,13 +71,17 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Data.Text.Lazy.Builder-import GHC+import GHC.Data.EnumSet (EnumSet)+import qualified GHC.Data.EnumSet as EnumSet+import GHC.LanguageExtensions.Type+import GHC.Parser.Annotation+import GHC.Types.SrcLoc+import GHC.Utils.Outputable (Outputable) import Ormolu.Config import Ormolu.Parser.Anns import Ormolu.Parser.CommentStream import Ormolu.Printer.SpanStream import Ormolu.Utils (showOutputable)-import Outputable (Outputable)  ---------------------------------------------------------------------------- -- The 'R' monad@@ -98,7 +107,9 @@     rcCanUseBraces :: Bool,     -- | Whether the source could have used the record dot preprocessor     rcUseRecDot :: Bool,-    rcPrinterOpts :: PrinterOptsTotal+    rcPrinterOpts :: PrinterOptsTotal,+    -- | Enabled extensions+    rcExtensions :: EnumSet Extension   }  -- | State context of 'R'.@@ -154,7 +165,7 @@     OnNextLine   deriving (Eq, Show) --- | Run an 'R' monad.+-- | Run 'R' monad. runR ::   -- | Monad to run   R () ->@@ -167,9 +178,11 @@   PrinterOptsTotal ->   -- | Use Record Dot Syntax   Bool ->+  -- | Enabled extensions+  EnumSet Extension ->   -- | Resulting rendition   Text-runR (R m) sstream cstream anns printerOpts recDot =+runR (R m) sstream cstream anns printerOpts recDot extensions =   TL.toStrict . toLazyText . scBuilder $ execState (runReaderT m rc) sc   where     rc =@@ -180,7 +193,8 @@           rcAnns = anns,           rcCanUseBraces = False,           rcUseRecDot = recDot,-          rcPrinterOpts = printerOpts+          rcPrinterOpts = printerOpts,+          rcExtensions = extensions         }     sc =       SC@@ -385,25 +399,35 @@ useRecordDot :: R Bool useRecordDot = R (asks rcUseRecDot) +-- | Like 'inci', but indents by exactly the given number of steps.+inciBy :: Int -> R () -> R ()+inciBy step (R m) = R (local modRC m)+  where+    modRC rc =+      rc+        { rcIndent = roundDownToNearest step (rcIndent rc) + step+        }+    roundDownToNearest r n = (n `div` r) * r++-- | Like 'inci', but indents by the given fraction of a full step.+inciByFrac :: Int -> R () -> R ()+inciByFrac x m = do+  indentStep <- R $ asks (runIdentity . poIndentation . rcPrinterOpts)+  let step = indentStep `quot` x+  inciBy step m+ -- | Increase indentation level by one indentation step for the inner -- computation. 'inci' should be used when a part of code must be more -- indented relative to the parts outside of 'inci' in order for the output -- to be valid Haskell. When layout is single-line there is no obvious -- effect, but with multi-line layout correct indentation levels matter. inci :: R () -> R ()-inci = inciBy 1+inci = inciByFrac 1 --- | Like 'inci', but indents by the given fraction of a full step.-inciBy :: Int -> R () -> R ()-inciBy x (R m) = do-  step <- (`quot` x) <$> R (asks (runIdentity . poIndentation . rcPrinterOpts))-  let modRC rc =-        rc-          { rcIndent = roundDownToNearest step (rcIndent rc) + step-          }-  R (local modRC m)-  where-    roundDownToNearest r n = (n `div` r) * r+-- | In rare cases, we have to indent by a positive amount smaller+-- than 'indentStep'.+inciHalf :: R () -> R ()+inciHalf = inciByFrac 2  -- | Set indentation level for the inner computation equal to current -- column. This makes sure that the entire inner block is uniformly@@ -595,3 +619,9 @@ -- | Return 'True' if we can use braces in this context. canUseBraces :: R Bool canUseBraces = R (asks rcCanUseBraces)++----------------------------------------------------------------------------+-- Extensions++isExtensionEnabled :: Extension -> R Bool+isExtensionEnabled ext = R . asks $ EnumSet.member ext . rcExtensions
src/Ormolu/Printer/Meat/Common.hs view
@@ -11,16 +11,22 @@     p_qualName,     p_infixDefHelper,     p_hsDocString,+    p_sourceText,   ) where  import Control.Monad-import Data.Functor import Data.List (intersperse, isPrefixOf) import qualified Data.Text as T-import GHC hiding (GhcPs, IE)-import Name (nameStableString)-import OccName (OccName (..))+import GHC.Hs.Doc+import GHC.Hs.ImpExp+import GHC.Parser.Annotation+import GHC.Types.Basic+import GHC.Types.Name (nameStableString)+import GHC.Types.Name.Occurrence (OccName (..))+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc+import GHC.Unit.Module.Name import Ormolu.Config import Ormolu.Printer.Combinators import Ormolu.Utils@@ -172,10 +178,10 @@           Named name -> " $" <> T.pack name         sequence_ $ intersperse (newline >> s) $ map txt' docLines   single <--    getPrinterOpt poHaddockStyle <&> \case-      HaddockSingleLine -> True+    getPrinterOpt poHaddockStyle >>= \case+      HaddockSingleLine -> pure True       -- Use multiple single-line comments when the whole comment is indented-      HaddockMultiLine -> maybe False ((> 1) . srcSpanStartCol) $ unSrcSpan l+      HaddockMultiLine -> maybe False ((> 1) . srcSpanStartCol) <$> getSrcSpan l   if single     then do       txt "--"@@ -192,10 +198,16 @@           txt "-}"    when needsNewline newline-  case l of-    UnhelpfulSpan _ ->+  getSrcSpan l >>= mapM_ (setSpanMark . HaddockSpan hstyle)+  where+    getSrcSpan = \case       -- It's often the case that the comment itself doesn't have a span       -- attached to it and instead its location can be obtained from       -- nearest enclosing span.-      getEnclosingSpan (const True) >>= mapM_ (setSpanMark . HaddockSpan hstyle)-    RealSrcSpan spn -> setSpanMark (HaddockSpan hstyle spn)+      UnhelpfulSpan _ -> getEnclosingSpan (const True)+      RealSrcSpan spn _ -> pure $ Just spn++p_sourceText :: SourceText -> R ()+p_sourceText = \case+  NoSourceText -> pure ()+  SourceText s -> space >> txt (T.pack s)
src/Ormolu/Printer/Meat/Declaration.hs view
@@ -14,8 +14,13 @@ import Data.List (sort) import Data.List.NonEmpty (NonEmpty (..), (<|)) import qualified Data.List.NonEmpty as NE-import GHC hiding (InlinePragma)-import OccName (occNameFS)+import GHC.Hs.Binds+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Pat+import GHC.Types.Name.Occurrence (occNameFS)+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Declaration.Annotation@@ -107,7 +112,7 @@   ValD NoExtField x -> p_valDecl x   SigD NoExtField x -> p_sigDecl x   InstD NoExtField x -> p_instDecl style x-  DerivD NoExtField x -> p_derivDecl x+  DerivD NoExtField x -> p_standaloneDerivDecl x   DefD NoExtField x -> p_defaultDecl x   ForD NoExtField x -> p_foreignDecl x   WarningD NoExtField x -> p_warnDecls x@@ -122,7 +127,6 @@       DocGroup n str -> p_hsDocString (Asterisk n) False (noLoc str)   RoleAnnotD NoExtField x -> p_roleAnnot x   KindSigD NoExtField s -> p_standaloneKindSig s-  XHsDecl x -> noExtCon x  p_tyClDecl :: FamilyStyle -> TyClDecl GhcPs -> R () p_tyClDecl style = \case@@ -132,7 +136,7 @@     p_dataDecl       Associated       tcdLName-      (tyVarsToTypes tcdTyVars)+      (tyVarsToTyPats tcdTyVars)       tcdFixity       tcdDataDefn   ClassDecl {..} ->@@ -147,20 +151,13 @@       tcdATs       tcdATDefs       tcdDocs-  XTyClDecl x -> noExtCon x  p_instDecl :: FamilyStyle -> InstDecl GhcPs -> R () p_instDecl style = \case   ClsInstD NoExtField x -> p_clsInstDecl x   TyFamInstD NoExtField x -> p_tyFamInstDecl style x   DataFamInstD NoExtField x -> p_dataFamInstDecl style x-  XInstDecl x -> noExtCon x -p_derivDecl :: DerivDecl GhcPs -> R ()-p_derivDecl = \case-  d@DerivDecl {} -> p_standaloneDerivDecl d-  XDerivDecl x -> noExtCon x- -- | Determine if these declarations should be grouped together. groupedDecls ::   LHsDecl GhcPs ->@@ -188,6 +185,7 @@     (KindSignature n, DataDeclaration n') -> n == n'     (KindSignature n, ClassDeclaration n') -> n == n'     (KindSignature n, FamilyDeclaration n') -> n == n'+    (KindSignature n, TypeSynonym n') -> n == n'     -- Special case for TH splices, we look at locations     (Splice, Splice) -> not (separatedByBlank id l_x l_y)     -- This looks only at Haddocks, normal comments are handled elsewhere@@ -247,7 +245,8 @@   DataDeclaration,   ClassDeclaration,   KindSignature,-  FamilyDeclaration ::+  FamilyDeclaration,+  TypeSynonym ::     RdrName -> HsDecl GhcPs pattern InlinePragma n <- SigD NoExtField (InlineSig NoExtField (L _ n) _) pattern SpecializePragma n <- SigD NoExtField (SpecSig NoExtField (L _ n) _ _)@@ -256,9 +255,10 @@ pattern AnnValuePragma n <- AnnD NoExtField (HsAnnotation NoExtField _ (ValueAnnProvenance (L _ n)) _) pattern Pattern n <- ValD NoExtField (PatSynBind NoExtField (PSB _ (L _ n) _ _ _)) pattern DataDeclaration n <- TyClD NoExtField (DataDecl NoExtField (L _ n) _ _ _)-pattern ClassDeclaration n <- TyClD NoExtField (ClassDecl NoExtField _ (L _ n) _ _ _ _ _ _ _ _)+pattern ClassDeclaration n <- TyClD NoExtField (ClassDecl _ _ (L _ n) _ _ _ _ _ _ _ _) pattern KindSignature n <- KindSigD NoExtField (StandaloneKindSig NoExtField (L _ n) _) pattern FamilyDeclaration n <- TyClD NoExtField (FamDecl NoExtField (FamilyDecl NoExtField _ (L _ n) _ _ _ _))+pattern TypeSynonym n <- TyClD NoExtField (SynDecl NoExtField (L _ n) _ _ _)  -- Declarations which can refer to multiple names @@ -290,7 +290,7 @@ defSigRdrNames _ = Nothing  funRdrNames :: HsDecl GhcPs -> Maybe [RdrName]-funRdrNames (ValD NoExtField (FunBind NoExtField (L _ n) _ _ _)) = Just [n]+funRdrNames (ValD NoExtField (FunBind NoExtField (L _ n) _ _)) = Just [n] funRdrNames (ValD NoExtField (PatBind NoExtField (L _ n) _ _)) = Just $ patBindNames n funRdrNames _ = Nothing @@ -300,9 +300,7 @@  warnSigRdrNames :: HsDecl GhcPs -> Maybe [RdrName] warnSigRdrNames (WarningD NoExtField (Warnings NoExtField _ ws)) = Just $-  flip concatMap ws $ \case-    L _ (Warning NoExtField ns _) -> map unLoc ns-    L _ (XWarnDecl x) -> noExtCon x+  flip concatMap ws $ \(L _ (Warning NoExtField ns _)) -> map unLoc ns warnSigRdrNames _ = Nothing  patBindNames :: Pat GhcPs -> [RdrName]@@ -321,7 +319,4 @@ patBindNames (SigPat _ (L _ p) _) = patBindNames p patBindNames (NPat NoExtField _ _ _) = [] patBindNames (NPlusKPat NoExtField (L _ n) _ _ _ _) = [n]-patBindNames (ConPatIn _ d) = concatMap (patBindNames . unLoc) (hsConPatArgs d)-patBindNames ConPatOut {} = notImplemented "ConPatOut" -- created by renamer-patBindNames (CoPat NoExtField _ p _) = patBindNames p-patBindNames (XPat x) = noExtCon x+patBindNames (ConPat NoExtField _ d) = concatMap (patBindNames . unLoc) (hsConPatArgs d)
src/Ormolu/Printer/Meat/Declaration.hs-boot view
@@ -4,7 +4,8 @@   ) where -import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common 
src/Ormolu/Printer/Meat/Declaration/Annotation.hs view
@@ -6,18 +6,18 @@   ) where -import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Declaration.Value  p_annDecl :: AnnDecl GhcPs -> R ()-p_annDecl = \case-  HsAnnotation NoExtField _ annProv expr -> pragma "ANN" . inci $ do+p_annDecl (HsAnnotation NoExtField _ annProv expr) =+  pragma "ANN" . inci $ do     p_annProv annProv     breakpoint     located expr p_hsExpr-  XAnnDecl x -> noExtCon x  p_annProv :: AnnProvenance (IdP GhcPs) -> R () p_annProv = \case
src/Ormolu/Printer/Meat/Declaration/Class.hs view
@@ -8,12 +8,19 @@   ) where -import Class import Control.Arrow import Control.Monad import Data.Foldable-import Data.List (sortOn)-import GHC+import Data.Function (on)+import Data.List (sortBy)+import GHC.Core.Class+import GHC.Hs.Binds+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.Basic+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Config import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common@@ -50,7 +57,7 @@         )           <$> catdefs       allDecls =-        snd <$> sortOn fst (sigs <> vals <> tyFams <> tyFamDefs <> docs)+        snd <$> sortBy (leftmost_smallest `on` fst) (sigs <> vals <> tyFams <> tyFamDefs <> docs)   txt "class"   switchLayout combinedSpans $ do     breakpoint@@ -69,7 +76,6 @@   unless (null allDecls) $ do     breakpoint -- Ensure whitespace is added after where clause.     inci (p_hsDeclsRespectGrouping Associated allDecls)-p_classDecl _ _ (XLHsQTyVars c) _ _ _ _ _ _ _ = noExtCon c  p_classContext :: LHsContext GhcPs -> R () p_classContext ctx = unless (null (unLoc ctx)) $ do
src/Ormolu/Printer/Meat/Declaration/Data.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}@@ -11,7 +12,14 @@ import Control.Monad import Data.Maybe (isJust, maybeToList) import qualified Data.Text as Text-import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Parser.Annotation+import GHC.Types.Basic+import GHC.Types.ForeignCall+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Config import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common@@ -24,7 +32,7 @@   -- | Type constructor   Located RdrName ->   -- | Type patterns-  [LHsType GhcPs] ->+  HsTyPats GhcPs ->   -- | Lexical fixity   LexicalFixity ->   -- | Data definition@@ -37,27 +45,37 @@   txt $ case style of     Associated -> mempty     Free -> " instance"-  let constructorSpans = getLoc name : fmap getLoc tpats-  switchLayout constructorSpans $ do+  case unLoc <$> dd_cType of+    Nothing -> pure ()+    Just (CType prag header (type_, _)) -> do+      p_sourceText prag+      case header of+        Nothing -> pure ()+        Just (Header h _) -> space *> p_sourceText h+      p_sourceText type_+      txt " #-}"+  let constructorSpans = getLoc name : fmap lhsTypeArgSrcSpan tpats+      sigSpans = maybeToList . fmap getLoc $ dd_kindSig+      declHeaderSpans = constructorSpans ++ sigSpans+  switchLayout declHeaderSpans $ do     breakpoint-    inci $-      p_infixDefHelper-        (isInfix fixity)-        True-        (p_rdrName name)-        (located' p_hsType <$> tpats)-  case dd_kindSig of-    Nothing -> return ()-    Just k -> do-      space-      txt "::"-      space-      located k p_hsType+    inci $ do+      switchLayout constructorSpans $+        p_infixDefHelper+          (isInfix fixity)+          True+          (p_rdrName name)+          (p_lhsTypeArg <$> tpats)+      forM_ dd_kindSig $ \k -> do+        space+        txt "::"+        breakpoint+        inci $ located k p_hsType   let gadt = isJust dd_kindSig || any (isGadt . unLoc) dd_cons   unless (null dd_cons) $     if gadt       then inci $ do-        switchLayout constructorSpans $ do+        switchLayout declHeaderSpans $ do           breakpoint           txt "where"         breakpoint@@ -85,7 +103,6 @@   unless (null $ unLoc dd_derivs) breakpoint   inci . located dd_derivs $ \xs ->     sep newline (located' p_hsDerivingClause) xs-p_dataDecl _ _ _ _ (XHsDataDefn x) = noExtCon x  p_conDecl ::   Bool ->@@ -97,7 +114,7 @@     let conDeclSpn =           fmap getLoc con_names             <> [getLoc con_forall]-            <> conTyVarsSpans con_qvars+            <> fmap getLoc con_qvars             <> maybeToList (fmap getLoc con_mb_cxt)             <> conArgsSpans con_args     switchLayout conDeclSpn $ do@@ -116,25 +133,31 @@                 then newline                 else breakpoint         interArgBreak-        when (unLoc con_forall) $ do-          p_forallBndrs ForallInvis p_hsTyVarBndr (hsq_explicit con_qvars)-          interArgBreak-        forM_ con_mb_cxt p_lhsContext-        case con_args of-          PrefixCon xs -> do-            sep breakpoint (located' p_hsType) xs-            unless (null xs) $ do-              space-              txt "->"-              breakpoint-          RecCon l -> do-            located l p_conDeclFields-            unless (null $ unLoc l) $ do-              space-              txt "->"-              breakpoint-          InfixCon _ _ -> notImplemented "InfixCon"-        p_hsType (unLoc con_res_ty)+        conTy <- case con_args of+          PrefixCon xs ->+            let go (HsScaled a b) t = L (combineLocs t b) (HsFunTy NoExtField a b t)+             in pure $ foldr go con_res_ty xs+          RecCon r@(L l rs) ->+            pure+              . L (combineLocs r con_res_ty)+              $ HsFunTy+                NoExtField+                (HsUnrestrictedArrow NormalSyntax)+                (L l $ HsRecTy NoExtField rs)+                con_res_ty+          InfixCon _ _ -> notImplemented "InfixCon" -- NOTE(amesgen) should be unreachable+        let qualTy = case con_mb_cxt of+              Nothing -> conTy+              Just qs ->+                L (combineLocs qs conTy) $+                  HsQualTy NoExtField qs conTy+        let quantifiedTy =+              if unLoc con_forall+                then+                  L (combineLocs con_forall qualTy) $+                    HsForAllTy NoExtField (mkHsForAllInvisTele con_qvars) qualTy+                else qualTy+        p_hsType (unLoc quantifiedTy)   ConDeclH98 {..} -> do     mapM_ (p_hsDocString Pipe True) con_doc     let conDeclWithContextSpn =@@ -146,7 +169,7 @@           getLoc con_name : conArgsSpans con_args     switchLayout conDeclWithContextSpn $ do       when (unLoc con_forall) $ do-        p_forallBndrs ForallInvis p_hsTyVarBndr con_ex_tvs+        p_forallBndrs ForAllInvis p_hsTyVarBndr con_ex_tvs         breakpoint         indent <- getPrinterOpt poIndentation         vlayout (pure ()) . txt $ Text.replicate (indent - 2) " "@@ -155,33 +178,27 @@         PrefixCon xs -> do           p_rdrName con_name           unless (null xs) breakpoint-          inci . sitcc $ sep breakpoint (sitcc . located' p_hsTypePostDoc) xs+          inci . sitcc $ sep breakpoint (sitcc . located' p_hsTypePostDoc) (hsScaledThing <$> xs)         RecCon l -> do           p_rdrName con_name           breakpoint           inciIf (not singleConstRec) (located l p_conDeclFields)-        InfixCon x y -> do+        InfixCon (HsScaled _ x) (HsScaled _ y) -> do           located x p_hsType           breakpoint           inci $ do             p_rdrName con_name             space             located y p_hsType-  XConDecl x -> noExtCon x  conArgsSpans :: HsConDeclDetails GhcPs -> [SrcSpan] conArgsSpans = \case   PrefixCon xs ->-    getLoc <$> xs+    getLoc . hsScaledThing <$> xs   RecCon l ->     [getLoc l]   InfixCon x y ->-    [getLoc x, getLoc y]--conTyVarsSpans :: LHsQTyVars GhcPs -> [SrcSpan]-conTyVarsSpans = \case-  HsQTvs {..} -> getLoc <$> hsq_explicit-  XLHsQTyVars x -> noExtCon x+    getLoc . hsScaledThing <$> [x, y]  p_lhsContext ::   LHsContext GhcPs ->@@ -198,7 +215,6 @@ isGadt = \case   ConDeclGADT {} -> True   ConDeclH98 {} -> False-  XConDecl {} -> False  p_hsDerivingClause ::   HsDerivingClause GhcPs ->@@ -239,9 +255,6 @@           txt "via"           space           located hsib_body p_hsType-      ViaStrategy (XHsImplicitBndrs x) ->-        noExtCon x-p_hsDerivingClause (XHsDerivingClause x) = noExtCon x  ---------------------------------------------------------------------------- -- Helpers
src/Ormolu/Printer/Meat/Declaration/Default.hs view
@@ -6,15 +6,14 @@   ) where -import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Type  p_defaultDecl :: DefaultDecl GhcPs -> R ()-p_defaultDecl = \case-  DefaultDecl NoExtField ts -> do-    txt "default"-    breakpoint-    inci . parens N $-      sep commaDel (sitcc . located' p_hsType) ts-  XDefaultDecl x -> noExtCon x+p_defaultDecl (DefaultDecl NoExtField ts) = do+  txt "default"+  breakpoint+  inci . parens N $+    sep commaDel (sitcc . located' p_hsType) ts
src/Ormolu/Printer/Meat/Declaration/Foreign.hs view
@@ -7,11 +7,12 @@   ) where -import BasicTypes import Control.Monad-import Data.Text-import ForeignCall-import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.ForeignCall+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Declaration.Signature@@ -24,7 +25,6 @@   fd@ForeignExport {fd_fe} -> do     p_foreignExport fd_fe     p_foreignTypeSig fd-  XForeignDecl x -> noExtCon x  -- | Printer for the last part of an import\/export, which is function name -- and type signature.@@ -67,8 +67,3 @@   space   located (L loc cCallConv) atom   located sourceText p_sourceText--p_sourceText :: SourceText -> R ()-p_sourceText = \case-  NoSourceText -> pure ()-  SourceText s -> space >> txt (pack s)
src/Ormolu/Printer/Meat/Declaration/Instance.hs view
@@ -11,19 +11,22 @@   ) where -import BasicTypes import Control.Arrow import Control.Monad import Data.Foldable-import Data.List (sortOn)-import GHC+import Data.Function (on)+import Data.List (sortBy)+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.Basic+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration import Ormolu.Printer.Meat.Declaration.Data import Ormolu.Printer.Meat.Declaration.TypeFamily import Ormolu.Printer.Meat.Type-import Ormolu.Utils  p_standaloneDerivDecl :: DerivDecl GhcPs -> R () p_standaloneDerivDecl DerivDecl {..} = do@@ -54,64 +57,51 @@         inci (located hsib_body p_hsType)         breakpoint         instTypes True-      ViaStrategy (XHsImplicitBndrs x) ->-        noExtCon x-p_standaloneDerivDecl (XDerivDecl _) = notImplemented "XDerivDecl"  p_clsInstDecl :: ClsInstDecl GhcPs -> R ()-p_clsInstDecl = \case-  ClsInstDecl {..} -> do-    txt "instance"-    case cid_poly_ty of-      HsIB {..} -> do-        -- GHC's AST does not necessarily store each kind of element in source-        -- location order. This happens because different declarations are stored in-        -- different lists. Consequently, to get all the declarations in proper-        -- order, they need to be manually sorted.-        let sigs = (getLoc &&& fmap (SigD NoExtField)) <$> cid_sigs-            vals = (getLoc &&& fmap (ValD NoExtField)) <$> toList cid_binds-            tyFamInsts =-              ( getLoc &&& fmap (InstD NoExtField . TyFamInstD NoExtField)-              )-                <$> cid_tyfam_insts-            dataFamInsts =-              ( getLoc &&& fmap (InstD NoExtField . DataFamInstD NoExtField)-              )-                <$> cid_datafam_insts-            allDecls =-              snd <$> sortOn fst (sigs <> vals <> tyFamInsts <> dataFamInsts)-        located hsib_body $ \x -> do-          breakpoint-          inci $ do-            match_overlap_mode cid_overlap_mode breakpoint-            p_hsType x-            unless (null allDecls) $ do-              breakpoint-              txt "where"-        unless (null allDecls) . inci $ do-          -- Ensure whitespace is added after where clause.-          breakpoint-          dontUseBraces $ p_hsDeclsRespectGrouping Associated allDecls-      XHsImplicitBndrs x -> noExtCon x-  XClsInstDecl x -> noExtCon x+p_clsInstDecl ClsInstDecl {..} = do+  txt "instance"+  let HsIB {..} = cid_poly_ty+  -- GHC's AST does not necessarily store each kind of element in source+  -- location order. This happens because different declarations are stored in+  -- different lists. Consequently, to get all the declarations in proper+  -- order, they need to be manually sorted.+  let sigs = (getLoc &&& fmap (SigD NoExtField)) <$> cid_sigs+      vals = (getLoc &&& fmap (ValD NoExtField)) <$> toList cid_binds+      tyFamInsts =+        ( getLoc &&& fmap (InstD NoExtField . TyFamInstD NoExtField)+        )+          <$> cid_tyfam_insts+      dataFamInsts =+        ( getLoc &&& fmap (InstD NoExtField . DataFamInstD NoExtField)+        )+          <$> cid_datafam_insts+      allDecls =+        snd <$> sortBy (leftmost_smallest `on` fst) (sigs <> vals <> tyFamInsts <> dataFamInsts)+  located hsib_body $ \x -> do+    breakpoint+    inci $ do+      match_overlap_mode cid_overlap_mode breakpoint+      p_hsType x+      unless (null allDecls) $ do+        breakpoint+        txt "where"+  unless (null allDecls) . inci $ do+    -- Ensure whitespace is added after where clause.+    breakpoint+    dontUseBraces $ p_hsDeclsRespectGrouping Associated allDecls  p_tyFamInstDecl :: FamilyStyle -> TyFamInstDecl GhcPs -> R ()-p_tyFamInstDecl style = \case-  TyFamInstDecl {..} -> do-    txt $ case style of-      Associated -> "type"-      Free -> "type instance"-    breakpoint-    inci (p_tyFamInstEqn tfid_eqn)+p_tyFamInstDecl style TyFamInstDecl {..} = do+  txt $ case style of+    Associated -> "type"+    Free -> "type instance"+  breakpoint+  inci (p_tyFamInstEqn tfid_eqn)  p_dataFamInstDecl :: FamilyStyle -> DataFamInstDecl GhcPs -> R ()-p_dataFamInstDecl style = \case-  DataFamInstDecl {dfid_eqn = HsIB {hsib_body = FamEqn {..}}} ->-    p_dataDecl style feqn_tycon (map typeArgToType feqn_pats) feqn_fixity feqn_rhs-  DataFamInstDecl {dfid_eqn = HsIB {hsib_body = XFamEqn {}}} ->-    notImplemented "XFamEqn"-  DataFamInstDecl {dfid_eqn = XHsImplicitBndrs {}} ->-    notImplemented "XHsImplicitBndrs"+p_dataFamInstDecl style (DataFamInstDecl {dfid_eqn = HsIB {hsib_body = FamEqn {..}}}) =+  p_dataDecl style feqn_tycon feqn_pats feqn_fixity feqn_rhs  match_overlap_mode :: Maybe (Located OverlapMode) -> R () -> R () match_overlap_mode overlap_mode layoutStrategy =
src/Ormolu/Printer/Meat/Declaration/RoleAnnotation.hs view
@@ -8,15 +8,16 @@   ) where -import CoAxiom-import GHC+import GHC.Core.Coercion.Axiom+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common  p_roleAnnot :: RoleAnnotDecl GhcPs -> R ()-p_roleAnnot = \case-  RoleAnnotDecl NoExtField l_name anns -> p_roleAnnot' l_name anns-  XRoleAnnotDecl x -> noExtCon x+p_roleAnnot (RoleAnnotDecl NoExtField l_name anns) = p_roleAnnot' l_name anns  p_roleAnnot' :: Located RdrName -> [Located (Maybe Role)] -> R () p_roleAnnot' l_name anns = do
src/Ormolu/Printer/Meat/Declaration/Rule.hs view
@@ -1,14 +1,18 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}  module Ormolu.Printer.Meat.Declaration.Rule   ( p_ruleDecls,   ) where -import BasicTypes import Control.Monad (unless)-import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Lit+import GHC.Hs.Type+import GHC.Types.Basic import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Declaration.Signature@@ -16,38 +20,33 @@ import Ormolu.Printer.Meat.Type  p_ruleDecls :: RuleDecls GhcPs -> R ()-p_ruleDecls = \case-  HsRules NoExtField _ xs ->-    pragma "RULES" $-      sep breakpoint (sitcc . located' p_ruleDecl) xs-  XRuleDecls x -> noExtCon x+p_ruleDecls (HsRules NoExtField _ xs) =+  pragma "RULES" $ sep breakpoint (sitcc . located' p_ruleDecl) xs  p_ruleDecl :: RuleDecl GhcPs -> R ()-p_ruleDecl = \case-  HsRule NoExtField ruleName activation tyvars ruleBndrs lhs rhs -> do-    located ruleName p_ruleName-    space-    p_activation activation+p_ruleDecl (HsRule NoExtField ruleName activation tyvars ruleBndrs lhs rhs) = do+  located ruleName p_ruleName+  space+  p_activation activation+  space+  case tyvars of+    Nothing -> return ()+    Just xs -> do+      p_forallBndrs ForAllInvis p_hsTyVarBndr xs+      space+  -- It appears that there is no way to tell if there was an empty forall+  -- in the input or no forall at all. We do not want to add redundant+  -- foralls, so let's just skip the empty ones.+  unless (null ruleBndrs) $+    p_forallBndrs ForAllInvis p_ruleBndr ruleBndrs+  breakpoint+  inci $ do+    located lhs p_hsExpr     space-    case tyvars of-      Nothing -> return ()-      Just xs -> do-        p_forallBndrs ForallInvis p_hsTyVarBndr xs-        space-    -- It appears that there is no way to tell if there was an empty forall-    -- in the input or no forall at all. We do not want to add redundant-    -- foralls, so let's just skip the empty ones.-    unless (null ruleBndrs) $-      p_forallBndrs ForallInvis p_ruleBndr ruleBndrs-    breakpoint+    equals     inci $ do-      located lhs p_hsExpr-      space-      equals-      inci $ do-        breakpoint-        located rhs p_hsExpr-  XRuleDecl x -> noExtCon x+      breakpoint+      located rhs p_hsExpr  p_ruleName :: (SourceText, RuleName) -> R () p_ruleName (_, name) = atom $ (HsString NoSourceText name :: HsLit GhcPs)@@ -55,7 +54,6 @@ p_ruleBndr :: RuleBndr GhcPs -> R () p_ruleBndr = \case   RuleBndr NoExtField x -> p_rdrName x-  RuleBndrSig NoExtField x hswc -> parens N . sitcc $ do+  RuleBndrSig NoExtField x HsPS {..} -> parens N . sitcc $ do     p_rdrName x-    p_typeAscription hswc-  XRuleBndr x -> noExtCon x+    p_typeAscription (HsWC NoExtField (HsIB NoExtField hsps_body))
src/Ormolu/Printer/Meat/Declaration/Signature.hs view
@@ -11,10 +11,15 @@   ) where -import BasicTypes-import BooleanFormula import Control.Monad-import GHC+import GHC.Data.BooleanFormula+import GHC.Hs.Binds+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.Basic+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Type@@ -63,7 +68,6 @@     then newline     else breakpoint   located t p_hsType-p_typeAscription (XHsWildCardBndrs x) = noExtCon x  p_patSynSig ::   [Located RdrName] ->@@ -105,7 +109,6 @@     atom n     space     sitcc $ sep commaDel p_rdrName names-  XFixitySig x -> noExtCon x  p_inlineSig ::   -- | Name@@ -164,6 +167,7 @@     txt "["     atom n     txt "]"+  FinalActive -> notImplemented "FinalActive" -- NOTE(amesgen) is this unreachable or just not implemented?  p_specInstSig :: LHsSigType GhcPs -> R () p_specInstSig hsib =@@ -222,7 +226,7 @@     atom x  p_standaloneKindSig :: StandaloneKindSig GhcPs -> R ()-p_standaloneKindSig (StandaloneKindSig NoExtField name bndrs) = do+p_standaloneKindSig (StandaloneKindSig NoExtField name (HsIB NoExtField sig)) = do   txt "type"   inci $ do     space@@ -230,7 +234,4 @@     space     txt "::"     breakpoint-    case bndrs of-      HsIB NoExtField sig -> located sig p_hsType-      XHsImplicitBndrs x -> noExtCon x-p_standaloneKindSig (XStandaloneKindSig c) = noExtCon c+    located sig p_hsType
src/Ormolu/Printer/Meat/Declaration/Splice.hs view
@@ -5,11 +5,11 @@   ) where -import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Declaration.Value (p_hsSplice)  p_spliceDecl :: SpliceDecl GhcPs -> R () p_spliceDecl = \case   SpliceDecl NoExtField splice _explicit -> located splice p_hsSplice-  XSpliceDecl x -> noExtCon x
src/Ormolu/Printer/Meat/Declaration/Type.hs view
@@ -7,7 +7,11 @@   ) where -import GHC+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.Basic+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Type@@ -37,4 +41,3 @@     then newline     else breakpoint   inci (located t p_hsType)-p_synDecl _ _ (XLHsQTyVars x) _ = noExtCon x
src/Ormolu/Printer/Meat/Declaration/TypeFamily.hs view
@@ -11,11 +11,14 @@  import Control.Monad import Data.Maybe (isNothing)-import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.Basic+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import Ormolu.Printer.Meat.Type-import Ormolu.Utils  p_famDecl :: FamilyStyle -> FamilyDecl GhcPs -> R () p_famDecl style FamilyDecl {fdTyVars = HsQTvs {..}, ..} = do@@ -53,27 +56,20 @@         Just eqs -> do           newline           sep newline (located' (inci . p_tyFamInstEqn)) eqs-p_famDecl _ FamilyDecl {fdTyVars = XLHsQTyVars {}} =-  notImplemented "XLHsQTyVars"-p_famDecl _ (XFamilyDecl x) = noExtCon x  p_familyResultSigL ::   Located (FamilyResultSig GhcPs) ->   Maybe (R ())-p_familyResultSigL l =-  case l of-    L _ a -> case a of-      NoSig NoExtField -> Nothing-      KindSig NoExtField k -> Just $ do-        txt "::"-        breakpoint-        located k p_hsType-      TyVarSig NoExtField bndr -> Just $ do-        equals-        breakpoint-        located bndr p_hsTyVarBndr-      XFamilyResultSig x ->-        noExtCon x+p_familyResultSigL (L _ a) = case a of+  NoSig NoExtField -> Nothing+  KindSig NoExtField k -> Just $ do+    txt "::"+    breakpoint+    located k p_hsType+  TyVarSig NoExtField bndr -> Just $ do+    equals+    breakpoint+    located bndr p_hsTyVarBndr  p_injectivityAnn :: InjectivityAnn GhcPs -> R () p_injectivityAnn (InjectivityAnn a bs) = do@@ -90,22 +86,20 @@   case feqn_bndrs of     Nothing -> return ()     Just bndrs -> do-      p_forallBndrs ForallInvis p_hsTyVarBndr bndrs+      p_forallBndrs ForAllInvis p_hsTyVarBndr bndrs       breakpoint   inciIf (not $ null feqn_bndrs) $ do-    let famLhsSpn = getLoc feqn_tycon : fmap (getLoc . typeArgToType) feqn_pats+    let famLhsSpn = getLoc feqn_tycon : fmap lhsTypeArgSrcSpan feqn_pats     switchLayout famLhsSpn $       p_infixDefHelper         (isInfix feqn_fixity)         True         (p_rdrName feqn_tycon)-        (located' p_hsType . typeArgToType <$> feqn_pats)+        (p_lhsTypeArg <$> feqn_pats)     space     equals     breakpoint     inci (located feqn_rhs p_hsType)-p_tyFamInstEqn HsIB {hsib_body = XFamEqn x} = noExtCon x-p_tyFamInstEqn (XHsImplicitBndrs x) = noExtCon x  ---------------------------------------------------------------------------- -- Helpers
src/Ormolu/Printer/Meat/Declaration/Value.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-}@@ -14,21 +15,33 @@   ) where -import Bag (bagToList)-import BasicTypes import Control.Monad-import Ctype (is_space) import Data.Bool (bool) import Data.Char (isPunctuation, isSymbol) import Data.Data hiding (Infix, Prefix)+import Data.Function (on) import Data.Functor ((<&>))-import Data.List (intersperse, sortOn)+import Data.Generics.Schemes (everything)+import Data.List (intersperse, sortBy) import Data.List.NonEmpty (NonEmpty (..), (<|)) import qualified Data.List.NonEmpty as NE+import Data.Maybe (isJust) import Data.Text (Text) import qualified Data.Text as Text-import GHC-import OccName (occNameString)+import GHC.Data.Bag (bagToList)+import GHC.Hs.Binds+import GHC.Hs.Expr+import GHC.Hs.Extension+import GHC.Hs.Lit+import GHC.Hs.Pat+import GHC.Hs.Type+import GHC.LanguageExtensions.Type (Extension (NegativeLiterals))+import GHC.Parser.Annotation+import GHC.Parser.CharClass (is_space)+import GHC.Types.Basic+import GHC.Types.Name.Occurrence (occNameString)+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Config import Ormolu.Printer.Combinators import Ormolu.Printer.Internal@@ -67,12 +80,11 @@  p_valDecl :: HsBindLR GhcPs GhcPs -> R () p_valDecl = \case-  FunBind NoExtField funId funMatches _ _ -> p_funBind funId funMatches+  FunBind NoExtField funId funMatches _ -> p_funBind funId funMatches   PatBind NoExtField pat grhss _ -> p_match PatternBind False NoSrcStrict [pat] grhss   VarBind {} -> notImplemented "VarBinds" -- introduced by the type checker   AbsBinds {} -> notImplemented "AbsBinds" -- introduced by the type checker   PatSynBind NoExtField psb -> p_patSynBind psb-  XHsBindsLR x -> noExtCon x  p_funBind ::   Located RdrName ->@@ -97,11 +109,13 @@   -- | Match group   MatchGroup GhcPs (Located body) ->   R ()-p_matchGroup' placer render style MG {..} = do+p_matchGroup' placer render style mg@MG {..} = do   let ob = case style of-        Case -> id-        LambdaCase -> id+        Case -> bracesIfEmpty+        LambdaCase -> bracesIfEmpty         _ -> dontUseBraces+        where+          bracesIfEmpty = if isEmptyMatchGroup mg then useBraces else id   -- Since we are forcing braces on 'sepSemi' based on 'ob', we have to   -- restore the brace state inside the sepsemi.   ub <- bool dontUseBraces useBraces <$> canUseBraces@@ -116,8 +130,6 @@         (matchStrictness m)         m_pats         m_grhss-    p_Match (XMatch x) = noExtCon x-p_matchGroup' _ _ _ (XMatchGroup x) = noExtCon x  -- | Function id obtained through pattern matching on 'FunBind' should not -- be used to print the actual equations because the different ‘RdrNames’@@ -249,11 +261,11 @@                 else EqualSign         sep newline (located' (p_grhs' placer render groupStyle)) grhssGRHSs       p_where = do-        let whereIsEmpty = GHC.isEmptyLocalBindsPR (unLoc grhssLocalBinds)-        unless (GHC.eqEmptyLocalBinds (unLoc grhssLocalBinds)) $ do+        let whereIsEmpty = eqEmptyLocalBinds (unLoc grhssLocalBinds)+        unless (eqEmptyLocalBinds (unLoc grhssLocalBinds)) $ do           breakpoint           indentWhere <- getPrinterOpt poIndentWheres-          bool (inciBy $ -2) id indentWhere $ txt "where"+          bool (inciByFrac $ -2) id indentWhere $ txt "where"           unless whereIsEmpty breakpoint           inciIf indentWhere $ located grhssLocalBinds p_hsLocalBinds   inciIf indentBody $ do@@ -267,7 +279,6 @@     switchLayout [patGrhssSpan] $       placeHanging placement p_body     inci p_where-p_match' _ _ _ _ _ _ (XGRHSs x) = noExtCon x  p_grhs :: GroupStyle -> GRHS GhcPs (LHsExpr GhcPs) -> R () p_grhs = p_grhs' exprPlacement p_hsExpr@@ -306,55 +317,53 @@         Nothing -> Nothing         Just gs -> (Just . getLoc . NE.last) gs     p_body = located body render-p_grhs' _ _ _ (XGRHS x) = noExtCon x  p_hsCmd :: HsCmd GhcPs -> R ()-p_hsCmd = \case-  HsCmdArrApp NoExtField body input arrType _ -> do-    located body p_hsExpr+p_hsCmd = p_hsCmd' N++p_hsCmd' :: BracketStyle -> HsCmd GhcPs -> R ()+p_hsCmd' s = \case+  HsCmdArrApp NoExtField body input arrType rightToLeft -> do+    let (l, r) = if rightToLeft then (body, input) else (input, body)+    located l p_hsExpr     breakpoint     inci $ do-      case arrType of-        HsFirstOrderApp -> txt "-<"-        HsHigherOrderApp -> txt "-<<"+      case (arrType, rightToLeft) of+        (HsFirstOrderApp, True) -> txt "-<"+        (HsHigherOrderApp, True) -> txt "-<<"+        (HsFirstOrderApp, False) -> txt ">-"+        (HsHigherOrderApp, False) -> txt ">>-"       placeHanging (exprPlacement (unLoc input)) $-        located input p_hsExpr-  HsCmdArrForm NoExtField form Prefix _ cmds -> banana $ do+        located r p_hsExpr+  HsCmdArrForm NoExtField form Prefix _ cmds -> banana s $ do     located form p_hsExpr     unless (null cmds) $ do       breakpoint       inci (sequence_ (intersperse breakpoint (located' p_hsCmdTop <$> cmds)))-  HsCmdArrForm NoExtField form Infix _ [left, right] -> do-    located left p_hsCmdTop-    space-    located form p_hsExpr-    placeHanging (cmdTopPlacement (unLoc right)) $-      located right p_hsCmdTop+  HsCmdArrForm NoExtField form Infix _ [left, right] ->+    let opTree = OpBranch (cmdOpTree left) form (cmdOpTree right)+     in p_cmdOpTree (reassociateOpTree getOpName opTree)   HsCmdArrForm NoExtField _ Infix _ _ -> notImplemented "HsCmdArrForm"-  HsCmdApp {} ->-    -- XXX Does this ever occur in the syntax tree? It does not seem like it-    -- does. Open an issue and ping @yumiova if this ever occurs in output.-    notImplemented "HsCmdApp"+  HsCmdApp NoExtField cmd expr -> do+    located cmd (p_hsCmd' s)+    space+    located expr p_hsExpr   HsCmdLam NoExtField mgroup -> p_matchGroup' cmdPlacement p_hsCmd Lambda mgroup   HsCmdPar NoExtField c -> parens N $ sitcc $ located c p_hsCmd   HsCmdCase NoExtField e mgroup ->     p_case cmdPlacement p_hsCmd e mgroup+  HsCmdLamCase NoExtField mgroup ->+    p_lamcase cmdPlacement p_hsCmd mgroup   HsCmdIf NoExtField _ if' then' else' ->     p_if cmdPlacement p_hsCmd if' then' else'   HsCmdLet NoExtField localBinds c ->     p_let p_hsCmd localBinds c   HsCmdDo NoExtField es -> do     txt "do"-    newline-    inci . located es $-      sitcc . sep newline (sitcc . withSpacing (p_stmt' cmdPlacement p_hsCmd))-  HsCmdWrap {} -> notImplemented "HsCmdWrap"-  XCmd x -> noExtCon x+    p_stmts cmdPlacement (p_hsCmd' S) es  p_hsCmdTop :: HsCmdTop GhcPs -> R ()-p_hsCmdTop = \case-  HsCmdTop NoExtField cmd -> located cmd p_hsCmd-  XCmdTop x -> noExtCon x+p_hsCmdTop (HsCmdTop NoExtField cmd) = located cmd p_hsCmd  -- | Render an expression preserving blank lines between such consecutive -- expressions found in the original source code.@@ -367,7 +376,7 @@ withSpacing f l = located l $ \x -> do   case getLoc l of     UnhelpfulSpan _ -> f x-    RealSrcSpan currentSpn -> do+    RealSrcSpan currentSpn _ -> do       getSpanMark >>= \case         -- Spacing before comments will be handled by the code         -- that prints comments, so we just have to deal with@@ -399,19 +408,15 @@   R () p_stmt' placer render = \case   LastStmt NoExtField body _ _ -> located body render-  BindStmt NoExtField p f _ _ -> do+  BindStmt NoExtField p f@(L l x) -> do     located p p_pat     space     txt "<-"     let loc = getLoc p-        placement =-          case f of-            L l' x ->-              if isOneLineSpan-                (mkSrcSpan (srcSpanEnd loc) (srcSpanStart l'))-                then placer x-                else Normal-    switchLayout [loc, getLoc f] $+        placement+          | isOneLineSpan (mkSrcSpan (srcSpanEnd loc) (srcSpanStart l)) = placer x+          | otherwise = Normal+    switchLayout [loc, l] $       placeHanging placement (located f render)   ApplicativeStmt {} -> notImplemented "ApplicativeStmt" -- generated by renamer   BodyStmt NoExtField body _ _ -> located body render@@ -457,8 +462,23 @@     txt "rec"     space     sitcc $ sepSemi (withSpacing (p_stmt' placer render)) recS_stmts-  XStmtLR c -> noExtCon c +p_stmts ::+  Data body =>+  -- | Placer+  (body -> Placement) ->+  -- | Render+  (body -> R ()) ->+  -- | Statements to render+  Located [Located (Stmt GhcPs (Located body))] ->+  R ()+p_stmts placer render es = do+  breakpoint+  ub <- layoutToBraces <$> getLayout+  inci . located es $+    sepSemi+      (ub . withSpacing (p_stmt' placer render))+ gatherStmt :: ExprLStmt GhcPs -> [[ExprLStmt GhcPs]] gatherStmt (L _ (ParStmt NoExtField block _ _)) =   foldr ((<>) . gatherStmtBlock) [] block@@ -469,7 +489,6 @@ gatherStmtBlock :: ParStmtBlock GhcPs GhcPs -> [[ExprLStmt GhcPs]] gatherStmtBlock (ParStmtBlock _ stmts _ _) =   foldr (liftAppend . gatherStmt) [] stmts-gatherStmtBlock (XParStmtBlock x) = noExtCon x  p_hsLocalBinds :: HsLocalBindsLR GhcPs GhcPs -> R () p_hsLocalBinds = \case@@ -490,7 +509,7 @@         p_item' (p, item) =           positionToBracing p $             withSpacing (either p_valDecl p_sigDecl) item-        binds = sortOn (srcSpanStart . getLoc) items+        binds = sortBy (leftmost_smallest `on` getLoc) items     sitcc $ sepSemi p_item' (attachRelativePos binds)   HsValBinds NoExtField _ -> notImplemented "HsValBinds"   HsIPBinds NoExtField (IPBinds NoExtField xs) ->@@ -504,11 +523,8 @@         p_ipBind (IPBind NoExtField (Right _) _) =           -- Should only occur after the type checker           notImplemented "IPBind _ (Right _) _"-        p_ipBind (XIPBind x) = noExtCon x      in sepSemi (located' p_ipBind) xs-  HsIPBinds NoExtField _ -> notImplemented "HsIpBinds"   EmptyLocalBinds NoExtField -> return ()-  XHsLocalBindsLR x -> noExtCon x  p_hsRecField ::   HsRecField' RdrName (LHsExpr GhcPs) ->@@ -530,13 +546,12 @@ p_hsExpr' :: BracketStyle -> HsExpr GhcPs -> R () p_hsExpr' s = \case   HsVar NoExtField name -> p_rdrName name-  HsUnboundVar NoExtField v -> atom (unboundVarOcc v)+  HsUnboundVar NoExtField occ -> atom occ   HsConLikeOut NoExtField _ -> notImplemented "HsConLikeOut"   HsRecFld NoExtField x ->     case x of       Unambiguous NoExtField name -> p_rdrName name       Ambiguous NoExtField name -> p_rdrName name-      XAmbiguousFieldOcc xx -> noExtCon xx   HsOverLabel NoExtField _ v -> do     txt "#"     atom v@@ -551,10 +566,8 @@       r -> atom r   HsLam NoExtField mgroup ->     p_matchGroup Lambda mgroup-  HsLamCase NoExtField mgroup -> do-    txt "\\case"-    breakpoint-    inci (p_matchGroup LambdaCase mgroup)+  HsLamCase NoExtField mgroup ->+    p_lamcase exprPlacement p_hsExpr mgroup   HsApp NoExtField f x -> do     let -- In order to format function applications with multiple parameters         -- nicer, traverse the AST to gather the function and all the@@ -583,16 +596,22 @@     case placement of       Normal -> do         let -- Usually we want to bump indentation for arguments for the-            -- sake of readability. However, when the function itself is a-            -- do-block or case expression it is not a good idea. It seems-            -- to be safe to always bump indentation when the function-            -- expression is parenthesised.-            doIndent =-              case func of-                L _ (HsPar NoExtField _) -> True-                L _ (HsAppType NoExtField _ _) -> True-                L _ (HsMultiIf NoExtField _) -> True-                L spn _ -> isOneLineSpan spn+            -- sake of readability. However:+            -- When the function is itself a multi line do-block or a case+            -- expression, we can't indent by indentStep or more.+            -- When we are on the other hand *in* a do block, we have to+            -- indent by at least 1.+            -- Thus, we indent by half of indentStep when the function is+            -- a multi line do block or case expression.+            indentArg+              | isOneLineSpan (getLoc func) = case unLoc func of+                HsDo {} -> inciBy 2+                _ -> inci+              | otherwise = case unLoc func of+                HsDo {} -> inciHalf+                HsCase {} -> inciHalf+                HsLamCase {} -> inciHalf+                _ -> inci         ub <-           getLayout <&> \case             SingleLine -> useBraces@@ -600,8 +619,8 @@         ub $ do           located func (p_hsExpr' s)           breakpoint-          inciIf doIndent $ sep breakpoint (located' p_hsExpr) initp-        inciIf doIndent $ do+          indentArg $ sep breakpoint (located' p_hsExpr) initp+        indentArg $ do           unless (null initp) breakpoint           located lastp p_hsExpr       Hanging -> do@@ -609,7 +628,7 @@           located func (p_hsExpr' s)           breakpoint           sep breakpoint (located' p_hsExpr) initp-        placeHanging placement $+        placeHanging placement . dontUseBraces $           located lastp p_hsExpr   HsAppType NoExtField e a -> do     located e p_hsExpr@@ -625,9 +644,16 @@   OpApp NoExtField x op y -> do     let opTree = OpBranch (exprOpTree x) op (exprOpTree y)     p_exprOpTree s (reassociateOpTree getOpName opTree)-  NegApp NoExtField e _ -> do+  NegApp NoExtField e NoExtField -> do+    negativeLiterals <- isExtensionEnabled NegativeLiterals+    let isLiteral = case unLoc e of+          HsLit {} -> True+          HsOverLit {} -> True+          _ -> False     txt "-"-    space+    -- If NegativeLiterals is enabled, we have to insert a space before+    -- negated literals, as `- 1` and `-1` have differing AST.+    when (negativeLiterals && isLiteral) space     located e p_hsExpr   HsPar NoExtField e -> do     parens s $ sitcc $ located e $ dontUseBraces . p_hsExpr@@ -649,7 +675,6 @@         p_arg = \case           Present NoExtField x -> located x p_hsExprListItem           Missing NoExtField -> pure ()-          XTupArg x -> noExtCon x         p_larg = sitcc . located' p_arg         parens' =           case boxity of@@ -666,7 +691,7 @@     p_unboxedSum N tag arity (located e p_hsExpr)   HsCase NoExtField e mgroup ->     p_case exprPlacement p_hsExpr e mgroup-  HsIf NoExtField _ if' then' else' ->+  HsIf NoExtField if' then' else' ->     p_if exprPlacement p_hsExpr if' then' else'   HsMultiIf NoExtField guards -> do     txt "if"@@ -675,14 +700,10 @@   HsLet NoExtField localBinds e ->     p_let p_hsExpr localBinds e   HsDo NoExtField ctx es -> do-    let doBody header = do+    let doBody moduleName header = do+          forM_ moduleName $ \m -> atom m *> txt "."           txt header-          breakpoint-          ub <- layoutToBraces <$> getLayout-          inci $-            sepSemi-              (ub . withSpacing (p_stmt' exprPlacement (p_hsExpr' S)))-              (unLoc es)+          p_stmts exprPlacement (p_hsExpr' S) es         compBody = brackets N . located es $ \xs -> do           let p_parBody =                 sep@@ -706,10 +727,10 @@           space           p_parBody lists     case ctx of-      DoExpr -> doBody "do"-      MDoExpr -> doBody "mdo"+      DoExpr moduleName -> doBody moduleName "do"+      MDoExpr moduleName -> doBody moduleName "mdo"       ListComp -> compBody-      MonadComp -> notImplemented "MonadComp"+      MonadComp -> compBody       ArrowExpr -> notImplemented "ArrowExpr"       GhciStmtCtxt -> notImplemented "GhciStmtCtxt"       PatGuard _ -> notImplemented "PatGuard"@@ -726,7 +747,6 @@           (f :: HsRecField GhcPs (LHsExpr GhcPs))             { hsRecFieldLbl = case unLoc $ hsRecFieldLbl f of                 FieldOcc _ n -> n-                XFieldOcc x -> noExtCon x             }         fields = located' (p_hsRecField . updName) <$> rec_flds         dotdot =@@ -739,20 +759,24 @@     located rupd_expr p_hsExpr     useRecordDot' <- useRecordDot     let mrs sp = case getLoc sp of-          RealSrcSpan r -> Just r+          RealSrcSpan r _ -> Just r           _ -> Nothing     let isPluginForm =           ((1 +) . srcSpanEndCol <$> mrs rupd_expr)             == (srcSpanStartCol <$> mrs (head rupd_flds))+            && onTheSameLine (getLoc rupd_expr) (getLoc $ head rupd_flds)     unless (useRecordDot' && isPluginForm) breakpointPreRecordBrace     let updName f =           (f :: HsRecUpdField GhcPs)             { hsRecFieldLbl = case unLoc $ hsRecFieldLbl f of                 Ambiguous _ n -> n                 Unambiguous _ n -> n-                XAmbiguousFieldOcc x -> noExtCon x             }-    inci . braces N $+        updBraces =+          if useRecordDot' && isPluginForm+            then recordDotBraces+            else inci . braces N+    updBraces $       sep         commaDel         (sitcc . located' (p_hsRecField . updName))@@ -763,8 +787,6 @@     txt "::"     breakpoint     inci $ located hsib_body p_hsType-  ExprWithTySig NoExtField _ HsWC {hswc_body = XHsImplicitBndrs x} -> noExtCon x-  ExprWithTySig NoExtField _ (XHsWildCardBndrs x) -> noExtCon x   ArithSeq NoExtField _ x ->     case x of       From from -> brackets s $ do@@ -787,18 +809,6 @@         txt ".."         space         located to p_hsExpr-  HsSCC NoExtField _ name x -> do-    txt "{-# SCC "-    atom name-    txt " #-}"-    breakpoint-    located x p_hsExpr-  HsCoreAnn NoExtField _ value x -> do-    txt "{-# CORE "-    atom value-    txt " #-}"-    breakpoint-    located x p_hsExpr   HsBracket NoExtField x -> p_hsBracket x   HsRnBracketOut {} -> notImplemented "HsRnBracketOut"   HsTcBracketOut {} -> notImplemented "HsTcBracketOut"@@ -818,9 +828,14 @@     inci (located e p_hsExpr)   HsTick {} -> notImplemented "HsTick"   HsBinTick {} -> notImplemented "HsBinTick"-  HsTickPragma {} -> notImplemented "HsTickPragma"-  HsWrap {} -> notImplemented "HsWrap"-  XExpr x -> noExtCon x+  HsPragE NoExtField prag x -> case prag of+    HsPragSCC NoExtField _ name -> do+      txt "{-# SCC "+      atom name+      txt " #-}"+      breakpoint+      located x p_hsExpr+    HsPragTick {} -> notImplemented "HsTickPragma"  p_patSynBind :: PatSynBind GhcPs GhcPs -> R () p_patSynBind PSB {..} = do@@ -872,7 +887,6 @@           space           p_rdrName r       inci rhs-p_patSynBind (XPatSynBind x) = noExtCon x  p_case ::   Data body =>@@ -894,6 +908,20 @@   breakpoint   inci (p_matchGroup' placer render Case mgroup) +p_lamcase ::+  Data body =>+  -- | Placer+  (body -> Placement) ->+  -- | Render+  (body -> R ()) ->+  -- | Expression+  MatchGroup GhcPs (Located body) ->+  R ()+p_lamcase placer render mgroup = do+  txt "\\case"+  breakpoint+  inci (p_matchGroup' placer render LambdaCase mgroup)+ p_if ::   Data body =>   -- | Placer@@ -965,7 +993,7 @@     parens' $ sep commaDel (sitcc . located' p_pat) pats   SumPat NoExtField pat tag arity ->     p_unboxedSum S tag arity (located pat p_pat)-  ConPatIn pat details ->+  ConPat NoExtField pat details ->     case details of       PrefixCon xs -> sitcc $ do         p_rdrName pat@@ -990,7 +1018,6 @@             p_rdrName pat             space             located r p_pat-  ConPatOut {} -> notImplemented "ConPatOut" -- presumably created by renamer?   ViewPat NoExtField expr pat -> sitcc $ do     located expr p_hsExpr     space@@ -999,7 +1026,12 @@     inci (located pat p_pat)   SplicePat NoExtField splice -> p_hsSplice splice   LitPat NoExtField p -> atom p-  NPat NoExtField v _ _ -> located v (atom . ol_val)+  NPat NoExtField v (isJust -> isNegated) NoExtField -> do+    when isNegated $ do+      txt "-"+      negativeLiterals <- isExtensionEnabled NegativeLiterals+      when negativeLiterals space+    located v (atom . ol_val)   NPlusKPat NoExtField n k _ _ _ -> sitcc $ do     p_rdrName n     breakpoint@@ -1007,11 +1039,9 @@       txt "+"       space       located k (atom . ol_val)-  SigPat NoExtField pat hswc -> do+  SigPat NoExtField pat HsPS {..} -> do     located pat p_pat-    p_typeAscription hswc-  CoPat {} -> notImplemented "CoPat" -- apparently created at some later stage-  XPat x -> noExtCon x+    p_typeAscription (HsWC NoExtField (HsIB NoExtField hsps_body))  p_pat_hsRecField :: HsRecField' (FieldOcc GhcPs) (LPat GhcPs) -> R () p_pat_hsRecField HsRecField {..} = do@@ -1051,8 +1081,6 @@     atom str     txt "|]"   HsSpliced {} -> notImplemented "HsSpliced"-  HsSplicedT {} -> notImplemented "HsSplicedT"-  XSplice x -> noExtCon x  p_hsSpliceTH ::   -- | Typed splice?@@ -1063,13 +1091,10 @@   SpliceDecoration ->   R () p_hsSpliceTH isTyped expr = \case-  HasParens -> do-    txt decoSymbol-    parens N (located expr (sitcc . p_hsExpr))-  HasDollar -> do+  DollarSplice -> do     txt decoSymbol     located expr (sitcc . p_hsExpr)-  NoParens ->+  BareSplice ->     located expr (sitcc . p_hsExpr)   where     decoSymbol = if isTyped then "$$" else "$"@@ -1083,9 +1108,9 @@           _ -> "e"     quote name (located expr p_hsExpr)   PatBr NoExtField pat -> located pat (quote "p" . p_pat)-  DecBrL NoExtField decls -> quote "d" (p_hsDecls Free decls)+  DecBrL NoExtField decls -> quote "d" (handleStarIsType decls (p_hsDecls Free decls))   DecBrG NoExtField _ -> notImplemented "DecBrG" -- result of renamer-  TypBr NoExtField ty -> quote "t" (located ty p_hsType)+  TypBr NoExtField ty -> quote "t" (located ty (handleStarIsType ty . p_hsType))   VarBr NoExtField isSingleQuote name -> do     txt (bool "''" "'" isSingleQuote)     -- HACK As you can see we use 'noLoc' here to be able to pass name into@@ -1107,7 +1132,6 @@     located expr p_hsExpr     breakpoint'     txt "||]"-  XBracket x -> noExtCon x   where     quote :: Text -> R () -> R ()     quote name body = do@@ -1119,6 +1143,19 @@         dontUseBraces body         breakpoint'         txt "|]"+    -- With StarIsType, type and declaration brackets might end with a *,+    -- so we have to insert a space in the end to prevent the (mis)parsing+    -- of an (*|) operator.+    -- The detection is a bit overcautious, as it adds the spaces as soon as+    -- HsStarTy is anywhere in the type/declaration.+    handleStarIsType :: Data a => a -> R () -> R ()+    handleStarIsType a p+      | containsHsStarTy a = space *> p <* space+      | otherwise = p+      where+        containsHsStarTy = everything (||) $ \b -> case cast @_ @(HsType GhcPs) b of+          Just HsStarTy {} -> True+          _ -> False  -- Print the source text of a string literal while indenting -- gaps correctly.@@ -1188,7 +1225,6 @@ getGRHSSpan :: GRHS GhcPs (Located body) -> SrcSpan getGRHSSpan (GRHS NoExtField guards body) =   combineSrcSpans' $ getLoc body :| map getLoc guards-getGRHSSpan (XGRHS x) = noExtCon x  -- | Place a thing that may have a hanging form. This function handles how -- to separate it from preceding expressions and whether to bump indentation@@ -1217,13 +1253,12 @@ cmdPlacement = \case   HsCmdLam NoExtField _ -> Hanging   HsCmdCase NoExtField _ _ -> Hanging+  HsCmdLamCase NoExtField _ -> Hanging   HsCmdDo NoExtField _ -> Hanging   _ -> Normal  cmdTopPlacement :: HsCmdTop GhcPs -> Placement-cmdTopPlacement = \case-  HsCmdTop NoExtField (L _ x) -> cmdPlacement x-  XCmdTop x -> noExtCon x+cmdTopPlacement (HsCmdTop NoExtField (L _ x)) = cmdPlacement x  -- | Check if given expression has a hanging form. exprPlacement :: HsExpr GhcPs -> Placement@@ -1236,8 +1271,8 @@     _ -> Normal   HsLamCase NoExtField _ -> Hanging   HsCase NoExtField _ _ -> Hanging-  HsDo NoExtField DoExpr _ -> Hanging-  HsDo NoExtField MDoExpr _ -> Hanging+  HsDo NoExtField (DoExpr _) _ -> Hanging+  HsDo NoExtField (MDoExpr _) _ -> Hanging   OpApp NoExtField _ op y ->     case (fmap getOpNameStr . getOpName . unLoc) op of       Just "$" -> exprPlacement (unLoc y)@@ -1277,28 +1312,14 @@   R () p_exprOpTree s (OpNode x) = located x (p_hsExpr' s) p_exprOpTree s (OpBranch x op y) = do-  -- If the beginning of the first argument and the second argument are on-  -- the same line, and the second argument has a hanging form, use hanging-  -- placement.-  let placement =-        if isOneLineSpan-          (mkSrcSpan (srcSpanStart (opTreeLoc x)) (srcSpanStart (opTreeLoc y)))-          then case y of-            OpNode (L _ n) -> exprPlacement n-            _ -> Normal-          else Normal+  let placement = opBranchPlacement exprPlacement x y       -- Distinguish holes used in infix notation.       -- eg. '1 _foo 2' and '1 `_foo` 2'       opWrapper = case unLoc op of         HsUnboundVar NoExtField _ -> backticks         _ -> id-  layout <- getLayout-  let ub = case layout of-        SingleLine -> useBraces-        MultiLine -> case placement of-          Hanging -> useBraces-          Normal -> dontUseBraces-      opNameStr = (fmap getOpNameStr . getOpName . unLoc) op+  ub <- opBranchBraceStyle placement+  let opNameStr = (fmap getOpNameStr . getOpName . unLoc) op       gotDollar = opNameStr == Just "$"       gotColon = opNameStr == Just ":"       gotRecordDot = isRecordDot (unLoc op) (opTreeLoc y)@@ -1308,7 +1329,7 @@       p_op = located op (opWrapper . p_hsExpr)       p_y = switchLayout [opTreeLoc y] (p_exprOpTree N y)       isSection = case (opTreeLoc x, getLoc op) of-        (RealSrcSpan treeSpan, RealSrcSpan opSpan) ->+        (RealSrcSpan treeSpan _, RealSrcSpan opSpan _) ->           srcSpanEndCol treeSpan /= srcSpanStartCol opSpan         _ -> False       isDoBlock = \case@@ -1317,7 +1338,7 @@   useRecordDot' <- useRecordDot   if       | gotColon -> do-        lhs+        ub lhs         space         p_op         case placement of@@ -1354,6 +1375,52 @@           OpNode (unLoc -> HsDo _ _ _) | isOneLineSpan (opTreeLoc x) -> breakpoint >> opAndRhs           _ -> placeHanging placement opAndRhs +pattern CmdTopCmd :: HsCmd GhcPs -> LHsCmdTop GhcPs+pattern CmdTopCmd cmd <- (L _ (HsCmdTop NoExtField (L _ cmd)))++cmdOpTree :: LHsCmdTop GhcPs -> OpTree (LHsCmdTop GhcPs) (LHsExpr GhcPs)+cmdOpTree = \case+  CmdTopCmd (HsCmdArrForm NoExtField op Infix _ [x, y]) ->+    OpBranch (cmdOpTree x) op (cmdOpTree y)+  n -> OpNode n++p_cmdOpTree :: OpTree (LHsCmdTop GhcPs) (LHsExpr GhcPs) -> R ()+p_cmdOpTree = \case+  OpNode n -> located n p_hsCmdTop+  OpBranch x op y -> do+    let placement = opBranchPlacement cmdTopPlacement x y+    ub <- opBranchBraceStyle placement+    ub $ p_cmdOpTree x+    placeHanging placement $ do+      located op p_hsExpr+      space+      p_cmdOpTree y++opBranchPlacement ::+  -- | Placement of nodes+  (ty -> Placement) ->+  -- | Left branch+  OpTree (Located ty) op ->+  -- | Right branch+  OpTree (Located ty) op ->+  Placement+opBranchPlacement f x y+  -- If the beginning of the first argument and the second argument are on+  -- the same line, and the second argument has a hanging form, use hanging+  -- placement.+  | isOneLineSpan (mkSrcSpan (srcSpanStart (opTreeLoc x)) (srcSpanStart (opTreeLoc y))),+    OpNode (L _ n) <- y =+    f n+  | otherwise = Normal++opBranchBraceStyle :: Placement -> R (R () -> R ())+opBranchBraceStyle placement =+  getLayout <&> \case+    SingleLine -> useBraces+    MultiLine -> case placement of+      Hanging -> useBraces+      Normal -> dontUseBraces+ -- | Return 'True' if given expression is a record-dot operator expression. isRecordDot ::   -- | Operator expression@@ -1361,8 +1428,8 @@   -- | Span of the expression on the right-hand side of the operator   SrcSpan ->   Bool-isRecordDot op (RealSrcSpan ySpan) = case op of-  HsVar NoExtField (L (RealSrcSpan opSpan) opName) ->+isRecordDot op (RealSrcSpan ySpan _) = case op of+  HsVar NoExtField (L (RealSrcSpan opSpan _) opName) ->     (getOpNameStr opName == ".") && (srcSpanEndCol opSpan == srcSpanStartCol ySpan)   _ -> False isRecordDot _ _ = False@@ -1373,7 +1440,7 @@   e <- getEnclosingSpan (const True)   case e of     Nothing -> return []-    Just e' -> getAnns (RealSrcSpan e')+    Just e' -> getAnns (RealSrcSpan e' Nothing)  -- | For use before record braces. Collapse to empty if not 'poRecordBraceSpace'. breakpointPreRecordBrace :: R ()
src/Ormolu/Printer/Meat/Declaration/Value.hs-boot view
@@ -7,7 +7,10 @@   ) where -import GHC+import GHC.Hs.Binds+import GHC.Hs.Expr+import GHC.Hs.Extension+import GHC.Hs.Pat import Ormolu.Printer.Combinators  p_valDecl :: HsBindLR GhcPs GhcPs -> R ()
src/Ormolu/Printer/Meat/Declaration/Warning.hs view
@@ -7,22 +7,23 @@   ) where -import BasicTypes import Data.Foldable import Data.Text (Text)-import GHC+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Types.Basic+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common  p_warnDecls :: WarnDecls GhcPs -> R () p_warnDecls (Warnings NoExtField _ warnings) =   traverse_ (located' p_warnDecl) warnings-p_warnDecls (XWarnDecls x) = noExtCon x  p_warnDecl :: WarnDecl GhcPs -> R () p_warnDecl (Warning NoExtField functions warningTxt) =   p_topLevelWarning functions warningTxt-p_warnDecl (XWarnDecl x) = noExtCon x  p_moduleWarning :: WarningTxt -> R () p_moduleWarning wtxt = do
src/Ormolu/Printer/Meat/ImportExport.hs view
@@ -12,7 +12,11 @@  import Control.Monad import qualified Data.Text as T-import GHC+import GHC.Hs.Extension+import GHC.Hs.ImpExp+import GHC.LanguageExtensions.Type+import GHC.Types.SrcLoc+import GHC.Unit.Types import Ormolu.Config (poDiffFriendlyImportExport) import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common@@ -31,11 +35,12 @@       (\(p, l) -> sitcc (located l (p_lie layout p)))       (attachRelativePos xs) -p_hsmodImport :: Bool -> ImportDecl GhcPs -> R ()-p_hsmodImport useQualifiedPost ImportDecl {..} = do+p_hsmodImport :: ImportDecl GhcPs -> R ()+p_hsmodImport ImportDecl {..} = do+  useQualifiedPost <- isExtensionEnabled ImportQualifiedPost   txt "import"   space-  when ideclSource (txt "{-# SOURCE #-}")+  when (ideclSource == IsBoot) (txt "{-# SOURCE #-}")   space   when ideclSafe (txt "safe")   space@@ -75,7 +80,6 @@             (\(p, l) -> sitcc (located l (p_lie layout p)))             (attachRelativePos xs)     newline-p_hsmodImport _ (XImportDecl x) = noExtCon x  p_lie :: Layout -> RelativePos -> IE GhcPs -> R () p_lie encLayout relativePos = \case@@ -116,7 +120,6 @@   IEDoc NoExtField str ->     p_hsDocString Pipe False (noLoc str)   IEDocNamed NoExtField str -> txt $ "-- $" <> T.pack str-  XIE x -> noExtCon x   where     p_comma =       case encLayout of@@ -145,7 +148,7 @@       txt "("       breakpoint'       sitcc body-      vlayout (txt ")") (inciBy (-1) trailingParen)+      vlayout (txt ")") (inciByFrac (-1) trailingParen)     False -> sitcc $ do       txt "("       body
src/Ormolu/Printer/Meat/Module.hs view
@@ -9,13 +9,12 @@ where  import Control.Monad-import qualified Data.Text as T-import GHC+import GHC.Hs+import GHC.Types.SrcLoc import Ormolu.Config import Ormolu.Imports (normalizeImports) import Ormolu.Parser.CommentStream import Ormolu.Parser.Pragma-import Ormolu.Parser.Shebang import Ormolu.Printer.Combinators import Ormolu.Printer.Comments import Ormolu.Printer.Meat.Common@@ -28,23 +27,15 @@ p_hsModule ::   -- | Stack header   Maybe (RealLocated Comment) ->-  -- | Shebangs-  [Shebang] ->   -- | Pragmas and the associated comments   [([RealLocated Comment], Pragma)] ->-  -- | Whether to use postfix qualified imports-  Bool ->   -- | AST to print-  HsModule GhcPs ->+  HsModule ->   R ()-p_hsModule mstackHeader shebangs pragmas qualifiedPost HsModule {..} = do+p_hsModule mstackHeader pragmas HsModule {..} = do   let deprecSpan = maybe [] (\(L s _) -> [s]) hsmodDeprecMessage       exportSpans = maybe [] (\(L s _) -> [s]) hsmodExports   switchLayout (deprecSpan <> exportSpans) $ do-    forM_ shebangs $ \(Shebang x) ->-      located x $ \shebang -> do-        txt (T.pack shebang)-        newline     forM_ mstackHeader $ \(L spn comment) -> do       spitCommentNow spn comment       newline@@ -77,7 +68,7 @@     newline     preserveGroups <- getPrinterOpt poRespectful     forM_ (normalizeImports preserveGroups hsmodImports) $ \importGroup -> do-      forM_ importGroup (located' (p_hsmodImport qualifiedPost))+      forM_ importGroup (located' p_hsmodImport)       newline     declNewline     switchLayout (getLoc <$> hsmodDecls) $ do
src/Ormolu/Printer/Meat/Pragma.hs view
@@ -13,11 +13,11 @@ import qualified Data.List as L import Data.Maybe (listToMaybe) import qualified Data.Text as T+import GHC.Types.SrcLoc import Ormolu.Parser.CommentStream import Ormolu.Parser.Pragma (Pragma (..)) import Ormolu.Printer.Combinators import Ormolu.Printer.Comments-import SrcLoc  -- | Pragma classification. data PragmaTy
src/Ormolu/Printer/Meat/Type.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-}  -- | Rendering of types.@@ -9,14 +10,23 @@     hasDocStrings,     p_hsContext,     p_hsTyVarBndr,+    ForAllVisibility (..),     p_forallBndrs,     p_conDeclFields,+    p_lhsTypeArg,     tyVarsToTypes,+    tyVarsToTyPats,   ) where  import Data.Data (Data)-import GHC hiding (isPromoted)+import GHC.Hs.Decls+import GHC.Hs.Extension+import GHC.Hs.Type+import GHC.Types.Basic hiding (isPromoted)+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc+import GHC.Types.Var import Ormolu.Printer.Combinators import Ormolu.Printer.Meat.Common import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration.Value (p_hsSplice, p_stringLit)@@ -36,8 +46,10 @@  p_hsType' :: Bool -> TypeDocStyle -> HsType GhcPs -> R () p_hsType' multilineArgs docStyle = \case-  HsForAllTy NoExtField visibility bndrs t -> do-    p_forallBndrs visibility p_hsTyVarBndr bndrs+  HsForAllTy NoExtField tele t -> do+    case tele of+      HsForAllInvis NoExtField bndrs -> p_forallBndrs ForAllInvis p_hsTyVarBndr bndrs+      HsForAllVis NoExtField bndrs -> p_forallBndrs ForAllVis p_hsTyVarBndr bndrs     interArgBreak     p_hsTypeR (unLoc t)   HsQualTy NoExtField qs t -> do@@ -82,10 +94,17 @@     inci $ do       txt "@"       located kd p_hsType-  HsFunTy NoExtField x y@(L _ y') -> do+  HsFunTy NoExtField arrow x y@(L _ y') -> do     located x p_hsType     space-    txt "->"+    case arrow of+      HsUnrestrictedArrow _ -> txt "->"+      HsLinearArrow _ -> txt "%1 ->"+      HsExplicitMult _ mult -> do+        txt "%"+        p_hsTypeR (unLoc mult)+        space+        txt "->"     interArgBreak     case y' of       HsFunTy {} -> p_hsTypeR y'@@ -170,6 +189,7 @@   XHsType (NHsCoreTy t) -> atom t   where     isPromoted = \case+      HsAppTy _ (L _ f) _ -> isPromoted f       HsTyVar _ IsPromoted _ -> True       HsExplicitTupleTy {} -> True       HsExplicitListTy {} -> True@@ -185,7 +205,9 @@ hasDocStrings :: HsType GhcPs -> Bool hasDocStrings = \case   HsDocTy {} -> True-  HsFunTy _ (L _ x) (L _ y) -> hasDocStrings x || hasDocStrings y+  HsFunTy _ _ (L _ x) (L _ y) -> hasDocStrings x || hasDocStrings y+  HsForAllTy _ _ (L _ x) -> hasDocStrings x+  HsQualTy _ _ (L _ x) -> hasDocStrings x   _ -> False  p_hsContext :: HsContext GhcPs -> R ()@@ -194,22 +216,34 @@   [x] -> located x p_hsType   xs -> parens N $ sep commaDel (sitcc . located' p_hsType) xs -p_hsTyVarBndr :: HsTyVarBndr GhcPs -> R ()+class IsInferredTyVarBndr flag where+  isInferred :: flag -> Bool++instance IsInferredTyVarBndr () where+  isInferred () = False++instance IsInferredTyVarBndr Specificity where+  isInferred = \case+    InferredSpec -> True+    SpecifiedSpec -> False++p_hsTyVarBndr :: IsInferredTyVarBndr flag => HsTyVarBndr flag GhcPs -> R () p_hsTyVarBndr = \case-  UserTyVar NoExtField x ->-    p_rdrName x-  KindedTyVar NoExtField l k -> parens N . sitcc $ do+  UserTyVar NoExtField flag x ->+    (if isInferred flag then braces N else id) $ p_rdrName x+  KindedTyVar NoExtField flag l k -> (if isInferred flag then braces else parens) N . sitcc $ do     located l atom     space     txt "::"     breakpoint     inci (located k p_hsType)-  XTyVarBndr x -> noExtCon x +data ForAllVisibility = ForAllInvis | ForAllVis+ -- | Render several @forall@-ed variables.-p_forallBndrs :: Data a => ForallVisFlag -> (a -> R ()) -> [Located a] -> R ()-p_forallBndrs ForallInvis _ [] = txt "forall."-p_forallBndrs ForallVis _ [] = txt "forall ->"+p_forallBndrs :: Data a => ForAllVisibility -> (a -> R ()) -> [Located a] -> R ()+p_forallBndrs ForAllInvis _ [] = txt "forall."+p_forallBndrs ForAllVis _ [] = txt "forall ->" p_forallBndrs vis p tyvars =   switchLayout (getLoc <$> tyvars) $ do     txt "forall"@@ -217,8 +251,8 @@     inci $ do       sitcc $ sep breakpoint (sitcc . located' p) tyvars       case vis of-        ForallInvis -> txt "."-        ForallVis -> space >> txt "->"+        ForAllInvis -> txt "."+        ForAllVis -> space >> txt "->"  p_conDeclFields :: [LConDeclField GhcPs] -> R () p_conDeclFields xs =@@ -236,7 +270,6 @@   txt "::"   breakpoint   sitcc . inci $ p_hsType (unLoc cd_fld_type)-p_conDeclField (XConDeclField x) = noExtCon x  tyOpTree :: LHsType GhcPs -> OpTree (LHsType GhcPs) (Located RdrName) tyOpTree (L _ (HsOpTy NoExtField l op r)) =@@ -254,18 +287,25 @@     space     p_tyOpTree r +p_lhsTypeArg :: LHsTypeArg GhcPs -> R ()+p_lhsTypeArg = \case+  HsValArg ty -> located ty p_hsType+  -- first argument is the SrcSpan of the @,+  -- but the @ always has to be directly before the type argument+  HsTypeArg _ ty -> txt "@" *> located ty p_hsType+  -- NOTE(amesgen) is this unreachable or just not implemented?+  HsArgPar _ -> notImplemented "HsArgPar"+ ---------------------------------------------------------------------------- -- Conversion functions  tyVarsToTypes :: LHsQTyVars GhcPs -> [LHsType GhcPs]-tyVarsToTypes = \case-  HsQTvs {..} -> fmap tyVarToType <$> hsq_explicit-  XLHsQTyVars x -> noExtCon x+tyVarsToTypes HsQTvs {..} = fmap tyVarToType <$> hsq_explicit -tyVarToType :: HsTyVarBndr GhcPs -> HsType GhcPs+tyVarToType :: HsTyVarBndr () GhcPs -> HsType GhcPs tyVarToType = \case-  UserTyVar NoExtField tvar -> HsTyVar NoExtField NotPromoted tvar-  KindedTyVar NoExtField tvar kind ->+  UserTyVar NoExtField () tvar -> HsTyVar NoExtField NotPromoted tvar+  KindedTyVar NoExtField () tvar kind ->     -- Note: we always add parentheses because for whatever reason GHC does     -- not use HsParTy for left-hand sides of declarations. Please see     -- <https://gitlab.haskell.org/ghc/ghc/issues/17404>. This is fine as@@ -273,4 +313,6 @@     -- declarations.     HsParTy NoExtField . noLoc $       HsKindSig NoExtField (noLoc (HsTyVar NoExtField NotPromoted tvar)) kind-  XTyVarBndr x -> noExtCon x++tyVarsToTyPats :: LHsQTyVars GhcPs -> HsTyPats GhcPs+tyVarsToTyPats HsQTvs {..} = HsValArg . fmap tyVarToType <$> hsq_explicit
src/Ormolu/Printer/Operators.hs view
@@ -15,8 +15,10 @@ import Data.Map.Strict (Map) import qualified Data.Map.Strict as M import Data.Maybe (fromMaybe, mapMaybe)-import GHC-import OccName (occNameString)+import GHC.Types.Basic+import GHC.Types.Name.Occurrence (occNameString)+import GHC.Types.Name.Reader+import GHC.Types.SrcLoc import Ormolu.Utils (unSrcSpan)  -- | Intermediate representation of operator trees. It has two type
src/Ormolu/Printer/SpanStream.hs view
@@ -14,7 +14,7 @@ import Data.Generics (everything, ext2Q) import Data.List (sortOn) import Data.Typeable (cast)-import SrcLoc+import GHC.Types.SrcLoc  -- | A stream of 'RealSrcSpan's in ascending order. This allows us to tell -- e.g. whether there is another \"located\" element of AST between current@@ -43,4 +43,4 @@       case cast mspn :: Maybe SrcSpan of         Nothing -> mempty         Just (UnhelpfulSpan _) -> mempty-        Just (RealSrcSpan spn) -> D.singleton spn+        Just (RealSrcSpan spn _) -> D.singleton spn
src/Ormolu/Processing/Common.hs view
@@ -1,27 +1,72 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ViewPatterns #-}  -- | Common definitions for pre- and post- processing. module Ormolu.Processing.Common-  ( OrmoluState (..),-    startDisabling,-    endDisabling,+  ( removeIndentation,+    reindent,+    linesInRegion,+    regionInbetween,+    intSetToRegions,   ) where -import Data.String (IsString (..))+import Data.Char (isSpace)+import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet+import Data.Text (Text)+import qualified Data.Text as T+import Ormolu.Config --- | Ormolu state.-data OrmoluState-  = -- | Enabled-    OrmoluEnabled-  | -- | Disabled-    OrmoluDisabled-  deriving (Eq, Show)+-- | Remove indentation from a given 'String'. Return the input with+-- indentation removed and the detected indentation level.+removeIndentation :: String -> (String, Int)+removeIndentation (lines -> xs) = (unlines (drop n <$> xs), n)+  where+    n = minimum (getIndent <$> xs)+    getIndent y =+      if all isSpace y+        then 0+        else length (takeWhile isSpace y) --- | Marker for the beginning of the region where Ormolu should be disabled.-startDisabling :: IsString s => s-startDisabling = "{- ORMOLU_DISABLE_START"+-- | Add indentation to a 'Text'.+reindent :: Int -> Text -> Text+reindent i = T.unlines . fmap (T.replicate i " " <>) . T.lines --- | Marker for the end of the region where Ormolu should be disabled.-endDisabling :: IsString s => s-endDisabling = "ORMOLU_DISABLE_END -}"+-- | All lines in the region specified by 'RegionDeltas'.+linesInRegion :: RegionDeltas -> String -> String+linesInRegion RegionDeltas {..} (lines -> ls) = unlines middle+  where+    (_, nonPrefix) = splitAt regionPrefixLength ls+    middle = take (length nonPrefix - regionSuffixLength) nonPrefix++-- | Get the region after the end of the first and till the end of+-- the second region.+regionInbetween ::+  -- | Total number of lines+  Int ->+  RegionDeltas ->+  RegionDeltas ->+  RegionDeltas+regionInbetween total r r' =+  RegionDeltas+    { regionPrefixLength = total - regionSuffixLength r,+      regionSuffixLength = total - regionPrefixLength r'+    }++-- | Convert a set of line indices into disjoint 'RegionDelta's+intSetToRegions ::+  -- | Total number of lines+  Int ->+  IntSet ->+  [RegionDeltas]+intSetToRegions total (IntSet.toAscList -> indices) =+  regionIndicesToDeltas total <$> go Nothing indices+  where+    go Nothing [] = []+    go (Just (a, b)) [] = [RegionIndices (Just a) (Just b)]+    go Nothing (i : is) = go (Just (i, i)) is+    go (Just (a, b)) (i : is)+      | b + 1 == i = go (Just (a, i)) is+      | otherwise = RegionIndices (Just a) (Just b) : go (Just (i, i)) is
src/Ormolu/Processing/Cpp.hs view
@@ -2,69 +2,61 @@  -- | Support for CPP. module Ormolu.Processing.Cpp-  ( State (..),-    processLine,-    unmaskLine,+  ( cppLines,   ) where -import Control.Monad import Data.Char (isSpace)+import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet import qualified Data.List as L import Data.Maybe (isJust)-import Data.String-import Data.Text (Text)-import qualified Data.Text as T  -- | State of the CPP processor. data State   = -- | Outside of CPP directives     Outside-  | -- | In a conditional expression-    InConditional-  | -- | In a continuation (after @\\@)+  | -- | In a conditional expression, with a positive nesting count+    InConditional Int+  | -- | In a continuation (after @\\@), but not in a conditional expression     InContinuation   deriving (Eq, Show) --- | Automatically mask the line when needed and update the 'State'.-processLine :: String -> State -> (String, State)-processLine line state-  | for "define " = (masked, state')-  | for "include " = (masked, state')-  | for "undef " = (masked, state')-  | for "ifdef " = (masked, InConditional)-  | for "ifndef " = (masked, InConditional)-  | for "if " = (masked, InConditional)-  | for "else" = (masked, InConditional)-  | for "elif" = (masked, InConditional)-  | for "endif" = (masked, state')-  | otherwise =-    case state of-      Outside -> (line, Outside)-      InConditional -> (masked, InConditional)-      InContinuation -> (masked, state')+-- | Return an 'IntSet' containing all lines which are affected by CPP.+cppLines :: String -> IntSet+cppLines input = IntSet.fromAscList $ go Outside (lines input `zip` [1 ..])   where-    for directive = isJust $ do-      s <- dropWhile isSpace <$> L.stripPrefix "#" line-      void (L.stripPrefix directive s)-    masked = maskLine line-    state' =-      if "\\" `L.isSuffixOf` line-        then InContinuation-        else Outside---- | Mask the given line.-maskLine :: String -> String-maskLine x = maskPrefix ++ x---- | If the given line is masked, unmask it. Otherwise return the line--- unchanged.-unmaskLine :: Text -> Text-unmaskLine x =-  case T.stripPrefix maskPrefix (T.stripStart x) of-    Nothing -> x-    Just x' -> x'---- | Mask prefix for CPP.-maskPrefix :: IsString s => s-maskPrefix = "-- ORMOLU_CPP_MASK"+    go _ [] = []+    go state ((line, i) : ls)+      | any for ["define ", "include ", "undef "] =+        i : go contState ls+      | any for ["ifdef ", "ifndef ", "if "] =+        let state' = case state of+              InConditional nc -> InConditional (nc + 1)+              _ -> InConditional 1+         in i : go state' ls+      | for "endif" =+        let state' = case state of+              InConditional nc | nc > 1 -> InConditional (nc - 1)+              _ -> Outside+         in i : go state' ls+      | otherwise =+        let is = case state of+              Outside -> []+              _ -> [i]+            state' = case state of+              InContinuation -> contState+              _ -> state+         in is <> go state' ls+      where+        for directive = isJust $ do+          s <- dropWhile isSpace <$> L.stripPrefix "#" line+          L.stripPrefix directive s+        contState =+          if "\\" `L.isSuffixOf` line && not inConditional+            then InContinuation+            else Outside+          where+            inConditional = case state of+              InConditional {} -> True+              _ -> False
− src/Ormolu/Processing/Postprocess.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}---- | Postprocessing for the results of printing.-module Ormolu.Processing.Postprocess-  ( postprocess,-  )-where--import Data.Text (Text)-import qualified Data.Text as T-import Ormolu.Processing.Common-import qualified Ormolu.Processing.Cpp as Cpp---- | Postprocess output of the formatter.-postprocess ::-  -- | Desired indentation level-  Int ->-  -- | Input to process-  Text ->-  Text-postprocess indent =-  T.unlines-    . fmap indentLine-    . fmap Cpp.unmaskLine-    . filter (not . magicComment)-    . T.lines-  where-    magicComment (T.stripStart -> x) =-      x == startDisabling || x == endDisabling-    indentLine x = T.replicate indent " " <> x
src/Ormolu/Processing/Preprocess.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}  -- | Preprocessing for input source code.@@ -9,139 +10,168 @@ where  import Control.Monad+import Data.Bifunctor (bimap) import Data.Char (isSpace)+import Data.Function ((&))+import Data.IntMap (IntMap)+import qualified Data.IntMap.Strict as IntMap+import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet import qualified Data.List as L-import Data.Maybe (isJust, maybeToList)-import FastString+import Data.Maybe (isJust)+import Data.Text (Text)+import qualified Data.Text as T import Ormolu.Config (RegionDeltas (..))-import Ormolu.Parser.Shebang (isShebang) import Ormolu.Processing.Common-import qualified Ormolu.Processing.Cpp as Cpp-import SrcLoc+import Ormolu.Processing.Cpp --- | Transform given input possibly returning comments extracted from it.--- This handles LINE pragmas, CPP, shebangs, and the magic comments for--- enabling\/disabling of Ormolu.+-- | Preprocess the specified region of the input into raw snippets+-- and subregions to be formatted. preprocess ::-  -- | File name, just to use in the spans-  FilePath ->-  -- | Input to process-  String ->-  -- | Region deltas+  -- | Whether CPP is enabled+  Bool ->   RegionDeltas ->-  -- | Literal prefix, pre-processed input, literal suffix, extra comments-  (String, String, String, [Located String])-preprocess path input RegionDeltas {..} =-  go 1 OrmoluEnabled Cpp.Outside id id regionLines+  String ->+  [Either Text RegionDeltas]+preprocess cppEnabled region rawInput = rawSnippetsAndRegionsToFormat   where-    (prefixLines, otherLines) = splitAt regionPrefixLength (lines input)-    (regionLines, suffixLines) =-      let regionLength = length otherLines - regionSuffixLength-       in splitAt regionLength otherLines-    go !n ormoluState cppState inputSoFar csSoFar = \case-      [] ->-        let input' = unlines (inputSoFar [])-         in ( unlines prefixLines,-              case ormoluState of-                OrmoluEnabled -> input'-                OrmoluDisabled -> input' ++ endDisabling,-              unlines suffixLines,-              csSoFar []-            )-      (x : xs) ->-        let (x', ormoluState', cppState', cs) =-              processLine path n ormoluState cppState x-         in go-              (n + 1)-              ormoluState'-              cppState'-              (inputSoFar . (x' :))-              (csSoFar . (maybeToList cs ++))-              xs+    (linesNotToFormat', replacementLines) = linesNotToFormat cppEnabled region rawInput+    regionsToFormat =+      intSetToRegions rawLineLength $+        IntSet.fromAscList [1 .. rawLineLength] IntSet.\\ linesNotToFormat'+    regionsNotToFormat = intSetToRegions rawLineLength linesNotToFormat'+    -- We want to interleave the regionsToFormat and regionsNotToFormat.+    -- If the first non-formattable region starts at the first line, it is+    -- the first interleaved region, otherwise, we start with the first+    -- region to format.+    interleave' = case regionsNotToFormat of+      r : _ | regionPrefixLength r == 0 -> interleave+      _ -> flip interleave+    rawSnippets = T.pack . flip linesInRegion updatedInput <$> regionsNotToFormat+      where+        updatedInput = unlines . fmap updateLine . zip [1 ..] . lines $ rawInput+        updateLine (i, line) = IntMap.findWithDefault line i replacementLines+    rawSnippetsAndRegionsToFormat =+      interleave' (Left <$> rawSnippets) (Right <$> regionsToFormat)+        >>= patchSeparatingBlankLines+        & dropWhile isBlankRawSnippet+        & L.dropWhileEnd isBlankRawSnippet+    -- For every formattable region, we want to ensure that it is separated by+    -- a blank line from preceding/succeeding raw snippets if it starts/ends+    -- with a blank line.+    -- Empty formattable regions are replaced by a blank line instead.+    -- Extraneous raw snippets at the start/end are dropped afterwards.+    patchSeparatingBlankLines = \case+      Right r@RegionDeltas {..} ->+        if all isSpace (linesInRegion r rawInput)+          then [blankRawSnippet]+          else+            [blankRawSnippet | isBlankLine regionPrefixLength] <> [Right r]+              <> [blankRawSnippet | isBlankLine (rawLineLength - regionSuffixLength - 1)]+      Left r -> [Left r]+      where+        blankRawSnippet = Left "\n"+        isBlankLine i = isJust . mfilter (all isSpace) $ rawLines !!? i+    isBlankRawSnippet = \case+      Left r | T.all isSpace r -> True+      _ -> False --- | Transform a given line possibly returning a comment extracted from it.-processLine ::-  -- | File name, just to use in the spans-  FilePath ->-  -- | Line number of this line-  Int ->-  -- | Whether Ormolu is currently enabled-  OrmoluState ->-  -- | CPP state-  Cpp.State ->-  -- | The actual line+    rawLines = lines rawInput+    rawLineLength = length rawLines++    interleave [] bs = bs+    interleave (a : as) bs = a : interleave bs as++    xs !!? i = if i >= 0 && i < length xs then Just $ xs !! i else Nothing++-- | All lines we are not supposed to format, and a set of replacements+-- for specific lines.+linesNotToFormat ::+  -- | Whether CPP is enabled+  Bool ->+  RegionDeltas ->   String ->-  -- | Adjusted line and possibly a comment extracted from it-  (String, OrmoluState, Cpp.State, Maybe (Located String))-processLine path n ormoluState Cpp.Outside line-  | "{-# LINE" `L.isPrefixOf` line =-    let (pragma, res) = getPragma line-        size = length pragma-        ss = mkSrcSpan (mkSrcLoc' 1) (mkSrcLoc' (size + 1))-     in (res, ormoluState, Cpp.Outside, Just (L ss pragma))-  | isOrmoluEnable line =-    case ormoluState of-      OrmoluEnabled ->-        (enableMarker, OrmoluEnabled, Cpp.Outside, Nothing)-      OrmoluDisabled ->-        (endDisabling ++ enableMarker, OrmoluEnabled, Cpp.Outside, Nothing)-  | isOrmoluDisable line =-    case ormoluState of-      OrmoluEnabled ->-        (disableMarker ++ startDisabling, OrmoluDisabled, Cpp.Outside, Nothing)-      OrmoluDisabled ->-        (disableMarker, OrmoluDisabled, Cpp.Outside, Nothing)-  | isShebang line =-    let ss = mkSrcSpan (mkSrcLoc' 1) (mkSrcLoc' (length line))-     in ("", ormoluState, Cpp.Outside, Just (L ss line))-  | otherwise =-    let (line', cppState') = Cpp.processLine line Cpp.Outside-     in (line', ormoluState, cppState', Nothing)+  (IntSet, IntMap String)+linesNotToFormat cppEnabled region@RegionDeltas {..} input =+  (unconsidered <> magicDisabled <> otherDisabled, lineUpdates)   where-    mkSrcLoc' = mkSrcLoc (mkFastString path) n-processLine _ _ ormoluState cppState line =-  let (line', cppState') = Cpp.processLine line cppState-   in (line', ormoluState, cppState', Nothing)+    unconsidered =+      IntSet.fromAscList $+        [1 .. regionPrefixLength] <> [totalLines - regionSuffixLength + 1 .. totalLines]+    totalLines = length (lines input)+    regionLines = linesInRegion region input+    (magicDisabled, lineUpdates) = magicDisabledLines regionLines+    otherDisabled = (mconcat allLines) regionLines+      where+        allLines = [shebangLines, linePragmaLines] <> [cppLines | cppEnabled] --- | Take a line pragma and output its replacement (where line pragma is--- replaced with spaces) and the contents of the pragma itself.-getPragma ::-  -- | Pragma line to analyze-  String ->-  -- | Contents of the pragma and its replacement line-  (String, String)-getPragma [] = error "Ormolu.Preprocess.getPragma: input must not be empty"-getPragma s@(x : xs)-  | "#-}" `L.isPrefixOf` s = ("#-}", "   " ++ drop 3 s)-  | otherwise =-    let (prag, remline) = getPragma xs-     in (x : prag, ' ' : remline)+-- | Ormolu state.+data OrmoluState+  = -- | Enabled+    OrmoluEnabled+  | -- | Disabled+    OrmoluDisabled+  deriving (Eq, Show) --- | Canonical enable marker.-enableMarker :: String-enableMarker = "{- ORMOLU_ENABLE -}"+-- | All lines which are disabled by Ormolu's magic comments,+-- as well as normalizing replacements.+magicDisabledLines :: String -> (IntSet, IntMap String)+magicDisabledLines input =+  bimap IntSet.fromAscList IntMap.fromAscList . mconcat $+    go OrmoluEnabled (lines input `zip` [1 ..])+  where+    go _ [] = []+    go state ((line, i) : ls)+      | Just marker <- disablingMagicComment line,+        state == OrmoluEnabled =+        ([i], [(i, marker)]) : go OrmoluDisabled ls+      | Just marker <- enablingMagicComment line,+        state == OrmoluDisabled =+        ([i], [(i, marker)]) : go OrmoluEnabled ls+      | otherwise = iIfDisabled : go state ls+      where+        iIfDisabled = case state of+          OrmoluDisabled -> ([i], [])+          OrmoluEnabled -> ([], []) --- | Canonical disable marker.-disableMarker :: String-disableMarker = "{- ORMOLU_DISABLE -}"+-- | All lines which satisfy a predicate.+linesFiltered :: (String -> Bool) -> String -> IntSet+linesFiltered p =+  IntSet.fromAscList . fmap snd . filter (p . fst) . (`zip` [1 ..]) . lines --- | Return 'True' if the given string is an enabling marker.-isOrmoluEnable :: String -> Bool-isOrmoluEnable s = magicComment "ORMOLU_ENABLE" s || magicComment "FOURMOLU_ENABLE" s+-- | Lines which contain a shebang.+shebangLines :: String -> IntSet+shebangLines = linesFiltered ("#!" `L.isPrefixOf`) --- | Return 'True' if the given string is a disabling marker.-isOrmoluDisable :: String -> Bool-isOrmoluDisable s = magicComment "ORMOLU_DISABLE" s || magicComment "FOURMOLU_DISABLE" s+-- | Lines which contain a LINE pragma.+linePragmaLines :: String -> IntSet+linePragmaLines = linesFiltered ("{-# LINE" `L.isPrefixOf`) +-- | If the given string is an enabling marker (Ormolu or Fourmolu style), then+-- return 'Just' the enabling marker. Otherwise return 'Nothing'.+enablingMagicComment :: String -> Maybe String+enablingMagicComment s+  | isMagicComment "ORMOLU_ENABLE" s = Just "{- ORMOLU_ENABLE -}"+  | isMagicComment "FOURMOLU_ENABLE" s = Just "{- FOURMOLU_ENABLE -}"+  | otherwise = Nothing++-- | If the given string is a disabling marker (Ormolu or Fourmolu style), then+-- return 'Just' the disabling marker. Otherwise return 'Nothing'.+disablingMagicComment :: String -> Maybe String+disablingMagicComment s+  | isMagicComment "ORMOLU_DISABLE" s = Just "{- ORMOLU_DISABLE -}"+  | isMagicComment "FOURMOLU_DISABLE" s = Just "{- FOURMOLU_DISABLE -}"+  | otherwise = Nothing+ -- | Construct a function for whitespace-insensitive matching of string.-magicComment ::+isMagicComment ::   -- | What to expect   String ->   -- | String to test   String ->   -- | Whether or not the two strings watch   Bool-magicComment expected s0 = isJust $ do+isMagicComment expected s0 = isJust $ do   let trim = dropWhile isSpace   s1 <- trim <$> L.stripPrefix "{-" (trim s0)   s2 <- trim <$> L.stripPrefix expected s1
+ src/Ormolu/Terminal.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | An abstraction for colorful output in terminal.+module Ormolu.Terminal+  ( -- * The 'Term' monad+    Term,+    ColorMode (..),+    runTerm,++    -- * Styling+    bold,+    cyan,+    green,+    red,++    -- * Printing+    put,+    putS,+    putSrcSpan,+    newline,+  )+where++import Control.Monad.Reader+import Data.Text (Text)+import qualified Data.Text.IO as T+import GHC.Types.SrcLoc+import Ormolu.Utils (showOutputable)+import System.Console.ANSI+import System.IO (Handle, hFlush, hPutStr)++----------------------------------------------------------------------------+-- The 'Term' monad++-- | Terminal monad.+newtype Term a = Term (ReaderT RC IO a)+  deriving (Functor, Applicative, Monad)++-- | Reader context of 'Term'.+data RC = RC+  { -- | Whether to use colors+    rcUseColor :: Bool,+    -- | Handle to print to+    rcHandle :: Handle+  }++-- | Whether to use colors and other features of ANSI terminals.+data ColorMode = Never | Always | Auto+  deriving (Eq, Show, Enum, Bounded)++-- | Run 'Term' monad.+runTerm ::+  -- | Monad to run+  Term a ->+  -- | Color mode+  ColorMode ->+  -- | Handle to print to+  Handle ->+  IO a+runTerm (Term m) colorMode rcHandle = do+  rcUseColor <- case colorMode of+    Never -> return False+    Always -> return True+    Auto -> hSupportsANSI rcHandle+  x <- runReaderT m RC {..}+  hFlush rcHandle+  return x++----------------------------------------------------------------------------+-- Styling++-- | Make the inner computation output bold text.+bold :: Term a -> Term a+bold = withSGR [SetConsoleIntensity BoldIntensity]++-- | Make the inner computation output cyan text.+cyan :: Term a -> Term a+cyan = withSGR [SetColor Foreground Dull Cyan]++-- | Make the inner computation output green text.+green :: Term a -> Term a+green = withSGR [SetColor Foreground Dull Green]++-- | Make the inner computation output red text.+red :: Term a -> Term a+red = withSGR [SetColor Foreground Dull Red]++-- | Alter 'SGR' for inner computation.+withSGR :: [SGR] -> Term a -> Term a+withSGR sgrs (Term m) = Term $ do+  RC {..} <- ask+  if rcUseColor+    then do+      liftIO $ hSetSGR rcHandle sgrs+      x <- m+      liftIO $ hSetSGR rcHandle [Reset]+      return x+    else m++----------------------------------------------------------------------------+-- Printing++-- | Output 'Text'.+put :: Text -> Term ()+put txt = Term $ do+  RC {..} <- ask+  liftIO $ T.hPutStr rcHandle txt++-- | Output 'String'.+putS :: String -> Term ()+putS str = Term $ do+  RC {..} <- ask+  liftIO $ hPutStr rcHandle str++-- | Output a 'GHC.SrcSpan'.+putSrcSpan :: SrcSpan -> Term ()+putSrcSpan = putS . showOutputable++-- | Output a newline.+newline :: Term ()+newline = Term $ do+  RC {..} <- ask+  liftIO $ T.hPutStr rcHandle "\n"
src/Ormolu/Utils.hs view
@@ -10,27 +10,25 @@     notImplemented,     showOutputable,     splitDocString,-    typeArgToType,     unSrcSpan,     incSpanLine,     separatedByBlank,     separatedByBlankNE,     onTheSameLine,-    removeIndentation,     groupBy',   ) where -import Data.Char (isSpace) import Data.List (dropWhileEnd)-import Data.List.NonEmpty (NonEmpty (..), nonEmpty)+import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as T-import GHC import GHC.DynFlags (baseDynFlags)-import qualified Outputable as GHC+import GHC.Hs+import GHC.Types.SrcLoc+import qualified GHC.Utils.Outputable as GHC  -- | Relative positions in a list. data RelativePos@@ -86,23 +84,16 @@         _ -> txt     escapeCommentBraces = T.replace "{-" "{\\-" . T.replace "-}" "-\\}" --- | Get 'LHsType' out of 'LHsTypeArg'.-typeArgToType :: LHsTypeArg p -> LHsType p-typeArgToType = \case-  HsValArg tm -> tm-  HsTypeArg _ ty -> ty-  HsArgPar _ -> notImplemented "HsArgPar"- -- | Get 'RealSrcSpan' out of 'SrcSpan' if the span is “helpful”. unSrcSpan :: SrcSpan -> Maybe RealSrcSpan unSrcSpan = \case-  RealSrcSpan r -> Just r+  RealSrcSpan r _ -> Just r   UnhelpfulSpan _ -> Nothing  -- | Increment line number in a 'SrcSpan'. incSpanLine :: Int -> SrcSpan -> SrcSpan incSpanLine i = \case-  RealSrcSpan s ->+  RealSrcSpan s _ ->     let start = realSrcSpanStart s         end = realSrcSpanEnd s         incLine x =@@ -110,7 +101,7 @@               line = srcLocLine x               col = srcLocCol x            in mkRealSrcLoc file (line + i) col-     in RealSrcSpan (mkRealSrcSpan (incLine start) (incLine end))+     in RealSrcSpan (mkRealSrcSpan (incLine start) (incLine end)) Nothing   UnhelpfulSpan x -> UnhelpfulSpan x  -- | Do two declarations have a blank between them?@@ -129,19 +120,6 @@ onTheSameLine :: SrcSpan -> SrcSpan -> Bool onTheSameLine a b =   isOneLineSpan (mkSrcSpan (srcSpanEnd a) (srcSpanStart b))---- | Remove indentation from a given 'String'. Return the input with--- indentation removed and the detected indentation level.-removeIndentation :: String -> (String, Int)-removeIndentation (lines -> xs) = (unlines (drop n <$> xs), n)-  where-    n = case nonEmpty xs of-      Nothing -> 0-      Just l -> minimum (getIndent <$> l)-    getIndent y =-      if all isSpace y-        then 0-        else length (takeWhile isSpace y)  -- | A generalisation of 'groupBy' to functions which aren't equivalences - a group ends -- when comparison fails with the previous element, rather than the first of the group.
+ src/Ormolu/Utils/Extensions.hs view
@@ -0,0 +1,145 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}++module Ormolu.Utils.Extensions+  ( Extension (..),+    getExtensionsFromCabalFile,+    findCabalFile,+    getCabalExtensionDynOptions,+  )+where++import Control.Exception+import Control.Monad.IO.Class+import qualified Data.ByteString as B+import Data.Map.Lazy (Map)+import qualified Data.Map.Lazy as M+import Data.Maybe (maybeToList)+import qualified Distribution.ModuleName as ModuleName+import Distribution.PackageDescription+import Distribution.PackageDescription.Parsec+import qualified Distribution.Types.CondTree as CT+import Language.Haskell.Extension+import Ormolu.Config+import Ormolu.Exception+import System.Directory+import System.FilePath+import System.IO (hPutStrLn, stderr)+import System.IO.Error (isDoesNotExistError)++-- | Get a map from Haskell source file paths (without any extensions)+-- to its default language extensions+getExtensionsFromCabalFile ::+  MonadIO m =>+  -- | Path to cabal file+  FilePath ->+  m (Map FilePath [DynOption])+getExtensionsFromCabalFile cabalFile = liftIO $ do+  GenericPackageDescription {..} <-+    parseGenericPackageDescriptionMaybe <$> B.readFile cabalFile >>= \case+      Just gpd -> pure gpd+      Nothing -> throwIO $ OrmoluCabalFileParsingFailed cabalFile+  let lib = maybeToList condLibrary+      sublibs = snd <$> condSubLibraries+  pure . M.unions . concat $+    [ buildMap extractFromLibrary <$> lib ++ sublibs,+      buildMap extractFromExecutable . snd <$> condExecutables,+      buildMap extractFromTestSuite . snd <$> condTestSuites,+      buildMap extractFromBenchmark . snd <$> condBenchmarks+    ]+  where+    buildMap f a = let (files, exts) = f mergedA in M.fromList $ (,exts) <$> files+      where+        (mergedA, _) = CT.ignoreConditions a++    extractFromBuildInfo extraModules BuildInfo {..} = (,exts) $ do+      m <- extraModules ++ (ModuleName.toFilePath <$> otherModules)+      (takeDirectory cabalFile </>) <$> prependSrcDirs (dropExtensions m)+      where+        prependSrcDirs f+          | null hsSourceDirs = [f]+          | otherwise = (</> f) <$> hsSourceDirs+        exts = maybe [] langExt defaultLanguage ++ fmap extToDynOption defaultExtensions+        langExt =+          pure . DynOption . \case+            Haskell98 -> "-XHaskell98"+            Haskell2010 -> "-XHaskell2010"+            UnknownLanguage lan -> "-X" ++ lan+        extToDynOption =+          DynOption . \case+            EnableExtension e -> "-X" ++ show e+            DisableExtension e -> "-XNo" ++ show e+            UnknownExtension e -> "-X" ++ e++    extractFromLibrary Library {..} =+      extractFromBuildInfo (ModuleName.toFilePath <$> exposedModules) libBuildInfo+    extractFromExecutable Executable {..} =+      extractFromBuildInfo [modulePath] buildInfo+    extractFromTestSuite TestSuite {..} =+      extractFromBuildInfo mainPath testBuildInfo+      where+        mainPath = case testInterface of+          TestSuiteExeV10 _ p -> [p]+          TestSuiteLibV09 _ p -> [ModuleName.toFilePath p]+          TestSuiteUnsupported {} -> []+    extractFromBenchmark Benchmark {..} =+      extractFromBuildInfo mainPath benchmarkBuildInfo+      where+        mainPath = case benchmarkInterface of+          BenchmarkExeV10 _ p -> [p]+          BenchmarkUnsupported {} -> []++-- | Find the path to an appropriate .cabal file for a Haskell+-- source file, if available+findCabalFile ::+  MonadIO m =>+  -- | Absolute path to a Haskell source file in a project with a .cabal file+  FilePath ->+  m (Maybe FilePath)+findCabalFile p = liftIO $ do+  let parentDir = takeDirectory p+  dirEntries <-+    listDirectory parentDir `catch` \case+      (isDoesNotExistError -> True) -> pure []+      e -> throwIO e+  let findDotCabal = \case+        [] -> pure Nothing+        e : es+          | takeExtension e == ".cabal" ->+            doesFileExist (parentDir </> e) >>= \case+              True -> pure $ Just e+              False -> findDotCabal es+        _ : es -> findDotCabal es+  findDotCabal dirEntries >>= \case+    Just cabalFile -> pure . Just $ parentDir </> cabalFile+    Nothing ->+      if isDrive parentDir+        then pure Nothing+        else findCabalFile parentDir++-- | Get the default language extensions of a Haskell source file.+-- The .cabal file can be provided explicitly or auto-detected.+getCabalExtensionDynOptions ::+  MonadIO m =>+  -- | Haskell source file+  FilePath ->+  m [DynOption]+getCabalExtensionDynOptions sourceFile' = liftIO $ do+  sourceFile <- makeAbsolute sourceFile'+  findCabalFile sourceFile >>= \case+    Just cabalFile -> do+      extsByFile <- getExtensionsFromCabalFile cabalFile+      case M.lookup (dropExtensions sourceFile) extsByFile of+        Just exts -> pure exts+        Nothing -> do+          relativeCabalFile <- makeRelativeToCurrentDirectory cabalFile+          note $+            "Found .cabal file "+              <> relativeCabalFile+              <> ", but it did not mention "+              <> sourceFile'+    Nothing -> note $ "Could not find a .cabal file for " <> sourceFile'+  where+    note msg = [] <$ hPutStrLn stderr msg
+ src/Ormolu/Utils/IO.hs view
@@ -0,0 +1,23 @@+-- | Write 'Text' to files using UTF8 and ignoring native+-- line ending conventions.+module Ormolu.Utils.IO+  ( writeFileUtf8,+    readFileUtf8,+  )+where++import Control.Exception (throwIO)+import Control.Monad.IO.Class+import qualified Data.ByteString as B+import Data.Text (Text)+import qualified Data.Text.Encoding as TE++-- | Write a 'Text' to a file using UTF8 and ignoring native+-- line ending conventions.+writeFileUtf8 :: MonadIO m => FilePath -> Text -> m ()+writeFileUtf8 p = liftIO . B.writeFile p . TE.encodeUtf8++-- | Read an entire file strictly into a 'Text' using UTF8 and+-- ignoring native line ending conventions.+readFileUtf8 :: MonadIO m => FilePath -> m Text+readFileUtf8 p = liftIO $ either throwIO pure . TE.decodeUtf8' =<< B.readFile p
+ tests/Ormolu/CabalExtensionsSpec.hs view
@@ -0,0 +1,35 @@+module Ormolu.CabalExtensionsSpec (spec) where++import qualified Data.Map as M+import Ormolu.Config+import Ormolu.Utils.Extensions+import System.Directory+import System.FilePath+import System.IO.Temp (withSystemTempDirectory)+import Test.Hspec++spec :: Spec+spec = describe "Handle extensions from .cabal files" $ do+  it "extract extensions from .cabal files" $ do+    extsByFile <- getExtensionsFromCabalFile "fourmolu.cabal"+    extsByFile `shouldNotSatisfy` M.null+    M.elems extsByFile `shouldSatisfy` all (== [DynOption "-XHaskell2010"])+    extsByFile+      `shouldSatisfy` members+        [ "./src/Ormolu",+          "./app/Main",+          "./tests/Spec"+        ]+  it "find the .cabal file" $ do+    let findsOrmoluCabal start expectedCabalFile = do+          cabalFile <- findCabalFile start+          cabalFile `shouldBe` Just expectedCabalFile+    findsOrmoluCabal "src/Ormolu/Config.hs" "./fourmolu.cabal"+    findsOrmoluCabal "a/b/c/d/e" "./fourmolu.cabal"+  it "do not consider directories as .cabal files" $+    withSystemTempDirectory "" $ \dir -> do+      createDirectory $ dir </> ".cabal"+      cabalFile <- findCabalFile $ dir </> "foo/bar.hs"+      cabalFile `shouldBe` Nothing+  where+    members as m = all (`M.member` m) as
+ tests/Ormolu/Diff/TextSpec.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE TemplateHaskell #-}++module Ormolu.Diff.TextSpec (spec) where++import Data.Text (Text)+import Ormolu.Diff.Text+import Ormolu.Terminal+import Ormolu.Utils.IO+import Path+import Path.IO+import qualified System.FilePath as FP+import System.IO (hClose)+import Test.Hspec++spec :: Spec+spec =+  describe "printTextDiff" $ do+    stdTest "one-line-added" "empty" "one-line"+    stdTest "one-line-removed" "one-line" "empty"+    stdTest "no-preceding" "main-foo" "main"+    stdTest "no-following" "main" "main-v2"+    stdTest "simple-hunk" "main-and-foo" "main-and-foo-v2"+    stdTest "joined-hunk" "main-and-bar" "main-and-bar-v2"+    stdTest "two-hunks" "main-and-baz" "main-and-baz-v2"+    stdTest "trimming" "spaced" "spaced-v2"+    stdTest "trailing-blank-line" "no-trailing-blank-line" "with-trailing-blank-line"++-- | Test diff printig.+stdTest ::+  -- | Name of the test case+  String ->+  -- | Location of input A+  FilePath ->+  -- | Location of input B+  FilePath ->+  Spec+stdTest name pathA pathB = it name $ do+  inputA <-+    parseRelFile (FP.addExtension pathA "hs")+      >>= readFileUtf8 . toFilePath . (diffInputsDir </>)+  inputB <-+    parseRelFile (FP.addExtension pathB "hs")+      >>= readFileUtf8 . toFilePath . (diffInputsDir </>)+  let expectedDiffPath = FP.addExtension name "txt"+  expectedDiffText <-+    parseRelFile expectedDiffPath+      >>= readFileUtf8 . toFilePath . (diffOutputsDir </>)+  let Just actualDiff = diffText inputA inputB "TEST"+  actualDiffText <- printDiff actualDiff+  actualDiffText `shouldBe` expectedDiffText++-- | Print to a 'Text' value.+printDiff :: TextDiff -> IO Text+printDiff diff =+  withSystemTempFile "ormolu-diff-test" $ \path h -> do+    runTerm (printTextDiff diff) Never h+    hClose h+    readFileUtf8 (toFilePath path)++diffTestsDir :: Path Rel Dir+diffTestsDir = $(mkRelDir "data/diff-tests")++diffInputsDir :: Path Rel Dir+diffInputsDir = diffTestsDir </> $(mkRelDir "inputs")++diffOutputsDir :: Path Rel Dir+diffOutputsDir = diffTestsDir </> $(mkRelDir "outputs")
+ tests/Ormolu/Parser/OptionsSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE LambdaCase #-}++module Ormolu.Parser.OptionsSpec (spec) where++import qualified Data.Text as T+import Ormolu+import Test.Hspec++spec :: Spec+spec = describe "GHC options in source files take priority" $ do+  it "default extensions can be disabled locally" $ do+    let src =+          unlines+            [ "{-# LANGUAGE NoBlockArguments #-}",+              "",+              "test = test do test"+            ]+    fixedPoint [] src `shouldThrow` \case+      OrmoluParsingFailed {} -> True+      _ -> False+  it "extensions disabled via CLI can be enabled locally" $ do+    let src =+          unlines+            [ "{-# LANGUAGE BlockArguments #-}",+              "",+              "test = test do test"+            ]+    fixedPoint ["-XNoBlockArguments"] src+  where+    fixedPoint opts input = do+      output <- ormolu defaultConfig {cfgDynOptions = DynOption <$> opts} "<input>" input+      T.unpack output `shouldBe` input
+ tests/Ormolu/Parser/ParseFailureSpec.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE LambdaCase #-}++module Ormolu.Parser.ParseFailureSpec (spec) where++import Ormolu+import Ormolu.Utils (showOutputable)+import System.FilePath+import Test.Hspec++spec :: Spec+spec = do+  "disabling-preserves-error-location.hs" `failsAt` "12:1"+  "line-pragma.hs" `failsAt` "4:47"++failsAt :: String -> String -> Spec+failsAt filename location =+  let filePath = baseDir </> filename+   in it (filename ++ " fails at " ++ location) $+        ormoluFile defaultConfig filePath+          `shouldThrow` \case+            OrmoluParsingFailed srcSpan _ ->+              showOutputable srcSpan == filePath ++ ":" ++ location+            _ -> False++baseDir :: FilePath+baseDir = "data" </> "parse-failures"
tests/Ormolu/PrinterSpec.hs view
@@ -4,13 +4,12 @@  import Control.Exception import Control.Monad-import Control.Monad.IO.Class import Data.List (isSuffixOf) import Data.Text (Text) import qualified Data.Text as T-import qualified Data.Text.IO as T import Ormolu import Ormolu.Config+import Ormolu.Utils.IO import Path import Path.IO import qualified System.FilePath as F@@ -30,11 +29,11 @@             poHaddockStyle = pure HaddockSingleLine,             poNewlinesBetweenDecls = pure 1           }-  sequence_ $ uncurry checkExample <$> [(ormoluOpts, ""), (defaultPrinterOpts, "-four")] <*> es+  sequence_ $ checkExample <$> [(ormoluOpts, "ormolu", ""), (defaultPrinterOpts, "fourmolu", "-four")] <*> es  -- | Check a single given example.-checkExample :: PrinterOptsTotal -> String -> Path Rel File -> Spec-checkExample po suffix srcPath' = it (fromRelFile srcPath' ++ " works") . withNiceExceptions $ do+checkExample :: (PrinterOptsTotal, String, String) -> Path Rel File -> Spec+checkExample (po, label, suffix) srcPath' = it (fromRelFile srcPath' ++ " works (" ++ label ++ ")") . withNiceExceptions $ do   let srcPath = examplesDir </> srcPath'       cfg = defaultConfig {cfgPrinterOpts = po}   expectedOutputPath <- deriveOutput suffix srcPath@@ -45,8 +44,9 @@   formatted0 <- ormoluFile cfg (fromRelFile srcPath)   -- 3. Check the output against expected output. Thus all tests should   -- include two files: input and expected output.-  -- T.writeFile (fromRelFile expectedOutputPath) formatted0-  expected <- (liftIO . T.readFile . fromRelFile) expectedOutputPath+  -- <<< UNCOMMENT NEXT LINE TO REGENERATE OUTPUT FILES >>>+  -- writeFile (fromRelFile expectedOutputPath) (T.unpack formatted0)+  expected <- readFileUtf8 $ fromRelFile expectedOutputPath   shouldMatch False formatted0 expected   -- 4. Check that running the formatter on the output produces the same   -- output again (the transformation is idempotent).