packages feed

hindent 5.0.0 → 5.0.1

raw patch · 32 files changed

+1451/−1467 lines, 32 filesdep +bytestringdep +exceptionsdep +utf8-stringdep ~basedep ~mtlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: bytestring, exceptions, utf8-string

Dependency ranges changed: base, mtl

API changes (from Hackage documentation)

- HIndent: Style :: !Text -> !Text -> !Text -> !s -> ![Extender s] -> !Config -> (forall s' m. MonadState (PrintState s') m => [Comment] -> m [Comment]) -> Style
- HIndent: [styleAuthor] :: Style -> !Text
- HIndent: [styleCommentPreprocessor] :: Style -> forall s' m. MonadState (PrintState s') m => [Comment] -> m [Comment]
- HIndent: [styleDefConfig] :: Style -> !Config
- HIndent: [styleDescription] :: Style -> !Text
- HIndent: [styleExtenders] :: Style -> ![Extender s]
- HIndent: [styleInitialState] :: Style -> !s
- HIndent: [styleName] :: Style -> !Text
- HIndent: data Style
- HIndent: johanTibell :: Style
- HIndent: testAll :: Text -> IO ()
- HIndent.Pretty: getState :: Printer s s
- HIndent.Pretty: modifyState :: (s -> s) -> Printer s ()
- HIndent.Pretty: putState :: s -> Printer s ()
- HIndent.Styles.JohanTibell: OpChainExp :: (Exp l) -> OpChainLink l
- HIndent.Styles.JohanTibell: OpChainLink :: (QOp l) -> OpChainLink l
- HIndent.Styles.JohanTibell: State :: State
- HIndent.Styles.JohanTibell: bindingGroup :: Binds NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: conDecl :: ConDecl NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: context :: Context NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: data OpChainLink l
- HIndent.Styles.JohanTibell: data State
- HIndent.Styles.JohanTibell: decl :: Decl NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: dependOrNewline :: Printer t () -> Exp NodeInfo -> (Exp NodeInfo -> Printer t ()) -> Printer t ()
- HIndent.Styles.JohanTibell: exp :: Exp NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: fieldupdate :: FieldUpdate NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: fitsOnOneLine :: MonadState (PrintState s) m => m a -> m (Bool, PrintState s)
- HIndent.Styles.JohanTibell: flattenOpChain :: Exp l -> [OpChainLink l]
- HIndent.Styles.JohanTibell: guardedRhs :: GuardedRhs NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: infixApp :: Exp NodeInfo -> Exp NodeInfo -> QOp NodeInfo -> Exp NodeInfo -> Maybe Int64 -> Printer s ()
- HIndent.Styles.JohanTibell: instance GHC.Show.Show l => GHC.Show.Show (HIndent.Styles.JohanTibell.OpChainLink l)
- HIndent.Styles.JohanTibell: isFlat :: Exp NodeInfo -> Printer s Bool
- HIndent.Styles.JohanTibell: isOverflow :: MonadState (PrintState s) m => m a -> m Bool
- HIndent.Styles.JohanTibell: isRecord :: QualConDecl t -> Bool
- HIndent.Styles.JohanTibell: isShort :: (Pretty ast) => ast NodeInfo -> Printer s (Bool)
- HIndent.Styles.JohanTibell: isSingleLiner :: MonadState (PrintState s) m => m a -> m Bool
- HIndent.Styles.JohanTibell: isSmall :: MonadState (PrintState t) m => m a -> m Bool
- HIndent.Styles.JohanTibell: johanTibell :: Style
- HIndent.Styles.JohanTibell: match :: Match NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: qualConDecl :: QualConDecl NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: recDecl :: ConDecl NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: recUpdateExpr :: Printer s () -> [FieldUpdate NodeInfo] -> Printer s ()
- HIndent.Styles.JohanTibell: rhs :: Rhs NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: shortName :: Int64
- HIndent.Styles.JohanTibell: stmt :: Stmt NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: typ :: Type NodeInfo -> Printer s ()
- HIndent.Styles.JohanTibell: unboxParens :: MonadState (PrintState s) m => m a -> m a
- HIndent.Types: Style :: !Text -> !Text -> !Text -> !s -> ![Extender s] -> !Config -> (forall s' m. MonadState (PrintState s') m => [Comment] -> m [Comment]) -> Style
- HIndent.Types: [CatchAll] :: forall s. (forall a. Typeable a => s -> a -> Maybe (Printer s ())) -> Extender s
- HIndent.Types: [Extender] :: forall s a. (Typeable a) => (a -> Printer s ()) -> Extender s
- HIndent.Types: [psCommentPreprocessor] :: PrintState s -> forall m. MonadState (PrintState s) m => [Comment] -> m [Comment]
- HIndent.Types: [psExtenders] :: PrintState s -> ![Extender s]
- HIndent.Types: [psUserState] :: PrintState s -> !s
- HIndent.Types: [styleAuthor] :: Style -> !Text
- HIndent.Types: [styleCommentPreprocessor] :: Style -> forall s' m. MonadState (PrintState s') m => [Comment] -> m [Comment]
- HIndent.Types: [styleDefConfig] :: Style -> !Config
- HIndent.Types: [styleDescription] :: Style -> !Text
- HIndent.Types: [styleExtenders] :: Style -> ![Extender s]
- HIndent.Types: [styleInitialState] :: Style -> !s
- HIndent.Types: [styleName] :: Style -> !Text
- HIndent.Types: data Extender s
- HIndent.Types: data Style
- HIndent.Types: instance Control.Monad.State.Class.MonadState (HIndent.Types.PrintState s) (HIndent.Types.Printer s)
- HIndent.Types: instance GHC.Base.Alternative (HIndent.Types.Printer s)
- HIndent.Types: instance GHC.Base.Applicative (HIndent.Types.Printer s)
- HIndent.Types: instance GHC.Base.Functor (HIndent.Types.Printer s)
- HIndent.Types: instance GHC.Base.Monad (HIndent.Types.Printer s)
- HIndent.Types: instance GHC.Base.MonadPlus (HIndent.Types.Printer s)
+ HIndent: getExtensions :: [Text] -> [Extension]
+ HIndent.Pretty: instance GHC.Show.Show l => GHC.Show.Show (HIndent.Pretty.OpChainLink l)
+ HIndent.Types: instance Control.Monad.State.Class.MonadState HIndent.Types.PrintState HIndent.Types.Printer
+ HIndent.Types: instance GHC.Base.Alternative HIndent.Types.Printer
+ HIndent.Types: instance GHC.Base.Applicative HIndent.Types.Printer
+ HIndent.Types: instance GHC.Base.Functor HIndent.Types.Printer
+ HIndent.Types: instance GHC.Base.Monad HIndent.Types.Printer
+ HIndent.Types: instance GHC.Base.MonadPlus HIndent.Types.Printer
- HIndent: prettyPrint :: ParseMode -> Style -> Module SrcSpanInfo -> [Comment] -> Either a Builder
+ HIndent: prettyPrint :: Config -> ParseMode -> Module SrcSpanInfo -> [Comment] -> Either a Builder
- HIndent: reformat :: Style -> Maybe [Extension] -> Text -> Either String Builder
+ HIndent: reformat :: Config -> Maybe [Extension] -> ByteString -> Either String Builder
- HIndent: test :: Style -> Text -> IO ()
+ HIndent: test :: ByteString -> IO ()
- HIndent: testAst :: Text -> Either String ([ComInfo], Module NodeInfo)
+ HIndent: testAst :: ByteString -> Either String ([ComInfo], Module NodeInfo)
- HIndent: testFile :: FilePath -> Style -> IO ()
+ HIndent: testFile :: FilePath -> IO ()
- HIndent.Pretty: braces :: MonadState (PrintState s) m => m a -> m a
+ HIndent.Pretty: braces :: MonadState (PrintState) m => m a -> m a
- HIndent.Pretty: brackets :: MonadState (PrintState s) m => m a -> m a
+ HIndent.Pretty: brackets :: MonadState (PrintState) m => m a -> m a
- HIndent.Pretty: column :: MonadState (PrintState s) m => Int64 -> m a -> m a
+ HIndent.Pretty: column :: MonadState (PrintState) m => Int64 -> m a -> m a
- HIndent.Pretty: comma :: MonadState (PrintState s) m => m ()
+ HIndent.Pretty: comma :: MonadState (PrintState) m => m ()
- HIndent.Pretty: commas :: MonadState (PrintState s) m => [m ()] -> m ()
+ HIndent.Pretty: commas :: MonadState (PrintState) m => [m ()] -> m ()
- HIndent.Pretty: depend :: MonadState (PrintState s) m => m () -> m b -> m b
+ HIndent.Pretty: depend :: MonadState (PrintState) m => m () -> m b -> m b
- HIndent.Pretty: dependBind :: MonadState (PrintState s) m => m a -> (a -> m b) -> m b
+ HIndent.Pretty: dependBind :: MonadState (PrintState) m => m a -> (a -> m b) -> m b
- HIndent.Pretty: getColumn :: MonadState (PrintState s) m => m Int64
+ HIndent.Pretty: getColumn :: MonadState (PrintState) m => m Int64
- HIndent.Pretty: getColumnLimit :: MonadState (PrintState s) m => m Int64
+ HIndent.Pretty: getColumnLimit :: MonadState (PrintState) m => m Int64
- HIndent.Pretty: getIndentSpaces :: MonadState (PrintState s) m => m Int64
+ HIndent.Pretty: getIndentSpaces :: MonadState (PrintState) m => m Int64
- HIndent.Pretty: getLineNum :: MonadState (PrintState s) m => m Int64
+ HIndent.Pretty: getLineNum :: MonadState (PrintState) m => m Int64
- HIndent.Pretty: indented :: MonadState (PrintState s) m => Int64 -> m a -> m a
+ HIndent.Pretty: indented :: MonadState (PrintState) m => Int64 -> m a -> m a
- HIndent.Pretty: indentedBlock :: MonadState (PrintState s) m => m a -> m a
+ HIndent.Pretty: indentedBlock :: MonadState (PrintState) m => m a -> m a
- HIndent.Pretty: int :: (Integral n, MonadState (PrintState s) m) => n -> m ()
+ HIndent.Pretty: int :: (MonadState (PrintState) m) => Integer -> m ()
- HIndent.Pretty: inter :: MonadState (PrintState s) m => m () -> [m ()] -> m ()
+ HIndent.Pretty: inter :: MonadState (PrintState) m => m () -> [m ()] -> m ()
- HIndent.Pretty: lined :: MonadState (PrintState s) m => [m ()] -> m ()
+ HIndent.Pretty: lined :: MonadState (PrintState) m => [m ()] -> m ()
- HIndent.Pretty: newline :: MonadState (PrintState s) m => m ()
+ HIndent.Pretty: newline :: MonadState (PrintState) m => m ()
- HIndent.Pretty: parens :: MonadState (PrintState s) m => m a -> m a
+ HIndent.Pretty: parens :: MonadState (PrintState) m => m a -> m a
- HIndent.Pretty: prefixedLined :: MonadState (PrintState s) m => Text -> [m ()] -> m ()
+ HIndent.Pretty: prefixedLined :: MonadState (PrintState) m => String -> [m ()] -> m ()
- HIndent.Pretty: pretty :: (Pretty ast, MonadState (PrintState s) m) => ast NodeInfo -> m ()
+ HIndent.Pretty: pretty :: (Pretty ast) => ast NodeInfo -> Printer ()
- HIndent.Pretty: pretty' :: (Pretty ast, Pretty (ast SrcSpanInfo), Functor ast, MonadState (PrintState s) m) => ast NodeInfo -> m ()
+ HIndent.Pretty: pretty' :: (Pretty ast, Pretty (ast SrcSpanInfo), MonadState (PrintState) m) => ast NodeInfo -> m ()
- HIndent.Pretty: prettyNoExt :: (Pretty ast, MonadState (PrintState s) m) => ast NodeInfo -> m ()
+ HIndent.Pretty: prettyNoExt :: (Pretty ast) => ast NodeInfo -> Printer ()
- HIndent.Pretty: printComment :: MonadState (PrintState s) m => Maybe SrcSpan -> Comment -> m ()
+ HIndent.Pretty: printComment :: MonadState (PrintState) m => Maybe SrcSpan -> Comment -> m ()
- HIndent.Pretty: printComments :: (Pretty ast, MonadState (PrintState s) m) => ComInfoLocation -> ast NodeInfo -> m ()
+ HIndent.Pretty: printComments :: (Pretty ast) => ComInfoLocation -> ast NodeInfo -> Printer ()
- HIndent.Pretty: rhsSeparator :: MonadState (PrintState s) m => m ()
+ HIndent.Pretty: rhsSeparator :: MonadState (PrintState) m => m ()
- HIndent.Pretty: space :: MonadState (PrintState s) m => m ()
+ HIndent.Pretty: space :: MonadState (PrintState) m => m ()
- HIndent.Pretty: spaced :: MonadState (PrintState s) m => [m ()] -> m ()
+ HIndent.Pretty: spaced :: MonadState (PrintState) m => [m ()] -> m ()
- HIndent.Pretty: string :: MonadState (PrintState s) m => String -> m ()
+ HIndent.Pretty: string :: MonadState (PrintState) m => String -> m ()
- HIndent.Pretty: swing :: MonadState (PrintState s) m => m () -> m b -> m b
+ HIndent.Pretty: swing :: Printer () -> Printer b -> Printer ()
- HIndent.Pretty: swingBy :: MonadState (PrintState s) m => Int64 -> m () -> m b -> m b
+ HIndent.Pretty: swingBy :: Int64 -> Printer () -> Printer b -> Printer b
- HIndent.Pretty: withCaseContext :: MonadState (PrintState s) m => Bool -> m a -> m a
+ HIndent.Pretty: withCaseContext :: MonadState (PrintState) m => Bool -> m a -> m a
- HIndent.Pretty: withCtx :: (MonadState (PrintState s) m, Pretty ast) => Maybe (ast NodeInfo) -> m b -> m b
+ HIndent.Pretty: withCtx :: (Pretty ast) => Maybe (ast NodeInfo) -> Printer b -> Printer b
- HIndent.Pretty: write :: MonadState (PrintState s) m => Builder -> m ()
+ HIndent.Pretty: write :: MonadState (PrintState) m => String -> m ()
- HIndent.Types: PrintState :: !Int64 -> !Builder -> !Bool -> !Int64 -> !Int64 -> !s -> ![Extender s] -> !Config -> !Bool -> !Bool -> !ParseMode -> (forall m. MonadState (PrintState s) m => [Comment] -> m [Comment]) -> PrintState s
+ HIndent.Types: PrintState :: !Int64 -> !Builder -> !Bool -> !Int64 -> !Int64 -> !Config -> !Bool -> !Bool -> !ParseMode -> PrintState
- HIndent.Types: Printer :: StateT (PrintState s) (MaybeT Identity) a -> Printer s a
+ HIndent.Types: Printer :: StateT PrintState (MaybeT Identity) a -> Printer a
- HIndent.Types: [psColumn] :: PrintState s -> !Int64
+ HIndent.Types: [psColumn] :: PrintState -> !Int64
- HIndent.Types: [psConfig] :: PrintState s -> !Config
+ HIndent.Types: [psConfig] :: PrintState -> !Config
- HIndent.Types: [psEolComment] :: PrintState s -> !Bool
+ HIndent.Types: [psEolComment] :: PrintState -> !Bool
- HIndent.Types: [psIndentLevel] :: PrintState s -> !Int64
+ HIndent.Types: [psIndentLevel] :: PrintState -> !Int64
- HIndent.Types: [psInsideCase] :: PrintState s -> !Bool
+ HIndent.Types: [psInsideCase] :: PrintState -> !Bool
- HIndent.Types: [psLine] :: PrintState s -> !Int64
+ HIndent.Types: [psLine] :: PrintState -> !Int64
- HIndent.Types: [psNewline] :: PrintState s -> !Bool
+ HIndent.Types: [psNewline] :: PrintState -> !Bool
- HIndent.Types: [psOutput] :: PrintState s -> !Builder
+ HIndent.Types: [psOutput] :: PrintState -> !Builder
- HIndent.Types: [psParseMode] :: PrintState s -> !ParseMode
+ HIndent.Types: [psParseMode] :: PrintState -> !ParseMode
- HIndent.Types: [runPrinter] :: Printer s a -> StateT (PrintState s) (MaybeT Identity) a
+ HIndent.Types: [runPrinter] :: Printer a -> StateT PrintState (MaybeT Identity) a
- HIndent.Types: data PrintState s
+ HIndent.Types: data PrintState
- HIndent.Types: newtype Printer s a
+ HIndent.Types: newtype Printer a

Files

+ BENCHMARKS.md view
@@ -0,0 +1,90 @@+# Large inputs++Bunch of declarations++``` haskell+listPrinters =+  [(''[]+   ,\(typeVariable:_) _automaticPrinter ->+      (let presentVar = varE (presentVarName typeVariable)+       in lamE [varP (presentVarName typeVariable)]+               [|(let typeString = "[" ++ fst $(presentVar) ++ "]"+                  in (typeString+                     ,\xs ->+                        case fst $(presentVar) of+                          "GHC.Types.Char" ->+                            ChoicePresentation+                              "String"+                              [("String",undefined)+                              ,("List of characters",undefined)]+                          _ ->+                            ListPresentation typeString+                                             (map (snd $(presentVar)) xs)))|]))]+printComments loc' ast = do+  let correctLocation comment = comInfoLocation comment == Just loc'+      commentsWithLocation = filter correctLocation (nodeInfoComments info)+  comments <- return $ map comInfoComment commentsWithLocation++  forM_ comments $ \comment -> do+    -- Preceeding comments must have a newline before them.+    hasNewline <- gets psNewline+    when (not hasNewline && loc' == Before) newline++    printComment (Just $ srcInfoSpan $ nodeInfoSpan info) comment+  where info = ann ast+exp' (App _ op a) =+  do (fits,st) <-+       fitsOnOneLine (spaced (map pretty (f : args)))+     if fits+        then put st+        else do pretty f+                newline+                spaces <- getIndentSpaces+                indented spaces (lined (map pretty args))+  where (f,args) = flatten op [a]+        flatten :: Exp NodeInfo+                -> [Exp NodeInfo]+                -> (Exp NodeInfo,[Exp NodeInfo])+        flatten (App _ f' a') b =+          flatten f' (a' : b)+        flatten f' as = (f',as)+infixApp :: Exp NodeInfo+         -> Exp NodeInfo+         -> QOp NodeInfo+         -> Exp NodeInfo+         -> Maybe Int64+         -> Printer ()+```++# Complex inputs++Quasi-quotes with nested lets and operators++``` haskell+quasiQuotes =+  [(''[]+   ,\(typeVariable:_) _automaticPrinter ->+      (let presentVar = varE (presentVarName typeVariable)+       in lamE [varP (presentVarName typeVariable)]+               [|(let typeString = "[" ++ fst $(presentVar) ++ "]"+                  in (typeString+                     ,\xs ->+                        case fst $(presentVar) of+                          "GHC.Types.Char" ->+                            ChoicePresentation+                              "String"+                              [("String"+                               ,StringPresentation "String"+                                                   (concatMap getCh (map (snd $(presentVar)) xs)))+                              ,("List of characters"+                               ,ListPresentation typeString+                                                 (map (snd $(presentVar)) xs))]+                            where getCh (CharPresentation "GHC.Types.Char" ch) =+                                    ch+                                  getCh (ChoicePresentation _ ((_,CharPresentation _ ch):_)) =+                                    ch+                                  getCh _ = ""+                          _ ->+                            ListPresentation typeString+                                             (map (snd $(presentVar)) xs)))|]))]+```
+ CHANGELOG.md view
@@ -0,0 +1,35 @@+5.0.1:+    * Re-implement using bytestring instead of text+    * Made compatible with GHC 7.8 through to GHC 8.0+    * Added test suite and benchmarks in TESTS.md and BENCHMARKS.md++5.0.0:+	* Drop support for styles++4.6.4++	* Copy/delete file instead of renaming++4.4.6++	* Fix whole module printer+	* Accept a filename to reformat++4.4.5++	* Fix bug in infix patterns++4.4.2++	* Bunch of Gibiansky style fixes.+	* Support CPP.+	* Tibell style fixes.++4.3.8++	* Fixed: bug in printing operators in statements.++4.5.4++	* Improvements to Tibell style.+	* 6x speed up on rendering operators.
− LICENSE
@@ -1,24 +0,0 @@-Copyright (c) 2014, hindent-All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:-    * Redistributions of source code must retain the above copyright-      notice, this list of conditions and the following disclaimer.-    * Redistributions in binary form must reproduce the above copyright-      notice, this list of conditions and the following disclaimer in the-      documentation and/or other materials provided with the distribution.-    * Neither the name of hindent nor the-      names of its contributors may be used to endorse or promote products-      derived from this software without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE-DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ LICENSE.md view
@@ -0,0 +1,28 @@+Copyright (c) 2014, Chris Done++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++* Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+* Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+* Neither the name of hindent nor the names of its contributors may be+ used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHRIS DONE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ TESTS.md view
@@ -0,0 +1,198 @@+# Introduction++This file is a test suite. Each section maps to an HSpec test, and+each line that is followed by a Haskell code fence is tested to make+sure re-formatting that code snippet produces the same result.++You can browse through this document to see what HIndent's style is+like, or contribute additional sections to it, or regression tests.++# Modules++Module header++``` haskell+module X where+```++Exports++``` haskell+module X+  (x+  ,y+  ,Z+  ,P(x, z))+  where+```++## Imports++Import lists++``` haskell+import Data.Text+import Data.Text+import qualified Data.Text as T+import qualified Data.Text (a, b, c)+import Data.Text (a, b, c)+import Data.Text hiding (a, b, c)+```++# Declarations++Type declaration++``` haskell+type EventSource a = (AddHandler a, a -> IO ())+```++# Expressions++Lazy patterns in a lambda++``` haskell+f = \ ~a -> undefined -- \~a yields parse error on input ‘\~’+```++Bang patterns in a lambda++``` haskell+f = \ !a -> undefined -- \!a yields parse error on input ‘\!’+```++List comprehensions++``` haskell+defaultExtensions =+  [ e+  | e@EnableExtension {} <- knownExtensions ] \\+  map EnableExtension badExtensions+```++Record indentation++``` haskell+getGitProvider :: EventProvider GitRecord ()+getGitProvider =+  EventProvider+  { getModuleName = "Git"+  , getEvents = getRepoCommits+  }+```++Records again++``` haskell+commitToEvent :: FolderPath -> TimeZone -> Commit -> Event.Event+commitToEvent gitFolderPath timezone commit =+  Event.Event+  { pluginName = getModuleName getGitProvider+  , eventIcon = "glyphicon-cog"+  , eventDate = localTimeToUTC timezone (commitDate commit)+  }+```++Cases++``` haskell+strToMonth :: String -> Int+strToMonth month =+  case month of+    "Jan" -> 1+    "Feb" -> 2+    _ -> error $ "Unknown month " ++ month+```++Operators++``` haskell+x =+  Value <$> thing <*> secondThing <*> thirdThing <*> fourthThing <*>+  Just thisissolong <*>+  Just stilllonger+```++# Type signatures++Class constraints++``` haskell+fun+  :: (Class a, Class b)+  => a -> b -> c+```++Tuples++``` haskell+fun :: (a, b, c) -> (a, b)+```++# Function declarations++Where clause++``` haskell+sayHello :: IO ()+sayHello = do+  name <- getLine+  putStrLn $ greeting name+  where+    greeting name = "Hello, " ++ name ++ "!"+```++Guards and pattern guards++``` haskell+f :: Int+f x+  | x <- Just x+  , x <- Just x =+    case x of+      Just x -> e+  | otherwise = do e+  where+    x = y+```++Case inside a `where` and `do`++``` haskell+g x =+  case x of+    a -> x+  where+    foo =+      case x of+        _ -> do+          launchMissiles+      where+        y = 2+```++Let inside a `where`++``` haskell+g x =+  let x = 1+  in x+  where+    foo =+      let y = 2+          z = 3+      in y+```++# Behaviour checks++Unicode++``` haskell+α = γ * "ω" -- υ+```++Empty module++``` haskell+```
− benchmarks/BigDeclarations.hs
@@ -1,17 +0,0 @@-listPrinters =-  [(''[]-   ,\(typeVariable:_) _automaticPrinter ->-      (let presentVar = varE (presentVarName typeVariable)-       in lamE [varP (presentVarName typeVariable)]-               [|(let typeString = "[" ++ fst $(presentVar) ++ "]"-                  in (typeString-                     ,\xs ->-                        case fst $(presentVar) of-                          "GHC.Types.Char" ->-                            ChoicePresentation-                              "String"-                              [("String",undefined)-                              ,("List of characters",undefined)]-                          _ ->-                            ListPresentation typeString-                                             (map (snd $(presentVar)) xs)))|]))]
hindent.cabal view
@@ -1,25 +1,26 @@ name:                hindent-version:             5.0.0+version:             5.0.1 synopsis:            Extensible Haskell pretty printer description:         Extensible Haskell pretty printer. Both a library and an executable.                      .                      See the Github page for usage\/explanation: <https://github.com/chrisdone/hindent> license:             BSD3 stability:           Unstable-license-file:        LICENSE+license-file:        LICENSE.md author:              Chris Done, Andrew Gibiansky, Tobias Pflug, Pierre Radermecker maintainer:          chrisdone@gmail.com-copyright:           2014 Chris Done+copyright:           2014 Chris Done, 2015 Andrew Gibiansky category:            Development build-type:          Simple cabal-version:       >=1.8 homepage: http://www.github.com/chrisdone/hindent bug-reports: https://github.com/chrisdone/hindent/issues data-files:          elisp/hindent.el-extra-source-files:  README.md-                     benchmarks/BigDeclarations.hs-                     test/johan-tibell/expected/*.exp-                     test/johan-tibell/tests/*.test+extra-source-files:+ README.md+ CHANGELOG.md+ BENCHMARKS.md+ TESTS.md  source-repository head     type:           git@@ -32,14 +33,16 @@                      HIndent.Types                      HIndent.Pretty                      HIndent.Comments-                     HIndent.Styles.JohanTibell   build-depends:     base >= 4.7 && <5                    , containers                    , haskell-src-exts >= 1.18                    , monad-loops                    , mtl-                   , text+                   , bytestring+                   , utf8-string                    , transformers+                   , exceptions+                   , text  executable hindent   hs-source-dirs:    src/main@@ -47,44 +50,45 @@   main-is:           Main.hs   build-depends:     base >= 4 && < 5                    , hindent-                   , text+                   , bytestring+                   , utf8-string                    , descriptive >= 0.7 && < 0.10                    , haskell-src-exts                    , ghc-prim                    , directory--executable hindent-generate-tests-  hs-source-dirs:    src/main-  ghc-options:       -Wall -O2-  main-is:           TestGenerate.hs-  build-depends:     base >= 4 && < 5-                   , hindent                    , text-                   , directory -test-suite hspec+test-suite hindent-test   type: exitcode-stdio-1.0-  hs-source-dirs: test-  main-is: Spec.hs+  hs-source-dirs: src/main/+  main-is: Test.hs+  other-modules: Markdone   build-depends:     base >= 4 && <5                    , hindent                    , haskell-src-exts                    , monad-loops                    , mtl-                   , text+                   , bytestring+                   , utf8-string                    , hspec                    , directory+                   , deepseq+                   , exceptions+                   , utf8-string  benchmark hindent-bench   type: exitcode-stdio-1.0   hs-source-dirs:    src/main   ghc-options:       -Wall -O2 -rtsopts   main-is:           Benchmark.hs+  other-modules: Markdone   build-depends:     base >= 4 && < 5                    , hindent-                   , text+                   , bytestring+                   , utf8-string                    , haskell-src-exts                    , ghc-prim                    , directory                    , criterion                    , deepseq+                   , exceptions
src/HIndent.hs view
@@ -1,5 +1,6 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings, TupleSections, ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings, TupleSections, ScopedTypeVariables, PatternGuards #-}  -- | Haskell indenter. @@ -8,98 +9,100 @@    reformat   ,prettyPrint   ,parseMode-  -- * Style-  ,Style(..)-  ,johanTibell   -- * Testing   ,test   ,testFile-  ,testAll   ,testAst   ,defaultExtensions+  ,getExtensions   )   where -import           HIndent.Comments-import           HIndent.Pretty-import           HIndent.Styles.JohanTibell (johanTibell)-import           HIndent.Types--import           Control.Applicative ((<$>)) import           Control.Monad.State.Strict import           Control.Monad.Trans.Maybe+import           Data.ByteString (ByteString)+import qualified Data.ByteString as S+import           Data.ByteString.Builder (Builder)+import qualified Data.ByteString.Builder as S+import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Internal as S+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Char8 as L8+import qualified Data.ByteString.UTF8 as UTF8+import qualified Data.ByteString.Unsafe as S import           Data.Function (on) import           Data.Functor.Identity import           Data.List-import           Data.List (groupBy, intersperse)-import           Data.Maybe (fromMaybe)+import           Data.Maybe import           Data.Monoid-import qualified Data.Text.IO as ST-import           Data.Text.Lazy (Text)-import qualified Data.Text.Lazy as T hiding (singleton)-import           Data.Text.Lazy.Builder (Builder)-import qualified Data.Text.Lazy.Builder as T-import qualified Data.Text.Lazy.IO as T+import           Data.Text (Text)+import qualified Data.Text as T+import           HIndent.Comments+import           HIndent.Pretty+import           HIndent.Types import           Language.Haskell.Exts hiding (Style, prettyPrint, Pretty, style, parse) -data CodeBlock = HaskellSource Text-               | CPPDirectives Text+data CodeBlock = HaskellSource ByteString+               | CPPDirectives ByteString   deriving (Show, Eq)  -- | Format the given source.-reformat :: Style -> Maybe [Extension] -> Text -> Either String Builder-reformat style mexts x =-  mconcat . intersperse "\n" <$> mapM processBlock (cppSplitBlocks x)+reformat :: Config -> Maybe [Extension] -> ByteString -> Either String Builder+reformat config mexts x =+  fmap (mconcat . intersperse "\n") (mapM processBlock (cppSplitBlocks x))   where     processBlock :: CodeBlock -> Either String Builder-    processBlock (CPPDirectives text) = Right $ T.fromLazyText text+    processBlock (CPPDirectives text) = Right $ S.byteString text     processBlock (HaskellSource text) =-      let lines = lines' text-          prefix = findPrefix lines-          code = T.unpack $ unlines' $ map (stripPrefix prefix) lines-      in case parseModuleWithComments mode' code of+      let ls = S8.lines text+          prefix = findPrefix ls+          code = unlines' (map (stripPrefix prefix) ls)+      in case parseModuleWithComments mode' (UTF8.toString code) of         ParseOk (m, comments) ->-          T.fromLazyText <$> addPrefix prefix <$> T.toLazyText <$> prettyPrint mode' style m comments+          fmap (S.lazyByteString .+          addPrefix prefix .+          S.toLazyByteString)+          (prettyPrint config mode' m comments)         ParseFailed _ e -> Left e -    lines' = T.split (== '\n')-    unlines' = mconcat . intersperse "\n"+    unlines' = S.concat . intersperse "\n"+    unlines'' = L.concat . intersperse "\n" -    addPrefix :: Text -> Text -> Text-    addPrefix prefix = unlines' . map (prefix <>) . lines'+    addPrefix :: ByteString -> L8.ByteString -> L8.ByteString+    addPrefix prefix = unlines'' . map (L8.fromStrict prefix <>) . L8.lines -    stripPrefix :: Text -> Text -> Text+    stripPrefix :: ByteString -> ByteString -> ByteString     stripPrefix prefix line =-      if T.null (T.dropWhile (== '\n') line)+      if S.null (S8.dropWhile (== '\n') line)       then line-      else fromMaybe (error "Missing expected prefix") . T.stripPrefix prefix $ line+      else fromMaybe (error "Missing expected prefix") . s8_stripPrefix prefix $ line -    findPrefix :: [Text] -> Text+    findPrefix :: [ByteString] -> ByteString     findPrefix = takePrefix False . findSmallestPrefix . dropNewlines -    dropNewlines :: [Text] -> [Text]-    dropNewlines = filter (not . T.null . T.dropWhile (== '\n'))+    dropNewlines :: [ByteString] -> [ByteString]+    dropNewlines = filter (not . S.null . S8.dropWhile (== '\n')) -    takePrefix :: Bool -> Text -> Text+    takePrefix :: Bool -> ByteString -> ByteString     takePrefix bracketUsed txt =-      case T.uncons txt of+      case S8.uncons txt of         Nothing -> ""         Just ('>', txt') -> if not bracketUsed-                              then T.cons '>' (takePrefix True txt')+                              then S8.cons '>' (takePrefix True txt')                               else ""         Just (c, txt') -> if c == ' ' || c == '\t'-                            then T.cons c (takePrefix bracketUsed txt')+                            then S8.cons c (takePrefix bracketUsed txt')                             else ""  -    findSmallestPrefix :: [Text] -> Text+    findSmallestPrefix :: [ByteString] -> ByteString     findSmallestPrefix [] = ""     findSmallestPrefix ("":_) = ""     findSmallestPrefix (p:ps) =-      let first = T.head p-          startsWithChar c x  = T.length x > 0 && T.head x == c+      let first = S8.head p+          startsWithChar c x  = S8.length x > 0 && S8.head x == c       in if all (startsWithChar first) ps-           then T.cons first (findSmallestPrefix (T.tail p : map T.tail ps))+           then S8.cons first (findSmallestPrefix (S.tail p : map S.tail ps))            else ""      mode' =@@ -120,67 +123,81 @@ -- > #endif -- -- will become five blocks, one for each CPP line and one for each pair of declarations.-cppSplitBlocks :: Text -> [CodeBlock]+cppSplitBlocks :: ByteString -> [CodeBlock] cppSplitBlocks inp =-  modifyLast (inBlock (`T.append` trailing)) .+  modifyLast (inBlock (<> trailing)) .   map (classify . mconcat . intersperse "\n") .-  groupBy ((==) `on` cppLine) .-  T.lines $ inp+  groupBy ((==) `on` cppLine) . S8.lines $+  inp   where-    cppLine :: Text -> Bool-    cppLine src = any (`T.isPrefixOf` src) ["#if", "#end", "#else", "#define", "#undef", "#elif"]--    classify :: Text -> CodeBlock-    classify text = if cppLine text-                    then CPPDirectives text-                    else HaskellSource text-+    cppLine :: ByteString -> Bool+    cppLine src =+      any+        (`S8.isPrefixOf` src)+        ["#if", "#end", "#else", "#define", "#undef", "#elif"]+    classify :: ByteString -> CodeBlock+    classify text =+      if cppLine text+        then CPPDirectives text+        else HaskellSource text     -- Hack to work around some parser issues in haskell-src-exts: Some pragmas     -- need to have a newline following them in order to parse properly, so we include     -- the trailing newline in the code block if it existed.-    trailing :: Text-    trailing = if T.isSuffixOf "\n" inp then "\n" else ""-+    trailing+      :: ByteString+    trailing =+      if S8.isSuffixOf "\n" inp+        then "\n"+        else ""     modifyLast :: (a -> a) -> [a] -> [a]-    modifyLast _ []  = []+    modifyLast _ [] = []     modifyLast f [x] = [f x]     modifyLast f (x:xs) = x : modifyLast f xs--    inBlock :: (Text -> Text) -> CodeBlock -> CodeBlock+    inBlock :: (ByteString -> ByteString) -> CodeBlock -> CodeBlock     inBlock f (HaskellSource txt) = HaskellSource (f txt)     inBlock _ dir = dir + -- | Print the module.-prettyPrint :: ParseMode-            -> Style+prettyPrint :: Config+            -> ParseMode             -> Module SrcSpanInfo             -> [Comment]             -> Either a Builder-prettyPrint mode' style m comments =+prettyPrint config mode' m comments =   let (cs,ast) =         annotateComments (fromMaybe m $ applyFixities baseFixities m) comments       csComments = map comInfoComment cs-  in case style of-      style@(Style { styleCommentPreprocessor = preprocessor }) ->-        Right (runPrinterStyle-                  mode'-                  style-                  -- For the time being, assume that all "free-floating" comments come at the beginning.-                  -- If they were not at the beginning, they would be after some ast node.-                  -- Thus, print them before going for the ast.-                  (do comments <- preprocessor (reverse csComments)-                      mapM_ (printComment Nothing) comments-                      pretty ast))+  in Right (runPrinterStyle+               config+               mode' +               -- For the time being, assume that all "free-floating" comments come at the beginning.+               -- If they were not at the beginning, they would be after some ast node.+               -- Thus, print them before going for the ast.+               (do mapM_ (printComment Nothing) csComments+                   pretty ast))+ -- | Pretty print the given printable thing.-runPrinterStyle :: ParseMode -> Style -> (forall s. Printer s ()) -> Builder-runPrinterStyle mode' (Style _name _author _desc st extenders config preprocessor) m =-  maybe (error "Printer failed with mzero call.")+runPrinterStyle :: Config -> ParseMode -> Printer () -> Builder+runPrinterStyle config mode' m =+    maybe+        (error "Printer failed with mzero call.")         psOutput         (runIdentity-           (runMaybeT (execStateT-                         (runPrinter m)-                         (PrintState 0 mempty False 0 1 st extenders config False False mode' preprocessor))))+             (runMaybeT+                  (execStateT+                       (runPrinter m)+                       (PrintState+                            0+                            mempty+                            False+                            0+                            1+                            config+                            False+                            False+                            mode'))))  -- | Parse mode, includes all extensions, doesn't assume any fixities. parseMode :: ParseMode@@ -193,42 +210,27 @@         isDisabledExtention _ = True  -- | Test the given file.-testFile :: FilePath -> Style -> IO ()-testFile fp style = T.readFile fp >>= test style+testFile :: FilePath -> IO ()+testFile fp  = S.readFile fp >>= test  -- | Test with the given style, prints to stdout.-test :: Style -> Text -> IO ()-test style =-  either error (T.putStrLn . T.toLazyText) .-  reformat style Nothing---- | Test with all styles, prints to stdout.-testAll :: Text -> IO ()-testAll i =-  forM_ styles-        (\style ->-           do ST.putStrLn ("-- " <> styleName style <> ":")-              test style i-              ST.putStrLn "")+test :: ByteString -> IO ()+test =+  either error (L8.putStrLn . S.toLazyByteString) .+  reformat defaultConfig Nothing  -- | Parse the source and annotate it with comments, yielding the resulting AST.-testAst :: Text -> Either String ([ComInfo], Module NodeInfo)+testAst :: ByteString -> Either String ([ComInfo], Module NodeInfo) testAst x =-  case parseModuleWithComments parseMode-                               (T.unpack x) of-    ParseOk (m,comments) ->-      Right (annotateComments m comments)+  case parseModuleWithComments parseMode (UTF8.toString x) of+    ParseOk (m,comments) -> Right (annotateComments m comments)     ParseFailed _ e -> Left e --- | Styles list, useful for programmatically choosing.-styles :: [Style]-styles =-  [johanTibell]- -- | Default extensions. defaultExtensions :: [Extension] defaultExtensions =-  [e | e@EnableExtension{} <- knownExtensions] \\+  [ e+  | e@EnableExtension {} <- knownExtensions ] \\   map EnableExtension badExtensions  -- | Extensions which steal too much syntax.@@ -240,3 +242,32 @@     ,UnboxedTuples -- breaks (#) lens operator     -- ,QuasiQuotes -- breaks [x| ...], making whitespace free list comps break     ]+++s8_stripPrefix :: ByteString -> ByteString -> Maybe ByteString+s8_stripPrefix bs1@(S.PS _ _ l1) bs2+   | bs1 `S.isPrefixOf` bs2 = Just (S.unsafeDrop l1 bs2)+   | otherwise = Nothing++--------------------------------------------------------------------------------+-- Extensions stuff stolen from hlint++-- | Consume an extensions list from arguments.+getExtensions :: [Text] -> [Extension]+getExtensions = foldl f defaultExtensions . map T.unpack+  where f _ "Haskell98" = []+        f a ('N':'o':x)+          | Just x' <- readExtension x =+            delete x' a+        f a x+          | Just x' <- readExtension x =+            x' :+            delete x' a+        f _ x = error $ "Unknown extension: " ++ x++-- | Parse an extension.+readExtension :: String -> Maybe Extension+readExtension x =+  case classifyExtension x of+    UnknownExtension _ -> Nothing+    x' -> Just x'
src/HIndent/Comments.hs view
@@ -5,14 +5,16 @@  module HIndent.Comments where -import Control.Applicative ((<|>))-import Control.Arrow (first, second)-import Control.Monad.State.Strict-import Data.Data+import           Control.Arrow (first, second)+import           Control.Monad.State.Strict+import           Data.Data+import qualified Data.Foldable import qualified Data.Map.Strict as M-import Data.Traversable-import HIndent.Types-import Language.Haskell.Exts hiding (Style,prettyPrint,Pretty,style,parse)+import           Data.Monoid+import           Data.Traversable+import           HIndent.Types+import           Language.Haskell.Exts hiding (Style,prettyPrint,Pretty,style,parse)+import           Prelude  -- Order by start of span, larger spans before smaller spans. newtype OrderByStart =@@ -57,7 +59,7 @@             ([],nodeinfos)   where     nodeinfos :: M.Map SrcSpanInfo NodeInfo-    nodeinfos = foldr (\ssi -> M.insert ssi (NodeInfo ssi [])) M.empty src+    nodeinfos = Data.Foldable.foldr (\ssi -> M.insert ssi (NodeInfo ssi [])) M.empty src      -- Assign a single comment to the right AST node     assignComment :: Comment -> State ([ComInfo],M.Map SrcSpanInfo NodeInfo) ()@@ -114,5 +116,5 @@     nodeBefore (Comment _ ss _) = fmap snd $ (OrderByEnd ss) `M.lookupLT` spansByEnd     nodeAfter (Comment _ ss _) = fmap snd $ (OrderByStart ss) `M.lookupGT` spansByStart -    spansByStart = foldr (\ssi -> M.insert (OrderByStart $ srcInfoSpan ssi) ssi) M.empty src-    spansByEnd = foldr (\ssi -> M.insert (OrderByEnd $ srcInfoSpan ssi) ssi) M.empty src+    spansByStart = Data.Foldable.foldr (\ssi -> M.insert (OrderByStart $ srcInfoSpan ssi) ssi) M.empty src+    spansByEnd = Data.Foldable.foldr (\ssi -> M.insert (OrderByEnd $ srcInfoSpan ssi) ssi) M.empty src
src/HIndent/Pretty.hs view
@@ -14,10 +14,6 @@     Pretty   , pretty   , prettyNoExt-  -- * User state-  ,getState-  ,putState-  ,modifyState   -- * Insertion   , write   , newline@@ -62,27 +58,20 @@   )   where -import           Control.Monad.Trans.Maybe-import           Data.Functor.Identity-import           HIndent.Types--import           Language.Haskell.Exts.Comments import           Control.Monad.State.Strict hiding (state)+import qualified Data.ByteString.Builder as S+import qualified Data.Foldable+import           Data.Foldable (traverse_) import           Data.Int import           Data.List import           Data.Maybe-import           Data.Foldable (traverse_)-import           Data.Monoid hiding (Alt)-import           Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import           Data.Text.Lazy.Builder (Builder)-import qualified Data.Text.Lazy.Builder as T-import           Data.Text.Lazy.Builder.Int+import           Data.Monoid ((<>)) import           Data.Typeable+import           HIndent.Types import qualified Language.Haskell.Exts as P-import           Language.Haskell.Exts.Syntax+import           Language.Haskell.Exts.Comments import           Language.Haskell.Exts.SrcLoc+import           Language.Haskell.Exts.Syntax import           Prelude hiding (exp)  --------------------------------------------------------------------------------@@ -90,47 +79,29 @@  -- | Pretty printing class. class (Annotated ast,Typeable ast) => Pretty ast where-  prettyInternal :: MonadState (PrintState s) m => ast NodeInfo -> m ()+  prettyInternal :: ast NodeInfo -> Printer ()  -- | Pretty print using extenders.-pretty :: (Pretty ast,MonadState (PrintState s) m)-       => ast NodeInfo -> m ()-pretty a =-  do st <- get-     case st of-       PrintState{psExtenders = es,psUserState = s} ->-         do-           printComments Before a-           depend-             (case listToMaybe (mapMaybe (makePrinter s) es) of-                Just (Printer m) ->-                  modify (\s' ->-                            fromMaybe s'-                                      (runIdentity (runMaybeT (execStateT m s'))))-                Nothing -> prettyNoExt a)-             (printComments After a)-  where makePrinter _ (Extender f) =-          case cast a of-            Just v -> Just (f v)-            Nothing -> Nothing-        makePrinter s (CatchAll f) = f s a+pretty :: (Pretty ast)+       => ast NodeInfo -> Printer ()+pretty a = do+    printComments Before a+    depend (prettyNoExt a) (printComments After a)  -- | Run the basic printer for the given node without calling an -- extension hook for this node, but do allow extender hooks in child -- nodes. Also auto-inserts comments.-prettyNoExt :: (Pretty ast,MonadState (PrintState s) m)-            => ast NodeInfo -> m ()+prettyNoExt :: (Pretty ast)+            => ast NodeInfo -> Printer () prettyNoExt = prettyInternal  -- | Print comments of a node.-printComments :: (Pretty ast,MonadState (PrintState s) m)-              => ComInfoLocation -> ast NodeInfo -> m ()+printComments :: (Pretty ast)+              => ComInfoLocation -> ast NodeInfo -> Printer () printComments loc' ast = do-  preprocessor <- gets psCommentPreprocessor-   let correctLocation comment = comInfoLocation comment == Just loc'       commentsWithLocation = filter correctLocation (nodeInfoComments info)-  comments <- preprocessor $ map comInfoComment commentsWithLocation+  comments <- return $ map comInfoComment commentsWithLocation    forM_ comments $ \comment -> do     -- Preceeding comments must have a newline before them.@@ -140,9 +111,8 @@     printComment (Just $ srcInfoSpan $ nodeInfoSpan info) comment   where info = ann ast - -- | Pretty print a comment.-printComment :: MonadState (PrintState s) m => Maybe SrcSpan -> Comment -> m ()+printComment :: MonadState (PrintState) m => Maybe SrcSpan -> Comment -> m () printComment mayNodespan (Comment inline cspan str) =   do -- Insert proper amount of space before comment.      -- This maintains alignment. This cannot force comments@@ -167,27 +137,15 @@  -- | Pretty print using HSE's own printer. The 'P.Pretty' class here -- is HSE's.-pretty' :: (Pretty ast,P.Pretty (ast SrcSpanInfo),Functor ast,MonadState (PrintState s) m)+pretty' :: (Pretty ast,P.Pretty (ast SrcSpanInfo),MonadState (PrintState) m)         => ast NodeInfo -> m ()-pretty' = write . T.fromText . T.pack . P.prettyPrint . fmap nodeInfoSpan+pretty' = write . P.prettyPrint . fmap nodeInfoSpan  -------------------------------------------------------------------------------- -- * Combinators --- | Get the user state.-getState :: Printer s s-getState = gets psUserState---- | Put the user state.-putState :: s -> Printer s ()-putState s' = modifyState (const s')---- | Modify the user state.-modifyState :: (s -> s) -> Printer s ()-modifyState f = modify (\s -> s {psUserState = f (psUserState s)})- -- | Increase indentation level by n spaces for the given printer.-indented :: MonadState (PrintState s) m => Int64 -> m a -> m a+indented :: MonadState (PrintState) m => Int64 -> m a -> m a indented i p =   do level <- gets psIndentLevel      modify (\s -> s {psIndentLevel = level + i})@@ -195,21 +153,21 @@      modify (\s -> s {psIndentLevel = level})      return m -indentedBlock :: MonadState (PrintState s) m => m a -> m a+indentedBlock :: MonadState (PrintState) m => m a -> m a indentedBlock p =   do indentSpaces <- getIndentSpaces      indented indentSpaces p  -- | Print all the printers separated by spaces.-spaced :: MonadState (PrintState s) m => [m ()] -> m ()+spaced :: MonadState (PrintState) m => [m ()] -> m () spaced = inter space  -- | Print all the printers separated by commas.-commas :: MonadState (PrintState s) m => [m ()] -> m ()+commas :: MonadState (PrintState) m => [m ()] -> m () commas = inter comma  -- | Print all the printers separated by sep.-inter :: MonadState (PrintState s) m => m () -> [m ()] -> m ()+inter :: MonadState (PrintState) m => m () -> [m ()] -> m () inter sep ps =   foldr (\(i,p) next ->            depend (do p@@ -221,28 +179,28 @@         (zip [1 ..] ps)  -- | Print all the printers separated by newlines.-lined :: MonadState (PrintState s) m => [m ()] -> m ()+lined :: MonadState (PrintState) m => [m ()] -> m () lined ps = sequence_ (intersperse newline ps)  -- | Print all the printers separated newlines and optionally a line -- prefix.-prefixedLined :: MonadState (PrintState s) m => Text -> [m ()] -> m ()+prefixedLined :: MonadState (PrintState) m => String -> [m ()] -> m () prefixedLined pref ps' =   case ps' of     [] -> return ()     (p:ps) ->       do p          indented (fromIntegral-                     (T.length pref *+                     (length pref *                       (-1)))                   (mapM_ (\p' ->                             do newline-                               depend (write (T.fromText pref)) p')+                               depend (write pref) p')                          ps)  -- | Set the (newline-) indent level to the given column for the given -- printer.-column :: MonadState (PrintState s) m => Int64 -> m a -> m a+column :: MonadState (PrintState) m => Int64 -> m a -> m a column i p =   do level <- gets psIndentLevel      modify (\s -> s {psIndentLevel = i})@@ -251,21 +209,21 @@      return m  -- | Get the current indent level.-getColumn :: MonadState (PrintState s) m => m Int64+getColumn :: MonadState (PrintState) m => m Int64 getColumn = gets psColumn  -- | Get the current line number.-getLineNum :: MonadState (PrintState s) m => m Int64+getLineNum :: MonadState (PrintState) m => m Int64 getLineNum = gets psLine  -- | Output a newline.-newline :: MonadState (PrintState s) m => m ()+newline :: MonadState (PrintState) m => m () newline =   do write "\n"      modify (\s -> s {psNewline = True})  -- | Set the context to a case context, where RHS is printed with -> .-withCaseContext :: MonadState (PrintState s) m+withCaseContext :: MonadState (PrintState) m                 => Bool -> m a -> m a withCaseContext bool pr =   do original <- gets psInsideCase@@ -275,7 +233,7 @@      return result  -- | Get the current RHS separator, either = or -> .-rhsSeparator :: MonadState (PrintState s) m+rhsSeparator :: MonadState (PrintState) m              => m () rhsSeparator =   do inCase <- gets psInsideCase@@ -285,7 +243,7 @@  -- | Make the latter's indentation depend upon the end column of the -- former.-depend :: MonadState (PrintState s) m => m () -> m b -> m b+depend :: MonadState (PrintState) m => m () -> m b -> m b depend maker dependent =   do state' <- get      maker@@ -297,7 +255,7 @@  -- | Make the latter's indentation depend upon the end column of the -- former.-dependBind :: MonadState (PrintState s) m => m a -> (a -> m b) -> m b+dependBind :: MonadState (PrintState) m => m a -> (a -> m b) -> m b dependBind maker dependent =   do state' <- get      v <- maker@@ -308,7 +266,7 @@         else (dependent v)  -- | Wrap in parens.-parens :: MonadState (PrintState s) m => m a -> m a+parens :: MonadState (PrintState) m => m a -> m a parens p =   depend (write "(")          (do v <- p@@ -316,7 +274,7 @@              return v)  -- | Wrap in braces.-braces :: MonadState (PrintState s) m => m a -> m a+braces :: MonadState (PrintState) m => m a -> m a braces p =   depend (write "{")          (do v <- p@@ -324,7 +282,7 @@              return v)  -- | Wrap in brackets.-brackets :: MonadState (PrintState s) m => m a -> m a+brackets :: MonadState (PrintState) m => m a -> m a brackets p =   depend (write "[")          (do v <- p@@ -332,20 +290,20 @@              return v)  -- | Write a space.-space :: MonadState (PrintState s) m => m ()+space :: MonadState (PrintState) m => m () space = write " "  -- | Write a comma.-comma :: MonadState (PrintState s) m => m ()+comma :: MonadState (PrintState) m => m () comma = write ","  -- | Write an integral.-int :: (Integral n, MonadState (PrintState s) m)-    => n -> m ()-int = write . decimal+int :: (MonadState (PrintState) m)+    => Integer -> m ()+int = write . show  -- | Write out a string, updating the current position information.-write :: MonadState (PrintState s) m => Builder -> m ()+write :: MonadState (PrintState) m => String -> m () write x =   do eol <- gets psEolComment      when (eol && x /= "\n") newline@@ -353,40 +311,38 @@      let clearEmpty =            configClearEmptyLines (psConfig state)          writingNewline = x == "\n"+         out :: String          out =            if psNewline state &&               not (clearEmpty && writingNewline)-              then T.fromText-                     (T.replicate (fromIntegral (psIndentLevel state))-                                  " ") <>+              then (replicate (fromIntegral (psIndentLevel state))+                               ' ') <>                    x               else x-         out' = T.toLazyText out      modify (\s ->-               s {psOutput = psOutput state <> out+               s {psOutput = psOutput state <> S.stringUtf8 out                  ,psNewline = False                  ,psEolComment = False-                 ,psLine = psLine state + additionalLines+                 ,psLine = psLine state + fromIntegral additionalLines                  ,psColumn =                     if additionalLines > 0-                       then LT.length (LT.concat (take 1 (reverse srclines)))-                       else psColumn state + LT.length out'})-  where x' = T.toLazyText x-        srclines = LT.lines x'+                       then fromIntegral (length (concat (take 1 (reverse srclines))))+                       else psColumn state + fromIntegral (length out)})+  where srclines = lines x         additionalLines =-          LT.length (LT.filter (== '\n') x')+          length (filter (== '\n') x)  -- | Write a string.-string :: MonadState (PrintState s) m =>String -> m ()-string = write . T.fromText . T.pack+string :: MonadState (PrintState) m => String -> m ()+string = write  -- | Indent spaces, e.g. 2.-getIndentSpaces :: MonadState (PrintState s) m => m Int64+getIndentSpaces :: MonadState (PrintState) m => m Int64 getIndentSpaces =   gets (configIndentSpaces . psConfig)  -- | Column limit, e.g. 80-getColumnLimit :: MonadState (PrintState s) m => m Int64+getColumnLimit :: MonadState (PrintState) m => m Int64 getColumnLimit =   gets (configMaxColumns . psConfig) @@ -407,9 +363,8 @@ nullBinds (IPBinds _ x) = null x  -- | Render a type with a context, or not.-withCtx :: (MonadState (PrintState s) m-           ,Pretty ast)-        => Maybe (ast NodeInfo) -> m b -> m b+withCtx :: (Pretty ast)+        => Maybe (ast NodeInfo) -> Printer b -> Printer b withCtx Nothing m = m withCtx (Just ctx) m =   do pretty ctx@@ -418,7 +373,7 @@      m  -- | Maybe render an overlap definition.-maybeOverlap :: MonadState (PrintState s) m => Maybe (Overlap NodeInfo) -> m ()+maybeOverlap ::  Maybe (Overlap NodeInfo) -> Printer () maybeOverlap =   maybe (return ())         (\p ->@@ -426,17 +381,22 @@            space)  -- | Swing the second printer below and indented with respect to the first.-swing :: MonadState (PrintState s) m => m () -> m b -> m b+swing :: Printer () -> Printer b -> Printer () swing a b =   do orig <- gets psIndentLevel      a-     newline-     indentSpaces <- getIndentSpaces-     column (orig + indentSpaces) b+     (fits,st) <- fitsOnOneLine (do space+                                    b)+     if fits+        then put st+        else do newline+                indentSpaces <- getIndentSpaces+                _ <- column (orig + indentSpaces) b+                return ()  -- | Swing the second printer below and indented with respect to the first by -- the specified amount.-swingBy :: MonadState (PrintState s) m => Int64 -> m () -> m b -> m b+swingBy :: Int64 -> Printer() -> Printer b -> Printer b swingBy i a b =   do orig <- gets psIndentLevel      a@@ -447,13 +407,8 @@ -- * Instances  instance Pretty Context where-  prettyInternal ctx =-    case ctx of-      CxSingle _ a -> pretty a-      CxTuple _ as ->-        parens (prefixedLined ","-                              (map pretty as))-      CxEmpty _ -> parens (return ())+  prettyInternal  =+    context  instance Pretty Pat where   prettyInternal x =@@ -530,7 +485,7 @@       PVar{} -> pretty' x  -- | Pretty print a name for being an infix operator.-prettyInfixOp :: MonadState (PrintState s) m => QName NodeInfo -> m ()+prettyInfixOp ::  QName NodeInfo -> Printer () prettyInfixOp x =   case x of     Qual _ mn n ->@@ -544,79 +499,89 @@     Special _ s -> pretty s  instance Pretty Type where-  prettyInternal x =-    case x of-      TyForall _ mbinds ctx ty ->-        depend (case mbinds of-                  Nothing -> return ()-                  Just ts ->-                    do write "forall "-                       spaced (map pretty ts)-                       write ". ")-               (withCtx ctx (pretty ty))-      TyFun _ a b ->-        depend (do pretty a-                   write " -> ")-               (pretty b)-      TyTuple _ boxed tys ->-        depend (write (case boxed of-                         Unboxed -> "(#"-                         Boxed -> "("))-               (do commas (map pretty tys)-                   write (case boxed of-                            Unboxed -> "#)"-                            Boxed -> ")"))-      TyList _ t -> brackets (pretty t)-      TyParArray _ t ->-        brackets (do write ":"-                     pretty t-                     write ":")-      TyApp _ f a -> spaced [pretty f,pretty a]-      TyVar _ n -> pretty n-      TyCon _ p -> pretty p-      TyParen _ e -> parens (pretty e)-      TyInfix _ a op b ->-        depend (do pretty a-                   space)-               (depend (do prettyInfixOp op-                           space)-                       (pretty b))-      TyKind _ ty k ->-        parens (do pretty ty-                   write " :: "-                   pretty k)-      TyBang _ bangty unpackty right ->-        do pretty unpackty-           pretty bangty-           pretty right-      TyEquals _ left right ->-        do pretty left-           write " ~ "-           pretty right-      ty@TyPromoted{} -> pretty' ty-      TySplice{} -> error "FIXME: No implementation for TySplice."-      TyWildCard _ name ->-        case name of-          Nothing -> write "_"-          Just n ->-            do write "_"-               pretty n+  prettyInternal  =+    typ  instance Pretty Exp where   prettyInternal = exp  -- | Render an expression.-exp :: MonadState (PrintState s) m => Exp NodeInfo -> m ()-exp (ExprHole {}) = write "_"-exp (InfixApp _ a op b) =-  depend (do pretty a-             space-             pretty op-             space)-         (do pretty b)+exp :: Exp NodeInfo -> Printer ()+-- | Do after lambda should swing.+exp (Lambda _ pats (Do l stmts)) =+  do+     (fits,st) <-+       fitsOnOneLine+         (do write "\\"+             spaced (map pretty pats)+             write " -> "+             pretty (Do l stmts))+     if fits+        then put st+        else swing (do write "\\"+                       spaced (map pretty pats)+                       write " -> do")+                    (lined (map pretty stmts))+-- | Space out tuples.+exp (Tuple _ boxed exps) =+  depend (write (case boxed of+                   Unboxed -> "(#"+                   Boxed -> "("))+         (do single <- isSingleLiner p+             underflow <- fmap not (isOverflow p)+             if single && underflow+                then p+                else prefixedLined ","+                                   (map (depend space . pretty) exps)+             write (case boxed of+                      Unboxed -> "#)"+                      Boxed -> ")"))+  where p = inter (write ", ") (map pretty exps)+-- | Space out tuples.+exp (TupleSection _ boxed mexps) =+  depend (write (case boxed of+                   Unboxed -> "(#"+                   Boxed -> "("))+         (do inter (write ", ") (map (maybe (return ()) pretty) mexps)+             write (case boxed of+                      Unboxed -> "#)"+                      Boxed -> ")"))+-- | Infix apps, same algorithm as ChrisDone at the moment.+exp e@(InfixApp _ a op b) =+  infixApp e a op b Nothing+-- | If bodies are indented 4 spaces. Handle also do-notation.+exp (If _ if' then' else') =+  do depend (write "if ")+            (pretty if')+     newline+     indentSpaces <- getIndentSpaces+     indented indentSpaces+              (do branch "then " then'+                  newline+                  branch "else " else')+     -- Special handling for do.+  where branch str e =+          case e of+            Do _ stmts ->+              do write str+                 write "do"+                 newline+                 indentSpaces <- getIndentSpaces+                 indented indentSpaces (lined (map pretty stmts))+            _ ->+              depend (write str)+                     (pretty e)+-- | App algorithm similar to ChrisDone algorithm, but with no+-- parent-child alignment. exp (App _ op a) =-  swing (do pretty f)-        (lined (map pretty args))+  do (fits,st) <-+       fitsOnOneLine (spaced (map pretty (f : args)))+     if fits+        then put st+        else do pretty f+                newline+                spaces <- getIndentSpaces+                indented spaces (lined (map pretty args))   where (f,args) = flatten op [a]         flatten :: Exp NodeInfo                 -> [Exp NodeInfo]@@ -624,29 +589,55 @@         flatten (App _ f' a') b =           flatten f' (a' : b)         flatten f' as = (f',as)+-- | Space out commas in list.+exp (List _ es) =+  do single <- isSingleLiner p+     underflow <- fmap not (isOverflow p)+     if single && underflow+        then p+        else brackets (prefixedLined ","+                                     (map (depend space . pretty) es))+  where p =+          brackets (inter (write ", ")+                          (map pretty es))+exp (RecUpdate _ exp' updates) = recUpdateExpr (pretty exp') updates+exp (RecConstr _ qname updates) = recUpdateExpr (pretty qname) updates+exp (Let _ binds e) =+  depend (write "let ")+         (do pretty binds+             newline+             indented (-4) (depend (write "in ")+                                   (pretty e)))+exp (ListComp _ e qstmt) =+  brackets (do space+               pretty e+               unless (null qstmt)+                      (do newline+                          indented (-1)+                                   (write "|")+                          prefixedLined ","+                                        (map (\x -> do space+                                                       pretty x+                                                       space)+                                             qstmt)))+exp (TypeApp _ _) = error "FIXME: No implementation for TypeApp"+exp (ExprHole {}) = write "_" exp (NegApp _ e) =   depend (write "-")          (pretty e) exp (Lambda _ ps e) =-  depend (write "\\")-         (do spaced (map pretty ps)-             swing (write " -> ")-                   (pretty e))-exp (Let _ binds e) =-  do depend (write "let ")-            (pretty binds)-     newline-     depend (write "in ")-            (pretty e)-exp (If _ p t e) =-  do depend (write "if ")-            (do pretty p-                newline-                depend (write "then ")-                       (pretty t)-                newline-                depend (write "else ")-                       (pretty e))+  depend+    (write "\\")+    (do spaced+          (map+             (\(i,x) -> do+                case (i, x) of+                  (0,PIrrPat {}) -> space+                  (0,PBangPat {}) -> space+                  _ -> return ()+                pretty x)+             (zip [0 :: Int ..] ps))+        swing (write " ->") (pretty e)) exp (Paren _ e) = parens (pretty e) exp (Case _ e alts) =   do depend (write "case ")@@ -660,26 +651,6 @@ exp (MDo _ stmts) =   depend (write "mdo ")          (lined (map pretty stmts))-exp (Tuple _ boxed exps) =-  depend (write (case boxed of-                   Unboxed -> "(#"-                   Boxed -> "("))-         (do prefixedLined ","-                           (map pretty exps)-             write (case boxed of-                      Unboxed -> "#)"-                      Boxed -> ")"))-exp (TupleSection _ boxed mexps) =-  depend (write (case boxed of-                   Unboxed -> "(#"-                   Boxed -> "("))-         (do commas (map (maybe (return ()) pretty) mexps)-             write (case boxed of-                      Unboxed -> "#)"-                      Boxed -> ")"))-exp (List _ es) =-  brackets (prefixedLined ","-                          (map pretty es)) exp (LeftSection _ e op) =   parens (depend (do pretty e                      space)@@ -688,16 +659,6 @@   parens (depend (do pretty e                      space)                  (pretty op))-exp (RecConstr _ n fs) =-  depend (do pretty n-             space)-         (braces (prefixedLined ","-                                (map (indentedBlock . pretty) fs)))-exp (RecUpdate _ n fs) =-  depend (do pretty n-             space)-         (braces (prefixedLined ","-                                (map (indentedBlock . pretty) fs))) exp (EnumFrom _ e) =   brackets (do pretty e                write " ..")@@ -716,14 +677,6 @@                    (depend (do pretty t                                write " .. ")                            (pretty f)))-exp (ListComp _ e qstmt) =-  brackets (do pretty e-               unless (null qstmt)-                      (do newline-                          indented (-1)-                                   (write "|")-                          prefixedLined ","-                                        (map pretty qstmt))) exp (ExpTypeSig _ e t) =   depend (do pretty e              write " :: ")@@ -776,20 +729,11 @@ exp x@ParArrayComp{} = pretty' x exp ParComp{} =   error "FIXME: No implementation for ParComp."+exp (OverloadedLabel _ label) = string ('#' : label)  instance Pretty Stmt where-  prettyInternal x =-    case x of-      Generator _ p e ->-        depend (do pretty p-                   write " <- ")-               (pretty e)-      Qualifier _ e -> pretty e-      LetStmt _ binds ->-        depend (write "let ")-               (pretty binds)-      RecStmt{} ->-        error "FIXME: No implementation for RecStmt."+  prettyInternal =+    stmt  instance Pretty QualStmt where   prettyInternal x =@@ -807,13 +751,13 @@         error "FIXME: No implementation for GroupByUsing."  instance Pretty Decl where-  prettyInternal = decl+  prettyInternal = decl'  -- | Render a declaration.-decl :: MonadState (PrintState s) m => Decl NodeInfo -> m ()-decl (PatBind _ pat rhs mbinds) =+decl ::  Decl NodeInfo -> Printer ()+decl (PatBind _ pat rhs' mbinds) =   do pretty pat-     withCaseContext False (pretty rhs)+     withCaseContext False (pretty rhs')      case mbinds of        Nothing -> return ()        Just binds ->@@ -850,11 +794,11 @@      unless (null (fromMaybe [] decls))             (do newline                 indentedBlock (lined (map pretty (fromMaybe [] decls))))-decl (TypeDecl _ typehead typ) =+decl (TypeDecl _ typehead typ') =   depend (write "type ")          (depend (pretty typehead)                  (depend (write " = ")-                         (pretty typ)))+                         (pretty typ')))  decl TypeFamDecl{} =   error "FIXME: No implementation for TypeFamDecl."@@ -946,12 +890,12 @@     case x of       BangedTy _ -> write "!"       LazyTy _ -> write "~"-      NoStrictAnnot _ -> pure ()+      NoStrictAnnot _ -> return ()  instance Pretty Unpackedness where   prettyInternal (Unpack _) = write "{-# UNPACK -#}"   prettyInternal (NoUnpack _) = write "{-# NOUNPACK -#}"-  prettyInternal (NoUnpackPragma _) = pure ()+  prettyInternal (NoUnpackPragma _) = return ()  instance Pretty Binds where   prettyInternal x =@@ -990,20 +934,7 @@  instance Pretty ConDecl where   prettyInternal x =-    case x of-      ConDecl _ name bangty ->-        depend (do pretty name-                   space)-               (lined (map pretty bangty))-      InfixConDecl l a f b ->-        pretty (ConDecl l f [a,b])-      RecDecl _ name fields ->-        depend (do pretty name-                   write " ")-               (do depend (write "{")-                          (prefixedLined ","-                                         (map pretty fields))-                   write "}")+    conDecl x  instance Pretty FieldDecl where   prettyInternal (FieldDecl _ names ty) =@@ -1016,14 +947,15 @@     case x of       FieldUpdate _ n e ->         swing (do pretty n-                  write " = ")-              (pretty e)+                  write " =")+               (pretty e)       FieldPun _ n -> pretty n       FieldWildcard _ -> write ".."  instance Pretty GuardedRhs where-  prettyInternal x =-    case x of+  prettyInternal  =+    guardedRhs+    {-case x of       GuardedRhs _ stmts e ->         do indented 1                     (do prefixedLined@@ -1033,7 +965,7 @@                                      pretty p)                                stmts))            swing (write " " >> rhsSeparator >> write " ")-                 (pretty e)+                 (pretty e)-}  instance Pretty InjectivityInfo where   prettyInternal x = pretty' x@@ -1050,20 +982,20 @@       _ -> pretty' i  instance Pretty Match where-  prettyInternal x =-    case x of-      Match _ name pats rhs mbinds ->+  prettyInternal = match+    {-case x of+      Match _ name pats rhs' mbinds ->         do depend (do pretty name                       space)                   (spaced (map pretty pats))-           withCaseContext False (pretty rhs)+           withCaseContext False (pretty rhs')            case mbinds of              Nothing -> return ()              Just binds ->                do newline                   indentedBlock (depend (write "where ")                                         (pretty binds))-      InfixMatch _ pat1 name pats rhs mbinds ->+      InfixMatch _ pat1 name pats rhs' mbinds ->         do depend (do pretty pat1                       space                       case name of@@ -1072,13 +1004,13 @@                         Symbol _ s -> string s)                   (do space                       spaced (map pretty pats))-           withCaseContext False (pretty rhs)+           withCaseContext False (pretty rhs')            case mbinds of              Nothing -> return ()              Just binds ->                do newline                   indentedBlock (depend (write "where ")-                                        (pretty binds))+                                        (pretty binds))-}  instance Pretty PatField where   prettyInternal x =@@ -1102,18 +1034,8 @@                        (pretty d))  instance Pretty Rhs where-  prettyInternal x =-    case x of-      UnGuardedRhs _ e -> do-        (swing (write " " >> rhsSeparator >> write " ")-               (pretty e))-      GuardedRhss _ gas ->-        do newline-           indented 2-                    (lined (map (\p ->-                                   do write "|"-                                      pretty p)-                                gas))+  prettyInternal =+    rhs  instance Pretty Splice where   prettyInternal x =@@ -1138,15 +1060,15 @@     case x of       -- Base cases       IHCon _ name -> pretty name-      IHInfix _ typ name ->-        depend (pretty typ)+      IHInfix _ typ' name ->+        depend (pretty typ')                (do space                    prettyInfixOp name)       -- Recursive application-      IHApp _ ihead typ ->+      IHApp _ ihead typ' ->         depend (pretty ihead)                (do space-                   pretty typ)+                   pretty typ')       -- Wrapping in parens       IHParen _ h -> parens (pretty h) @@ -1321,7 +1243,7 @@  instance Pretty ModuleName where   prettyInternal (ModuleName _ name) =-    write (T.fromString name)+    write name  instance Pretty ImportSpecList where   prettyInternal = pretty'@@ -1342,3 +1264,458 @@  instance Pretty ExportSpec where   prettyInternal = pretty'++-- Do statements need to handle infix expression indentation specially because+-- do x *+--    y+-- is two invalid statements, not one valid infix op.+stmt :: Stmt NodeInfo -> Printer ()+stmt (Qualifier _ e@(InfixApp _ a op b)) =+  do col <- fmap (psColumn . snd)+                 (sandbox (write ""))+     infixApp e a op b (Just col)+stmt (Generator _ p e) =+  do indentSpaces <- getIndentSpaces+     pretty p+     indented indentSpaces+              (dependOrNewline+                 (write " <- ")+                 e+                 pretty)+stmt x = case x of+           Generator _ p e ->+             depend (do pretty p+                        write " <- ")+                    (pretty e)+           Qualifier _ e -> pretty e+           LetStmt _ binds ->+             depend (write "let ")+                    (pretty binds)+           RecStmt{} ->+             error "FIXME: No implementation for RecStmt."++-- | Make the right hand side dependent if it fits on one line,+-- otherwise send it to the next line.+dependOrNewline :: Printer ()+                -> Exp NodeInfo+                -> (Exp NodeInfo -> Printer ())+                -> Printer ()+dependOrNewline left right f =+  do (fits,st) <- fitsOnOneLine renderDependent+     if fits+        then put st+        else do left+                newline+                (f right)+  where renderDependent = depend left (f right)++-- | Handle do and case specially and also space out guards more.+rhs :: Rhs NodeInfo -> Printer ()+rhs (UnGuardedRhs _ (Do _ dos)) =+  do inCase <- gets psInsideCase+     write (if inCase then " -> " else " = ")+     indentSpaces <- getIndentSpaces+     let indentation | inCase = indentSpaces+                     | otherwise = max 2 indentSpaces+     swingBy indentation+             (write "do")+             (lined (map pretty dos))+rhs (UnGuardedRhs _ e) =+  do (fits,st) <-+       fitsOnOneLine+         (do write " "+             rhsSeparator+             write " "+             pretty e)+     if fits+        then put st+        else swing (write " " >> rhsSeparator)+                    (pretty e)+rhs (GuardedRhss _ gas) =+  do newline+     indented 2+              (lined (map (\p ->+                             do write "|"+                                pretty p)+                          gas))++-- | Implement dangling right-hand-sides.+guardedRhs :: GuardedRhs NodeInfo -> Printer ()+-- | Handle do specially.++guardedRhs (GuardedRhs _ stmts (Do _ dos)) =+  do indented 1+              (do prefixedLined+                    ","+                    (map (\p ->+                            do space+                               pretty p)+                         stmts))+     inCase <- gets psInsideCase+     write (if inCase then " -> " else " = ")+     swing (write "do")+            (lined (map pretty dos))+guardedRhs (GuardedRhs _ stmts e) =+  do (fits,st) <-+       fitsOnOneLine+         (indented 1+                   (do prefixedLined+                         ","+                         (map (\p ->+                                 do space+                                    pretty p)+                              stmts)))+     put st+     if fits+        then do (fits',st') <-+                  fitsOnOneLine+                    (do write " "+                        rhsSeparator+                        write " "+                        pretty e)+                if fits'+                   then put st'+                   else swingIt+        else swingIt+  where swingIt =+          swing (write " " >> rhsSeparator)+                 (pretty e)+++match :: Match NodeInfo -> Printer ()+match (Match _ name pats rhs' mbinds) =+  do depend (do pretty name+                space)+            (spaced (map pretty pats))+     withCaseContext False (pretty rhs')+     Data.Foldable.forM_ mbinds bindingGroup+match (InfixMatch _ pat1 name pats rhs' mbinds) =+  do depend (do pretty pat1+                space+                case name of+                  Ident _ i ->+                    string ("`" ++ i ++ "`")+                  Symbol _ s -> string s)+            (do space+                spaced (map pretty pats))+     withCaseContext False (pretty rhs')+     Data.Foldable.forM_ mbinds bindingGroup++-- | Format contexts with spaces and commas between class constraints.+context :: Context NodeInfo -> Printer ()+context ctx@(CxTuple _ asserts) =+  do (fits,st) <-+       fitsOnOneLine+         (parens (inter (comma >> space)+                        (map pretty asserts)))+     if fits+        then put st+        else prettyNoExt ctx+context ctx = case ctx of+                CxSingle _ a -> pretty a+                CxTuple _ as ->+                  parens (prefixedLined ","+                                        (map pretty as))+                CxEmpty _ -> parens (return ())++unboxParens :: MonadState (PrintState) m => m a -> m a+unboxParens p =+  depend (write "(# ")+         (do v <- p+             write " #)"+             return v)++typ :: Type NodeInfo -> Printer ()+typ (TyTuple _ Boxed types) = parens $ inter (write ", ") $ map pretty types+typ (TyTuple _ Unboxed types) = unboxParens $ inter (write ", ") $ map pretty types+typ x = case x of+          TyForall _ mbinds ctx ty ->+            depend (case mbinds of+                      Nothing -> return ()+                      Just ts ->+                        do write "forall "+                           spaced (map pretty ts)+                           write ". ")+                   (withCtx ctx (pretty ty))+          TyFun _ a b ->+            depend (do pretty a+                       write " -> ")+                   (pretty b)+          TyTuple _ boxed tys ->+            depend (write (case boxed of+                             Unboxed -> "(#"+                             Boxed -> "("))+                   (do commas (map pretty tys)+                       write (case boxed of+                                Unboxed -> "#)"+                                Boxed -> ")"))+          TyList _ t -> brackets (pretty t)+          TyParArray _ t ->+            brackets (do write ":"+                         pretty t+                         write ":")+          TyApp _ f a -> spaced [pretty f,pretty a]+          TyVar _ n -> pretty n+          TyCon _ p -> pretty p+          TyParen _ e -> parens (pretty e)+          TyInfix _ a op b ->+            depend (do pretty a+                       space)+                   (depend (do prettyInfixOp op+                               space)+                           (pretty b))+          TyKind _ ty k ->+            parens (do pretty ty+                       write " :: "+                       pretty k)+          TyBang _ bangty unpackty right ->+            do pretty unpackty+               pretty bangty+               pretty right+          TyEquals _ left right ->+            do pretty left+               write " ~ "+               pretty right+          ty@TyPromoted{} -> pretty' ty+          TySplice{} -> error "FIXME: No implementation for TySplice."+          TyWildCard _ name ->+            case name of+              Nothing -> write "_"+              Just n ->+                do write "_"+                   pretty n+          _ -> error ("FIXME: No implementation for " ++ show x)++-- | Specially format records. Indent where clauses only 2 spaces.+decl' :: Decl NodeInfo -> Printer ()+-- | Pretty print type signatures like+--+-- foo :: (Show x, Read x)+--     => (Foo -> Bar)+--     -> Maybe Int+--     -> (Char -> X -> Y)+--     -> IO ()+--+decl' (TypeSig _ names ty') =+  do small <- isSmall (declTy ty')+     if small+        then depend (do inter (write ", ")+                              (map pretty names)+                        write " :: ")+                    (declTy ty')+        else do inter (write ", ")+                      (map pretty names)+                newline+                indentSpaces <- getIndentSpaces+                indented indentSpaces+                         (depend (write ":: ")+                                 (declTy ty'))+  where declTy dty =+          case dty of+            TyForall _ mbinds mctx ty ->+              do case mbinds of+                   Nothing -> return ()+                   Just ts ->+                     do write "forall "+                        spaced (map pretty ts)+                        write ". "+                        newline+                 case mctx of+                   Nothing -> prettyTy ty+                   Just ctx ->+                     do pretty ctx+                        newline+                        indented (-3)+                                 (depend (write "=> ")+                                         (prettyTy ty))+            _ -> prettyTy dty+        collapseFaps (TyFun _ arg result) = arg : collapseFaps result+        collapseFaps e = [e]+        prettyTy ty =+          do small <- isSmall (pretty ty)+             if small+                then pretty ty+                else case collapseFaps ty of+                       [] -> pretty ty+                       tys ->+                         prefixedLined "-> "+                                       (map pretty tys)+decl' (PatBind _ pat rhs' mbinds) =+  withCaseContext False $+    do pretty pat+       pretty rhs'+       Data.Foldable.forM_ mbinds bindingGroup++-- | Handle records specially for a prettier display (see guide).+decl' (DataDecl _ dataornew ctx dhead condecls@[_] mderivs)+  | any isRecord condecls =+    do depend (do pretty dataornew+                  unless (null condecls) space)+              (withCtx ctx+                       (do pretty dhead+                           multiCons condecls))+       case mderivs of+         Nothing -> return ()+         Just derivs -> pretty derivs+  where multiCons xs =+          depend (write " =")+                 (inter (write "|")+                        (map (depend space . qualConDecl) xs))+decl' e = decl e++-- | Use special record display, used by 'dataDecl' in a record scenario.+qualConDecl :: QualConDecl NodeInfo -> Printer ()+qualConDecl x =+  case x of+    QualConDecl _ tyvars ctx d ->+      depend (unless (null (fromMaybe [] tyvars))+                     (do write "forall "+                         spaced (map pretty (fromMaybe [] tyvars))+                         write ". "))+             (withCtx ctx (recDecl d))++-- | Fields are preceded with a space.+conDecl :: ConDecl NodeInfo -> Printer ()+conDecl (RecDecl _ name fields) =+  depend (do pretty name+             write " ")+         (do depend (write "{")+                    (prefixedLined ","+                                   (map (depend space . pretty) fields))+             write "}")+conDecl x = case x of+              ConDecl _ name bangty ->+                depend (do pretty name+                           space)+                       (lined (map pretty bangty))+              InfixConDecl l a f b ->+                pretty (ConDecl l f [a,b])+              RecDecl _ name fields ->+                depend (do pretty name+                           write " ")+                       (do depend (write "{")+                                  (prefixedLined ","+                                                 (map pretty fields))+                           write "}")++-- | Record decls are formatted like: Foo+-- { bar :: X+-- }+recDecl :: ConDecl NodeInfo -> Printer ()+recDecl (RecDecl _ name fields) =+  do pretty name+     indentSpaces <- getIndentSpaces+     newline+     column indentSpaces+            (do depend (write "{")+                       (prefixedLined ","+                                      (map (depend space . pretty) fields))+                newline+                write "} ")+recDecl r = prettyNoExt r++recUpdateExpr :: Printer () -> [FieldUpdate NodeInfo] -> Printer ()+recUpdateExpr expWriter updates = do+    expWriter+    newline+    mapM_+      (\(i,x) -> do+         if i == 0+           then write "{ "+           else write ", "+         pretty x+         newline)+      (zip [0::Int ..] updates)+    write "}"++--------------------------------------------------------------------------------+-- Predicates++-- | Is the decl a record?+isRecord :: QualConDecl t -> Bool+isRecord (QualConDecl _ _ _ RecDecl{}) = True+isRecord _ = False++-- | Does printing the given thing overflow column limit? (e.g. 80)+isOverflow :: MonadState (PrintState) m => m a -> m Bool+isOverflow p =+  do (_,st) <- sandbox p+     columnLimit <- getColumnLimit+     return (psColumn st > columnLimit)++-- | Does printing the given thing overflow column limit? (e.g. 80)+fitsOnOneLine :: MonadState (PrintState) m => m a -> m (Bool,PrintState)+fitsOnOneLine p =+  do line <- gets psLine+     (_,st) <- sandbox p+     columnLimit <- getColumnLimit+     return (psLine st == line && psColumn st < columnLimit,st)++-- | Is the given expression a single-liner when printed?+isSingleLiner :: MonadState (PrintState) m+              => m a -> m Bool+isSingleLiner p =+  do line <- gets psLine+     (_,st) <- sandbox p+     return (psLine st == line)++isSmall :: MonadState PrintState m => m a -> m Bool+isSmall p =+  do overflows <- isOverflow p+     oneLine <- isSingleLiner p+     return (not overflows && oneLine)++bindingGroup :: Binds NodeInfo -> Printer ()+bindingGroup binds =+  do newline+     indented 2+              (do write "where"+                  newline+                  indented 2 (pretty binds))++infixApp :: Exp NodeInfo+         -> Exp NodeInfo+         -> QOp NodeInfo+         -> Exp NodeInfo+         -> Maybe Int64+         -> Printer ()+infixApp e a op b indent =+  do (fits,st) <-+       fitsOnOneLine+         (spaced (map (\link ->+                         case link of+                           OpChainExp e' -> pretty e'+                           OpChainLink qop -> pretty qop)+                      (flattenOpChain e)))+     if fits+        then put st+        else do prettyWithIndent a+                space+                pretty op+                newline+                case indent of+                  Nothing -> prettyWithIndent b+                  Just col ->+                    do indentSpaces <- getIndentSpaces+                       column (col + indentSpaces)+                              (prettyWithIndent b)+  where prettyWithIndent e' =+          case e' of+            (InfixApp _ a' op' b') ->+              infixApp e' a' op' b' indent+            _ -> pretty e'++-- | A link in a chain of operator applications.+data OpChainLink l+  = OpChainExp (Exp l)+  | OpChainLink (QOp l)+  deriving (Show)++-- | Flatten a tree of InfixApp expressions into a chain of operator+-- links.+flattenOpChain :: Exp l -> [OpChainLink l]+flattenOpChain (InfixApp _ left op right) =+  flattenOpChain left <>+  [OpChainLink op] <>+  flattenOpChain right+flattenOpChain e = [OpChainExp e]
− src/HIndent/Styles/JohanTibell.hs
@@ -1,586 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}---- | Stub module for Johan Tibell's style.------ Documented here: <https://github.com/tibbe/haskell-style-guide/blob/master/haskell-style.md>------ Questions:------ How to indent after a guarded alt/rhs?--- How to indent let?--- How to indent large ADT constructors types?--module HIndent.Styles.JohanTibell where--import Control.Monad hiding (forM_)-import Control.Monad.State.Class-import Data.Foldable (forM_)-import Data.Int-import Data.Maybe-import Data.Monoid-import HIndent.Pretty-import HIndent.Types-import Language.Haskell.Exts.Syntax-import Prelude hiding (exp)------------------------------------------------------------------------------------- Style configuration---- | A short function name.-shortName :: Int64-shortName = 10---- | Empty state.-data State =-  State---- | The printer style.-johanTibell :: Style-johanTibell =-  Style {styleName = "johan-tibell"-        ,styleAuthor = "Chris Done"-        ,styleDescription = "Style modeled from Johan's style guide here: <https://github.com/tibbe/haskell-style-guide/blob/master/haskell-style.md>"-        ,styleInitialState = State-        ,styleExtenders =-           [Extender decl-           ,Extender match-           ,Extender context-           ,Extender typ-           ,Extender conDecl-           ,Extender exp-           ,Extender guardedRhs-           ,Extender rhs-           ,Extender stmt-           ,Extender fieldupdate-           ]-        ,styleDefConfig =-           defaultConfig {configMaxColumns = 80-                         ,configIndentSpaces = 4}-        ,styleCommentPreprocessor = return}------------------------------------------------------------------------------------- Extenders---- Do statements need to handle infix expression indentation specially because--- do x *---    y--- is two invalid statements, not one valid infix op.-stmt :: Stmt NodeInfo -> Printer s ()-stmt (Qualifier _ e@(InfixApp _ a op b)) =-  do col <- fmap (psColumn . snd)-                 (sandbox (write ""))-     infixApp e a op b (Just col)-stmt (Generator _ p e) =-  do indentSpaces <- getIndentSpaces-     pretty p-     indented indentSpaces-              (dependOrNewline-                 (write " <- ")-                 e-                 pretty)-stmt e = prettyNoExt e---- | Make the right hand side dependent if it fits on one line,--- otherwise send it to the next line.-dependOrNewline :: Printer t ()-                -> Exp NodeInfo-                -> (Exp NodeInfo -> Printer t ())-                -> Printer t ()-dependOrNewline left right f =-  do (fits,st) <- fitsOnOneLine renderDependent-     if fits-        then put st-        else do left-                newline-                (f right)-  where renderDependent = depend left (f right)---- | Handle do and case specially and also space out guards more.-rhs :: Rhs NodeInfo -> Printer s ()-rhs (UnGuardedRhs _ (Do _ dos)) =-  do inCase <- gets psInsideCase-     write (if inCase then " -> " else " = ")-     indentSpaces <- getIndentSpaces-     let indentation | inCase = indentSpaces-                     | otherwise = max 4 indentSpaces-     swingBy indentation-             (write "do")-             (lined (map pretty dos))-rhs (UnGuardedRhs _ e) =-  do (fits,st) <--       fitsOnOneLine-         (do write " "-             rhsSeparator-             write " "-             pretty e)-     if fits-        then put st-        else swing (write " " >> rhsSeparator >> write " ")-                   (pretty e)-rhs (GuardedRhss _ gas) =-  do newline-     indented 2-              (lined (map (\p ->-                             do write "|"-                                pretty p)-                          gas))---- | Implement dangling right-hand-sides.-guardedRhs :: GuardedRhs NodeInfo -> Printer s ()--- | Handle do specially.--guardedRhs (GuardedRhs _ stmts (Do _ dos)) =-  do indented 1-              (do prefixedLined-                    ","-                    (map (\p ->-                            do space-                               pretty p)-                         stmts))-     inCase <- gets psInsideCase-     write (if inCase then " -> " else " = ")-     swing (write "do")-           (lined (map pretty dos))-guardedRhs (GuardedRhs _ stmts e) =-  do (fits,st) <--       fitsOnOneLine-         (indented 1-                   (do prefixedLined-                         ","-                         (map (\p ->-                                 do space-                                    pretty p)-                              stmts)))-     put st-     if fits-        then do (fits',st') <--                  fitsOnOneLine-                    (do write " "-                        rhsSeparator-                        write " "-                        pretty e)-                if fits'-                   then put st'-                   else swingIt-        else swingIt-  where swingIt =-          swing (write " " >> rhsSeparator >> write " ")-                (pretty e)----- | Expression customizations.-exp :: Exp NodeInfo -> Printer s ()--- | Do after lambda should swing.-exp (Lambda _ pats (Do l stmts)) =-  do-     (fits,st) <--       fitsOnOneLine-         (do write "\\"-             spaced (map pretty pats)-             write " -> "-             pretty (Do l stmts))-     if fits-        then put st-        else swing (do write "\\"-                       spaced (map pretty pats)-                       write " -> do")-                   (lined (map pretty stmts))--- | Space out tuples.-exp (Tuple _ boxed exps) =-  depend (write (case boxed of-                   Unboxed -> "(#"-                   Boxed -> "("))-         (do single <- isSingleLiner p-             underflow <- fmap not (isOverflow p)-             if single && underflow-                then p-                else prefixedLined ","-                                   (map (depend space . pretty) exps)-             write (case boxed of-                      Unboxed -> "#)"-                      Boxed -> ")"))-  where p = inter (write ", ") (map pretty exps)--- | Space out tuples.-exp (TupleSection _ boxed mexps) =-  depend (write (case boxed of-                   Unboxed -> "(#"-                   Boxed -> "("))-         (do inter (write ", ") (map (maybe (return ()) pretty) mexps)-             write (case boxed of-                      Unboxed -> "#)"-                      Boxed -> ")"))--- | Infix apps, same algorithm as ChrisDone at the moment.-exp e@(InfixApp _ a op b) =-  infixApp e a op b Nothing--- | If bodies are indented 4 spaces. Handle also do-notation.-exp (If _ if' then' else') =-  do depend (write "if ")-            (pretty if')-     newline-     indentSpaces <- getIndentSpaces-     indented indentSpaces-              (do branch "then " then'-                  newline-                  branch "else " else')-     -- Special handling for do.-  where branch str e =-          case e of-            Do _ stmts ->-              do write str-                 write "do"-                 newline-                 indentSpaces <- getIndentSpaces-                 indented indentSpaces (lined (map pretty stmts))-            _ ->-              depend (write str)-                     (pretty e)--- | App algorithm similar to ChrisDone algorithm, but with no--- parent-child alignment.-exp (App _ op a) =-  do (fits,st) <--       fitsOnOneLine (spaced (map pretty (f : args)))-     if fits-        then put st-        else do pretty f-                newline-                spaces <- getIndentSpaces-                indented spaces (lined (map pretty args))-  where (f,args) = flatten op [a]-        flatten :: Exp NodeInfo-                -> [Exp NodeInfo]-                -> (Exp NodeInfo,[Exp NodeInfo])-        flatten (App _ f' a') b =-          flatten f' (a' : b)-        flatten f' as = (f',as)--- | Space out commas in list.-exp (List _ es) =-  do single <- isSingleLiner p-     underflow <- fmap not (isOverflow p)-     if single && underflow-        then p-        else brackets (prefixedLined ","-                                     (map (depend space . pretty) es))-  where p =-          brackets (inter (write ", ")-                          (map pretty es))-exp (RecUpdate _ exp' updates) = recUpdateExpr (pretty exp') updates-exp (RecConstr _ qname updates) = recUpdateExpr (pretty qname) updates-exp (Let _ binds e) =-  depend (write "let ")-         (do pretty binds-             newline-             indented (-4) (depend (write "in ")-                                   (pretty e)))-exp (ListComp _ e qstmt) =-  brackets (do space-               pretty e-               unless (null qstmt)-                      (do newline-                          indented (-1)-                                   (write "|")-                          prefixedLined ","-                                        (map (\x -> do space-                                                       pretty x-                                                       space)-                                             qstmt)))-exp e = prettyNoExt e--match :: Match NodeInfo -> Printer s ()-match (Match _ name pats rhs' mbinds) =-  do depend (do pretty name-                space)-            (spaced (map pretty pats))-     withCaseContext False (pretty rhs')-     forM_ mbinds bindingGroup-match (InfixMatch _ pat1 name pats rhs' mbinds) =-  do depend (do pretty pat1-                space-                case name of-                  Ident _ i ->-                    string ("`" ++ i ++ "`")-                  Symbol _ s -> string s)-            (do space-                spaced (map pretty pats))-     withCaseContext False (pretty rhs')-     forM_ mbinds bindingGroup---- | Format contexts with spaces and commas between class constraints.-context :: Context NodeInfo -> Printer s ()-context ctx@(CxTuple _ asserts) =-  do (fits,st) <--       fitsOnOneLine-         (parens (inter (comma >> space)-                        (map pretty asserts)))-     if fits-        then put st-        else prettyNoExt ctx-context ctx = prettyNoExt ctx--unboxParens :: MonadState (PrintState s) m => m a -> m a-unboxParens p =-  depend (write "(# ")-         (do v <- p-             write " #)"-             return v)--typ :: Type NodeInfo -> Printer s ()-typ (TyTuple _ Boxed types) = parens $ inter (write ", ") $ map pretty types-typ (TyTuple _ Unboxed types) = unboxParens $ inter (write ", ") $ map pretty types-typ ty = prettyNoExt ty---- | Specially format records. Indent where clauses only 2 spaces.-decl :: Decl NodeInfo -> Printer s ()--- | Pretty print type signatures like------ foo :: (Show x, Read x)---     => (Foo -> Bar)---     -> Maybe Int---     -> (Char -> X -> Y)---     -> IO ()----decl (TypeSig _ names ty') =-  do small <- isSmall (declTy ty')-     if small-        then depend (do inter (write ", ")-                              (map pretty names)-                        write " :: ")-                    (declTy ty')-        else do inter (write ", ")-                      (map pretty names)-                newline-                indentSpaces <- getIndentSpaces-                indented indentSpaces-                         (depend (write ":: ")-                                 (declTy ty'))-  where declTy dty =-          case dty of-            TyForall _ mbinds mctx ty ->-              do case mbinds of-                   Nothing -> return ()-                   Just ts ->-                     do write "forall "-                        spaced (map pretty ts)-                        write ". "-                        newline-                 case mctx of-                   Nothing -> prettyTy ty-                   Just ctx ->-                     do pretty ctx-                        newline-                        indented (-3)-                                 (depend (write "=> ")-                                         (prettyTy ty))-            _ -> prettyTy dty-        collapseFaps (TyFun _ arg result) = arg : collapseFaps result-        collapseFaps e = [e]-        prettyTy ty =-          do small <- isSmall (pretty ty)-             if small-                then pretty ty-                else case collapseFaps ty of-                       [] -> pretty ty-                       tys ->-                         prefixedLined "-> "-                                       (map pretty tys)-decl (PatBind _ pat rhs' mbinds) =-  withCaseContext False $-    do pretty pat-       pretty rhs'-       forM_ mbinds bindingGroup---- | Handle records specially for a prettier display (see guide).-decl (DataDecl _ dataornew ctx dhead condecls@[_] mderivs)-  | any isRecord condecls =-    do depend (do pretty dataornew-                  unless (null condecls) space)-              (withCtx ctx-                       (do pretty dhead-                           multiCons condecls))-       case mderivs of-         Nothing -> return ()-         Just derivs -> pretty derivs-  where multiCons xs =-          depend (write " =")-                 (inter (write "|")-                        (map (depend space . qualConDecl) xs))-decl e = prettyNoExt e---- | Use special record display, used by 'dataDecl' in a record scenario.-qualConDecl :: QualConDecl NodeInfo -> Printer s ()-qualConDecl x =-  case x of-    QualConDecl _ tyvars ctx d ->-      depend (unless (null (fromMaybe [] tyvars))-                     (do write "forall "-                         spaced (map pretty (fromMaybe [] tyvars))-                         write ". "))-             (withCtx ctx (recDecl d))---- | Fields are preceded with a space.-conDecl :: ConDecl NodeInfo -> Printer s ()-conDecl (RecDecl _ name fields) =-  depend (do pretty name-             write " ")-         (do depend (write "{")-                    (prefixedLined ","-                                   (map (depend space . pretty) fields))-             write "}")-conDecl e = prettyNoExt e---- | Record decls are formatted like: Foo--- { bar :: X--- }-recDecl :: ConDecl NodeInfo -> Printer s ()-recDecl (RecDecl _ name fields) =-  do pretty name-     indentSpaces <- getIndentSpaces-     newline-     column indentSpaces-            (do depend (write "{")-                       (prefixedLined ","-                                      (map (depend space . pretty) fields))-                newline-                write "} ")-recDecl r = prettyNoExt r--recUpdateExpr :: Printer s () -> [FieldUpdate NodeInfo] -> Printer s ()-recUpdateExpr expWriter updates = do-  expWriter-  newline-  indentSpaces <- getIndentSpaces-  write "{ "-  -- -2 because the "{ " moved us 2 chars to the right.-  indented (indentSpaces -2) $ do-    prefixedLined ", " $ map pretty updates-    newline-  write "}"------------------------------------------------------------------------------------- Predicates---- | Is the decl a record?-isRecord :: QualConDecl t -> Bool-isRecord (QualConDecl _ _ _ RecDecl{}) = True-isRecord _ = False---- | Does printing the given thing overflow column limit? (e.g. 80)-isOverflow :: MonadState (PrintState s) m => m a -> m Bool-isOverflow p =-  do (_,st) <- sandbox p-     columnLimit <- getColumnLimit-     return (psColumn st > columnLimit)---- | Does printing the given thing overflow column limit? (e.g. 80)-fitsOnOneLine :: MonadState (PrintState s) m => m a -> m (Bool,PrintState s)-fitsOnOneLine p =-  do line <- gets psLine-     (_,st) <- sandbox p-     columnLimit <- getColumnLimit-     return (psLine st == line && psColumn st < columnLimit,st)---- | Is the given expression a single-liner when printed?-isSingleLiner :: MonadState (PrintState s) m-              => m a -> m Bool-isSingleLiner p =-  do line <- gets psLine-     (_,st) <- sandbox p-     return (psLine st == line)---- | Is the expression "short"? Used for app heads.-isShort :: (Pretty ast)-        => ast NodeInfo -> Printer s (Bool)-isShort p =-  do line <- gets psLine-     orig <- fmap (psColumn . snd) (sandbox (write ""))-     (_,st) <- sandbox (pretty p)-     return (psLine st == line &&-             (psColumn st < orig + shortName))---- | Is an expression flat?-isFlat :: Exp NodeInfo -> Printer s Bool-isFlat (Lambda _ _ e) = isFlat e-isFlat (App _ a b) =-  return (isName a && isName b)-  where isName (Var{}) = True-        isName _ = False-isFlat (NegApp _ a) = isFlat a-isFlat VarQuote{} = return True-isFlat TypQuote{} = return True-isFlat (List _ []) = return True-isFlat Var{} = return True-isFlat Lit{} = return True-isFlat Con{} = return True-isFlat (LeftSection _ e _) = isFlat e-isFlat (RightSection _ _ e) = isFlat e-isFlat _ = return False---- | rhs on field update on the same line as lhs.-fieldupdate :: FieldUpdate NodeInfo -> Printer s ()-fieldupdate e =-  case e of-    FieldUpdate _ n e' -> do pretty n-                             write " = "-                             pretty e'-    _ -> prettyNoExt e--isSmall :: MonadState (PrintState t) m => m a -> m Bool-isSmall p =-  do overflows <- isOverflow p-     oneLine <- isSingleLiner p-     return (not overflows && oneLine)--bindingGroup :: Binds NodeInfo -> Printer s ()-bindingGroup binds =-  do newline-     indented 2-              (do write "where"-                  newline-                  indented 2 (pretty binds))--infixApp :: Exp NodeInfo-         -> Exp NodeInfo-         -> QOp NodeInfo-         -> Exp NodeInfo-         -> Maybe Int64-         -> Printer s ()-infixApp e a op b indent =-  do (fits,st) <--       fitsOnOneLine-         (spaced (map (\link ->-                         case link of-                           OpChainExp e' -> pretty e'-                           OpChainLink qop -> pretty qop)-                      (flattenOpChain e)))-     if fits-        then put st-        else do prettyWithIndent a-                space-                pretty op-                newline-                case indent of-                  Nothing -> prettyWithIndent b-                  Just col ->-                    do indentSpaces <- getIndentSpaces-                       column (col + indentSpaces)-                              (prettyWithIndent b)-  where prettyWithIndent e' =-          case e' of-            (InfixApp _ a' op' b') ->-              infixApp e' a' op' b' indent-            _ -> pretty e'---- | A link in a chain of operator applications.-data OpChainLink l-  = OpChainExp (Exp l)-  | OpChainLink (QOp l)-  deriving (Show)---- | Flatten a tree of InfixApp expressions into a chain of operator--- links.-flattenOpChain :: Exp l -> [OpChainLink l]-flattenOpChain (InfixApp _ left op right) =-  flattenOpChain left <>-  [OpChainLink op] <>-  flattenOpChain right-flattenOpChain e = [OpChainExp e]
src/HIndent/Types.hs view
@@ -10,8 +10,6 @@ module HIndent.Types   (Printer(..)   ,PrintState(..)-  ,Extender(..)-  ,Style(..)   ,Config(..)   ,defaultConfig   ,NodeInfo(..)@@ -26,50 +24,28 @@ import Data.Data import Data.Functor.Identity import Data.Int (Int64)-import Data.Text (Text)-import Data.Text.Lazy.Builder (Builder)+import Data.ByteString.Builder import Language.Haskell.Exts.Comments import Language.Haskell.Exts.Parser import Language.Haskell.Exts.SrcLoc  -- | A pretty printing monad.-newtype Printer s a =-  Printer {runPrinter :: StateT (PrintState s) (MaybeT Identity) a}-  deriving (Applicative,Monad,Functor,MonadState (PrintState s),MonadPlus,Alternative)+newtype Printer a =+  Printer {runPrinter :: StateT PrintState (MaybeT Identity) a}+  deriving (Applicative,Monad,Functor,MonadState PrintState,MonadPlus,Alternative)  -- | The state of the pretty printer.-data PrintState s =+data PrintState =   PrintState {psIndentLevel :: !Int64 -- ^ Current indentation level.              ,psOutput :: !Builder -- ^ The current output.              ,psNewline :: !Bool -- ^ Just outputted a newline?              ,psColumn :: !Int64 -- ^ Current column.              ,psLine :: !Int64 -- ^ Current line number.-             ,psUserState :: !s -- ^ User state.-             ,psExtenders :: ![Extender s] -- ^ Extenders.              ,psConfig :: !Config -- ^ Config which styles may or may not pay attention to.              ,psEolComment :: !Bool -- ^ An end of line comment has just been outputted.              ,psInsideCase :: !Bool -- ^ Whether we're in a case statement, used for Rhs printing.              ,psParseMode :: !ParseMode -- ^ Mode used to parse the original AST.-             ,psCommentPreprocessor :: forall m. MonadState (PrintState s) m => [Comment] -> m [Comment] -- ^ Preprocessor applied to comments on an AST before printing.              }---- | A printer extender. Takes as argument the user state that the--- printer was run with, and the current node to print. Use--- 'prettyNoExt' to fallback to the built-in printer.-data Extender s where-  Extender :: forall s a. (Typeable a) => (a -> Printer s ()) -> Extender s-  CatchAll :: forall s. (forall a. Typeable a => s -> a -> Maybe (Printer s ())) -> Extender s---- | A printer style.-data Style =-  forall s. Style {styleName :: !Text -- ^ Name of the style, used in the commandline interface.-                  ,styleAuthor :: !Text -- ^ Author of the printer (as opposed to the author of the style).-                  ,styleDescription :: !Text -- ^ Description of the style.-                  ,styleInitialState :: !s -- ^ User state, if needed.-                  ,styleExtenders :: ![Extender s] -- ^ Extenders to the printer.-                  ,styleDefConfig :: !Config -- ^ Default config to use for this style.-                  ,styleCommentPreprocessor :: forall s' m. MonadState (PrintState s') m => [Comment] -> m [Comment] -- ^ Preprocessor to use for comments.-                  }  -- | Configurations shared among the different styles. Styles may pay -- attention to or completely disregard this configuration.
src/main/Benchmark.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE BangPatterns #-}  -- | Benchmark the pretty printer.@@ -7,28 +8,41 @@ import           Control.DeepSeq import           Criterion import           Criterion.Main-import           Data.Text.Lazy (Text)-import qualified Data.Text.Lazy.IO as LT-import qualified Data.Text.Lazy.Builder as T+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy.Builder as L+import qualified Data.ByteString.Lazy.UTF8 as LUTF8+import qualified Data.ByteString.UTF8 as UTF8 import           HIndent+import           HIndent.Types+import           Markdone  -- | Main benchmarks. main :: IO ()-main =-  defaultMain-    [env setupEnv-         (\ ~bigDecls ->-             bgroup "Main"-                    [bgroup "BigDeclarations"-                            [bench ("HIndent.reformat: " ++-                                    show (styleName style))-                                   (nf (either error T.toLazyText .-                                        reformat style (Just defaultExtensions))-                                       bigDecls)|style <- styles]])]+main = do+    bytes <- S.readFile "BENCHMARKS.md"+    !forest <- fmap force (parse (tokenize bytes))+    defaultMain (toCriterion forest) --- | Setup the environment for the benchmarks.-setupEnv :: IO Text-setupEnv = do-  bigDecls <- LT.readFile "benchmarks/BigDeclarations.hs"-  let !decls = force bigDecls-  return decls+-- | Convert the Markdone document to Criterion benchmarks.+toCriterion :: [Markdone] -> [Benchmark]+toCriterion = go+  where+    go (Section name children:next) =+      bgroup (S8.unpack name) (go children) : go next+    go (PlainText desc:CodeFence lang code:next) =+      if lang == "haskell"+        then (bench+                (UTF8.toString desc)+                (nf+                   (either error L.toLazyByteString .+                    reformat+                      HIndent.Types.defaultConfig+                      (Just defaultExtensions))+                   code)) :+             go next+        else go next+    go (PlainText {}:next) = go next+    go (CodeFence {}:next) = go next+    go [] = []+
src/main/Main.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE Unsafe #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}@@ -10,17 +11,15 @@  import           HIndent import           HIndent.Types-+import qualified Data.ByteString as S+import qualified Data.ByteString.Builder as S+import qualified Data.ByteString.Lazy.Char8 as L8 import           Control.Applicative-import           Data.List import           Data.Text (Text) import qualified Data.Text as T-import qualified Data.Text.Lazy.Builder as T-import qualified Data.Text.Lazy.IO as T import           Data.Version (showVersion) import           Descriptive import           Descriptive.Options-import           GHC.Tuple import           Language.Haskell.Exts hiding (Style,style) import           Paths_hindent (version) import           System.Directory@@ -39,15 +38,14 @@         Succeeded (style,exts,mfilepath) ->             case mfilepath of                 Just filepath -> do-                    text <- T.readFile filepath+                    text <- S.readFile filepath                     tmpDir <- getTemporaryDirectory                     (fp,h) <- openTempFile tmpDir "hindent.hs"-                    T.hPutStrLn-                        h-                        (either-                             error-                             T.toLazyText-                             (reformat style (Just exts) text))+                    L8.putStrLn+                                   (either+                                        error+                                        S.toLazyByteString+                                        (reformat style (Just exts) text))                     hFlush h                     hClose h                     let exdev e =@@ -60,14 +58,15 @@                                 else throw e                     renameFile fp filepath `catch` exdev                 Nothing ->-                    T.interact-                        (either error T.toLazyText . reformat style (Just exts))+                    L8.interact+                           (either error S.toLazyByteString . reformat style (Just exts) . L8.toStrict)         Failed (Wrap (Stopped Version) _) ->             putStrLn ("hindent " ++ showVersion version)         Failed (Wrap (Stopped Help) _) -> putStrLn help         _ -> error help   where +help :: [Char] help =     "hindent " ++     T.unpack (textDescription (describe options [])) ++@@ -81,15 +80,16 @@  -- | Program options. options :: Monad m-        => Consumer [Text] (Option Stoppers) m (Style,[Extension],Maybe FilePath)+        => Consumer [Text] (Option Stoppers) m (Config,[Extension],Maybe FilePath) options = ver *> ((,,) <$> style <*> exts <*> file)   where-    ver = stop (flag "version" "Print the version" Version) *>-          stop (flag "help" "Show help" Help)+    ver =+        stop (flag "version" "Print the version" Version) *>+        stop (flag "help" "Show help" Help)     style =         makeStyle <$>         fmap-            (const johanTibell)+            (const defaultConfig)             (optional                  (constant "--style" "Style to print with" () *>                   anyString "STYLE")) <*>@@ -104,31 +104,6 @@             Nothing -> s             Just len ->                 s-                { styleDefConfig = (styleDefConfig s)-                  { configMaxColumns = len-                  }+                { configMaxColumns = len                 }     file = fmap (fmap T.unpack) (optional (anyString "[<filename>]"))------------------------------------------------------------------------------------- Extensions stuff stolen from hlint---- | Consume an extensions list from arguments.-getExtensions :: [Text] -> [Extension]-getExtensions = foldl f defaultExtensions . map T.unpack-  where f _ "Haskell98" = []-        f a ('N':'o':x)-          | Just x' <- readExtension x =-            delete x' a-        f a x-          | Just x' <- readExtension x =-            x' :-            delete x' a-        f _ x = error $ "Unknown extension: " ++ x---- | Parse an extension.-readExtension :: String -> Maybe Extension-readExtension x =-  case classifyExtension x of-    UnknownExtension _ -> Nothing-    x' -> Just x'
+ src/main/Markdone.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}++-- | A subset of markdown that only supports @#headings@ and code+-- fences.+--+-- All content must be in section headings with proper hierarchy,+-- anything else is rejected.++module Markdone where++import           Control.DeepSeq+import           Control.Monad.Catch+import           Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as S8+import           Data.Char+import           Data.Typeable+import           GHC.Generics++-- | A markdone token.+data Token+  = Heading !Int+            !ByteString+  | PlainLine !ByteString+  | BeginFence !ByteString+  | EndFence+  deriving (Show)++-- | A markdone document.+data Markdone+  = Section !ByteString+            ![Markdone]+  | CodeFence !ByteString+              !ByteString+  | PlainText !ByteString+  deriving (Show,Generic)+instance NFData Markdone++-- | Parse error.+data MarkdownError = NoFenceEnd | ExpectedSection+  deriving (Typeable,Show)+instance Exception MarkdownError++-- | Tokenize the bytestring.+tokenize :: ByteString -> [Token]+tokenize = map token . S8.lines+  where+    token line =+      if S8.isPrefixOf "#" line+        then let (hashes,title) = S8.span (== '#') line+             in Heading (S8.length hashes) (S8.dropWhile isSpace title)+        else if S8.isPrefixOf "```" line+               then if line == "```"+                      then EndFence+                      else BeginFence+                             (S8.dropWhile+                                (\c ->+                                    c == '`' || c == ' ')+                                line)+               else PlainLine line++-- | Parse into a forest.+parse :: (Functor m,MonadThrow m) => [Token] -> m [Markdone]+parse = go (0 :: Int)+  where+    go level =+      \case+        (Heading n label:rest) ->+          let (children,rest') =+                span+                  (\case+                     Heading nextN _ -> nextN > n+                     _ -> True)+                  rest+          in do childs <- go (level + 1) children+                siblings <- go level rest'+                return (Section label childs : siblings)+        (BeginFence label:rest)+          | level > 0 ->+            let (content,rest') =+                  (span+                     (\case+                        PlainLine {} -> True+                        _ -> False)+                     rest)+            in case rest' of+                 (EndFence:rest'') ->+                   fmap+                     (CodeFence+                        label+                        (S8.intercalate "\n" (map getPlain content)) :)+                     (go level rest'')+                 _ -> throwM NoFenceEnd+        PlainLine p:rest+          | level > 0 ->+            let (content,rest') =+                  (span+                     (\case+                        PlainLine {} -> True+                        _ -> False)+                     (PlainLine p : rest))+            in fmap+                 (PlainText+                    (S8.intercalate+                       "\n"+                       (filter (not . S8.null) (map getPlain content))) :)+                 (go level rest')+        [] -> return []+        _ -> throwM ExpectedSection+    getPlain (PlainLine x) = x+    getPlain _ = ""
+ src/main/Test.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Test the pretty printer.++module Main where++import qualified Data.ByteString as S+import           Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Builder as L+import qualified Data.ByteString.Lazy.Char8 as L8+import qualified Data.ByteString.Lazy.UTF8 as LUTF8+import qualified Data.ByteString.UTF8 as UTF8+import           Data.Monoid+import           HIndent+import           HIndent.Types+import           Markdone+import           Test.Hspec++-- | Main benchmarks.+main :: IO ()+main = do+    bytes <- S.readFile "TESTS.md"+    forest <- parse (tokenize bytes)+    hspec (toSpec forest)++-- -- | Convert the Markdone document to Spec benchmarks.+toSpec :: [Markdone] -> Spec+toSpec = go+  where+    go (Section name children:next) = do+        describe (UTF8.toString name) (go children)+        go next+    go (PlainText desc:CodeFence lang code:next) =+      if lang == "haskell"+        then do+          it+            (UTF8.toString desc)+            (shouldBeReadable+               (either+                  (("-- " <>) . L8.pack)+                  L.toLazyByteString+                  (reformat+                     HIndent.Types.defaultConfig+                     (Just defaultExtensions)+                     code))+               (L.fromStrict code))+          go next+        else go next+    go (PlainText {}:next) = go next+    go (CodeFence {}:next) = go next+    go [] = return ()++-- | Version of 'shouldBe' that prints strings in a readable way,+-- better for our use-case.+shouldBeReadable :: ByteString -> ByteString -> Expectation+shouldBeReadable x y = shouldBe (Readable x) (Readable y)++-- | Prints a string without quoting and escaping.+newtype Readable = Readable ByteString deriving (Eq)+instance Show Readable where+  show (Readable x) = "\n" ++ LUTF8.toString x
− src/main/TestGenerate.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-module Main(main) where--import Control.Monad-import Control.Applicative-import Data.List (find, unfoldr, isPrefixOf, intercalate)--import System.Directory-import System.Environment-import qualified Data.Text as T-import qualified Data.Text.Lazy as L-import qualified Data.Text.Lazy.Builder as L--import qualified HIndent--testDir, expectedDir :: String-testDir = "tests"-expectedDir = "expected"---- This executable generates a test suite for a style using a test suite--- from a previous style. Given arguments `from` and `to` which are style names,--- it will take all the input files for `from`, create identical input files for `to`,--- run each block in the input files through the `to` style, and generate expectation files matching the output.-main :: IO ()-main = do-  args <- getArgs-  case args of-    [from, to] -> generateTests from to-    _          -> putStrLn "Two arguments required: source tests and destination tests."--generateTests :: String -> String -> IO ()-generateTests from to = do-  --  Find the source and destination styles.-  let Just toStyle = findStyle (T.pack to)--  --  Get all the test and expectation files for the original test suite.-  testFilenamesFrom <- filter (not . isPrefixOf ".") <$> getDirectoryContents (tests from)--  -- Verify the target directories exist.-  createDirectoryIfMissing True $ tests to-  createDirectoryIfMissing True $ expected to--  -- Copy test files to the new style test directory.-  forM_ testFilenamesFrom $ \filename ->-    copyFile (tests from ++ filename) (tests to ++ filename)--  -- Generate expectation files for the new style test directory.-  forM_ testFilenamesFrom $ \filename -> do-    let dstFilename = expected to ++ expectedFilename filename-    contents <- expectationFileContents toStyle <$> readFile (tests to ++ filename)-    writeFile dstFilename contents--  where-    findStyle style = find ((== style). HIndent.styleName) [HIndent.johanTibell]-    tests style = "test/" ++ style ++ "/" ++ testDir ++ "/"-    expected style = "test/" ++ style ++ "/" ++ expectedDir ++ "/"-    expectedFilename filename = take (length filename - 4) filename ++ "exp"--expectationFileContents :: HIndent.Style -> String -> String-expectationFileContents style contents =-  let testDecls = parsePieces contents-      fmt input = L.unpack $ L.toLazyText $ case HIndent.reformat style Nothing $ L.pack input of-                                              Left err      -> error err-                                              Right builder -> builder-      outputs = map (replaceEmptyNewlines . fmt) testDecls-  in intercalate "\n" outputs-  where-    replaceEmptyNewlines = unlines . map replaceNewline . lines-    replaceNewline "" = ">"-    replaceNewline x = x--parsePieces :: String -> [String]-parsePieces str = map (intercalate "\n" . map mkNewlines) pieces-  where-    pieces = unfoldr unfolder (lines str)--    unfolder :: [String] -> Maybe ([String], [String])-    unfolder [] = Nothing-    unfolder remaining = Just $-     case break pieceBreak (zip remaining (tail remaining ++ [""]))  of-       (nonNull, [])     -> (map fst nonNull, [])-       (nonNull, _:rest) -> (map fst nonNull, map fst rest)--    pieceBreak :: (String, String) -> Bool-    pieceBreak ("", "") = error "Two consecutive line breaks!"-    pieceBreak (line, next) = null line && head next /= ' '--    mkNewlines :: String -> String-    mkNewlines ">" = ""-    mkNewlines x = x
− test/Spec.hs
@@ -1,92 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-module Main (main) where--import           Control.Monad-import           Control.Applicative-import           Data.List (find, unfoldr, break, isPrefixOf, intercalate)--import           Test.Hspec-import           System.Directory-import qualified Data.Text as T-import qualified Data.Text.Lazy as L-import qualified Data.Text.Lazy.Builder as L--import Language.Haskell.Exts.Extension--import qualified HIndent--styles :: [FilePath]-styles = ["johan-tibell"]--testDir, expectedDir :: String-testDir = "tests"-expectedDir = "expected"--main :: IO ()-main = forM_ styles testStyle--testStyle :: FilePath -> IO ()-testStyle style = do-  let Just theStyle = find ((== T.pack style) . HIndent.styleName) [HIndent.johanTibell]-  testFilenames <- filter (not . isPrefixOf ".") <$> getDirectoryContents tests-  let expFiles = map ((expected ++) . expectedFilename) testFilenames-      testFiles = map (tests ++) testFilenames-  specs <- forM (zip testFiles expFiles) (uncurry $ useTestFiles theStyle)-  hspec $ foldl1 (>>) specs--  where-    tests = "test/" ++ style ++ "/" ++ testDir ++ "/"-    expected = "test/" ++ style ++ "/" ++ expectedDir ++ "/"--    expectedFilename filename = take (length filename - 4) filename ++ "exp"--useTestFiles :: HIndent.Style -> FilePath -> FilePath -> IO Spec-useTestFiles style test exp = do-  testContents <- readFile test-  expContents <- readFile exp-  let testDecls = parsePieces testContents-      expDecls = parsePieces expContents-  when (length testDecls /= length expDecls) $-    error $ concat-              [ "Mismatched number of pieces in files "-              , test-              , " ("-              , show $ length testDecls-              , ")"-              , " and "-              , exp-              , " ("-              , show $ length expDecls-              , ")"-              ]-  return $ describe ("hindent applied to chunks in " ++ test) $ foldl1 (>>) $ zipWith (mkSpec style)-                                                                                testDecls expDecls--mkSpec :: HIndent.Style -> String -> String -> Spec-mkSpec style input desired = it "works" $-  case HIndent.reformat style (Just exts) (L.pack input) of-    Left err      -> expectationFailure ("Error: " ++ err)-    Right builder -> L.unpack (L.toLazyText builder) `shouldBe` desired-  where exts =-          glasgowExts ++-          map EnableExtension [TemplateHaskell,DataKinds, MultiWayIf]--parsePieces :: String -> [String]-parsePieces str = map (intercalate "\n" . map mkNewlines) pieces-  where-    pieces = unfoldr unfolder (lines str)--    unfolder :: [String] -> Maybe ([String], [String])-    unfolder [] = Nothing-    unfolder remaining = Just $-      case break pieceBreak (zip remaining (tail remaining ++ [""])) of-        (nonNull, [])     -> (map fst nonNull, [])-        (nonNull, _:rest) -> (map fst nonNull, map fst rest)--    pieceBreak :: (String, String) -> Bool-    pieceBreak ("", "") = error $ "Two consecutive line breaks in:\n" ++ str-    pieceBreak (line, next) = null line && head next /= ' '--    mkNewlines :: String -> String-    mkNewlines ">" = ""-    mkNewlines x = x
− test/johan-tibell/expected/1.exp
@@ -1,6 +0,0 @@-getGitProvider :: EventProvider GitRecord ()-getGitProvider = -    EventProvider-    { getModuleName = "Git"-    , getEvents = getRepoCommits-    }
− test/johan-tibell/expected/2.exp
@@ -1,6 +0,0 @@-strToMonth :: String -> Int-strToMonth month = -    case month of-        "Jan" -> 1-        "Feb" -> 2-        _ -> error $ "Unknown month " ++ month
− test/johan-tibell/expected/3.exp
@@ -1,6 +0,0 @@-sayHello :: IO ()-sayHello = do-    name <- getLine-    putStrLn $ greeting name-  where-    greeting name = "Hello, " ++ name ++ "!"
− test/johan-tibell/expected/4.exp
@@ -1,7 +0,0 @@-commitToEvent :: FolderPath -> TimeZone -> Commit -> Event.Event-commitToEvent gitFolderPath timezone commit = -    Event.Event-    { pluginName = getModuleName getGitProvider-    , eventIcon = "glyphicon-cog"-    , eventDate = localTimeToUTC timezone (commitDate commit)-    }
− test/johan-tibell/expected/5.exp
@@ -1,9 +0,0 @@-fun-    :: (Class a, Class b)-    => a -> b -> c--fun :: (a, b, c) -> (a, b)--fun-    :: (Class a, Class b)-    => a -> (# d, e #) -> c
− test/johan-tibell/expected/6.exp
@@ -1,21 +0,0 @@-f :: Int-f x-  | x <- Just x-  , x <- Just x = -      case x of-          Just x -> e-  | otherwise = do-      e-  where-    x = y--g x = -    case x of-        a -> x-  where-    foo = -        case x of-            _ -> do-                launchMissiles-      where-        y = 2
− test/johan-tibell/expected/7.exp
@@ -1,8 +0,0 @@-g x = -    let x = 1-    in x-  where-    foo = -        let y = 2-            z = 3-        in y
− test/johan-tibell/tests/1.test
@@ -1,6 +0,0 @@-getGitProvider :: EventProvider GitRecord ()-getGitProvider = EventProvider-    {-        getModuleName = "Git",-        getEvents = getRepoCommits-    }
− test/johan-tibell/tests/2.test
@@ -1,5 +0,0 @@-strToMonth :: String -> Int-strToMonth month = case month of-    "Jan" -> 1-    "Feb" -> 2-    _ -> error $ "Unknown month " ++ month
− test/johan-tibell/tests/3.test
@@ -1,6 +0,0 @@-sayHello :: IO ()-sayHello = do-    name <- getLine-    putStrLn $ greeting name-    where-        greeting name = "Hello, " ++ name ++ "!"
− test/johan-tibell/tests/4.test
@@ -1,7 +0,0 @@-commitToEvent :: FolderPath -> TimeZone -> Commit -> Event.Event-commitToEvent gitFolderPath timezone commit = Event.Event-    {-        pluginName = getModuleName getGitProvider,-        eventIcon = "glyphicon-cog",-        eventDate = localTimeToUTC timezone (commitDate commit)-    }
− test/johan-tibell/tests/5.test
@@ -1,7 +0,0 @@-fun :: (Class a,Class b)-    => a -> b -> c--fun :: (a,b,c) -> (a,b)--fun :: (Class a, Class b)-    => a ->(# d,e #)-> c
− test/johan-tibell/tests/6.test
@@ -1,15 +0,0 @@-f :: Int-f x | x <- Just x-    , x <- Just x = case x of-         Just x -> e-  | otherwise = do-    e-  where-    x = y--g x = case x of a -> x-  where-    foo = case x of-        _ -> do launchMissiles-      where-        y = 2
− test/johan-tibell/tests/7.test
@@ -1,3 +0,0 @@-g x = let x = 1 in x-  where-    foo = let y = 2; z = 3 in y