packages feed

brittany 0.10.0.0 → 0.11.0.0

raw patch · 33 files changed

+3085/−2421 lines, 33 filesdep +randomdep ~aesondep ~basedep ~butcherPVP ok

version bump matches the API change (PVP)

Dependencies added: random

Dependency ranges changed: aeson, base, butcher, czipwith, ghc, ghc-boot-th, hspec, multistate

API changes (from Hackage documentation)

- Language.Haskell.Brittany.Internal.Config: configParser :: CmdParser Identity out (CConfig Option)
+ Language.Haskell.Brittany: ErrorMacroConfig :: String -> String -> BrittanyError
+ Language.Haskell.Brittany: [_conf_obfuscate] :: CConfig f -> f (Last Bool)
+ Language.Haskell.Brittany: [_conf_roundtrip_exactprint_only] :: CConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal: extractCommentConfigs :: Anns -> TopLevelDeclNameMap -> Either (String, String) InlineConfig
+ Language.Haskell.Brittany.Internal: getTopLevelDeclNameMap :: ParsedSource -> TopLevelDeclNameMap
+ Language.Haskell.Brittany.Internal.Config: [_conf_obfuscate] :: CConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.Config: [_conf_roundtrip_exactprint_only] :: CConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.Config: cmdlineConfigParser :: CmdParser Identity out (CConfig Option)
+ Language.Haskell.Brittany.Internal.Config.Types: [_conf_obfuscate] :: CConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.Config.Types: [_conf_roundtrip_exactprint_only] :: CConfig f -> f (Last Bool)
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.CZipWith.CFunctor Language.Haskell.Brittany.Internal.Config.Types.CConfig
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.CZipWith.CFunctor Language.Haskell.Brittany.Internal.Config.Types.CDebugConfig
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.CZipWith.CFunctor Language.Haskell.Brittany.Internal.Config.Types.CErrorHandlingConfig
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.CZipWith.CFunctor Language.Haskell.Brittany.Internal.Config.Types.CForwardOptions
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.CZipWith.CFunctor Language.Haskell.Brittany.Internal.Config.Types.CLayoutConfig
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.CZipWith.CFunctor Language.Haskell.Brittany.Internal.Config.Types.CPreProcessorConfig
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.Data.Data (Language.Haskell.Brittany.Internal.Config.Types.CConfig Data.Semigroup.Option)
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.Data.Data (Language.Haskell.Brittany.Internal.Config.Types.CDebugConfig Data.Semigroup.Option)
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.Data.Data (Language.Haskell.Brittany.Internal.Config.Types.CErrorHandlingConfig Data.Semigroup.Option)
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.Data.Data (Language.Haskell.Brittany.Internal.Config.Types.CForwardOptions Data.Semigroup.Option)
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.Data.Data (Language.Haskell.Brittany.Internal.Config.Types.CLayoutConfig Data.Semigroup.Option)
+ Language.Haskell.Brittany.Internal.Config.Types: instance Data.Data.Data (Language.Haskell.Brittany.Internal.Config.Types.CPreProcessorConfig Data.Semigroup.Option)
+ Language.Haskell.Brittany.Internal.Obfuscation: obfuscate :: Text -> IO Text
+ Language.Haskell.Brittany.Internal.Prelude: todo :: a
+ Language.Haskell.Brittany.Internal.Prelude: type GhcPs = RdrName
+ Language.Haskell.Brittany.Internal.Types: ErrorMacroConfig :: String -> String -> BrittanyError
+ Language.Haskell.Brittany.Internal.Types: InlineConfig :: CConfig Option -> Map String (CConfig Option) -> Map AnnKey (CConfig Option) -> InlineConfig
+ Language.Haskell.Brittany.Internal.Types: TopLevelDeclNameMap :: (Map AnnKey String) -> TopLevelDeclNameMap
+ Language.Haskell.Brittany.Internal.Types: [_icd_perBinding] :: InlineConfig -> Map String (CConfig Option)
+ Language.Haskell.Brittany.Internal.Types: [_icd_perKey] :: InlineConfig -> Map AnnKey (CConfig Option)
+ Language.Haskell.Brittany.Internal.Types: [_icd_perModule] :: InlineConfig -> CConfig Option
+ Language.Haskell.Brittany.Internal.Types: data InlineConfig
+ Language.Haskell.Brittany.Internal.Types: instance Data.Data.Data Language.Haskell.Brittany.Internal.Types.InlineConfig
+ Language.Haskell.Brittany.Internal.Types: newtype TopLevelDeclNameMap
+ Language.Haskell.Brittany.Internal.Utils: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Data.Semigroup.Semigroup (Language.Haskell.Brittany.Internal.Utils.Max a)
- Language.Haskell.Brittany: Config :: f (Last Int) -> CDebugConfig f -> CLayoutConfig f -> CErrorHandlingConfig f -> CForwardOptions f -> CPreProcessorConfig f -> CConfig f
+ Language.Haskell.Brittany: Config :: f (Last Int) -> CDebugConfig f -> CLayoutConfig f -> CErrorHandlingConfig f -> CForwardOptions f -> CPreProcessorConfig f -> f (Last Bool) -> f (Last Bool) -> CConfig f
- Language.Haskell.Brittany.Internal: pPrintModule :: Config -> Anns -> ParsedSource -> ([BrittanyError], Text)
+ Language.Haskell.Brittany.Internal: pPrintModule :: Config -> InlineConfig -> Anns -> ParsedSource -> ([BrittanyError], Text)
- Language.Haskell.Brittany.Internal: pPrintModuleAndCheck :: Config -> Anns -> ParsedSource -> IO ([BrittanyError], Text)
+ Language.Haskell.Brittany.Internal: pPrintModuleAndCheck :: Config -> InlineConfig -> Anns -> ParsedSource -> IO ([BrittanyError], Text)
- Language.Haskell.Brittany.Internal.Config: Config :: f (Last Int) -> CDebugConfig f -> CLayoutConfig f -> CErrorHandlingConfig f -> CForwardOptions f -> CPreProcessorConfig f -> CConfig f
+ Language.Haskell.Brittany.Internal.Config: Config :: f (Last Int) -> CDebugConfig f -> CLayoutConfig f -> CErrorHandlingConfig f -> CForwardOptions f -> CPreProcessorConfig f -> f (Last Bool) -> f (Last Bool) -> CConfig f
- Language.Haskell.Brittany.Internal.Config.Types: Config :: f (Last Int) -> CDebugConfig f -> CLayoutConfig f -> CErrorHandlingConfig f -> CForwardOptions f -> CPreProcessorConfig f -> CConfig f
+ Language.Haskell.Brittany.Internal.Config.Types: Config :: f (Last Int) -> CDebugConfig f -> CLayoutConfig f -> CErrorHandlingConfig f -> CForwardOptions f -> CPreProcessorConfig f -> f (Last Bool) -> f (Last Bool) -> CConfig f
- Language.Haskell.Brittany.Internal.Config.Types: cMap :: CZipWith k => (forall a. f a -> g a) -> k f -> k g
+ Language.Haskell.Brittany.Internal.Config.Types: cMap :: CFunctor c => forall (f :: * -> *) (g :: * -> *). () => (forall a. () => f a -> g a) -> c f -> c g
- Language.Haskell.Brittany.Internal.Types: type PPM = MultiRWS '[Map AnnKey Anns, Config, Anns] '[Builder, [BrittanyError], Seq String] '[]
+ Language.Haskell.Brittany.Internal.Types: type PPM = MultiRWS '[Map AnnKey Anns, InlineConfig, Config, Anns] '[Builder, [BrittanyError], Seq String] '[]
- Language.Haskell.Brittany.Internal.Types: type ToBriDoc (sym :: * -> *) = Located (sym RdrName) -> ToBriDocM BriDocNumbered
+ Language.Haskell.Brittany.Internal.Types: type ToBriDoc (sym :: * -> *) = Located (sym GhcPs) -> ToBriDocM BriDocNumbered

Files

ChangeLog.md view
@@ -1,5 +1,52 @@ # Revision history for brittany +## 0.11.0.0 -- May 2018++* Support for ghc-8.4+* Implement inline-config+    e.g. "-- brittany --indent=4"++    respects the following comment forms as input:++    ~~~~+    source comment                       affected target+    ======================================================+    "-- brittany CONFIG"                 whole module+    "-- brittany-next-binding CONFIG"    next binding+    "-- brittany-disable-next-binding"   next binding+    "-- brittany @ myExampleFunc CONFIG" `myExampleFunc`+    ~~~~++    multiline-comments are supported too, although+    the specification must still be a single line. E.g.+    +    > "{- brittany --columns 50 -}"+    +    CONFIG is either:+    +    1) one or more flags in the form of what brittany accepts+       on the commandline, e.g. "-- columns 50", or+    2) one or more specifications in the form of what brittany+       accepts in its config files for the layouting config+       (a one-line yaml document), e.g. "{ lconfig_cols: 50 }"+* Implement `IndentPolicyMultiple` (thanks to Bryan Richter @chreekat)+    Restrict indentation amounts to `n * indentAmount`+* Implement `--obfuscate` that replaces non-keyword identifiers with random+  names+* Do not write files unless there are changes (don't update modtime)+  (`--write-mode=inplace`) (#93)+* Bugfixes:+    - Fix empty function constraints (`() => IO ()`) (#133)+    - Fix overflowing columns caused by aligning with surrounding lines+      for certain complex cases+    - Implement hacky workaround for `type instance`s (`-XTypeFamilies`) (#89)+* Layouting changes:+    - On default settings, allow single-line module header+      `module MyModule where` when no exports+    - Fix one case of non-optimal layouting for if-then-else+    - Allow same-line let binding inside do-notation with+      `IndentPolicyLeft/Multiple` and `indentAmount>=4`+ ## 0.10.0.0 -- March 2018  * Implement module/exports/imports layouting (thanks to sniperrifle2004)
README.md view
@@ -48,7 +48,7 @@  # Other usage notes -- Supports GHC versions `8.0.*` and `8.2.*`.+- Supports GHC versions `8.0`, `8.2` and `8.4`. - included in stackage with lts>=10.0 (or nightlies dating to >=2017-11-15) - config (file) documentation is lacking. - some config values can not be configured via commandline yet.@@ -72,7 +72,7 @@      ~~~~.sh     cabal unpack brittany-    cd brittany-0.8.0.2+    cd brittany-0.11.0.0     # cabal new-configure -w $PATH_TO_GHC_8_0     cabal new-build exe:brittany     # and it should be safe to just copy the executable, e.g.@@ -159,7 +159,7 @@  # License -Copyright (C) 2016-2017 Lennart Spitzner+Copyright (C) 2016-2018 Lennart Spitzner  This program is free software: you can redistribute it and/or modify it under the terms of the
brittany.cabal view
@@ -1,5 +1,5 @@ name:                 brittany-version:              0.10.0.0+version:              0.11.0.0 synopsis:             Haskell source code formatter description: {   See <https://github.com/lspitzner/brittany/blob/master/README.md the README>.@@ -12,10 +12,10 @@ license-file:         LICENSE author:               Lennart Spitzner maintainer:           Lennart Spitzner <hexagoxel@hexagoxel.de>-copyright:            Copyright (C) 2016-2017 Lennart Spitzner+copyright:            Copyright (C) 2016-2018 Lennart Spitzner category:             Language build-type:           Simple-cabal-version:        >=1.18+cabal-version:        1.18 homepage:             https://github.com/lspitzner/brittany/ bug-reports:          https://github.com/lspitzner/brittany/issues extra-doc-files: {@@ -55,6 +55,7 @@     Language.Haskell.Brittany.Internal.Config     Language.Haskell.Brittany.Internal.Config.Types     Language.Haskell.Brittany.Internal.Config.Types.Instances+    Language.Haskell.Brittany.Internal.Obfuscation     Paths_brittany   }   other-modules: {@@ -82,22 +83,22 @@     -fno-warn-redundant-constraints   }   build-depends:-    { base >=4.9 && <4.11-    , ghc >=8.0.1 && <8.3+    { base >=4.9 && <4.12+    , ghc >=8.0.1 && <8.5     , ghc-paths >=0.1.0.9 && <0.2     , ghc-exactprint >=0.5.6.0 && <0.5.7     , transformers >=0.5.2.0 && <0.6     , containers >=0.5.7.1 && <0.6     , mtl >=2.2.1 && <2.3     , text >=1.2 && <1.3-    , multistate >=0.7.1.1 && <0.8+    , multistate >=0.7.1.1 && <0.9     , syb >=0.6 && <0.8     , neat-interpolation >=0.3.2 && <0.4     , data-tree-print     , pretty >=1.1.3.3 && <1.2     , bytestring >=0.10.8.1 && <0.11     , directory >=1.2.6.2 && <1.4-    , butcher >=1.3 && <1.4+    , butcher >=1.3.1 && <1.4     , yaml >=0.8.18 && <0.9     , aeson >=1.0.1.0 && <1.3     , extra >=1.4.10 && <1.7@@ -109,9 +110,10 @@     , deepseq >=1.4.2.0 && <1.5     , semigroups >=0.18.2 && <0.19     , cmdargs >=0.10.14 && <0.11-    , czipwith >=1.0.0.0 && <1.1-    , ghc-boot-th >=8.0.1 && <8.3+    , czipwith >=1.0.1.0 && <1.1+    , ghc-boot-th >=8.0.1 && <8.5     , filepath >=1.4.1.0 && <1.5+    , random >= 1.1 && <1.2     }   default-extensions: {     CPP@@ -174,7 +176,6 @@     , cmdargs     , czipwith     , ghc-boot-th-    , hspec >=2.4.1 && <2.5     , filepath >=1.4.1.0 && <1.5     }   hs-source-dirs:      src-brittany@@ -242,9 +243,8 @@     , cmdargs     , czipwith     , ghc-boot-th-    , hspec >=2.4.1 && <2.5+    , hspec >=2.4.1 && <2.6     }-  ghc-options:      -Wall   main-is:          TestMain.hs   other-modules:    TestUtils                     AsymptoticPerfTests@@ -310,11 +310,10 @@     , cmdargs     , czipwith     , ghc-boot-th-    , hspec >=2.4.1 && <2.5+    , hspec >=2.4.1 && <2.6     , filepath     , parsec >=3.1.11 && <3.2     }-  ghc-options:      -Wall   main-is:          Main.hs   other-modules:   hs-source-dirs:   src-literatetests@@ -353,9 +352,8 @@     , base     , text     , transformers-    , hspec >=2.4.1 && <2.5+    , hspec >=2.4.1 && <2.6     }-  ghc-options:      -Wall   main-is:          Main.hs   other-modules:   hs-source-dirs:   src-libinterfacetests
src-brittany/Main.hs view
@@ -11,6 +11,7 @@ import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types import qualified Language.Haskell.GHC.ExactPrint.Parsers as ExactPrint.Parsers import qualified Data.Map as Map+import qualified Data.Monoid  import           Text.Read (Read(..)) import qualified Text.ParserCombinators.ReadP as ReadP@@ -27,6 +28,7 @@ import           Language.Haskell.Brittany.Internal.Config import           Language.Haskell.Brittany.Internal.Config.Types import           Language.Haskell.Brittany.Internal.Utils+import           Language.Haskell.Brittany.Internal.Obfuscation  import qualified Text.PrettyPrint as PP @@ -132,7 +134,7 @@   printVersion   <- addSimpleBoolFlag "" ["version"] mempty   printLicense   <- addSimpleBoolFlag "" ["license"] mempty   configPaths    <- addFlagStringParams "" ["config-file"] "PATH" (flagHelpStr "path to config file") -- TODO: allow default on addFlagStringParam ?-  cmdlineConfig  <- configParser+  cmdlineConfig  <- cmdlineConfigParser   suppressOutput <- addSimpleBoolFlag     ""     ["suppress-output"]@@ -148,7 +150,7 @@           , PP.text "inplace: override respective input file (without backup!)"           ]         )-    <> flagDefault Display+    Data.Monoid.<> flagDefault Display     )   inputParams <- addParamNoFlagStrings "PATH" (paramHelpStr "paths to input/inout haskell source files")   reorderStop@@ -178,13 +180,14 @@     config <- runMaybeT (readConfigsWithUserConfig cmdlineConfig configsToLoad) >>= \case       Nothing -> System.Exit.exitWith (System.Exit.ExitFailure 53)       Just x  -> return x-    when (confUnpack $ _dconf_dump_config $ _conf_debug $ config) $+    when (config & _conf_debug & _dconf_dump_config & confUnpack) $       trace (showConfigYaml config) $ return ()      results <- zipWithM (coreIO putStrErrLn config suppressOutput) inputPaths outputPaths-    case sequence_ results of-      Left  _ -> System.Exit.exitWith (System.Exit.ExitFailure 1)-      Right _ -> pure ()+    case results of+      xs | all Data.Either.isRight xs -> pure ()+      [Left x] -> System.Exit.exitWith (System.Exit.ExitFailure x)+      _        -> System.Exit.exitWith (System.Exit.ExitFailure 1)   -- | The main IO parts for the default mode of operation, and after commandline@@ -209,11 +212,14 @@   -- CPP (but requires the input to be a file..).   let cppMode            = config & _conf_preprocessor & _ppconf_CPPMode & confUnpack   -- the flag will do the following: insert a marker string-  -- ("-- BRITTANY_INCLUDE_HACK ") right before any lines starting with+  -- ("-- BRITANY_INCLUDE_HACK ") right before any lines starting with   -- "#include" before processing (parsing) input; and remove that marker   -- string from the transformation output.+  -- The flag is intentionally misspelled to prevent clashing with+  -- inline-config stuff.   let hackAroundIncludes = config & _conf_preprocessor & _ppconf_hackAroundIncludes & confUnpack-  let exactprintOnly     = config & _conf_debug & _dconf_roundtrip_exactprint_only & confUnpack+  let exactprintOnly     = (config & _conf_roundtrip_exactprint_only & confUnpack)+                        || (config & _conf_debug & _dconf_roundtrip_exactprint_only & confUnpack)   let cppCheckFunc dynFlags = if GHC.xopt GHC.Cpp dynFlags         then case cppMode of           CPPModeAbort -> do@@ -230,7 +236,7 @@   parseResult <- case inputPathM of     Nothing -> do       -- TODO: refactor this hack to not be mixed into parsing logic-      let hackF s = if "#include" `isPrefixOf` s then "-- BRITTANY_INCLUDE_HACK " ++ s else s+      let hackF s = if "#include" `isPrefixOf` s then "-- BRITANY_INCLUDE_HACK " ++ s else s       let hackTransform =             if hackAroundIncludes && not exactprintOnly then List.intercalate "\n" . fmap hackF . lines' else id       inputString <- liftIO $ System.IO.hGetContents System.IO.stdin@@ -242,27 +248,41 @@       putErrorLn $ show left       ExceptT.throwE 60     Right (anns, parsedSource, hasCPP) -> do+      inlineConf <- case extractCommentConfigs anns (getTopLevelDeclNameMap parsedSource) of+        Left (err, input) -> do+          putErrorLn+            $  "Error: parse error in inline configuration:"+          putErrorLn err+          putErrorLn $ "  in the string \"" ++ input ++ "\"."+          ExceptT.throwE 61+        Right c -> -- trace (showTree c) $+          pure c       when (config & _conf_debug .> _dconf_dump_ast_full .> confUnpack) $ do         let val = printTreeWithCustom 100 (customLayouterF anns) parsedSource         trace ("---- ast ----\n" ++ show val) $ return ()-      (errsWarns, outLText) <- do+      (errsWarns, outSText) <- do         if exactprintOnly           then do-            pure ([], TextL.pack $ ExactPrint.exactPrint parsedSource anns)+            pure ([], Text.pack $ ExactPrint.exactPrint parsedSource anns)           else do             let omitCheck = config & _conf_errorHandling .> _econf_omit_output_valid_check .> confUnpack             (ews, outRaw) <- if hasCPP || omitCheck-              then return $ pPrintModule config anns parsedSource-              else liftIO $ pPrintModuleAndCheck config anns parsedSource-            let hackF s = fromMaybe s $ TextL.stripPrefix (TextL.pack "-- BRITTANY_INCLUDE_HACK ") s-            pure $ if hackAroundIncludes-              then (ews, TextL.intercalate (TextL.pack "\n") $ fmap hackF $ TextL.splitOn (TextL.pack "\n") outRaw)-              else (ews, outRaw)+              then return $ pPrintModule config inlineConf anns parsedSource+              else liftIO $ pPrintModuleAndCheck config inlineConf anns parsedSource+            let hackF s = fromMaybe s $ TextL.stripPrefix (TextL.pack "-- BRITANY_INCLUDE_HACK ") s+            let out = TextL.toStrict $ if hackAroundIncludes+                  then TextL.intercalate (TextL.pack "\n") $ fmap hackF $ TextL.splitOn (TextL.pack "\n") outRaw+                  else outRaw+            out' <- if config & _conf_obfuscate & confUnpack+              then lift $ obfuscate out+              else pure out+            pure $ (ews, out')       let customErrOrder ErrorInput{}         = 4           customErrOrder LayoutWarning{}      = 0 :: Int           customErrOrder ErrorOutputCheck{}   = 1           customErrOrder ErrorUnusedComment{} = 2           customErrOrder ErrorUnknownNode{}   = 3+          customErrOrder ErrorMacroConfig{}   = 5       when (not $ null errsWarns) $ do         let groupedErrsWarns = Data.List.Extra.groupOn customErrOrder $ List.sortOn customErrOrder $ errsWarns         groupedErrsWarns `forM_` \case@@ -293,6 +313,11 @@             unused `forM_` \case               ErrorUnusedComment str -> putErrorLn str               _                      -> error "cannot happen (TM)"+          (ErrorMacroConfig err input:_) -> do+            putErrorLn+              $  "Error: parse error in inline configuration:"+            putErrorLn err+            putErrorLn $ "  in the string \"" ++ input ++ "\"."           [] -> error "cannot happen"       -- TODO: don't output anything when there are errors unless user       -- adds some override?@@ -303,8 +328,20 @@           shouldOutput = not suppressOutput && (not hasErrors || outputOnErrs)        when shouldOutput $ addTraceSep (_conf_debug config) $ case outputPathM of-        Nothing -> liftIO $ TextL.IO.putStr $ outLText-        Just p  -> liftIO $ TextL.IO.writeFile p $ outLText+        Nothing -> liftIO $ Text.IO.putStr $ outSText+        Just p  -> liftIO $ do+          isIdentical <- case inputPathM of+            Nothing   -> pure False+            Just path -> do+              (== outSText) <$> Text.IO.readFile path+              -- The above means we read the file twice, but the+              -- GHC API does not really expose the source it+              -- read. Should be in cache still anyways.+              --+              -- We do not use TextL.IO.readFile because lazy IO is evil.+              -- (not identical -> read is not finished -> handle still open ->+              -- write below crashes - evil.)+          unless isIdentical $ Text.IO.writeFile p $ outSText        when hasErrors $ ExceptT.throwE 70  where
src-literatetests/15-regressions.blt view
@@ -587,3 +587,27 @@   <|> alterantiveTwo   -- d   <|> alternativeThree -- e   ) -- f++#test issue 133+{-# LANGUAGE ScopedTypeVariables #-}+func+  :: forall a+   . ()+  => aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+  -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+func+  :: ()+  => aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+  -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa++#test alignment-potential-overflow+go l [] = Right l+go l ((IRType, _a) : eqr) = go l eqr+go l ((_, IRType) : eqr) = go l eqr+go _ ((IRTypeError ps t1 t2, _) : _) = Left $ makeError ps t1 t2+go _ ((_, IRTypeError ps t1 t2) : _) = Left $ makeError ps t1 t2++#test issue 89 - type-family-instance++type instance (XPure StageParse) = ()+type Pair a = (a, a)
+ src-literatetests/30-tests-context-free.blt view
@@ -0,0 +1,1399 @@++###############################################################################+###############################################################################+###############################################################################+#group type signatures+###############################################################################+###############################################################################+###############################################################################++#test simple001+func :: a -> a++#test long typeVar+func+  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd++#test keep linebreak mode+func+  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> lakjsdlkjasldkj+  -> lakjsdlkjasldkj++#test simple parens 1+func :: ((a))++#test simple parens 2+func :: (a -> a) -> a++#test simple parens 3+func :: a -> (a -> a)++#test did anyone say parentheses?+func :: (((((((((())))))))))++-- current output is.. funny. wonder if that can/needs to be improved..+#test give me more!+#pending+func :: ((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))++#test unit+func :: ()+++###############################################################################++#test paren'd func 1+func+  :: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     -> lakjsdlkjasldkj+     -> lakjsdlkjasldkj+     )++#test paren'd func 2+func+  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> (lakjsdlkjasldkj -> lakjsdlkjasldkj)++#test paren'd func 3+func+  :: (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd -> lakjsdlkjasldkj)+  -> lakjsdlkjasldkj++#test paren'd func 4+func+  :: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     )+  -> lakjsdlkjasldkj++#test paren'd func 5+func+  :: ( ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       )+     )++###############################################################################++#test type application 1+func :: asd -> Either a b++#test type application 2+func+  :: asd+  -> Either+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd++#test type application 3+func+  :: asd+  -> Trither+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd++#test type application 4+func+  :: Trither+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> asd++#test type application 5+func+  :: Trither+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd -> asd)++#test type application 6+func+  :: Trither+       asd+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       )++#test type application paren 1+func+  :: asd+  -> ( Trither+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     )++#test type application paren 2+func+  :: asd+  -> ( Trither+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     )+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd++#test type application paren 3+func+  :: ( Trither+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     )+       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> asd++###############################################################################++#test list simple+func :: [a -> b]++#test list func+func+  :: [ lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     ]++#test list paren+func+  :: [ ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       )+     ]++################################################################## -- #############++#test tuple type 1+func :: (a, b, c)++#test tuple type 2+func :: ((a, b, c), (a, b, c), (a, b, c))++#test tuple type long+func+  :: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     )++#test tuple type nested+func+  :: ( ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       , (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd)+       , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       )+     )++#test tuple type function+func+  :: [ ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+       )+     ]+###############################################################################+#test type operator stuff+#pending+test050 :: a :+: b+test051+  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  :+: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+test052+  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  :+: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd++###############################################################################++#test forall oneliner+{-# LANGUAGE ScopedTypeVariables #-}+func :: forall (a :: *) b . a -> b++#test forall context multiline+{-# LANGUAGE ScopedTypeVariables #-}+func+  :: forall m+   . Foo+  => ColMap2+  -> ColInfo+  -> ColInfo+  -> ColInfo+  -> ColInfo+  -> m ()++#test forall no-context multiline+{-# LANGUAGE ScopedTypeVariables #-}+func+  :: forall m+   . ColMap2+  -> ColInfo+  -> ColInfo+  -> ColInfo+  -> ColInfo+  -> ColInfo+  -> m ()++#test language pragma issue+{-# LANGUAGE ScopedTypeVariables #-}+func :: forall (a :: *) b . a -> b++#test comments 1+func :: a -> b -- comment++#test comments 2+funcA :: a -> b -- comment A+funcB :: a -> b -- comment B++#test comments all+#pending+-- a+func -- b+  :: -- c+  a -- d+  -> -- e+  ( -- f+  c -- g+  , -- h+  d -- i+  ) -- j+-- k++###############################################################################++#test ImplicitParams 1+{-# LANGUAGE ImplicitParams #-}+func :: (?asd::Int) -> ()++#test ImplicitParams 2+{-# LANGUAGE ImplicitParams #-}+func+  :: ( ?asd+     :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+     )+  -> ()+++###############################################################################+###############################################################################+###############################################################################+#group type signatures pragmas+###############################################################################+###############################################################################+###############################################################################++#test inline pragma 1+func = f+ where+  {-# INLINE f #-}+  f = id++#test inline pragma 2+func = ($)+ where+  {-# INLINE ($) #-}+  ($) = id++#test inline pragma 3+func = f+ where+  {-# INLINE CONLIKE [1] f #-}+  f = id++#test inline pragma 4+#pending this does not work with the compiler version we currently use yet (i think). should work with ghc-8.0.2.+func = f+ where+  {-# INLINE [~] f #-}+  f = id+++###############################################################################+###############################################################################+###############################################################################+#group equation.basic+###############################################################################+###############################################################################+###############################################################################+## some basic testing of different kinds of equations.+## some focus on column layouting for multiple-equation definitions.+## (that part probably is not implemented in any way yet.)++#test basic 1+func x = x++#test infix 1+x *** y = x++#test symbol prefix+(***) x y = x+++###############################################################################+###############################################################################+###############################################################################+#group equation.patterns+###############################################################################+###############################################################################+###############################################################################++#test wildcard+func _ = x++#test simple long pattern+#pending+func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable+  = x++#test simple multiline pattern+#pending+func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable+  reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable+  = x++#test another multiline pattern+#pending+func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable+  a+  b+  = x++#test simple constructor+func (A a) = a++#test list constructor+func (x : xr) = x++#test some other constructor symbol+#pending+func (x :+: xr) = x+++###############################################################################+###############################################################################+###############################################################################+#group equation.guards+###############################################################################+###############################################################################+###############################################################################+#test simple guard+func | True = x++#test multiple-clauses-1+func x+  | x = simple expression+  | otherwise = 0++#test multiple-clauses-2+func x+  | a somewhat longer guard x = "and a somewhat longer expession that does not"+  | otherwise = "fit without putting the guards in new lines"++#test multiple-clauses-3+func x+  | very long guard, another rather long guard that refers to x = nontrivial+    expression+    foo+    bar+    alsdkjlasdjlasj+  | otherwise = 0++#test multiple-clauses-4+func x+  | very long guard, another rather long guard that refers to x+  = nontrivialexpression foo bar alsdkjlasdjlasj+  | otherwise+  = 0++#test multiple-clauses-5+func x+  | very loooooooooooooooooooooooooooooong guard+  , another rather long guard that refers to x+  = nontrivial expression foo bar alsdkjlasdjlasj+  | otherwise+  = 0+++###############################################################################+###############################################################################+###############################################################################+#group expression.basic+###############################################################################+###############################################################################+###############################################################################++#test var+func = x++describe "infix op" $ do+#test 1+func = x + x++#test long+#pending+func = mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj+  + mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj++#test long keep linemode 1+#pending+func = mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj+  + mweroiuxlskdfjlksj+  + mweroiuxlskdfjlksj++#test long keep linemode 2+#pending+func = mweroiuxlskdfjlksj+  + mweroiuxlskdfjlksj+  + mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj++#test literals+func = 1+func = "abc"+func = 1.1e5+func = 'x'+func = 981409823458910394810928414192837123987123987123++#test lambdacase+{-# LANGUAGE LambdaCase #-}+func = \case+  FooBar -> x+  Baz -> y++#test lambda+func = \x -> abc++describe "app" $ do+#test 1+func = klajsdas klajsdas klajsdas++#test 2+func = lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd+  lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd+  lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd++#test 3+func = lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd+  lakjsdlajsdljas+  lakjsdlajsdljas+  lakjsdlajsdljas++###+#group expression.basic.sections+###++#test left+func = (1 +)++#test right+func = (+ 1)++#test left inf+## TODO: this could be improved..+func = (1 `abc`)++#test right inf+func = (`abc` 1)++###+#group tuples+###++#test 1+func = (abc, def)++#test 2+#pending+func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd+  , lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd)++#test let in on single line+foo =+  let longIdentifierForShortValue = 1+  in longIdentifierForShortValue + longIdentifierForShortValue++++###############################################################################+###############################################################################+###############################################################################+#group expression.do statements+###############################################################################+###############################################################################+###############################################################################++#test simple+func = do+  stmt+  stmt++#test bind+func = do+  x <- stmt+  stmt x++#test let+func = do+  let x = 13+  stmt x+++###############################################################################+###############################################################################+###############################################################################+#group expression.lists+###############################################################################+###############################################################################+###############################################################################++#test monad-comprehension-case-of+func =+  foooooo+    $ [ case+          foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+        of+          _ -> True+      ]+++###############################################################################+###############################################################################+###############################################################################+#group expression.multiwayif+###############################################################################+###############################################################################+###############################################################################++#test simple+{-# LANGUAGE MultiWayIf #-}+func = if+  | cond1 -> loooooooooooooooooooooooooooooong expr1+  | cond2 -> loooooooooooooooooooooooooooooong expr2++#test simplenested+{-# LANGUAGE MultiWayIf #-}+func = do+  foo+  bar $ if+    | cond1 -> loooooooooooooooooooooooooooooong expr1+    | cond2 -> loooooooooooooooooooooooooooooong expr2+++###############################################################################+###############################################################################+###############################################################################+#group stylisticspecialcases+###############################################################################+###############################################################################+###############################################################################++#test operatorprefixalignment-even-with-multiline-alignbreak+func =+  foo+    $ [ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+      , bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+      ]+    ++ [ccccccccccccccccccccccccccccccccccccccccccccccccccccccccc]++###############################################################################+###############################################################################+###############################################################################+#group module+###############################################################################+###############################################################################+###############################################################################++#test simple+module Main where++#test no-exports+module Main () where++#test one-export+module Main (main) where++#test several-exports+module Main (main, test1, test2) where++#test many-exports+module Main+  ( main+  , test1+  , test2+  , test3+  , test4+  , test5+  , test6+  , test7+  , test8+  , test9+  )+where++#test exports-with-comments+module Main+  ( main+  -- main+  , test1+  , test2+  -- Test 3+  , test3+  , test4+  -- Test 5+  , test5+  -- Test 6+  )+where++#test simple-export-with-things+module Main (Test(..)) where++#test simple-export-with-module-contents+module Main (module Main) where++#test export-with-things+module Main (Test(Test, a, b)) where++#test export-with-empty-thing+module Main (Test()) where++#test empty-with-comment+-- Intentionally left empty++###############################################################################+###############################################################################+###############################################################################+#group import+###############################################################################+###############################################################################+###############################################################################++#test simple-import+import Data.List++#test simple-import-alias+import Data.List as L++#test simple-qualified-import+import qualified Data.List++#test simple-qualified-import-alias+import qualified Data.List as L++#test simple-safe+import safe Data.List as L++#test simple-source+import {-# SOURCE #-} Data.List ()++#test simple-safe-qualified+import safe qualified Data.List hiding (nub)++#test simple-safe-qualified-source+import {-# SOURCE #-} safe qualified Data.List++#test simple-qualified-package+import qualified "base" Data.List++#test qualifier-effect+import {-# SOURCE #-} safe qualified "base" Data.List as L+import {-# SOURCE #-} safe qualified "base" Data.List ()+import {-# SOURCE #-} safe qualified Data.List hiding ()++#test instances-only+import qualified Data.List ()++#test one-element+import Data.List (nub)++#test several-elements+import Data.List (nub, foldl', indexElem)++#test a-ridiculous-amount-of-elements+import Test+  ( Long+  , list+  , with+  , items+  , that+  , will+  , not+  , quite+  , fit+  , onA+  , single+  , line+  , anymore+  )++#test with-things+import Test (T, T2(), T3(..), T4(T4), T5(T5, t5), T6((<|>)), (+))++#test hiding+import Test hiding ()+import Test as T hiding ()++#test long-module-name-simple+import TestJustShortEnoughModuleNameLikeThisOne ()+import TestJustAbitToLongModuleNameLikeThisOneIs ()+import MoreThanSufficientlyLongModuleNameWithSome+  (items, that, will, not, fit, inA, compact, layout)++#test long-module-name-as+import TestJustShortEnoughModuleNameLikeThisOn as T+import TestJustAbitToLongModuleNameLikeThisOneI as T++#test long-module-name-hiding+import TestJustShortEnoughModuleNameLike hiding ()+import TestJustAbitToLongModuleNameLikeTh hiding ()++#test long-module-name-simple-items+import MoreThanSufficientlyLongModuleNameWithSome+  (items, that, will, not, fit, inA, compact, layout)++#test long-module-name-hiding-items+import TestJustShortEnoughModuleNameLike hiding (abc, def, ghci, jklm)++#test import-with-comments+-- Test+import Data.List (nub) -- Test+{- Test -}+import qualified Data.List as L (foldl') {- Test -}++#test import-with-comments-2++import Test+  ( abc+  , def+  -- comment+  )++#test import-with-comments-3++import Test+  ( abc+  -- comment+  )++#test import-with-comments-4+import Test+  ( abc+  -- comment+  , def+  , ghi+  {- comment -}+  , jkl+  -- comment+  )++-- Test+import Test (test)++#test import-with-comments-5+import Test+  ( -- comment+  )++#test long-bindings+import Test (longbindingNameThatoverflowsColum)+import Test (Long(List, Of, Things))++#test things-with-with-comments+import Test+  ( Thing+    ( With+    -- Comments+    , and+    -- also+    , items+    -- !+    )+  )+import Test+  ( Thing+    ( Item+    -- and Comment+    )+  )+import Test+  ( Thing+    ( With+    -- Comments+    , and+    -- also+    , items+    -- !+    )+  )++#test prefer-dense-empty-list+import VeryLongModuleNameThatCouldEvenCauseAnEmptyBindingListToExpandIntoMultipleLine+  ()++#test preamble full-preamble+{-# LANGUAGE BangPatterns #-}++{-+ - Test module+ -}+module Test+  ( test1+  -- ^ test+  , test2+  -- | test+  , test3+  , test4+  , test5+  , test6+  , test7+  , test8+  , test9+  , test10+  )+where++-- Test+import Data.List (nub) -- Test+{- Test -}+import qualified Data.List as L (foldl') {- Test -}++-- Test+import Test (test)++###############################################################################+###############################################################################+###############################################################################+#group regression+###############################################################################+###############################################################################+###############################################################################++#test newlines-comment+func = do+  abc <- foo++--abc+return ()++#test parenthesis-around-unit+func = (())++#test let-defs indentation+func = do+  let+    foo True = True+    foo _ = False+  return ()++#test let-defs no indent+func = do+  let+    foo True = True+    foo _ = False+  return ()++#test let-defs no indent+func = do+  let+    foo = True+    b = False+  return ()++#test let-defs no indent+func =+  let+    foo = True+    b = False+  in return ()++#test record update indentation 1+func = do+  s <- mGet+  mSet $ s { _lstate_indent = _lstate_indent state }++#test record update indentation 2+func = do+  s <- mGet+  mSet $ s+    { _lstate_indent = _lstate_indent state+    , _lstate_foo = _lstate_foo state+    }++#test record update indentation 3+func = do+  s <- mGet+  mSet $ s+    { _lstate_indent = _lstate_indent lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+    , _lstate_foo = _lstate_foo kasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+    }++#test record construction 1+func = Foo {_lstate_indent = _lstate_indent state}++#test record construction 2+func = Foo+  { _lstate_indent = _lstate_indent lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  , _lstate_foo = _lstate_foo lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+  }++#test record construction 3+func = do+  Foo+    { _lstate_indent = _lstate_indent lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+    , _lstate_foo = _lstate_foo lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd+    }++#test post-indent comment+func = do+-- abc+  -- def+  return ()++#test post-unindent comment+func = do+  do+    return ()+    -- abc+  -- def+  return ()++#test CPP empty comment case+#pending CPP parsing needs fixing for roundTripEqual+{-# LANGUAGE CPP #-}+module Test where+func = do+#if FOO+  let x = 13+#endif+  stmt x++## really, the following should be handled by forcing the Alt to multiline+## because there are comments. as long as this is not implemented though,+## we should ensure the trivial solution works.+#test comment inline placement (temporary)+func+  :: Int -- basic indentation amount+  -> Int -- currently used width in current line (after indent)+         -- used to accurately calc placing of the current-line+  -> LayoutDesc+  -> Int++#test some indentation thingy+func =+  (lkjadljasldjalskdjaldjalsdjkalsdjlaksdjlasjdlajsaldskj+  $ abc+  $ def+  $ ghi+  $ jkl+  )++#test parenthesized operator+buildG bounds0 edges0 = accumArray (flip (:)) [] bounds0 (map reassoc edges0)+  where reassoc (v, e, w) = (v, (e, w))++#test record pattern matching stuff+downloadRepoPackage = case repo of+  RepoLocal {..} -> return ()+  RepoLocal { abc } -> return ()+  RepoLocal{} -> return ()++#test do let comment indentation level problem+func = do+  let+    (primaryPkg, otherPkgs) = selectPrimaryLocalPackage pwd pkgs'+    (bproblems, x) = resolveBuildTargets primaryPkg otherPkgs utargets''+    -- default local dir target if there's no given target+    utargets'' = "foo"+  return ()++#test list comprehension comment placement+func =+  [ (thing, take 10 alts) --TODO: select best ones+  | (thing, _got, alts@(_ : _)) <- nosuchFooThing+  , gast <- award+  ]++#test if-then-else comment placement+func = if x+  then if y -- y is important+    then foo+    else bar+  else Nothing++#test qualified infix pattern+#pending "TODO"+wrapPatPrepend pat prepElem = do+  patDocs <- layoutPat pat+  case Seq.viewl patDocs of+    Seq.EmptyL -> return $ Seq.empty+    x1 Seq.:< xR -> do+      x1' <- docSeq [prepElem, return x1]+      return $ x1' Seq.<| xR++#test type signature multiline forcing issue+layoutWriteNewlineBlock+  :: ( MonadMultiWriter Text.Builder.Builder m+     , MonadMultiState LayoutState m+     , MonadMultiWriter (Seq String) m+     )+  => m ()++#test multiwayif proper indentation+{-# LANGUAGE MultiWayIf #-}+readMergePersConfig path shouldCreate conf = do+  exists <- liftIO $ System.Directory.doesFileExist path+  if+    | exists -> do+      contents <- liftIO $ ByteString.readFile path -- no lazy IO, tyvm.+      fileConf <- case Data.Yaml.decodeEither contents of+        Left e -> do+          liftIO+            $ putStrErrLn+            $ "error reading in brittany config from "+            ++ path+            ++ ":"+          liftIO $ putStrErrLn e+          mzero+        Right x -> return x+      return $ fileConf Semigroup.<> conf+    | shouldCreate -> do+      liftIO $ ByteString.writeFile path $ Data.Yaml.encode $ cMap+        (Option . Just . runIdentity)+        staticDefaultConfig+      return $ conf+    | otherwise -> do+      return conf++#test nested pattern alignment issue"+func = BuildReport+ where+  convertInstallOutcome = case result of+    Left BR.PlanningFailed -> PlanningFailed+    Left (BR.DependentFailed p) -> DependencyFailed p+    Left (BR.DownloadFailed _) -> DownloadFailed+    Left (BR.UnpackFailed _) -> UnpackFailed+    Left (BR.ConfigureFailed _) -> ConfigureFailed+    Left (BR.BuildFailed _) -> BuildFailed+    Left (BR.TestsFailed _) -> TestsFailed+    Left (BR.InstallFailed _) -> InstallFailed+    Right (BR.BuildOk _ _ _) -> InstallOk++#test nested pattern alignment issue"+func = BuildReport+ where+  convertInstallOutcome = case result of+    Left BR.PlanningFailed -> PlanningFailed+    Left (BR.DependentFailed p) -> DependencyFailed p+    Left (BR.DownloadFailed _) -> DownloadFailed+    Left (BR.UnpackFailed _) -> UnpackFailed+    Left (BR.ConfigureFailed _) -> ConfigureFailed+    Left (BR.BuildFailed _) -> BuildFailed+    Left (BR.TestsFailed _) -> TestsFailed+    Left (BR.InstallFailed _) -> InstallFailed+    Right (BR.BuildOk _ _ _) -> InstallOk++#test partially overflowing alignment issue"+showPackageDetailedInfo pkginfo =+  renderStyle (style { lineLength = 80, ribbonsPerLine = 1 })+    $ char '*'+    $+$ something+          [ entry "Synopsis" synopsis hideIfNull reflowParagraphs+          , entry+            "Versions available"+            sourceVersions+            (altText null "[ Not available from server ]")+            (dispTopVersions 9 (preferredVersions pkginfo))+          , entry+            "Versions installed"+            installedVersions+            (altText+              null+              (if hasLib pkginfo then "[ Not installed ]" else "[ Unknown ]")+            )+            (dispTopVersions 4 (preferredVersions pkginfo))+          , entry "Homepage" homepage orNotSpecified text+          , entry "Bug reports" bugReports orNotSpecified text+          , entry "Description" description hideIfNull reflowParagraphs+          , entry "Category" category hideIfNull text+          , entry "License" license alwaysShow disp+          , entry "Author" author hideIfNull reflowLines+          , entry "Maintainer" maintainer hideIfNull reflowLines+          , entry "Source repo" sourceRepo orNotSpecified text+          , entry "Executables" executables hideIfNull (commaSep text)+          , entry "Flags" flags hideIfNull (commaSep dispFlag)+          , entry "Dependencies" dependencies hideIfNull (commaSep dispExtDep)+          , entry "Documentation" haddockHtml showIfInstalled text+          , entry "Cached" haveTarball alwaysShow dispYesNo+          , if not (hasLib pkginfo)+            then empty+            else text "Modules:"+              $+$ nest 4 (vcat (map disp . sort . modules $ pkginfo))+          ]++#test issue 7a+isValidPosition position+  | validX && validY = Just position+  | otherwise = Nothing++#test issue-6-pattern-linebreak-validity+## this is ugly, but at least syntactically valid.+foo = Reflex.runSpiderHost $ ReflexHost.hostApp $ do+  (inputEvent :: Reflex.Event Reflex.Spider String, inputFire :: String+    -> IO Bool) <-+    ReflexHost.newExternalEvent+  liftIO . forkIO . forever $ getLine >>= inputFire+  ReflexHost.performEvent_ $ fmap (liftIO . putStrLn) inputEvent++#test issue 16+foldrDesc f z = unSwitchQueue $ \q ->+  switch (Min.foldrDesc (f unTaggedF) z q) (Min.foldrAsc (f unTaggedF) z q)++#test issue 18+autocheckCases =+  [ ("Never Deadlocks", representative deadlocksNever)+  , ("No Exceptions", representative exceptionsNever)+  , ("Consistent Result", alwaysSame) -- already representative+  ]++#test issue 18b+autocheckCases =+  [ ("Never Deadlocks", representative deadlocksNever)+  , ("No Exceptions", representative exceptionsNever)+  , ( "Consistent Result"+    , alwaysSame -- already representative+    )+  ]++#test issue 18c+func =+  [ (abc, (1111, 1111))+  , (def, (2, 2))+  , foo -- comment+  ]++#test issue 26+foo a b = g a b -- fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+  where g a b = b + b * a++#test issue 26b+foo a b = g a b where g a b = b + b * a -- fooooooooooooooooooooooooooooooooooo++#test aggressive alignment 1+func = do+  abc <- expr+  abcccccccccccccccccc <- expr+  abcccccccccccccccccccccccccccccccccccccccccc <- expr+  abccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc <- expr++#test example alignment 1+func (MyLongFoo abc def) = 1+func (Bar a d) = 2+func _ = 3++#test listcomprehension-case-of+parserCompactLocation =+  [ try+      $ [ ParseRelAbs (Text.Read.read digits) _ _+        | digits <- many1 digit+        , rel1 :: Maybe (Either Int (Ratio Int)) <- optionMaybe+          [ case divPart of+              Nothing -> Left $ Text.Read.read digits+              Just ddigits ->+                Right $ Text.Read.read digits % Text.Read.read ddigits+          | digits <- many1 digit+          , divPart <- optionMaybe (string "/" *> many1 digit)+          ]+        ]+  ]++#test opapp-specialcasing-1+func = fooooooooooooooooooooooooooooooooo $ foooooooooooooooooooooooooooooooo+  foooooooooooooooooooooooooooooooo+  foooooooooooooooooooooooooooooooo++#test opapp-specialcasing-2+func =+  fooooooooooooooooooooooooooooooooo+    + foooooooooooooooooooooooooooooooo+        foooooooooooooooooooooooooooooooo+        foooooooooooooooooooooooooooooooo++#test opapp-specialcasing-3+func = fooooooooooooooooooooooooooooooooo + foooooooooooooooooooooooooooooooo+  [ foooooooooooooooooooooooooooooooo+  , foooooooooooooooooooooooooooooooo+  , foooooooooooooooooooooooooooooooo+  ]++#test opapp-indenting+parserPrim =+  [ r+  | r <-+    [ SGPPrimFloat $ bool id (0 -) minus $ readGnok+        "parserPrim"+        (d1 ++ d2 ++ d3 ++ d4)+    | d2 <- string "."+    , d3 <- many1 (oneOf "0123456789")+    , _ <- string "f"+    ]+    <|> [ SGPPrimFloat $ bool id (0 -) minus $ fromIntegral+            (readGnok "parserPrim" d1 :: Integer)+        | _ <- string "f"+        ]+    <|> [ SGPPrimInt $ bool id (0 -) minus $ fromIntegral+            (readGnok "parserPrim" d1 :: Integer)+        | _ <- string "i"+        ]+  ]++#test another-parspacing-testcase++samples = (SV.unpackaaaaadat) <&> \f ->+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa++#test recordupd-singleline-bug++runBrittany tabSize text = do+  let+    config' = staticDefaultConfig+    config = config'+      { _conf_layout = (_conf_layout config')+        { _lconfig_indentAmount = coerce tabSize+        }+      , _conf_forward = forwardOptionsSyntaxExtsEnabled+      }+  parsePrintModule config text++#test issue 38++{-# LANGUAGE TypeApplications #-}+foo = bar @Baz++#test comment-before-BDCols+{-# LANGUAGE TypeApplications #-}+layoutPatternBindFinal alignmentToken binderDoc mPatDoc clauseDocs = do+  docAlt+    $  -- one-line solution+      [ docCols+          (ColBindingLine alignmentToken)+          [ docSeq (patPartInline ++ [guardPart])+          , docSeq+            [ appSep $ return binderDoc+            , docForceSingleline $ return body+            , wherePart+            ]+          ]+      | not hasComments+      , [(guards, body, _bodyRaw)] <- [clauseDocs]+      , let guardPart = singleLineGuardsDoc guards+      , wherePart <- case mWhereDocs of+        Nothing -> return @[] $ docEmpty+        Just [w] -> return @[] $ docSeq+          [ docSeparator+          , appSep $ docLit $ Text.pack "where"+          , docSetIndentLevel $ docForceSingleline $ return w+          ]+        _ -> []+      ]+    ++ -- one-line solution + where in next line(s)+       [ docLines+         $ [ docCols+               (ColBindingLine alignmentToken)+               [ docSeq (patPartInline ++ [guardPart])+               , docSeq+                 [appSep $ return binderDoc, docForceParSpacing $ return body]+               ]+           ]+         ++ wherePartMultiLine+       | [(guards, body, _bodyRaw)] <- [clauseDocs]+       , let guardPart = singleLineGuardsDoc guards+       , Data.Maybe.isJust mWhereDocs+       ]+    ++ -- two-line solution + where in next line(s)+       [ docLines+         $ [ docForceSingleline+             $ docSeq (patPartInline ++ [guardPart, return binderDoc])+           , docEnsureIndent BrIndentRegular $ docForceSingleline $ return+             body+           ]+         ++ wherePartMultiLine+       | [(guards, body, _bodyRaw)] <- [clauseDocs]+       , let guardPart = singleLineGuardsDoc guards+       ]++#test comment-testcase-17+{-# LANGUAGE MultiWayIf #-}+func = do+  let+    foo = if+      | Constuctoooooooooooooooooooooooooooooooooooor `elem` artics -- TODO+                                                                    -> max+        (defLen - 0.2) -- TODO+        (defLen * 0.8)+      | otherwise -> max (defLen - 0.05) (defLen * 0.95) -- TODO+  return True++#test issue 49++foo n = case n of+  1 -> True+  -1 -> False++bar n = case n of+  (-2, -2) -> (-2, -2)++#test issue 48 a++foo =+  let+    a = b@1+    cccc = ()+  in foo++#test issue 48 b++{-# LANGUAGE TypeApplications #-}+foo =+  let+    a = b @1+    cccc = ()+  in foo+++###############################################################################+###############################################################################+###############################################################################+#group pending+###############################################################################+###############################################################################+###############################################################################++++## this testcase is not about idempotency, but about _how_ the output differs+## from the input; i cannot really express this yet with the current+## test-suite.+## #test ayaz+##+## myManageHook =+##   composeOne [isFullscreen -?> doFullFloat, isDialog -?> doFloat, transience]+##     <+> composeAll+##           [ className =? "Pidgin" --> doFloat+##           , className =? "XCalc" --> doFloat+##           -- plan9port's acme+##           , className =? "acme" --> doFloat+##           -- Acme with Vi bindings editor+##           , title =? "ED" --> doFloat+##           , title =? "wlc-x11" --> doFloat+##           , className =? "Skype" --> doFloat+##           , className =? "ffplay" --> doFloat+##           , className =? "mpv" --> doFloat+##           , className =? "Plugin-container" --> doFloat -- Firefox flash, etc.+##           -- Firefox works well tiled, but it has dialog windows we want to float.+##           , appName =? "Browser" --> doFloat+##           ]+##  where+##   role = stringProperty "WM_WINDOW_ROLE"
+ src-literatetests/40-indent-policy-multiple.blt view
@@ -0,0 +1,42 @@+###############################################################################+###############################################################################+###############################################################################+#group indent-policy-multiple+###############################################################################+###############################################################################+###############################################################################++#test long+-- brittany { lconfig_indentAmount: 4, lconfig_indentPolicy: IndentPolicyMultiple }+func =+    mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj+        + mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj++#test let indAmount=4+-- brittany { lconfig_indentAmount: 4, lconfig_indentPolicy: IndentPolicyMultiple }+foo = do+    let aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =+            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+    foo++#test let indAmount=8+-- brittany { lconfig_indentAmount: 8, lconfig_indentPolicy: IndentPolicyMultiple }+foo = do+        let aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =+                aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+        foo+foo = do+        let aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =+                aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+                        + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+                        + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+        foo++#test nested do-block+-- brittany { lconfig_indentAmount: 4, lconfig_indentPolicy: IndentPolicyMultiple }+foo = asdyf8asdf+    "ajsdfas"+    [ asjdf asyhf $ do+        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+    ]
src-literatetests/Main.hs view
@@ -46,7 +46,7 @@           $ filter (".blt"`isSuffixOf`) files   inputs <- blts `forM` \blt -> Text.IO.readFile ("src-literatetests" </> blt)   let groups = createChunks =<< inputs-  inputCtxFree <- Text.IO.readFile "src-literatetests/tests-context-free.blt"+  inputCtxFree <- Text.IO.readFile "src-literatetests/30-tests-context-free.blt"   let groupsCtxFree = createChunks inputCtxFree   hspec $ do     groups `forM_` \(groupname, tests) -> do@@ -160,9 +160,9 @@  defaultTestConfig :: Config defaultTestConfig = Config-  { _conf_version = _conf_version staticDefaultConfig-  , _conf_debug   = _conf_debug staticDefaultConfig-  , _conf_layout  = LayoutConfig+  { _conf_version                   = _conf_version staticDefaultConfig+  , _conf_debug                     = _conf_debug staticDefaultConfig+  , _conf_layout                    = LayoutConfig     { _lconfig_cols                      = coerce (80 :: Int)     , _lconfig_indentPolicy              = coerce IndentPolicyFree     , _lconfig_indentAmount              = coerce (2 :: Int)@@ -178,13 +178,13 @@     , _lconfig_reformatModulePreamble    = coerce True     , _lconfig_allowSingleLineExportList = coerce True     }-  , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig)+  , _conf_errorHandling             = (_conf_errorHandling staticDefaultConfig)     { _econf_omit_output_valid_check = coerce True     }-  , _conf_preprocessor = _conf_preprocessor staticDefaultConfig-  , _conf_forward      = ForwardOptions-    { _options_ghc = Identity []-    }+  , _conf_preprocessor              = _conf_preprocessor staticDefaultConfig+  , _conf_forward = ForwardOptions {_options_ghc = Identity []}+  , _conf_roundtrip_exactprint_only = coerce False+  , _conf_obfuscate = coerce False   }  contextFreeTestConfig :: Config
− src-literatetests/tests-context-free.blt
@@ -1,1399 +0,0 @@--###############################################################################-###############################################################################-###############################################################################-#group type signatures-###############################################################################-###############################################################################-###############################################################################--#test simple001-func :: a -> a--#test long typeVar-func-  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd--#test keep linebreak mode-func-  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> lakjsdlkjasldkj-  -> lakjsdlkjasldkj--#test simple parens 1-func :: ((a))--#test simple parens 2-func :: (a -> a) -> a--#test simple parens 3-func :: a -> (a -> a)--#test did anyone say parentheses?-func :: (((((((((())))))))))---- current output is.. funny. wonder if that can/needs to be improved..-#test give me more!-#pending-func :: ((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))--#test unit-func :: ()---###############################################################################--#test paren'd func 1-func-  :: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     -> lakjsdlkjasldkj-     -> lakjsdlkjasldkj-     )--#test paren'd func 2-func-  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> (lakjsdlkjasldkj -> lakjsdlkjasldkj)--#test paren'd func 3-func-  :: (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd -> lakjsdlkjasldkj)-  -> lakjsdlkjasldkj--#test paren'd func 4-func-  :: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     )-  -> lakjsdlkjasldkj--#test paren'd func 5-func-  :: ( ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       )-     )--###############################################################################--#test type application 1-func :: asd -> Either a b--#test type application 2-func-  :: asd-  -> Either-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd--#test type application 3-func-  :: asd-  -> Trither-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd--#test type application 4-func-  :: Trither-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> asd--#test type application 5-func-  :: Trither-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd -> asd)--#test type application 6-func-  :: Trither-       asd-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       )--#test type application paren 1-func-  :: asd-  -> ( Trither-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     )--#test type application paren 2-func-  :: asd-  -> ( Trither-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     )-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd--#test type application paren 3-func-  :: ( Trither-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-         lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     )-       lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> asd--###############################################################################--#test list simple-func :: [a -> b]--#test list func-func-  :: [ lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     ]--#test list paren-func-  :: [ ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       )-     ]--################################################################## -- #############--#test tuple type 1-func :: (a, b, c)--#test tuple type 2-func :: ((a, b, c), (a, b, c), (a, b, c))--#test tuple type long-func-  :: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     )--#test tuple type nested-func-  :: ( ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       , (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd)-       , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       )-     )--#test tuple type function-func-  :: [ ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       , lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-       )-     ]-###############################################################################-#test type operator stuff-#pending-test050 :: a :+: b-test051-  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  :+: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-test052-  :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  :+: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd--###############################################################################--#test forall oneliner-{-# LANGUAGE ScopedTypeVariables #-}-func :: forall (a :: *) b . a -> b--#test forall context multiline-{-# LANGUAGE ScopedTypeVariables #-}-func-  :: forall m-   . Foo-  => ColMap2-  -> ColInfo-  -> ColInfo-  -> ColInfo-  -> ColInfo-  -> m ()--#test forall no-context multiline-{-# LANGUAGE ScopedTypeVariables #-}-func-  :: forall m-   . ColMap2-  -> ColInfo-  -> ColInfo-  -> ColInfo-  -> ColInfo-  -> ColInfo-  -> m ()--#test language pragma issue-{-# LANGUAGE ScopedTypeVariables #-}-func :: forall (a :: *) b . a -> b--#test comments 1-func :: a -> b -- comment--#test comments 2-funcA :: a -> b -- comment A-funcB :: a -> b -- comment B--#test comments all-#pending--- a-func -- b-  :: -- c-  a -- d-  -> -- e-  ( -- f-  c -- g-  , -- h-  d -- i-  ) -- j--- k--###############################################################################--#test ImplicitParams 1-{-# LANGUAGE ImplicitParams #-}-func :: (?asd::Int) -> ()--#test ImplicitParams 2-{-# LANGUAGE ImplicitParams #-}-func-  :: ( ?asd-     :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     -> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-     )-  -> ()---###############################################################################-###############################################################################-###############################################################################-#group type signatures pragmas-###############################################################################-###############################################################################-###############################################################################--#test inline pragma 1-func = f- where-  {-# INLINE f #-}-  f = id--#test inline pragma 2-func = ($)- where-  {-# INLINE ($) #-}-  ($) = id--#test inline pragma 3-func = f- where-  {-# INLINE CONLIKE [1] f #-}-  f = id--#test inline pragma 4-#pending this does not work with the compiler version we currently use yet (i think). should work with ghc-8.0.2.-func = f- where-  {-# INLINE [~] f #-}-  f = id---###############################################################################-###############################################################################-###############################################################################-#group equation.basic-###############################################################################-###############################################################################-###############################################################################-## some basic testing of different kinds of equations.-## some focus on column layouting for multiple-equation definitions.-## (that part probably is not implemented in any way yet.)--#test basic 1-func x = x--#test infix 1-x *** y = x--#test symbol prefix-(***) x y = x---###############################################################################-###############################################################################-###############################################################################-#group equation.patterns-###############################################################################-###############################################################################-###############################################################################--#test wildcard-func _ = x--#test simple long pattern-#pending-func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable-  = x--#test simple multiline pattern-#pending-func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable-  reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable-  = x--#test another multiline pattern-#pending-func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable-  a-  b-  = x--#test simple constructor-func (A a) = a--#test list constructor-func (x : xr) = x--#test some other constructor symbol-#pending-func (x :+: xr) = x---###############################################################################-###############################################################################-###############################################################################-#group equation.guards-###############################################################################-###############################################################################-###############################################################################-#test simple guard-func | True = x--#test multiple-clauses-1-func x-  | x = simple expression-  | otherwise = 0--#test multiple-clauses-2-func x-  | a somewhat longer guard x = "and a somewhat longer expession that does not"-  | otherwise = "fit without putting the guards in new lines"--#test multiple-clauses-3-func x-  | very long guard, another rather long guard that refers to x = nontrivial-    expression-    foo-    bar-    alsdkjlasdjlasj-  | otherwise = 0--#test multiple-clauses-4-func x-  | very long guard, another rather long guard that refers to x-  = nontrivialexpression foo bar alsdkjlasdjlasj-  | otherwise-  = 0--#test multiple-clauses-5-func x-  | very loooooooooooooooooooooooooooooong guard-  , another rather long guard that refers to x-  = nontrivial expression foo bar alsdkjlasdjlasj-  | otherwise-  = 0---###############################################################################-###############################################################################-###############################################################################-#group expression.basic-###############################################################################-###############################################################################-###############################################################################--#test var-func = x--describe "infix op" $ do-#test 1-func = x + x--#test long-#pending-func = mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj-  + mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj--#test long keep linemode 1-#pending-func = mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj-  + mweroiuxlskdfjlksj-  + mweroiuxlskdfjlksj--#test long keep linemode 2-#pending-func = mweroiuxlskdfjlksj-  + mweroiuxlskdfjlksj-  + mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj--#test literals-func = 1-func = "abc"-func = 1.1e5-func = 'x'-func = 981409823458910394810928414192837123987123987123--#test lambdacase-{-# LANGUAGE LambdaCase #-}-func = \case-  FooBar -> x-  Baz -> y--#test lambda-func = \x -> abc--describe "app" $ do-#test 1-func = klajsdas klajsdas klajsdas--#test 2-func = lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd-  lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd-  lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd--#test 3-func = lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd-  lakjsdlajsdljas-  lakjsdlajsdljas-  lakjsdlajsdljas--###-#group expression.basic.sections-###--#test left-func = (1 +)--#test right-func = (+ 1)--#test left inf-## TODO: this could be improved..-func = (1 `abc`)--#test right inf-func = (`abc` 1)--###-#group tuples-###--#test 1-func = (abc, def)--#test 2-#pending-func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd-  , lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd)--#test let in on single line-foo =-  let longIdentifierForShortValue = 1-  in longIdentifierForShortValue + longIdentifierForShortValue----###############################################################################-###############################################################################-###############################################################################-#group expression.do statements-###############################################################################-###############################################################################-###############################################################################--#test simple-func = do-  stmt-  stmt--#test bind-func = do-  x <- stmt-  stmt x--#test let-func = do-  let x = 13-  stmt x---###############################################################################-###############################################################################-###############################################################################-#group expression.lists-###############################################################################-###############################################################################-###############################################################################--#test monad-comprehension-case-of-func =-  foooooo-    $ [ case-          foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-        of-          _ -> True-      ]---###############################################################################-###############################################################################-###############################################################################-#group expression.multiwayif-###############################################################################-###############################################################################-###############################################################################--#test simple-{-# LANGUAGE MultiWayIf #-}-func = if-  | cond1 -> loooooooooooooooooooooooooooooong expr1-  | cond2 -> loooooooooooooooooooooooooooooong expr2--#test simplenested-{-# LANGUAGE MultiWayIf #-}-func = do-  foo-  bar $ if-    | cond1 -> loooooooooooooooooooooooooooooong expr1-    | cond2 -> loooooooooooooooooooooooooooooong expr2---###############################################################################-###############################################################################-###############################################################################-#group stylisticspecialcases-###############################################################################-###############################################################################-###############################################################################--#test operatorprefixalignment-even-with-multiline-alignbreak-func =-  foo-    $ [ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-      , bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-      ]-    ++ [ccccccccccccccccccccccccccccccccccccccccccccccccccccccccc]--###############################################################################-###############################################################################-###############################################################################-#group module-###############################################################################-###############################################################################-###############################################################################--#test simple-module Main where--#test no-exports-module Main () where--#test one-export-module Main (main) where--#test several-exports-module Main (main, test1, test2) where--#test many-exports-module Main-  ( main-  , test1-  , test2-  , test3-  , test4-  , test5-  , test6-  , test7-  , test8-  , test9-  )-where--#test exports-with-comments-module Main-  ( main-  -- main-  , test1-  , test2-  -- Test 3-  , test3-  , test4-  -- Test 5-  , test5-  -- Test 6-  )-where--#test simple-export-with-things-module Main (Test(..)) where--#test simple-export-with-module-contents-module Main (module Main) where--#test export-with-things-module Main (Test(Test, a, b)) where--#test export-with-empty-thing-module Main (Test()) where--#test empty-with-comment--- Intentionally left empty--###############################################################################-###############################################################################-###############################################################################-#group import-###############################################################################-###############################################################################-###############################################################################--#test simple-import-import Data.List--#test simple-import-alias-import Data.List as L--#test simple-qualified-import-import qualified Data.List--#test simple-qualified-import-alias-import qualified Data.List as L--#test simple-safe-import safe Data.List as L--#test simple-source-import {-# SOURCE #-} Data.List ()--#test simple-safe-qualified-import safe qualified Data.List hiding (nub)--#test simple-safe-qualified-source-import {-# SOURCE #-} safe qualified Data.List--#test simple-qualified-package-import qualified "base" Data.List--#test qualifier-effect-import {-# SOURCE #-} safe qualified "base" Data.List as L-import {-# SOURCE #-} safe qualified "base" Data.List ()-import {-# SOURCE #-} safe qualified Data.List hiding ()--#test instances-only-import qualified Data.List ()--#test one-element-import Data.List (nub)--#test several-elements-import Data.List (nub, foldl', indexElem)--#test a-ridiculous-amount-of-elements-import Test-  ( Long-  , list-  , with-  , items-  , that-  , will-  , not-  , quite-  , fit-  , onA-  , single-  , line-  , anymore-  )--#test with-things-import Test (T, T2(), T3(..), T4(T4), T5(T5, t5), T6((<|>)), (+))--#test hiding-import Test hiding ()-import Test as T hiding ()--#test long-module-name-simple-import TestJustShortEnoughModuleNameLikeThisOne ()-import TestJustAbitToLongModuleNameLikeThisOneIs ()-import MoreThanSufficientlyLongModuleNameWithSome-  (items, that, will, not, fit, inA, compact, layout)--#test long-module-name-as-import TestJustShortEnoughModuleNameLikeThisOn as T-import TestJustAbitToLongModuleNameLikeThisOneI as T--#test long-module-name-hiding-import TestJustShortEnoughModuleNameLike hiding ()-import TestJustAbitToLongModuleNameLikeTh hiding ()--#test long-module-name-simple-items-import MoreThanSufficientlyLongModuleNameWithSome-  (items, that, will, not, fit, inA, compact, layout)--#test long-module-name-hiding-items-import TestJustShortEnoughModuleNameLike hiding (abc, def, ghci, jklm)--#test import-with-comments--- Test-import Data.List (nub) -- Test-{- Test -}-import qualified Data.List as L (foldl') {- Test -}--#test import-with-comments-2--import Test-  ( abc-  , def-  -- comment-  )--#test import-with-comments-3--import Test-  ( abc-  -- comment-  )--#test import-with-comments-4-import Test-  ( abc-  -- comment-  , def-  , ghi-  {- comment -}-  , jkl-  -- comment-  )---- Test-import Test (test)--#test import-with-comments-5-import Test-  ( -- comment-  )--#test long-bindings-import Test (longbindingNameThatoverflowsColum)-import Test (Long(List, Of, Things))--#test things-with-with-comments-import Test-  ( Thing-    ( With-    -- Comments-    , and-    -- also-    , items-    -- !-    )-  )-import Test-  ( Thing-    ( Item-    -- and Comment-    )-  )-import Test-  ( Thing-    ( With-    -- Comments-    , and-    -- also-    , items-    -- !-    )-  )--#test prefer-dense-empty-list-import VeryLongModuleNameThatCouldEvenCauseAnEmptyBindingListToExpandIntoMultipleLine-  ()--#test preamble full-preamble-{-# LANGUAGE BangPatterns #-}--{-- - Test module- -}-module Test-  ( test1-  -- ^ test-  , test2-  -- | test-  , test3-  , test4-  , test5-  , test6-  , test7-  , test8-  , test9-  , test10-  )-where---- Test-import Data.List (nub) -- Test-{- Test -}-import qualified Data.List as L (foldl') {- Test -}---- Test-import Test (test)--###############################################################################-###############################################################################-###############################################################################-#group regression-###############################################################################-###############################################################################-###############################################################################--#test newlines-comment-func = do-  abc <- foo----abc-return ()--#test parenthesis-around-unit-func = (())--#test let-defs indentation-func = do-  let-    foo True = True-    foo _ = False-  return ()--#test let-defs no indent-func = do-  let-    foo True = True-    foo _ = False-  return ()--#test let-defs no indent-func = do-  let-    foo = True-    b = False-  return ()--#test let-defs no indent-func =-  let-    foo = True-    b = False-  in return ()--#test record update indentation 1-func = do-  s <- mGet-  mSet $ s { _lstate_indent = _lstate_indent state }--#test record update indentation 2-func = do-  s <- mGet-  mSet $ s-    { _lstate_indent = _lstate_indent state-    , _lstate_foo = _lstate_foo state-    }--#test record update indentation 3-func = do-  s <- mGet-  mSet $ s-    { _lstate_indent = _lstate_indent lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-    , _lstate_foo = _lstate_foo kasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-    }--#test record construction 1-func = Foo {_lstate_indent = _lstate_indent state}--#test record construction 2-func = Foo-  { _lstate_indent = _lstate_indent lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  , _lstate_foo = _lstate_foo lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-  }--#test record construction 3-func = do-  Foo-    { _lstate_indent = _lstate_indent lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-    , _lstate_foo = _lstate_foo lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd-    }--#test post-indent comment-func = do--- abc-  -- def-  return ()--#test post-unindent comment-func = do-  do-    return ()-    -- abc-  -- def-  return ()--#test CPP empty comment case-#pending CPP parsing needs fixing for roundTripEqual-{-# LANGUAGE CPP #-}-module Test where-func = do-#if FOO-  let x = 13-#endif-  stmt x--## really, the following should be handled by forcing the Alt to multiline-## because there are comments. as long as this is not implemented though,-## we should ensure the trivial solution works.-#test comment inline placement (temporary)-func-  :: Int -- basic indentation amount-  -> Int -- currently used width in current line (after indent)-         -- used to accurately calc placing of the current-line-  -> LayoutDesc-  -> Int--#test some indentation thingy-func =-  (lkjadljasldjalskdjaldjalsdjkalsdjlaksdjlasjdlajsaldskj-  $ abc-  $ def-  $ ghi-  $ jkl-  )--#test parenthesized operator-buildG bounds0 edges0 = accumArray (flip (:)) [] bounds0 (map reassoc edges0)-  where reassoc (v, e, w) = (v, (e, w))--#test record pattern matching stuff-downloadRepoPackage = case repo of-  RepoLocal {..} -> return ()-  RepoLocal { abc } -> return ()-  RepoLocal{} -> return ()--#test do let comment indentation level problem-func = do-  let-    (primaryPkg, otherPkgs) = selectPrimaryLocalPackage pwd pkgs'-    (bproblems, x) = resolveBuildTargets primaryPkg otherPkgs utargets''-    -- default local dir target if there's no given target-    utargets'' = "foo"-  return ()--#test list comprehension comment placement-func =-  [ (thing, take 10 alts) --TODO: select best ones-  | (thing, _got, alts@(_ : _)) <- nosuchFooThing-  , gast <- award-  ]--#test if-then-else comment placement-func = if x-  then if y -- y is important-    then foo-    else bar-  else Nothing--#test qualified infix pattern-#pending "TODO"-wrapPatPrepend pat prepElem = do-  patDocs <- layoutPat pat-  case Seq.viewl patDocs of-    Seq.EmptyL -> return $ Seq.empty-    x1 Seq.:< xR -> do-      x1' <- docSeq [prepElem, return x1]-      return $ x1' Seq.<| xR--#test type signature multiline forcing issue-layoutWriteNewlineBlock-  :: ( MonadMultiWriter Text.Builder.Builder m-     , MonadMultiState LayoutState m-     , MonadMultiWriter (Seq String) m-     )-  => m ()--#test multiwayif proper indentation-{-# LANGUAGE MultiWayIf #-}-readMergePersConfig path shouldCreate conf = do-  exists <- liftIO $ System.Directory.doesFileExist path-  if-    | exists -> do-      contents <- liftIO $ ByteString.readFile path -- no lazy IO, tyvm.-      fileConf <- case Data.Yaml.decodeEither contents of-        Left e -> do-          liftIO-            $ putStrErrLn-            $ "error reading in brittany config from "-            ++ path-            ++ ":"-          liftIO $ putStrErrLn e-          mzero-        Right x -> return x-      return $ fileConf Semigroup.<> conf-    | shouldCreate -> do-      liftIO $ ByteString.writeFile path $ Data.Yaml.encode $ cMap-        (Option . Just . runIdentity)-        staticDefaultConfig-      return $ conf-    | otherwise -> do-      return conf--#test nested pattern alignment issue"-func = BuildReport- where-  convertInstallOutcome = case result of-    Left BR.PlanningFailed -> PlanningFailed-    Left (BR.DependentFailed p) -> DependencyFailed p-    Left (BR.DownloadFailed _) -> DownloadFailed-    Left (BR.UnpackFailed _) -> UnpackFailed-    Left (BR.ConfigureFailed _) -> ConfigureFailed-    Left (BR.BuildFailed _) -> BuildFailed-    Left (BR.TestsFailed _) -> TestsFailed-    Left (BR.InstallFailed _) -> InstallFailed-    Right (BR.BuildOk _ _ _) -> InstallOk--#test nested pattern alignment issue"-func = BuildReport- where-  convertInstallOutcome = case result of-    Left BR.PlanningFailed -> PlanningFailed-    Left (BR.DependentFailed p) -> DependencyFailed p-    Left (BR.DownloadFailed _) -> DownloadFailed-    Left (BR.UnpackFailed _) -> UnpackFailed-    Left (BR.ConfigureFailed _) -> ConfigureFailed-    Left (BR.BuildFailed _) -> BuildFailed-    Left (BR.TestsFailed _) -> TestsFailed-    Left (BR.InstallFailed _) -> InstallFailed-    Right (BR.BuildOk _ _ _) -> InstallOk--#test partially overflowing alignment issue"-showPackageDetailedInfo pkginfo =-  renderStyle (style { lineLength = 80, ribbonsPerLine = 1 })-    $ char '*'-    $+$ something-          [ entry "Synopsis" synopsis hideIfNull reflowParagraphs-          , entry-            "Versions available"-            sourceVersions-            (altText null "[ Not available from server ]")-            (dispTopVersions 9 (preferredVersions pkginfo))-          , entry-            "Versions installed"-            installedVersions-            (altText-              null-              (if hasLib pkginfo then "[ Not installed ]" else "[ Unknown ]")-            )-            (dispTopVersions 4 (preferredVersions pkginfo))-          , entry "Homepage" homepage orNotSpecified text-          , entry "Bug reports" bugReports orNotSpecified text-          , entry "Description" description hideIfNull reflowParagraphs-          , entry "Category" category hideIfNull text-          , entry "License" license alwaysShow disp-          , entry "Author" author hideIfNull reflowLines-          , entry "Maintainer" maintainer hideIfNull reflowLines-          , entry "Source repo" sourceRepo orNotSpecified text-          , entry "Executables" executables hideIfNull (commaSep text)-          , entry "Flags" flags hideIfNull (commaSep dispFlag)-          , entry "Dependencies" dependencies hideIfNull (commaSep dispExtDep)-          , entry "Documentation" haddockHtml showIfInstalled text-          , entry "Cached" haveTarball alwaysShow dispYesNo-          , if not (hasLib pkginfo)-            then empty-            else text "Modules:"-              $+$ nest 4 (vcat (map disp . sort . modules $ pkginfo))-          ]--#test issue 7a-isValidPosition position-  | validX && validY = Just position-  | otherwise = Nothing--#test issue-6-pattern-linebreak-validity-## this is ugly, but at least syntactically valid.-foo = Reflex.runSpiderHost $ ReflexHost.hostApp $ do-  (inputEvent :: Reflex.Event Reflex.Spider String, inputFire :: String-    -> IO Bool) <--    ReflexHost.newExternalEvent-  liftIO . forkIO . forever $ getLine >>= inputFire-  ReflexHost.performEvent_ $ fmap (liftIO . putStrLn) inputEvent--#test issue 16-foldrDesc f z = unSwitchQueue $ \q ->-  switch (Min.foldrDesc (f unTaggedF) z q) (Min.foldrAsc (f unTaggedF) z q)--#test issue 18-autocheckCases =-  [ ("Never Deadlocks", representative deadlocksNever)-  , ("No Exceptions", representative exceptionsNever)-  , ("Consistent Result", alwaysSame) -- already representative-  ]--#test issue 18b-autocheckCases =-  [ ("Never Deadlocks", representative deadlocksNever)-  , ("No Exceptions", representative exceptionsNever)-  , ( "Consistent Result"-    , alwaysSame -- already representative-    )-  ]--#test issue 18c-func =-  [ (abc, (1111, 1111))-  , (def, (2, 2))-  , foo -- comment-  ]--#test issue 26-foo a b = g a b -- fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-  where g a b = b + b * a--#test issue 26b-foo a b = g a b where g a b = b + b * a -- fooooooooooooooooooooooooooooooooooo--#test aggressive alignment 1-func = do-  abc <- expr-  abcccccccccccccccccc <- expr-  abcccccccccccccccccccccccccccccccccccccccccc <- expr-  abccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc <- expr--#test example alignment 1-func (MyLongFoo abc def) = 1-func (Bar a d) = 2-func _ = 3--#test listcomprehension-case-of-parserCompactLocation =-  [ try-      $ [ ParseRelAbs (Text.Read.read digits) _ _-        | digits <- many1 digit-        , rel1 :: Maybe (Either Int (Ratio Int)) <- optionMaybe-          [ case divPart of-              Nothing -> Left $ Text.Read.read digits-              Just ddigits ->-                Right $ Text.Read.read digits % Text.Read.read ddigits-          | digits <- many1 digit-          , divPart <- optionMaybe (string "/" *> many1 digit)-          ]-        ]-  ]--#test opapp-specialcasing-1-func = fooooooooooooooooooooooooooooooooo $ foooooooooooooooooooooooooooooooo-  foooooooooooooooooooooooooooooooo-  foooooooooooooooooooooooooooooooo--#test opapp-specialcasing-2-func =-  fooooooooooooooooooooooooooooooooo-    + foooooooooooooooooooooooooooooooo-        foooooooooooooooooooooooooooooooo-        foooooooooooooooooooooooooooooooo--#test opapp-specialcasing-3-func = fooooooooooooooooooooooooooooooooo + foooooooooooooooooooooooooooooooo-  [ foooooooooooooooooooooooooooooooo-  , foooooooooooooooooooooooooooooooo-  , foooooooooooooooooooooooooooooooo-  ]--#test opapp-indenting-parserPrim =-  [ r-  | r <--    [ SGPPrimFloat $ bool id (0 -) minus $ readGnok-        "parserPrim"-        (d1 ++ d2 ++ d3 ++ d4)-    | d2 <- string "."-    , d3 <- many1 (oneOf "0123456789")-    , _ <- string "f"-    ]-    <|> [ SGPPrimFloat $ bool id (0 -) minus $ fromIntegral-            (readGnok "parserPrim" d1 :: Integer)-        | _ <- string "f"-        ]-    <|> [ SGPPrimInt $ bool id (0 -) minus $ fromIntegral-            (readGnok "parserPrim" d1 :: Integer)-        | _ <- string "i"-        ]-  ]--#test another-parspacing-testcase--samples = (SV.unpackaaaaadat) <&> \f ->-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--#test recordupd-singleline-bug--runBrittany tabSize text = do-  let-    config' = staticDefaultConfig-    config = config'-      { _conf_layout = (_conf_layout config')-        { _lconfig_indentAmount = coerce tabSize-        }-      , _conf_forward = forwardOptionsSyntaxExtsEnabled-      }-  parsePrintModule config text--#test issue 38--{-# LANGUAGE TypeApplications #-}-foo = bar @Baz--#test comment-before-BDCols-{-# LANGUAGE TypeApplications #-}-layoutPatternBindFinal alignmentToken binderDoc mPatDoc clauseDocs = do-  docAlt-    $  -- one-line solution-      [ docCols-          (ColBindingLine alignmentToken)-          [ docSeq (patPartInline ++ [guardPart])-          , docSeq-            [ appSep $ return binderDoc-            , docForceSingleline $ return body-            , wherePart-            ]-          ]-      | not hasComments-      , [(guards, body, _bodyRaw)] <- [clauseDocs]-      , let guardPart = singleLineGuardsDoc guards-      , wherePart <- case mWhereDocs of-        Nothing -> return @[] $ docEmpty-        Just [w] -> return @[] $ docSeq-          [ docSeparator-          , appSep $ docLit $ Text.pack "where"-          , docSetIndentLevel $ docForceSingleline $ return w-          ]-        _ -> []-      ]-    ++ -- one-line solution + where in next line(s)-       [ docLines-         $ [ docCols-               (ColBindingLine alignmentToken)-               [ docSeq (patPartInline ++ [guardPart])-               , docSeq-                 [appSep $ return binderDoc, docForceParSpacing $ return body]-               ]-           ]-         ++ wherePartMultiLine-       | [(guards, body, _bodyRaw)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       , Data.Maybe.isJust mWhereDocs-       ]-    ++ -- two-line solution + where in next line(s)-       [ docLines-         $ [ docForceSingleline-             $ docSeq (patPartInline ++ [guardPart, return binderDoc])-           , docEnsureIndent BrIndentRegular $ docForceSingleline $ return-             body-           ]-         ++ wherePartMultiLine-       | [(guards, body, _bodyRaw)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       ]--#test comment-testcase-17-{-# LANGUAGE MultiWayIf #-}-func = do-  let-    foo = if-      | Constuctoooooooooooooooooooooooooooooooooooor `elem` artics -- TODO-                                                                    -> max-        (defLen - 0.2) -- TODO-        (defLen * 0.8)-      | otherwise -> max (defLen - 0.05) (defLen * 0.95) -- TODO-  return True--#test issue 49--foo n = case n of-  1 -> True-  -1 -> False--bar n = case n of-  (-2, -2) -> (-2, -2)--#test issue 48 a--foo =-  let-    a = b@1-    cccc = ()-  in foo--#test issue 48 b--{-# LANGUAGE TypeApplications #-}-foo =-  let-    a = b @1-    cccc = ()-  in foo---###############################################################################-###############################################################################-###############################################################################-#group pending-###############################################################################-###############################################################################-###############################################################################----## this testcase is not about idempotency, but about _how_ the output differs-## from the input; i cannot really express this yet with the current-## test-suite.-## #test ayaz-##-## myManageHook =-##   composeOne [isFullscreen -?> doFullFloat, isDialog -?> doFloat, transience]-##     <+> composeAll-##           [ className =? "Pidgin" --> doFloat-##           , className =? "XCalc" --> doFloat-##           -- plan9port's acme-##           , className =? "acme" --> doFloat-##           -- Acme with Vi bindings editor-##           , title =? "ED" --> doFloat-##           , title =? "wlc-x11" --> doFloat-##           , className =? "Skype" --> doFloat-##           , className =? "ffplay" --> doFloat-##           , className =? "mpv" --> doFloat-##           , className =? "Plugin-container" --> doFloat -- Firefox flash, etc.-##           -- Firefox works well tiled, but it has dialog windows we want to float.-##           , appName =? "Browser" --> doFloat-##           ]-##  where-##   role = stringProperty "WM_WINDOW_ROLE"
src-unittests/TestUtils.hs view
@@ -42,9 +42,9 @@  defaultTestConfig :: Config defaultTestConfig = Config-  { _conf_version = _conf_version staticDefaultConfig-  , _conf_debug   = _conf_debug staticDefaultConfig-  , _conf_layout  = LayoutConfig+  { _conf_version                   = _conf_version staticDefaultConfig+  , _conf_debug                     = _conf_debug staticDefaultConfig+  , _conf_layout                    = LayoutConfig     { _lconfig_cols                      = coerce (80 :: Int)     , _lconfig_indentPolicy              = coerce IndentPolicyFree     , _lconfig_indentAmount              = coerce (2 :: Int)@@ -60,11 +60,11 @@     , _lconfig_reformatModulePreamble    = coerce True     , _lconfig_allowSingleLineExportList = coerce True     }-  , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig)+  , _conf_errorHandling             = (_conf_errorHandling staticDefaultConfig)     { _econf_ExactPrintFallback = coerce ExactPrintFallbackModeNever     }-  , _conf_preprocessor = (_conf_preprocessor staticDefaultConfig)-  , _conf_forward      = ForwardOptions-    { _options_ghc = Identity []-    }+  , _conf_preprocessor              = (_conf_preprocessor staticDefaultConfig)+  , _conf_forward = ForwardOptions {_options_ghc = Identity []}+  , _conf_roundtrip_exactprint_only = coerce False+  , _conf_obfuscate = coerce False   }
src/Language/Haskell/Brittany/Internal.hs view
@@ -8,6 +8,8 @@    -- re-export from utils:   , parseModule   , parseModuleFromString+  , extractCommentConfigs+  , getTopLevelDeclNameMap   ) where @@ -22,7 +24,10 @@ import           Data.Data import           Control.Monad.Trans.Except import           Data.HList.HList+import qualified Data.Yaml+import qualified Data.ByteString.Char8 import           Data.CZipWith+import qualified UI.Butcher.Monadic as Butcher  import qualified Data.Text.Lazy.Builder as Text.Builder @@ -47,15 +52,170 @@  import qualified GHC as GHC hiding (parseModule) import           ApiAnnotation ( AnnKeywordId(..) )-import           RdrName ( RdrName(..) ) import           GHC ( runGhc, GenLocated(L), moduleNameString ) import           SrcLoc ( SrcSpan ) import           HsSyn import qualified DynFlags as GHC import qualified GHC.LanguageExtensions.Type as GHC +import           Data.Char (isSpace)  ++data InlineConfigTarget+    = InlineConfigTargetModule+    | InlineConfigTargetNextDecl    -- really only next in module+    | InlineConfigTargetNextBinding -- by name+    | InlineConfigTargetBinding String++extractCommentConfigs+  :: ExactPrint.Anns+  -> TopLevelDeclNameMap+  -> Either (String, String) InlineConfig+extractCommentConfigs anns (TopLevelDeclNameMap declNameMap) = do+  let+    commentLiness =+      [ ( k+        , [ x+          | (ExactPrint.Comment x _ _, _) <-+            (  ExactPrint.annPriorComments ann+            ++ ExactPrint.annFollowingComments ann+            )+          ]+          ++ [ x+             | (ExactPrint.AnnComment (ExactPrint.Comment x _ _), _) <-+               ExactPrint.annsDP ann+             ]+        )+      | (k, ann) <- Map.toList anns+      ]+  let configLiness = commentLiness <&> second+        (Data.Maybe.mapMaybe $ \line -> do+          l1 <-+            List.stripPrefix "-- BRITTANY" line+            <|> List.stripPrefix "--BRITTANY" line+            <|> List.stripPrefix "-- brittany" line+            <|> List.stripPrefix "--brittany" line+            <|> (List.stripPrefix "{- BRITTANY" line >>= stripSuffix "-}")+          let l2 = dropWhile isSpace l1+          guard+            (  ("@" `isPrefixOf` l2)+            || ("-disable" `isPrefixOf` l2)+            || ("-next" `isPrefixOf` l2)+            || ("{" `isPrefixOf` l2)+            || ("--" `isPrefixOf` l2)+            )+          pure l2+        )+  let+    configParser = Butcher.addAlternatives+      [ ( "commandline-config"+        , \s -> "-" `isPrefixOf` dropWhile (== ' ') s+        , cmdlineConfigParser+        )+      , ( "yaml-config-document"+        , \s -> "{" `isPrefixOf` dropWhile (== ' ') s+        , Butcher.addCmdPart (Butcher.varPartDesc "yaml-config-document")+        $ fmap (\lconf -> (mempty { _conf_layout = lconf }, ""))+        . Data.Yaml.decode+        . Data.ByteString.Char8.pack+          -- TODO: use some proper utf8 encoder instead?+        )+      ]+    parser = do -- we will (mis?)use butcher here to parse the inline config+                -- line.+      let nextDecl = do+            conf <- configParser+            Butcher.addCmdImpl (InlineConfigTargetNextDecl, conf)+      Butcher.addCmd "-next-declaration" nextDecl+      Butcher.addCmd "-Next-Declaration" nextDecl+      Butcher.addCmd "-NEXT-DECLARATION" nextDecl+      let nextBinding = do+            conf <- configParser+            Butcher.addCmdImpl (InlineConfigTargetNextBinding, conf)+      Butcher.addCmd "-next-binding" nextBinding+      Butcher.addCmd "-Next-Binding" nextBinding+      Butcher.addCmd "-NEXT-BINDING" nextBinding+      let disableNextBinding = do+            Butcher.addCmdImpl+              ( InlineConfigTargetNextBinding+              , mempty { _conf_roundtrip_exactprint_only = pure $ pure True }+              )+      Butcher.addCmd "-disable-next-binding" disableNextBinding+      Butcher.addCmd "-Disable-Next-Binding" disableNextBinding+      Butcher.addCmd "-DISABLE-NEXT-BINDING" disableNextBinding+      let disableNextDecl = do+            Butcher.addCmdImpl+              ( InlineConfigTargetNextDecl+              , mempty { _conf_roundtrip_exactprint_only = pure $ pure True }+              )+      Butcher.addCmd "-disable-next-declaration" disableNextDecl+      Butcher.addCmd "-Disable-Next-Declaration" disableNextDecl+      Butcher.addCmd "-DISABLE-NEXT-DECLARATION" disableNextDecl+      Butcher.addCmd "@" $ do+        -- Butcher.addCmd "module" $ do+        --   conf <- configParser+        --   Butcher.addCmdImpl (InlineConfigTargetModule, conf)+        Butcher.addNullCmd $ do+          bindingName <- Butcher.addParamString "BINDING" mempty+          conf        <- configParser+          Butcher.addCmdImpl (InlineConfigTargetBinding bindingName, conf)+      conf <- configParser+      Butcher.addCmdImpl (InlineConfigTargetModule, conf)+  lineConfigss <- configLiness `forM` \(k, ss) -> do+    r <- ss `forM` \s -> case Butcher.runCmdParserSimple s parser of+      Left  err -> Left $ (err, s)+      Right c   -> Right $ c+    pure (k, r)++  let perModule = foldl'+        (<>)+        mempty+        [ conf+        | (_                       , lineConfigs) <- lineConfigss+        , (InlineConfigTargetModule, conf       ) <- lineConfigs+        ]+  let+    perBinding = Map.fromListWith+      (<>)+      [ (n, conf)+      | (k     , lineConfigs) <- lineConfigss+      , (target, conf       ) <- lineConfigs+      , n                     <- case target of+        InlineConfigTargetBinding s -> [s]+        InlineConfigTargetNextBinding | Just name <- Map.lookup k declNameMap ->+          [name]+        _ -> []+      ]+  let+    perKey = Map.fromListWith+      (<>)+      [ (k, conf)+      | (k     , lineConfigs) <- lineConfigss+      , (target, conf       ) <- lineConfigs+      , case target of+        InlineConfigTargetNextDecl -> True+        InlineConfigTargetNextBinding | Nothing <- Map.lookup k declNameMap ->+          True+        _ -> False+      ]++  pure $ InlineConfig+    { _icd_perModule  = perModule+    , _icd_perBinding = perBinding+    , _icd_perKey     = perKey+    }+++getTopLevelDeclNameMap :: GHC.ParsedSource -> TopLevelDeclNameMap+getTopLevelDeclNameMap (L _ (HsModule _name _exports _ decls _ _)) =+  TopLevelDeclNameMap $ Map.fromList+    [ (ExactPrint.mkAnnKey decl, name)+    | decl       <- decls+    , (name : _) <- [getDeclBindingNames decl]+    ]++ -- | Exposes the transformation in an pseudo-pure fashion. The signature -- contains `IO` due to the GHC API not exposing a pure parsing function, but -- there should be no observable effects.@@ -68,15 +228,16 @@ -- may wish to put some proper upper bound on the input's size as a timeout -- won't do. parsePrintModule :: Config -> Text -> IO (Either [BrittanyError] Text)-parsePrintModule configRaw inputText = runExceptT $ do-  let config = configRaw { _conf_debug = _conf_debug staticDefaultConfig }+parsePrintModule configWithDebugs inputText = runExceptT $ do+  let config =+        configWithDebugs { _conf_debug = _conf_debug staticDefaultConfig }   let ghcOptions         = config & _conf_forward & _options_ghc & runIdentity   let config_pp          = config & _conf_preprocessor   let cppMode            = config_pp & _ppconf_CPPMode & confUnpack   let hackAroundIncludes = config_pp & _ppconf_hackAroundIncludes & confUnpack   (anns, parsedSource, hasCPP) <- do     let hackF s = if "#include" `isPrefixOf` s-          then "-- BRITTANY_INCLUDE_HACK " ++ s+          then "-- BRITANY_INCLUDE_HACK " ++ s           else s     let hackTransform = if hackAroundIncludes           then List.intercalate "\n" . fmap hackF . lines'@@ -93,8 +254,10 @@       cppCheckFunc       (hackTransform $ Text.unpack inputText)     case parseResult of-      Left  err -> throwE $ [ErrorInput err]-      Right x   -> pure $ x+      Left  err -> throwE [ErrorInput err]+      Right x   -> pure x+  inlineConf <- either (throwE . (: []) . uncurry ErrorMacroConfig) pure+    $ extractCommentConfigs anns (getTopLevelDeclNameMap parsedSource)   (errsWarns, outputTextL) <- do     let omitCheck =           config@@ -102,10 +265,10 @@             & _econf_omit_output_valid_check             & confUnpack     (ews, outRaw) <- if hasCPP || omitCheck-      then return $ pPrintModule config anns parsedSource-      else lift $ pPrintModuleAndCheck config anns parsedSource+      then return $ pPrintModule config inlineConf anns parsedSource+      else lift $ pPrintModuleAndCheck config inlineConf anns parsedSource     let hackF s = fromMaybe s-          $ TextL.stripPrefix (TextL.pack "-- BRITTANY_INCLUDE_HACK ") s+          $ TextL.stripPrefix (TextL.pack "-- BRITANY_INCLUDE_HACK ") s     pure $ if hackAroundIncludes       then         ( ews@@ -119,6 +282,7 @@       customErrOrder ErrorOutputCheck{}   = 1       customErrOrder ErrorUnusedComment{} = 2       customErrOrder ErrorUnknownNode{}   = 3+      customErrOrder ErrorMacroConfig{}   = 5   let hasErrors =         case config & _conf_errorHandling & _econf_Werror & confUnpack of           False -> 0 < maximum (-1 : fmap customErrOrder errsWarns)@@ -133,10 +297,11 @@ -- can occur. pPrintModule   :: Config+  -> InlineConfig   -> ExactPrint.Anns   -> GHC.ParsedSource   -> ([BrittanyError], TextL.Text)-pPrintModule conf anns parsedModule =+pPrintModule conf inlineConf anns parsedModule =   let     ((out, errs), debugStrings) =       runIdentity@@ -146,6 +311,7 @@         $ MultiRWSS.withMultiWriterW         $ MultiRWSS.withMultiReader anns         $ MultiRWSS.withMultiReader conf+        $ MultiRWSS.withMultiReader inlineConf         $ MultiRWSS.withMultiReader (extractToplevelAnns parsedModule anns)         $ do             traceIfDumpConf "bridoc annotations raw" _dconf_dump_annotations@@ -169,12 +335,13 @@ -- if it does not. pPrintModuleAndCheck   :: Config+  -> InlineConfig   -> ExactPrint.Anns   -> GHC.ParsedSource   -> IO ([BrittanyError], TextL.Text)-pPrintModuleAndCheck conf anns parsedModule = do+pPrintModuleAndCheck conf inlineConf anns parsedModule = do   let ghcOptions     = conf & _conf_forward & _options_ghc & runIdentity-  let (errs, output) = pPrintModule conf anns parsedModule+  let (errs, output) = pPrintModule conf inlineConf anns parsedModule   parseResult <- parseModuleFromString ghcOptions                                        "output"                                        (\_ -> return $ Right ())@@ -193,28 +360,34 @@   parseResult <- ExactPrint.Parsers.parseModuleFromString filename inputStr   case parseResult of     Left  (_   , s           ) -> return $ Left $ "parsing error: " ++ s-    Right (anns, parsedModule) -> do+    Right (anns, parsedModule) -> runExceptT $ do+      inlineConf <-+        case extractCommentConfigs anns (getTopLevelDeclNameMap parsedModule) of+          Left  err -> throwE $ "error in inline config: " ++ show err+          Right x   -> pure x       let omitCheck =             conf               &  _conf_errorHandling               .> _econf_omit_output_valid_check               .> confUnpack       (errs, ltext) <- if omitCheck-        then return $ pPrintModule conf anns parsedModule-        else pPrintModuleAndCheck conf anns parsedModule-      return $ if null errs-        then Right $ TextL.toStrict $ ltext+        then return $ pPrintModule conf inlineConf anns parsedModule+        else lift $ pPrintModuleAndCheck conf inlineConf anns parsedModule+      if null errs+        then pure $ TextL.toStrict $ ltext         else-          let errStrs = errs <&> \case-                ErrorInput         str -> str-                ErrorUnusedComment str -> str-                LayoutWarning      str -> str-                ErrorUnknownNode str _ -> str-                ErrorOutputCheck       -> "Output is not syntactically valid."-          in  Left $ "pretty printing error(s):\n" ++ List.unlines errStrs+          let+            errStrs = errs <&> \case+              ErrorInput         str -> str+              ErrorUnusedComment str -> str+              LayoutWarning      str -> str+              ErrorUnknownNode str _ -> str+              ErrorMacroConfig str _ -> "when parsing inline config: " ++ str+              ErrorOutputCheck       -> "Output is not syntactically valid."+          in  throwE $ "pretty printing error(s):\n" ++ List.unlines errStrs  --- this approach would for with there was a pure GHC.parseDynamicFilePragma.+-- this approach would for if there was a pure GHC.parseDynamicFilePragma. -- Unfortunately that does not exist yet, so we cannot provide a nominally -- pure interface. @@ -248,12 +421,25 @@ --           Left $ "pretty printing error(s):\n" ++ List.unlines errStrs --         else return $ TextL.toStrict $ Text.Builder.toLazyText out -ppModule :: GenLocated SrcSpan (HsModule RdrName) -> PPM ()+toLocal :: Config -> ExactPrint.Anns -> PPMLocal a -> PPM a+toLocal conf anns m = do+  (x, write) <- lift $ MultiRWSS.runMultiRWSTAW (conf :+: anns :+: HNil) HNil $ m+  MultiRWSS.mGetRawW >>= \w -> MultiRWSS.mPutRawW (w `mappend` write)+  pure x++ppModule :: GenLocated SrcSpan (HsModule GhcPs) -> PPM () ppModule lmod@(L _loc _m@(HsModule _name _exports _ decls _ _)) = do   post <- ppPreamble lmod   decls `forM_` \decl -> do-    filteredAnns <- mAsk <&> \annMap ->-      Map.findWithDefault Map.empty (ExactPrint.mkAnnKey decl) annMap+    let declAnnKey       = ExactPrint.mkAnnKey decl+    let declBindingNames = getDeclBindingNames decl+    inlineConf <- mAsk+    let inlineModConf = _icd_perModule inlineConf+    let mDeclConf     = Map.lookup declAnnKey $ _icd_perKey inlineConf+    let mBindingConfs =+          declBindingNames <&> \n -> Map.lookup n $ _icd_perBinding inlineConf+    filteredAnns <- mAsk+      <&> \annMap -> Map.findWithDefault Map.empty declAnnKey annMap      traceIfDumpConf "bridoc annotations filtered/transformed"                     _dconf_dump_annotations@@ -261,13 +447,20 @@      config <- mAsk -    MultiRWSS.withoutMultiReader $ do-      MultiRWSS.mPutRawR $ config :+: filteredAnns :+: HNil-      ppDecl decl+    let config' = cZipWith fromOptionIdentity config $ mconcat+          (inlineModConf : (catMaybes (mBindingConfs ++ [mDeclConf])))++    let exactprintOnly = config' & _conf_roundtrip_exactprint_only & confUnpack+    toLocal config' filteredAnns $ do+      bd <- briDocMToPPM $ if exactprintOnly+        then briDocByExactNoComment decl+        else layoutDecl decl+      layoutBriDoc bd+   let finalComments = filter-        ( fst .> \case+        (fst .> \case           ExactPrint.AnnComment{} -> True-          _                             -> False+          _                       -> False         )         post   post `forM_` \case@@ -275,54 +468,28 @@       ppmMoveToExactLoc l       mTell $ Text.Builder.fromString cmStr     (ExactPrint.G AnnEofPos, (ExactPrint.DP (eofZ, eofX))) ->-      let-        folder (acc, _) (kw, ExactPrint.DP (y, x)) = case kw of-          ExactPrint.AnnComment cm-            | GHC.RealSrcSpan span <- ExactPrint.commentIdentifier cm-            -> ( acc + y + GHC.srcSpanEndLine span - GHC.srcSpanStartLine span-               , x + GHC.srcSpanEndCol span - GHC.srcSpanStartCol span-               )-          _ -> (acc + y, x)-        (cmY, cmX) = foldl' folder (0, 0) finalComments-      in-        ppmMoveToExactLoc $ ExactPrint.DP (eofZ - cmY, eofX - cmX)+      let folder (acc, _) (kw, ExactPrint.DP (y, x)) = case kw of+            ExactPrint.AnnComment cm+              | GHC.RealSrcSpan span <- ExactPrint.commentIdentifier cm+              -> ( acc + y + GHC.srcSpanEndLine span - GHC.srcSpanStartLine span+                 , x + GHC.srcSpanEndCol span - GHC.srcSpanStartCol span+                 )+            _ -> (acc + y, x)+          (cmY, cmX) = foldl' folder (0, 0) finalComments+      in  ppmMoveToExactLoc $ ExactPrint.DP (eofZ - cmY, eofX - cmX)     _ -> return () -withTransformedAnns :: Data ast => ast -> PPMLocal () -> PPMLocal ()-withTransformedAnns ast m = do-  -- TODO: implement `local` for MultiReader/MultiRWS-  readers@(conf :+: anns :+: HNil) <- MultiRWSS.mGetRawR-  MultiRWSS.mPutRawR (conf :+: f anns :+: HNil)-  m-  MultiRWSS.mPutRawR readers- where-  f anns =-    let ((), (annsBalanced, _), _) =-          ExactPrint.runTransform anns (commentAnnFixTransformGlob ast)-    in  annsBalanced +getDeclBindingNames :: LHsDecl GhcPs -> [String]+getDeclBindingNames (L _ decl) = case decl of+  SigD (TypeSig ns _) -> ns <&> \(L _ n) -> Text.unpack (rdrNameToText n)+  ValD (FunBind (L _ n) _ _ _ _) -> [Text.unpack $ rdrNameToText n]+  _ -> [] -ppDecl :: LHsDecl RdrName -> PPMLocal ()-ppDecl d@(L loc decl) = case decl of-  SigD sig -> -- trace (_sigHead sig) $-              withTransformedAnns d $ do-    -- runLayouter $ Old.layoutSig (L loc sig)-    briDoc <- briDocMToPPM $ layoutSig (L loc sig)-    layoutBriDoc briDoc-  ValD bind -> -- trace (_bindHead bind) $-               withTransformedAnns d $ do-    -- Old.layoutBind (L loc bind)-    briDoc <- briDocMToPPM $ do-      eitherNode <- layoutBind (L loc bind)-      case eitherNode of-        Left  ns -> docLines $ return <$> ns-        Right n  -> return n-    layoutBriDoc briDoc-  _ -> briDocMToPPM (briDocByExactNoComment d) >>= layoutBriDoc  -- Prints the information associated with the module annotation -- This includes the imports-ppPreamble :: GenLocated SrcSpan (HsModule RdrName)+ppPreamble :: GenLocated SrcSpan (HsModule GhcPs)            -> PPM [(ExactPrint.KeywordId, ExactPrint.DeltaPos)] ppPreamble lmod@(L loc m@(HsModule _ _ _ _ _ _)) = do   filteredAnns <- mAsk <&> \annMap ->@@ -380,9 +547,7 @@     $ annsDoc filteredAnns'    if shouldReformatPreamble-    then MultiRWSS.withoutMultiReader $ do-      MultiRWSS.mPutRawR $ config :+: filteredAnns' :+: HNil-      withTransformedAnns lmod $ do+    then toLocal config filteredAnns' $ withTransformedAnns lmod $ do         briDoc <- briDocMToPPM $ layoutModule lmod         layoutBriDoc briDoc     else@@ -390,13 +555,13 @@       in  MultiRWSS.withMultiReader filteredAnns' $ processDefault emptyModule   return post -_sigHead :: Sig RdrName -> String+_sigHead :: Sig GhcPs -> String _sigHead = \case   TypeSig names _ ->     "TypeSig " ++ intercalate "," (Text.unpack . lrdrNameToText <$> names)   _ -> "unknown sig" -_bindHead :: HsBind RdrName -> String+_bindHead :: HsBind GhcPs -> String _bindHead = \case   FunBind fId _ _ _ [] -> "FunBind " ++ (Text.unpack $ lrdrNameToText $ fId)   PatBind _pat _ _ _ ([], []) -> "PatBind smth"
src/Language/Haskell/Brittany/Internal/Backend.hs view
@@ -56,7 +56,7 @@  instance Show ColInfo where   show ColInfoStart = "ColInfoStart"-  show ColInfoNo{} = "ColInfoNo{}"+  show (ColInfoNo bd) = "ColInfoNo " ++ show (take 30 (show (briDocToDoc bd)) ++ "..")   show (ColInfo ind sig list) = "ColInfo " ++ show ind ++ " " ++ show sig ++ " " ++ show list  data ColBuildState = ColBuildState@@ -345,6 +345,81 @@     BDNonBottomSpacing bd   -> rec bd     BDDebug _ bd            -> rec bd +-- In theory+-- =========++-- .. this algorithm works roughly in these steps:+--+-- 1. For each line, get the (nested) column info, descending as far as+--    BDCols nodes go. The column info is a (rose) tree where the leafs+--    are arbitrary (non-BDCols) BriDocs.+-- 2. Walk through the lines and compare its column info with that of its+--    predecessor. If both are non-leafs and the column "signatures" align+--    (they don't align e.g. when they are totally different syntactical+--    structures or the number of children differs), mark these parts of+--    the two tree structures as connected and recurse to its children+--    (i.e. again comparing the children in this line with the children in+--    the previous line).+-- 3. What we now have is one tree per line, and connections between "same"+--    nodes between lines. These connection can span multiple lines.+--    We next look at spacing information. This is available at the leafs,+--    but in this step we aggregate _over connections_. At the top level, this+--    gives us one piece of data: How long would each line be, if we fully+--    aligned everything (kept all connections "active"). In contrast to+--    just taking the sum of all leafs for each tree, this line length includes+--    the spaces used for alignment.+-- 4. Treat those lines where alignment would result in overflowing of the+--    column limit. This "treatment" is currently configurable, and can e.g.+--    mean:+--    a) we stop alignment alltogether,+--    b) we remove alignment just from the overflowing lines,+--    c) we reduce the number of spaces inserted in overflowing lines using+--       some technique to make them not overflow, but without reducing the+--       space insertion to zero,+--    d) don't do anything+-- 5. Actually print the lines, walking over each tree and inserting spaces+--    according to the info and decisions gathered in the previous steps.+--+-- Possible improvements+-- =====================+--+-- - If alignment is disabled for specific lines, the aggregated per-connection+--   info of those lines is still retained and not recalculated. This can+--   result in spaces being inserted to create alignment with a line that+--   would overflow and thus gets disabled entirely.+--   An better approach would be to repeat step 3 after marking overflowing+--   lines as such, and not include the overflowing spacings as references+--   for non-overflowing ones. In the simplest case one additional iteration+--   would suffice, e.g. 1-2-3-4-3-5, but it would also be possible to refine+--   this and first remove alignment in the deepest parts of the tree for+--   overflowing lines, repeating and moving upwards until no lines are+--   anymore overflowing.+--   Further, it may make sense to break up connections when overflowing would+--   occur.+-- - It may also make sense to not filter all overflowing lines, but remove+--   them one-by-one and in each step recalculate the aggregated connection+--   spacing info. Because removing one overflowing line from the calculation+--   may very well cause another previously overflowing line to not overflow+--   any longer.+--   There is also a nasty optimization problem hiding in there (find the+--   minimal amount of alignment disabling that results in no overflows)+--   but that is overkill.+--+--   (with both these improvements there would be quite some repetition between+--   steps 3 and 4, but it should be possible to ensure termination. Still,+--   performance might become an issue as such an approach is not necessarily+--   linear in bridoc size any more.)+--+-- In practice+-- ===========+--+-- .. the current implementation is somewhat sloppy. Steps 1 and 2+-- are executed in one step, step 3 already applies one strategy that disables+-- certain connections (see `_lconfig_alignmentLimit`) and step 4 does some+-- of the calculations one might expect to occur in step 3. Steps 4 and 5+-- are executed in the same recursion, too.+-- Also, _lconfig_alignmentLimit really is itself a hack that hides the issue+-- mentioned in the first "possible improvement". alignColsLines :: LayoutConstraints m => [BriDoc] -> m () alignColsLines bridocs = do -- colInfos `forM_` \colInfo -> do   -- tellDebugMess ("alignColsLines: at " ++ take 100 (show $ briDocToDoc $ head bridocs))@@ -358,11 +433,12 @@   alignBreak <-     mAsk <&> _conf_layout .> _lconfig_alignmentBreakOnMultiline .> confUnpack   case () of-    _ ->+    _ -> do+      -- tellDebugMess ("processedMap: " ++ show processedMap)       sequence_         $   List.intersperse layoutWriteEnsureNewlineBlock         $   colInfos-        <&> processInfo processedMap+        <&> processInfo colMax processedMap      where       (colInfos, finalState) =         StateS.runState (mergeBriDocs bridocs) (ColBuildState IntMapS.empty 0)@@ -393,10 +469,9 @@                 Nothing           -> 0                 Just (_, maxs, _) -> sum maxs             maxCols = {-Foldable.foldl1 maxZipper-}-              fmap colAggregation $ transpose $ Foldable.toList-              --  $ trace ("colss=" ++ show colss ++ " for" ++ take 100 (show $ briDocToDoc $ head bridocs))-              colss-            (_, posXs) = mapAccumL (\acc x -> (acc + x, acc)) curX maxCols+              fmap colAggregation $ transpose $ Foldable.toList colss+            (_, posXs) = -- trace ("colss=" ++ show colss ++ ", maxCols=" ++ show maxCols ++ " for " ++ take 100 (show $ briDocToDoc $ head bridocs)) $+                         mapAccumL (\acc x -> (acc + x, acc)) curX maxCols             counter count l = if List.last posXs + List.last l <= colMax               then count + 1               else count@@ -528,12 +603,13 @@     $ c { _cbs_map = IntMapS.insert ind (lastFlag, space) $ _cbs_map c }   return info -processInfo :: LayoutConstraints m => ColMap2 -> ColInfo -> m ()-processInfo m = \case+processInfo :: LayoutConstraints m => Int -> ColMap2 -> ColInfo -> m ()+processInfo maxSpace m = \case   ColInfoStart       -> error "should not happen (TM)"   ColInfoNo doc      -> layoutBriDocM doc-  ColInfo ind _ list -> do-    colMax    <- mAsk <&> _conf_layout .> _lconfig_cols .> confUnpack+  ColInfo ind _ list -> -- trace ("processInfo ind=" ++ show ind ++ ", list=" ++ show list ++ ", colmap=" ++ show m) $+                        do+    colMaxConf <- mAsk <&> _conf_layout .> _lconfig_cols .> confUnpack     alignMode <- mAsk <&> _conf_layout .> _lconfig_columnAlignMode .> confUnpack     curX      <- do       state <- mGet@@ -546,8 +622,14 @@           Nothing -> spaceAdd + i           Just c -> c         Right{} -> spaceAdd+    let colMax = min colMaxConf (curX + maxSpace)     -- tellDebugMess $ show curX-    let Just (ratio, maxCols, _colss) = IntMapS.lookup ind m+    let Just (ratio, maxCols1, _colss) = IntMapS.lookup ind m+    let maxCols2 = list <&> \e -> case e of+          (_, ColInfo i _ _) ->+            let Just (_, ms, _) = IntMapS.lookup i m in sum ms+          (l, _) -> l+    let maxCols = zipWith max maxCols1 maxCols2     let (maxX, posXs) = mapAccumL (\acc x -> (acc + x, acc)) curX maxCols     -- handle the cases that the vertical alignment leads to more than max     -- cols:@@ -568,15 +650,21 @@             offsets = (subtract curX) <$> posXs             fixed   = offsets <&> fromIntegral .> (*factor) .> truncate           _ -> posXs+    let spacings = zipWith (-)+                           (List.tail fixedPosXs ++ [min maxX colMax])+                           fixedPosXs+    -- tellDebugMess $ "ind = " ++ show ind     -- tellDebugMess $ "maxCols = " ++ show maxCols     -- tellDebugMess $ "fixedPosXs = " ++ show fixedPosXs-    let alignAct = zip fixedPosXs list `forM_` \(destX, x) -> do+    -- tellDebugMess $ "list = " ++ show list+    -- tellDebugMess $ "maxSpace = " ++ show maxSpace+    let alignAct = zip3 fixedPosXs spacings list `forM_` \(destX, s, x) -> do           layoutWriteEnsureAbsoluteN destX-          processInfo m (snd x)+          processInfo s m (snd x)         noAlignAct = list `forM_` (snd .> processInfoIgnore)-        animousAct =-          -- per-item check if there is overflowing.+        animousAct = -- trace ("animousAct fixedPosXs=" ++ show fixedPosXs ++ ", list=" ++ show list ++ ", maxSpace=" ++ show maxSpace ++ ", colMax="++show colMax) $                      if List.last fixedPosXs + fst (List.last list) > colMax+                     -- per-item check if there is overflowing.           then noAlignAct           else alignAct     case alignMode of
src/Language/Haskell/Brittany/Internal/Config.hs view
@@ -5,7 +5,7 @@   , DebugConfig   , LayoutConfig   , Config-  , configParser+  , cmdlineConfigParser   , staticDefaultConfig   , forwardOptionsSyntaxExtsEnabled   , readConfig@@ -38,6 +38,7 @@ import           Language.Haskell.Brittany.Internal.Utils  import           Data.Coerce ( Coercible, coerce )+import qualified Data.List.NonEmpty as NonEmpty  import qualified System.Directory as Directory import qualified System.FilePath.Posix as FilePath@@ -88,6 +89,8 @@   , _conf_forward = ForwardOptions     { _options_ghc = Identity []     }+  , _conf_roundtrip_exactprint_only  = coerce False+  , _conf_obfuscate                  = coerce False   }  forwardOptionsSyntaxExtsEnabled :: ForwardOptions@@ -108,8 +111,9 @@     ]   } -configParser :: CmdParser Identity out (CConfig Option)-configParser = do+-- brittany-next-binding --columns=200+cmdlineConfigParser :: CmdParser Identity out (CConfig Option)+cmdlineConfigParser = do   -- TODO: why does the default not trigger; ind never should be []!!   ind                <- addFlagReadParams "" ["indent"] "AMOUNT" (flagHelpStr "spaces per indentation level")   cols               <- addFlagReadParams "" ["columns"] "AMOUNT" (flagHelpStr "target max columns (80 is an old default for this)")@@ -140,6 +144,7 @@                                            ["ghc-options"]                                            "STRING"                                            (flagHelp $ parDoc "allows to define default language extensions. The parameter is forwarded to ghc.")+  obfuscate <- addSimpleBoolFlag "" ["obfuscate"] (flagHelp $ parDoc "apply obfuscator to the output.")    return $ Config     { _conf_version = mempty@@ -155,7 +160,7 @@       , _dconf_dump_bridoc_simpl_columns  = wrapLast $ falseToNothing dumpBriDocColumns       , _dconf_dump_bridoc_simpl_indent   = wrapLast $ falseToNothing dumpBriDocIndent       , _dconf_dump_bridoc_final          = wrapLast $ falseToNothing dumpBriDocFinal-      , _dconf_roundtrip_exactprint_only  = wrapLast $ falseToNothing roundtripOnly+      , _dconf_roundtrip_exactprint_only  = mempty       }     , _conf_layout = LayoutConfig       { _lconfig_cols                      = optionConcat cols@@ -186,6 +191,8 @@     , _conf_forward = ForwardOptions       { _options_ghc = [ optionsGhc & List.unwords & CmdArgs.splitArgs | not $ null optionsGhc ]       }+    , _conf_roundtrip_exactprint_only  = wrapLast $ falseToNothing roundtripOnly+    , _conf_obfuscate                  = wrapLast $ falseToNothing obfuscate     }  where   falseToNothing = Option . Bool.bool Nothing (Just True)@@ -272,7 +279,7 @@   -> MaybeT IO Config readConfigs cmdlineConfig configPaths = do   configs <- readConfig `mapM` configPaths-  let merged = Semigroup.mconcat $ reverse (cmdlineConfig:catMaybes configs)+  let merged = Semigroup.sconcat $ NonEmpty.reverse (cmdlineConfig :| catMaybes configs)   return $ cZipWith fromOptionIdentity staticDefaultConfig merged  -- | Reads provided configs
src/Language/Haskell/Brittany/Internal/Config/Types.hs view
@@ -5,6 +5,9 @@ {-# LANGUAGE DeriveDataTypeable #-}  module Language.Haskell.Brittany.Internal.Config.Types+  ( module Language.Haskell.Brittany.Internal.Config.Types+  , cMap+  ) where  @@ -142,6 +145,12 @@   , _conf_errorHandling :: CErrorHandlingConfig f   , _conf_forward       :: CForwardOptions f   , _conf_preprocessor  :: CPreProcessorConfig f+  , _conf_roundtrip_exactprint_only :: f (Semigroup.Last Bool)+  , _conf_obfuscate     :: f (Semigroup.Last Bool)+    -- ^ this field is somewhat of a duplicate of the one in DebugConfig.+    -- It is used for per-declaration disabling by the inline config+    -- implementation. Could have re-used the existing field, but felt risky+    -- to use a "debug" labeled field for non-debug functionality.   }   deriving (Generic) @@ -173,6 +182,16 @@ deriving instance Data (CPreProcessorConfig Identity) deriving instance Data (CConfig Identity) +#if MIN_VERSION_ghc(8,2,0)+-- these instances break on earlier ghcs+deriving instance Data (CDebugConfig Option)+deriving instance Data (CLayoutConfig Option)+deriving instance Data (CErrorHandlingConfig Option)+deriving instance Data (CForwardOptions Option)+deriving instance Data (CPreProcessorConfig Option)+deriving instance Data (CConfig Option)+#endif+ instance Semigroup.Semigroup (CDebugConfig Option) where   (<>) = gmappend instance Semigroup.Semigroup (CLayoutConfig Option) where@@ -277,8 +296,12 @@                                  -- A PROGRAM BY TRANSFORMING IT.   deriving (Show, Generic, Data) -cMap :: CZipWith k => (forall a . f a -> g a) -> k f -> k g-cMap f c = cZipWith (\_ -> f) c c+instance CFunctor CDebugConfig+instance CFunctor CLayoutConfig+instance CFunctor CErrorHandlingConfig+instance CFunctor CForwardOptions+instance CFunctor CPreProcessorConfig+instance CFunctor CConfig  deriveCZipWith ''CDebugConfig deriveCZipWith ''CLayoutConfig
src/Language/Haskell/Brittany/Internal/Config/Types/Instances.hs view
@@ -119,6 +119,8 @@     <*> v .:?= Text.pack "conf_errorHandling"     <*> v .:?= Text.pack "conf_forward"     <*> v .:?= Text.pack "conf_preprocessor"+    <*> v .:?  Text.pack "conf_roundtrip_exactprint_only"+    <*> v .:?  Text.pack "conf_obfuscate"   parseJSON invalid    = Aeson.typeMismatch "Config" invalid  -- Pretends that the value is {} when the key is not present.
src/Language/Haskell/Brittany/Internal/ExactPrintUtils.hs view
@@ -7,6 +7,7 @@   , commentAnnFixTransformGlob   , extractToplevelAnns   , foldedAnnKeys+  , withTransformedAnns   ) where @@ -17,6 +18,8 @@ import           Language.Haskell.Brittany.Internal.Types import           Language.Haskell.Brittany.Internal.Config.Types import           Language.Haskell.Brittany.Internal.Utils+import           Data.Data+import           Data.HList.HList  import           DynFlags ( getDynFlags ) import           GHC ( runGhc, GenLocated(L), moduleNameString )@@ -29,10 +32,9 @@ import qualified Lexer         as GHC import qualified StringBuffer  as GHC import qualified Outputable    as GHC-import           RdrName ( RdrName(..) )+import qualified CmdLineParser as GHC import           HsSyn import           SrcLoc ( SrcSpan, Located )-import           RdrName ( RdrName(..) )   import qualified Language.Haskell.GHC.ExactPrint            as ExactPrint@@ -79,7 +81,7 @@     when (not $ null warnings)       $  ExceptT.throwE       $  "when parsing ghc flags: encountered warnings: "-      ++ show (warnings <&> \(L _ s) -> s)+      ++ show (warnings <&> warnExtractorCompat)     x   <- ExceptT.ExceptT $ liftIO $ dynCheck dflags2     res <- lift $ ExactPrint.parseModuleApiAnnsWithCppInternal cpp dflags2 fp     either (\(span, err) -> ExceptT.throwE $ show span ++ ": " ++ err)@@ -111,7 +113,7 @@     when (not $ null warnings)       $  ExceptT.throwE       $  "when parsing ghc flags: encountered warnings: "-      ++ show (warnings <&> \(L _ s) -> s)+      ++ show (warnings <&> warnExtractorCompat)     dynCheckRes <- ExceptT.ExceptT $ liftIO $ dynCheck dflags1     let res = ExactPrint.parseModuleFromStringInternal dflags1 fp str     case res of@@ -187,7 +189,7 @@  where   genF :: Data.Data.Data a => a -> ExactPrint.Transform ()   genF = (\_ -> return ()) `SYB.extQ` exprF-  exprF :: Located (HsExpr RdrName) -> ExactPrint.Transform ()+  exprF :: Located (HsExpr GhcPs) -> ExactPrint.Transform ()   exprF lexpr@(L _ expr) = case expr of     RecordCon _lname _ _ (HsRecFields fs@(_:_) Nothing) ->       moveTrailingComments lexpr (List.last fs)@@ -226,7 +228,7 @@ -- elements to the relevant annotations. Avoids quadratic behaviour a trivial -- implementation would have. extractToplevelAnns-  :: Located (HsModule RdrName)+  :: Located (HsModule GhcPs)   -> ExactPrint.Anns   -> Map ExactPrint.AnnKey ExactPrint.Anns extractToplevelAnns lmod anns = output@@ -265,3 +267,31 @@   )   ast   where locTyCon = SYB.typeRepTyCon (SYB.typeOf (L () ()))+++withTransformedAnns+  :: Data ast+  => ast+  -> MultiRWSS.MultiRWS '[Config, ExactPrint.Anns] w s a+  -> MultiRWSS.MultiRWS '[Config, ExactPrint.Anns] w s a+withTransformedAnns ast m = do+  -- TODO: implement `local` for MultiReader/MultiRWS+  readers@(conf :+: anns :+: HNil) <- MultiRWSS.mGetRawR+  MultiRWSS.mPutRawR (conf :+: f anns :+: HNil)+  x <- m+  MultiRWSS.mPutRawR readers+  pure x+ where+  f anns =+    let ((), (annsBalanced, _), _) =+          ExactPrint.runTransform anns (commentAnnFixTransformGlob ast)+    in  annsBalanced+++#if MIN_VERSION_ghc(8,4,0) /* ghc-8.4 */+warnExtractorCompat :: GHC.Warn -> String+warnExtractorCompat (GHC.Warn _ (L _ s)) = s+#else /* ghc-8.0 && ghc-8.2 */+warnExtractorCompat :: GenLocated l String -> String+warnExtractorCompat (L _ s) = s+#endif
src/Language/Haskell/Brittany/Internal/LayouterBasics.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ module Language.Haskell.Brittany.Internal.LayouterBasics   ( processDefault   , rdrNameToText@@ -11,7 +13,10 @@   , docEmpty   , docLit   , docAlt-  , docAltFilter+  , CollectAltM+  , addAlternativeCond+  , addAlternative+  , runFilteredAlternative   , docLines   , docCols   , docSeq@@ -60,6 +65,8 @@  #include "prelude.inc" +import qualified Control.Monad.Writer.Strict as Writer+ import qualified Language.Haskell.GHC.ExactPrint as ExactPrint import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types@@ -111,7 +118,7 @@   --       the module (header). This would remove the need for this hack!   case str of     "\n" -> return ()-    _    -> mTell $ Text.Builder.fromString $ str+    _    -> mTell $ Text.Builder.fromString str  -- | Use ExactPrint's output for this node; add a newly generated inline comment -- at insertion position (meant to point out to the user that this node is@@ -166,7 +173,7 @@         False         t   let errorAction = do-        mTell $ [ErrorUnknownNode infoStr ast]+        mTell [ErrorUnknownNode infoStr ast]         docLit           $ Text.pack "{- BRITTANY ERROR UNHANDLED SYNTACTICAL CONSTRUCT -}"   case (fallbackMode, Text.lines exactPrinted) of@@ -256,8 +263,8 @@        )  filterAnns :: Data.Data.Data ast => ast -> ExactPrint.Anns -> ExactPrint.Anns-filterAnns ast anns =-  Map.filterWithKey (\k _ -> k `Set.member` foldedAnnKeys ast) anns+filterAnns ast =+  Map.filterWithKey (\k _ -> k `Set.member` foldedAnnKeys ast)  hasAnyCommentsBelow :: Data ast => GHC.Located ast -> ToBriDocM Bool hasAnyCommentsBelow ast@(L l _) = do@@ -297,10 +304,10 @@  -- docEmpty :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -- docEmpty = allocateNode BDFEmpty--- +-- -- docLit :: MonadMultiState NodeAllocIndex m => Text -> m BriDocNumbered -- docLit t = allocateNode $ BDFLit t--- +-- -- docExt :: (ExactPrint.Annotate.Annotate ast, MonadMultiState NodeAllocIndex m) --        => Located ast -> ExactPrint.Types.Anns -> Bool -> m BriDocNumbered -- docExt x anns shouldAddComment = allocateNode $ BDFExternal@@ -308,51 +315,51 @@ --                   (foldedAnnKeys x) --                   shouldAddComment --                   (Text.pack $ ExactPrint.exactPrint x anns)--- +-- -- docAlt :: MonadMultiState NodeAllocIndex m => [m BriDocNumbered] -> m BriDocNumbered -- docAlt l = allocateNode . BDFAlt =<< sequence l--- --- +--+-- -- docSeq :: MonadMultiState NodeAllocIndex m => [m BriDocNumbered] -> m BriDocNumbered -- docSeq l = allocateNode . BDFSeq =<< sequence l--- +-- -- docLines :: MonadMultiState NodeAllocIndex m => [m BriDocNumbered] -> m BriDocNumbered -- docLines l = allocateNode . BDFLines =<< sequence l--- +-- -- docCols :: MonadMultiState NodeAllocIndex m => ColSig -> [m BriDocNumbered] -> m BriDocNumbered -- docCols sig l = allocateNode . BDFCols sig =<< sequence l--- +-- -- docAddBaseY :: MonadMultiState NodeAllocIndex m => BrIndent -> m BriDocNumbered -> m BriDocNumbered -- docAddBaseY ind bdm = allocateNode . BDFAddBaseY ind =<< bdm--- +-- -- docSetBaseY :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -> m BriDocNumbered -- docSetBaseY bdm = allocateNode . BDFSetBaseY =<< bdm--- +-- -- docSetIndentLevel :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -> m BriDocNumbered -- docSetIndentLevel bdm = allocateNode . BDFSetIndentLevel =<< bdm--- +-- -- docSeparator :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -- docSeparator = allocateNode BDFSeparator--- +-- -- docAnnotationPrior :: MonadMultiState NodeAllocIndex m => AnnKey -> m BriDocNumbered -> m BriDocNumbered -- docAnnotationPrior annKey bdm = allocateNode . BDFAnnotationPrior annKey =<< bdm--- +-- -- docAnnotationPost :: MonadMultiState NodeAllocIndex m => AnnKey -> m BriDocNumbered -> m BriDocNumbered -- docAnnotationPost  annKey bdm = allocateNode . BDFAnnotationPost annKey =<< bdm--- +-- -- docNonBottomSpacing :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -> m BriDocNumbered -- docNonBottomSpacing bdm = allocateNode . BDFNonBottomSpacing =<< bdm--- +-- -- appSep :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -> m BriDocNumbered -- appSep x = docSeq [x, docSeparator]--- +-- -- docCommaSep :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -- docCommaSep = appSep $ docLit $ Text.pack ","--- +-- -- docParenLSep :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -- docParenLSep = appSep $ docLit $ Text.pack "("--- --- +--+-- -- docPostComment :: (Data.Data.Data ast, MonadMultiState NodeAllocIndex m) --                => Located ast --                -> m BriDocNumbered@@ -360,7 +367,7 @@ -- docPostComment ast bdm = do --   bd <- bdm --   allocateNode $ BDFAnnotationPost (ExactPrint.Types.mkAnnKey ast) bd--- +-- -- docWrapNode :: ( Data.Data.Data ast, MonadMultiState NodeAllocIndex m) --             => Located ast --             -> m BriDocNumbered@@ -375,7 +382,7 @@ --     $ (,) i2 --     $ BDFAnnotationPost (ExactPrint.Types.mkAnnKey ast) --     $ bd--- +-- -- docPar :: MonadMultiState NodeAllocIndex m --        => m BriDocNumbered --        -> m BriDocNumbered@@ -384,13 +391,13 @@ --   line <- lineM --   indented <- indentedM --   allocateNode $ BDFPar BrIndentNone line indented--- +-- -- docForceSingleline :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -> m BriDocNumbered -- docForceSingleline bdm = allocateNode . BDFForceSingleline =<< bdm--- +-- -- docForceMultiline :: MonadMultiState NodeAllocIndex m => m BriDocNumbered -> m BriDocNumbered -- docForceMultiline bdm = allocateNode . BDFForceMultiline =<< bdm--- +-- -- docEnsureIndent :: MonadMultiState NodeAllocIndex m => BrIndent -> m BriDocNumbered -> m BriDocNumbered -- docEnsureIndent ind mbd = mbd >>= \bd -> allocateNode $ BDFEnsureIndent ind bd @@ -415,10 +422,22 @@ docAlt :: [ToBriDocM BriDocNumbered] -> ToBriDocM BriDocNumbered docAlt l = allocateNode . BDFAlt =<< sequence l -docAltFilter :: [(Bool, ToBriDocM BriDocNumbered)] -> ToBriDocM BriDocNumbered-docAltFilter = docAlt . map snd . filter fst+newtype CollectAltM a = CollectAltM (Writer.Writer [ToBriDocM BriDocNumbered] a)+  deriving (Functor, Applicative, Monad) +addAlternativeCond :: Bool -> ToBriDocM BriDocNumbered -> CollectAltM ()+addAlternativeCond cond doc =+  when cond (addAlternative doc) +addAlternative :: ToBriDocM BriDocNumbered -> CollectAltM ()+addAlternative =+  CollectAltM . Writer.tell . (: [])++runFilteredAlternative :: CollectAltM () -> ToBriDocM BriDocNumbered+runFilteredAlternative (CollectAltM action) =+  docAlt $ Writer.execWriter action++ docSeq :: [ToBriDocM BriDocNumbered] -> ToBriDocM BriDocNumbered docSeq [] = docEmpty docSeq l = allocateNode . BDFSeq =<< sequence l@@ -565,7 +584,7 @@   docWrapNode ast bdsm = do     bds <- bdsm     case bds of-      [] -> return $ [] -- TODO: this might be bad. maybe. then again, not really. well.+      [] -> return [] -- TODO: this might be bad. maybe. then again, not really. well.       [bd] -> do         bd' <- docWrapNode ast (return bd)         return [bd']@@ -577,23 +596,23 @@   docWrapNodePrior ast bdsm = do     bds <- bdsm     case bds of-      [] -> return $ []+      [] -> return []       (bd1:bdR) -> do         bd1' <- docWrapNodePrior ast (return bd1)-        return $ (bd1':bdR)+        return (bd1':bdR)   docWrapNodeRest ast bdsm = do     bds <- bdsm     case reverse bds of-      [] -> return $ []+      [] -> return []       (bdN:bdR) -> do         bdN' <- docWrapNodeRest ast (return bdN)-        return $ reverse $ (bdN':bdR)+        return $ reverse (bdN':bdR)  instance DocWrapable a => DocWrapable (Seq a) where   docWrapNode ast bdsm = do     bds <- bdsm     case Seq.viewl bds of-      Seq.EmptyL -> return $ Seq.empty -- TODO: this might be bad. maybe. then again, not really. well.+      Seq.EmptyL -> return Seq.empty -- TODO: this might be bad. maybe. then again, not really. well.       bd1 Seq.:< rest -> case Seq.viewr rest of         Seq.EmptyR -> do           bd1' <- docWrapNode ast (return bd1)@@ -605,14 +624,14 @@   docWrapNodePrior ast bdsm = do     bds <- bdsm     case Seq.viewl bds of-      Seq.EmptyL -> return $ Seq.empty+      Seq.EmptyL -> return Seq.empty       bd1 Seq.:< bdR -> do         bd1' <- docWrapNodePrior ast (return bd1)         return $ bd1' Seq.<| bdR   docWrapNodeRest ast bdsm = do     bds <- bdsm     case Seq.viewr bds of-      Seq.EmptyR -> return $ Seq.empty+      Seq.EmptyR -> return Seq.empty       bdR Seq.:> bdN -> do         bdN' <- docWrapNodeRest ast (return bdN)         return $ bdR Seq.|> bdN'@@ -623,19 +642,19 @@     if null bds       then do         bd' <- docWrapNode ast (return bd)-        return $ (bds, bd', x)+        return (bds, bd', x)       else do         bds' <- docWrapNodePrior ast (return bds)         bd' <- docWrapNodeRest ast (return bd)-        return $ (bds', bd', x)+        return (bds', bd', x)   docWrapNodePrior ast stuffM = do     (bds, bd, x) <- stuffM     bds' <- docWrapNodePrior ast (return bds)-    return $ (bds', bd, x)+    return (bds', bd, x)   docWrapNodeRest ast stuffM = do     (bds, bd, x) <- stuffM     bd' <- docWrapNodeRest ast (return bd)-    return $ (bds, bd', x)+    return (bds, bd', x)   @@ -661,7 +680,7 @@ unknownNodeError   :: Data.Data.Data ast => String -> ast -> ToBriDocM BriDocNumbered unknownNodeError infoStr ast = do-  mTell $ [ErrorUnknownNode infoStr ast]+  mTell [ErrorUnknownNode infoStr ast]   docLit $ Text.pack "{- BRITTANY ERROR UNHANDLED SYNTACTICAL CONSTRUCT -}"  spacifyDocs :: [ToBriDocM BriDocNumbered] -> [ToBriDocM BriDocNumbered]
src/Language/Haskell/Brittany/Internal/Layouters/Decl.hs view
@@ -2,7 +2,8 @@ {-# LANGUAGE TypeApplications #-}  module Language.Haskell.Brittany.Internal.Layouters.Decl-  ( layoutSig+  ( layoutDecl+  , layoutSig   , layoutBind   , layoutLocalBinds   , layoutGuardLStmt@@ -20,7 +21,11 @@ import           Language.Haskell.Brittany.Internal.LayouterBasics import           Language.Haskell.Brittany.Internal.Config.Types -import           RdrName ( RdrName(..) )+import qualified Language.Haskell.GHC.ExactPrint as ExactPrint+import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint+import           Language.Haskell.Brittany.Internal.ExactPrintUtils+import           Language.Haskell.Brittany.Internal.Utils+ import           GHC ( runGhc, GenLocated(L), moduleNameString ) import           SrcLoc ( SrcSpan ) import           HsSyn@@ -41,6 +46,28 @@   +layoutDecl :: ToBriDoc HsDecl+layoutDecl d@(L loc decl) = case decl of+  SigD sig  -> withTransformedAnns d $ layoutSig (L loc sig)+  ValD bind -> withTransformedAnns d $ layoutBind (L loc bind) >>= \case+    Left  ns -> docLines $ return <$> ns+    Right n  -> return n+  InstD (TyFamInstD{}) -> do+    -- this is a (temporary (..)) workaround for "type instance" decls+    -- that do not round-trip through exactprint properly.+    let fixer s = case List.stripPrefix "type " s of+          Just rest | not ("instance" `isPrefixOf` rest) ->+            "type instance " ++ rest+          _ -> s+    str <- mAsk <&> \anns ->+      intercalate "\n" $ fmap fixer $ lines' $ ExactPrint.exactPrint d anns+    allocateNode $ BDFExternal (ExactPrint.mkAnnKey d)+                               (foldedAnnKeys d)+                               False+                               (Text.pack str)+  _ -> briDocByExactNoComment d++ layoutSig :: ToBriDoc Sig layoutSig lsig@(L _loc sig) = case sig of #if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */@@ -88,11 +115,7 @@   InlineSig name (InlinePragma _ spec _arity phaseAct conlike) ->     docWrapNode lsig $ do       nameStr <- lrdrNameToTextAnn name-      let specStr = case spec of-            Inline          -> "INLINE "-            Inlinable       -> "INLINABLE "-            NoInline        -> "NOINLINE "-            EmptyInlineSpec -> "" -- i have no idea if this is correct.+      specStr <- specStringCompat lsig spec       let phaseStr = case phaseAct of             NeverActive      -> "" -- not [] - for NOINLINE NeverActive is                                    -- in fact the default@@ -108,7 +131,23 @@         <> Text.pack " #-}"   _ -> briDocByExactNoComment lsig -- TODO -layoutGuardLStmt :: ToBriDoc' (Stmt RdrName (LHsExpr RdrName))+specStringCompat+  :: MonadMultiWriter [BrittanyError] m => LSig GhcPs -> InlineSpec -> m String+#if MIN_VERSION_ghc(8,4,0)+specStringCompat ast = \case+  NoUserInline    -> mTell [ErrorUnknownNode "NoUserInline" ast] $> ""+  Inline          -> pure "INLINE "+  Inlinable       -> pure "INLINABLE "+  NoInline        -> pure "NOINLINE "+#else+specStringCompat _ = \case+  Inline          -> pure "INLINE "+  Inlinable       -> pure "INLINABLE "+  NoInline        -> pure "NOINLINE "+  EmptyInlineSpec -> pure ""+#endif++layoutGuardLStmt :: ToBriDoc' (Stmt GhcPs (LHsExpr GhcPs)) layoutGuardLStmt lgstmt@(L _ stmtLR) = docWrapNode lgstmt $ case stmtLR of   BodyStmt body _ _ _      -> layoutExpr body   BindStmt lPat expr _ _ _ -> do@@ -122,7 +161,7 @@  layoutBind   :: ToBriDocC-       (HsBindLR RdrName RdrName)+       (HsBindLR GhcPs GhcPs)        (Either [BriDocNumbered] BriDocNumbered) layoutBind lbind@(L _ bind) = case bind of   FunBind fId (MG lmatches@(L _ matches) _ _ _) _ _ [] -> do@@ -148,15 +187,15 @@                                                             hasComments   _ -> Right <$> unknownNodeError "" lbind -data BagBindOrSig = BagBind (LHsBindLR RdrName RdrName)-                  | BagSig (LSig RdrName)+data BagBindOrSig = BagBind (LHsBindLR GhcPs GhcPs)+                  | BagSig (LSig GhcPs)  bindOrSigtoSrcSpan :: BagBindOrSig -> SrcSpan bindOrSigtoSrcSpan (BagBind (L l _)) = l bindOrSigtoSrcSpan (BagSig  (L l _)) = l  layoutLocalBinds-  :: ToBriDocC (HsLocalBindsLR RdrName RdrName) (Maybe [BriDocNumbered])+  :: ToBriDocC (HsLocalBindsLR GhcPs GhcPs) (Maybe [BriDocNumbered]) layoutLocalBinds lbinds@(L _ binds) = case binds of   -- HsValBinds (ValBindsIn lhsBindsLR []) ->   --   Just . (>>= either id return) . Data.Foldable.toList <$> mapBagM layoutBind lhsBindsLR -- TODO: fix ordering@@ -178,11 +217,11 @@   x@(HsIPBinds _ipBinds) -> Just . (:[]) <$> unknownNodeError "HsIPBinds" x   EmptyLocalBinds        -> return $ Nothing --- TODO: we don't need the `LHsExpr RdrName` anymore, now that there is+-- TODO: we don't need the `LHsExpr GhcPs` anymore, now that there is -- parSpacing stuff.B layoutGrhs-  :: LGRHS RdrName (LHsExpr RdrName)-  -> ToBriDocM ([BriDocNumbered], BriDocNumbered, LHsExpr RdrName)+  :: LGRHS GhcPs (LHsExpr GhcPs)+  -> ToBriDocM ([BriDocNumbered], BriDocNumbered, LHsExpr GhcPs) layoutGrhs lgrhs@(L _ (GRHS guards body)) = do   guardDocs <- docWrapNode lgrhs $ layoutStmt `mapM` guards   bodyDoc   <- layoutExpr body@@ -191,12 +230,14 @@ layoutPatternBind   :: Maybe Text   -> BriDocNumbered-  -> LMatch RdrName (LHsExpr RdrName)+  -> LMatch GhcPs (LHsExpr GhcPs)   -> ToBriDocM BriDocNumbered-layoutPatternBind mIdStr binderDoc lmatch@(L _ match@(Match fixityOrCtx pats _ (GRHSs grhss whereBinds))) = do+layoutPatternBind mIdStr binderDoc lmatch@(L _ match) = do+  let pats                     = m_pats match+  let (GRHSs grhss whereBinds) = m_grhss match   patDocs <- pats `forM` \p -> fmap return $ colsWrapPat =<< layoutPat p   let isInfix = isInfixMatch match-  let mIdStr' = fixPatternBindIdentifier fixityOrCtx <$> mIdStr+  let mIdStr' = fixPatternBindIdentifier match <$> mIdStr   patDoc <- docWrapNodePrior lmatch $ case (mIdStr', patDocs) of     (Just idStr, p1 : pr) | isInfix -> docCols       ColPatternsFuncInfix@@ -222,25 +263,26 @@                          mWhereDocs                          hasComments -#if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */+#if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 && ghc-8.4 */ fixPatternBindIdentifier-  :: HsMatchContext (NameOrRdrName RdrName) -> Text -> Text-fixPatternBindIdentifier ctx idStr = case ctx of-  (FunRhs _ _ SrcLazy    ) -> Text.cons '~' idStr-  (FunRhs _ _ SrcStrict  ) -> Text.cons '!' idStr-  (FunRhs _ _ NoSrcStrict) -> idStr-  (StmtCtxt ctx1         ) -> fixPatternBindIdentifier' ctx1-  _                        -> idStr+  :: Match GhcPs (LHsExpr GhcPs) -> Text -> Text+fixPatternBindIdentifier match idStr = go $ m_ctxt match  where+  go = \case+    (FunRhs _ _ SrcLazy    ) -> Text.cons '~' idStr+    (FunRhs _ _ SrcStrict  ) -> Text.cons '!' idStr+    (FunRhs _ _ NoSrcStrict) -> idStr+    (StmtCtxt ctx1         ) -> goInner ctx1+    _                        -> idStr   -- I have really no idea if this path ever occurs, but better safe than   -- risking another "drop bangpatterns" bugs.-  fixPatternBindIdentifier' = \case-    (PatGuard      ctx1) -> fixPatternBindIdentifier ctx1 idStr-    (ParStmtCtxt   ctx1) -> fixPatternBindIdentifier' ctx1-    (TransStmtCtxt ctx1) -> fixPatternBindIdentifier' ctx1+  goInner = \case+    (PatGuard      ctx1) -> go ctx1+    (ParStmtCtxt   ctx1) -> goInner ctx1+    (TransStmtCtxt ctx1) -> goInner ctx1     _                    -> idStr-#else                      /* ghc-8.0 */-fixPatternBindIdentifier :: MatchFixity RdrName -> Text -> Text+#else                       /* ghc-8.0 */+fixPatternBindIdentifier :: Match GhcPs (LHsExpr GhcPs) -> Text -> Text fixPatternBindIdentifier _ x = x #endif @@ -248,7 +290,7 @@   :: Maybe Text   -> BriDocNumbered   -> Maybe BriDocNumbered-  -> [([BriDocNumbered], BriDocNumbered, LHsExpr RdrName)]+  -> [([BriDocNumbered], BriDocNumbered, LHsExpr GhcPs)]   -> Maybe [BriDocNumbered]   -> Bool   -> ToBriDocM BriDocNumbered@@ -308,258 +350,237 @@             ++ (List.intersperse docCommaSep                                  (docForceSingleline . return <$> gs)                )+      wherePart = case mWhereDocs of+        Nothing  -> Just docEmpty+        Just [w] -> Just $ docSeq+          [ docSeparator+          , appSep $ docLit $ Text.pack "where"+          , docSetIndentLevel $ docForceSingleline $ return w+          ]+        _        -> Nothing    indentPolicy <- mAsk     <&> _conf_layout     .>  _lconfig_indentPolicy     .>  confUnpack-  docAltFilter-    $  -- one-line solution-       [ ( True-         , docCols-         (ColBindingLine alignmentToken)-         [ docSeq (patPartInline ++ [guardPart])-         , docSeq-           [ appSep $ return binderDoc-           , docForceSingleline $ return body-           , wherePart-           ]-         ]-         )-       | not hasComments-       , [(guards, body, _bodyRaw)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       , wherePart <- case mWhereDocs of-         Nothing  -> return @[] $ docEmpty-         Just [w] -> return @[] $ docSeq-           [ docSeparator-           , appSep $ docLit $ Text.pack "where"-           , docSetIndentLevel $ docForceSingleline $ return w-           ]-         _        -> []-       ]-    ++ -- one-line solution + where in next line(s)-       [ ( True-         , docLines-         $  [ docCols-              (ColBindingLine alignmentToken)-              [ docSeq (patPartInline ++ [guardPart])-              , docSeq-                [appSep $ return binderDoc, docForceParSpacing $ return body]-              ]-            ]-         ++ wherePartMultiLine-         )-       | [(guards, body, _bodyRaw)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       , Data.Maybe.isJust mWhereDocs-       ]-    ++ -- two-line solution + where in next line(s)-       [ ( True -         , docLines-         $  [ docForceSingleline-            $ docSeq (patPartInline ++ [guardPart, return binderDoc])-            , docEnsureIndent BrIndentRegular $ docForceSingleline $ return body-            ]-         ++ wherePartMultiLine-         )-       | [(guards, body, _bodyRaw)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       ]-    ++ -- pattern and exactly one clause in single line, body as par;-       -- where in following lines-       [ ( True-         , docLines-         $  [ docCols-              (ColBindingLine alignmentToken)-              [ docSeq (patPartInline ++ [guardPart])-              , docSeq-                [ appSep $ return binderDoc-                , docForceParSpacing $ docAddBaseY BrIndentRegular $ return body-                ]++  runFilteredAlternative $ do++    case clauseDocs of+      [(guards, body, _bodyRaw)] -> do+        let guardPart = singleLineGuardsDoc guards+        forM_ wherePart $ \wherePart' ->+          -- one-line solution+          addAlternativeCond (not hasComments) $ docCols+            (ColBindingLine alignmentToken)+            [ docSeq (patPartInline ++ [guardPart])+            , docSeq+              [ appSep $ return binderDoc+              , docForceSingleline $ return body+              , wherePart'               ]             ]-          -- , lineMod $ docAlt-          --   [ docSetBaseY $ return body-          --   , docAddBaseY BrIndentRegular $ return body-          --   ]-         ++ wherePartMultiLine-         )-       | [(guards, body, _bodyRaw)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       ]-    ++ -- pattern and exactly one clause in single line, body in new line.-       [ ( True-         , docLines-         $  [ docSeq (patPartInline ++ [guardPart, return binderDoc])-            , docEnsureIndent BrIndentRegular-            $ docNonBottomSpacing-            $ (docAddBaseY BrIndentRegular $ return body)-            ]-         ++ wherePartMultiLine-         )-       | [(guards, body, _)] <- [clauseDocs]-       , let guardPart = singleLineGuardsDoc guards-       ]-    ++ -- multiple clauses added in-paragraph, each in a single line-       -- example: foo | bar = baz-       --              | lll = asd-       [ ( indentPolicy /= IndentPolicyLeft-         , docLines-         $  [ docSeq-              [ appSep $ docForceSingleline $ return patDoc-              , docSetBaseY-              $   docLines-              $   clauseDocs-              <&> \(guardDocs, bodyDoc, _) -> do-                    let guardPart = singleLineGuardsDoc guardDocs-                    -- the docForceSingleline might seems superflous, but it-                    -- helps the alternative resolving impl.-                    docForceSingleline $ docCols-                      ColGuardedBody-                      [ guardPart-                      , docSeq+        -- one-line solution + where in next line(s)+        addAlternativeCond (Data.Maybe.isJust mWhereDocs)+          $ docLines+          $  [ docCols+               (ColBindingLine alignmentToken)+               [ docSeq (patPartInline ++ [guardPart])+               , docSeq+                 [appSep $ return binderDoc, docForceParSpacing $ return body]+               ]+             ]+          ++ wherePartMultiLine+        -- two-line solution + where in next line(s)+        addAlternative+          $ docLines+          $  [ docForceSingleline+             $ docSeq (patPartInline ++ [guardPart, return binderDoc])+             , docEnsureIndent BrIndentRegular $ docForceSingleline $ return body+             ]+          ++ wherePartMultiLine+        -- pattern and exactly one clause in single line, body as par;+        -- where in following lines+        addAlternative+          $ docLines+          $  [ docCols+               (ColBindingLine alignmentToken)+               [ docSeq (patPartInline ++ [guardPart])+               , docSeq+                 [ appSep $ return binderDoc+                 , docForceParSpacing $ docAddBaseY BrIndentRegular $ return body+                 ]+               ]+             ]+           -- , lineMod $ docAlt+           --   [ docSetBaseY $ return body+           --   , docAddBaseY BrIndentRegular $ return body+           --   ]+          ++ wherePartMultiLine+        -- pattern and exactly one clause in single line, body in new line.+        addAlternative+          $ docLines+          $  [ docSeq (patPartInline ++ [guardPart, return binderDoc])+             , docEnsureIndent BrIndentRegular+             $ docNonBottomSpacing+             $ docAddBaseY BrIndentRegular+             $ return body+             ]+          ++ wherePartMultiLine++      _ -> return () -- no alternatives exclusively when `length clauseDocs /= 1`++    case mPatDoc of+      Nothing     -> return ()+      Just patDoc ->+        -- multiple clauses added in-paragraph, each in a single line+        -- example: foo | bar = baz+        --              | lll = asd+        addAlternativeCond (indentPolicy == IndentPolicyFree)+          $ docLines+          $  [ docSeq+               [ appSep $ docForceSingleline $ return patDoc+               , docSetBaseY+               $   docLines+               $   clauseDocs+               <&> \(guardDocs, bodyDoc, _) -> do+                     let guardPart = singleLineGuardsDoc guardDocs+                     -- the docForceSingleline might seems superflous, but it+                     -- helps the alternative resolving impl.+                     docForceSingleline $ docCols+                       ColGuardedBody+                       [ guardPart+                       , docSeq+                         [ appSep $ return binderDoc+                         , docForceSingleline $ return bodyDoc+                         -- i am not sure if there is a benefit to using+                         -- docForceParSpacing additionally here:+                         -- , docAddBaseY BrIndentRegular $ return bodyDoc+                         ]+                       ]+               ]+             ]+          ++ wherePartMultiLine+    -- multiple clauses, each in a separate, single line+    addAlternative+      $ docLines+      $  [ docAddBaseY BrIndentRegular+           $   patPartParWrap+           $   docLines+           $   map docSetBaseY+           $   clauseDocs+           <&> \(guardDocs, bodyDoc, _) -> do+                 let guardPart = singleLineGuardsDoc guardDocs+                 -- the docForceSingleline might seems superflous, but it+                 -- helps the alternative resolving impl.+                 docForceSingleline $ docCols+                   ColGuardedBody+                   [ guardPart+                   , docSeq+                     [ appSep $ return binderDoc+                     , docForceSingleline $ return bodyDoc+                     -- i am not sure if there is a benefit to using+                     -- docForceParSpacing additionally here:+                     -- , docAddBaseY BrIndentRegular $ return bodyDoc+                     ]+                   ]+         ]+      ++ wherePartMultiLine+    -- multiple clauses, each with the guard(s) in a single line, body+    -- as a paragraph+    addAlternative+      $ docLines+      $  [ docAddBaseY BrIndentRegular+           $   patPartParWrap+           $   docLines+           $   map docSetBaseY+           $   clauseDocs+           <&> \(guardDocs, bodyDoc, _) ->+                 docSeq+                 $ ( case guardDocs of+                     [] -> []+                     [g] ->+                       [ docForceSingleline+                       $ docSeq [appSep $ docLit $ Text.pack "|", return g]+                       ]+                     gs ->+                       [  docForceSingleline+                       $  docSeq+                       $  [appSep $ docLit $ Text.pack "|"]+                       ++ List.intersperse docCommaSep (return <$> gs)+                       ]+                   )+                   ++ [ docSeparator+                      , docCols+                        ColOpPrefix                         [ appSep $ return binderDoc-                        , docForceSingleline $ return bodyDoc-                        -- i am not sure if there is a benefit to using-                        -- docForceParSpacing additionally here:-                        -- , docAddBaseY BrIndentRegular $ return bodyDoc+                        , docAddBaseY BrIndentRegular+                        $ docForceParSpacing+                        $ return bodyDoc                         ]                       ]-              ]-            ]-         ++ wherePartMultiLine-         )-       | Just patDoc <- [mPatDoc]-       ]-    ++ -- multiple clauses, each in a separate, single line-       [ ( True-         , docLines-         $  [ docAddBaseY BrIndentRegular-              $   patPartParWrap-              $   docLines-              $   map docSetBaseY-              $   clauseDocs-              <&> \(guardDocs, bodyDoc, _) -> do-                    let guardPart = singleLineGuardsDoc guardDocs-                    -- the docForceSingleline might seems superflous, but it-                    -- helps the alternative resolving impl.-                    docForceSingleline $ docCols-                      ColGuardedBody-                      [ guardPart-                      , docSeq+         ]+      ++ wherePartMultiLine+    -- multiple clauses, each with the guard(s) in a single line, body+    -- in a new line as a paragraph+    addAlternative+      $ docLines+      $  [ docAddBaseY BrIndentRegular+           $   patPartParWrap+           $   docLines+           $   map docSetBaseY+           $   clauseDocs+           >>= \(guardDocs, bodyDoc, _) ->+                 ( case guardDocs of+                   [] -> []+                   [g] ->+                     [ docForceSingleline+                     $ docSeq [appSep $ docLit $ Text.pack "|", return g]+                     ]+                   gs ->+                     [  docForceSingleline+                     $  docSeq+                     $  [appSep $ docLit $ Text.pack "|"]+                     ++ List.intersperse docCommaSep (return <$> gs)+                     ]+                 )+                 ++ [ docCols+                      ColOpPrefix+                      [ appSep $ return binderDoc+                      , docAddBaseY BrIndentRegular+                      $ docForceParSpacing+                      $ return bodyDoc+                      ]+                    ]+         ]+      ++ wherePartMultiLine+    -- conservative approach: everything starts on the left.+    addAlternative+      $ docLines+      $  [ docAddBaseY BrIndentRegular+           $   patPartParWrap+           $   docLines+           $   map docSetBaseY+           $   clauseDocs+           >>= \(guardDocs, bodyDoc, _) ->+                 ( case guardDocs of+                     [] -> []+                     [g] ->+                       [docSeq [appSep $ docLit $ Text.pack "|", return g]]+                     (g1:gr) ->+                       ( docSeq [appSep $ docLit $ Text.pack "|", return g1]+                       : (   gr+                         <&> \g ->+                               docSeq+                                 [appSep $ docLit $ Text.pack ",", return g]+                         )+                       )+                   )+                   ++ [ docCols+                        ColOpPrefix                         [ appSep $ return binderDoc-                        , docForceSingleline $ return bodyDoc-                        -- i am not sure if there is a benefit to using-                        -- docForceParSpacing additionally here:-                        -- , docAddBaseY BrIndentRegular $ return bodyDoc+                        , docAddBaseY BrIndentRegular $ return bodyDoc                         ]                       ]-            ]-         ++ wherePartMultiLine-         )-       ]-    ++ -- multiple clauses, each with the guard(s) in a single line, body-       -- as a paragraph-       [ ( True-         , docLines-         $  [ docAddBaseY BrIndentRegular-              $   patPartParWrap-              $   docLines-              $   map docSetBaseY-              $   clauseDocs-              <&> \(guardDocs, bodyDoc, _) ->-                    docSeq-                    $ ( case guardDocs of-                        [] -> []-                        [g] ->-                          [ docForceSingleline-                          $ docSeq [appSep $ docLit $ Text.pack "|", return g]-                          ]-                        gs ->-                          [  docForceSingleline-                          $  docSeq-                          $  [appSep $ docLit $ Text.pack "|"]-                          ++ List.intersperse docCommaSep (return <$> gs)-                          ]-                      )-                      ++ [ docSeparator-                         , docCols-                           ColOpPrefix-                           [ appSep $ return binderDoc-                           , docAddBaseY BrIndentRegular-                           $ docForceParSpacing-                           $ return bodyDoc-                           ]-                         ]-            ]-         ++ wherePartMultiLine-         )-       ]-    ++ -- multiple clauses, each with the guard(s) in a single line, body-       -- in a new line as a paragraph-       [ ( True-         , docLines-         $  [ docAddBaseY BrIndentRegular-              $   patPartParWrap-              $   docLines-              $   map docSetBaseY-              $   clauseDocs-              >>= \(guardDocs, bodyDoc, _) ->-                    ( case guardDocs of-                      [] -> []-                      [g] ->-                        [ docForceSingleline-                        $ docSeq [appSep $ docLit $ Text.pack "|", return g]-                        ]-                      gs ->-                        [  docForceSingleline-                        $  docSeq-                        $  [appSep $ docLit $ Text.pack "|"]-                        ++ List.intersperse docCommaSep (return <$> gs)-                        ]-                    )-                    ++ [ docCols-                         ColOpPrefix-                         [ appSep $ return binderDoc-                         , docAddBaseY BrIndentRegular-                         $ docForceParSpacing-                         $ return bodyDoc-                         ]-                       ]-            ]-         ++ wherePartMultiLine-         )-       ]-    ++ -- conservative approach: everything starts on the left.-       [ ( True-         , docLines-         $  [ docAddBaseY BrIndentRegular-              $   patPartParWrap-              $   docLines-              $   map docSetBaseY-              $   clauseDocs-              >>= \(guardDocs, bodyDoc, _) ->-                    ( case guardDocs of-                        [] -> []-                        [g] ->-                          [docSeq [appSep $ docLit $ Text.pack "|", return g]]-                        (g1:gr) ->-                          ( docSeq [appSep $ docLit $ Text.pack "|", return g1]-                          : (   gr-                            <&> \g ->-                                  docSeq-                                    [appSep $ docLit $ Text.pack ",", return g]-                            )-                          )-                      )-                      ++ [ docCols-                           ColOpPrefix-                           [ appSep $ return binderDoc-                           , docAddBaseY BrIndentRegular $ return bodyDoc-                           ]-                         ]-            ]-         ++ wherePartMultiLine-         )-       ]+         ]+      ++ wherePartMultiLine
src/Language/Haskell/Brittany/Internal/Layouters/Expr.hs view
@@ -15,8 +15,7 @@ import           Language.Haskell.Brittany.Internal.LayouterBasics import           Language.Haskell.Brittany.Internal.Config.Types -import           RdrName ( RdrName(..) )-import           GHC ( runGhc, GenLocated(L), moduleNameString, AnnKeywordId(..) )+import           GHC ( runGhc, GenLocated(L), moduleNameString, AnnKeywordId(..), RdrName(..) ) import           HsSyn import           Name import qualified FastString@@ -56,12 +55,17 @@       allocateNode $ overLitValBriDoc olit     HsLit lit -> do       allocateNode $ litBriDoc lit-    HsLam (MG (L _ [lmatch@(L _ (Match _ pats _ (GRHSs [lgrhs@(L _ (GRHS [] body))] (L _ EmptyLocalBinds))))]) _ _ _) -> do+    HsLam (MG (L _ [lmatch@(L _ match)]) _ _ _)+      |  pats                  <- m_pats match+      ,  GRHSs [lgrhs] llocals <- m_grhss match+      ,  L _ EmptyLocalBinds   <- llocals+      ,  L _ (GRHS [] body)    <- lgrhs+      -> do       patDocs <- pats `forM` \p -> fmap return $ colsWrapPat =<< layoutPat p       bodyDoc <- docAddBaseY BrIndentRegular <$> docSharedWrapper layoutExpr body       let funcPatternPartLine =             docCols ColCasePattern-              $ (patDocs <&> (\p -> docSeq [docForceSingleline p, docSeparator]))+              (patDocs <&> (\p -> docSeq [docForceSingleline p, docSeparator]))       docAlt         [ -- single line           docSeq@@ -106,16 +110,16 @@ #else /* ghc-8.0 */     HsLamCase _ (MG lmatches@(L _ matches) _ _ _) -> do #endif-      binderDoc <- docLit $ Text.pack "->"+      binderDoc   <- docLit $ Text.pack "->"       funcPatDocs <- docWrapNode lmatches $ layoutPatternBind Nothing binderDoc `mapM` matches       docSetParSpacing $ docAddBaseY BrIndentRegular $ docPar         (docLit $ Text.pack "\\case")         (docSetBaseAndIndent $ docNonBottomSpacing $ docLines $ return <$> funcPatDocs)     HsApp exp1@(L _ HsApp{}) exp2 -> do-      let gather :: [LHsExpr RdrName] -> LHsExpr RdrName -> (LHsExpr RdrName, [LHsExpr RdrName])+      let gather :: [LHsExpr GhcPs] -> LHsExpr GhcPs -> (LHsExpr GhcPs, [LHsExpr GhcPs])           gather list = \case-            (L _ (HsApp l r)) -> gather (r:list) l-            x -> (x, list)+            L _ (HsApp l r) -> gather (r:list) l+            x               -> (x, list)       let (headE, paramEs) = gather [exp2] exp1       let colsOrSequence = case headE of             L _ (HsVar (L _ (Unqual occname))) ->@@ -123,51 +127,46 @@             _ -> docSeq       headDoc <- docSharedWrapper layoutExpr headE       paramDocs <- docSharedWrapper layoutExpr `mapM` paramEs-      docAltFilter-        [ -- foo x y-          ( True-          , colsOrSequence+      runFilteredAlternative $ do+        -- foo x y+        addAlternative+          $ colsOrSequence           $ appSep (docForceSingleline headDoc)           : spacifyDocs (docForceSingleline <$> paramDocs)-          )-        , -- foo x-          --     y-          ( allowFreeIndent-          , docSeq-            [ appSep (docForceSingleline headDoc)-            , docSetBaseY-            $ docAddBaseY BrIndentRegular-            $ docLines-            $ (docForceSingleline <$> paramDocs)-            ]-          )-        , -- foo-          --   x-          --   y-          ( True-          , docSetParSpacing+        -- foo x+        --     y+        addAlternativeCond allowFreeIndent+          $ docSeq+          [ appSep (docForceSingleline headDoc)+          , docSetBaseY           $ docAddBaseY BrIndentRegular+          $ docLines+          $ docForceSingleline <$> paramDocs+          ]+        -- foo+        --   x+        --   y+        addAlternative+          $ docSetParSpacing+          $ docAddBaseY BrIndentRegular           $ docPar             (docForceSingleline headDoc)             ( docNonBottomSpacing             $ docLines paramDocs             )-          )-        , -- ( multi-          --   line-          --   function-          -- )-          --   x-          --   y-          ( True-          , docAddBaseY BrIndentRegular+        -- ( multi+        --   line+        --   function+        -- )+        --   x+        --   y+        addAlternative+          $ docAddBaseY BrIndentRegular           $ docPar             headDoc             ( docNonBottomSpacing             $ docLines paramDocs             )-          )-        ]     HsApp exp1 exp2 -> do       -- TODO: if expDoc1 is some literal, we may want to create a docCols here.       expDoc1 <- docSharedWrapper layoutExpr exp1@@ -225,7 +224,7 @@       -- TODO       briDocByExactInlineOnly "HsAppTypeOut{}" lexpr     OpApp expLeft@(L _ OpApp{}) expOp _ expRight -> do-      let gather :: [(LHsExpr RdrName, LHsExpr RdrName)] -> LHsExpr RdrName -> (LHsExpr RdrName, [(LHsExpr RdrName, LHsExpr RdrName)])+      let gather :: [(LHsExpr GhcPs, LHsExpr GhcPs)] -> LHsExpr GhcPs -> (LHsExpr GhcPs, [(LHsExpr GhcPs, LHsExpr GhcPs)])           gather opExprList = \case             (L _ (OpApp l1 op1 _ r1)) -> gather ((op1, r1): opExprList) l1             final -> (final, opExprList)@@ -235,47 +234,44 @@                                               | xD <- docSharedWrapper layoutExpr x                                               , yD <- docSharedWrapper layoutExpr y                                               ]-      opLastDoc <- docSharedWrapper layoutExpr expOp-      expLastDoc <- docSharedWrapper layoutExpr expRight+      opLastDoc   <- docSharedWrapper layoutExpr expOp+      expLastDoc  <- docSharedWrapper layoutExpr expRight       hasComments <- hasAnyCommentsBelow lexpr       let allowPar = case (expOp, expRight) of             (L _ (HsVar (L _ (Unqual occname))), _)               | occNameString occname == "$" -> True             (_, L _ (HsApp _ (L _ HsVar{}))) -> False             _ -> True-      docAltFilter-        [ ( not hasComments+      runFilteredAlternative $ do+        addAlternativeCond (not hasComments)+          $ docSeq+          [ appSep $ docForceSingleline leftOperandDoc           , docSeq-            [ appSep $ docForceSingleline leftOperandDoc-            , docSeq-            $ (appListDocs <&> \(od, ed) -> docSeq-                [ appSep $ docForceSingleline od-                , appSep $ docForceSingleline ed-                ]-              )-            , appSep $ docForceSingleline opLastDoc-            , (if allowPar then docForceParSpacing else docForceSingleline)-                expLastDoc-            ]-          )+          $ appListDocs <&> \(od, ed) -> docSeq+              [ appSep $ docForceSingleline od+              , appSep $ docForceSingleline ed+              ]+          , appSep $ docForceSingleline opLastDoc+          , (if allowPar then docForceParSpacing else docForceSingleline)+              expLastDoc+          ]         -- this case rather leads to some unfortunate layouting than to anything         -- useful; disabling for now. (it interfers with cols stuff.)-        -- , docSetBaseY-        -- - $ docPar+        -- addAlternative+        --   $ docSetBaseY+        --   $ docPar         --     leftOperandDoc         --     ( docLines-        -- -    $ (appListDocs <&> \(od, ed) -> docCols ColOpPrefix [appSep od, docSetBaseY ed])+        --      $ (appListDocs <&> \(od, ed) -> docCols ColOpPrefix [appSep od, docSetBaseY ed])         --       ++ [docCols ColOpPrefix [appSep opLastDoc, docSetBaseY expLastDoc]]         --     )-        , (otherwise-          , docPar+        addAlternative $+          docPar             leftOperandDoc             ( docLines             $ (appListDocs <&> \(od, ed) -> docCols ColOpPrefix [appSep od, docSetBaseY ed])               ++ [docCols ColOpPrefix [appSep opLastDoc, docSetBaseY expLastDoc]]             )-          )-        ]     OpApp expLeft expOp _ expRight -> do       expDocLeft  <- docSharedWrapper layoutExpr expLeft       expDocOp    <- docSharedWrapper layoutExpr expOp@@ -285,47 +281,47 @@               | occNameString occname == "$" -> True             (_, L _ (HsApp _ (L _ HsVar{}))) -> False             _ -> True-      docAltFilter-        $   [ -- one-line-              (,) True-            $ docSeq-              [ appSep $ docForceSingleline expDocLeft-              , appSep $ docForceSingleline expDocOp-              , docForceSingleline expDocRight-              ]-            -- , -- line + freely indented block for right expression-            --   docSeq-            --   [ appSep $ docForceSingleline expDocLeft-            --   , appSep $ docForceSingleline expDocOp-            --   , docSetBaseY $ docAddBaseY BrIndentRegular expDocRight-            --   ]-            , -- two-line-              (,) True-            $ docAddBaseY BrIndentRegular-            $ docPar-                expDocLeft-                ( docForceSingleline-                $ docCols ColOpPrefix [appSep $ expDocOp, docSetBaseY expDocRight]-                )-            , -- one-line + par-              (,) allowPar-            $ docSeq-              [ appSep $ docForceSingleline expDocLeft-              , appSep $ docForceSingleline expDocOp-              , docForceParSpacing expDocRight-              ]-            , -- more lines-              (,) True-            $ docAddBaseY BrIndentRegular-            $ docPar-                expDocLeft-                (docCols ColOpPrefix [appSep $ expDocOp, docSetBaseY expDocRight])-            ]+      runFilteredAlternative $ do+        -- one-line+        addAlternative+          $ docSeq+          [ appSep $ docForceSingleline expDocLeft+          , appSep $ docForceSingleline expDocOp+          , docForceSingleline expDocRight+          ]+        -- -- line + freely indented block for right expression+        -- addAlternative+        --   $ docSeq+        --   [ appSep $ docForceSingleline expDocLeft+        --   , appSep $ docForceSingleline expDocOp+        --   , docSetBaseY $ docAddBaseY BrIndentRegular expDocRight+        --   ]+        -- two-line+        addAlternative+          $ docAddBaseY BrIndentRegular+          $ docPar+              expDocLeft+              ( docForceSingleline+              $ docCols ColOpPrefix [appSep $ expDocOp, docSetBaseY expDocRight]+              )+        -- one-line + par+        addAlternativeCond allowPar+          $ docSeq+          [ appSep $ docForceSingleline expDocLeft+          , appSep $ docForceSingleline expDocOp+          , docForceParSpacing expDocRight+          ]+        -- more lines+        addAlternative+          $ docAddBaseY BrIndentRegular+          $ docPar+              expDocLeft+              (docCols ColOpPrefix [appSep expDocOp, docSetBaseY expDocRight])     NegApp op _ -> do       opDoc <- docSharedWrapper layoutExpr op-      docSeq $ [ docLit $ Text.pack "-"-               , opDoc-               ]+      docSeq [ docLit $ Text.pack "-"+             , opDoc+             ]     HsPar innerExp -> do       innerExpDoc <- docSharedWrapper (docWrapNode lexpr . layoutExpr) innerExp       docAlt@@ -364,7 +360,7 @@       case splitFirstLast argDocs of         FirstLastEmpty -> docSeq           [ openLit-          , docNodeAnnKW lexpr (Just AnnOpenP) $ closeLit+          , docNodeAnnKW lexpr (Just AnnOpenP) closeLit           ]         FirstLastSingleton e -> docAlt           [ docCols ColTuple@@ -380,24 +376,21 @@             , closeLit             ]           ]-        FirstLast e1 ems eN ->-          docAltFilter-            [ (,) (not hasComments)-            $ docCols ColTuple-              (  [docSeq [openLit, docForceSingleline e1]]-              ++ (ems <&> \e -> docSeq [docCommaSep, docForceSingleline e])-              ++ [docSeq [docCommaSep, docNodeAnnKW lexpr (Just AnnOpenP) (docForceSingleline eN), closeLit]]-              )-            , (,) True-            $ let-                start = docCols ColTuples-                          [appSep $ openLit, e1]-                linesM = ems <&> \d ->-                        docCols ColTuples [docCommaSep, d]-                lineN = docCols ColTuples [docCommaSep, docNodeAnnKW lexpr (Just AnnOpenP) eN]-                end   = closeLit-              in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN] ++ [end]-            ]+        FirstLast e1 ems eN -> runFilteredAlternative $ do+          addAlternativeCond (not hasComments)+            $  docCols ColTuple+            $  [docSeq [openLit, docForceSingleline e1]]+            ++ (ems <&> \e -> docSeq [docCommaSep, docForceSingleline e])+            ++ [docSeq [docCommaSep, docNodeAnnKW lexpr (Just AnnOpenP) (docForceSingleline eN), closeLit]]+          addAlternative $+            let+              start = docCols ColTuples+                        [appSep openLit, e1]+              linesM = ems <&> \d ->+                      docCols ColTuples [docCommaSep, d]+              lineN = docCols ColTuples [docCommaSep, docNodeAnnKW lexpr (Just AnnOpenP) eN]+              end   = closeLit+            in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN, end]     HsCase cExp (MG lmatches@(L _ matches) _ _ _) -> do       cExpDoc <- docSharedWrapper layoutExpr cExp       binderDoc <- docLit $ Text.pack "->"@@ -429,13 +422,14 @@       let maySpecialIndent =             case indentPolicy of               IndentPolicyLeft -> BrIndentRegular-              _ -> BrIndentSpecial 3+              IndentPolicyMultiple -> BrIndentRegular+              IndentPolicyFree -> BrIndentSpecial 3       -- TODO: some of the alternatives (especially last and last-but-one)       -- overlap.-      docAltFilter-        [ -- if _ then _ else _-          (,) (not hasComments)-        $ docSeq+      runFilteredAlternative $ do+        -- if _ then _ else _+        addAlternativeCond (not hasComments)+          $ docSeq           [ appSep $ docLit $ Text.pack "if"           , appSep $ docForceSingleline ifExprDoc           , appSep $ docLit $ Text.pack "then"@@ -443,113 +437,115 @@           , appSep $ docLit $ Text.pack "else"           , docForceSingleline elseExprDoc           ]-        , -- either-          --   if expr-          --   then foo-          --     bar-          --   else foo-          --     bar-          -- or-          --   if expr-          --   then-          --     stuff-          --   else-          --     stuff-          -- note that this has par-spacing-          (,) True-        $ docSetParSpacing-        $ docAddBaseY BrIndentRegular-        $ docPar-            ( docSeq-              [ docNodeAnnKW lexpr Nothing $ appSep $ docLit $ Text.pack "if"-              , docNodeAnnKW lexpr (Just AnnIf) $ docForceSingleline ifExprDoc-              ])-            (docLines-              [ docAddBaseY BrIndentRegular-              $ docNodeAnnKW lexpr (Just AnnThen)-              $ docAlt-                [ docSeq [appSep $ docLit $ Text.pack "then", docForceParSpacing thenExprDoc]+        -- either+        --   if expr+        --   then foo+        --     bar+        --   else foo+        --     bar+        -- or+        --   if expr+        --   then+        --     stuff+        --   else+        --     stuff+        -- note that this has par-spacing+        addAlternative+          $ docSetParSpacing+          $ docAddBaseY BrIndentRegular+          $ docPar+              ( docSeq+                [ docNodeAnnKW lexpr Nothing $ appSep $ docLit $ Text.pack "if"+                , docNodeAnnKW lexpr (Just AnnIf) $ docForceSingleline ifExprDoc+                ])+              (docLines+                [ docAddBaseY BrIndentRegular+                $ docNodeAnnKW lexpr (Just AnnThen)+                $ docNonBottomSpacing $ docAlt+                  [ docSeq [appSep $ docLit $ Text.pack "then", docForceParSpacing thenExprDoc]+                  , docAddBaseY BrIndentRegular+                  $ docPar (docLit $ Text.pack "then") thenExprDoc+                  ]                 , docAddBaseY BrIndentRegular-                $ docPar (docLit $ Text.pack "then") thenExprDoc-                ]-              , docAddBaseY BrIndentRegular-              $ docAlt-                [ docSeq [appSep $ docLit $ Text.pack "else", docForceParSpacing elseExprDoc]+                $ docNonBottomSpacing $ docAlt+                  [ docSeq [appSep $ docLit $ Text.pack "else", docForceParSpacing elseExprDoc]+                  , docAddBaseY BrIndentRegular+                  $ docPar (docLit $ Text.pack "else") elseExprDoc+                  ]+                ])+        -- either+        --   if multi+        --      line+        --      condition+        --   then foo+        --     bar+        --   else foo+        --     bar+        -- or+        --   if multi+        --      line+        --      condition+        --   then+        --     stuff+        --   else+        --     stuff+        -- note that this does _not_ have par-spacing+        addAlternative+          $ docAddBaseY BrIndentRegular+          $ docPar+              ( docAddBaseY maySpecialIndent+              $ docSeq+                [ docNodeAnnKW lexpr Nothing $ appSep $ docLit $ Text.pack "if"+                , docNodeAnnKW lexpr (Just AnnIf) $ ifExprDoc+                ])+              (docLines+                [ docAddBaseY BrIndentRegular+                $ docNodeAnnKW lexpr (Just AnnThen)+                $ docAlt+                  [ docSeq [appSep $ docLit $ Text.pack "then", docForceParSpacing thenExprDoc]+                  , docAddBaseY BrIndentRegular+                  $ docPar (docLit $ Text.pack "then") thenExprDoc+                  ]                 , docAddBaseY BrIndentRegular-                $ docPar (docLit $ Text.pack "else") elseExprDoc-                ]-              ])-        , -- either-          --   if multi-          --      line-          --      condition-          --   then foo-          --     bar-          --   else foo-          --     bar-          -- or-          --   if multi-          --      line-          --      condition-          --   then-          --     stuff-          --   else-          --     stuff-          -- note that this does _not_ have par-spacing-          (,) True-        $ docAddBaseY BrIndentRegular-        $ docPar-            ( docAddBaseY maySpecialIndent+                $ docAlt+                  [ docSeq [appSep $ docLit $ Text.pack "else", docForceParSpacing elseExprDoc]+                  , docAddBaseY BrIndentRegular+                  $ docPar (docLit $ Text.pack "else") elseExprDoc+                  ]+                ])+        addAlternative+          $ docSetBaseY+          $ docLines+            [ docAddBaseY maySpecialIndent             $ docSeq               [ docNodeAnnKW lexpr Nothing $ appSep $ docLit $ Text.pack "if"               , docNodeAnnKW lexpr (Just AnnIf) $ ifExprDoc-              ])-            (docLines-              [ docAddBaseY BrIndentRegular-              $ docNodeAnnKW lexpr (Just AnnThen)-              $ docAlt-                [ docSeq [appSep $ docLit $ Text.pack "then", docForceParSpacing thenExprDoc]-                , docAddBaseY BrIndentRegular-                $ docPar (docLit $ Text.pack "then") thenExprDoc-                ]-              , docAddBaseY BrIndentRegular-              $ docAlt-                [ docSeq [appSep $ docLit $ Text.pack "else", docForceParSpacing elseExprDoc]-                , docAddBaseY BrIndentRegular-                $ docPar (docLit $ Text.pack "else") elseExprDoc-                ]-              ])-        , (,) True-        $ docSetBaseY-        $ docLines-          [ docAddBaseY maySpecialIndent-          $ docSeq-            [ docNodeAnnKW lexpr Nothing $ appSep $ docLit $ Text.pack "if"-            , docNodeAnnKW lexpr (Just AnnIf) $ ifExprDoc+              ]+            , docNodeAnnKW lexpr (Just AnnThen)+            $ docAddBaseY BrIndentRegular+            $ docPar (docLit $ Text.pack "then") thenExprDoc+            , docAddBaseY BrIndentRegular+            $ docPar (docLit $ Text.pack "else") elseExprDoc             ]-          , docNodeAnnKW lexpr (Just AnnThen)-          $ docAddBaseY BrIndentRegular-          $ docPar (docLit $ Text.pack "then") thenExprDoc-          , docAddBaseY BrIndentRegular-          $ docPar (docLit $ Text.pack "else") elseExprDoc-          ]-        ]     HsMultiIf _ cases -> do-      clauseDocs <- cases `forM` layoutGrhs-      binderDoc <- docLit $ Text.pack "->"+      clauseDocs  <- cases `forM` layoutGrhs+      binderDoc   <- docLit $ Text.pack "->"       hasComments <- hasAnyCommentsBelow lexpr       docSetParSpacing $ docAddBaseY BrIndentRegular $ docPar         (docLit $ Text.pack "if")         (layoutPatternBindFinal Nothing binderDoc Nothing clauseDocs Nothing hasComments)     HsLet binds exp1 -> do-      expDoc1 <- docSharedWrapper layoutExpr exp1+      expDoc1   <- docSharedWrapper layoutExpr exp1       -- We jump through some ugly hoops here to ensure proper sharing.       mBindDocs <- mapM (fmap (fmap return) . docWrapNodeRest lexpr . return)                =<< layoutLocalBinds binds       let-        ifIndentLeftElse :: a -> a -> a-        ifIndentLeftElse x y =-          if indentPolicy == IndentPolicyLeft then x else y+        ifIndentFreeElse :: a -> a -> a+        ifIndentFreeElse x y =+          case indentPolicy of+            IndentPolicyLeft -> y+            IndentPolicyMultiple -> y+            IndentPolicyFree -> x       -- this `docSetBaseAndIndent` might seem out of place (especially the       -- Indent part; setBase is necessary due to the use of docLines below),       -- but is here due to ghc-exactprint's DP handling of "let" in@@ -562,35 +558,35 @@         Just [bindDoc] -> docAlt           [ docSeq               [ appSep $ docLit $ Text.pack "let"-              , appSep $ docForceSingleline $ bindDoc+              , appSep $ docForceSingleline bindDoc               , appSep $ docLit $ Text.pack "in"-              , docForceSingleline $ expDoc1+              , docForceSingleline expDoc1               ]           , docLines               [ docAlt                   [ docSeq                       [ appSep $ docLit $ Text.pack "let"-                      , ifIndentLeftElse docForceSingleline docSetBaseAndIndent+                      , ifIndentFreeElse docSetBaseAndIndent docForceSingleline                       $ bindDoc                       ]                   , docAddBaseY BrIndentRegular                   $ docPar                     (docLit $ Text.pack "let")-                    (docSetBaseAndIndent $ bindDoc)+                    (docSetBaseAndIndent bindDoc)                   ]               , docAlt                   [ docSeq-                      [ appSep $ docLit $ Text.pack $ ifIndentLeftElse "in" "in "-                      , ifIndentLeftElse docForceSingleline docSetBaseAndIndent expDoc1+                      [ appSep $ docLit $ Text.pack $ ifIndentFreeElse "in " "in"+                      , ifIndentFreeElse docSetBaseAndIndent docForceSingleline expDoc1                       ]                   , docAddBaseY BrIndentRegular                   $ docPar                     (docLit $ Text.pack "in")-                    (docSetBaseY $ expDoc1)+                    (docSetBaseY expDoc1)                   ]               ]           ]-        Just bindDocs@(_:_) -> docAltFilter+        Just bindDocs@(_:_) -> runFilteredAlternative $ do           --either           --  let           --    a = b@@ -604,43 +600,40 @@           --    c = d           --  in           --    fooooooooooooooooooo-          [ ( indentPolicy == IndentPolicyLeft-            , docLines-              [ docAddBaseY BrIndentRegular-              $ docPar-                (docLit $ Text.pack "let")-                (docSetBaseAndIndent $ docLines $ bindDocs)-              , docSeq-                [ docLit $ Text.pack "in "-                , docAddBaseY BrIndentRegular $ expDoc1+          let noHangingBinds =+                [ docAddBaseY BrIndentRegular+                $ docPar+                  (docLit $ Text.pack "let")+                  (docSetBaseAndIndent $ docLines bindDocs)+                , docSeq+                  [ docLit $ Text.pack "in "+                  , docAddBaseY BrIndentRegular expDoc1+                  ]                 ]-              ]-            )-          , ( indentPolicy /= IndentPolicyLeft-            , docLines+          addAlternative $ case indentPolicy of+            IndentPolicyLeft     -> docLines noHangingBinds+            IndentPolicyMultiple -> docLines noHangingBinds+            IndentPolicyFree     -> docLines               [ docSeq                 [ appSep $ docLit $ Text.pack "let"-                , docSetBaseAndIndent $ docLines $ bindDocs+                , docSetBaseAndIndent $ docLines bindDocs                 ]               , docSeq                 [ appSep $ docLit $ Text.pack "in "-                , docSetBaseY $ expDoc1+                , docSetBaseY expDoc1                 ]               ]-            )-          , ( True-            , docLines-              [ docAddBaseY BrIndentRegular-              $ docPar-                (docLit $ Text.pack "let")-                (docSetBaseAndIndent $ docLines $ bindDocs)-              , docAddBaseY BrIndentRegular-              $ docPar-                (docLit $ Text.pack "in")-                (docSetBaseY $ expDoc1)-              ]-            )-          ]+          addAlternative+            $ docLines+            [ docAddBaseY BrIndentRegular+            $ docPar+              (docLit $ Text.pack "let")+              (docSetBaseAndIndent $ docLines $ bindDocs)+            , docAddBaseY BrIndentRegular+            $ docPar+              (docLit $ Text.pack "in")+              (docSetBaseY $ expDoc1)+            ]         _ -> docSeq [appSep $ docLit $ Text.pack "let in", expDoc1]       -- docSeq [appSep $ docLit "let in", expDoc1]     HsDo DoExpr (L _ stmts) _ -> do@@ -660,11 +653,11 @@     HsDo x  (L _ stmts) _ | case x of { ListComp -> True                                       ; MonadComp -> True                                       ; _ -> False } -> do-      stmtDocs <- docSharedWrapper layoutStmt `mapM` stmts+      stmtDocs    <- docSharedWrapper layoutStmt `mapM` stmts       hasComments <- hasAnyCommentsBelow lexpr-      docAltFilter-        [ (,) (not hasComments)-        $ docSeq+      runFilteredAlternative $ do+        addAlternativeCond (not hasComments)+          $ docSeq           [ docNodeAnnKW lexpr Nothing           $ appSep           $ docLit@@ -675,11 +668,11 @@           $ List.last stmtDocs           , appSep $ docLit $ Text.pack "|"           , docSeq $ List.intersperse docCommaSep-                  $ fmap docForceSingleline $ List.init stmtDocs+          $ docForceSingleline <$> List.init stmtDocs           , docLit $ Text.pack " ]"           ]-        , (,) True-        $ let+        addAlternative $+          let             start = docCols ColListComp                       [ docNodeAnnKW lexpr Nothing                       $ appSep $ docLit $ Text.pack "["@@ -694,12 +687,11 @@                     docCols ColListComp [docCommaSep, d]             end   = docLit $ Text.pack "]"           in docSetBaseY $ docLines $ [start, line1] ++ lineM ++ [end]-        ]     HsDo{} -> do       -- TODO       unknownNodeError "HsDo{} no comp" lexpr     ExplicitList _ _ elems@(_:_) -> do-      elemDocs <- elems `forM` docSharedWrapper layoutExpr+      elemDocs    <- elems `forM` docSharedWrapper layoutExpr       hasComments <- hasAnyCommentsBelow lexpr       case splitFirstLast elemDocs of         FirstLastEmpty -> docSeq@@ -716,28 +708,26 @@             [ docSeq               [ docLit $ Text.pack "["               , docSeparator-              , docSetBaseY $ docNodeAnnKW lexpr (Just AnnOpenS) $ e+              , docSetBaseY $ docNodeAnnKW lexpr (Just AnnOpenS) e               ]             , docLit $ Text.pack "]"             ]           ]-        FirstLast e1 ems eN ->-          docAltFilter-            [  (,) (not hasComments)+        FirstLast e1 ems eN -> runFilteredAlternative $ do+          addAlternativeCond (not hasComments)             $  docSeq             $  [docLit $ Text.pack "["]             ++ List.intersperse docCommaSep (docForceSingleline <$> (e1:ems ++ [docNodeAnnKW lexpr (Just AnnOpenS) eN]))             ++ [docLit $ Text.pack "]"]-            , (,) True-            $ let-                start = docCols ColList-                          [appSep $ docLit $ Text.pack "[", e1]-                linesM = ems <&> \d ->-                        docCols ColList [docCommaSep, d]-                lineN = docCols ColList [docCommaSep, docNodeAnnKW lexpr (Just AnnOpenS) eN]-                end   = docLit $ Text.pack "]"-              in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN] ++ [end]-            ]+          addAlternative $+            let+              start = docCols ColList+                        [appSep $ docLit $ Text.pack "[", e1]+              linesM = ems <&> \d ->+                      docCols ColList [docCommaSep, d]+              lineN = docCols ColList [docCommaSep, docNodeAnnKW lexpr (Just AnnOpenS) eN]+              end   = docLit $ Text.pack "]"+            in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN] ++ [end]     ExplicitList _ _ [] ->       docLit $ Text.pack "[]"     ExplicitPArr{} -> do@@ -757,20 +747,20 @@         fExpDoc <- if pun           then return Nothing           else Just <$> docSharedWrapper layoutExpr fExpr-        return $ (fieldl, lrdrNameToText lnameF, fExpDoc)+        return (fieldl, lrdrNameToText lnameF, fExpDoc)       let line1 appender wrapper =             [ appender $ docLit $ Text.pack "{"-            , docWrapNodePrior fd1l $ appSep $ docLit $ fd1n+            , docWrapNodePrior fd1l $ appSep $ docLit fd1n             , case fd1e of                 Just x -> docSeq                   [ appSep $ docLit $ Text.pack "="-                  , docWrapNodeRest fd1l $ wrapper $ x+                  , docWrapNodeRest fd1l $ wrapper x                   ]                 Nothing -> docEmpty             ]       let lineR wrapper = fdr <&> \(lfield, fText, fDoc) ->             [ docCommaSep-            , appSep $ docLit $ fText+            , appSep $ docLit fText             , case fDoc of                 Just x -> docWrapNode lfield $ docSeq                   [ appSep $ docLit $ Text.pack "="@@ -784,14 +774,14 @@             ]       docAlt         [  docSeq-        $  [docNodeAnnKW lexpr Nothing $ nameDoc, docSeparator]+        $  [docNodeAnnKW lexpr Nothing nameDoc, docSeparator]         ++ line1 id docForceSingleline         ++ join (lineR docForceSingleline)         ++ lineN         , docSetParSpacing         $ docAddBaseY BrIndentRegular         $ docPar-            (docNodeAnnKW lexpr Nothing $ nameDoc)+            (docNodeAnnKW lexpr Nothing nameDoc)             ( docNonBottomSpacing             $ docLines             $  [docCols ColRecUpdate $ line1 appSep (docAddBaseY BrIndentRegular)]@@ -808,20 +798,20 @@         fExpDoc <- if pun           then return Nothing           else Just <$> docSharedWrapper layoutExpr fExpr-        return $ (fieldl, lrdrNameToText lnameF, fExpDoc)+        return (fieldl, lrdrNameToText lnameF, fExpDoc)       let line1 appender wrapper =             [ appender $ docLit $ Text.pack "{"-            , docWrapNodePrior fd1l $ appSep $ docLit $ fd1n+            , docWrapNodePrior fd1l $ appSep $ docLit fd1n             , case fd1e of                 Just x -> docSeq                   [ appSep $ docLit $ Text.pack "="-                  , docWrapNodeRest fd1l $ wrapper $ x+                  , docWrapNodeRest fd1l $ wrapper x                   ]                 Nothing -> docEmpty             ]       let lineR wrapper = fdr <&> \(lfield, fText, fDoc) ->             [ docCommaSep-            , appSep $ docLit $ fText+            , appSep $ docLit fText             , case fDoc of                 Just x -> docWrapNode lfield $ docSeq                   [ appSep $ docLit $ Text.pack "="@@ -839,7 +829,7 @@             ]       docAlt         [  docSeq-        $  [docNodeAnnKW lexpr Nothing $ nameDoc, docSeparator]+        $  [docNodeAnnKW lexpr Nothing nameDoc, docSeparator]         ++ line1 id docForceSingleline         ++ join (lineR docForceSingleline)         ++ lineDot@@ -847,7 +837,7 @@         , docSetParSpacing         $ docAddBaseY BrIndentRegular         $ docPar-            (docNodeAnnKW lexpr Nothing $ nameDoc)+            (docNodeAnnKW lexpr Nothing nameDoc)             ( docNonBottomSpacing             $ docLines             $  [docCols ColRecUpdate $ line1 appSep (docAddBaseY BrIndentRegular)]@@ -870,77 +860,76 @@           return $ case ambName of             Unambiguous n _ -> (lfield, lrdrNameToText n, rFExpDoc)             Ambiguous   n _ -> (lfield, lrdrNameToText n, rFExpDoc)-      docAltFilter+      runFilteredAlternative $ do         -- container { fieldA = blub, fieldB = blub }-        [ ( True-          , docSeq-            [ docNodeAnnKW lexpr Nothing $ appSep $ docForceSingleline rExprDoc-            , appSep $ docLit $ Text.pack "{"-            , appSep $ docSeq $ List.intersperse docCommaSep-                    $ rFs <&> \case-                      (lfield, fieldStr, Just fieldDoc) ->-                        docWrapNode lfield $ docSeq-                              [ appSep $ docLit fieldStr-                              , appSep $ docLit $ Text.pack "="-                              , docForceSingleline fieldDoc-                              ]-                      (lfield, fieldStr, Nothing) ->-                        docWrapNode lfield $ docLit fieldStr-            , docLit $ Text.pack "}"-            ]-          )+        addAlternative+          $ docSeq+          [ docNodeAnnKW lexpr Nothing $ appSep $ docForceSingleline rExprDoc+          , appSep $ docLit $ Text.pack "{"+          , appSep $ docSeq $ List.intersperse docCommaSep+                  $ rFs <&> \case+                    (lfield, fieldStr, Just fieldDoc) ->+                      docWrapNode lfield $ docSeq+                            [ appSep $ docLit fieldStr+                            , appSep $ docLit $ Text.pack "="+                            , docForceSingleline fieldDoc+                            ]+                    (lfield, fieldStr, Nothing) ->+                      docWrapNode lfield $ docLit fieldStr+          , docLit $ Text.pack "}"+          ]         -- hanging single-line fields         -- container { fieldA = blub         --           , fieldB = blub         --           }-        , ( indentPolicy /= IndentPolicyLeft-          , docSeq-            [ docNodeAnnKW lexpr Nothing $ appSep rExprDoc-            , docSetBaseY $ docLines $ let-                line1 = docCols ColRecUpdate-                  [ appSep $ docLit $ Text.pack "{"-                  , docWrapNodePrior rF1f $ appSep $ docLit $ rF1n-                  , case rF1e of-                      Just x -> docWrapNodeRest rF1f $ docSeq-                                      [ appSep $ docLit $ Text.pack "="+        addAlternativeCond (indentPolicy == IndentPolicyFree)+          $ docSeq+          [ docNodeAnnKW lexpr Nothing $ appSep rExprDoc+          , docSetBaseY $ docLines $ let+              line1 = docCols ColRecUpdate+                [ appSep $ docLit $ Text.pack "{"+                , docWrapNodePrior rF1f $ appSep $ docLit rF1n+                , case rF1e of+                    Just x -> docWrapNodeRest rF1f $ docSeq+                                    [ appSep $ docLit $ Text.pack "="+                                    , docForceSingleline x+                                    ]+                    Nothing -> docEmpty+                ]+              lineR = rFr <&> \(lfield, fText, fDoc) -> docWrapNode lfield $ docCols ColRecUpdate+                [ docCommaSep+                , appSep $ docLit fText+                , case fDoc of+                    Just x ->  docSeq [ appSep $ docLit $ Text.pack "="                                       , docForceSingleline x                                       ]-                      Nothing -> docEmpty-                  ]-                lineR = rFr <&> \(lfield, fText, fDoc) -> docWrapNode lfield $ docCols ColRecUpdate-                  [ docCommaSep-                  , appSep $ docLit $ fText-                  , case fDoc of-                      Just x ->  docSeq [ appSep $ docLit $ Text.pack "="-                                        , docForceSingleline x-                                        ]-                      Nothing -> docEmpty-                  ]-                lineN = docSeq-                  [ docNodeAnnKW lexpr (Just AnnOpenC) docEmpty-                  , docLit $ Text.pack "}"-                  ]-                in [line1] ++ lineR ++ [lineN]-            ]-          )-          -- non-hanging with expressions placed to the right of the names-          -- container-          -- { fieldA = blub-          -- , fieldB = potentially-          --     multiline-          -- }-        , ( True-          , docSetParSpacing+                    Nothing -> docEmpty+                ]+              lineN = docSeq+                [ docNodeAnnKW lexpr (Just AnnOpenC) docEmpty+                , docLit $ Text.pack "}"+                ]+              in [line1] ++ lineR ++ [lineN]+          ]+        -- non-hanging with expressions placed to the right of the names+        -- container+        -- { fieldA = blub+        -- , fieldB = potentially+        --     multiline+        -- }+        addAlternative+          $ docSetParSpacing           $ docAddBaseY BrIndentRegular           $ docPar-              (docNodeAnnKW lexpr Nothing $ rExprDoc)+              (docNodeAnnKW lexpr Nothing rExprDoc)               (docNonBottomSpacing $ docLines $ let-                expressionWrapper = if indentPolicy == IndentPolicyLeft-                  then docForceParSpacing-                  else docSetBaseY+                expressionWrapper = case indentPolicy of+                  IndentPolicyLeft -> docForceParSpacing+                  IndentPolicyMultiple -> docForceParSpacing+                  IndentPolicyFree -> docSetBaseY                 line1 = docCols ColRecUpdate                   [ appSep $ docLit $ Text.pack "{"-                  , docWrapNodePrior rF1f $ appSep $ docLit $ rF1n+                  , docWrapNodePrior rF1f $ appSep $ docLit rF1n                   , docWrapNodeRest rF1f $ case rF1e of                       Just x -> docAlt                         [ docSeq [ appSep $ docLit $ Text.pack "="@@ -954,7 +943,7 @@                 lineR = rFr <&> \(lfield, fText, fDoc) -> docWrapNode lfield                   $ docCols ColRecUpdate                   [ docCommaSep-                  , appSep $ docLit $ fText+                  , appSep $ docLit fText                   , case fDoc of                       Just x -> docAlt                         [ docSeq [ appSep $ docLit $ Text.pack "="@@ -971,8 +960,6 @@                   ]                 in [line1] ++ lineR ++ [lineN]               )-          )-        ] #if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */     ExprWithTySig exp1 (HsWC _ (HsIB _ typ1 _)) -> do #else /* ghc-8.0 */@@ -1078,7 +1065,7 @@       docLit $ Text.pack "_"     EAsPat asName asExpr -> do       docSeq-        [ docLit $ (lrdrNameToText asName) <> Text.pack "@"+        [ docLit $ lrdrNameToText asName <> Text.pack "@"         , layoutExpr asExpr         ]     EViewPat{} -> do@@ -1100,7 +1087,31 @@ #endif  -#if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */+#if MIN_VERSION_ghc(8,4,0) /* ghc-8.4 */+litBriDoc :: HsLit GhcPs -> BriDocFInt+litBriDoc = \case+  HsChar       (SourceText t) _c                         -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ ['\'', c, '\'']+  HsCharPrim   (SourceText t) _c                         -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ ['\'', c, '\'']+  HsString     (SourceText t) _fastString                -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ FastString.unpackFS fastString+  HsStringPrim (SourceText t) _byteString                -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ Data.ByteString.Char8.unpack byteString+  HsInt        _              (IL (SourceText t) _ _)    -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsIntPrim    (SourceText t) _i                         -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsWordPrim   (SourceText t) _i                         -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsInt64Prim  (SourceText t) _i                         -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsWord64Prim (SourceText t) _i                         -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsInteger (SourceText t) _i                      _type -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsRat     _              (FL (SourceText t) _ _) _type -> BDFLit $ Text.pack t+  HsFloatPrim  _ (FL (SourceText t) _ _)                 -> BDFLit $ Text.pack t+  HsDoublePrim _ (FL (SourceText t) _ _)                 -> BDFLit $ Text.pack t+  _ -> error "litBriDoc: literal with no SourceText"++overLitValBriDoc :: OverLitVal -> BriDocFInt+overLitValBriDoc = \case+  HsIntegral   (IL (SourceText t) _ _) -> BDFLit $ Text.pack t+  HsFractional (FL (SourceText t) _ _) -> BDFLit $ Text.pack t+  HsIsString (SourceText t) _ -> BDFLit $ Text.pack t+  _ -> error "overLitValBriDoc: literal with no SourceText"+#elif MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */ litBriDoc :: HsLit -> BriDocFInt litBriDoc = \case   HsChar       (SourceText t) _c          -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ ['\'', c, '\'']@@ -1112,10 +1123,10 @@   HsWordPrim   (SourceText t) _i          -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i   HsInt64Prim  (SourceText t) _i          -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i   HsWord64Prim (SourceText t) _i          -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i-  HsInteger (SourceText t) _i _type       -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i-  HsRat (FL t _) _type       -> BDFLit $ Text.pack t-  HsFloatPrim  (FL t _)      -> BDFLit $ Text.pack t-  HsDoublePrim (FL t _)      -> BDFLit $ Text.pack t+  HsInteger    (SourceText t) _i _type    -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ show i+  HsRat        (FL t _) _type             -> BDFLit $ Text.pack t+  HsFloatPrim  (FL t _)                   -> BDFLit $ Text.pack t+  HsDoublePrim (FL t _)                   -> BDFLit $ Text.pack t   _ -> error "litBriDoc: literal with no SourceText"  overLitValBriDoc :: OverLitVal -> BriDocFInt@@ -1124,7 +1135,7 @@   HsFractional (FL t _) -> BDFLit $ Text.pack t   HsIsString (SourceText t) _        -> BDFLit $ Text.pack t   _ -> error "overLitValBriDoc: literal with no SourceText"-#else+#else                        /* ghc-8.0 */ litBriDoc :: HsLit -> BriDocFInt litBriDoc = \case   HsChar       t _c          -> BDFLit $ Text.pack t -- BDFLit $ Text.pack $ ['\'', c, '\'']
src/Language/Haskell/Brittany/Internal/Layouters/Expr.hs-boot view
@@ -14,7 +14,6 @@ import           Language.Haskell.Brittany.Internal.Types import           Language.Haskell.Brittany.Internal.LayouterBasics -import           RdrName ( RdrName(..) ) import           GHC ( runGhc, GenLocated(L), moduleNameString ) import           HsSyn import           Name@@ -23,8 +22,12 @@  layoutExpr :: ToBriDoc HsExpr --- layoutStmt :: ToBriDoc' (StmtLR RdrName RdrName (LHsExpr RdrName))+-- layoutStmt :: ToBriDoc' (StmtLR GhcPs GhcPs (LHsExpr GhcPs)) +#if   MIN_VERSION_ghc(8,4,0) /* ghc-8.4 */+litBriDoc :: HsLit GhcPs -> BriDocFInt+#else /* ghc-8.0 && ghc-8.2 */ litBriDoc :: HsLit -> BriDocFInt+#endif  overLitValBriDoc :: OverLitVal -> BriDocFInt
src/Language/Haskell/Brittany/Internal/Layouters/IE.hs view
@@ -11,7 +11,6 @@ import           Language.Haskell.Brittany.Internal.LayouterBasics import           Language.Haskell.Brittany.Internal.Config.Types -import           RdrName (RdrName(..)) import           GHC     ( unLoc                          , runGhc                          , GenLocated(L)@@ -46,18 +45,15 @@   IEThingWith _ (IEWildcard _) _ _ -> docSeq [ien, docLit $ Text.pack "(..)"]   IEThingWith _ _ ns _ -> do     hasComments <- hasAnyCommentsBelow lie-    docAltFilter-      [ ( not hasComments-        , docSeq+    runFilteredAlternative $ do+      addAlternativeCond (not hasComments)+        $  docSeq         $  [ien, docLit $ Text.pack "("]         ++ intersperse docCommaSep (map nameDoc ns)         ++ [docParenR]-        )-      , (otherwise-        , docAddBaseY BrIndentRegular+      addAlternative+        $ docAddBaseY BrIndentRegular         $ docPar ien (layoutItems (splitFirstLast ns))-        )-      ]    where     nameDoc = (docLit =<<) . lrdrNameToTextAnn . prepareName     layoutItem n = docSeq [docCommaSep, docWrapNode n $ nameDoc n]@@ -92,7 +88,7 @@ -- handling of the resulting list. Adding parens is -- left to the caller since that is context sensitive layoutAnnAndSepLLIEs-  :: Located [LIE RdrName] -> ToBriDocM [ToBriDocM BriDocNumbered]+  :: Located [LIE GhcPs] -> ToBriDocM [ToBriDocM BriDocNumbered] layoutAnnAndSepLLIEs llies@(L _ lies) = do   let makeIENode ie = docSeq [docCommaSep, ie]   let ieDocs = layoutIE <$> lies@@ -117,29 +113,26 @@ -- () -- no comments -- ( -- a comment -- )-layoutLLIEs :: Bool -> Located [LIE RdrName] -> ToBriDocM BriDocNumbered+layoutLLIEs :: Bool -> Located [LIE GhcPs] -> ToBriDocM BriDocNumbered layoutLLIEs enableSingleline llies = do   ieDs        <- layoutAnnAndSepLLIEs llies   hasComments <- hasAnyCommentsBelow llies-  case ieDs of-    [] -> docAltFilter-      [ (not hasComments, docLit $ Text.pack "()")-      , ( hasComments-        , docPar (docSeq [docParenLSep, docWrapNodeRest llies docEmpty])+  runFilteredAlternative $+    case ieDs of+      [] -> do+        addAlternativeCond (not hasComments) $+          docLit $ Text.pack "()"+        addAlternativeCond hasComments $+          docPar (docSeq [docParenLSep, docWrapNodeRest llies docEmpty])                  docParenR-        )-      ]-    (ieDsH:ieDsT) -> docAltFilter-      [ ( not hasComments && enableSingleline-        , docSeq-        $  [docLit (Text.pack "(")]-        ++ (docForceSingleline <$> ieDs)-        ++ [docParenR]-        )-      , ( otherwise-        , docPar (docSetBaseY $ docSeq [docParenLSep, ieDsH])-        $  docLines-        $  ieDsT-        ++ [docParenR]-        )-      ]+      (ieDsH:ieDsT) -> do+        addAlternativeCond (not hasComments && enableSingleline)+          $  docSeq+          $  [docLit (Text.pack "(")]+          ++ (docForceSingleline <$> ieDs)+          ++ [docParenR]+        addAlternative+          $  docPar (docSetBaseY $ docSeq [docParenLSep, ieDsH])+          $  docLines+          $  ieDsT+          ++ [docParenR]
src/Language/Haskell/Brittany/Internal/Layouters/Import.hs view
@@ -7,7 +7,6 @@ import           Language.Haskell.Brittany.Internal.Layouters.IE import           Language.Haskell.Brittany.Internal.Config.Types -import           RdrName                                  ( RdrName(..) ) import           GHC                                      ( unLoc                                                           , GenLocated(L)                                                           , moduleNameString@@ -49,7 +48,7 @@     importAsCol <- mAsk <&> _conf_layout .> _lconfig_importAsColumn .> confUnpack     indentPolicy <- mAsk <&>  _conf_layout .> _lconfig_indentPolicy .> confUnpack     let-      compact  = indentPolicy == IndentPolicyLeft+      compact  = indentPolicy /= IndentPolicyFree       modNameT = Text.pack $ moduleNameString modName       pkgNameT = Text.pack . prepPkg . sl_st <$> pkg       masT     = Text.pack . moduleNameString . prepModName <$> mas@@ -98,25 +97,21 @@                 [] -> if hasComments                   then docPar                     (docSeq [hidDoc, docParenLSep, docWrapNode llies docEmpty])-                    (docEnsureIndent (BrIndentSpecial hidDocColDiff) $ docParenR)+                    (docEnsureIndent (BrIndentSpecial hidDocColDiff) docParenR)                   else docSeq [hidDoc, docParenLSep, docSeparator, docParenR]                   -- ..[hiding].( b )-                [ieD] -> docAltFilter-                  [ ( not hasComments-                    , docSeq-                      [ hidDoc-                      , docParenLSep-                      , docForceSingleline $ ieD-                      , docSeparator-                      , docParenR-                      ]-                    )-                  , ( otherwise-                    , docPar-                      (docSeq [hidDoc, docParenLSep, docNonBottomSpacing ieD])-                      (docEnsureIndent (BrIndentSpecial hidDocColDiff) docParenR)-                    )-                  ]+                [ieD] -> runFilteredAlternative $ do+                  addAlternativeCond (not hasComments)+                    $ docSeq+                    [ hidDoc+                    , docParenLSep+                    , docForceSingleline ieD+                    , docSeparator+                    , docParenR+                    ]+                  addAlternative $ docPar+                    (docSeq [hidDoc, docParenLSep, docNonBottomSpacing ieD])+                    (docEnsureIndent (BrIndentSpecial hidDocColDiff) docParenR)                   -- ..[hiding].( b                   --            , b'                   --            )
src/Language/Haskell/Brittany/Internal/Layouters/Module.hs view
@@ -8,7 +8,6 @@ import           Language.Haskell.Brittany.Internal.Layouters.Import import           Language.Haskell.Brittany.Internal.Config.Types -import           RdrName (RdrName(..)) import GHC (unLoc, runGhc, GenLocated(L), moduleNameString, AnnKeywordId(..)) import           HsSyn import           Name@@ -33,30 +32,35 @@       <&> _conf_layout       .>  _lconfig_allowSingleLineExportList       .>  confUnpack+    -- the config should not prevent single-line layout when there is no+    -- export list+    let allowSingleLine = allowSingleLineExportList || Data.Maybe.isNothing les     docLines       $ docSeq           [ docNodeAnnKW lmod Nothing docEmpty              -- A pseudo node that serves merely to force documentation              -- before the node-          , docNodeMoveToKWDP lmod AnnModule $ docAltFilter-            [ (,) allowSingleLineExportList $ docForceSingleline $ docSeq-                   [ appSep $ docLit $ Text.pack "module"-                   , appSep $ docLit tn-                   , docWrapNode lmod $ appSep $ case les of-                     Nothing -> docEmpty-                     Just x  -> layoutLLIEs True x-                   , docLit $ Text.pack "where"-                   ]-            , (,) otherwise $ docLines-                   [ docAddBaseY BrIndentRegular $ docPar-                     (docSeq [appSep $ docLit $ Text.pack "module", docLit tn]-                     )-                     (docWrapNode lmod $ case les of-                       Nothing -> docEmpty-                       Just x  -> layoutLLIEs False x-                     )-                   , docLit $ Text.pack "where"-                   ]-            ]+          , docNodeMoveToKWDP lmod AnnModule $ runFilteredAlternative $ do+            addAlternativeCond allowSingleLine $+              docForceSingleline+                $ docSeq+                [ appSep $ docLit $ Text.pack "module"+                , appSep $ docLit tn+                , docWrapNode lmod $ appSep $ case les of+                  Nothing -> docEmpty+                  Just x  -> layoutLLIEs True x+                , docLit $ Text.pack "where"+                ]+            addAlternative+              $ docLines+              [ docAddBaseY BrIndentRegular $ docPar+                (docSeq [appSep $ docLit $ Text.pack "module", docLit tn]+                )+                (docWrapNode lmod $ case les of+                  Nothing -> docEmpty+                  Just x  -> layoutLLIEs False x+                )+              , docLit $ Text.pack "where"+              ]           ]       : map layoutImport imports
src/Language/Haskell/Brittany/Internal/Layouters/Pattern.hs view
@@ -13,7 +13,6 @@ import           Language.Haskell.Brittany.Internal.Types import           Language.Haskell.Brittany.Internal.LayouterBasics -import           RdrName ( RdrName(..) ) import           GHC ( Located, runGhc, GenLocated(L), moduleNameString ) import           HsSyn import           Name@@ -34,7 +33,7 @@ --        ^^^^^^^^^^ this part -- We will use `case .. of` as the imagined prefix to the examples used in -- the different cases below.-layoutPat :: ToBriDocC (Pat RdrName) (Seq BriDocNumbered)+layoutPat :: ToBriDocC (Pat GhcPs) (Seq BriDocNumbered) layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of   WildPat _  -> fmap Seq.singleton $ docLit $ Text.pack "_"     -- _ -> expr@@ -94,14 +93,14 @@       fExpDoc <- if pun         then return Nothing         else Just <$> docSharedWrapper layoutPat fPat-      return $ (lrdrNameToText lnameF, fExpDoc)-    fmap Seq.singleton $ docSeq+      return (lrdrNameToText lnameF, fExpDoc)+    Seq.singleton <$> docSeq       [ appSep $ docLit t       , appSep $ docLit $ Text.pack "{"       , docSeq $ List.intersperse docCommaSep                $ fds <&> \case           (fieldName, Just fieldDoc) -> docSeq-            [ appSep $ docLit $ fieldName+            [ appSep $ docLit fieldName             , appSep $ docLit $ Text.pack "="             , fieldDoc >>= colsWrapPat             ]@@ -112,7 +111,7 @@   ConPatIn lname (RecCon (HsRecFields [] (Just 0))) -> do     -- Abc { .. } -> expr     let t = lrdrNameToText lname-    fmap Seq.singleton $ docSeq+    Seq.singleton <$> docSeq       [ appSep $ docLit t       , docLit $ Text.pack "{..}"       ]@@ -123,13 +122,13 @@       fExpDoc <- if pun         then return Nothing         else Just <$> docSharedWrapper layoutPat fPat-      return $ (lrdrNameToText lnameF, fExpDoc)-    fmap Seq.singleton $ docSeq+      return (lrdrNameToText lnameF, fExpDoc)+    Seq.singleton <$> docSeq       [ appSep $ docLit t       , appSep $ docLit $ Text.pack "{"       , docSeq $ fds >>= \case           (fieldName, Just fieldDoc) ->-            [ appSep $ docLit $ fieldName+            [ appSep $ docLit fieldName             , appSep $ docLit $ Text.pack "="             , fieldDoc >>= colsWrapPat             , docCommaSep@@ -167,7 +166,7 @@                docAddBaseY BrIndentRegular $ docSeq           [ appSep $ return xN           , appSep $ docLit $ Text.pack "::"-          , docForceSingleline $ tyDoc+          , docForceSingleline tyDoc           ]         return $ xR Seq.|> xN'   ListPat elems _ _ ->@@ -193,30 +192,30 @@ -- else --   VarPat n -> return $ stringLayouter lpat $ rdrNameToText n -- endif-  _ -> fmap return $ briDocByExactInlineOnly "some unknown pattern" lpat+  _ -> return <$> briDocByExactInlineOnly "some unknown pattern" lpat  colsWrapPat :: Seq BriDocNumbered -> ToBriDocM BriDocNumbered colsWrapPat = docCols ColPatterns . fmap return . Foldable.toList  wrapPatPrepend-  :: Located (Pat RdrName)+  :: Located (Pat GhcPs)   -> ToBriDocM BriDocNumbered   -> ToBriDocM (Seq BriDocNumbered) wrapPatPrepend pat prepElem = do   patDocs <- layoutPat pat   case Seq.viewl patDocs of-    Seq.EmptyL -> return $ Seq.empty+    Seq.EmptyL -> return Seq.empty     x1 Seq.:< xR -> do       x1' <- docSeq [prepElem, return x1]       return $ x1' Seq.<| xR  wrapPatListy-  :: [Located (Pat RdrName)]+  :: [Located (Pat GhcPs)]   -> String   -> String   -> ToBriDocM (Seq BriDocNumbered) wrapPatListy elems start end = do-  elemDocs <- Seq.fromList elems `forM` \e -> layoutPat e >>= colsWrapPat+  elemDocs <- Seq.fromList elems `forM` (layoutPat >=> colsWrapPat)   sDoc <- docLit $ Text.pack start   eDoc <- docLit $ Text.pack end   case Seq.viewl elemDocs of
src/Language/Haskell/Brittany/Internal/Layouters/Stmt.hs view
@@ -13,8 +13,10 @@ import           Language.Haskell.Brittany.Internal.LayouterBasics import           Language.Haskell.Brittany.Internal.Config.Types -import           RdrName ( RdrName(..) )-import           GHC ( runGhc, GenLocated(L), moduleNameString )+import           GHC                            ( runGhc+                                                , GenLocated(L)+                                                , moduleNameString+                                                ) import           HsSyn import           Name import qualified FastString@@ -26,9 +28,11 @@   -layoutStmt :: ToBriDoc' (StmtLR RdrName RdrName (LHsExpr RdrName))+layoutStmt :: ToBriDoc' (StmtLR GhcPs GhcPs (LHsExpr GhcPs)) layoutStmt lstmt@(L _ stmt) = do   indentPolicy <- mAsk <&> _conf_layout .> _lconfig_indentPolicy .> confUnpack+  indentAmount :: Int <-+    mAsk <&> _conf_layout .> _lconfig_indentAmount .> confUnpack   docWrapNode lstmt $ case stmt of     LastStmt body False _ -> do       layoutExpr body@@ -48,69 +52,67 @@             $ docPar (docLit $ Text.pack "<-") (expDoc)           ]         ]-    LetStmt binds -> layoutLocalBinds binds >>= \case-      Nothing        -> docLit $ Text.pack "let" -- i just tested-                                -- it, and it is-                                -- indeed allowed.-                                -- heh.-      Just []        -> docLit $ Text.pack "let" -- this probably never happens-      Just [bindDoc] -> docAlt-        [ -- let bind = expr-          docCols-          ColDoLet-          [ appSep $ docLit $ Text.pack "let"-          , ( if indentPolicy == IndentPolicyLeft-              then docForceSingleline-              else docSetBaseAndIndent-            )-            $ return bindDoc+    LetStmt binds -> do+      let isFree         = indentPolicy == IndentPolicyFree+      let indentFourPlus = indentAmount >= 4+      layoutLocalBinds binds >>= \case+        Nothing        -> docLit $ Text.pack "let"+          -- i just tested the above, and it is indeed allowed. heh.+        Just []        -> docLit $ Text.pack "let" -- this probably never happens+        Just [bindDoc] -> docAlt+          [ -- let bind = expr+            docCols+            ColDoLet+            [ appSep $ docLit $ Text.pack "let"+            , let+                f = case indentPolicy of+                  IndentPolicyFree -> docSetBaseAndIndent+                  IndentPolicyLeft -> docForceSingleline+                  IndentPolicyMultiple | indentFourPlus -> docSetBaseAndIndent+                                       | otherwise      -> docForceSingleline+              in  f $ return bindDoc+            ]+          , -- let+              --   bind = expr+            docAddBaseY BrIndentRegular $ docPar+            (docLit $ Text.pack "let")+            (docSetBaseAndIndent $ return bindDoc)           ]-        , -- let-          --   bind = expr-          docAddBaseY BrIndentRegular $ docPar-          (docLit $ Text.pack "let")-          (docSetBaseAndIndent $ return bindDoc)-        ]-      Just bindDocs -> docAltFilter-        [ -- let aaa = expra+        Just bindDocs -> runFilteredAlternative $ do+          -- let aaa = expra           --     bbb = exprb           --     ccc = exprc-          ( indentPolicy /= IndentPolicyLeft-          , docSeq+          addAlternativeCond (isFree || indentFourPlus) $ docSeq             [ appSep $ docLit $ Text.pack "let"-            , docSetBaseAndIndent $ docLines $ return <$> bindDocs+            , let f = if indentFourPlus+                    then docEnsureIndent BrIndentRegular+                    else docSetBaseAndIndent+              in  f $ docLines $ return <$> bindDocs             ]-          )-        , -- let+          -- let           --   aaa = expra           --   bbb = exprb           --   ccc = exprc-          ( True-          , docAddBaseY BrIndentRegular $ docPar-            (docLit $ Text.pack "let")-            (docSetBaseAndIndent $ docLines $ return <$> bindDocs)-          )+          addAlternativeCond (not indentFourPlus)+            $ docAddBaseY BrIndentRegular+            $ docPar (docLit $ Text.pack "let")+                     (docSetBaseAndIndent $ docLines $ return <$> bindDocs)+    RecStmt stmts _ _ _ _ _ _ _ _ _ -> runFilteredAlternative $ do+      -- rec stmt1+      --     stmt2+      --     stmt3+      addAlternativeCond (indentPolicy == IndentPolicyFree) $ docSeq+        [ docLit (Text.pack "rec")+        , docSeparator+        , docSetBaseAndIndent $ docLines $ layoutStmt <$> stmts         ]-    RecStmt stmts _ _ _ _ _ _ _ _ _ -> docAltFilter-      [ -- rec stmt1-        --     stmt2-        --     stmt3-        ( indentPolicy /= IndentPolicyLeft-        , docSeq-          [ docLit (Text.pack "rec")-          , docSeparator-          , docSetBaseAndIndent $ docLines $ layoutStmt <$> stmts-          ]-        )-      , -- rec-        --   stmt1-        --   stmt2-        --   stmt3-        ( True-        , docAddBaseY BrIndentRegular-          $ docPar (docLit (Text.pack "rec")) (docLines $ layoutStmt <$> stmts)-        )-      ]+      -- rec+      --   stmt1+      --   stmt2+      --   stmt3+      addAlternative $ docAddBaseY BrIndentRegular $ docPar+        (docLit (Text.pack "rec"))+        (docLines $ layoutStmt <$> stmts)     BodyStmt expr _ _ _ -> do       expDoc <- docSharedWrapper layoutExpr expr       docAddBaseY BrIndentRegular $ expDoc
src/Language/Haskell/Brittany/Internal/Layouters/Stmt.hs-boot view
@@ -12,7 +12,6 @@ import           Language.Haskell.Brittany.Internal.Types import           Language.Haskell.Brittany.Internal.LayouterBasics -import           RdrName ( RdrName(..) ) import           GHC ( runGhc, GenLocated(L), moduleNameString ) import           HsSyn import           Name@@ -21,4 +20,4 @@   -layoutStmt :: ToBriDoc' (StmtLR RdrName RdrName (LHsExpr RdrName))+layoutStmt :: ToBriDoc' (StmtLR GhcPs GhcPs (LHsExpr GhcPs))
src/Language/Haskell/Brittany/Internal/Layouters/Type.hs view
@@ -13,7 +13,6 @@ import           Language.Haskell.Brittany.Internal.Types import           Language.Haskell.Brittany.Internal.LayouterBasics -import           RdrName ( RdrName(..) ) import           GHC ( runGhc                      , GenLocated(L)                      , moduleNameString@@ -47,7 +46,7 @@     t <- lrdrNameToTextAnn name     docWrapNode name $ docLit t #endif-  HsForAllTy bndrs (L _ (HsQualTy (L _ cntxts@(_:_)) typ2)) -> do+  HsForAllTy bndrs (L _ (HsQualTy (L _ cntxts) typ2)) -> do     typeDoc <- docSharedWrapper layoutType typ2     tyVarDocs <- bndrs `forM` \case       (L _ (UserTyVar name)) -> return $ (lrdrNameToText name, Nothing)@@ -90,6 +89,7 @@                     ])         ]       contextDoc = case cntxtDocs of+        [] -> docLit $ Text.pack "()"         [x] -> x         _ -> docAlt           [ let@@ -210,13 +210,12 @@             ]           )       ]-  (HsQualTy (L _ []) _) ->-    briDocByExactInlineOnly "HsQualTy [] _" ltype-  HsQualTy lcntxts@(L _ cntxts@(_:_)) typ1 -> do+  HsQualTy lcntxts@(L _ cntxts) typ1 -> do     typeDoc <- docSharedWrapper layoutType typ1     cntxtDocs <- cntxts `forM` docSharedWrapper layoutType     let       contextDoc = docWrapNode lcntxts $ case cntxtDocs of+        [] -> docLit $ Text.pack "()"         [x] -> x         _ -> docAlt           [ let
+ src/Language/Haskell/Brittany/Internal/Obfuscation.hs view
@@ -0,0 +1,100 @@+module Language.Haskell.Brittany.Internal.Obfuscation+  ( obfuscate+  )+where++++#include "prelude.inc"++import           Data.Char+import           System.Random++++obfuscate :: Text -> IO Text+obfuscate input = do+  let predi x = isAlphaNum x || x `elem` "_'"+  let groups = List.groupBy (\a b -> predi a && predi b) (Text.unpack input)+  let idents = Set.toList $ Set.fromList $ filter (all predi) groups+  let exceptionFilter x | x `elem` keywords = False+      exceptionFilter x | x `elem` extraKWs = False+      exceptionFilter x                     = not $ null $ drop 1 x+  let filtered = filter exceptionFilter idents+  mappings <- fmap Map.fromList $ filtered `forM` \x -> do+    r <- createAlias x+    pure (x, r)+  let groups' = groups <&> \w -> fromMaybe w (Map.lookup w mappings)+  pure $ Text.concat $ fmap Text.pack groups'++keywords :: [String]+keywords =+  [ "case"+  , "class"+  , "data"+  , "default"+  , "deriving"+  , "do"+  , "mdo"+  , "else"+  , "forall"+  , "if"+  , "import"+  , "in"+  , "infix"+  , "infixl"+  , "infixr"+  , "instance"+  , "let"+  , "module"+  , "newtype"+  , "of"+  , "qualified"+  , "then"+  , "type"+  , "where"+  , "_"+  , "foreign"+  , "ccall"+  , "as"+  , "safe"+  , "unsafe"+  , "hiding"+  , "proc"+  , "rec"+  , "family"+  ]++extraKWs :: [String]+extraKWs = ["return", "pure", "Int", "True", "False", "otherwise"]++createAlias :: String -> IO String+createAlias xs = go NoHint xs+ where+  go _hint ""       = pure ""+  go hint (c : cr)  = do+    c' <- case hint of+      VocalHint | isUpper c -> randomFrom $ "AAAEEEOOOIIIUUU" ++ ['A' .. 'Z']+      _ | isUpper c         -> randomFrom ['A' .. 'Z']+      VocalHint | isLower c -> randomFrom $ "aaaeeeoooiiiuuu" ++ ['a' .. 'z']+      _ | isLower c         -> randomFrom ['a' .. 'z']+      _                     -> pure c+    cr' <- go (if c' `elem` "aeuioAEUIO" then NoVocalHint else VocalHint) cr+    pure (c' : cr')++data Hint = NoHint | VocalHint | NoVocalHint++_randomRange :: Random a => a -> a -> IO a+_randomRange lo hi = do+  gen <- getStdGen+  let (x, gen') = randomR (lo, hi) gen+  setStdGen gen'+  pure x++randomFrom :: Random a => [a] -> IO a+randomFrom l = do+  let hi = length l - 1+  gen <- getStdGen+  let (x, gen') = randomR (0, hi) gen+  setStdGen gen'+  pure $ l List.!! x
src/Language/Haskell/Brittany/Internal/Prelude.hs view
@@ -1,8 +1,24 @@-module Language.Haskell.Brittany.Internal.Prelude (module E)+module Language.Haskell.Brittany.Internal.Prelude+  ( module E+  , module Language.Haskell.Brittany.Internal.Prelude+  ) where   +-- rather project-specific stuff:+---------------------------------+#if MIN_VERSION_ghc(8,4,0) /* ghc-8.4 */+import HsExtension                    as E ( GhcPs )+#endif++import RdrName                        as E ( RdrName )++++-- more general:+----------------+ import Data.Functor.Identity         as E ( Identity(..) ) import Control.Concurrent.Chan       as E ( Chan ) import Control.Concurrent.MVar       as E ( MVar )@@ -255,14 +271,16 @@ import Foreign.ForeignPtr            as E ( ForeignPtr                                           ) -import Data.Monoid                   as E ( (<>)-                                          , mconcat+import Data.Monoid                   as E ( mconcat                                           , Monoid (..)                                           )  import Data.Bifunctor                as E ( bimap ) import Data.Functor                  as E ( (<$), ($>) ) import Data.Function                 as E ( (&) )+import Data.Semigroup                as E ( (<>)+                                          , Semigroup(..)+                                          ) import System.IO                     as E ( hFlush                                           , stdout                                           )@@ -306,10 +324,11 @@ import Control.Monad.Trans.MultiRWS  as E ( -- MultiRWST (..)                                           -- , MultiRWSTNull                                           -- , MultiRWS-                                          -- , +                                          -- ,                                             MonadMultiReader(..)                                           , MonadMultiWriter(..)                                           , MonadMultiState(..)+                                          , mGet                                           -- , runMultiRWST                                           -- , runMultiRWSTASW                                           -- , runMultiRWSTW@@ -376,3 +395,10 @@ import Data.Data                     as E ( toConstr                                           ) +todo :: a+todo = error "todo"+++#if !MIN_VERSION_ghc(8,4,0) /* ghc-8.0, ghc-8.2 */+type GhcPs = RdrName+#endif
src/Language/Haskell/Brittany/Internal/PreludeUtils.hs view
@@ -32,13 +32,12 @@   x <|> Strict.Nothing = x   _ <|> x = x -traceFunctionWith-  :: String -> (a -> String) -> (b -> String) -> (a -> b) -> (a -> b)-traceFunctionWith name s1 s2 f x =-  trace traceStr y-  where-    y = f x-    traceStr = name ++ "\nBEFORE:\n" ++ s1 x ++ "\nAFTER:\n" ++ s2 y+traceFunctionWith :: String -> (a -> String) -> (b -> String) -> (a -> b) -> (a -> b)+traceFunctionWith name s1 s2 f x = trace traceStr y+ where+  y = f x+  traceStr =+    name ++ "\nBEFORE:\n" ++ s1 x ++ "\nAFTER:\n" ++ s2 y  (<&!>) :: Monad m => m a -> (a -> b) -> m b (<&!>) = flip (<$!>)
src/Language/Haskell/Brittany/Internal/Transformations/Alt.hs view
@@ -141,11 +141,7 @@         BDFSeparator  -> processSpacingSimple bdX $> bdX         BDFAddBaseY indent bd -> do           acp <- mGet-          indAmount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> confUnpack-          let indAdd = case indent of-                BrIndentNone -> 0-                BrIndentRegular -> indAmount-                BrIndentSpecial i -> i+          indAdd <- fixIndentationForMultiple acp indent           mSet $ acp { _acp_indentPrep = max (_acp_indentPrep acp) indAdd }           r <- rec bd           acp' <- mGet@@ -315,11 +311,7 @@           return $ reWrap $ BDFLines (l':lr')         BDFEnsureIndent indent bd -> do           acp <- mGet-          indAmount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> confUnpack-          let indAdd = case indent of-                BrIndentNone -> 0-                BrIndentRegular -> indAmount-                BrIndentSpecial i -> i+          indAdd <- fixIndentationForMultiple acp indent           mSet $ acp             { _acp_indentPrep = 0               -- TODO: i am not sure this is valid, in general.@@ -857,3 +849,25 @@       VerticalSpacingParSome i -> VerticalSpacingParSome $ x1 `max` i       VerticalSpacingParNone -> VerticalSpacingParSome $ x1       VerticalSpacingParAlways i -> VerticalSpacingParAlways $ x1 `max` i++fixIndentationForMultiple+  :: (MonadMultiReader (CConfig Identity) m) => AltCurPos -> BrIndent -> m Int+fixIndentationForMultiple acp indent = do+  indAmount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> confUnpack+  let indAddRaw = case indent of+        BrIndentNone      -> 0+        BrIndentRegular   -> indAmount+        BrIndentSpecial i -> i+  -- for IndentPolicyMultiple, we restrict the amount of added+  -- indentation in such a manner that we end up on a multiple of the+  -- base indentation.+  indPolicy <- mAsk <&> _conf_layout .> _lconfig_indentPolicy .> confUnpack+  pure $ if indPolicy == IndentPolicyMultiple+    then+      let indAddMultiple1 =+            indAddRaw - ((_acp_indent acp + indAddRaw) `mod` indAmount)+          indAddMultiple2 = if indAddMultiple1 <= 0+            then indAddMultiple1 + indAmount+            else indAddMultiple1+      in  indAddMultiple2+    else indAddRaw
src/Language/Haskell/Brittany/Internal/Types.hs view
@@ -13,10 +13,10 @@ #include "prelude.inc"  import qualified Language.Haskell.GHC.ExactPrint as ExactPrint+import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types  import qualified Data.Text.Lazy.Builder as Text.Builder -import           RdrName ( RdrName(..) ) import           GHC ( Located, runGhc, GenLocated(L), moduleNameString, AnnKeywordId )  import           Language.Haskell.GHC.ExactPrint ( AnnKey, Comment )@@ -28,8 +28,17 @@   +data InlineConfig = InlineConfig+  { _icd_perModule :: CConfig Option+  , _icd_perBinding :: Map String (CConfig Option)+  , _icd_perKey :: Map ExactPrint.Types.AnnKey (CConfig Option)+  }+#if MIN_VERSION_ghc(8,2,0)+  deriving Data.Data.Data+#endif+ type PPM = MultiRWSS.MultiRWS-  '[Map ExactPrint.AnnKey ExactPrint.Anns, Config, ExactPrint.Anns]+  '[Map ExactPrint.AnnKey ExactPrint.Anns, InlineConfig, Config, ExactPrint.Anns]   '[Text.Builder.Builder, [BrittanyError], Seq String]   '[] @@ -38,6 +47,8 @@   '[Text.Builder.Builder, [BrittanyError], Seq String]   '[] +newtype TopLevelDeclNameMap = TopLevelDeclNameMap (Map ExactPrint.AnnKey String)+ data LayoutState = LayoutState   { _lstate_baseYs         :: [Int]      -- ^ stack of number of current indentation columns@@ -119,6 +130,9 @@     -- ^ parsing failed   | ErrorUnusedComment String     -- ^ internal error: some comment went missing+  | ErrorMacroConfig String String+    -- ^ in-source config string parsing error; first argument is the parser+    --   output and second the corresponding, ill-formed input.   | LayoutWarning String     -- ^ some warning   | forall ast . Data.Data.Data ast => ErrorUnknownNode String ast@@ -190,9 +204,9 @@  type ToBriDocM = MultiRWSS.MultiRWS '[Config, Anns] '[[BrittanyError], Seq String] '[NodeAllocIndex] -type ToBriDoc (sym :: * -> *) = Located (sym RdrName) -> ToBriDocM BriDocNumbered-type ToBriDoc' sym            = Located sym           -> ToBriDocM BriDocNumbered-type ToBriDocC sym c          = Located sym           -> ToBriDocM c+type ToBriDoc (sym :: * -> *) = Located (sym GhcPs) -> ToBriDocM BriDocNumbered+type ToBriDoc' sym            = Located sym         -> ToBriDocM BriDocNumbered+type ToBriDocC sym c          = Located sym         -> ToBriDocM c  data DocMultiLine   = MultiLineNo
src/Language/Haskell/Brittany/Internal/Utils.hs view
@@ -84,9 +84,12 @@ newtype Max a = Max { getMax :: a }   deriving (Eq, Ord, Show, Bounded, Num) +instance (Num a, Ord a) => Semigroup (Max a) where+  (<>) = Data.Coerce.coerce (max :: a -> a -> a)+ instance (Num a, Ord a) => Monoid (Max a) where   mempty  = Max 0-  mappend = Data.Coerce.coerce (max :: a -> a -> a)+  mappend = (<>)  newtype ShowIsId = ShowIsId String deriving Data @@ -222,7 +225,7 @@ tellDebugMess s = mTell $ Seq.singleton s  tellDebugMessShow :: forall a m . (MonadMultiWriter-  (Seq String) m, Show a) => a -> m () +  (Seq String) m, Show a) => a -> m () tellDebugMessShow = tellDebugMess . show  -- i should really put that into multistate..