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 +159/−0
- README.md +72/−17
- app/Main.hs +138/−62
- data/diff-tests/inputs/empty.hs +0/−0
- data/diff-tests/inputs/main-and-bar-v2.hs +11/−0
- data/diff-tests/inputs/main-and-bar.hs +11/−0
- data/diff-tests/inputs/main-and-baz-v2.hs +12/−0
- data/diff-tests/inputs/main-and-baz.hs +12/−0
- data/diff-tests/inputs/main-and-foo-v2.hs +7/−0
- data/diff-tests/inputs/main-and-foo.hs +7/−0
- data/diff-tests/inputs/main-foo.hs +4/−0
- data/diff-tests/inputs/main-v2.hs +4/−0
- data/diff-tests/inputs/main.hs +4/−0
- data/diff-tests/inputs/no-trailing-blank-line.hs +1/−0
- data/diff-tests/inputs/one-line.hs +1/−0
- data/diff-tests/inputs/spaced-v2.hs +16/−0
- data/diff-tests/inputs/spaced.hs +16/−0
- data/diff-tests/inputs/with-trailing-blank-line.hs +1/−0
- data/diff-tests/outputs/joined-hunk.txt +15/−0
- data/diff-tests/outputs/no-following.txt +7/−0
- data/diff-tests/outputs/no-preceding.txt +6/−0
- data/diff-tests/outputs/one-line-added.txt +3/−0
- data/diff-tests/outputs/one-line-removed.txt +3/−0
- data/diff-tests/outputs/simple-hunk.txt +9/−0
- data/diff-tests/outputs/trailing-blank-line.txt +4/−0
- data/diff-tests/outputs/trimming.txt +5/−0
- data/diff-tests/outputs/two-hunks.txt +16/−0
- data/examples/declaration/class/newlines-and-haddocks-four-out.hs +4/−0
- data/examples/declaration/class/newlines-and-haddocks-out.hs +4/−0
- data/examples/declaration/class/newlines-and-haddocks.hs +4/−0
- data/examples/declaration/data/ctype-four-out.hs +1/−0
- data/examples/declaration/data/ctype-out.hs +1/−0
- data/examples/declaration/data/ctype.hs +1/−0
- data/examples/declaration/data/field-layout/gadt-four-out.hs +11/−0
- data/examples/declaration/data/field-layout/gadt-out.hs +11/−0
- data/examples/declaration/data/field-layout/gadt.hs +10/−0
- data/examples/declaration/data/field-layout/record-four-out.hs +12/−0
- data/examples/declaration/data/field-layout/record-out.hs +12/−0
- data/examples/declaration/data/field-layout/record.hs +11/−0
- data/examples/declaration/data/field-layout/variants-four-out.hs +10/−0
- data/examples/declaration/data/field-layout/variants-out.hs +10/−0
- data/examples/declaration/data/field-layout/variants.hs +10/−0
- data/examples/declaration/data/gadt/multiline-where-four-out.hs +23/−0
- data/examples/declaration/data/gadt/multiline-where-out.hs +23/−0
- data/examples/declaration/data/gadt/multiline-where.hs +17/−0
- data/examples/declaration/instance/newlines-between-methods-four-out.hs +1/−1
- data/examples/declaration/instance/newlines-between-methods-out.hs +1/−1
- data/examples/declaration/signature/standalone-kind-four-out.hs +16/−0
- data/examples/declaration/signature/standalone-kind-out.hs +16/−0
- data/examples/declaration/signature/standalone-kind.hs +17/−0
- data/examples/declaration/splice/bracket-declaration-four-out.hs +9/−0
- data/examples/declaration/splice/bracket-declaration-out.hs +9/−0
- data/examples/declaration/splice/bracket-declaration.hs +8/−0
- data/examples/declaration/splice/bracket-four-out.hs +4/−0
- data/examples/declaration/splice/bracket-out.hs +4/−0
- data/examples/declaration/splice/bracket.hs +4/−0
- data/examples/declaration/splice/grouped-splices-four-out.hs +2/−0
- data/examples/declaration/splice/grouped-splices-out.hs +2/−0
- data/examples/declaration/splice/grouped-splices.hs +2/−0
- data/examples/declaration/splice/quasiquote-four-out.hs +4/−0
- data/examples/declaration/splice/quasiquote-out.hs +4/−0
- data/examples/declaration/splice/quasiquote.hs +3/−0
- data/examples/declaration/type-families/closed-type-family/type-arguments-four-out.hs +4/−0
- data/examples/declaration/type-families/closed-type-family/type-arguments-out.hs +4/−0
- data/examples/declaration/type-families/closed-type-family/type-arguments.hs +4/−0
- data/examples/declaration/type-families/data-family/type-arguments-four-out.hs +5/−0
- data/examples/declaration/type-families/data-family/type-arguments-out.hs +5/−0
- data/examples/declaration/type-families/data-family/type-arguments.hs +5/−0
- data/examples/declaration/type/misc-kind-signatures-four-out.hs +5/−0
- data/examples/declaration/type/misc-kind-signatures-out.hs +6/−0
- data/examples/declaration/type/misc-kind-signatures.hs +5/−0
- data/examples/declaration/type/promotion-0-four-out.hs +9/−0
- data/examples/declaration/type/promotion-0-out.hs +9/−0
- data/examples/declaration/type/promotion-0.hs +9/−0
- data/examples/declaration/type/promotion-1-four-out.hs +9/−0
- data/examples/declaration/type/promotion-1-out.hs +15/−0
- data/examples/declaration/type/promotion-1.hs +9/−0
- data/examples/declaration/type/promotion-four-out.hs +0/−16
- data/examples/declaration/type/promotion-out.hs +0/−21
- data/examples/declaration/type/promotion.hs +0/−16
- data/examples/declaration/value/function/application-1-four-out.hs +7/−7
- data/examples/declaration/value/function/application-1-out.hs +7/−7
- data/examples/declaration/value/function/application-2-four-out.hs +38/−0
- data/examples/declaration/value/function/application-2-out.hs +38/−0
- data/examples/declaration/value/function/application-2.hs +36/−0
- data/examples/declaration/value/function/arrow/proc-applications-four-out.hs +4/−0
- data/examples/declaration/value/function/arrow/proc-applications-out.hs +4/−0
- data/examples/declaration/value/function/arrow/proc-applications.hs +4/−0
- data/examples/declaration/value/function/arrow/proc-applications2-four-out.hs +11/−0
- data/examples/declaration/value/function/arrow/proc-applications2-out.hs +11/−0
- data/examples/declaration/value/function/arrow/proc-applications2.hs +11/−0
- data/examples/declaration/value/function/arrow/proc-cases-four-out.hs +5/−0
- data/examples/declaration/value/function/arrow/proc-cases-out.hs +5/−0
- data/examples/declaration/value/function/arrow/proc-cases.hs +5/−0
- data/examples/declaration/value/function/arrow/proc-do-complex-four-out.hs +3/−0
- data/examples/declaration/value/function/arrow/proc-do-complex-out.hs +3/−0
- data/examples/declaration/value/function/arrow/proc-do-complex.hs +3/−0
- data/examples/declaration/value/function/arrow/proc-do-simple1-four-out.hs +1/−2
- data/examples/declaration/value/function/arrow/proc-do-simple1-out.hs +1/−2
- data/examples/declaration/value/function/arrow/proc-do-simple2-four-out.hs +3/−2
- data/examples/declaration/value/function/arrow/proc-do-simple2-out.hs +3/−2
- data/examples/declaration/value/function/arrow/proc-do-simple2.hs +2/−0
- data/examples/declaration/value/function/arrow/proc-form-do-indent-four-out.hs +13/−0
- data/examples/declaration/value/function/arrow/proc-form-do-indent-out.hs +13/−0
- data/examples/declaration/value/function/arrow/proc-form-do-indent.hs +13/−0
- data/examples/declaration/value/function/arrow/proc-forms2-four-out.hs +29/−5
- data/examples/declaration/value/function/arrow/proc-forms2-out.hs +29/−5
- data/examples/declaration/value/function/arrow/proc-forms2.hs +22/−0
- data/examples/declaration/value/function/block-arguments-four-out.hs +2/−0
- data/examples/declaration/value/function/block-arguments-out.hs +2/−0
- data/examples/declaration/value/function/block-arguments.hs +2/−0
- data/examples/declaration/value/function/case-empty-four-out.hs +6/−0
- data/examples/declaration/value/function/case-empty-out.hs +6/−0
- data/examples/declaration/value/function/case-empty.hs +6/−0
- data/examples/declaration/value/function/comprehension/transform-monad-four-out.hs +18/−0
- data/examples/declaration/value/function/comprehension/transform-monad-out.hs +18/−0
- data/examples/declaration/value/function/comprehension/transform-monad.hs +16/−0
- data/examples/declaration/value/function/lambda-single-line-four-out.hs +1/−0
- data/examples/declaration/value/function/lambda-single-line-out.hs +1/−0
- data/examples/declaration/value/function/lambda-single-line.hs +1/−0
- data/examples/declaration/value/function/lexical-negation-four-out.hs +8/−0
- data/examples/declaration/value/function/lexical-negation-out.hs +8/−0
- data/examples/declaration/value/function/lexical-negation.hs +8/−0
- data/examples/declaration/value/function/negation-four-out.hs +13/−1
- data/examples/declaration/value/function/negation-out.hs +13/−1
- data/examples/declaration/value/function/negation.hs +12/−0
- data/examples/declaration/value/function/negative-literals-four-out.hs +13/−0
- data/examples/declaration/value/function/negative-literals-out.hs +13/−0
- data/examples/declaration/value/function/negative-literals.hs +13/−0
- data/examples/declaration/value/function/operators-7-four-out.hs +1/−0
- data/examples/declaration/value/function/operators-7-out.hs +1/−0
- data/examples/declaration/value/function/operators-7.hs +1/−0
- data/examples/declaration/value/function/pattern/as-pattern.hs +1/−1
- data/examples/declaration/value/function/pragmas-four-out.hs +4/−2
- data/examples/declaration/value/function/pragmas-out.hs +4/−2
- data/examples/declaration/value/function/pragmas.hs +2/−0
- data/examples/declaration/value/function/record/constructors-four-out.hs +27/−0
- data/examples/declaration/value/function/record/constructors-out.hs +31/−0
- data/examples/declaration/value/function/record/constructors.hs +22/−0
- data/examples/declaration/value/function/record/dot-multiline-four-out.hs +15/−0
- data/examples/declaration/value/function/record/dot-multiline-out.hs +15/−0
- data/examples/declaration/value/function/record/dot-multiline.hs +10/−0
- data/examples/declaration/value/function/record/dot-singleline-four-out.hs +15/−0
- data/examples/declaration/value/function/record/dot-singleline-out.hs +15/−0
- data/examples/declaration/value/function/record/dot-singleline.hs +14/−0
- data/examples/declaration/value/function/record/hanging-after-equal-con-four-out.hs +8/−0
- data/examples/declaration/value/function/record/hanging-after-equal-con-out.hs +8/−0
- data/examples/declaration/value/function/record/hanging-after-equal-con.hs +7/−0
- data/examples/declaration/value/function/record/hanging-after-equal-update-four-out.hs +8/−0
- data/examples/declaration/value/function/record/hanging-after-equal-update-out.hs +8/−0
- data/examples/declaration/value/function/record/hanging-after-equal-update.hs +7/−0
- data/examples/declaration/value/function/record/inter-comments-four-out.hs +13/−0
- data/examples/declaration/value/function/record/inter-comments-out.hs +13/−0
- data/examples/declaration/value/function/record/inter-comments.hs +11/−0
- data/examples/declaration/value/function/record/updaters-four-out.hs +8/−0
- data/examples/declaration/value/function/record/updaters-out.hs +11/−0
- data/examples/declaration/value/function/record/updaters.hs +7/−0
- data/examples/declaration/value/function/record/wildcards-four-out.hs +14/−0
- data/examples/declaration/value/function/record/wildcards-out.hs +14/−0
- data/examples/declaration/value/function/record/wildcards.hs +13/−0
- data/examples/module-header/multiline-with-comments-four-out.hs +3/−0
- data/examples/module-header/multiline-with-comments-out.hs +3/−0
- data/examples/module-header/multiline-with-comments.hs +3/−0
- data/examples/other/cpp/continuation-four-out.hs +10/−0
- data/examples/other/cpp/continuation-out.hs +10/−0
- data/examples/other/cpp/continuation.hs +10/−0
- data/examples/other/cpp/lonely-hash-four-out.hs +16/−0
- data/examples/other/cpp/lonely-hash-out.hs +16/−0
- data/examples/other/cpp/lonely-hash.hs +16/−0
- data/examples/other/cpp/separation-0a-four-out.hs +8/−0
- data/examples/other/cpp/separation-0a-out.hs +8/−0
- data/examples/other/cpp/separation-0a.hs +8/−0
- data/examples/other/cpp/separation-0b-four-out.hs +11/−0
- data/examples/other/cpp/separation-0b-out.hs +11/−0
- data/examples/other/cpp/separation-0b.hs +11/−0
- data/examples/other/cpp/separation-1a-four-out.hs +13/−0
- data/examples/other/cpp/separation-1a-out.hs +13/−0
- data/examples/other/cpp/separation-1a.hs +13/−0
- data/examples/other/cpp/separation-1b-four-out.hs +16/−0
- data/examples/other/cpp/separation-1b-out.hs +16/−0
- data/examples/other/cpp/separation-1b.hs +16/−0
- data/examples/other/cpp/separation-2a-four-out.hs +10/−0
- data/examples/other/cpp/separation-2a-out.hs +10/−0
- data/examples/other/cpp/separation-2a.hs +10/−0
- data/examples/other/cpp/separation-2b-four-out.hs +13/−0
- data/examples/other/cpp/separation-2b-out.hs +13/−0
- data/examples/other/cpp/separation-2b.hs +13/−0
- data/examples/other/cpp/shifted-four-out.hs +23/−0
- data/examples/other/cpp/shifted-out.hs +23/−0
- data/examples/other/cpp/shifted.hs +19/−0
- data/examples/other/cpp/simple-import-four-out.hs +16/−0
- data/examples/other/cpp/simple-import-out.hs +16/−0
- data/examples/other/cpp/simple-import.hs +16/−0
- data/examples/other/disabling/closing-comment-in-disabled-region-four-out.hs +3/−0
- data/examples/other/disabling/closing-comment-in-disabled-region-out.hs +3/−0
- data/examples/other/disabling/closing-comment-in-disabled-region.hs +3/−0
- data/examples/other/disabling/empty-disabled-region-four-out.hs +7/−0
- data/examples/other/disabling/empty-disabled-region-out.hs +7/−0
- data/examples/other/disabling/empty-disabled-region.hs +7/−0
- data/examples/other/disabling/line-pragma-in-disabled-region-four-out.hs +7/−0
- data/examples/other/disabling/line-pragma-in-disabled-region-out.hs +7/−0
- data/examples/other/disabling/line-pragma-in-disabled-region.hs +7/−0
- data/examples/other/disabling/mixed-styles-four-out.hs +17/−0
- data/examples/other/disabling/mixed-styles-out.hs +17/−0
- data/examples/other/disabling/mixed-styles.hs +17/−0
- data/examples/other/disabling/normalize-magic-comments-four-out.hs +8/−0
- data/examples/other/disabling/normalize-magic-comments-out.hs +8/−0
- data/examples/other/disabling/normalize-magic-comments.hs +8/−0
- data/examples/other/disabling/preserve-empty-lines-four-out.hs +11/−0
- data/examples/other/disabling/preserve-empty-lines-out.hs +11/−0
- data/examples/other/disabling/preserve-empty-lines.hs +12/−0
- data/examples/other/disabling/preserve-trailing-whitespace-four-out.hs +5/−0
- data/examples/other/disabling/preserve-trailing-whitespace-out.hs +5/−0
- data/examples/other/disabling/preserve-trailing-whitespace.hs +5/−0
- data/examples/other/disabling/single-definition-four-out.hs +10/−0
- data/examples/other/disabling/single-definition-out.hs +10/−0
- data/examples/other/disabling/single-definition.hs +10/−0
- data/examples/other/disabling/whole-file-four-out.hs +10/−0
- data/examples/other/disabling/whole-file-out.hs +10/−0
- data/examples/other/disabling/whole-file.hs +10/−0
- data/examples/other/haddock-without-module-header-four-out.hs +5/−0
- data/examples/other/haddock-without-module-header-out.hs +5/−0
- data/examples/other/haddock-without-module-header.hs +5/−0
- data/examples/other/linear-arrows-four-out.hs +22/−0
- data/examples/other/linear-arrows-out.hs +23/−0
- data/examples/other/linear-arrows.hs +20/−0
- data/examples/other/no-linear-arrows-four-out.hs +4/−0
- data/examples/other/no-linear-arrows-out.hs +5/−0
- data/examples/other/no-linear-arrows.hs +4/−0
- data/parse-failures/disabling-preserves-error-location.hs +11/−0
- data/parse-failures/line-pragma.hs +5/−0
- fourmolu.cabal +50/−70
- src/GHC.hs +0/−12
- src/GHC/DynFlags.hs +12/−5
- src/Ormolu.hs +22/−15
- src/Ormolu/Config.hs +6/−1
- src/Ormolu/Diff.hs +0/−158
- src/Ormolu/Diff/ParseResult.hs +149/−0
- src/Ormolu/Diff/Text.hs +286/−0
- src/Ormolu/Exception.hs +84/−62
- src/Ormolu/Imports.hs +8/−10
- src/Ormolu/Parser.hs +51/−34
- src/Ormolu/Parser/Anns.hs +11/−15
- src/Ormolu/Parser/CommentStream.hs +15/−32
- src/Ormolu/Parser/Pragma.hs +7/−7
- src/Ormolu/Parser/Result.hs +12/−23
- src/Ormolu/Parser/Shebang.hs +0/−27
- src/Ormolu/Printer.hs +22/−19
- src/Ormolu/Printer/Combinators.hs +36/−6
- src/Ormolu/Printer/Comments.hs +1/−1
- src/Ormolu/Printer/Internal.hs +48/−18
- src/Ormolu/Printer/Meat/Common.hs +23/−11
- src/Ormolu/Printer/Meat/Declaration.hs +17/−22
- src/Ormolu/Printer/Meat/Declaration.hs-boot +2/−1
- src/Ormolu/Printer/Meat/Declaration/Annotation.hs +4/−4
- src/Ormolu/Printer/Meat/Declaration/Class.hs +11/−5
- src/Ormolu/Printer/Meat/Declaration/Data.hs +67/−54
- src/Ormolu/Printer/Meat/Declaration/Default.hs +7/−8
- src/Ormolu/Printer/Meat/Declaration/Foreign.hs +5/−10
- src/Ormolu/Printer/Meat/Declaration/Instance.hs +46/−56
- src/Ormolu/Printer/Meat/Declaration/RoleAnnotation.hs +6/−5
- src/Ormolu/Printer/Meat/Declaration/Rule.hs +31/−33
- src/Ormolu/Printer/Meat/Declaration/Signature.hs +11/−10
- src/Ormolu/Printer/Meat/Declaration/Splice.hs +2/−2
- src/Ormolu/Printer/Meat/Declaration/Type.hs +5/−2
- src/Ormolu/Printer/Meat/Declaration/TypeFamily.hs +18/−24
- src/Ormolu/Printer/Meat/Declaration/Value.hs +227/−160
- src/Ormolu/Printer/Meat/Declaration/Value.hs-boot +4/−1
- src/Ormolu/Printer/Meat/Declaration/Warning.hs +5/−4
- src/Ormolu/Printer/Meat/ImportExport.hs +10/−7
- src/Ormolu/Printer/Meat/Module.hs +5/−14
- src/Ormolu/Printer/Meat/Pragma.hs +1/−1
- src/Ormolu/Printer/Meat/Type.hs +66/−24
- src/Ormolu/Printer/Operators.hs +4/−2
- src/Ormolu/Printer/SpanStream.hs +2/−2
- src/Ormolu/Processing/Common.hs +62/−17
- src/Ormolu/Processing/Cpp.hs +43/−51
- src/Ormolu/Processing/Postprocess.hs +0/−31
- src/Ormolu/Processing/Preprocess.hs +139/−109
- src/Ormolu/Terminal.hs +125/−0
- src/Ormolu/Utils.hs +7/−29
- src/Ormolu/Utils/Extensions.hs +145/−0
- src/Ormolu/Utils/IO.hs +23/−0
- tests/Ormolu/CabalExtensionsSpec.hs +35/−0
- tests/Ormolu/Diff/TextSpec.hs +67/−0
- tests/Ormolu/Parser/OptionsSpec.hs +32/−0
- tests/Ormolu/Parser/ParseFailureSpec.hs +26/−0
- tests/Ormolu/PrinterSpec.hs +7/−7
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 @@ [](http://opensource.org/licenses/BSD-3-Clause) [](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).