hindent 3.9.1 → 4.0
raw patch · 11 files changed
+755/−314 lines, 11 filesdep ~haskell-src-extsnew-component:exe:hindent-generate-testsPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: haskell-src-exts
API changes (from Hackage documentation)
- HIndent.Pretty: instance Pretty GuardedAlt
- HIndent.Pretty: instance Pretty GuardedAlts
- HIndent.Pretty: instance Pretty IfAlt
- HIndent.Types: comInfoOwnLine :: ComInfo -> !Bool
+ HIndent.Pretty: getLineNum :: MonadState PrintState m => m Int64
+ HIndent.Pretty: instance Pretty ExportSpec
+ HIndent.Pretty: instance Pretty ExportSpecList
+ HIndent.Pretty: instance Pretty InstRule
+ HIndent.Pretty: instance Pretty Overlap
+ HIndent.Pretty: instance Pretty Sign
+ HIndent.Pretty: instance Pretty WarningText
+ HIndent.Pretty: printComments :: (Pretty ast, MonadState PrintState m) => ComInfoLocation -> ast NodeInfo -> m ()
+ HIndent.Pretty: rhsSeparator :: MonadState PrintState m => m ()
+ HIndent.Pretty: withCaseContext :: MonadState PrintState m => Bool -> m a -> m a
+ HIndent.Styles.ChrisDone: State :: State
+ HIndent.Styles.ChrisDone: contextualGuardedRhs :: s -> GuardedRhs NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: data State
+ HIndent.Styles.ChrisDone: decl :: t -> Decl NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: dependOrNewline :: Printer () -> Exp NodeInfo -> (Exp NodeInfo -> Printer ()) -> Printer ()
+ HIndent.Styles.ChrisDone: exp :: s -> Exp NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: fieldupdate :: t -> FieldUpdate NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: guardedalt :: s -> GuardedRhs NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: guardedrhs :: s -> GuardedRhs NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: infixApp :: (Pretty ast, Pretty ast1, Pretty ast2) => Exp NodeInfo -> ast NodeInfo -> ast1 NodeInfo -> ast2 NodeInfo -> Maybe Int64 -> Printer ()
+ HIndent.Styles.ChrisDone: isFlat :: Exp NodeInfo -> Bool
+ HIndent.Styles.ChrisDone: isOverflow :: Printer a -> Printer Bool
+ HIndent.Styles.ChrisDone: isOverflowMax :: Printer a -> Printer Bool
+ HIndent.Styles.ChrisDone: isShort :: Pretty ast => ast NodeInfo -> Printer (Bool, PrintState)
+ HIndent.Styles.ChrisDone: isSingleLiner :: MonadState PrintState m => m a -> m Bool
+ HIndent.Styles.ChrisDone: isSmall :: MonadState PrintState m => m a -> m (Bool, PrintState)
+ HIndent.Styles.ChrisDone: multi :: Pretty ast => Int64 -> [ast NodeInfo] -> Bool -> Printer ()
+ HIndent.Styles.ChrisDone: rhs :: s -> Rhs NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: sandboxNonOverflowing :: Pretty ast => [ast NodeInfo] -> Printer ((Bool, Bool), PrintState)
+ HIndent.Styles.ChrisDone: sandboxSingles :: Pretty ast => [ast NodeInfo] -> Printer (Bool, PrintState)
+ HIndent.Styles.ChrisDone: shortName :: Int64
+ HIndent.Styles.ChrisDone: smallColumnLimit :: Int64
+ HIndent.Styles.ChrisDone: stmt :: s -> Stmt NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: unguardedalt :: t -> Rhs NodeInfo -> Printer ()
+ HIndent.Styles.ChrisDone: unguardedrhs :: s -> Rhs NodeInfo -> Printer ()
+ HIndent.Styles.Fundamental: State :: State
+ HIndent.Styles.Fundamental: data State
+ HIndent.Styles.Gibiansky: State :: State
+ HIndent.Styles.Gibiansky: alt :: Extend Alt
+ HIndent.Styles.Gibiansky: appExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: applicativeExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: astStartLine :: Annotated ast => ast NodeInfo -> Int
+ HIndent.Styles.Gibiansky: attemptSingleLine :: Printer a -> Printer a -> Printer a
+ HIndent.Styles.Gibiansky: caseExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: collectTypes :: Type l -> [Type l]
+ HIndent.Styles.Gibiansky: condecls :: Extend ConDecl
+ HIndent.Styles.Gibiansky: context :: Extend Context
+ HIndent.Styles.Gibiansky: data State
+ HIndent.Styles.Gibiansky: decls :: Extend Decl
+ HIndent.Styles.Gibiansky: derivings :: Extend Deriving
+ HIndent.Styles.Gibiansky: doExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: dollarExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: exportList :: Extend ExportSpecList
+ HIndent.Styles.Gibiansky: exprs :: Extend Exp
+ HIndent.Styles.Gibiansky: fieldUpdate :: Extend FieldUpdate
+ HIndent.Styles.Gibiansky: funBody :: [Pat NodeInfo] -> Rhs NodeInfo -> Maybe (Binds NodeInfo) -> Printer ()
+ HIndent.Styles.Gibiansky: guardedRhs :: Extend GuardedRhs
+ HIndent.Styles.Gibiansky: imp :: Extend ImportDecl
+ HIndent.Styles.Gibiansky: indentOnce :: Printer ()
+ HIndent.Styles.Gibiansky: indentSpaces :: Integral a => a
+ HIndent.Styles.Gibiansky: isDoBlock :: Rhs l -> Bool
+ HIndent.Styles.Gibiansky: lambdaExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: letExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: lineDelta :: (Annotated ast1, Annotated ast2) => ast1 NodeInfo -> ast2 NodeInfo -> Int
+ HIndent.Styles.Gibiansky: listExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: maxSingleLineExports :: Integral a => a
+ HIndent.Styles.Gibiansky: moduleHead :: Extend ModuleHead
+ HIndent.Styles.Gibiansky: multiLineList :: [Exp NodeInfo] -> Printer ()
+ HIndent.Styles.Gibiansky: recUpdateExpr :: Printer () -> [FieldUpdate NodeInfo] -> Printer ()
+ HIndent.Styles.Gibiansky: rhss :: Extend Rhs
+ HIndent.Styles.Gibiansky: sameLine :: (Annotated ast, Annotated ast') => ast NodeInfo -> ast' NodeInfo -> Bool
+ HIndent.Styles.Gibiansky: singleLineList :: [Exp NodeInfo] -> Printer ()
+ HIndent.Styles.Gibiansky: typ :: Extend Type
+ HIndent.Styles.Gibiansky: type Extend f = forall t. t -> f NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: writeWhereBinds :: Binds NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: State :: State
+ HIndent.Styles.JohanTibell: conDecl :: t -> ConDecl NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: data State
+ HIndent.Styles.JohanTibell: decl :: t -> Decl NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: exp :: t -> Exp NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: guardedRhs :: t -> GuardedRhs NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: infixApp :: (Pretty ast, Pretty ast1, Pretty ast2) => Exp NodeInfo -> ast NodeInfo -> ast1 NodeInfo -> ast2 NodeInfo -> Maybe Int64 -> Printer ()
+ HIndent.Styles.JohanTibell: isFlat :: Exp NodeInfo -> Printer Bool
+ HIndent.Styles.JohanTibell: isOverflow :: Printer a -> Printer Bool
+ HIndent.Styles.JohanTibell: isRecord :: QualConDecl t -> Bool
+ HIndent.Styles.JohanTibell: isShort :: Pretty ast => ast NodeInfo -> Printer (Bool)
+ HIndent.Styles.JohanTibell: isSingleLiner :: MonadState PrintState m => m a -> m Bool
+ HIndent.Styles.JohanTibell: qualConDecl :: QualConDecl NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: recDecl :: ConDecl NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: rhs :: t -> Rhs NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: shortName :: Int64
+ HIndent.Types: After :: ComInfoLocation
+ HIndent.Types: Before :: ComInfoLocation
+ HIndent.Types: comInfoLocation :: ComInfo -> !(Maybe ComInfoLocation)
+ HIndent.Types: data ComInfoLocation
+ HIndent.Types: instance Data ComInfoLocation
+ HIndent.Types: instance Eq ComInfoLocation
+ HIndent.Types: instance Show ComInfoLocation
+ HIndent.Types: instance Typeable ComInfoLocation
+ HIndent.Types: psInsideCase :: PrintState -> !Bool
- HIndent.Pretty: braces :: Printer a -> Printer a
+ HIndent.Pretty: braces :: MonadState PrintState m => m a -> m a
- HIndent.Pretty: brackets :: Printer a -> Printer a
+ HIndent.Pretty: brackets :: MonadState PrintState m => m a -> m a
- HIndent.Pretty: class (Annotated ast, Typeable1 ast) => Pretty ast
+ HIndent.Pretty: class (Annotated ast, Typeable ast) => Pretty ast
- HIndent.Pretty: column :: Int64 -> Printer a -> Printer a
+ HIndent.Pretty: column :: MonadState PrintState m => Int64 -> m a -> m a
- HIndent.Pretty: comma :: Printer ()
+ HIndent.Pretty: comma :: MonadState PrintState m => m ()
- HIndent.Pretty: commas :: [Printer ()] -> Printer ()
+ HIndent.Pretty: commas :: MonadState PrintState m => [m ()] -> m ()
- HIndent.Pretty: depend :: Printer () -> Printer b -> Printer b
+ HIndent.Pretty: depend :: MonadState PrintState m => m () -> m b -> m b
- HIndent.Pretty: dependBind :: Printer a -> (a -> Printer b) -> Printer b
+ HIndent.Pretty: dependBind :: MonadState PrintState m => m a -> (a -> m b) -> m b
- HIndent.Pretty: getColumn :: Printer Int64
+ HIndent.Pretty: getColumn :: MonadState PrintState m => m Int64
- HIndent.Pretty: getColumnLimit :: Printer Int64
+ HIndent.Pretty: getColumnLimit :: MonadState PrintState m => m Int64
- HIndent.Pretty: getIndentSpaces :: Printer Int64
+ HIndent.Pretty: getIndentSpaces :: MonadState PrintState m => m Int64
- HIndent.Pretty: indented :: Int64 -> Printer a -> Printer a
+ HIndent.Pretty: indented :: MonadState PrintState m => Int64 -> m a -> m a
- HIndent.Pretty: int :: Integral n => n -> Printer ()
+ HIndent.Pretty: int :: (Integral n, MonadState PrintState m) => n -> m ()
- HIndent.Pretty: inter :: Printer () -> [Printer ()] -> Printer ()
+ HIndent.Pretty: inter :: MonadState PrintState m => m () -> [m ()] -> m ()
- HIndent.Pretty: lined :: [Printer ()] -> Printer ()
+ HIndent.Pretty: lined :: MonadState PrintState m => [m ()] -> m ()
- HIndent.Pretty: maybeCtx :: Maybe (Context NodeInfo) -> Printer ()
+ HIndent.Pretty: maybeCtx :: MonadState PrintState m => Maybe (Context NodeInfo) -> m ()
- HIndent.Pretty: newline :: Printer ()
+ HIndent.Pretty: newline :: MonadState PrintState m => m ()
- HIndent.Pretty: parens :: Printer a -> Printer a
+ HIndent.Pretty: parens :: MonadState PrintState m => m a -> m a
- HIndent.Pretty: prefixedLined :: Text -> [Printer ()] -> Printer ()
+ HIndent.Pretty: prefixedLined :: MonadState PrintState m => Text -> [m ()] -> m ()
- HIndent.Pretty: pretty :: Pretty ast => ast NodeInfo -> Printer ()
+ HIndent.Pretty: pretty :: (Pretty ast, MonadState PrintState m) => ast NodeInfo -> m ()
- HIndent.Pretty: pretty' :: (Pretty ast, Pretty (ast SrcSpanInfo), Functor ast) => ast NodeInfo -> Printer ()
+ HIndent.Pretty: pretty' :: (Pretty ast, Pretty (ast SrcSpanInfo), Functor ast, MonadState PrintState m) => ast NodeInfo -> m ()
- HIndent.Pretty: prettyNoExt :: Pretty ast => ast NodeInfo -> Printer ()
+ HIndent.Pretty: prettyNoExt :: (Pretty ast, MonadState PrintState m) => ast NodeInfo -> m ()
- HIndent.Pretty: printComment :: Maybe SrcSpan -> ComInfo -> Printer ()
+ HIndent.Pretty: printComment :: MonadState PrintState m => Maybe SrcSpan -> ComInfo -> m ()
- HIndent.Pretty: space :: Printer ()
+ HIndent.Pretty: space :: MonadState PrintState m => m ()
- HIndent.Pretty: spaced :: [Printer ()] -> Printer ()
+ HIndent.Pretty: spaced :: MonadState PrintState m => [m ()] -> m ()
- HIndent.Pretty: string :: String -> Printer ()
+ HIndent.Pretty: string :: MonadState PrintState m => String -> m ()
- HIndent.Pretty: swing :: Printer () -> Printer b -> Printer b
+ HIndent.Pretty: swing :: MonadState PrintState m => m () -> m b -> m b
- HIndent.Pretty: write :: Builder -> Printer ()
+ HIndent.Pretty: write :: MonadState PrintState m => Builder -> m ()
- HIndent.Types: ComInfo :: !Comment -> !Bool -> ComInfo
+ HIndent.Types: ComInfo :: !Comment -> !(Maybe ComInfoLocation) -> ComInfo
- HIndent.Types: PrintState :: !Int64 -> !Builder -> !Bool -> !Int64 -> !Int64 -> !s -> ![Extender s] -> !Config -> !Bool -> PrintState
+ HIndent.Types: PrintState :: !Int64 -> !Builder -> !Bool -> !Int64 -> !Int64 -> !s -> ![Extender s] -> !Config -> !Bool -> !Bool -> PrintState
Files
- hindent.cabal +14/−5
- src/HIndent.hs +72/−39
- src/HIndent/Pretty.hs +200/−128
- src/HIndent/Styles/ChrisDone.hs +49/−33
- src/HIndent/Styles/Fundamental.hs +1/−3
- src/HIndent/Styles/Gibiansky.hs +288/−39
- src/HIndent/Styles/JohanTibell.hs +7/−55
- src/HIndent/Types.hs +13/−7
- src/main/TestGenerate.hs +89/−0
- test/Spec.hs +11/−3
- vim/hindent.vim +11/−2
hindent.cabal view
@@ -1,5 +1,5 @@ name: hindent-version: 3.9.1+version: 4.0 synopsis: Extensible Haskell pretty printer description: Extensible Haskell pretty printer. Both a library and an executable. .@@ -27,7 +27,7 @@ HIndent.Styles.Gibiansky build-depends: base >= 4 && <5 , data-default- , haskell-src-exts == 1.15.*+ , haskell-src-exts == 1.16.* , monad-loops , mtl , text@@ -36,18 +36,27 @@ hs-source-dirs: src/main ghc-options: -Wall -O2 main-is: Main.hs- build-depends: base >= 4.7 && < 5+ build-depends: base >= 4 && < 5 , hindent , text +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 type: exitcode-stdio-1.0 hs-source-dirs: test main-is: Spec.hs- build-depends: base >= 4.7 && <5+ build-depends: base >= 4 && <5 , hindent , data-default- , haskell-src-exts == 1.15.*+ , haskell-src-exts == 1.16.* , monad-loops , mtl , text
src/HIndent.hs view
@@ -47,9 +47,9 @@ reformat style x = case parseModuleWithComments parseMode (T.unpack x) of- ParseOk (mod,comments) ->+ ParseOk (m,comments) -> let (cs,ast) =- annotateComments (fromMaybe mod $ applyFixities baseFixities mod) comments+ annotateComments (fromMaybe m $ applyFixities baseFixities m) comments in Right (prettyPrint style -- For the time being, assume that all "free-floating" comments come at the beginning.@@ -65,7 +65,7 @@ psOutput (execState (runPrinter m) (case style of Style _name _author _desc st extenders config ->- PrintState 0 mempty False 0 1 st extenders config False))+ PrintState 0 mempty False 0 1 st extenders config False False)) -- | Parse mode, includes all extensions, doesn't assume any fixities. parseMode :: ParseMode@@ -97,8 +97,8 @@ testAst x = case parseModuleWithComments parseMode (T.unpack x) of- ParseOk (mod,comments) ->- Right (annotateComments mod comments)+ ParseOk (m,comments) ->+ Right (annotateComments m comments) ParseFailed _ e -> Left e -- | Styles list, useful for programmatically choosing.@@ -109,45 +109,73 @@ -- | Annotate the AST with comments. annotateComments :: forall ast. (Data (ast NodeInfo),Traversable ast,Annotated ast) => ast SrcSpanInfo -> [Comment] -> ([ComInfo],ast NodeInfo)-annotateComments =- -- Add all comments to the ast.- foldr processComment .- -- Turn result into a tuple, with ast as second element.- ([],) .- -- Replace source spans with node infos in the AST.- -- The node infos have empty comment lists.- fmap (\n -> NodeInfo n [])+annotateComments src comments =+ let+ -- Make sure to process comments top to bottom.+ reversed = reverse comments++ -- Replace source spans with node infos in the AST.+ src' = fmap (\n -> NodeInfo n []) src++ -- Add all comments to the ast.+ (cominfos, src'') = foldr processComment ([], src') reversed++ in -- Reverse order of comments at each node.+ (cominfos, fmap (\(NodeInfo n cs) -> NodeInfo n $ reverse cs) src'')+ where processComment :: Comment -> ([ComInfo],ast NodeInfo) -> ([ComInfo],ast NodeInfo) -- Add in a single comment to the ast. processComment c@(Comment _ cspan _) (cs,ast) = -- Try to find the node after which this comment lies.- case execState (traverse (collect c) ast) Nothing of+ case execState (traverse (collect After c) ast) Nothing of -- When no node is found, the comment is on its own line.- Nothing ->- (ComInfo c True :- cs- ,ast)+ Nothing -> (ComInfo c Nothing : cs, ast)+ -- We found the node that this comment follows.- -- Insert this comment into the ast.- Just l ->- let ownLine =- srcSpanStartLine cspan /=- srcSpanEndLine (srcInfoSpan l)- in (cs- ,evalState (traverse (insert l (ComInfo c ownLine)) ast) False)+ -- Check whether the node is on the same line.+ Just (NodeInfo l coms)+ -- If it's on a different line than the node, but the node has an+ -- EOL comment, and the EOL comment and this comment are aligned,+ -- attach this comment to the preceding node.+ | ownLine && alignedWithPrevious -> insertedBefore++ -- If it's on a different line than the node, look for the following node to attach it to.+ | ownLine ->+ case execState (traverse (collect Before c) ast) Nothing of+ -- If we don't find a node after the comment, leave it with the previous node.+ Nothing -> insertedBefore+ Just (NodeInfo node _) ->+ (cs, evalState (traverse (insert node (ComInfo c $ Just Before)) ast) False)++ -- If it's on the same line, insert this comment into that node.+ | otherwise -> insertedBefore+ where+ ownLine = srcSpanStartLine cspan /= srcSpanEndLine (srcInfoSpan l)+ insertedBefore = (cs, evalState (traverse (insert l (ComInfo c $ Just After)) ast) False)+ alignedWithPrevious+ | null coms = False+ | otherwise = case last coms of+ -- Require single line comment after the node.+ ComInfo (Comment False prevSpan _) (Just After) ->+ srcSpanStartLine prevSpan == srcSpanStartLine cspan - 1 &&+ srcSpanStartColumn prevSpan == srcSpanStartColumn cspan+ _ -> False+ -- For a comment, check whether the comment is after the node. -- If it is, store it in the state; otherwise do nothing.- collect :: Comment -> NodeInfo -> State (Maybe SrcSpanInfo) NodeInfo- collect c ni@(NodeInfo newL _) =- do when (commentAfter ni c)- (modify (maybe (Just newL)- (\oldL ->- Just (if (spanBefore `on` srcInfoSpan) oldL newL- then newL- else oldL))))+ -- The location specifies where the comment should lie relative to the node.+ collect :: ComInfoLocation -> Comment -> NodeInfo -> State (Maybe NodeInfo) NodeInfo+ collect loc' c ni@(NodeInfo newL _) =+ do when (commentLocated loc' ni c)+ (modify (maybe (Just ni)+ (\oldni@(NodeInfo oldL _) ->+ Just (if (spanTest loc' `on` srcInfoSpan) oldL newL+ then ni+ else oldni)))) return ni+ -- Insert the comment into the ast. Find the right node and add it to the -- comments of that node. Do nothing afterwards. insert :: SrcSpanInfo -> ComInfo -> NodeInfo -> State Bool NodeInfo@@ -159,13 +187,18 @@ else return ni -- | Is the comment after the node?-commentAfter :: NodeInfo -> Comment -> Bool-commentAfter (NodeInfo (SrcSpanInfo n _) _) (Comment _ c _) =- spanBefore n c+commentLocated :: ComInfoLocation -> NodeInfo -> Comment -> Bool+commentLocated loc' (NodeInfo (SrcSpanInfo n _) _) (Comment _ c _) =+ spanTest loc' n c --- | Does the first span end before the second starts?-spanBefore :: SrcSpan -> SrcSpan -> Bool-spanBefore before after =+-- | For @After@, does the first span end before the second starts?+-- For @Before@, does the first span start after the second ends?+spanTest :: ComInfoLocation -> SrcSpan -> SrcSpan -> Bool+spanTest loc' first second = (srcSpanStartLine after > srcSpanEndLine before) || ((srcSpanStartLine after == srcSpanEndLine before) && (srcSpanStartColumn after > srcSpanEndColumn before))+ where (before,after) =+ case loc' of+ After -> (first,second)+ Before -> (second,first)
src/HIndent/Pretty.hs view
@@ -23,6 +23,9 @@ -- * Common node types , maybeCtx , printComment+ , printComments+ , withCaseContext+ , rhsSeparator -- * Interspersing , inter , spaced@@ -37,6 +40,7 @@ , indented , column , getColumn+ , getLineNum , depend , dependBind , swing@@ -54,7 +58,7 @@ import HIndent.Types import Language.Haskell.Exts.Comments-import Control.Monad.State hiding (state)+import Control.Monad.State.Strict hiding (state) import Data.Int import Data.List import Data.Maybe@@ -75,20 +79,23 @@ -- * Pretty printing class -- | Pretty printing class.-class (Annotated ast,Typeable1 ast) => Pretty ast where- prettyInternal :: ast NodeInfo -> Printer ()+class (Annotated ast,Typeable ast) => Pretty ast where+ prettyInternal :: MonadState PrintState m => ast NodeInfo -> m () -- | Pretty print using extenders.-pretty :: (Pretty ast)- => ast NodeInfo -> Printer ()+pretty :: (Pretty ast,MonadState PrintState m)+ => ast NodeInfo -> m () pretty a = do st <- get case st of PrintState{psExtenders = es,psUserState = s} ->- do case listToMaybe (mapMaybe (makePrinter s) es) of- Just m -> m- Nothing -> prettyNoExt a- printComments a+ do+ printComments Before a+ depend+ (case listToMaybe (mapMaybe (makePrinter s) es) of+ Just (Printer m) -> modify (execState m)+ Nothing -> prettyNoExt a)+ (printComments After a) where makePrinter s (Extender f) = case cast a of Just v -> Just (f s v)@@ -98,23 +105,28 @@ -- | 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)- => ast NodeInfo -> Printer ()+prettyNoExt :: (Pretty ast,MonadState PrintState m)+ => ast NodeInfo -> m () prettyNoExt = prettyInternal -- | Print comments of a node.-printComments :: (Pretty ast)- => ast NodeInfo -> Printer ()-printComments ast =- mapM_ (printComment (Just (srcInfoSpan (nodeInfoSpan info)))) comments+printComments :: (Pretty ast,MonadState PrintState m)+ => ComInfoLocation -> ast NodeInfo -> m ()+printComments loc' ast =+ forM_ comments $ \comment ->+ when (comInfoLocation comment == Just loc') $ 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 comments = nodeInfoComments info -- | Pretty print a comment.-printComment :: Maybe SrcSpan -> ComInfo -> Printer ()-printComment mayNodespan (ComInfo (Comment inline cspan str) own) =- do when own newline- -- Insert proper amount of space before comment.+printComment :: MonadState PrintState m => Maybe SrcSpan -> ComInfo -> m ()+printComment mayNodespan (ComInfo (Comment inline cspan str) _) =+ do -- Insert proper amount of space before comment. -- This maintains alignment. This cannot force comments -- to go before the left-most possible indent (specified by depends). case mayNodespan of@@ -134,15 +146,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)- => ast NodeInfo -> Printer ()+pretty' :: (Pretty ast,P.Pretty (ast SrcSpanInfo),Functor ast,MonadState PrintState m)+ => ast NodeInfo -> m () pretty' = write . T.fromText . T.pack . P.prettyPrint . fmap nodeInfoSpan -------------------------------------------------------------------------------- -- * Combinators -- | Increase indentation level by n spaces for the given printer.-indented :: Int64 -> Printer a -> Printer a+indented :: MonadState PrintState m => Int64 -> m a -> m a indented i p = do level <- gets psIndentLevel modify (\s -> s {psIndentLevel = level + i})@@ -151,15 +163,15 @@ return m -- | Print all the printers separated by spaces.-spaced :: [Printer ()] -> Printer ()+spaced :: MonadState PrintState m => [m ()] -> m () spaced = inter space -- | Print all the printers separated by commas.-commas :: [Printer ()] -> Printer ()+commas :: MonadState PrintState m => [m ()] -> m () commas = inter comma -- | Print all the printers separated by sep.-inter :: Printer () -> [Printer ()] -> Printer ()+inter :: MonadState PrintState m => m () -> [m ()] -> m () inter sep ps = foldr (\(i,p) next -> depend (do p@@ -171,12 +183,12 @@ (zip [1 ..] ps) -- | Print all the printers separated by newlines.-lined :: [Printer ()] -> Printer ()+lined :: MonadState PrintState m => [m ()] -> m () lined ps = sequence_ (intersperse newline ps) -- | Print all the printers separated newlines and optionally a line -- prefix.-prefixedLined :: Text -> [Printer ()] -> Printer ()+prefixedLined :: MonadState PrintState m => Text -> [m ()] -> m () prefixedLined pref ps' = case ps' of [] -> return ()@@ -192,7 +204,7 @@ -- | Set the (newline-) indent level to the given column for the given -- printer.-column :: Int64 -> Printer a -> Printer a+column :: MonadState PrintState m => Int64 -> m a -> m a column i p = do level <- gets psIndentLevel modify (\s -> s {psIndentLevel = i})@@ -201,18 +213,41 @@ return m -- | Get the current indent level.-getColumn :: Printer Int64+getColumn :: MonadState PrintState m => m Int64 getColumn = gets psColumn +-- | Get the current line number.+getLineNum :: MonadState PrintState m => m Int64+getLineNum = gets psLine+ -- | Output a newline.-newline :: Printer ()+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 m+ => Bool -> m a -> m a+withCaseContext bool pr =+ do original <- gets psInsideCase+ modify (\s -> s {psInsideCase = bool})+ result <- pr+ modify (\s -> s {psInsideCase = original})+ return result++-- | Get the current RHS separator, either = or -> .+rhsSeparator :: MonadState PrintState m+ => m ()+rhsSeparator =+ do inCase <- gets psInsideCase+ if inCase+ then write "->"+ else write "="+ -- | Make the latter's indentation depend upon the end column of the -- former.-depend :: Printer () -> Printer b -> Printer b+depend :: MonadState PrintState m => m () -> m b -> m b depend maker dependent = do state' <- get maker@@ -224,7 +259,7 @@ -- | Make the latter's indentation depend upon the end column of the -- former.-dependBind :: Printer a -> (a -> Printer b) -> Printer b+dependBind :: MonadState PrintState m => m a -> (a -> m b) -> m b dependBind maker dependent = do state' <- get v <- maker@@ -235,7 +270,7 @@ else (dependent v) -- | Wrap in parens.-parens :: Printer a -> Printer a+parens :: MonadState PrintState m => m a -> m a parens p = depend (write "(") (do v <- p@@ -243,7 +278,7 @@ return v) -- | Wrap in braces.-braces :: Printer a -> Printer a+braces :: MonadState PrintState m => m a -> m a braces p = depend (write "{") (do v <- p@@ -251,7 +286,7 @@ return v) -- | Wrap in brackets.-brackets :: Printer a -> Printer a+brackets :: MonadState PrintState m => m a -> m a brackets p = depend (write "[") (do v <- p@@ -259,20 +294,20 @@ return v) -- | Write a space.-space :: Printer ()+space :: MonadState PrintState m => m () space = write " " -- | Write a comma.-comma :: Printer ()+comma :: MonadState PrintState m => m () comma = write "," -- | Write an integral.-int :: Integral n- => n -> Printer ()+int :: (Integral n, MonadState PrintState m)+ => n -> m () int = write . decimal -- | Write out a string, updating the current position information.-write :: Builder -> Printer ()+write :: MonadState PrintState m => Builder -> m () write x = do eol <- gets psEolComment when (eol && x /= "\n") newline@@ -304,16 +339,16 @@ LT.length (LT.filter (== '\n') x') -- | Write a string.-string :: String -> Printer ()+string :: MonadState PrintState m =>String -> m () string = write . T.fromText . T.pack -- | Indent spaces, e.g. 2.-getIndentSpaces :: Printer Int64+getIndentSpaces :: MonadState PrintState m => m Int64 getIndentSpaces = gets (configIndentSpaces . psConfig) -- | Column limit, e.g. 80-getColumnLimit :: Printer Int64+getColumnLimit :: MonadState PrintState m => m Int64 getColumnLimit = gets (configMaxColumns . psConfig) @@ -334,15 +369,23 @@ nullBinds (IPBinds _ x) = null x -- | Maybe render a class context.-maybeCtx :: Maybe (Context NodeInfo) -> Printer ()+maybeCtx :: MonadState PrintState m => Maybe (Context NodeInfo) -> m () maybeCtx = maybe (return ()) (\p -> pretty p >> write " => ") +-- | Maybe render an overlap definition.+maybeOverlap :: MonadState PrintState m => Maybe (Overlap NodeInfo) -> m ()+maybeOverlap =+ maybe (return ())+ (\p ->+ pretty p >>+ space)+ -- | Swing the second printer below and indented with respect to the first.-swing :: Printer () -> Printer b -> Printer b+swing :: MonadState PrintState m => m () -> m b -> m b swing a b = do orig <- gets psIndentLevel a@@ -359,16 +402,12 @@ CxSingle _ a -> pretty a CxTuple _ as -> parens (commas (map pretty as))- CxParen _ c -> parens (pretty c) CxEmpty _ -> parens (return ()) instance Pretty Pat where prettyInternal x = case x of- PLit _ l -> pretty l- PNeg _ l ->- depend (write "-")- (pretty l)+ PLit _ sign l -> pretty sign >> pretty l PNPlusK _ n k -> depend (do pretty n write "+")@@ -436,7 +475,7 @@ PVar{} -> pretty' x -- | Pretty print a name for being an infix operator.-prettyInfixOp :: QName NodeInfo -> Printer ()+prettyInfixOp :: MonadState PrintState m => QName NodeInfo -> m () prettyInfixOp x = case x of Qual{} -> pretty' x@@ -471,6 +510,10 @@ 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@@ -485,14 +528,23 @@ parens (do pretty ty write " :: " pretty k)+ TyBang _ bangty right ->+ do pretty bangty+ pretty right+ TyEquals _ left right ->+ do pretty left+ write " == "+ pretty right TyPromoted{} -> error "FIXME: No implementation for TyPromoted."+ TySplice{} ->+ error "FIXME: No implementation for TySplice." instance Pretty Exp where prettyInternal = exp -- | Render an expression.-exp :: Exp NodeInfo -> Printer ()+exp :: MonadState PrintState m => Exp NodeInfo -> m () exp (InfixApp _ a op b) = depend (do pretty a space@@ -539,7 +591,7 @@ write " of") newline indentSpaces <- getIndentSpaces- indented indentSpaces (lined (map pretty alts))+ indented indentSpaces (lined (map (withCaseContext True . pretty) alts)) exp (Do _ stmts) = depend (write "do ") (lined (map pretty stmts))@@ -662,15 +714,13 @@ exp x@RightArrApp{} = pretty' x exp x@LeftArrHighApp{} = pretty' x exp x@RightArrHighApp{} = pretty' x+exp x@ParArray{} = pretty' x+exp x@ParArrayFromTo{} = pretty' x+exp x@ParArrayFromThenTo{} = pretty' x+exp x@ParArrayComp{} = pretty' x exp ParComp{} = error "FIXME: No implementation for ParComp." -instance Pretty IfAlt where- prettyInternal (IfAlt _ cond body) =- do pretty cond- swing (write " -> ")- (pretty body)- instance Pretty Stmt where prettyInternal x = case x of@@ -704,26 +754,22 @@ prettyInternal = decl -- | Render a declaration.-decl :: Decl NodeInfo -> Printer ()-decl (PatBind _ pat mty rhs mbinds) =- case mty of- Just e ->- error ("Unimplemented (Maybe Type) in PatBind." ++ show e)- Nothing ->- do pretty pat- pretty rhs- indentSpaces <- getIndentSpaces- case mbinds of- Nothing -> return ()- Just binds ->- do newline- indented indentSpaces- (depend (write "where ")- (pretty binds))-decl (InstDecl _ ctx dhead decls) =+decl :: MonadState PrintState m => Decl NodeInfo -> m ()+decl (PatBind _ pat rhs mbinds) =+ do pretty pat+ withCaseContext False (pretty rhs)+ indentSpaces <- getIndentSpaces+ case mbinds of+ Nothing -> return ()+ Just binds ->+ do newline+ indented indentSpaces+ (depend (write "where ")+ (pretty binds))+decl (InstDecl _ moverlap dhead decls) = do indentSpaces <- getIndentSpaces depend (write "instance ")- (depend (maybeCtx ctx)+ (depend (maybeOverlap moverlap) (depend (pretty dhead) (unless (null (fromMaybe [] decls)) (write " where"))))@@ -752,8 +798,12 @@ (do newline indentSpaces <- getIndentSpaces indented indentSpaces (lined (map pretty (fromMaybe [] decls))))-decl TypeDecl{} =- error "FIXME: No implementation for TypeDecl."+decl (TypeDecl _ typehead typ) =+ depend (write "type ")+ (depend (pretty typehead)+ (depend (write " = ")+ (pretty typ)))+ decl TypeFamDecl{} = error "FIXME: No implementation for TypeFamDecl." decl (DataDecl _ dataornew ctx dhead condecls mderivs) =@@ -814,7 +864,10 @@ error "FIXME: No implementation for SpecInlineSig." decl InstSig{} = error "FIXME: No implementation for InstSig."+decl ClosedTypeFamDecl{} =+ error "FIXME: No implementation for ClosedTypeFamDecl." decl x@WarnPragmaDecl{} = pretty' x+decl x@MinimalPragma{} = pretty' x decl x@AnnPragma{} = pretty' x decl x@InfixDecl{} = pretty' x decl x@DefaultDecl{} = pretty' x@@ -854,17 +907,14 @@ do pretty a write " ~ " pretty b+ ParenA _ asst -> parens $ pretty asst+ VarA _ var -> pretty var instance Pretty BangType where prettyInternal x = case x of- BangedTy _ ty ->- depend (write "!")- (pretty ty)- UnBangedTy _ ty -> pretty ty- UnpackedTy _ ty ->- depend (write "{-# UNPACK #-} !")- (pretty ty)+ BangedTy _ -> write "!"+ UnpackedTy _ -> write "{-# UNPACK #-} !" instance Pretty Binds where prettyInternal x =@@ -899,6 +949,11 @@ pretty this write " = " pretty that+ ClsDefSig _ name ty ->+ do write "default "+ pretty name+ write " :: "+ pretty ty instance Pretty ConDecl where prettyInternal x =@@ -933,34 +988,6 @@ FieldPun _ n -> pretty n FieldWildcard _ -> write ".." -instance Pretty GuardedAlts where- prettyInternal x =- case x of- UnGuardedAlt _ e ->- swing (write " -> ")- (pretty e)- GuardedAlts _ gas ->- do newline- indented 2- (lined (map (\p ->- do write "|"- pretty p)- gas))--instance Pretty GuardedAlt where- prettyInternal x =- case x of- GuardedAlt _ stmts e ->- do indented 1- (do (prefixedLined- ","- (map (\p ->- do space- pretty p)- stmts)))- swing (write " -> ")- (pretty e)- instance Pretty GuardedRhs where prettyInternal x = case x of@@ -972,7 +999,7 @@ do space pretty p) stmts))- swing (write " = ")+ swing (write " " >> rhsSeparator >> write " ") (pretty e) instance Pretty InstDecl where@@ -993,7 +1020,7 @@ do depend (do pretty name space) (spaced (map pretty pats))- pretty rhs+ withCaseContext False (pretty rhs) case mbinds of Nothing -> return () Just binds ->@@ -1011,7 +1038,7 @@ Symbol _ s -> string s) (do space spaced (map pretty pats))- pretty rhs+ withCaseContext False (pretty rhs) case mbinds of Nothing -> return () Just binds ->@@ -1045,8 +1072,8 @@ instance Pretty Rhs where prettyInternal x = case x of- UnGuardedRhs _ e ->- (swing (write " = ")+ UnGuardedRhs _ e -> do+ (swing (write " " >> rhsSeparator >> write " ") (pretty e)) GuardedRhss _ gas -> do newline@@ -1066,23 +1093,48 @@ depend (write "$") (parens (pretty e)) +instance Pretty InstRule where+ prettyInternal (IParen _ rule) = parens $ pretty rule+ prettyInternal (IRule _ mvarbinds mctx ihead) =+ do case mvarbinds of+ Nothing -> return ()+ Just xs -> spaced (map pretty xs)+ depend (maybeCtx mctx)+ (pretty ihead)++ instance Pretty InstHead where prettyInternal x = case x of- IHead _ name tys ->- spaced (pretty name :- map pretty tys)- IHInfix l a o b -> pretty (IHead l o [a,b])+ -- Base cases+ IHCon _ name -> pretty name+ IHInfix _ typ name ->+ depend (pretty typ)+ (do space+ prettyInfixOp name)+ -- Recursive application+ IHApp _ ihead typ ->+ depend (pretty ihead)+ (do space+ pretty typ)+ -- Wrapping in parens IHParen _ h -> parens (pretty h) instance Pretty DeclHead where prettyInternal x = case x of- DHead _ name tys ->- spaced (pretty name :- map pretty tys)- DHInfix l a o b -> pretty (DHead l o [a,b])+ DHead _ name -> pretty name DHParen _ h -> parens (pretty h)+ DHInfix _ var name ->+ do pretty var+ space+ write "`"+ pretty name+ write "`"+ DHApp _ dhead var ->+ depend (pretty dhead)+ (do space+ pretty var) instance Pretty SpecialCon where prettyInternal s =@@ -1101,6 +1153,15 @@ Cons _ -> write ":" UnboxedSingleCon _ -> write "(##)" +instance Pretty Overlap where+ prettyInternal (Overlap _) = write "{-# OVERLAP #-}"+ prettyInternal (NoOverlap _) = write "{-# NO_OVERLAP #-}"+ prettyInternal (Incoherent _) = write "{-# INCOHERENT #-}"++instance Pretty Sign where+ prettyInternal (Signless _) = return ()+ prettyInternal (Negative _) = write "-"+ -------------------------------------------------------------------------------- -- * Unimplemented or incomplete printers @@ -1110,7 +1171,9 @@ Module _ mayModHead pragmas imps decls -> do case mayModHead of Nothing -> return ()- Just modHead -> pretty' modHead+ Just modHead -> do+ pretty modHead+ unless (null pragmas && null imps && null decls) $ newline inter newline (map pretty pragmas) inter newline (map pretty imps) inter newline (map pretty decls)@@ -1183,4 +1246,13 @@ prettyInternal = pretty' instance Pretty ImportSpec where+ prettyInternal = pretty'++instance Pretty WarningText where+ prettyInternal = pretty'++instance Pretty ExportSpecList where+ prettyInternal = pretty'++instance Pretty ExportSpec where prettyInternal = pretty'
src/HIndent/Styles/ChrisDone.hs view
@@ -5,9 +5,7 @@ -- -- Documented here: <https://github.com/chrisdone/haskell-style-guide> -module HIndent.Styles.ChrisDone- (chrisDone)- where+module HIndent.Styles.ChrisDone where import HIndent.Pretty import HIndent.Types@@ -31,7 +29,8 @@ smallColumnLimit = 50 -- | Empty state.-data State = State+data State =+ State -- | The printer style. chrisDone :: Style@@ -44,9 +43,7 @@ [Extender exp ,Extender fieldupdate ,Extender rhs- ,Extender guardedrhs- ,Extender guardedalt- ,Extender unguardedalt+ ,Extender contextualGuardedRhs ,Extender stmt ,Extender decl] ,styleDefConfig =@@ -119,17 +116,43 @@ _ -> prettyNoExt e -- | Right-hand sides are dependent.-rhs :: State -> Rhs NodeInfo -> Printer ()-rhs _ (UnGuardedRhs _ e) =+rhs :: s -> Rhs NodeInfo -> Printer ()+rhs s grhs =+ do inCase <- gets psInsideCase+ if inCase+ then unguardedalt s grhs+ else unguardedrhs s grhs++-- | Right-hand sides are dependent.+unguardedrhs :: s -> Rhs NodeInfo -> Printer ()+unguardedrhs _ (UnGuardedRhs _ e) = do indentSpaces <- getIndentSpaces indented indentSpaces (dependOrNewline (write " = ") e pretty)-rhs _ e = prettyNoExt e+unguardedrhs _ e = prettyNoExt e +-- | Unguarded case alts.+unguardedalt :: t -> Rhs NodeInfo -> Printer ()+unguardedalt _ (UnGuardedRhs _ e) =+ dependOrNewline+ (write " -> ")+ e+ (indented 2 .+ pretty)+unguardedalt _ e = prettyNoExt e++-- | Decide whether to do alts or rhs based on the context.+contextualGuardedRhs :: s -> GuardedRhs NodeInfo -> Printer ()+contextualGuardedRhs s grhs =+ do inCase <- gets psInsideCase+ if inCase+ then guardedalt s grhs+ else guardedrhs s grhs+ -- | I want guarded RHS be dependent or newline.-guardedrhs :: State -> GuardedRhs NodeInfo -> Printer ()+guardedrhs :: s -> GuardedRhs NodeInfo -> Printer () guardedrhs _ (GuardedRhs _ stmts e) = indented 1 (do prefixedLined@@ -145,8 +168,8 @@ pretty)) -- | I want guarded alts be dependent or newline.-guardedalt :: State -> GuardedAlt NodeInfo -> Printer ()-guardedalt _ (GuardedAlt _ stmts e) =+guardedalt :: s -> GuardedRhs NodeInfo -> Printer ()+guardedalt _ (GuardedRhs _ stmts e) = indented 1 (do (prefixedLined ","@@ -160,28 +183,19 @@ (indented 1 . pretty)) --- | I want unguarded alts be dependent or newline.-unguardedalt :: State -> GuardedAlts NodeInfo -> Printer ()-unguardedalt _ (UnGuardedAlt _ e) =- dependOrNewline- (write " -> ")- e- (indented 2 .- pretty)-unguardedalt _ e = prettyNoExt e- -- Do statements need to handle infix expression indentation specially because -- do x * -- y -- is two invalid statements, not one valid infix op.-stmt :: State -> Stmt NodeInfo -> Printer ()+stmt :: s -> Stmt NodeInfo -> Printer () stmt _ (Qualifier _ e@(InfixApp _ a op b)) =- do col <- fmap (psColumn . snd) (sandbox (write ""))+ do col <- fmap (psColumn . snd)+ (sandbox (write "")) infixApp e a op b (Just col) stmt _ e = prettyNoExt e -- | Expressions-exp :: State -> Exp NodeInfo -> Printer ()+exp :: s -> Exp NodeInfo -> Printer () -- Infix applications will render on one line if possible, otherwise -- if any of the arguments are not "flat" then that expression is -- line-separated.@@ -264,7 +278,9 @@ => [ast NodeInfo] -> Printer (Bool,PrintState) sandboxSingles args = sandbox (allM (\(i,arg) ->- do when (i /= (0::Int)) newline+ do when (i /=+ (0 :: Int))+ newline line <- gets psLine pretty arg st <- get@@ -306,10 +322,12 @@ => ast NodeInfo -> Printer (Bool,PrintState) isShort p = do line <- gets psLine- orig <- fmap (psColumn . snd) (sandbox (write ""))+ orig <- fmap (psColumn . snd)+ (sandbox (write "")) (_,st) <- sandbox (pretty p) return (psLine st == line &&- (psColumn st < orig + shortName),st)+ (psColumn st < orig + shortName)+ ,st) -- | Is the given expression "small"? I.e. does it fit on one line and -- under 'smallColumnLimit' columns.@@ -323,12 +341,10 @@ -- | Is an expression flat? isFlat :: Exp NodeInfo -> Bool isFlat (Lambda _ _ e) = isFlat e-isFlat (App _ a b) =- isName a && isName b+isFlat (App _ a b) = isName a && isName b where isName (Var{}) = True isName _ = False-isFlat (InfixApp _ a _ b) =- isFlat a && isFlat b+isFlat (InfixApp _ a _ b) = isFlat a && isFlat b isFlat (NegApp _ a) = isFlat a isFlat VarQuote{} = True isFlat TypQuote{} = True
src/HIndent/Styles/Fundamental.hs view
@@ -3,9 +3,7 @@ -- | Fundamental built-in style. Defines no additional extensions or -- configurations beyond the default printer. -module HIndent.Styles.Fundamental- (fundamental)- where+module HIndent.Styles.Fundamental where import HIndent.Types
src/HIndent/Styles/Gibiansky.hs view
@@ -1,18 +1,19 @@ {-# LANGUAGE FlexibleContexts, OverloadedStrings, RecordWildCards, RankNTypes #-} -module HIndent.Styles.Gibiansky (gibiansky) where+module HIndent.Styles.Gibiansky where import Data.Foldable-import Control.Monad (unless, when, replicateM_, void)+import Control.Applicative((<$>))+import Control.Monad (unless, when, replicateM_) import Control.Monad.State (gets, get, put)-import Debug.Trace import HIndent.Pretty import HIndent.Types import Language.Haskell.Exts.Annotated.Syntax import Language.Haskell.Exts.SrcLoc-import Prelude hiding (exp, all, mapM_)+import Language.Haskell.Exts.Comments+import Prelude hiding (exp, all, mapM_, minimum, and, maximum) -- | Empty state. data State = State@@ -30,12 +31,16 @@ , Extender typ , Extender exprs , Extender rhss+ , Extender guardedRhs , Extender decls , Extender condecls- , Extender guardedAlts+ , Extender alt+ , Extender moduleHead+ , Extender exportList+ , Extender fieldUpdate ] , styleDefConfig =- defaultConfig { configMaxColumns = maxColumns+ defaultConfig { configMaxColumns = 100 , configIndentSpaces = indentSpaces , configClearEmptyLines = True }@@ -49,21 +54,26 @@ indentOnce :: Printer () indentOnce = replicateM_ indentSpaces $ write " " --- | Max number of columns per line.-maxColumns :: Integral a => a-maxColumns = 100+-- | How many exports to format in a single line.+-- If an export list has more than this, it will be formatted as multiple lines.+maxSingleLineExports :: Integral a => a+maxSingleLineExports = 4 -attemptSingleLine :: Printer a -> Printer a -> Printer ()+attemptSingleLine :: Printer a -> Printer a -> Printer a attemptSingleLine single multiple = do -- Try printing on one line. prevState <- get- void single+ result <- single -- If it doesn't fit, reprint on multiple lines. col <- getColumn- when (col > maxColumns) $ do- put prevState- void multiple+ maxColumns <- configMaxColumns <$> gets psConfig+ if col > maxColumns+ then do+ put prevState+ multiple+ else+ return result -------------------------------------------------------------------------------- -- Extenders@@ -126,6 +136,16 @@ write "=> " indented 3 $ pretty rest +typ _ (TyTuple _ boxed types) = parens $ do+ boxed'+ inter (write ", ") $ map pretty types+ boxed'++ where+ boxed' = case boxed of+ Boxed -> return ()+ Unboxed -> write "#"+ typ _ ty@(TyFun _ from to) = -- If the function argument types are on the same line, -- put the entire function type on the same line.@@ -148,7 +168,7 @@ sameLine :: (Annotated ast, Annotated ast') => ast NodeInfo -> ast' NodeInfo -> Bool sameLine x y = line x == line y where- line :: Annotated ast => ast NodeInfo -> Int + line :: Annotated ast => ast NodeInfo -> Int line = startLine . nodeInfoSpan . ann collectTypes :: Type l -> [Type l]@@ -163,6 +183,10 @@ exprs _ exp@(InfixApp _ _ (QVarOp _ (UnQual _ (Symbol _ "$"))) _) = dollarExpr exp exprs _ exp@(InfixApp _ _ (QVarOp _ (UnQual _ (Symbol _ "<*>"))) _) = applicativeExpr exp exprs _ exp@Lambda{} = lambdaExpr exp+exprs _ exp@Case{} = caseExpr exp+exprs _ (RecUpdate _ exp updates) = recUpdateExpr (pretty exp) updates+exprs _ (RecConstr _ qname updates) = recUpdateExpr (pretty qname) updates+exprs _ (Tuple _ _ exps) = parens $ inter (write ", ") $ map pretty exps exprs _ exp = prettyNoExt exp letExpr :: Exp NodeInfo -> Printer ()@@ -178,7 +202,65 @@ letExpr _ = error "Not a let" appExpr :: Exp NodeInfo -> Printer ()-appExpr (App _ f x) = spaced [pretty f, pretty x]+appExpr app@(App _ f x) = do+ prevState <- get+ prevLine <- getLineNum+ attemptSingleLine singleLine multiLine+ curLine <- getLineNum++ -- If the multiline version takes more than two lines,+ -- print everything with one argument per line.+ when (curLine - prevLine > 1) $ do+ -- Restore to before printing.+ put prevState++ allArgsSeparate <- not <$> canSingleLine (pretty f)+ if allArgsSeparate+ then separateArgs app+ else do+ col <- getColumn+ column col $ do+ pretty f+ newline+ indented indentSpaces $ pretty x++ where+ singleLine = spaced [pretty f, pretty x]+ multiLine = do+ col <- getColumn+ column col $ do+ pretty f+ newline+ indentOnce+ pretty x++ canSingleLine :: Printer a -> Printer Bool+ canSingleLine printer = do+ st <- get+ prevLine <- getLineNum+ _ <- printer+ curLine <- getLineNum+ put st+ return $ prevLine == curLine++ -- Separate a function application into the function+ -- and all of its arguments. Arguments are returned in reverse order.+ collectArgs :: Exp NodeInfo -> (Exp NodeInfo, [Exp NodeInfo])+ collectArgs (App _ g y) =+ let (fun, args) = collectArgs g in+ (fun, y : args)+ collectArgs nonApp = (nonApp, [])++ separateArgs :: Exp NodeInfo -> Printer ()+ separateArgs expr =+ let (fun, args) = collectArgs expr+ in do+ col <- getColumn+ column col $ do+ pretty fun+ newline+ indented indentSpaces $ lined $ map pretty $ reverse args+ appExpr _ = error "Not an app" doExpr :: Exp NodeInfo -> Printer ()@@ -193,19 +275,20 @@ listExpr _ = error "Not a list" singleLineList :: [Exp NodeInfo] -> Printer ()-singleLineList exprs = do+singleLineList exps = do write "["- inter (write ", ") $ map pretty exprs+ inter (write ", ") $ map pretty exps write "]" multiLineList :: [Exp NodeInfo] -> Printer () multiLineList [] = write "[]"-multiLineList (first:exprs) = do+multiLineList (first:exps) = do col <- getColumn- column col $ do+ ind <- gets psIndentLevel+ column (max col ind) $ do write "[ " pretty first- forM_ exprs $ \el -> do+ forM_ exps $ \el -> do newline write ", " pretty el@@ -288,11 +371,113 @@ pretty exp lambdaExpr _ = error "Not a lambda" +caseExpr :: Exp NodeInfo -> Printer ()+caseExpr (Case _ exp alts) = do+ allSingle <- and <$> mapM isSingle alts++ depend (write "case ") $ do+ pretty exp+ write " of"+ newline++ withCaseContext True $ indented indentSpaces $+ if allSingle+ then do+ maxPatLen <- maximum <$> mapM (patternLen . altPattern) alts+ lined $ map (prettyCase $ Just maxPatLen) alts+ else lined $ map (prettyCase Nothing) alts+ where+ isSingle :: Alt NodeInfo -> Printer Bool+ isSingle alt' = fst <$> sandbox (do+ line <- gets psLine+ pretty alt'+ line' <- gets psLine+ return $ line == line')++ altPattern :: Alt l -> Pat l+ altPattern (Alt _ p _ _) = p++ patternLen :: Pat NodeInfo -> Printer Int+ patternLen pat = fromIntegral <$> fst <$> sandbox (do+ col <- getColumn+ pretty pat+ col' <- getColumn+ return $ col' - col)++ prettyCase :: Maybe Int -> Alt NodeInfo -> Printer ()+ prettyCase mpatlen (Alt _ p galts mbinds) = do+ -- Padded pattern+ case mpatlen of+ Just patlen -> do+ col <- getColumn+ pretty p+ col' <- getColumn+ replicateM_ (patlen - fromIntegral (col' - col)) space+ Nothing -> pretty p++ case galts of+ UnGuardedRhs{} -> pretty galts+ GuardedRhss{} -> indented indentSpaces $ pretty galts++ -- Optional where clause!+ forM_ mbinds $ \binds -> do+ newline+ indented indentSpaces $ depend (write "where ") (pretty binds)+++caseExpr _ = error "Not a case"++recUpdateExpr :: Printer () -> [FieldUpdate NodeInfo] -> Printer ()+recUpdateExpr expWriter updates = do+ expWriter+ write " "+ attemptSingleLine single mult++ where+ single = do+ write "{ "+ inter (write ", ") $ map pretty updates+ write " }"+ mult = do+ col <- getColumn+ column col $ do+ write "{ "+ inter (newline >> write ", ") $ map pretty updates+ newline+ write "}"+ rhss :: Extend Rhs rhss _ (UnGuardedRhs _ exp) = do- write " = "+ write " " + rhsSeparator+ if onNextLine exp+ then indented indentSpaces $ do+ newline+ pretty exp+ else do+ space+ pretty exp+ + where+ onNextLine Let{} = True+ onNextLine _ = False+rhss _ (GuardedRhss _ rs) =+ lined $ flip map rs $ \a@(GuardedRhs _ stmts exp) -> do+ printComments Before a+ write "| "+ inter (write ", ") $ map pretty stmts+ write " "+ rhsSeparator+ write " "+ pretty exp++guardedRhs :: Extend GuardedRhs+guardedRhs _ (GuardedRhs _ stmts exp) = do+ indented 1 $ prefixedLined "," (map (\p -> space >> pretty p) stmts)+ write " " + rhsSeparator+ write " " pretty exp-rhss _ rhs = prettyNoExt rhs decls :: Extend Decl decls _ (DataDecl _ dataOrNew Nothing declHead constructors mayDeriving) = do@@ -317,11 +502,10 @@ newline indented indentSpaces $ pretty deriv -decls _ (PatBind _ pat Nothing rhs mbinds) = funBody [pat] rhs mbinds-decls _ (FunBind _ matches) = - forM_ matches $ \match -> do-- (name, pat, rhs, mbinds) <- +decls _ (PatBind _ pat rhs mbinds) = funBody [pat] rhs mbinds+decls _ (FunBind _ matches) =+ lined $ flip map matches $ \match -> do+ (name, pat, rhs, mbinds) <- case match of Match _ name pat rhs mbinds -> return (name, pat, rhs, mbinds) InfixMatch _ left name pat rhs mbinds -> do@@ -337,8 +521,13 @@ funBody :: [Pat NodeInfo] -> Rhs NodeInfo -> Maybe (Binds NodeInfo) -> Printer () funBody pat rhs mbinds = do spaced $ map pretty pat- pretty rhs + withCaseContext False $ case rhs of+ UnGuardedRhs{} -> pretty rhs+ GuardedRhss{} -> do+ newline + indented indentSpaces $ pretty rhs+ -- Process the binding group, if it exists. forM_ mbinds $ \binds -> do newline@@ -350,16 +539,24 @@ indented indentSpaces $ writeWhereBinds binds writeWhereBinds :: Binds NodeInfo -> Printer ()-writeWhereBinds (BDecls _ binds@(first:rest)) = do+writeWhereBinds ds@(BDecls _ binds@(first:rest)) = do+ printComments Before ds pretty first forM_ (zip binds rest) $ \(prev, cur) -> do- let prevLine = srcSpanEndLine . srcInfoSpan . nodeInfoSpan . ann $ prev- curLine = startLine . nodeInfoSpan . ann $ cur- emptyLines = curLine - prevLine- replicateM_ (traceShowId emptyLines) newline+ replicateM_ (max 1 $ lineDelta cur prev) newline pretty cur writeWhereBinds binds = prettyNoExt binds +astStartLine :: Annotated ast => ast NodeInfo -> Int+astStartLine decl =+ let info = ann decl+ comments = nodeInfoComments info+ befores = filter ((== Just Before) . comInfoLocation) comments+ commentStartLine (Comment _ sp _) = srcSpanStartLine sp+ in if null befores+ then startLine $ nodeInfoSpan info+ else minimum $ map (commentStartLine . comInfoComment) befores+ isDoBlock :: Rhs l -> Bool isDoBlock (UnGuardedRhs _ Do{}) = True isDoBlock _ = False@@ -389,8 +586,60 @@ write "}" condecls _ other = prettyNoExt other -guardedAlts :: Extend GuardedAlts-guardedAlts _ (UnGuardedAlt _ exp) = do- write " -> "- pretty exp-guardedAlts _ alt = prettyNoExt alt+alt :: Extend Alt+alt _ (Alt _ p rhs mbinds) = do+ pretty p+ case rhs of+ UnGuardedRhs{} -> pretty rhs+ GuardedRhss{} -> indented indentSpaces $ pretty rhs+ forM_ mbinds $ \binds -> do+ newline+ indented indentSpaces $+ depend (write "where ") (pretty binds)++moduleHead :: Extend ModuleHead+moduleHead _ (ModuleHead _ name mwarn mexports) = do+ forM_ mwarn pretty+ write "module "+ pretty name+ forM_ mexports $ \exports -> do+ space+ pretty exports+ write " where"++exportList :: Extend ExportSpecList+exportList _ (ExportSpecList _ exports) = do+ write "("+ if length exports <= maxSingleLineExports+ then do+ inter (write ", ") $ map pretty exports+ write ")"+ else indented indentSpaces' $ do+ -- First export+ let first:rest = exports+ newline+ pretty first+ write ","++ forM_ (zip rest exports) $ \(cur, prev) -> do+ replicateM_ (max 1 $ lineDelta cur prev) newline+ pretty cur+ write ","+ newline+ write ")"+ where+ indentSpaces' = 2 * indentSpaces++lineDelta :: (Annotated ast1, Annotated ast2) => ast1 NodeInfo -> ast2 NodeInfo -> Int+lineDelta cur prev = emptyLines+ where+ prevLine = srcSpanEndLine . srcInfoSpan . nodeInfoSpan . ann $ prev+ curLine = astStartLine cur+ emptyLines = curLine - prevLine++fieldUpdate :: Extend FieldUpdate+fieldUpdate _ (FieldUpdate _ name val) = do+ pretty name+ write " = "+ pretty val+fieldUpdate _ upd = prettyNoExt upd
src/HIndent/Styles/JohanTibell.hs view
@@ -11,9 +11,7 @@ -- How to indent let? -- How to indent large ADT constructors types? -module HIndent.Styles.JohanTibell- (johanTibell)- where+module HIndent.Styles.JohanTibell where import Control.Monad import Control.Monad.State.Class@@ -49,9 +47,7 @@ ,Extender exp ,Extender guardedRhs ,Extender rhs- ,Extender ifAlt- ,Extender alts- ,Extender guardedAlt]+ ] ,styleDefConfig = defaultConfig {configMaxColumns = 80 ,configIndentSpaces = 4}}@@ -76,46 +72,6 @@ gas)) _ -> prettyNoExt x --- | Case alts.-alts :: t -> GuardedAlts NodeInfo -> Printer ()--- | Handle do specially.-alts _ x =- case x of- UnGuardedAlt _ (Do _ dos) ->- swing (write " -> do")- (lined (map pretty dos))- GuardedAlts _ gas ->- do newline- indentSpaces <- getIndentSpaces- indented indentSpaces- (lined (map (\p ->- do write "|"- pretty p)- gas))- _ -> prettyNoExt x---- | Handle do specially.-guardedAlt _ x =- case x of- GuardedAlt _ stmts (Do _ dos) ->- do indented 1- (do (prefixedLined- ","- (map (\p ->- do space- pretty p)- stmts)))- swing (write " -> do ")- (lined (map pretty dos))- _ -> prettyNoExt x---- | Handle do specially.-ifAlt _ (IfAlt _ cond (Do _ dos)) =- do pretty cond- swing (write " -> do")- (lined (map pretty dos))-ifAlt _ e = prettyNoExt e- -- | Implement dangling right-hand-sides. guardedRhs :: t -> GuardedRhs NodeInfo -> Printer () -- | Handle do specially.@@ -171,16 +127,16 @@ newline branch "else " else') -- Special handling for do.- where branch string e =+ where branch str e = case e of Do _ stmts ->- do write string+ do write str write "do" newline indentSpaces <- getIndentSpaces indented indentSpaces (lined (map pretty stmts)) _ ->- depend (write string)+ depend (write str) (pretty e) -- | App algorithm similar to ChrisDone algorithm, but with no -- parent-child alignment.@@ -225,13 +181,9 @@ -- | Specially format records. Indent where clauses only 2 spaces. decl :: t -> Decl NodeInfo -> Printer ()-decl _ (PatBind _ pat mty rhs mbinds) =- case mty of- Just e ->- error ("Unimplemented (Maybe Type) in PatBind." ++ show e)- Nothing ->+decl _ (PatBind _ pat rhs' mbinds) = do pretty pat- pretty rhs+ pretty rhs' case mbinds of Nothing -> return () Just binds ->
src/HIndent/Types.hs view
@@ -14,8 +14,9 @@ ,Config(..) ,defaultConfig ,NodeInfo(..)- ,ComInfo(..))- where+ ,ComInfo(..)+ ,ComInfoLocation(..)+ ) where import Control.Applicative import Control.Monad.State.Strict (MonadState(..),State)@@ -43,11 +44,12 @@ ,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. } instance Eq PrintState where- PrintState ilevel out newline col line _ _ _ eolc == PrintState ilevel' out' newline' col' line' _ _ _ eolc' =- (ilevel,out,newline,col,line,eolc) == (ilevel',out',newline',col',line',eolc')+ PrintState ilevel out newline col line _ _ _ eolc inc == PrintState ilevel' out' newline' col' line' _ _ _ eolc' inc' =+ (ilevel,out,newline,col,line,eolc, inc) == (ilevel',out',newline',col',line',eolc', inc') -- | A printer extender. Takes as argument the user state that the -- printer was run with, and the current node to print. Use@@ -87,13 +89,17 @@ -- | Information for each node in the AST. data NodeInfo = NodeInfo {nodeInfoSpan :: !SrcSpanInfo -- ^ Location info from the parser.- ,nodeInfoComments :: ![ComInfo] -- ^ Comments which follow this node.+ ,nodeInfoComments :: ![ComInfo] -- ^ Comments which are attached to this node. } deriving (Typeable,Show,Data) +-- | Comment relative locations.+data ComInfoLocation = Before | After+ deriving (Show,Typeable,Data,Eq)+ -- | Comment with some more info. data ComInfo =- ComInfo {comInfoComment :: !Comment -- ^ The normal comment type.- ,comInfoOwnLine :: !Bool -- ^ Does the comment rest on its own line?+ ComInfo {comInfoComment :: !Comment -- ^ The normal comment type.+ ,comInfoLocation :: !(Maybe ComInfoLocation) -- ^ Where the comment lies relative to the node. } deriving (Show,Typeable,Data)
+ src/main/TestGenerate.hs view
@@ -0,0 +1,89 @@+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.styles+ 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 $ 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 view
@@ -13,7 +13,7 @@ import qualified HIndent styles :: [FilePath]-styles = ["gibiansky"]+styles = ["fundamental", "gibiansky", "chris-done"] testDir, expectedDir :: String testDir = "tests"@@ -44,7 +44,11 @@ let testDecls = parsePieces testContents expDecls = parsePieces expContents when (length testDecls /= length expDecls) $- error $ "Mismatched number of pieces in files " ++ test ++ " and " ++ exp+ 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@@ -54,7 +58,7 @@ Right builder -> L.unpack (L.toLazyText builder) `shouldBe` desired parsePieces :: String -> [String]-parsePieces str = map (intercalate "\n") pieces+parsePieces str = map (intercalate "\n" . map mkNewlines) pieces where pieces = unfoldr unfolder (lines str) @@ -68,3 +72,7 @@ pieceBreak :: (String, String) -> Bool pieceBreak ("", "") = error "Two consecutive line breaks!" pieceBreak (line, next) = null line && head next /= ' '++ mkNewlines :: String -> String+ mkNewlines ">" = ""+ mkNewlines x = x
vim/hindent.vim view
@@ -7,7 +7,16 @@ let g:hindent_style = "fundamental" endif +function! FormatHaskell()+ if !empty(v:char)+ return 1+ else+ let l:filter = "hindent --style " . g:hindent_style+ let l:command = v:lnum.','.(v:lnum+v:count-1).'!'.l:filter+ execute l:command+ endif+endfunction+ if has("autocmd")- let hindent = "hindent --style " . g:hindent_style- autocmd FileType haskell setlocal formatexpr=FormatprgLocal(hindent)+ autocmd FileType haskell setlocal formatexpr=FormatHaskell() endif