packages feed

floskell 0.9.0 → 0.10.0

raw patch · 21 files changed

+1908/−1038 lines, 21 filesdep +attoparsecdep −monad-loopsdep ~exceptionsdep ~haskell-src-extsPVP ok

version bump matches the API change (PVP)

Dependencies added: attoparsec

Dependencies removed: monad-loops

Dependency ranges changed: exceptions, haskell-src-exts

API changes (from Hackage documentation)

- Floskell: [styleInitialState] :: Style -> !FlexConfig
- Floskell: prettyPrint :: Style -> Module SrcSpanInfo -> [Comment] -> Either a ByteString
- Floskell.Comments: OrderByEnd :: SrcSpan -> OrderByEnd
- Floskell.Comments: OrderByStart :: SrcSpan -> OrderByStart
- Floskell.Comments: annotateComments :: Traversable ast => ast SrcSpanInfo -> [Comment] -> ([ComInfo], ast NodeInfo)
- Floskell.Comments: newtype OrderByEnd
- Floskell.Comments: newtype OrderByStart
- Floskell.Config: FlexConfig :: !PenaltyConfig -> !AlignConfig -> !IndentConfig -> !LayoutConfig -> !OpConfig -> !GroupConfig -> !OptionConfig -> FlexConfig
- Floskell.Config: [cfgLayoutTypesig] :: LayoutConfig -> !Layout
- Floskell.Config: data FlexConfig
- Floskell.Config: defaultFlexConfig :: FlexConfig
- Floskell.Config: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.Config.FlexConfig
- Floskell.Config: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.Config.FlexConfig
- Floskell.Config: instance Data.Default.Class.Default Floskell.Config.FlexConfig
- Floskell.Config: instance GHC.Generics.Generic Floskell.Config.FlexConfig
- Floskell.Config: safeFlexConfig :: FlexConfig -> FlexConfig
- Floskell.Pretty: CompactBinds :: Binds l -> CompactBinds l
- Floskell.Pretty: GuardedAlt :: GuardedRhs l -> GuardedAlt l
- Floskell.Pretty: GuardedAlts :: Rhs l -> GuardedAlts l
- Floskell.Pretty: MayAst :: Maybe (a l) -> MayAst a l
- Floskell.Pretty: compareAST :: (Functor ast, Ord (ast ())) => ast NodeInfo -> ast NodeInfo -> Ordering
- Floskell.Pretty: copyComments :: (Annotated ast1, Annotated ast2) => Location -> ast1 NodeInfo -> ast2 NodeInfo -> ast2 NodeInfo
- Floskell.Pretty: filterComments :: Annotated a => (Maybe Location -> Bool) -> a NodeInfo -> [ComInfo]
- Floskell.Pretty: flattenApp :: Annotated ast => (ast NodeInfo -> Maybe (ast NodeInfo, ast NodeInfo)) -> ast NodeInfo -> [ast NodeInfo]
- Floskell.Pretty: flattenInfix :: (Annotated ast1, Annotated ast2) => (ast1 NodeInfo -> Maybe (ast1 NodeInfo, ast2 NodeInfo, ast1 NodeInfo)) -> ast1 NodeInfo -> (ast1 NodeInfo, [(ast2 NodeInfo, ast1 NodeInfo)])
- Floskell.Pretty: instance Floskell.Pretty.Pretty Language.Haskell.Exts.Syntax.Kind
- Floskell.Pretty: lineDelta :: Annotated ast => ast NodeInfo -> ast NodeInfo -> Int
- Floskell.Pretty: lined :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer ()
- Floskell.Pretty: linedFn :: Annotated ast => (ast NodeInfo -> Printer ()) -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: linedOnside :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer ()
- Floskell.Pretty: list :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> ByteString -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: list' :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: listAutoWrap :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> ByteString -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: listH :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> ByteString -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: listH' :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: listV :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> ByteString -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: listV' :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: listVinternal :: (Annotated ast, Pretty ast) => LayoutContext -> ByteString -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: measure :: Printer a -> Printer (Maybe Int)
- Floskell.Pretty: measureAlt :: Alt NodeInfo -> Printer (Maybe [Int])
- Floskell.Pretty: measureClassDecl :: ClassDecl NodeInfo -> Printer (Maybe [Int])
- Floskell.Pretty: measureDecl :: Decl NodeInfo -> Printer (Maybe [Int])
- Floskell.Pretty: measureInstDecl :: InstDecl NodeInfo -> Printer (Maybe [Int])
- Floskell.Pretty: moduleName :: ModuleName a -> String
- Floskell.Pretty: nameLength :: Name a -> Int
- Floskell.Pretty: newtype CompactBinds l
- Floskell.Pretty: newtype GuardedAlt l
- Floskell.Pretty: newtype GuardedAlts l
- Floskell.Pretty: newtype MayAst a l
- Floskell.Pretty: noNodeInfo :: NodeInfo
- Floskell.Pretty: opName :: QOp a -> ByteString
- Floskell.Pretty: opName' :: QName a -> ByteString
- Floskell.Pretty: prettyApp :: (Annotated ast1, Annotated ast2, Pretty ast1, Pretty ast2) => ast1 NodeInfo -> [ast2 NodeInfo] -> Printer ()
- Floskell.Pretty: prettyConDecls :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer ()
- Floskell.Pretty: prettyDecls :: (Annotated ast, Pretty ast) => (ast NodeInfo -> ast NodeInfo -> Bool) -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: prettyForall :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer ()
- Floskell.Pretty: prettyHSE :: Pretty (ast NodeInfo) => PrettyPrinter ast
- Floskell.Pretty: prettyImports :: [ImportDecl NodeInfo] -> Printer ()
- Floskell.Pretty: prettyInfixApp :: (Annotated ast, Pretty ast, Pretty (op NodeInfo)) => (op NodeInfo -> ByteString) -> LayoutContext -> (ast NodeInfo, [(op NodeInfo, ast NodeInfo)]) -> Printer ()
- Floskell.Pretty: prettyOnside :: (Annotated ast, Pretty ast) => PrettyPrinter ast
- Floskell.Pretty: prettyPragma :: ByteString -> Printer () -> Printer ()
- Floskell.Pretty: prettyPragma' :: ByteString -> Maybe (Printer ()) -> Printer ()
- Floskell.Pretty: prettyPragmas :: [ModulePragma NodeInfo] -> Printer ()
- Floskell.Pretty: prettyRecord :: (Annotated ast1, Pretty ast1, Annotated ast2, Pretty ast2) => (ast2 NodeInfo -> Printer (Maybe Int)) -> LayoutContext -> ast1 NodeInfo -> [ast2 NodeInfo] -> Printer ()
- Floskell.Pretty: prettyRecordFields :: (Annotated ast, Pretty ast) => (ast NodeInfo -> Printer (Maybe Int)) -> LayoutContext -> [ast NodeInfo] -> Printer ()
- Floskell.Pretty: prettySimpleDecl :: (Annotated ast1, Pretty ast1, Annotated ast2, Pretty ast2) => ast1 NodeInfo -> ByteString -> ast2 NodeInfo -> Printer ()
- Floskell.Pretty: prettyTypesig :: (Annotated ast, Pretty ast) => LayoutContext -> [ast NodeInfo] -> Type NodeInfo -> Printer ()
- Floskell.Pretty: printComment :: Maybe SrcSpan -> Comment -> Printer ()
- Floskell.Pretty: printComments :: Annotated ast => Location -> ast NodeInfo -> Printer ()
- Floskell.Pretty: qnameLength :: QName a -> Int
- Floskell.Pretty: run :: (a -> a -> Bool) -> [a] -> ([a], [a])
- Floskell.Pretty: runs :: (a -> a -> Bool) -> [a] -> [[a]]
- Floskell.Pretty: skipBlank :: Annotated ast => (ast NodeInfo -> ast NodeInfo -> Bool) -> ast NodeInfo -> ast NodeInfo -> Bool
- Floskell.Pretty: skipBlankAfterDecl :: Decl a -> Bool
- Floskell.Pretty: skipBlankClassDecl :: ClassDecl NodeInfo -> ClassDecl NodeInfo -> Bool
- Floskell.Pretty: skipBlankDecl :: Decl NodeInfo -> Decl NodeInfo -> Bool
- Floskell.Pretty: skipBlankInstDecl :: InstDecl NodeInfo -> InstDecl NodeInfo -> Bool
- Floskell.Pretty: stopImportModule :: TabStop
- Floskell.Pretty: stopImportSpec :: TabStop
- Floskell.Pretty: stopRecordField :: TabStop
- Floskell.Pretty: stopRhs :: TabStop
- Floskell.Pretty: type PrettyPrinter f = f NodeInfo -> Printer ()
- Floskell.Pretty: withComputedTabStop :: TabStop -> (AlignConfig -> Bool) -> (a -> Printer (Maybe [Int])) -> [a] -> Printer b -> Printer b
- Floskell.Printers: linebreak :: Printer ()
- Floskell.Printers: withIndentFlat :: (IndentConfig -> Indent) -> ByteString -> Printer a -> Printer a
- Floskell.Types: ComInfo :: !Comment -> !Maybe Location -> ComInfo
- Floskell.Types: FlexConfig :: !PenaltyConfig -> !AlignConfig -> !IndentConfig -> !LayoutConfig -> !OpConfig -> !GroupConfig -> !OptionConfig -> FlexConfig
- Floskell.Types: Style :: !Text -> !Text -> !Text -> !FlexConfig -> Style
- Floskell.Types: [comInfoComment] :: ComInfo -> !Comment
- Floskell.Types: [comInfoLocation] :: ComInfo -> !Maybe Location
- Floskell.Types: [nodeInfoComments] :: NodeInfo -> ![ComInfo]
- Floskell.Types: [psUserState] :: PrintState -> !FlexConfig
- Floskell.Types: [styleAuthor] :: Style -> !Text
- Floskell.Types: [styleDescription] :: Style -> !Text
- Floskell.Types: [styleInitialState] :: Style -> !FlexConfig
- Floskell.Types: [styleName] :: Style -> !Text
- Floskell.Types: data ComInfo
- Floskell.Types: data FlexConfig
- Floskell.Types: data Style
- Floskell.Types: instance GHC.Show.Show Floskell.Types.ComInfo
+ Floskell: AppConfig :: Style -> Language -> [Extension] -> [Fixity] -> AppConfig
+ Floskell: [appExtensions] :: AppConfig -> [Extension]
+ Floskell: [appFixities] :: AppConfig -> [Fixity]
+ Floskell: [appLanguage] :: AppConfig -> Language
+ Floskell: [appStyle] :: AppConfig -> Style
+ Floskell: [styleConfig] :: Style -> !Config
+ Floskell: data AppConfig
+ Floskell: defaultAppConfig :: AppConfig
+ Floskell: findAppConfig :: IO (Maybe FilePath)
+ Floskell: findAppConfigIn :: FilePath -> IO (Maybe FilePath)
+ Floskell: readAppConfig :: FilePath -> IO AppConfig
+ Floskell: setExtensions :: AppConfig -> [String] -> AppConfig
+ Floskell: setFixities :: AppConfig -> [String] -> AppConfig
+ Floskell: setLanguage :: AppConfig -> Maybe String -> AppConfig
+ Floskell: setStyle :: AppConfig -> Maybe String -> AppConfig
+ Floskell.Attoparsec: data Position
+ Floskell.Attoparsec: instance GHC.Base.Monoid Floskell.Attoparsec.Position
+ Floskell.Attoparsec: instance GHC.Base.Semigroup Floskell.Attoparsec.Position
+ Floskell.Attoparsec: instance GHC.Classes.Eq Floskell.Attoparsec.Position
+ Floskell.Attoparsec: instance GHC.Classes.Ord Floskell.Attoparsec.Position
+ Floskell.Attoparsec: instance GHC.Show.Show Floskell.Attoparsec.Position
+ Floskell.Attoparsec: parseOnly :: Parser a -> ByteString -> Either String a
+ Floskell.Comments: annotateWithComments :: Traversable ast => ast SrcSpanInfo -> [Comment] -> ast NodeInfo
+ Floskell.Config: Config :: !PenaltyConfig -> !AlignConfig -> !IndentConfig -> !LayoutConfig -> !OpConfig -> !GroupConfig -> !OptionConfig -> Config
+ Floskell.Config: DeclClass :: DeclarationConstruct
+ Floskell.Config: DeclInstance :: DeclarationConstruct
+ Floskell.Config: DeclModule :: DeclarationConstruct
+ Floskell.Config: DeclWhere :: DeclarationConstruct
+ Floskell.Config: ImportsGroup :: ![String] -> !ImportsGroupOrder -> ImportsGroup
+ Floskell.Config: ImportsGroupGrouped :: ImportsGroupOrder
+ Floskell.Config: ImportsGroupKeep :: ImportsGroupOrder
+ Floskell.Config: ImportsGroupSorted :: ImportsGroupOrder
+ Floskell.Config: NoImportSort :: SortImportsRule
+ Floskell.Config: SortImportsByGroups :: ![ImportsGroup] -> SortImportsRule
+ Floskell.Config: SortImportsByPrefix :: SortImportsRule
+ Floskell.Config: [cfgAlignMatches] :: AlignConfig -> !Bool
+ Floskell.Config: [cfgIndentTypesig] :: IndentConfig -> !Indent
+ Floskell.Config: [cfgLayoutType] :: LayoutConfig -> !Layout
+ Floskell.Config: [cfgOptionAlignSumTypeDecl] :: OptionConfig -> !Bool
+ Floskell.Config: [cfgOptionDeclNoBlankLines] :: OptionConfig -> !Set DeclarationConstruct
+ Floskell.Config: [cfgOptionFlexibleOneline] :: OptionConfig -> !Bool
+ Floskell.Config: [importsOrder] :: ImportsGroup -> !ImportsGroupOrder
+ Floskell.Config: [importsPrefixes] :: ImportsGroup -> ![String]
+ Floskell.Config: data Config
+ Floskell.Config: data DeclarationConstruct
+ Floskell.Config: data ImportsGroup
+ Floskell.Config: data ImportsGroupOrder
+ Floskell.Config: data SortImportsRule
+ Floskell.Config: defaultConfig :: Config
+ Floskell.Config: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.Config.Config
+ Floskell.Config: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.Config.DeclarationConstruct
+ Floskell.Config: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.Config.ImportsGroup
+ Floskell.Config: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.Config.ImportsGroupOrder
+ Floskell.Config: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.Config.SortImportsRule
+ Floskell.Config: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.Config.Config
+ Floskell.Config: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.Config.DeclarationConstruct
+ Floskell.Config: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.Config.ImportsGroup
+ Floskell.Config: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.Config.ImportsGroupOrder
+ Floskell.Config: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.Config.SortImportsRule
+ Floskell.Config: instance Data.Default.Class.Default Floskell.Config.Config
+ Floskell.Config: instance GHC.Classes.Eq Floskell.Config.DeclarationConstruct
+ Floskell.Config: instance GHC.Classes.Ord Floskell.Config.DeclarationConstruct
+ Floskell.Config: instance GHC.Generics.Generic Floskell.Config.Config
+ Floskell.Config: instance GHC.Generics.Generic Floskell.Config.DeclarationConstruct
+ Floskell.Config: instance GHC.Generics.Generic Floskell.Config.ImportsGroup
+ Floskell.Config: instance GHC.Generics.Generic Floskell.Config.ImportsGroupOrder
+ Floskell.Config: safeConfig :: Config -> Config
+ Floskell.ConfigFile: AppConfig :: Style -> Language -> [Extension] -> [Fixity] -> AppConfig
+ Floskell.ConfigFile: [appExtensions] :: AppConfig -> [Extension]
+ Floskell.ConfigFile: [appFixities] :: AppConfig -> [Fixity]
+ Floskell.ConfigFile: [appLanguage] :: AppConfig -> Language
+ Floskell.ConfigFile: [appStyle] :: AppConfig -> Style
+ Floskell.ConfigFile: data AppConfig
+ Floskell.ConfigFile: defaultAppConfig :: AppConfig
+ Floskell.ConfigFile: findAppConfig :: IO (Maybe FilePath)
+ Floskell.ConfigFile: findAppConfigIn :: FilePath -> IO (Maybe FilePath)
+ Floskell.ConfigFile: instance Data.Aeson.Types.FromJSON.FromJSON Floskell.ConfigFile.AppConfig
+ Floskell.ConfigFile: instance Data.Aeson.Types.ToJSON.ToJSON Floskell.ConfigFile.AppConfig
+ Floskell.ConfigFile: instance GHC.Generics.Generic Floskell.ConfigFile.AppConfig
+ Floskell.ConfigFile: lookupExtension :: String -> Extension
+ Floskell.ConfigFile: lookupFixity :: String -> Fixity
+ Floskell.ConfigFile: lookupLanguage :: String -> Language
+ Floskell.ConfigFile: lookupStyle :: String -> Style
+ Floskell.ConfigFile: readAppConfig :: FilePath -> IO AppConfig
+ Floskell.ConfigFile: setExtensions :: AppConfig -> [String] -> AppConfig
+ Floskell.ConfigFile: setFixities :: AppConfig -> [String] -> AppConfig
+ Floskell.ConfigFile: setLanguage :: AppConfig -> Maybe String -> AppConfig
+ Floskell.ConfigFile: setStyle :: AppConfig -> Maybe String -> AppConfig
+ Floskell.ConfigFile: showExtension :: Extension -> String
+ Floskell.ConfigFile: showFixity :: Fixity -> String
+ Floskell.ConfigFile: showLanguage :: Language -> String
+ Floskell.ConfigFile: showStyle :: Style -> String
+ Floskell.Fixities: builtinFixities :: [Fixity]
+ Floskell.Fixities: packageFixities :: [(String, [Fixity])]
+ Floskell.Imports: groupImports :: Int -> [ImportDecl a] -> [[ImportDecl a]]
+ Floskell.Imports: sortImports :: [ImportDecl a] -> [ImportDecl a]
+ Floskell.Imports: splitImports :: [ImportsGroup] -> [ImportDecl a] -> [[ImportDecl a]]
+ Floskell.Printers: ignoreOneline :: Printer a -> Printer a
+ Floskell.Printers: indentedBy :: Int -> Printer a -> Printer a
+ Floskell.Printers: withIndentAfter :: (IndentConfig -> Indent) -> Printer () -> Printer a -> Printer a
+ Floskell.Printers: withIndentConfig :: (IndentConfig -> Indent) -> Printer a -> (Int -> Printer a) -> Printer a
+ Floskell.Printers: withIndentFlex :: (IndentConfig -> Indent) -> Printer a -> Printer a
+ Floskell.Styles: Style :: !Text -> !Text -> !Text -> !Config -> Style
+ Floskell.Styles: [styleAuthor] :: Style -> !Text
+ Floskell.Styles: [styleConfig] :: Style -> !Config
+ Floskell.Styles: [styleDescription] :: Style -> !Text
+ Floskell.Styles: [styleName] :: Style -> !Text
+ Floskell.Styles: data Style
+ Floskell.Types: Comment :: !CommentType -> !SrcSpan -> !String -> Comment
+ Floskell.Types: Config :: !PenaltyConfig -> !AlignConfig -> !IndentConfig -> !LayoutConfig -> !OpConfig -> !GroupConfig -> !OptionConfig -> Config
+ Floskell.Types: InlineComment :: CommentType
+ Floskell.Types: LineComment :: CommentType
+ Floskell.Types: PreprocessorDirective :: CommentType
+ Floskell.Types: SrcSpan :: String -> Int -> Int -> Int -> Int -> SrcSpan
+ Floskell.Types: TypeFlex :: TypeLayout
+ Floskell.Types: TypeFree :: TypeLayout
+ Floskell.Types: TypeVertical :: TypeLayout
+ Floskell.Types: [commentSpan] :: Comment -> !SrcSpan
+ Floskell.Types: [commentText] :: Comment -> !String
+ Floskell.Types: [commentType] :: Comment -> !CommentType
+ Floskell.Types: [nodeInfoLeadingComments] :: NodeInfo -> ![Comment]
+ Floskell.Types: [nodeInfoTrailingComments] :: NodeInfo -> ![Comment]
+ Floskell.Types: [psConfig] :: PrintState -> !Config
+ Floskell.Types: [psTypeLayout] :: PrintState -> !TypeLayout
+ Floskell.Types: [srcSpanEndColumn] :: SrcSpan -> Int
+ Floskell.Types: [srcSpanEndLine] :: SrcSpan -> Int
+ Floskell.Types: [srcSpanFilename] :: SrcSpan -> String
+ Floskell.Types: [srcSpanStartColumn] :: SrcSpan -> Int
+ Floskell.Types: [srcSpanStartLine] :: SrcSpan -> Int
+ Floskell.Types: data Comment
+ Floskell.Types: data CommentType
+ Floskell.Types: data Config
+ Floskell.Types: data SrcSpan
+ Floskell.Types: data TypeLayout
+ Floskell.Types: initialPrintState :: Config -> PrintState
+ Floskell.Types: instance GHC.Classes.Eq Floskell.Types.TypeLayout
+ Floskell.Types: instance GHC.Classes.Ord Floskell.Types.TypeLayout
+ Floskell.Types: instance GHC.Show.Show Floskell.Types.Comment
+ Floskell.Types: instance GHC.Show.Show Floskell.Types.CommentType
+ Floskell.Types: instance GHC.Show.Show Floskell.Types.TypeLayout
+ Floskell.Types: noNodeInfo :: NodeInfo
+ Floskell.Types: nodeSpan :: Annotated ast => ast NodeInfo -> SrcSpan
- Floskell: Style :: !Text -> !Text -> !Text -> !FlexConfig -> Style
+ Floskell: Style :: !Text -> !Text -> !Text -> !Config -> Style
- Floskell: reformat :: Style -> Language -> [Extension] -> Maybe FilePath -> ByteString -> Either String ByteString
+ Floskell: reformat :: AppConfig -> Maybe FilePath -> ByteString -> Either String ByteString
- Floskell.Buffer: column :: Buffer -> Int64
+ Floskell.Buffer: column :: Buffer -> Int
- Floskell.Buffer: line :: Buffer -> Int64
+ Floskell.Buffer: line :: Buffer -> Int
- Floskell.Config: AlignConfig :: !(Int, Int) -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> AlignConfig
+ Floskell.Config: AlignConfig :: !(Int, Int) -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> AlignConfig
- Floskell.Config: IndentConfig :: !Int -> !Int -> !Int -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> IndentConfig
+ Floskell.Config: IndentConfig :: !Int -> !Int -> !Int -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> !Indent -> IndentConfig
- Floskell.Config: OptionConfig :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> OptionConfig
+ Floskell.Config: OptionConfig :: !Bool -> !Bool -> !SortImportsRule -> !Bool -> !Bool -> !Bool -> !Bool -> !Set DeclarationConstruct -> OptionConfig
- Floskell.Config: [cfgAlign] :: FlexConfig -> !AlignConfig
+ Floskell.Config: [cfgAlign] :: Config -> !AlignConfig
- Floskell.Config: [cfgGroup] :: FlexConfig -> !GroupConfig
+ Floskell.Config: [cfgGroup] :: Config -> !GroupConfig
- Floskell.Config: [cfgIndent] :: FlexConfig -> !IndentConfig
+ Floskell.Config: [cfgIndent] :: Config -> !IndentConfig
- Floskell.Config: [cfgLayout] :: FlexConfig -> !LayoutConfig
+ Floskell.Config: [cfgLayout] :: Config -> !LayoutConfig
- Floskell.Config: [cfgOp] :: FlexConfig -> !OpConfig
+ Floskell.Config: [cfgOp] :: Config -> !OpConfig
- Floskell.Config: [cfgOptionSortImports] :: OptionConfig -> !Bool
+ Floskell.Config: [cfgOptionSortImports] :: OptionConfig -> !SortImportsRule
- Floskell.Config: [cfgOptions] :: FlexConfig -> !OptionConfig
+ Floskell.Config: [cfgOptions] :: Config -> !OptionConfig
- Floskell.Config: [cfgPenalty] :: FlexConfig -> !PenaltyConfig
+ Floskell.Config: [cfgPenalty] :: Config -> !PenaltyConfig
- Floskell.Pretty: pretty :: (Annotated ast, Pretty ast) => PrettyPrinter ast
+ Floskell.Pretty: pretty :: (Annotated ast, Pretty ast) => ast NodeInfo -> Printer ()
- Floskell.Pretty: prettyPrint :: (Pretty ast, Pretty (ast NodeInfo)) => PrettyPrinter ast
+ Floskell.Pretty: prettyPrint :: (Pretty ast, Pretty (ast NodeInfo)) => ast NodeInfo -> Printer ()
- Floskell.Printers: column :: Int64 -> Printer a -> Printer a
+ Floskell.Printers: column :: Int -> Printer a -> Printer a
- Floskell.Printers: getConfig :: (FlexConfig -> b) -> Printer b
+ Floskell.Printers: getConfig :: (Config -> b) -> Printer b
- Floskell.Printers: getNextColumn :: Printer Int64
+ Floskell.Printers: getNextColumn :: Printer Int
- Floskell.Printers: getOption :: (OptionConfig -> Bool) -> Printer Bool
+ Floskell.Printers: getOption :: (OptionConfig -> a) -> Printer a
- Floskell.Printers: int :: Integer -> Printer ()
+ Floskell.Printers: int :: Int -> Printer ()
- Floskell.Types: NodeInfo :: !SrcSpanInfo -> ![ComInfo] -> NodeInfo
+ Floskell.Types: NodeInfo :: !SrcSpan -> ![Comment] -> ![Comment] -> NodeInfo
- Floskell.Types: PrintState :: !Buffer -> !Int64 -> !Int64 -> !Map TabStop Int64 -> !FlexConfig -> !Bool -> OutputRestriction -> PrintState
+ Floskell.Types: PrintState :: !Buffer -> !Int -> !Int -> !Map TabStop Int -> !Config -> !Bool -> !OutputRestriction -> !TypeLayout -> PrintState
- Floskell.Types: [cfgAlign] :: FlexConfig -> !AlignConfig
+ Floskell.Types: [cfgAlign] :: Config -> !AlignConfig
- Floskell.Types: [cfgGroup] :: FlexConfig -> !GroupConfig
+ Floskell.Types: [cfgGroup] :: Config -> !GroupConfig
- Floskell.Types: [cfgIndent] :: FlexConfig -> !IndentConfig
+ Floskell.Types: [cfgIndent] :: Config -> !IndentConfig
- Floskell.Types: [cfgLayout] :: FlexConfig -> !LayoutConfig
+ Floskell.Types: [cfgLayout] :: Config -> !LayoutConfig
- Floskell.Types: [cfgOp] :: FlexConfig -> !OpConfig
+ Floskell.Types: [cfgOp] :: Config -> !OpConfig
- Floskell.Types: [cfgOptions] :: FlexConfig -> !OptionConfig
+ Floskell.Types: [cfgOptions] :: Config -> !OptionConfig
- Floskell.Types: [cfgPenalty] :: FlexConfig -> !PenaltyConfig
+ Floskell.Types: [cfgPenalty] :: Config -> !PenaltyConfig
- Floskell.Types: [nodeInfoSpan] :: NodeInfo -> !SrcSpanInfo
+ Floskell.Types: [nodeInfoSpan] :: NodeInfo -> !SrcSpan
- Floskell.Types: [psIndentLevel] :: PrintState -> !Int64
+ Floskell.Types: [psIndentLevel] :: PrintState -> !Int
- Floskell.Types: [psOnside] :: PrintState -> !Int64
+ Floskell.Types: [psOnside] :: PrintState -> !Int
- Floskell.Types: [psOutputRestriction] :: PrintState -> OutputRestriction
+ Floskell.Types: [psOutputRestriction] :: PrintState -> !OutputRestriction
- Floskell.Types: [psTabStops] :: PrintState -> !Map TabStop Int64
+ Floskell.Types: [psTabStops] :: PrintState -> !Map TabStop Int
- Floskell.Types: psColumn :: PrintState -> Int64
+ Floskell.Types: psColumn :: PrintState -> Int
- Floskell.Types: psLine :: PrintState -> Int64
+ Floskell.Types: psLine :: PrintState -> Int

Files

CHANGELOG.md view
@@ -1,3 +1,23 @@-# Floskell 1.0.0+# Floskell 0.10.0 (2019-05-03)++* Updated to haskell-src-exts-1.21.0, with support for `DerivingVia` and `TypeInType`+* Support for custom fixity declarations (with common libraries built in)+* More control over sorting and formatting of imports+* More control over formatting of type signatures+* New option to align `=` with `|` in data declarations+* New option to allow `do`, `case`, and lambda in `try-oneline` layouts+* New option to avoid vertical space between declarations+* New option to tabstop-align right-hand-side of function match clauses+* Improved handling of CPP directives+* Improved positioning of comments+* Better error messages for JSON syntax errors in configuration file+* Many formatting fixes++Incompatible changes:++* `formatting/layout/typesig` has been removed in favor of+  `formatting/layout/type`++# Floskell 0.9.0 (2019-01-25)  * Initial release
README.md view
@@ -168,6 +168,58 @@ tuple = (1,2) ``` +### Preprocessor Directives (CPP)++Floskell, in general, supports Haskell source with conditional+compilation directives using the `CPP` language extensions.  However,+due to the way this support is implemented, some care must be taken to+not confuse the Haskell source parser.++Floskell treats conditional compilation directives as if they were+simply comments.  As a consequence, the input must still be valid+Haskell when all preprocessor lines are removed.  This is relevant+when using `#if`/`#else`/`#endif` sequences, as Floskell will see both+the if- and else-block in sequence.  For example, the following cannot+be processed with Floskell, as the first declaration of `prettyPrint`+ends with an incomplete `do` block:++```haskell+#if MIN_VERSION_haskell_src_exts(1,21,0)+    prettyPrint (GadtDecl _ name _ _ mfielddecls ty) = do+#else+    prettyPrint (GadtDecl _ name mfielddecls ty) = do+#endif+        pretty name+        operator Declaration "::"+        mayM_ mfielddecls $ \decls -> do+            prettyRecordFields len Declaration decls+            operator Type "->"+        pretty ty+```++Instead, some of the contents of the `do` block have to be duplicated,+so that the contents of the `#if` are valid Haskell on their own.++```haskell+#if MIN_VERSION_haskell_src_exts(1,21,0)+    prettyPrint (GadtDecl _ name _ _ mfielddecls ty) = do+        pretty name+        operator Declaration "::"+        mayM_ mfielddecls $ \decls -> do+            prettyRecordFields len Declaration decls+            operator Type "->"+        pretty ty+#else+    prettyPrint (GadtDecl _ name mfielddecls ty) = do+        pretty name+        operator Declaration "::"+        mayM_ mfielddecls $ \decls -> do+            prettyRecordFields len Declaration decls+            operator Type "->"+        pretty ty+#endif+```+  ## Customization 
TEST.md view
@@ -242,6 +242,13 @@   IntNil :: List Int   IntCons :: { val :: Int } -> List Int   deriving (Eq, Ord, Show)++newtype Penalty = Penalty Int+  deriving (Eq, Ord)+  deriving stock (Read, Show)+  deriving newtype (Num)+  deriving anyclass (FromJSON, ToJSON)+  deriving (Semigroup, Monoid) via M.Sum Int ```  ### ClassDecl and InstDecl@@ -459,6 +466,7 @@ ### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig  ``` haskell+{-# LANGUAGE TupleSections #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UnboxedSums #-} @@ -478,6 +486,10 @@ foo = (1 -- the one  , 2) +foo = (1,)+foo = (,2)+foo = (,2,)+ foo = (# #) foo = (# 1, 2 #) foo = (# 1 -- the one@@ -694,6 +706,18 @@   some expression ``` +## Patterns++Long function pattern matches allow linebreaks.++``` haskell+doThing+  (Constructor field1 field2 field3)+  (Constructor field1 field2 field3)+  (Constructor field1 field2 field3)+  = undefined+```+ ## Onside  Indent within onside started on non-empty line should still not stack.@@ -747,4 +771,64 @@   if condition -- comment     then this     else that+```++## Comments++Don't be too eager in assigning comments to the following AST node.++``` haskell+data Foo = Foo+  { fooBar :: Text+  -- ^A comment, long enough to end up on its own line, or at least I hope so.+  } deriving (Eq)+```++Keep comments together and aligned.++``` haskell+-- block+-- one+data Foo = Foo  -- some+                -- comments+         | Quux -- more+                -- comments+-- block+-- two+```++Only comments.++``` haskell+-- some comment+```++Make sure no comments are dropped from operators or argument.++``` haskell+foo = some -- comment 1+      -- comment 2+      %~ -- comment 3+      argument -- comment 4+```++## Indentation and Line Prefixes++Preserving indentation and line prefixes so that Floskell can be run+on individual declarations and quoted haskell code.++``` haskell+    data Enum =+     One   -- Foo+     | Two   -- Bar+     | Three -- Baz+```++``` haskell+>+>    data Enum =+>     One   -- Foo+>     | Two   -- Bar+>     | Three -- Baz+> ```
floskell.cabal view
@@ -1,5 +1,5 @@ name:                floskell-version:             0.9.0+version:             0.10.0 synopsis:            A flexible Haskell source code pretty printer description:         A flexible Haskell source code pretty printer.                      .@@ -21,6 +21,7 @@                      CHANGELOG.md                      BENCHMARK.md                      TEST.md+                     stack.yaml  source-repository head     type:           git@@ -30,43 +31,46 @@   hs-source-dirs:    src/   ghc-options:       -Wall   exposed-modules:   Floskell+                     Floskell.Attoparsec                      Floskell.Buffer                      Floskell.Comments                      Floskell.Config+                     Floskell.ConfigFile+                     Floskell.Fixities+                     Floskell.Imports                      Floskell.Pretty                      Floskell.Printers                      Floskell.Styles                      Floskell.Types-  build-depends:     base >= 4.7 && <5-                   , aeson-                   , containers-                   , unordered-containers-                   , data-default-                   , haskell-src-exts >= 1.20-                   , monad-loops-                   , monad-dijkstra-                   , mtl-                   , bytestring-                   , utf8-string-                   , transformers-                   , text+  build-depends:     base >=4.9 && <4.13+                   , aeson >=0.11.3.0 && <1.5+                   , attoparsec >=0.13.1.0 && <0.14+                   , bytestring >=0.10.8.1 && <0.11+                   , containers >=0.5.7.1 && <0.7+                   , data-default >=0.7.1.1 && <0.8+                   , directory >=1.2.6.2 && <1.4+                   , filepath >=1.4.1.0 && <1.5+                   , haskell-src-exts >= 1.19 && <1.22+                   , monad-dijkstra >=0.1.1 && <0.2+                   , mtl >=2.2.1 && <2.3+                   , text >=1.2.2.2 && <1.3+                   , transformers >=0.5.2.0 && <0.6+                   , unordered-containers >=0.2.8.0 && <0.3+                   , utf8-string >=1.0.1.1 && <1.1  executable floskell   hs-source-dirs:    src/main   ghc-options:       -Wall -Wno-missing-home-modules -optP-Wno-nonportable-include-path   main-is:           Main.hs-  build-depends:     base >= 4 && < 5+  build-depends:     base >=4.9 && <4.13                    , floskell-                   , aeson-                   , aeson-pretty-                   , bytestring-                   , optparse-applicative-                   , haskell-src-exts-                   , ghc-prim-                   , directory-                   , filepath-                   , unordered-containers-                   , text+                   , aeson-pretty >=0.8.2 && <0.9+                   , bytestring >=0.10.8.1 && <0.11+                   , directory >=1.2.6.2 && <1.4+                   , ghc-prim >=0.5.0.0 && <0.6+                   , haskell-src-exts >= 1.19 && <1.22+                   , optparse-applicative >=0.12.1.0 && <0.15+                   , text >=1.2.2.2 && <1.3  test-suite floskell-test   type: exitcode-stdio-1.0@@ -74,18 +78,15 @@   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N   main-is:           Test.hs   other-modules:     Markdone-  build-depends:     base >= 4 && <5+  build-depends:     base >=4.9 && <4.13                    , floskell-                   , haskell-src-exts-                   , monad-loops-                   , mtl-                   , bytestring-                   , utf8-string-                   , hspec-                   , directory-                   , text-                   , deepseq-                   , exceptions+                   , bytestring >=0.10.8.1 && <0.11+                   , deepseq >=1.4.2.0 && <1.5+                   , exceptions >=0.8.3 && <0.12+                   , haskell-src-exts >= 1.19 && <1.22+                   , hspec >=2.2.4 && <2.8+                   , text >=1.2.2.2 && <1.3+                   , utf8-string >=1.0.1.1 && <1.1  benchmark floskell-bench   type: exitcode-stdio-1.0@@ -93,14 +94,13 @@   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N   main-is:           Benchmark.hs   other-modules:     Markdone-  build-depends:     base >= 4 && < 5+  build-depends:     base >=4.9 && <4.13                    , floskell-                   , bytestring-                   , utf8-string-                   , haskell-src-exts-                   , ghc-prim-                   , directory-                   , criterion-                   , deepseq-                   , exceptions-                   , text+                   , bytestring >=0.10.8.1 && <0.11+                   , criterion >=1.1.1.0 && <1.6+                   , deepseq >=1.4.2.0 && <1.5+                   , exceptions >=0.8.3 && <0.11+                   , ghc-prim >=0.5.0.0 && <0.6+                   , haskell-src-exts >= 1.19 && < 1.22+                   , text >=1.2.2.2 && <1.3+                   , utf8-string >=1.0.1.1 && <1.1
src/Floskell.hs view
@@ -4,9 +4,18 @@  -- | Haskell indenter. module Floskell-    ( -- * Formatting functions.-      reformat-    , prettyPrint+    ( -- * Configuration+      AppConfig(..)+    , defaultAppConfig+    , findAppConfig+    , findAppConfigIn+    , readAppConfig+    , setStyle+    , setLanguage+    , setExtensions+    , setFixities+      -- * Formatting functions.+    , reformat       -- * Style     , Style(..)     , styles@@ -14,135 +23,189 @@     , defaultExtensions     ) where -import           Data.ByteString            ( ByteString )-import qualified Data.ByteString            as S-import qualified Data.ByteString.Char8      as S8-import qualified Data.ByteString.Internal   as S-import qualified Data.ByteString.Lazy       as L+import           Data.ByteString.Lazy       ( ByteString ) 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 qualified Data.ByteString.Lazy.UTF8  as UTF8 import           Data.List-import qualified Data.Map.Strict            as Map import           Data.Maybe import           Data.Monoid  import qualified Floskell.Buffer            as Buffer import           Floskell.Comments-import           Floskell.Pretty            ( pretty, printComment )-import           Floskell.Styles            ( styles )+import           Floskell.Config+import           Floskell.ConfigFile+import           Floskell.Fixities          ( builtinFixities )+import           Floskell.Pretty            ( pretty )+import           Floskell.Styles            ( Style(..), styles ) import           Floskell.Types  import           Language.Haskell.Exts-                 hiding ( Pretty, Style, parse, prettyPrint, style )+                 hiding ( Comment, Pretty, Style, parse, prettyPrint, style ) import qualified Language.Haskell.Exts      as Exts -data CodeBlock = HaskellSource Int ByteString | CPPDirectives ByteString+data CodeBlock = HaskellSource Int [ByteString] | CPPDirectives [ByteString]     deriving ( Show, Eq ) --- | Format the given source.-reformat :: Style-         -> Language-         -> [Extension]-         -> Maybe FilePath-         -> ByteString-         -> Either String L.ByteString-reformat style language langextensions mfilepath x = preserveTrailingNewline x-    . mconcat . intersperse "\n" <$> mapM processBlock (cppSplitBlocks x)+trimBy :: (a -> Bool) -> [a] -> ([a], [a], [a])+trimBy f xs = (prefix, middle, suffix)   where-    processBlock :: CodeBlock -> Either String L.ByteString-    processBlock (CPPDirectives text) = Right $ L.fromStrict text-    processBlock (HaskellSource offset text) =-        let ls = S8.lines text-            prefix = findPrefix ls-            code = unlines' (map (stripPrefix prefix) ls)-            exts = readExtensions (UTF8.toString code)-            mode'' = case exts of-                Nothing -> mode'-                Just (Nothing, exts') ->-                    mode' { extensions = exts' ++ extensions mode' }-                Just (Just lang, exts') ->-                    mode' { baseLanguage = lang-                          , extensions   = exts' ++ extensions mode'-                          }-        in-            case parseModuleWithComments mode'' (UTF8.toString code) of-                ParseOk (m, comments) ->-                    fmap (addPrefix prefix) (prettyPrint style m comments)-                ParseFailed loc e -> Left $-                    Exts.prettyPrint (loc { srcLine = srcLine loc + offset })-                    ++ ": " ++ e+    (prefix, xs') = span f xs -    unlines' = S.concat . intersperse "\n"+    (suffix', middle') = span f $ reverse xs' -    unlines'' = L.concat . intersperse "\n"+    middle = reverse middle' -    addPrefix :: ByteString -> L8.ByteString -> L8.ByteString-    addPrefix prefix = unlines'' . map (L8.fromStrict prefix <>) . L8.lines+    suffix = reverse suffix' -    stripPrefix :: ByteString -> ByteString -> ByteString-    stripPrefix prefix line = if S.null (S8.dropWhile (== '\n') line)-                              then line-                              else fromMaybe (error "Missing expected prefix")-                                  . s8_stripPrefix prefix $ line+findLinePrefix :: (Char -> Bool) -> [ByteString] -> ByteString+findLinePrefix _ [] = ""+findLinePrefix f (x : xs') = go (L8.takeWhile f x) xs'+  where+    go prefix xs = if all (prefix `L8.isPrefixOf`) xs+                   then prefix+                   else go (L8.take (L8.length prefix - 1) prefix) xs -    findPrefix :: [ByteString] -> ByteString-    findPrefix = takePrefix False . findSmallestPrefix . dropNewlines+findIndent :: (Char -> Bool) -> [ByteString] -> ByteString+findIndent _ [] = ""+findIndent f (x : xs') = go (L8.takeWhile f x) $ filter (not . L8.all f) xs'+  where+    go indent xs = if all (indent `L8.isPrefixOf`) xs+                   then indent+                   else go (L8.take (L8.length indent - 1) indent) xs -    dropNewlines :: [ByteString] -> [ByteString]-    dropNewlines = filter (not . S.null . S8.dropWhile (== '\n'))+preserveVSpace :: Monad m+               => ([ByteString] -> m [ByteString])+               -> [ByteString]+               -> m [ByteString]+preserveVSpace format input = do+    output <- format input'+    return $ prefix ++ output ++ suffix+  where+    (prefix, input', suffix) = trimBy L8.null input -    takePrefix :: Bool -> ByteString -> ByteString-    takePrefix bracketUsed txt = case S8.uncons txt of-        Nothing -> ""-        Just ('>', txt') ->-            if not bracketUsed then S8.cons '>' (takePrefix True txt') else ""-        Just (c, txt') -> if c == ' ' || c == '\t'-                          then S8.cons c (takePrefix bracketUsed txt')-                          else ""+preservePrefix :: Monad m+               => (Int -> [ByteString] -> m [ByteString])+               -> [ByteString]+               -> m [ByteString]+preservePrefix format input = do+    output <- format (prefixLength prefix) input'+    return $ map (prefix <>) output+  where+    prefix = findLinePrefix allowed input -    findSmallestPrefix :: [ByteString] -> ByteString-    findSmallestPrefix [] = ""-    findSmallestPrefix ("" : _) = ""-    findSmallestPrefix (p : ps) =-        let first = S8.head p-            startsWithChar c x = S8.length x > 0 && S8.head x == c-        in-            if all (startsWithChar first) ps-            then S8.cons first (findSmallestPrefix (S.tail p : map S.tail ps))-            else ""+    input' = map (L8.drop $ L8.length prefix) input +    allowed c = c == ' ' || c == '\t' || c == '>'++    prefixLength = sum . map (\c -> if c == '\t' then 8 else 1) . L8.unpack++preserveIndent :: Monad m+               => (Int -> [ByteString] -> m [ByteString])+               -> [ByteString]+               -> m [ByteString]+preserveIndent format input = do+    output <- format (prefixLength prefix) input'+    return $ map (prefix <>) output+  where+    prefix = findIndent allowed input++    input' = map (L8.drop $ L8.length prefix) input++    allowed c = c == ' ' || c == '\t'++    prefixLength = sum . map (\c -> if c == '\t' then 8 else 1) . L8.unpack++withReducedLineLength :: Int -> Config -> Config+withReducedLineLength offset config = config { cfgPenalty = penalty }+  where+    penalty = (cfgPenalty config) { penaltyMaxLineLength =+                                        penaltyMaxLineLength (cfgPenalty config)+                                        - offset+                                  }++-- | Format the given source.+reformat+    :: AppConfig -> Maybe FilePath -> ByteString -> Either String ByteString+reformat config mfilepath input = fmap (L8.intercalate "\n")+    . preserveVSpace (preservePrefix (reformatLines mode cfg)) $+    L8.split '\n' input+  where+    mode = case readExtensions $ UTF8.toString input of+        Nothing -> mode'+        Just (Nothing, exts') ->+            mode' { extensions = exts' ++ extensions mode' }+        Just (Just lang, exts') ->+            mode' { baseLanguage = lang+                  , extensions   = exts' ++ extensions mode'+                  }+     mode' = defaultParseMode { parseFilename = fromMaybe "<stdin>" mfilepath-                             , baseLanguage  = language-                             , extensions    = langextensions+                             , baseLanguage  = appLanguage config+                             , extensions    = appExtensions config+                             , fixities      =+                                   Just $ appFixities config ++ builtinFixities                              } -    preserveTrailingNewline x x' = if not (S8.null x) && S8.last x == '\n'-                                       && not (L8.null x') && L8.last x' /= '\n'-                                   then x' <> "\n"-                                   else x'+    cfg = styleConfig $ appStyle config --- | Break a Haskell code string into chunks, using CPP as a delimiter.--- Lines that start with '#if', '#end', or '#else' are their own chunks, and--- also act as chunk separators. For example, the code------ > #ifdef X--- > x = X--- > y = Y--- > #else--- > x = Y--- > y = X--- > #endif------ will become five blocks, one for each CPP line and one for each pair of declarations.-cppSplitBlocks :: ByteString -> [CodeBlock]-cppSplitBlocks = map (classify . unlines') . groupBy ((==) `on` (cppLine . snd))-    . zip [ 0 .. ] . S8.lines+reformatLines+    :: ParseMode -> Config -> Int -> [ByteString] -> Either String [ByteString]+reformatLines mode config indent = format . filterPreprocessorDirectives   where-    cppLine :: ByteString -> Bool+    config' = withReducedLineLength indent config++    format (code, comments) =+        preserveVSpace (preserveIndent (reformatBlock mode config' comments))+                       code++-- | Format a continuous block of code without CPP directives.+reformatBlock :: ParseMode+              -> Config+              -> [Comment]+              -> Int+              -> [ByteString]+              -> Either String [ByteString]+reformatBlock mode config cpp indent lines =+    case parseModuleWithComments mode code of+        ParseOk (m, comments') ->+            let comments = map makeComment comments'+                ast = annotateWithComments m (mergeComments comments cpp)+            in+                case prettyPrint (pretty ast) config' of+                    Nothing -> Left "Printer failed with mzero call."+                    Just output -> Right $ L8.lines output+        ParseFailed loc e -> Left $+            Exts.prettyPrint (loc { srcLine = srcLine loc }) ++ ": " ++ e+  where+    code = UTF8.toString $ L8.intercalate "\n" lines++    config' = withReducedLineLength indent config++    makeComment (Exts.Comment inline span text) =+        Comment (if inline then InlineComment else LineComment) span text++    mergeComments xs [] = xs+    mergeComments [] ys = ys+    mergeComments xs@(x : xs') ys@(y : ys') =+        if srcSpanStartLine (commentSpan x) < srcSpanStartLine (commentSpan y)+        then x : mergeComments xs' ys+        else y : mergeComments xs ys'++-- | Remove CPP directives from input source, retur+filterPreprocessorDirectives :: [ByteString] -> ([ByteString], [Comment])+filterPreprocessorDirectives lines = (code, comments)+  where+    code = map (\l -> if cppLine l then "" else l) lines++    comments = map makeComment . filter (cppLine . snd) $ zip [ 1 .. ] lines++    makeComment (n, l) =+        Comment PreprocessorDirective+                (SrcSpan "" n 1 n (fromIntegral $ L8.length l + 1))+                (L8.unpack l)+     cppLine src =-        any (`S8.isPrefixOf` src)+        any (`L8.isPrefixOf` src)             [ "#if"             , "#end"             , "#else"@@ -154,47 +217,9 @@             , "#warning"             ] -    unlines' :: [(Int, ByteString)] -> (Int, ByteString)-    unlines' [] = (0, "")-    unlines' xs@((line, _) : _) = (line, S8.unlines $ map snd xs)--    classify :: (Int, ByteString) -> CodeBlock-    classify (ofs, text) =-        if cppLine text then CPPDirectives text else HaskellSource ofs text---- | Print the module.-prettyPrint :: Style-            -> Module SrcSpanInfo-            -> [Comment]-            -> Either a L.ByteString-prettyPrint style m comments =-    let (cs, ast) =-            annotateComments (fromMaybe m $ applyFixities baseFixities m)-                             comments-        csComments = map comInfoComment cs-    in-        Right (runPrinterStyle 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-                                    mapM_ (printComment Nothing)-                                          (reverse csComments)-                                    pretty ast))---- | Pretty print the given printable thing.-runPrinterStyle :: Style -> Printer () -> L.ByteString-runPrinterStyle (Style _name _author _desc st) m =-    maybe (error "Printer failed with mzero call.")-          (Buffer.toLazyByteString . psBuffer)-          (snd <$> execPrinter m-                               (PrintState Buffer.empty-                                           0-                                           0-                                           Map.empty-                                           st-                                           False-                                           Anything))+prettyPrint :: Printer a -> Config -> Maybe ByteString+prettyPrint printer = fmap (Buffer.toLazyByteString . psBuffer . snd)+    . execPrinter printer . initialPrintState  -- | Default extensions. defaultExtensions :: [Extension]@@ -214,9 +239,3 @@     , DoRec -- same     , TypeApplications -- since GHC 8 and haskell-src-exts-1.19     ]---- ,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
+ src/Floskell/Attoparsec.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE CPP #-}++module Floskell.Attoparsec ( Position, parseOnly ) where++import qualified Data.Attoparsec.ByteString as AP+import qualified Data.ByteString            as B+import           Data.Semigroup             as Sem+import           Data.Word                  ( Word8 )++data Position = Position { posLine :: !Int, posColumn :: !Int }+    deriving ( Eq, Ord, Show )++instance Sem.Semigroup Position where+    (Position l c) <> (Position l' c') =+        Position (l + l') (if l' > 0 then c' else c + c')++instance Monoid Position where+    mempty = Position 0 0++#if !(MIN_VERSION_base(4,11,0))+    mappend = (<>)+#endif++advance :: Position -> Word8 -> Position+advance (Position l _) 10 = Position (l + 1) 0+advance (Position l c) _ = Position l (c + 1)++position :: B.ByteString -> Position+position = B.foldl' advance mempty++positionAt :: B.ByteString -> B.ByteString -> Position+positionAt l r = position $ B.take (B.length l - B.length r) l++parseOnly :: AP.Parser a -> B.ByteString -> Either String a+parseOnly p b = case AP.feed (AP.parse p b) B.empty of+    AP.Done _ x -> Right x+    AP.Fail r _ err -> Left $ parseError (positionAt b r) err+    AP.Partial _ -> error "impossible"+  where+    parseError (Position l c) err = err ++ ", at line " ++ show (l + 1)+        ++ ", column " ++ show c
src/Floskell/Buffer.hs view
@@ -15,13 +15,11 @@ import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Lazy    as BL -import           Data.Int                ( Int64 )- data Buffer =     Buffer { bufferData        :: !Builder -- ^ The current output.            , bufferDataNoSpace :: !Builder -- ^ The current output without trailing spaces.-           , bufferLine        :: !Int64   -- ^ Current line number.-           , bufferColumn      :: !Int64   -- ^ Current column number.+           , bufferLine        :: !Int     -- ^ Current line number.+           , bufferColumn      :: !Int     -- ^ Current column number.            }  -- | An empty output buffer.@@ -39,7 +37,7 @@     buf { bufferData        = newBufferData         , bufferDataNoSpace =               if BS.all (== 32) str then bufferData buf else newBufferData-        , bufferColumn      = bufferColumn buf + fromIntegral (BS.length str)+        , bufferColumn      = bufferColumn buf + BS.length str         }   where     newBufferData = bufferData buf `mappend` BB.byteString str@@ -55,11 +53,11 @@     newBufferData = bufferDataNoSpace buf `mappend` BB.char7 '\n'  -- | Return the current line number, counting from 0.-line :: Buffer -> Int64+line :: Buffer -> Int line = bufferLine  -- | Return the column number, counting from 0.-column :: Buffer -> Int64+column :: Buffer -> Int column = bufferColumn  -- | Return the contents of the output buffer as a lazy ByteString.
src/Floskell/Comments.hs view
@@ -1,16 +1,16 @@ -- | Comment handling.-module Floskell.Comments where+module Floskell.Comments ( annotateWithComments ) where -import           Control.Arrow              ( first, second )+import           Control.Arrow                ( first, second ) import           Control.Monad.State.Strict -import           Data.Foldable              ( traverse_ )-import qualified Data.Map.Strict            as M+import           Data.Foldable                ( traverse_ )+import           Data.List                    ( isPrefixOf )+import qualified Data.Map.Strict              as M  import           Floskell.Types -import           Language.Haskell.Exts-                 hiding ( Pretty, Style, parse, prettyPrint, style )+import           Language.Haskell.Exts.SrcLoc ( SrcSpanInfo(..) )  -- Order by start of span, larger spans before smaller spans. newtype OrderByStart = OrderByStart SrcSpan@@ -34,84 +34,79 @@         `mappend` compare (srcSpanStartLine r) (srcSpanStartLine l)         `mappend` compare (srcSpanStartColumn r) (srcSpanStartColumn l) +onSameLine :: SrcSpan -> SrcSpan -> Bool+onSameLine ss ss' = srcSpanEndLine ss == srcSpanStartLine ss'++isAfterComment :: Comment -> Bool+isAfterComment (Comment PreprocessorDirective _ str) = "#endif" `isPrefixOf` str+isAfterComment (Comment _ _ str) =+    take 1 (dropWhile (== ' ') $ dropWhile (== '-') str) == "^"++isAlignedWith :: Comment -> Comment -> Bool+isAlignedWith (Comment _ before _) (Comment _ after _) =+    srcSpanEndLine before == srcSpanStartLine after - 1+    && srcSpanStartColumn before == srcSpanStartColumn after+ -- | Annotate the AST with comments.-annotateComments :: Traversable ast-                 => ast SrcSpanInfo-                 -> [Comment]-                 -> ([ComInfo], ast NodeInfo)-annotateComments src comments =+annotateWithComments+    :: Traversable ast => ast SrcSpanInfo -> [Comment] -> ast NodeInfo+annotateWithComments src comments =     evalState (do                    traverse_ assignComment comments-                   cis <- gets fst-                   ast <- traverse transferComments src-                   return (cis, ast))-              ([], nodeinfos)+                   traverse transferComments src)+              nodeinfos   where-    nodeinfos :: M.Map SrcSpanInfo NodeInfo-    nodeinfos = foldr (\ssi -> M.insert ssi (NodeInfo ssi [])) M.empty src+    nodeinfos :: M.Map SrcSpanInfo ([Comment], [Comment])+    nodeinfos = foldr (\ssi -> M.insert ssi ([], [])) M.empty src      -- Assign a single comment to the right AST node-    assignComment :: Comment-                  -> State ([ComInfo], M.Map SrcSpanInfo NodeInfo) ()-    assignComment comment@(Comment _ cspan _) =-        -- Find the biggest AST node directly in front of this comment.-        case nodeBefore comment of-            -- Comments before any AST node are handled separately.-            Nothing -> modify $ first $ (:) (ComInfo comment Nothing)--            Just ssi ->-                -- Comments on the same line as the AST node belong to this node.-                if sameline (srcInfoSpan ssi) cspan-                then insertComment After ssi-                else do-                    nodeinfo <- gets ((M.! ssi) . snd)-                    case nodeinfo of-                        -- We've already collected comments for this-                        -- node and this comment is a continuation.-                        NodeInfo _ (ComInfo c' _ : _)-                            | aligned c' comment -> insertComment After ssi+    assignComment+        :: Comment -> State (M.Map SrcSpanInfo ([Comment], [Comment])) ()+    assignComment comment@(Comment _ cspan _) = case surrounding comment of+        (Nothing, Nothing) -> error "No target nodes for comment"+        (Just before, Nothing) -> insertComment After before+        (Nothing, Just after) -> insertComment Before after+        (Just before, Just after) ->+            if srcInfoSpan before `onSameLine` cspan || isAfterComment comment+            then insertComment After before+            else do+                cmts <- gets (M.! before)+                case cmts of+                    -- We've already collected comments for this+                    -- node and this comment is a continuation.+                    (_, c' : _)+                        | c' `isAlignedWith` comment ->+                            insertComment After before -                        -- The comment does not belong to this node.-                        -- If there is a node following this comment,-                        -- assign it to that node, else keep it here,-                        -- anyway.-                        _ -> case nodeAfter comment of-                            Nothing -> insertComment After ssi-                            Just ssi' -> insertComment Before ssi'+                    -- The comment does not belong to this node.+                    -- If there is a node following this comment,+                    -- assign it to that node, else keep it here,+                    -- anyway.+                    _ -> insertComment Before after       where-        sameline :: SrcSpan -> SrcSpan -> Bool-        sameline before after = srcSpanEndLine before == srcSpanStartLine after--        aligned :: Comment -> Comment -> Bool-        aligned (Comment _ before _) (Comment _ after _) =-            srcSpanEndLine before == srcSpanStartLine after - 1-            && srcSpanStartColumn before == srcSpanStartColumn after-         insertComment :: Location                       -> SrcSpanInfo-                      -> State ([ComInfo], M.Map SrcSpanInfo NodeInfo) ()-        insertComment l ssi = modify $ second $-            M.adjust (addComment (ComInfo comment (Just l))) ssi--        addComment :: ComInfo -> NodeInfo -> NodeInfo-        addComment x (NodeInfo s xs) = NodeInfo s (x : xs)+                      -> State (M.Map SrcSpanInfo ([Comment], [Comment])) ()+        insertComment Before ssi = modify $ M.adjust (first (comment :)) ssi+        insertComment After ssi = modify $ M.adjust (second (comment :)) ssi      -- Transfer collected comments into the AST.-    transferComments :: SrcSpanInfo-                     -> State ([ComInfo], M.Map SrcSpanInfo NodeInfo) NodeInfo+    transferComments+        :: SrcSpanInfo+        -> State (M.Map SrcSpanInfo ([Comment], [Comment])) NodeInfo     transferComments ssi = do-        ni <- gets ((M.! ssi) . snd)+        (c, c') <- gets (M.! ssi)         -- Sometimes, there are multiple AST nodes with the same         -- SrcSpan.  Make sure we assign comments to only one of         -- them.-        modify $ second $ M.adjust (\(NodeInfo s _) -> NodeInfo s []) ssi-        return ni { nodeInfoComments = reverse $ nodeInfoComments ni }+        modify $ M.insert ssi ([], [])+        return $ NodeInfo (srcInfoSpan ssi) (reverse c) (reverse c') -    nodeBefore (Comment _ ss _) =-        fmap snd $ OrderByEnd ss `M.lookupLT` spansByEnd+    surrounding (Comment _ ss _) = (nodeBefore ss, nodeAfter ss) -    nodeAfter (Comment _ ss _) =-        fmap snd $ OrderByStart ss `M.lookupGT` spansByStart+    nodeBefore ss = fmap snd $ OrderByEnd ss `M.lookupLT` spansByEnd++    nodeAfter ss = fmap snd $ OrderByStart ss `M.lookupGT` spansByStart      spansByStart = foldr (\ssi -> M.insert (OrderByStart $ srcInfoSpan ssi) ssi)                          M.empty
src/Floskell/Config.hs view
@@ -17,10 +17,14 @@     , LayoutConfig(..)     , OpConfig(..)     , GroupConfig(..)+    , ImportsGroupOrder(..)+    , ImportsGroup(..)+    , SortImportsRule(..)+    , DeclarationConstruct(..)     , OptionConfig(..)-    , FlexConfig(..)-    , defaultFlexConfig-    , safeFlexConfig+    , Config(..)+    , defaultConfig+    , safeConfig     , cfgMapFind     , cfgOpWs     , cfgGroupWs@@ -39,6 +43,8 @@ import qualified Data.HashMap.Lazy  as HashMap import           Data.Map.Strict    ( Map ) import qualified Data.Map.Strict    as Map+import           Data.Set           ( Set )+import qualified Data.Set           as Set import qualified Data.Text          as T import qualified Data.Text.Encoding as T ( decodeUtf8, encodeUtf8 ) @@ -95,6 +101,7 @@                 , cfgAlignImportModule :: !Bool                 , cfgAlignImportSpec   :: !Bool                 , cfgAlignLetBinds     :: !Bool+                , cfgAlignMatches      :: !Bool                 , cfgAlignRecordFields :: !Bool                 , cfgAlignWhere        :: !Bool                 }@@ -107,6 +114,7 @@                       , cfgAlignImportModule = False                       , cfgAlignImportSpec   = False                       , cfgAlignLetBinds     = False+                      , cfgAlignMatches      = False                       , cfgAlignRecordFields = False                       , cfgAlignWhere        = False                       }@@ -126,6 +134,7 @@                  , cfgIndentLetBinds :: !Indent                  , cfgIndentLetIn :: !Indent                  , cfgIndentMultiIf :: !Indent+                 , cfgIndentTypesig :: !Indent                  , cfgIndentWhereBinds :: !Indent                  }     deriving ( Generic )@@ -145,6 +154,7 @@                        , cfgIndentLetBinds = IndentBy 4                        , cfgIndentLetIn = IndentBy 4                        , cfgIndentMultiIf = IndentBy 4+                       , cfgIndentTypesig = IndentBy 4                        , cfgIndentWhereBinds = IndentBy 2                        } @@ -159,7 +169,7 @@                  , cfgLayoutLet :: !Layout                  , cfgLayoutListComp :: !Layout                  , cfgLayoutRecord :: !Layout-                 , cfgLayoutTypesig :: !Layout+                 , cfgLayoutType :: !Layout                  }     deriving ( Generic ) @@ -174,7 +184,7 @@                        , cfgLayoutLet = Flex                        , cfgLayoutListComp = Flex                        , cfgLayoutRecord = Flex-                       , cfgLayoutTypesig = Flex+                       , cfgLayoutType = Flex                        }  newtype OpConfig = OpConfig { unOpConfig :: ConfigMap Whitespace }@@ -195,44 +205,66 @@                                 , cfgMapOverrides = Map.empty                                 } -data OptionConfig = OptionConfig { cfgOptionSortPragmas           :: !Bool-                                 , cfgOptionSplitLanguagePragmas  :: !Bool-                                 , cfgOptionSortImports           :: !Bool-                                 , cfgOptionSortImportLists       :: !Bool-                                 , cfgOptionPreserveVerticalSpace :: !Bool+data ImportsGroupOrder =+    ImportsGroupKeep | ImportsGroupSorted | ImportsGroupGrouped+    deriving ( Generic )++data ImportsGroup = ImportsGroup { importsPrefixes :: ![String]+                                 , importsOrder    :: !ImportsGroupOrder                                  }     deriving ( Generic ) +data SortImportsRule =+    NoImportSort | SortImportsByPrefix | SortImportsByGroups ![ImportsGroup]++data DeclarationConstruct = DeclModule | DeclClass | DeclInstance | DeclWhere+    deriving ( Eq, Ord, Generic )++data OptionConfig =+    OptionConfig { cfgOptionSortPragmas           :: !Bool+                 , cfgOptionSplitLanguagePragmas  :: !Bool+                 , cfgOptionSortImports           :: !SortImportsRule+                 , cfgOptionSortImportLists       :: !Bool+                 , cfgOptionAlignSumTypeDecl      :: !Bool+                 , cfgOptionFlexibleOneline       :: !Bool+                 , cfgOptionPreserveVerticalSpace :: !Bool+                 , cfgOptionDeclNoBlankLines      :: !(Set DeclarationConstruct)+                 }+    deriving ( Generic )+ instance Default OptionConfig where     def = OptionConfig { cfgOptionSortPragmas           = False                        , cfgOptionSplitLanguagePragmas  = False-                       , cfgOptionSortImports           = False+                       , cfgOptionSortImports           = NoImportSort                        , cfgOptionSortImportLists       = False+                       , cfgOptionAlignSumTypeDecl      = False+                       , cfgOptionFlexibleOneline       = False                        , cfgOptionPreserveVerticalSpace = False+                       , cfgOptionDeclNoBlankLines      = Set.empty                        } -data FlexConfig = FlexConfig { cfgPenalty :: !PenaltyConfig-                             , cfgAlign   :: !AlignConfig-                             , cfgIndent  :: !IndentConfig-                             , cfgLayout  :: !LayoutConfig-                             , cfgOp      :: !OpConfig-                             , cfgGroup   :: !GroupConfig-                             , cfgOptions :: !OptionConfig-                             }+data Config = Config { cfgPenalty :: !PenaltyConfig+                     , cfgAlign   :: !AlignConfig+                     , cfgIndent  :: !IndentConfig+                     , cfgLayout  :: !LayoutConfig+                     , cfgOp      :: !OpConfig+                     , cfgGroup   :: !GroupConfig+                     , cfgOptions :: !OptionConfig+                     }     deriving ( Generic ) -instance Default FlexConfig where-    def = FlexConfig { cfgPenalty = def-                     , cfgAlign   = def-                     , cfgIndent  = def-                     , cfgLayout  = def-                     , cfgOp      = def-                     , cfgGroup   = def-                     , cfgOptions = def-                     }+instance Default Config where+    def = Config { cfgPenalty = def+                 , cfgAlign   = def+                 , cfgIndent  = def+                 , cfgLayout  = def+                 , cfgOp      = def+                 , cfgGroup   = def+                 , cfgOptions = def+                 } -defaultFlexConfig :: FlexConfig-defaultFlexConfig =+defaultConfig :: Config+defaultConfig =     def { cfgOp = OpConfig ((unOpConfig def) { cfgMapOverrides =                                                    Map.fromList opWsOverrides                                              })@@ -248,8 +280,8 @@           )         ] -safeFlexConfig :: FlexConfig -> FlexConfig-safeFlexConfig cfg = cfg { cfgGroup = group, cfgOp = op }+safeConfig :: Config -> Config+safeConfig cfg = cfg { cfgGroup = group, cfgOp = op }   where     group = GroupConfig $         updateOverrides (unGroupConfig $ cfgGroup cfg)@@ -445,14 +477,44 @@ instance FromJSON GroupConfig where     parseJSON = genericParseJSON (recordOptions 0) +instance ToJSON ImportsGroupOrder where+    toJSON = genericToJSON (enumOptions 12)++instance FromJSON ImportsGroupOrder where+    parseJSON = genericParseJSON (enumOptions 12)++instance ToJSON ImportsGroup where+    toJSON = genericToJSON (recordOptions 7)++instance FromJSON ImportsGroup where+    parseJSON x@JSON.Array{} =+        ImportsGroup <$> parseJSON x <*> pure ImportsGroupKeep+    parseJSON x = genericParseJSON (recordOptions 7) x++instance ToJSON SortImportsRule where+    toJSON NoImportSort = toJSON False+    toJSON SortImportsByPrefix = toJSON True+    toJSON (SortImportsByGroups xs) = toJSON xs++instance FromJSON SortImportsRule where+    parseJSON (JSON.Bool False) = return NoImportSort+    parseJSON (JSON.Bool True) = return SortImportsByPrefix+    parseJSON v = SortImportsByGroups <$> parseJSON v++instance ToJSON DeclarationConstruct where+    toJSON = genericToJSON (enumOptions 4)++instance FromJSON DeclarationConstruct where+    parseJSON = genericParseJSON (enumOptions 4)+ instance ToJSON OptionConfig where     toJSON = genericToJSON (recordOptions 9)  instance FromJSON OptionConfig where     parseJSON = genericParseJSON (recordOptions 9) -instance ToJSON FlexConfig where+instance ToJSON Config where     toJSON = genericToJSON (recordOptions 3) -instance FromJSON FlexConfig where+instance FromJSON Config where     parseJSON = genericParseJSON (recordOptions 3)
+ src/Floskell/ConfigFile.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Floskell.ConfigFile+    ( AppConfig(..)+    , defaultAppConfig+    , findAppConfig+    , findAppConfigIn+    , readAppConfig+    , showStyle+    , showLanguage+    , showExtension+    , showFixity+    , lookupStyle+    , lookupLanguage+    , lookupExtension+    , lookupFixity+    , setStyle+    , setLanguage+    , setExtensions+    , setFixities+    ) where++import           Control.Applicative        ( (<|>) )++import           Data.Aeson+                 ( (.:?), (.=), FromJSON(..), ToJSON(..) )+import qualified Data.Aeson                 as JSON+import qualified Data.Aeson.Parser          as JSON ( json' )+import qualified Data.Aeson.Types           as JSON ( typeMismatch )+import qualified Data.Attoparsec.ByteString as AP+import qualified Data.ByteString            as BS+import           Data.Char                  ( isLetter, isSpace )+import qualified Data.HashMap.Lazy          as HashMap+import           Data.List                  ( inits )+import qualified Data.Text                  as T++import           Floskell.Attoparsec        ( parseOnly )+import           Floskell.Styles            ( Style(..), styles )++import           GHC.Generics               ( Generic )++import           Language.Haskell.Exts+                 ( Extension(..), Fixity(..), Language(..), classifyExtension+                 , classifyLanguage )+import qualified Language.Haskell.Exts      as HSE++import           System.Directory+                 ( XdgDirectory(..), doesFileExist, findFileWith+                 , getAppUserDataDirectory, getCurrentDirectory+                 , getHomeDirectory, getXdgDirectory )+import           System.FilePath+                 ( joinPath, splitDirectories, takeDirectory )++data AppConfig = AppConfig { appStyle      :: Style+                           , appLanguage   :: Language+                           , appExtensions :: [Extension]+                           , appFixities   :: [Fixity]+                           }+    deriving ( Generic )++instance ToJSON AppConfig where+    toJSON AppConfig{..} =+        JSON.object [ "style" .= showStyle appStyle+                    , "language" .= showLanguage appLanguage+                    , "extensions" .= map showExtension appExtensions+                    , "fixities" .= map showFixity appFixities+                    , "formatting" .= styleConfig appStyle+                    ]++instance FromJSON AppConfig where+    parseJSON (JSON.Object o) = do+        style <- maybe (appStyle defaultAppConfig) lookupStyle <$> o .:? "style"+        language <- maybe (appLanguage defaultAppConfig) lookupLanguage+            <$> o .:? "language"+        extensions <- maybe (appExtensions defaultAppConfig)+                            (map lookupExtension) <$> o .:? "extensions"+        fixities <- maybe (appFixities defaultAppConfig) (map lookupFixity)+            <$> o .:? "fixities"+        let fmt = styleConfig style+        fmt' <- maybe fmt (updateConfig fmt) <$> o .:? "formatting"+        let style' = style { styleConfig = fmt' }+        return $ AppConfig style' language extensions fixities+      where+        updateConfig cfg v = case JSON.fromJSON $ mergeJSON (toJSON cfg) v of+            JSON.Error e -> error e+            JSON.Success x -> x++        mergeJSON JSON.Null r = r+        mergeJSON l JSON.Null = l+        mergeJSON (JSON.Object l) (JSON.Object r) =+            JSON.Object (HashMap.unionWith mergeJSON l r)+        mergeJSON _ r = r++    parseJSON v = JSON.typeMismatch "AppConfig" v++-- | Default program configuration.+defaultAppConfig :: AppConfig+defaultAppConfig = AppConfig (head styles) Haskell2010 [] []++-- | Show name of a style.+showStyle :: Style -> String+showStyle = T.unpack . styleName++-- | Show a Haskell language name.+showLanguage :: Language -> String+showLanguage = show++-- | Show a Haskell language extension.+showExtension :: Extension -> String+showExtension (EnableExtension x) = show x+showExtension (DisableExtension x) = "No" ++ show x+showExtension (UnknownExtension x) = x++-- | Show a fixity declaration.+showFixity :: Fixity -> String+showFixity (Fixity assoc prec op) =+    showAssoc assoc ++ " " ++ show prec ++ " " ++ showOp op+  where+    showAssoc (HSE.AssocNone _) = "infix"+    showAssoc (HSE.AssocLeft _) = "infixl"+    showAssoc (HSE.AssocRight _) = "infixr"++    showOp (HSE.UnQual _ (HSE.Symbol _ symbol)) = symbol+    showOp (HSE.UnQual _ (HSE.Ident _ ident)) = "`" ++ ident ++ "`"+    showOp _ = error "Operator in fixity list not supported"++-- | Lookup a style by name.+lookupStyle :: String -> Style+lookupStyle name = case filter ((== T.pack name) . styleName) styles of+    [] -> error $ "Unknown style: " ++ name+    x : _ -> x++-- | Lookup a language by name.+lookupLanguage :: String -> Language+lookupLanguage name = case classifyLanguage name of+    UnknownLanguage _ -> error $ "Unknown language: " ++ name+    x -> x++-- | Lookup an extension by name.+lookupExtension :: String -> Extension+lookupExtension name = case classifyExtension name of+    UnknownExtension _ -> error $ "Unkown extension: " ++ name+    x -> x++-- | Parse a fixity declaration.+lookupFixity :: String -> Fixity+lookupFixity decl =+    let (assoc, decl') = break isSpace $ dropWhile isSpace decl+        (prec, decl'') = break isSpace $ dropWhile isSpace decl'+        (op, _) = break isSpace $ dropWhile isSpace decl''+    in+        Fixity (readAssoc assoc) (read prec) (readOp op)+  where+    readAssoc "infix" = HSE.AssocNone ()+    readAssoc "infixl" = HSE.AssocLeft ()+    readAssoc "infixr" = HSE.AssocRight ()+    readAssoc assoc = error $ "Unknown associativity: " ++ assoc++    readOp op = HSE.UnQual () $ case op of+        '(' : op' -> HSE.Symbol () (init op')+        '`' : op' -> HSE.Ident () (init op')+        c : _ -> if isLetter c then HSE.Ident () op else HSE.Symbol () op+        _ -> error "Missing operator in infix declaration"++-- | Try to find a configuration file based on current working+-- directory, or in one of the application configuration directories.+findAppConfig :: IO (Maybe FilePath)+findAppConfig = getCurrentDirectory >>= findAppConfigIn++findAppConfigIn :: FilePath -> IO (Maybe FilePath)+findAppConfigIn src = do+    isFile <- doesFileExist src+    let startFrom = if isFile then takeDirectory src else src++    dotfilePaths <- sequence [ getHomeDirectory, getXdgDirectory XdgConfig "" ]+    dotfileConfig <- findFileWith doesFileExist dotfilePaths ".floskell.json"+    userPaths <- sequence [ getAppUserDataDirectory "floskell"+                          , getXdgDirectory XdgConfig "floskell"+                          ]+    userConfig <- findFileWith doesFileExist userPaths "config.json"+    let localPaths =+            map joinPath . reverse . drop 1 . inits . splitDirectories $+            startFrom+    localConfig <- findFileWith doesFileExist localPaths "floskell.json"+    return $ localConfig <|> userConfig <|> dotfileConfig++-- | Load a configuration file.+readAppConfig :: FilePath -> IO AppConfig+readAppConfig file = do+    text <- BS.readFile file+    either (error . (++) (file ++ ": ")) return $ eitherDecodeStrict text++setStyle :: AppConfig -> Maybe String -> AppConfig+setStyle cfg mbStyle =+    cfg { appStyle = maybe (appStyle cfg) lookupStyle mbStyle }++setLanguage :: AppConfig -> Maybe String -> AppConfig+setLanguage cfg mbLanguage =+    cfg { appLanguage = maybe (appLanguage cfg) lookupLanguage mbLanguage }++setExtensions :: AppConfig -> [String] -> AppConfig+setExtensions cfg exts =+    cfg { appExtensions = appExtensions cfg ++ map lookupExtension exts }++setFixities :: AppConfig -> [String] -> AppConfig+setFixities cfg fixities =+    cfg { appFixities = appFixities cfg ++ map lookupFixity fixities }++eitherDecodeStrict :: FromJSON a => BS.ByteString -> Either String a+eitherDecodeStrict i = case parseOnly jsonEOF' i of+    Right x -> case JSON.fromJSON x of+        JSON.Error e -> Left e+        JSON.Success x' -> Right x'+    Left e -> Left e+  where+    jsonEOF' = JSON.json' <* skipSpace <* AP.endOfInput++    skipSpace =+        AP.skipWhile $ \w -> w == 0x20 || w == 0x0a || w == 0x0d || w == 0x09
+ src/Floskell/Fixities.hs view
@@ -0,0 +1,176 @@+-- DO NOT EDIT+-- Edit and run scripts/update-fixities to update the list of builtin fixities+module Floskell.Fixities ( builtinFixities, packageFixities ) where++import           Language.Haskell.Exts.Fixity+                 ( Fixity, baseFixities, infix_, infixl_, infixr_ )++builtinFixities :: [Fixity]+builtinFixities = concatMap snd packageFixities++packageFixities :: [(String, [Fixity])]+packageFixities = [ ("base", baseFixities)+                  , ("aeson", aesonFixities)+                  , ("conduit", conduitFixities)+                  , ("lens", lensFixities)+                  , ("pipes", pipesFixities)+                  , ("servant", servantFixities)+                  ]++aesonFixities :: [Fixity]+aesonFixities =+    -- Data/Aeson/Types/ToJSON.hs+    infixr_ 8 [ ".=" ]+    -- Data/Aeson/Encoding/Internal.hs+    ++ infixr_ 6 [ ">*<" ] ++ infixr_ 6 [ "><" ]+    -- Data/Aeson/TH.hs+    ++ infixr_ 6 [ "<^>" ] ++ infixr_ 4 [ "<%>" ]++conduitFixities :: [Fixity]+conduitFixities =+    -- src/Data/Conduit/Internal/Conduit.hs+    infixr_ 0 [ "$$" ] ++ infixl_ 1 [ "$=" ] ++ infixr_ 2 [ "=$" ]+    ++ infixr_ 2 [ "=$=" ] ++ infixr_ 0 [ "$$+" ] ++ infixr_ 0 [ "$$++" ]+    ++ infixr_ 0 [ "$$+-" ] ++ infixl_ 1 [ "$=+" ] ++ infixr_ 2 [ ".|" ]+    ++ infixr_ 0 [ "=$$+" ] ++ infixr_ 0 [ "=$$++" ] ++ infixr_ 0 [ "=$$+-" ]+    -- src/Data/Conduit/Internal/Pipe.hs+    ++ infixr_ 9 [ "<+<" ] ++ infixl_ 9 [ ">+>" ]++lensFixities :: [Fixity]+lensFixities =+    -- src/System/FilePath/Lens.hs+    infixr_ 4 [ "</>~", "<</>~", "<<</>~", "<.>~", "<<.>~", "<<<.>~" ]+    ++ infix_ 4 [ "</>=", "<</>=", "<<</>=", "<.>=", "<<.>=", "<<<.>=" ]+    -- src/Data/Bits/Lens.hs+    ++ infixr_ 4 [ ".|.~", ".&.~", "<.|.~", "<.&.~", "<<.|.~", "<<.&.~" ]+    ++ infix_ 4 [ ".|.=", ".&.=", "<.|.=", "<.&.=", "<<.|.=", "<<.&.=" ]+    -- src/Control/Lens/Fold.hs+    ++ infixl_ 8 [ "^..", "^?", "^?!", "^@..", "^@?", "^@?!" ]+    -- src/Control/Lens/Indexed.hs+    ++ infixr_ 9 [ "<.>", "<.", ".>" ]+    -- src/Control/Lens/Setter.hs+    ++ infixr_ 4+               [ "%@~"+               , ".@~"+               , ".~"+               , "+~"+               , "*~"+               , "-~"+               , "//~"+               , "^~"+               , "^^~"+               , "**~"+               , "&&~"+               , "<>~"+               , "||~"+               , "%~"+               , "<.~"+               , "?~"+               , "<?~"+               ]+    ++ infix_ 4+              [ "%@="+              , ".@="+              , ".="+              , "+="+              , "*="+              , "-="+              , "//="+              , "^="+              , "^^="+              , "**="+              , "&&="+              , "<>="+              , "||="+              , "%="+              , "<.="+              , "?="+              , "<?="+              ] ++ infixr_ 2 [ "<~" ]+    -- src/Control/Lens/Cons.hs+    ++ infixr_ 5 [ "<|", "`cons`" ] ++ infixl_ 5 [ "|>", "`snoc`" ]+    ++ infixr_ 5 [ ":<" ] ++ infixl_ 5 [ ":>" ]+    -- src/Control/Lens/Plated.hs+    ++ infixr_ 9 [ "..." ]+    -- src/Control/Lens/Getter.hs+    ++ infixl_ 8 [ "^.", "^@." ]+    -- src/Control/Lens/Zoom.hs+    ++ infixr_ 2 [ "`zoom`", "`magnify`" ]+    -- src/Control/Lens/Lens.hs+    ++ infixl_ 8 [ "^#" ]+    ++ infixr_ 4+               [ "%%@~"+               , "<%@~"+               , "<<%@~"+               , "%%~"+               , "<+~"+               , "<*~"+               , "<-~"+               , "<//~"+               , "<^~"+               , "<^^~"+               , "<**~"+               , "<&&~"+               , "<||~"+               , "<<>~"+               , "<%~"+               , "<<%~"+               , "<<.~"+               , "<<?~"+               , "<#~"+               , "#~"+               , "#%~"+               , "<#%~"+               , "#%%~"+               ]+    ++ infix_ 4+              [ "%%@="+              , "<%@="+              , "<<%@="+              , "%%="+              , "<+="+              , "<*="+              , "<-="+              , "<//="+              , "<^="+              , "<^^="+              , "<**="+              , "<&&="+              , "<||="+              , "<<>="+              , "<%="+              , "<<%="+              , "<<.="+              , "<<?="+              , "<#="+              , "#="+              , "#%="+              , "<#%="+              , "#%%="+              ] ++ infixr_ 2 [ "<<~" ] ++ infixl_ 1 [ "??", "&~" ]+    ++ infixl_ 1 [ "&" ] ++ infixl_ 1 [ "<&>" ]+    -- src/Control/Lens/Review.hs+    ++ infixr_ 8 [ "#" ]+    -- src/Control/Lens/Traversal.hs+    ++ infixl_ 5 [ "`failing`" ]++pipesFixities :: [Fixity]+pipesFixities =+    -- src/Pipes.hs+    infixl_ 4 [ "<~" ] ++ infixr_ 4 [ "~>" ] ++ infixl_ 5 [ "~<" ]+    ++ infixr_ 5 [ ">~" ] ++ infixl_ 7 [ ">->" ] ++ infixr_ 7 [ "<-<" ]+    -- src/Pipes/Core.hs+    ++ infixl_ 3 [ "//>" ] ++ infixr_ 3 [ "<\\\\" ]+    ++ infixr_ 4 [ "/>/", ">\\\\" ] ++ infixl_ 4 [ "\\<\\", "//<" ]+    ++ infixl_ 5 [ "\\>\\" ] ++ infixr_ 5 [ "/</" ] ++ infixl_ 6 [ "<<+" ]+    ++ infixr_ 6 [ "+>>" ] ++ infixl_ 7 [ ">+>", ">>~" ]+    ++ infixr_ 7 [ "<+<", "~<<" ] ++ infixl_ 8 [ "<~<" ] ++ infixr_ 8 [ ">~>" ]++servantFixities :: [Fixity]+servantFixities =+    -- src/Servant/API/Sub.hs+    infixr_ 4 [ ":>" ]+    -- src/Servant/API/Alternative.hs+    ++ infixr_ 3 [ ":<|>" ]+    -- src/Servant/API/Generic.hs+    ++ infixl_ 0 [ ":-" ]
+ src/Floskell/Imports.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE TupleSections #-}++module Floskell.Imports ( sortImports, groupImports, splitImports ) where++import           Control.Monad.Trans.State    ( State, execState, gets, modify )++import           Data.Function                ( on )+import           Data.List+                 ( groupBy, inits, intercalate, sortOn, sortOn, unfoldr )+import qualified Data.Map                     as M+import           Data.Monoid                  ( First(..) )++import           Floskell.Config+                 ( ImportsGroup(..), ImportsGroupOrder(..) )++import           Language.Haskell.Exts.Syntax ( ImportDecl(..), ModuleName(..) )++moduleName :: ImportDecl a -> String+moduleName i = case importModule i of+    (ModuleName _ s) -> s++splitOn :: Char -> String -> [String]+splitOn c = unfoldr go+  where+    go [] = Nothing+    go x = Just $ drop 1 <$> break (== c) x++modulePrefixes :: String -> [String]+modulePrefixes = map (intercalate ".") . reverse . inits . splitOn '.'++data St a = St { stIndex  :: M.Map String Int+               , stGroups :: M.Map Int (ImportsGroup, [ImportDecl a])+               , stRest   :: [ImportDecl a]+               }++commonPrefixLength :: Eq a => [[a]] -> Int+commonPrefixLength = go 0+  where+    go l [] = l+    go l ([] : _) = l+    go l ((x : xs) : ys) =+        if all ((== [ x ]) . take 1) ys then go (l + 1) (xs : ys) else l++sortImports :: [ImportDecl a] -> [ImportDecl a]+sortImports = sortOn moduleName++groupImports :: Int -> [ImportDecl a] -> [[ImportDecl a]]+groupImports n = groupBy ((==) `on` prefix n)+  where+    prefix l = take 1 . drop l . splitOn '.' . moduleName++lookupFirst :: Ord a => [a] -> M.Map a b -> Maybe b+lookupFirst ks m = getFirst . mconcat $ map (First . (`M.lookup` m)) ks++placeImport :: ImportDecl a -> State (St a) ()+placeImport i = do+    idx <- gets (lookupFirst (modulePrefixes $ moduleName i) . stIndex)+    case idx of+        Just idx' -> modify $ \s -> s { stGroups = placeAt idx' (stGroups s) }+        Nothing -> modify $ \s -> s { stRest = stRest s ++ [ i ] }+  where+    placeAt = M.adjust (fmap (++ [ i ]))++splitImports :: [ImportsGroup] -> [ImportDecl a] -> [[ImportDecl a]]+splitImports groups imports = extract $+    execState (mapM_ placeImport imports) initial+  where+    initial = St { stIndex  = M.fromList . concat $+                       zipWith (\n g -> map (, n) (importsPrefixes g))+                               [ 0 .. ]+                               groups+                 , stGroups = M.fromList $+                       zipWith (\n g -> (n, (g, []))) [ 0 .. ] groups+                 , stRest   = []+                 }++    extract s = filter (not . null) $+        concatMap maybeSortAndGroup (M.elems $ stGroups s) ++ [ stRest s ]++    maybeSortAndGroup (g, is) = case importsOrder g of+        ImportsGroupKeep -> [ is ]+        ImportsGroupSorted -> [ sortImports is ]+        ImportsGroupGrouped -> groupImports (commonPrefixLength $+                                             importsPrefixes g) $ sortImports is
src/Floskell/Pretty.hs view
@@ -1,34 +1,33 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -module Floskell.Pretty where+module Floskell.Pretty ( Pretty(..), pretty ) where -import           Control.Applicative            ( (<|>) )+import           Control.Applicative          ( (<|>) ) import           Control.Monad                  ( forM_, guard, replicateM_, unless, void, when )-import           Control.Monad.State.Strict     ( get, gets, modify )--import           Data.ByteString                ( ByteString )-import qualified Data.ByteString                as BS-import qualified Data.ByteString.Char8          as BS8-import qualified Data.ByteString.Lazy           as BL+import           Control.Monad.State.Strict   ( get, gets, modify ) -import           Data.List                      ( groupBy, sortBy, sortOn )-import           Data.Maybe                     ( catMaybes, fromMaybe )+import           Data.Bool                    ( bool )+import           Data.ByteString              ( ByteString )+import qualified Data.ByteString              as BS+import qualified Data.ByteString.Char8        as BS8+import qualified Data.ByteString.Lazy         as BL+import           Data.List                    ( groupBy, sortBy, sortOn )+import           Data.Maybe                   ( catMaybes, fromMaybe )+import qualified Data.Set                     as Set -import qualified Floskell.Buffer                as Buffer+import qualified Floskell.Buffer              as Buffer import           Floskell.Config+import           Floskell.Imports+                 ( groupImports, sortImports, splitImports ) import           Floskell.Printers- import           Floskell.Types -import           Language.Haskell.Exts.Comments ( Comment(..) )-import qualified Language.Haskell.Exts.Pretty   as HSE--import           Language.Haskell.Exts.SrcLoc-                 ( SrcSpan(..), noSrcSpan, srcInfoSpan )+import qualified Language.Haskell.Exts.Pretty as HSE import           Language.Haskell.Exts.Syntax  -- | Like `span`, but comparing adjacent items.@@ -60,7 +59,9 @@            => (ast NodeInfo -> Maybe (ast NodeInfo, ast NodeInfo))            -> ast NodeInfo            -> [ast NodeInfo]-flattenApp fn = go . amap (\info -> info { nodeInfoComments = [] })+flattenApp fn = go . amap (\info -> info { nodeInfoLeadingComments  = []+                                         , nodeInfoTrailingComments = []+                                         })   where     go x = case fn x of         Just (lhs, rhs) -> let lhs' = go $ copyComments Before x lhs@@ -74,7 +75,9 @@     => (ast1 NodeInfo -> Maybe (ast1 NodeInfo, ast2 NodeInfo, ast1 NodeInfo))     -> ast1 NodeInfo     -> (ast1 NodeInfo, [(ast2 NodeInfo, ast1 NodeInfo)])-flattenInfix fn = go . amap (\info -> info { nodeInfoComments = [] })+flattenInfix fn = go . amap (\info -> info { nodeInfoLeadingComments  = []+                                           , nodeInfoTrailingComments = []+                                           })   where     go x = case fn x of         Just (lhs, op, rhs) ->@@ -84,27 +87,25 @@                 (lhs', ops ++ (op, lhs'') : ops')         Nothing -> (x, []) --- | Syntax shortcut for Pretty Printers.-type PrettyPrinter f = f NodeInfo -> Printer ()- -- | Pretty printing prettyHSE using haskell-src-exts pretty printer-prettyHSE :: HSE.Pretty (ast NodeInfo) => PrettyPrinter ast+prettyHSE :: HSE.Pretty (ast NodeInfo) => ast NodeInfo -> Printer () prettyHSE ast = string $ HSE.prettyPrint ast  -- | Type class for pretty-printable types. class Pretty ast where-    prettyPrint :: PrettyPrinter ast-    default prettyPrint :: HSE.Pretty (ast NodeInfo) => PrettyPrinter ast+    prettyPrint :: ast NodeInfo -> Printer ()+    default prettyPrint+        :: HSE.Pretty (ast NodeInfo) => ast NodeInfo -> Printer ()     prettyPrint = prettyHSE  -- | Pretty print a syntax tree with annotated comments-pretty :: (Annotated ast, Pretty ast) => PrettyPrinter ast+pretty :: (Annotated ast, Pretty ast) => ast NodeInfo -> Printer () pretty ast = do     printComments Before ast     prettyPrint ast     printComments After ast -prettyOnside :: (Annotated ast, Pretty ast) => PrettyPrinter ast+prettyOnside :: (Annotated ast, Pretty ast) => ast NodeInfo -> Printer () prettyOnside ast = do     eol <- gets psEolComment     when eol newline@@ -116,23 +117,15 @@             printComments After ast         else onside $ pretty ast --- | Empty NodeInfo-noNodeInfo :: NodeInfo-noNodeInfo = NodeInfo noSrcSpan []- -- | Compare two AST nodes ignoring the annotation-compareAST :: (Functor ast, Ord (ast ()))-           => ast NodeInfo-           -> ast NodeInfo-           -> Ordering+compareAST+    :: (Functor ast, Ord (ast ())) => ast NodeInfo -> ast NodeInfo -> Ordering compareAST a b = void a `compare` void b --- | Return comments with matching location.-filterComments :: Annotated a-               => (Maybe Location -> Bool)-               -> a NodeInfo-               -> [ComInfo]-filterComments f = filter (f . comInfoLocation) . nodeInfoComments . ann+-- | Return leading comments.+filterComments :: Annotated a => Location -> a NodeInfo -> [Comment]+filterComments Before = nodeInfoLeadingComments . ann+filterComments After = nodeInfoTrailingComments . ann  -- | Copy comments from one AST node to another. copyComments :: (Annotated ast1, Annotated ast2)@@ -140,63 +133,73 @@              -> ast1 NodeInfo              -> ast2 NodeInfo              -> ast2 NodeInfo-copyComments loc from to = amap updateComments to-  where-    updateComments info =-        info { nodeInfoComments = oldComments ++ newComments }--    oldComments = filterComments (/= Just loc) to--    newComments = filterComments (== Just loc) from+copyComments Before from to =+    amap (\n ->+          n { nodeInfoLeadingComments = nodeInfoLeadingComments $ ann from })+         to+copyComments After from to =+    amap (\n ->+          n { nodeInfoTrailingComments = nodeInfoTrailingComments $ ann from })+         to  -- | Pretty print a comment.-printComment :: Maybe SrcSpan -> Comment -> Printer ()-printComment mayNodespan (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-        Just nodespan -> do-            let neededSpaces = srcSpanStartColumn cspan-                    - max 1 (srcSpanEndColumn nodespan)-            replicateM_ neededSpaces space-        Nothing -> return ()--    if inline-        then do+printComment :: Int -> Comment -> Printer ()+printComment correction Comment{..} = do+    col <- getNextColumn+    let padding = max 0 $ srcSpanStartColumn commentSpan + correction - col+    case commentType of+        PreprocessorDirective -> do+            nl <- gets psNewline+            unless nl newline+            column 0 $ string commentText+            modify (\s -> s { psEolComment = True })+        InlineComment -> do+            write $ BS.replicate padding 32             write "{-"-            string str+            string commentText             write "-}"-            when (1 == srcSpanStartColumn cspan) $+            when (1 == srcSpanStartColumn commentSpan) $                 modify (\s -> s { psEolComment = True })-        else do+        LineComment -> do+            write $ BS.replicate padding 32             write "--"-            string str+            string commentText             modify (\s -> s { psEolComment = True })  -- | Print comments of a node. printComments :: Annotated ast => Location -> ast NodeInfo -> Printer ()-printComments loc' ast = do-    let correctLocation comment = comInfoLocation comment == Just loc'-        commentsWithLocation = filter correctLocation (nodeInfoComments info)-        comments = map comInfoComment commentsWithLocation+printComments = printCommentsInternal True -    unless (null comments) $ do-        -- Preceeding comments must have a newline before them, but not break onside indent.-        nl <- gets psNewline-        onside' <- gets psOnside-        when nl $ modify $ \s -> s { psOnside = 0 }-        when (loc' == Before && not nl) newline+-- | Print comments of a node, but do not force newline before leading comments.+printComments' :: Annotated ast => Location -> ast NodeInfo -> Printer ()+printComments' = printCommentsInternal False -        forM_ comments $ printComment (Just $ srcInfoSpan $ nodeInfoSpan info)+printCommentsInternal+    :: Annotated ast => Bool -> Location -> ast NodeInfo -> Printer ()+printCommentsInternal nlBefore loc ast = unless (null comments) $ do+    let firstComment = head comments+    -- Preceeding comments must have a newline before them, but not break onside indent.+    nl <- gets psNewline+    onside' <- gets psOnside+    when nl $ modify $ \s -> s { psOnside = 0 }+    when (loc == Before && not nl && nlBefore) newline+    when (loc == After && not nl && notSameLine firstComment) newline -        -- Write newline before restoring onside indent.-        eol <- gets psEolComment-        when (loc' == Before && eol && onside' > 0) newline-        when nl $ modify $ \s -> s { psOnside = onside' }+    col <- getNextColumn+    forM_ comments $ printComment (col - srcSpanEndColumn ssi)++    -- Write newline before restoring onside indent.+    eol <- gets psEolComment+    when (loc == Before && eol && onside' > 0) newline+    when nl $ modify $ \s -> s { psOnside = onside' }   where-    info = ann ast+    ssi = nodeSpan ast +    comments = filterComments loc ast++    notSameLine comment = srcSpanEndLine ssi+        < srcSpanStartLine (commentSpan comment)+ -- | Return the configuration name of an operator opName :: QOp a -> ByteString opName op = case op of@@ -205,14 +208,17 @@  -- | Return the configuration name of an operator opName' :: QName a -> ByteString-opName' (Qual _ _ (Ident _ _)) = "``"-opName' (Qual _ _ (Symbol _ _)) = ""-opName' (UnQual _ (Ident _ _)) = "``"-opName' (UnQual _ (Symbol _ str)) = BS8.pack str+opName' (Qual _ _ name) = opName'' name+opName' (UnQual _ name) = opName'' name opName' (Special _ (FunCon _)) = "->" opName' (Special _ (Cons _)) = ":" opName' (Special _ _) = "" +-- | Return the configuration name of an operator+opName'' :: Name a -> ByteString+opName'' (Ident _ _) = "``"+opName'' (Symbol _ str) = BS8.pack str+ lineDelta :: Annotated ast => ast NodeInfo -> ast NodeInfo -> Int lineDelta prev next = nextLine - prevLine   where@@ -220,19 +226,15 @@      nextLine = minimum (nextNodeLine : nextCommentLines) -    prevNodeLine = srcSpanEndLine $ annSrcSpan prev--    nextNodeLine = srcSpanStartLine $ annSrcSpan next--    annSrcSpan = srcInfoSpan . nodeInfoSpan . ann+    prevNodeLine = srcSpanEndLine $ nodeSpan prev -    prevCommentLines = map (srcSpanEndLine . commentSrcSpan) $-        filterComments (== Just After) prev+    nextNodeLine = srcSpanStartLine $ nodeSpan next -    nextCommentLines = map (srcSpanStartLine . commentSrcSpan) $-        filterComments (== Just Before) next+    prevCommentLines = map (srcSpanEndLine . commentSpan) $+        filterComments After prev -    commentSrcSpan = (\(Comment _ sp _) -> sp) . comInfoComment+    nextCommentLines = map (srcSpanStartLine . commentSpan) $+        filterComments Before next  linedFn :: Annotated ast         => (ast NodeInfo -> Printer ())@@ -256,39 +258,35 @@ linedOnside :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer () linedOnside = linedFn prettyOnside +listVOpLen :: LayoutContext -> ByteString -> Printer Int+listVOpLen ctx sep = do+    ws <- getConfig (cfgOpWs ctx sep . cfgOp)+    return $ if wsLinebreak After ws+             then 0+             else BS.length sep + if wsSpace After ws then 1 else 0+ listVinternal :: (Annotated ast, Pretty ast)               => LayoutContext               -> ByteString               -> [ast NodeInfo]               -> Printer ()-listVinternal ctx sep xs = aligned $ do-    ws <- getConfig (cfgOpWs ctx sep . cfgOp)-    nl <- gets psNewline-    col <- getNextColumn-    let correction = if wsLinebreak After ws || length xs < 2-                     then 0-                     else BS.length sep + if wsSpace After ws then 1 else 0-        extraIndent = if nl then correction else 0-        itemCol = col + fromIntegral extraIndent-        sepCol = itemCol - fromIntegral correction-    case xs of-        [] -> newline-        (x : xs') -> column itemCol $ do-            cut $ do-                printCommentsSimple Before x-                cut . onside $ prettyPrint x-                printCommentsSimple After x+listVinternal ctx sep xs = case xs of+    [] -> newline+    (x : xs') -> do+        nl <- gets psNewline+        col <- getNextColumn+        delta <- listVOpLen ctx sep+        let itemCol = if nl && length xs > 1 then col + delta else col+            sepCol = itemCol - delta+        column itemCol $ do+            printComments' Before x+            cut . onside $ prettyPrint x+            printComments After x             forM_ xs' $ \x' -> do                 printComments Before x'                 column sepCol $ operatorV ctx sep                 cut . onside $ prettyPrint x'                 printComments After x'-  where-    printCommentsSimple loc ast =-        let comments = map comInfoComment $ filterComments (== Just loc) ast-        in-            forM_ comments $-            printComment (Just . srcInfoSpan . nodeInfoSpan $ ann ast)  listH :: (Annotated ast, Pretty ast)       => LayoutContext@@ -344,7 +342,8 @@        -> ByteString        -> [ast NodeInfo]        -> Printer ()-listV' = listVinternal+listV' ctx sep xs =+    if length xs > 1 then listVinternal ctx sep xs else mapM_ pretty xs  list' :: (Annotated ast, Pretty ast)       => LayoutContext@@ -368,43 +367,58 @@     write open     write close -listAutoWrap ctx open close sep (x : xs) =-    aligned . groupH ctx open close . aligned $ do-        ws <- getConfig (cfgOpWs ctx sep . cfgOp)-        let correction = if wsLinebreak After ws-                         then 0-                         else BS.length sep + if wsSpace After ws then 1 else 0-        col <- getNextColumn-        pretty x-        forM_ xs $ \x' -> do-            printComments Before x'-            cut $ do-                column (col - fromIntegral correction) $ operator ctx sep-                prettyPrint x'-                printComments After x'+listAutoWrap ctx open close sep xs =+    aligned . groupH ctx open close $ listAutoWrap' ctx sep xs +listAutoWrap' :: (Annotated ast, Pretty ast)+              => LayoutContext+              -> ByteString+              -> [ast NodeInfo]+              -> Printer ()+listAutoWrap' _ _ [] = return ()+listAutoWrap' ctx sep (x : xs) = aligned $ do+    ws <- getConfig (cfgOpWs ctx sep . cfgOp)+    let correction = if wsLinebreak After ws+                     then 0+                     else BS.length sep + if wsSpace After ws then 1 else 0+    col <- getNextColumn+    pretty x+    forM_ xs $ \x' -> do+        printComments Before x'+        cut $ do+            column (col - correction) $ operator ctx sep+            prettyPrint x'+            printComments After x'+ measure :: Printer a -> Printer (Maybe Int) measure p = do     s <- get     let s' = s { psBuffer = Buffer.empty, psEolComment = False }     return $ case execPrinter (oneline p) s' of         Nothing -> Nothing-        Just (_, s'') -> Just . fromIntegral . (\x -> x - psIndentLevel s)+        Just (_, s'') -> Just . (\x -> x - psIndentLevel s) . fromIntegral             . BL.length . Buffer.toLazyByteString $ psBuffer s'' -measureDecl :: Decl NodeInfo -> Printer (Maybe [Int])-measureDecl (PatBind _ pat _ Nothing) = fmap (: []) <$> measure (pretty pat)-measureDecl (FunBind _ matches) = sequence <$> traverse measureMatch matches+measure' :: Printer a -> Printer (Maybe [Int])+measure' p = fmap (: []) <$> measure p++measureMatch :: Match NodeInfo -> Printer (Maybe [Int])+measureMatch (Match _ name pats _ Nothing) = measure' (prettyApp name pats)+measureMatch (InfixMatch _ pat name pats _ Nothing) = measure' go   where-    measureMatch (Match _ name pats _ Nothing) = measure $ do-        pretty name-        space-        inter space $ map pretty pats-    measureMatch (InfixMatch _ pat name pats _ Nothing) = measure $ do+    go = do         pretty pat-        pretty $ VarOp noNodeInfo name-        inter space $ map pretty pats-    measureMatch _ = return Nothing+        withOperatorFormatting Pattern+                               (opName'' name)+                               (prettyHSE $ VarOp noNodeInfo name)+                               id+        inter spaceOrNewline $ map pretty pats+measureMatch _ = return Nothing++measureDecl :: Decl NodeInfo -> Printer (Maybe [Int])+measureDecl (PatBind _ pat _ Nothing) = measure' (pretty pat)+measureDecl (FunBind _ matches) =+    fmap concat . sequence <$> traverse measureMatch matches measureDecl _ = return Nothing  measureClassDecl :: ClassDecl NodeInfo -> Printer (Maybe [Int])@@ -416,7 +430,7 @@ measureInstDecl _ = return Nothing  measureAlt :: Alt NodeInfo -> Printer (Maybe [Int])-measureAlt (Alt _ pat _ Nothing) = fmap (: []) <$> measure (pretty pat)+measureAlt (Alt _ pat _ Nothing) = measure' (pretty pat) measureAlt _ = return Nothing  withComputedTabStop :: TabStop@@ -447,25 +461,6 @@ moduleName :: ModuleName a -> String moduleName (ModuleName _ s) = s -nameLength :: Name a -> Int-nameLength (Ident _ i) = length i-nameLength (Symbol _ s) = 2 + length s--qnameLength :: QName a -> Int-qnameLength (Qual _ mname name) = length (moduleName mname) + nameLength name-    + 1-qnameLength (UnQual _ name) = nameLength name-qnameLength (Special _ con) = case con of-    UnitCon _ -> 2-    ListCon _ -> 2-    FunCon _ -> 2-    TupleCon _ boxed n -> 2 + n + case boxed of-        Boxed -> 2-        Unboxed -> 0-    Cons _ -> 1-    UnboxedSingleCon _ -> 5-    ExprHole _ -> 1- prettyPragmas :: [ModulePragma NodeInfo] -> Printer () prettyPragmas ps = do     splitP <- getOption cfgOptionSplitLanguagePragmas@@ -495,24 +490,20 @@                     else Nothing     withTabStops [ (stopImportModule, alignModule)                  , (stopImportSpec, alignSpec)-                 ] $ if sortP-                     then inter blankline . map lined . groupBy samePrefix $-                         sortOn (moduleName . importModule) is-                     else lined is+                 ] $ case sortP of+        NoImportSort -> lined is+        SortImportsByPrefix -> prettyGroups . groupImports 0 $ sortImports is+        SortImportsByGroups groups -> prettyGroups $ splitImports groups is   where-    samePrefix left right = prefix left == prefix right--    prefix = takeWhile (/= '.') . moduleName . importModule+    prettyGroups = inter blankline . map (inter newline . map (cut . pretty))  skipBlank :: Annotated ast           => (ast NodeInfo -> ast NodeInfo -> Bool)           -> ast NodeInfo           -> ast NodeInfo           -> Bool-skipBlank skip a b = skip a b && null (comments After a)-    && null (comments Before b)-  where-    comments loc = filterComments (== Just loc)+skipBlank skip a b = skip a b && null (filterComments After a)+    && null (filterComments Before b)  skipBlankAfterDecl :: Decl a -> Bool skipBlankAfterDecl a = case a of@@ -546,9 +537,13 @@  prettyDecls :: (Annotated ast, Pretty ast)             => (ast NodeInfo -> ast NodeInfo -> Bool)+            -> DeclarationConstruct             -> [ast NodeInfo]             -> Printer ()-prettyDecls fn = inter blankline . map lined . runs fn+prettyDecls fn dc = inter sep . map lined . runs fn+  where+    sep = bool blankline newline . Set.member dc+        =<< getOption cfgOptionDeclNoBlankLines  prettySimpleDecl :: (Annotated ast1, Pretty ast1, Annotated ast2, Pretty ast2)                  => ast1 NodeInfo@@ -568,12 +563,38 @@         pretty rhs  prettyConDecls :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer ()-prettyConDecls condecls = withLayout cfgLayoutConDecls flex vertical+prettyConDecls condecls = do+    alignedConDecls <- getOption cfgOptionAlignSumTypeDecl+    if alignedConDecls && length condecls > 1+        then withLayout cfgLayoutDeclaration flex' vertical'+        else withLayout cfgLayoutDeclaration flex vertical   where-    flex = listH' Declaration "|" condecls+    flex = do+        operator Declaration "="+        withLayout cfgLayoutConDecls flexDecls verticalDecls -    vertical = listV' Declaration "|" condecls+    flex' = withLayout cfgLayoutConDecls flexDecls' verticalDecls' +    vertical = do+        operatorV Declaration "="+        withLayout cfgLayoutConDecls flexDecls verticalDecls++    vertical' = withLayout cfgLayoutConDecls flexDecls' verticalDecls'++    flexDecls = listAutoWrap' Declaration "|" condecls++    flexDecls' = horizontalDecls' <|> verticalDecls'++    horizontalDecls' = do+        operatorH Declaration "="+        listH' Declaration "|" condecls++    verticalDecls = listV' Declaration "|" condecls++    verticalDecls' = do+        withOperatorFormattingV Declaration "|" (write "=") id+        listV' Declaration "|" condecls+ prettyForall :: (Annotated ast, Pretty ast) => [ast NodeInfo] -> Printer () prettyForall vars = do     write "forall "@@ -585,37 +606,21 @@               -> [ast NodeInfo]               -> Type NodeInfo               -> Printer ()-prettyTypesig ctx names ty = withLayout cfgLayoutTypesig flex vertical+prettyTypesig ctx names ty = do+    inter comma $ map pretty names+    atTabStop stopRecordField+    withIndentConfig cfgIndentTypesig align indentby   where-    flex = do-        inter comma $ map pretty names-        atTabStop stopRecordField+    align = alignOnOperator ctx "::" $ pretty ty++    indentby i = indentedBy i $ do         operator ctx "::"+        nl <- gets psNewline+        when nl $ do+            delta <- listVOpLen ctx "->"+            write $ BS.replicate delta 32         pretty ty -    vertical = do-        inter comma $ map pretty names-        atTabStop stopRecordField-        alignOnOperator ctx "::" $ pretty' ty--    pretty' (TyForall _ mtyvarbinds mcontext ty') = do-        forM_ mtyvarbinds $ \tyvarbinds -> do-            write "forall "-            inter space $ map pretty tyvarbinds-            withOperatorFormattingV Type "." (write "." >> space) id-        forM_ mcontext $ \context -> do-            case context of-                (CxSingle _ asst) -> pretty asst-                (CxTuple _ assts) -> list Type "(" ")" "," assts-                (CxEmpty _) -> write "()"-            operatorV Type "=>"-        pretty' ty'-    pretty' (TyFun _ ty' ty'') = do-        pretty ty'-        operatorV Type "->"-        pretty' ty''-    pretty' ty' = pretty ty'- prettyApp :: (Annotated ast1, Annotated ast2, Pretty ast1, Pretty ast2)           => ast1 NodeInfo           -> [ast2 NodeInfo]@@ -632,26 +637,32 @@         pretty fn         withIndent cfgIndentApp $ linedOnside args -prettyInfixApp :: (Annotated ast, Pretty ast, HSE.Pretty (op NodeInfo))-               => (op NodeInfo -> ByteString)-               -> LayoutContext-               -> (ast NodeInfo, [(op NodeInfo, ast NodeInfo)])-               -> Printer ()+prettyInfixApp+    :: (Annotated ast, Pretty ast, Annotated op, HSE.Pretty (op NodeInfo))+    => (op NodeInfo -> ByteString)+    -> LayoutContext+    -> (ast NodeInfo, [(op NodeInfo, ast NodeInfo)])+    -> Printer () prettyInfixApp nameFn ctx (lhs, args) =     withLayout cfgLayoutInfixApp flex vertical   where     flex = do         pretty lhs         forM_ args $ \(op, arg) -> cut $ do-            withOperatorFormatting ctx (nameFn op) (prettyHSE op) id+            withOperatorFormatting ctx (nameFn op) (prettyOp op) id             pretty arg      vertical = do         pretty lhs         forM_ args $ \(op, arg) -> do-            withOperatorFormattingV ctx (nameFn op) (prettyHSE op) id+            withOperatorFormattingV ctx (nameFn op) (prettyOp op) id             pretty arg +    prettyOp op = do+        printComments Before op+        prettyHSE op+        printComments After op+ prettyRecord :: (Annotated ast1, Pretty ast1, Annotated ast2, Pretty ast2)              => (ast2 NodeInfo -> Printer (Maybe Int))              -> LayoutContext@@ -704,7 +715,7 @@         catMaybes [ ifNotEmpty prettyPragmas pragmas                   , pretty <$> mhead                   , ifNotEmpty prettyImports imports-                  , ifNotEmpty (prettyDecls skipBlankDecl) decls+                  , ifNotEmpty (prettyDecls skipBlankDecl DeclModule) decls                   ]       where         ifNotEmpty f xs = if null xs then Nothing else Just (f xs)@@ -764,14 +775,13 @@         atTabStop stopImportSpec         withLayout cfgLayoutImportSpecList (flex specs') (vertical specs')       where-        flex imports = do-            when hiding $ write " hiding"-            space+        flex imports = withIndentFlex cfgIndentImportSpecList $ do+            when hiding $ write "hiding "             listAutoWrap Other "(" ")" "," imports          vertical imports = withIndent cfgIndentImportSpecList $ do             when hiding $ write "hiding "-            listAutoWrap Other "(" ")" "," imports+            listV Other "(" ")" "," imports  instance Pretty ImportSpec @@ -803,18 +813,9 @@         depend' (pretty dataornew) $ do             mapM_ pretty mcontext             pretty declhead-            unless (null qualcondecls) $-                withLayout cfgLayoutDeclaration flex vertical+            unless (null qualcondecls) $ prettyConDecls qualcondecls         mapM_ pretty derivings-      where-        flex = do-            operator Declaration "="-            prettyConDecls qualcondecls -        vertical = do-            operatorV Declaration "="-            prettyConDecls qualcondecls-     prettyPrint (GDataDecl _                            dataornew                            mcontext@@ -845,16 +846,8 @@     prettyPrint (DataInsDecl _ dataornew ty qualcondecls derivings) = do         depend' (pretty dataornew >> write " instance") $ do             pretty ty-            withLayout cfgLayoutDeclaration flex vertical-        mapM_ pretty derivings-      where-        flex = do-            operator Declaration "="             prettyConDecls qualcondecls--        vertical = do-            operatorV Declaration "="-            prettyConDecls qualcondecls+        mapM_ pretty derivings      prettyPrint (GDataInsDecl _ dataornew ty mkind gadtdecls derivings) = do         depend' (pretty dataornew >> write " instance") $ do@@ -880,7 +873,7 @@                                                             cfgAlignClass                                                             measureClassDecl                                                             decls $-                prettyDecls skipBlankClassDecl decls+                prettyDecls skipBlankClassDecl DeclClass decls      prettyPrint (InstDecl _ moverlap instrule minstdecls) = do         depend "instance" $ do@@ -890,18 +883,25 @@             write " where"             withIndent cfgIndentClass $                 withComputedTabStop stopRhs cfgAlignClass measureInstDecl decls $-                prettyDecls skipBlankInstDecl decls+                prettyDecls skipBlankInstDecl DeclInstance decls +#if MIN_VERSION_haskell_src_exts(1,20,0)     prettyPrint (DerivDecl _ mderivstrategy moverlap instrule) =         depend "deriving" $ do             mayM_ mderivstrategy $ withPostfix space pretty             write "instance "             mayM_ moverlap $ withPostfix space pretty             pretty instrule+#else+    prettyPrint (DerivDecl _ moverlap instrule) = depend "deriving" $ do+        write "instance "+        mayM_ moverlap $ withPostfix space pretty+        pretty instrule+#endif      prettyPrint (InfixDecl _ assoc mint ops) = onside $ do         pretty assoc-        mayM_ mint $ withPrefix space (int . fromIntegral)+        mayM_ mint $ withPrefix space int         space         inter comma $ map prettyHSE ops @@ -914,6 +914,22 @@     prettyPrint (TypeSig _ names ty) =         onside $ prettyTypesig Declaration names ty +#if MIN_VERSION_haskell_src_exts(1,21,0)+    prettyPrint (PatSynSig _+                           names+                           mtyvarbinds+                           mcontext+                           mtyvarbinds'+                           mcontext'+                           ty) = depend "pattern" $ do+        inter comma $ map pretty names+        operator Declaration "::"+        mapM_ prettyForall mtyvarbinds+        mayM_ mcontext pretty+        mapM_ prettyForall mtyvarbinds'+        mayM_ mcontext' pretty+        pretty ty+#elif MIN_VERSION_haskell_src_exts(1,20,0)     prettyPrint (PatSynSig _ names mtyvarbinds mcontext mcontext' ty) =         depend "pattern" $ do             inter comma $ map pretty names@@ -922,8 +938,20 @@             mayM_ mcontext pretty             mayM_ mcontext' pretty             pretty ty+#else+    prettyPrint (PatSynSig _ name mtyvarbinds mcontext mcontext' ty) =+        depend "pattern" $ do+            pretty name+            operator Declaration "::"+            mapM_ prettyForall mtyvarbinds+            mayM_ mcontext pretty+            mayM_ mcontext' pretty+            pretty ty+#endif -    prettyPrint (FunBind _ matches) = linedOnside matches+    prettyPrint (FunBind _ matches) =+        withComputedTabStop stopRhs cfgAlignMatches measureMatch matches $+        linedOnside matches      prettyPrint (PatBind _ pat rhs mbinds) = do         onside $ do@@ -1058,7 +1086,7 @@         write "where"         withIndent cfgIndentWhereBinds $             withComputedTabStop stopRhs cfgAlignWhere measureDecl decls $-            prettyDecls skipBlankDecl decls+            prettyDecls skipBlankDecl DeclWhere decls      prettyPrint (IPBinds _ ipbinds) = withIndentBy cfgIndentWhere $ do         write "where"@@ -1125,18 +1153,9 @@     prettyPrint (InsData _ dataornew ty qualcondecls derivings) =         depend' (pretty dataornew) $ do             pretty ty-            unless (null qualcondecls) $-                withLayout cfgLayoutDeclaration flex vertical+            unless (null qualcondecls) $ prettyConDecls qualcondecls             mapM_ pretty derivings-      where-        flex = do-            operator Declaration "="-            prettyConDecls qualcondecls -        vertical = do-            operatorV Declaration "="-            prettyConDecls qualcondecls-     prettyPrint (InsGData _ dataornew ty mkind gadtdecls derivings) = do         depend' (pretty dataornew) $ do             pretty ty@@ -1149,14 +1168,31 @@         mapM_ pretty derivings  instance Pretty Deriving where+#if MIN_VERSION_haskell_src_exts(1,20,0)     prettyPrint (Deriving _ mderivstrategy instrules) =         withIndentBy cfgIndentDeriving $ do             write "deriving "-            mayM_ mderivstrategy $ withPostfix space pretty+            prettyStratBefore             case instrules of                 [ i@IRule{} ] -> pretty i                 [ IParen _ i ] -> listAutoWrap Other "(" ")" "," [ i ]                 _ -> listAutoWrap Other "(" ")" "," instrules+            prettyStratAfter+      where+        (prettyStratBefore, prettyStratAfter) = case mderivstrategy of+#if MIN_VERSION_haskell_src_exts(1,21,0)+            Just x@DerivVia{} -> (return (), space *> pretty x)+#endif+            Just x -> (pretty x <* space, return ())+            _ -> (return (), return ())+#else+    prettyPrint (Deriving _ instrules) = withIndentBy cfgIndentDeriving $ do+        write "deriving "+        case instrules of+            [ i@IRule{} ] -> pretty i+            [ IParen _ i ] -> listAutoWrap Other "(" ")" "," [ i ]+            _ -> listAutoWrap Other "(" ")" "," instrules+#endif  instance Pretty ConDecl where     prettyPrint (ConDecl _ name types) = do@@ -1189,6 +1225,15 @@         pretty condecl  instance Pretty GadtDecl where+#if MIN_VERSION_haskell_src_exts(1,21,0)+    prettyPrint (GadtDecl _ name _ _ mfielddecls ty) = do+        pretty name+        operator Declaration "::"+        mayM_ mfielddecls $ \decls -> do+            prettyRecordFields len Declaration decls+            operator Type "->"+        pretty ty+#else     prettyPrint (GadtDecl _ name mfielddecls ty) = do         pretty name         operator Declaration "::"@@ -1196,29 +1241,41 @@             prettyRecordFields len Declaration decls             operator Type "->"         pretty ty+#endif       where         len (FieldDecl _ names _) = measure $ inter comma $ map pretty names  instance Pretty Match where     prettyPrint (Match _ name pats rhs mbinds) = do         onside $ do-            pretty name-            unless (null pats) $ do-                space-                inter space $ map pretty pats+            prettyApp name pats             atTabStop stopRhs             pretty rhs         mapM_ pretty mbinds      prettyPrint (InfixMatch _ pat name pats rhs mbinds) = do         onside $ do-            pretty pat-            pretty $ VarOp noNodeInfo name-            inter space $ map pretty pats+            withLayout cfgLayoutInfixApp flex vertical             atTabStop stopRhs             pretty rhs         mapM_ pretty mbinds+      where+        flex = do+            pretty pat+            withOperatorFormatting Pattern+                                   (opName'' name)+                                   (prettyHSE $ VarOp noNodeInfo name)+                                   id+            inter spaceOrNewline $ map pretty pats +        vertical = do+            pretty pat+            withOperatorFormattingV Pattern+                                    (opName'' name)+                                    (prettyHSE $ VarOp noNodeInfo name)+                                    id+            linedOnside pats+ instance Pretty Rhs where     prettyPrint (UnGuardedRhs _ expr) =         cut $ withLayout cfgLayoutDeclaration flex vertical@@ -1282,7 +1339,10 @@      prettyPrint (InfixA _ ty qname ty') = do         pretty ty-        pretty $ QVarOp noNodeInfo qname+        withOperatorFormatting Type+                               (opName' qname)+                               (prettyHSE $ QVarOp noNodeInfo qname)+                               id         pretty ty'      prettyPrint (IParam _ ipname ty) = prettyTypesig Declaration [ ipname ] ty@@ -1299,74 +1359,126 @@         mapM_ pretty mname  instance Pretty Type where-    prettyPrint (TyForall _ mtyvarbinds mcontext ty) = do-        mapM_ prettyForall mtyvarbinds-        mapM_ pretty mcontext-        pretty ty+    prettyPrint t = do+        layout <- gets psTypeLayout+        case layout of+            TypeFree -> withLayout cfgLayoutType flex vertical+            TypeFlex -> prettyF t+            TypeVertical -> prettyV t+      where+        flex = withTypeLayout TypeFlex $ prettyF t -    prettyPrint (TyFun _ ty ty') = do-        pretty ty-        operator Type "->"-        pretty ty'+        vertical = withTypeLayout TypeVertical $ prettyV t -    prettyPrint (TyTuple _ boxed tys) = case boxed of-        Unboxed -> list Type "(#" "#)" "," tys-        Boxed -> list Type "(" ")" "," tys+        withTypeLayout :: TypeLayout -> Printer () -> Printer ()+        withTypeLayout l p = do+            layout <- gets psTypeLayout+            modify $ \s -> s { psTypeLayout = l }+            p+            modify $ \s -> s { psTypeLayout = layout } -    prettyPrint (TyUnboxedSum _ tys) = list Type "(#" "#)" "|" tys+        prettyF (TyForall _ mtyvarbinds mcontext ty) = do+            mapM_ prettyForall mtyvarbinds+            mapM_ pretty mcontext+            pretty ty -    prettyPrint (TyList _ ty) = group Type "[" "]" $ pretty ty+        prettyF (TyFun _ ty ty') = do+            pretty ty+            operator Type "->"+            pretty ty' -    prettyPrint (TyParArray _ ty) = group Type "[:" ":]" $ pretty ty+        prettyF (TyTuple _ boxed tys) = case boxed of+            Unboxed -> list Type "(#" "#)" "," tys+            Boxed -> list Type "(" ")" "," tys -    prettyPrint (TyApp _ ty ty') = do-        pretty ty-        space-        pretty ty'+#if MIN_VERSION_haskell_src_exts(1,20,0)+        prettyF (TyUnboxedSum _ tys) = list Type "(#" "#)" "|" tys+#endif -    prettyPrint (TyVar _ name) = pretty name+        prettyF (TyList _ ty) = group Type "[" "]" $ pretty ty -    prettyPrint (TyCon _ qname) = pretty qname+        prettyF (TyParArray _ ty) = group Type "[:" ":]" $ pretty ty -    prettyPrint (TyParen _ ty) = parens $ pretty ty+        prettyF (TyApp _ ty ty') = do+            pretty ty+            space+            pretty ty' -    prettyPrint (TyInfix _ ty op ty') = do-        pretty ty-        withOperatorFormatting Type opname (prettyHSE op) id-        pretty ty'-      where-        opname = opName' $ case op of-            PromotedName _ qname -> qname-            UnpromotedName _ qname -> qname+        prettyF (TyVar _ name) = pretty name -    prettyPrint (TyKind _ ty kind) = do-        pretty ty-        operator Type "::"-        pretty kind+        prettyF (TyCon _ qname) = pretty qname -    prettyPrint t@(TyPromoted _ _promoted) = prettyHSE t+        prettyF (TyParen _ ty) = parens . withTypeLayout TypeFree $ pretty ty -    prettyPrint (TyEquals _ ty ty') = do-        pretty ty-        operator Type "~"-        pretty ty'+#if MIN_VERSION_haskell_src_exts(1,20,0)+        prettyF (TyInfix _ ty op ty') = do+            pretty ty+            withOperatorFormatting Type opname (prettyHSE op) id+            pretty ty'+          where+            opname = opName' $ case op of+                PromotedName _ qname -> qname+                UnpromotedName _ qname -> qname+#else+        prettyF (TyInfix _ ty qname ty') = do+            pretty ty+            withOperatorFormatting Type (opName' qname) (prettyHSE qname) id+            pretty ty'+#endif -    prettyPrint (TySplice _ splice) = pretty splice+        prettyF (TyKind _ ty kind) = do+            pretty ty+            operator Type "::"+            pretty kind -    prettyPrint (TyBang _ bangtype unpackedness ty) = do-        pretty unpackedness-        pretty bangtype-        pretty ty+        prettyF ty@(TyPromoted _ _promoted) = prettyHSE ty -    prettyPrint t@(TyWildCard _ _mname) = prettyHSE t+        prettyF (TyEquals _ ty ty') = do+            pretty ty+            operator Type "~"+            pretty ty' -    prettyPrint (TyQuasiQuote _ str str') = do-        write "["-        string str-        write "|"-        string str'-        write "|]"+        prettyF (TySplice _ splice) = pretty splice +        prettyF (TyBang _ bangtype unpackedness ty) = do+            pretty unpackedness+            pretty bangtype+            pretty ty++        prettyF ty@(TyWildCard _ _mname) = prettyHSE ty++        prettyF (TyQuasiQuote _ str str') = do+            write "["+            string str+            write "|"+            string str'+            write "|]"++#if MIN_VERSION_haskell_src_exts(1,21,0)+        prettyF (TyStar _) = write "*"+#endif++        prettyV (TyForall _ mtyvarbinds mcontext ty) = do+            forM_ mtyvarbinds $ \tyvarbinds -> do+                write "forall "+                inter space $ map pretty tyvarbinds+                withOperatorFormattingV Type "." (write "." >> space) id+            forM_ mcontext $ \context -> do+                case context of+                    (CxSingle _ asst) -> pretty asst+                    (CxTuple _ assts) -> list Type "(" ")" "," assts+                    (CxEmpty _) -> write "()"+                operatorV Type "=>"+            prettyV ty++        prettyV (TyFun _ ty ty') = do+            pretty ty+            operatorV Type "->"+            prettyV ty'++        prettyV ty = prettyF ty++#if !MIN_VERSION_haskell_src_exts(1,21,0) instance Pretty Kind where     prettyPrint (KindStar _) = write "*" @@ -1387,6 +1499,7 @@     prettyPrint (KindTuple _ kinds) = list Type "'(" ")" "," kinds      prettyPrint (KindList _ kind) = group Type "'[" "]" $ pretty kind+#endif  instance Pretty TyVarBind where     prettyPrint (KindedVar _ name kind) = parens $ do@@ -1402,6 +1515,11 @@         operator Type "="         pretty ty' +flexibleOneline :: Printer a -> Printer a+flexibleOneline p = do+    allowOneline <- getOption cfgOptionFlexibleOneline+    if allowOneline then ignoreOneline p else p+ instance Pretty Exp where     prettyPrint (Var _ qname) = pretty qname @@ -1439,8 +1557,9 @@         write "\\"         maybeSpace         inter space $ map pretty pats-        operator Expression "->"-        pretty expr+        flexibleOneline $ do+            operator Expression "->"+            pretty expr       where         maybeSpace = case pats of             PIrrPat{} : _ -> space@@ -1456,11 +1575,15 @@             write "in "             prettyOnside expr -        vertical = withIndentFlat cfgIndentLet "let" $ do-            withIndent cfgIndentLetBinds $ pretty (CompactBinds binds)-            newline-            write "in"-            withIndent cfgIndentLetIn $ pretty expr+        vertical = withIndentAfter cfgIndentLet+                                   (do+                                        write "let"+                                        withIndent cfgIndentLetBinds $+                                            pretty (CompactBinds binds))+                                   (do+                                        newline+                                        write "in"+                                        withIndent cfgIndentLetIn $ pretty expr)      prettyPrint (If _ expr expr' expr'') = withLayout cfgLayoutIf flex vertical       where@@ -1474,14 +1597,17 @@             write "else "             prettyOnside expr'' -        vertical = withIndentFlat cfgIndentIf "if " $ do-            prettyOnside expr-            newline-            write "then "-            prettyOnside expr'-            newline-            write "else "-            prettyOnside expr''+        vertical = withIndentAfter cfgIndentIf+                                   (do+                                        write "if "+                                        prettyOnside expr)+                                   (do+                                        newline+                                        write "then "+                                        prettyOnside expr'+                                        newline+                                        write "else "+                                        prettyOnside expr'')      prettyPrint (MultiIf _ guardedrhss) = do         write "if"@@ -1493,15 +1619,15 @@         write " of"         if null alts             then write " { }"-            else withIndent cfgIndentCase $-                withComputedTabStop stopRhs cfgAlignCase measureAlt alts $+            else flexibleOneline . withIndent cfgIndentCase+                . withComputedTabStop stopRhs cfgAlignCase measureAlt alts $                 lined alts -    prettyPrint (Do _ stmts) = do+    prettyPrint (Do _ stmts) = flexibleOneline $ do         write "do"         withIndent cfgIndentDo $ linedOnside stmts -    prettyPrint (MDo _ stmts) = do+    prettyPrint (MDo _ stmts) = flexibleOneline $ do         write "mdo"         withIndent cfgIndentDo $ linedOnside stmts @@ -1509,13 +1635,16 @@         Boxed -> list Expression "(" ")" "," exprs         Unboxed -> list Expression "(#" "#)" "," exprs +#if MIN_VERSION_haskell_src_exts(1,20,0)     prettyPrint (UnboxedSum _ before after expr) = group Expression "(#" "#)"         . inter space $ replicate before (write "|") ++ [ pretty expr ]         ++ replicate after (write "|")+#endif      prettyPrint (TupleSection _ boxed mexprs) = case boxed of-        Boxed -> list Expression "(" ")" "," $ map MayAst mexprs-        Unboxed -> list Expression "(#" "#)" "," $ map MayAst mexprs+        Boxed -> list Expression "(" ")" "," $ map (MayAst noNodeInfo) mexprs+        Unboxed -> list Expression "(#" "#)" "," $+            map (MayAst noNodeInfo) mexprs      prettyPrint (List _ exprs) = list Expression "[" "]" "," exprs @@ -1693,13 +1822,13 @@         prettyPragma "GENERATED" $             inter space                   [ string $ show str-                  , int $ fromIntegral a+                  , int a                   , write ":"-                  , int $ fromIntegral b+                  , int b                   , write "-"-                  , int $ fromIntegral c+                  , int c                   , write ":"-                  , int $ fromIntegral d+                  , int d                   ]         space         pretty expr@@ -1730,7 +1859,7 @@         operator Expression ">>-"         pretty expr' -    prettyPrint (LCase _ alts) = do+    prettyPrint (LCase _ alts) = flexibleOneline $ do         write "\\case"         if null alts             then write " { }"@@ -1738,6 +1867,10 @@                 withComputedTabStop stopRhs cfgAlignCase measureAlt alts $                 lined alts +#if !MIN_VERSION_haskell_src_exts(1,20,0)+    prettyPrint (ExprHole _) = write "_"+#endif+ instance Pretty Alt where     prettyPrint (Alt _ pat rhs mbinds) = do         onside $ do@@ -1764,7 +1897,7 @@     prettyPrint (PNPlusK _ name integer) = do         pretty name         operator Pattern "+"-        int integer+        int $ fromIntegral integer      prettyPrint p@(PInfixApp _ _ qname _) =         prettyInfixApp opName Pattern $ flattenInfix flattenPInfixApp p@@ -1781,9 +1914,11 @@         Boxed -> list Pattern "(" ")" "," pats         Unboxed -> list Pattern "(#" "#)" "," pats +#if MIN_VERSION_haskell_src_exts(1,20,0)     prettyPrint (PUnboxedSum _ before after pat) = group Pattern "(#" "#)"         . inter space $ replicate before (write "|") ++ [ pretty pat ]         ++ replicate after (write "|")+#endif      prettyPrint (PList _ pats) = list Pattern "[" "]" "," pats @@ -1843,7 +1978,9 @@         inter space $ map pretty rpats         write "%>" +#if MIN_VERSION_haskell_src_exts(1,20,0)     prettyPrint (PSplice _ splice) = pretty splice+#endif      prettyPrint (PQuasiQuote _ str str') = do         write "[$"@@ -2034,11 +2171,11 @@         parens $ prettyTypesig Declaration [ name ] ty  instance Pretty Activation where-    prettyPrint (ActiveFrom _ pass) = brackets . int $ fromIntegral pass+    prettyPrint (ActiveFrom _ pass) = brackets $ int pass      prettyPrint (ActiveUntil _ pass) = brackets $ do         write "~"-        int $ fromIntegral pass+        int pass  instance Pretty Annotation where     prettyPrint (Ann _ name expr) = do@@ -2068,7 +2205,9 @@     prettyPrint (ParenFormula _ booleanformula) = parens $ pretty booleanformula  -- Stick with HSE+#if MIN_VERSION_haskell_src_exts(1,20,0) instance Pretty DerivStrategy+#endif  instance Pretty DataOrNew @@ -2126,18 +2265,17 @@     prettyPrint (CompactBinds (IPBinds _ ipbinds)) =         aligned $ linedOnside ipbinds -newtype MayAst a l = MayAst (Maybe (a l))+data MayAst a l = MayAst l (Maybe (a l))  instance Functor a => Functor (MayAst a) where-    fmap _ (MayAst Nothing) = MayAst Nothing-    fmap f (MayAst (Just x)) = MayAst . Just $ fmap f x+    fmap f (MayAst l x) = MayAst (f l) (fmap (fmap f) x)  instance Annotated a => Annotated (MayAst a) where-    ann (MayAst Nothing) = undefined-    ann (MayAst (Just x)) = ann x+    ann (MayAst l x) = maybe l ann x -    amap _ (MayAst Nothing) = MayAst Nothing-    amap f (MayAst (Just x)) = MayAst . Just $ amap f x+    amap f (MayAst l x) = MayAst (f l) (fmap (amap f) x)  instance (Annotated a, Pretty a) => Pretty (MayAst a) where-    prettyPrint (MayAst x) = mapM_ pretty x+    prettyPrint (MayAst _ x) = mapM_ pretty x++{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
src/Floskell/Printers.hs view
@@ -5,13 +5,13 @@     , getOption     , cut     , oneline+    , ignoreOneline       -- * Basic printing     , write     , string     , int     , space     , newline-    , linebreak     , blankline     , spaceOrNewline       -- * Tab stops@@ -21,8 +21,10 @@     , mayM_     , withPrefix     , withPostfix+    , withIndentConfig     , withIndent-    , withIndentFlat+    , withIndentFlex+    , withIndentAfter     , withIndentBy     , withLayout     , inter@@ -31,6 +33,7 @@     , column     , aligned     , indented+    , indentedBy     , onside     , depend     , depend'@@ -56,17 +59,14 @@     ) where  import           Control.Applicative        ( (<|>) )- import           Control.Monad              ( guard, unless, when ) import           Control.Monad.Search       ( cost, winner )- import           Control.Monad.State.Strict ( get, gets, modify )  import           Data.ByteString            ( ByteString ) import qualified Data.ByteString            as BS import qualified Data.ByteString.Builder    as BB import qualified Data.ByteString.Lazy       as BL-import           Data.Int                   ( Int64 ) import           Data.List                  ( intersperse ) import qualified Data.Map.Strict            as Map import           Data.Monoid                ( (<>) )@@ -76,25 +76,24 @@ import           Floskell.Types  -- | Query part of the pretty printer config-getConfig :: (FlexConfig -> b) -> Printer b-getConfig f = f <$> gets psUserState+getConfig :: (Config -> b) -> Printer b+getConfig f = f <$> gets psConfig  -- | Query pretty printer options-getOption :: (OptionConfig -> Bool) -> Printer Bool+getOption :: (OptionConfig -> a) -> Printer a getOption f = getConfig (f . cfgOptions)  -- | Line penalty calculation-linePenalty :: Bool -> Int64 -> Printer Penalty+linePenalty :: Bool -> Int -> Printer Penalty linePenalty eol col = do     indentLevel <- gets psIndentLevel     config <- getConfig cfgPenalty     let maxcol = penaltyMaxLineLength config     let pLinebreak = onlyIf eol $ penaltyLinebreak config-    let pIndent = fromIntegral indentLevel * (penaltyIndent config)-    let pOverfull = onlyIf (col > fromIntegral maxcol) $ penaltyOverfull config-            * fromIntegral (col - fromIntegral maxcol)-            + penaltyOverfullOnce config-    return . fromIntegral $ pLinebreak + pIndent + pOverfull+    let pIndent = indentLevel * penaltyIndent config+    let pOverfull = onlyIf (col > maxcol) $ penaltyOverfull config+            * (col - maxcol) + penaltyOverfullOnce config+    return . Penalty $ pLinebreak + pIndent + pOverfull   where     onlyIf cond penalty = if cond then penalty else 0 @@ -106,37 +105,43 @@ cut :: Printer a -> Printer a cut = winner +closeEolComment :: Printer ()+closeEolComment = do+    eol <- gets psEolComment+    when eol newline+ withOutputRestriction :: OutputRestriction -> Printer a -> Printer a withOutputRestriction r p = do     orig <- gets psOutputRestriction-    modify $ \s -> s { psOutputRestriction = max orig r }+    modify $ \s -> s { psOutputRestriction = r }     result <- p     modify $ \s -> s { psOutputRestriction = orig }     return result  oneline :: Printer a -> Printer a oneline p = do-    eol <- gets psEolComment-    when eol $ newline+    closeEolComment     withOutputRestriction NoOverflowOrLinebreak p +ignoreOneline :: Printer a -> Printer a+ignoreOneline = withOutputRestriction Anything+ -- | Write out a string, updating the current position information. write :: ByteString -> Printer () write x = do-    eol <- gets psEolComment-    when eol newline+    closeEolComment     write' x   where     write' x' = do         state <- get-        let indentLevel = fromIntegral (psIndentLevel state)+        let indentLevel = psIndentLevel state             out = if psNewline state                   then BS.replicate indentLevel 32 <> x'                   else x'             buffer = psBuffer state-            newCol = Buffer.column buffer + fromIntegral (BS.length out)+            newCol = Buffer.column buffer + BS.length out         guard $ psOutputRestriction state == Anything || newCol-            < fromIntegral (penaltyMaxLineLength (cfgPenalty (psUserState state)))+            < penaltyMaxLineLength (cfgPenalty (psConfig state))         penalty <- linePenalty False newCol         when (penalty /= mempty) $ cost mempty penalty         modify (\s ->@@ -147,7 +152,7 @@ string = write . BL.toStrict . BB.toLazyByteString . BB.stringUtf8  -- | Write an integral.-int :: Integer -> Printer ()+int :: Int -> Printer () int = string . show  -- | Write a space.@@ -169,9 +174,6 @@                     , psEolComment = False                     }) -linebreak :: Printer ()-linebreak = return () <|> newline- blankline :: Printer () blankline = newline >> newline @@ -184,9 +186,7 @@     oldstops <- gets psTabStops     modify $ \s ->         s { psTabStops =-                foldr (\(k, v) ->-                       Map.alter (const $ fmap (\x -> col + fromIntegral x) v)-                                 k)+                foldr (\(k, v) -> Map.alter (const $ fmap (\x -> col + x) v) k)                       (psTabStops s)                       stops           }@@ -199,7 +199,7 @@     mstop <- gets (Map.lookup tabstop . psTabStops)     mayM_ mstop $ \stop -> do         col <- getNextColumn-        let padding = max 0 $ fromIntegral (stop - col)+        let padding = max 0 (stop - col)         write (BS.replicate padding 32)  mayM_ :: Maybe a -> (a -> Printer ()) -> Printer ()@@ -212,40 +212,48 @@ withPostfix :: Applicative f => f a -> (x -> f b) -> x -> f b withPostfix post f x = f x <* post -withIndent :: (IndentConfig -> Indent) -> Printer a -> Printer a-withIndent fn p = do+withIndentConfig+    :: (IndentConfig -> Indent) -> Printer a -> (Int -> Printer a) -> Printer a+withIndentConfig fn align indentby = do     cfg <- getConfig (fn . cfgIndent)     case cfg of         Align -> align         IndentBy i -> indentby i         AlignOrIndentBy i -> align <|> indentby i++withIndent :: (IndentConfig -> Indent) -> Printer a -> Printer a+withIndent fn p = withIndentConfig fn align indentby   where     align = do         space         aligned p -    indentby i = indent i $ do+    indentby i = indentedBy i $ do         newline         p -withIndentFlat :: (IndentConfig -> Indent)-               -> ByteString-               -> Printer a-               -> Printer a-withIndentFlat fn kw p = do-    cfg <- getConfig (fn . cfgIndent)-    case cfg of-        Align -> align-        IndentBy i -> indentby i-        AlignOrIndentBy i -> align <|> indentby i+withIndentFlex :: (IndentConfig -> Indent) -> Printer a -> Printer a+withIndentFlex fn p = withIndentConfig fn align indentby   where+    align = do+        space+        aligned p++    indentby i = indentedBy i $ do+        spaceOrNewline+        p++withIndentAfter+    :: (IndentConfig -> Indent) -> Printer () -> Printer a -> Printer a+withIndentAfter fn before p = withIndentConfig fn align indentby+  where     align = aligned $ do-        write kw+        withIndentation id before         p      indentby i = do-        write kw-        indent i p+        withIndentation id before+        indentedBy i p  withIndentBy :: (IndentConfig -> Int) -> Printer a -> Printer a withIndentBy fn = withIndent (IndentBy . fn)@@ -262,31 +270,27 @@ inter x = sequence_ . intersperse x  -- | Get the column for the next printed character.-getNextColumn :: Printer Int64+getNextColumn :: Printer Int getNextColumn = do     st <- get     return $ if psEolComment st              then psIndentLevel st + psOnside st              else max (psColumn st) (psIndentLevel st) +withIndentation :: ((Int, Int) -> (Int, Int)) -> Printer a -> Printer a+withIndentation f p = do+    prevIndent <- gets psIndentLevel+    prevOnside <- gets psOnside+    let (newIndent, newOnside) = f (prevIndent, prevOnside)+    modify (\s -> s { psIndentLevel = newIndent, psOnside = newOnside })+    r <- p+    modify (\s -> s { psIndentLevel = prevIndent, psOnside = prevOnside })+    return r+ -- | Set the (newline-) indent level to the given column for the given -- printer.-column :: Int64 -> Printer a -> Printer a-column i p = do-    level <- gets psIndentLevel-    onside' <- gets psOnside-    modify (\s -> s { psIndentLevel = i-                    , psOnside      = if i > level then 0 else onside'-                    })-    m <- p-    modify (\s -> s { psIndentLevel = level, psOnside = onside' })-    return m---- | Increase indentation level by n spaces for the given printer.-indent :: Int -> Printer a -> Printer a-indent i p = do-    level <- gets psIndentLevel-    column (level + fromIntegral i) p+column :: Int -> Printer a -> Printer a+column i = withIndentation $ \(l, o) -> (i, if i > l then 0 else o)  aligned :: Printer a -> Printer a aligned p = do@@ -298,21 +302,21 @@ indented :: Printer a -> Printer a indented p = do     i <- getConfig (cfgIndentOnside . cfgIndent)-    indent i p+    indentedBy i p +-- | Increase indentation level by n spaces for the given printer.+indentedBy :: Int -> Printer a -> Printer a+indentedBy i p = do+    level <- gets psIndentLevel+    column (level + i) p+ -- | Increase indentation level b n spaces for the given printer, but -- ignore increase when computing further indentations. onside :: Printer a -> Printer a onside p = do-    eol <- gets psEolComment-    when eol newline+    closeEolComment     onsideIndent <- getConfig (cfgIndentOnside . cfgIndent)-    level <- gets psIndentLevel-    onside' <- gets psOnside-    modify (\s -> s { psOnside = fromIntegral onsideIndent })-    m <- p-    modify (\s -> s { psIndentLevel = level, psOnside = onside' })-    return m+    withIndentation (\(l, _) -> (l, onsideIndent)) p  depend :: ByteString -> Printer a -> Printer a depend kw = depend' (write kw)@@ -407,9 +411,7 @@                         -> Printer a withOperatorFormattingH ctx op opp fn = do     ws <- getConfig (cfgOpWs ctx op . cfgOp)-    nl <- gets psNewline-    eol <- gets psEolComment-    when (wsSpace Before ws && not nl && not eol) space+    when (wsSpace Before ws) space     fn $ do         opp         when (wsSpace After ws) space@@ -421,11 +423,7 @@                         -> Printer a withOperatorFormattingV ctx op opp fn = do     ws <- getConfig (cfgOpWs ctx op . cfgOp)-    nl <- gets psNewline-    eol <- gets psEolComment-    if wsLinebreak Before ws-        then newline-        else when (wsSpace Before ws && not nl && not eol) space+    if wsLinebreak Before ws then newline else when (wsSpace Before ws) space     fn $ do         opp         if wsLinebreak After ws then newline else when (wsSpace After ws) space
src/Floskell/Styles.hs view
@@ -1,16 +1,25 @@ {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} -module Floskell.Styles ( styles ) where+module Floskell.Styles ( Style(..), styles ) where  import qualified Data.Map        as Map+import qualified Data.Set        as Set+import           Data.Text       ( Text )  import           Floskell.Config-import           Floskell.Types -chrisDoneCfg :: FlexConfig-chrisDoneCfg = safeFlexConfig $-    defaultFlexConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions }+-- | A printer style.+data Style =+    Style { styleName        :: !Text   -- ^ Name of the style, used in the commandline interface.+          , styleAuthor      :: !Text   -- ^ Author of the style definition.+          , styleDescription :: !Text   -- ^ Description of the style.+          , styleConfig      :: !Config -- ^ Style definition.+          }++chrisDoneCfg :: Config+chrisDoneCfg = safeConfig $+    defaultConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions }   where     cfgIndent =         IndentConfig { cfgIndentOnside = 2@@ -25,9 +34,10 @@                      , cfgIndentLetBinds = Align                      , cfgIndentLetIn = Align                      , cfgIndentMultiIf = IndentBy 2+                     , cfgIndentTypesig = Align                      , cfgIndentWhereBinds = Align                      , cfgIndentExportSpecList = IndentBy 2-                     , cfgIndentImportSpecList = IndentBy 7+                     , cfgIndentImportSpecList = AlignOrIndentBy 7                      }      cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline@@ -35,12 +45,12 @@                              , cfgLayoutDeclaration = TryOneline                              , cfgLayoutExportSpecList = TryOneline                              , cfgLayoutIf = Vertical-                             , cfgLayoutImportSpecList = TryOneline+                             , cfgLayoutImportSpecList = Flex                              , cfgLayoutInfixApp = TryOneline                              , cfgLayoutLet = Vertical                              , cfgLayoutListComp = Flex                              , cfgLayoutRecord = Vertical-                             , cfgLayoutTypesig = TryOneline+                             , cfgLayoutType = TryOneline                              }      cfgOp =@@ -51,7 +61,7 @@     opWsOverrides =         [ (ConfigMapKey (Just ",") Nothing, Whitespace WsNone WsBefore False)         , ( ConfigMapKey (Just "record") Nothing-          , Whitespace WsAfter WsAfter False+          , Whitespace WsAfter WsNone False           )         , ( ConfigMapKey (Just ".") (Just Type)           , Whitespace WsAfter WsAfter False@@ -71,20 +81,23 @@      cfgOptions = OptionConfig { cfgOptionSortPragmas           = False                               , cfgOptionSplitLanguagePragmas  = False-                              , cfgOptionSortImports           = False+                              , cfgOptionSortImports           = NoImportSort                               , cfgOptionSortImportLists       = False+                              , cfgOptionAlignSumTypeDecl      = True+                              , cfgOptionFlexibleOneline       = False                               , cfgOptionPreserveVerticalSpace = False+                              , cfgOptionDeclNoBlankLines      = Set.empty                               } -cramerCfg :: FlexConfig-cramerCfg = safeFlexConfig $-    defaultFlexConfig { cfgAlign-                      , cfgIndent-                      , cfgLayout-                      , cfgOp-                      , cfgGroup-                      , cfgOptions-                      }+cramerCfg :: Config+cramerCfg = safeConfig $+    defaultConfig { cfgAlign+                  , cfgIndent+                  , cfgLayout+                  , cfgOp+                  , cfgGroup+                  , cfgOptions+                  }   where     cfgAlign = AlignConfig { cfgAlignLimits       = (10, 25)                            , cfgAlignCase         = False@@ -92,6 +105,7 @@                            , cfgAlignImportModule = True                            , cfgAlignImportSpec   = True                            , cfgAlignLetBinds     = False+                           , cfgAlignMatches      = False                            , cfgAlignRecordFields = True                            , cfgAlignWhere        = False                            }@@ -109,6 +123,7 @@                      , cfgIndentLetBinds = Align                      , cfgIndentLetIn = IndentBy 4                      , cfgIndentMultiIf = IndentBy 4+                     , cfgIndentTypesig = Align                      , cfgIndentWhereBinds = IndentBy 2                      , cfgIndentExportSpecList = IndentBy 4                      , cfgIndentImportSpecList = AlignOrIndentBy 17@@ -119,12 +134,12 @@                              , cfgLayoutDeclaration = Flex                              , cfgLayoutExportSpecList = TryOneline                              , cfgLayoutIf = TryOneline-                             , cfgLayoutImportSpecList = TryOneline+                             , cfgLayoutImportSpecList = Flex                              , cfgLayoutInfixApp = Flex                              , cfgLayoutLet = TryOneline                              , cfgLayoutListComp = TryOneline                              , cfgLayoutRecord = TryOneline-                             , cfgLayoutTypesig = TryOneline+                             , cfgLayoutType = TryOneline                              }      cfgOp =@@ -176,22 +191,26 @@           )         ] -    cfgOptions = OptionConfig { cfgOptionSortPragmas           = True-                              , cfgOptionSplitLanguagePragmas  = True-                              , cfgOptionSortImports           = True-                              , cfgOptionSortImportLists       = True-                              , cfgOptionPreserveVerticalSpace = True-                              }+    cfgOptions =+        OptionConfig { cfgOptionSortPragmas           = True+                     , cfgOptionSplitLanguagePragmas  = True+                     , cfgOptionSortImports           = SortImportsByPrefix+                     , cfgOptionSortImportLists       = True+                     , cfgOptionAlignSumTypeDecl      = False+                     , cfgOptionFlexibleOneline       = False+                     , cfgOptionPreserveVerticalSpace = True+                     , cfgOptionDeclNoBlankLines      = Set.empty+                     } -gibianskyCfg :: FlexConfig-gibianskyCfg = safeFlexConfig $-    defaultFlexConfig { cfgAlign-                      , cfgIndent-                      , cfgLayout-                      , cfgOp-                      , cfgGroup-                      , cfgOptions-                      }+gibianskyCfg :: Config+gibianskyCfg = safeConfig $+    defaultConfig { cfgAlign+                  , cfgIndent+                  , cfgLayout+                  , cfgOp+                  , cfgGroup+                  , cfgOptions+                  }   where     cfgAlign = AlignConfig { cfgAlignLimits       = (10, 25)                            , cfgAlignCase         = True@@ -199,6 +218,7 @@                            , cfgAlignImportModule = True                            , cfgAlignImportSpec   = False                            , cfgAlignLetBinds     = False+                           , cfgAlignMatches      = False                            , cfgAlignRecordFields = False                            , cfgAlignWhere        = False                            }@@ -216,9 +236,10 @@                      , cfgIndentLetBinds = Align                      , cfgIndentLetIn = Align                      , cfgIndentMultiIf = IndentBy 2+                     , cfgIndentTypesig = Align                      , cfgIndentWhereBinds = IndentBy 2                      , cfgIndentExportSpecList = IndentBy 4-                     , cfgIndentImportSpecList = IndentBy 4+                     , cfgIndentImportSpecList = Align                      }      cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline@@ -231,7 +252,7 @@                              , cfgLayoutLet = Vertical                              , cfgLayoutListComp = TryOneline                              , cfgLayoutRecord = TryOneline-                             , cfgLayoutTypesig = TryOneline+                             , cfgLayoutType = TryOneline                              }      cfgOp =@@ -242,7 +263,7 @@     opWsOverrides =         [ (ConfigMapKey (Just ",") Nothing, Whitespace WsAfter WsBefore False)         , ( ConfigMapKey (Just "record") Nothing-          , Whitespace WsAfter WsAfter False+          , Whitespace WsAfter WsNone False           )         , ( ConfigMapKey (Just ".") (Just Type)           , Whitespace WsAfter WsAfter False@@ -262,14 +283,17 @@      cfgOptions = OptionConfig { cfgOptionSortPragmas           = False                               , cfgOptionSplitLanguagePragmas  = False-                              , cfgOptionSortImports           = False+                              , cfgOptionSortImports           = NoImportSort                               , cfgOptionSortImportLists       = False+                              , cfgOptionAlignSumTypeDecl      = False+                              , cfgOptionFlexibleOneline       = False                               , cfgOptionPreserveVerticalSpace = False+                              , cfgOptionDeclNoBlankLines      = Set.empty                               } -johanTibellCfg :: FlexConfig-johanTibellCfg = safeFlexConfig $-    defaultFlexConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions }+johanTibellCfg :: Config+johanTibellCfg = safeConfig $+    defaultConfig { cfgIndent, cfgLayout, cfgOp, cfgGroup, cfgOptions }   where     cfgIndent =         IndentConfig { cfgIndentOnside = 4@@ -284,9 +308,10 @@                      , cfgIndentLetBinds = Align                      , cfgIndentLetIn = Align                      , cfgIndentMultiIf = IndentBy 2+                     , cfgIndentTypesig = Align                      , cfgIndentWhereBinds = IndentBy 2                      , cfgIndentExportSpecList = IndentBy 2-                     , cfgIndentImportSpecList = IndentBy 7+                     , cfgIndentImportSpecList = AlignOrIndentBy 7                      }      cfgLayout = LayoutConfig { cfgLayoutApp = TryOneline@@ -294,12 +319,12 @@                              , cfgLayoutDeclaration = TryOneline                              , cfgLayoutExportSpecList = TryOneline                              , cfgLayoutIf = Vertical-                             , cfgLayoutImportSpecList = TryOneline+                             , cfgLayoutImportSpecList = Flex                              , cfgLayoutInfixApp = TryOneline                              , cfgLayoutLet = Vertical                              , cfgLayoutListComp = Flex                              , cfgLayoutRecord = Vertical-                             , cfgLayoutTypesig = TryOneline+                             , cfgLayoutType = TryOneline                              }      cfgOp =@@ -345,45 +370,48 @@      cfgOptions = OptionConfig { cfgOptionSortPragmas           = False                               , cfgOptionSplitLanguagePragmas  = False-                              , cfgOptionSortImports           = False+                              , cfgOptionSortImports           = NoImportSort                               , cfgOptionSortImportLists       = False+                              , cfgOptionAlignSumTypeDecl      = True+                              , cfgOptionFlexibleOneline       = True                               , cfgOptionPreserveVerticalSpace = False+                              , cfgOptionDeclNoBlankLines      = Set.empty                               }  -- | Base style definition. base :: Style-base = Style { styleName         = "base"-             , styleAuthor       = "Enno Cramer"-             , styleDescription  = "Configurable formatting style"-             , styleInitialState = safeFlexConfig defaultFlexConfig+base = Style { styleName        = "base"+             , styleAuthor      = "Enno Cramer"+             , styleDescription = "Configurable formatting style"+             , styleConfig      = safeConfig defaultConfig              }  chrisDone :: Style-chrisDone = Style { styleName         = "chris-done"-                  , styleAuthor       = "Chris Done"-                  , styleDescription  = "Chris Done's style"-                  , styleInitialState = chrisDoneCfg+chrisDone = Style { styleName        = "chris-done"+                  , styleAuthor      = "Chris Done"+                  , styleDescription = "Chris Done's style"+                  , styleConfig      = chrisDoneCfg                   }  cramer :: Style-cramer = Style { styleName         = "cramer"-               , styleAuthor       = "Enno Cramer"-               , styleDescription  = "Enno Cramer's style"-               , styleInitialState = cramerCfg+cramer = Style { styleName        = "cramer"+               , styleAuthor      = "Enno Cramer"+               , styleDescription = "Enno Cramer's style"+               , styleConfig      = cramerCfg                }  gibiansky :: Style-gibiansky = Style { styleName         = "gibiansky"-                  , styleAuthor       = "Andrew Gibiansky"-                  , styleDescription  = "Andrew Gibiansky's style"-                  , styleInitialState = gibianskyCfg+gibiansky = Style { styleName        = "gibiansky"+                  , styleAuthor      = "Andrew Gibiansky"+                  , styleDescription = "Andrew Gibiansky's style"+                  , styleConfig      = gibianskyCfg                   }  johanTibell :: Style-johanTibell = Style { styleName         = "johan-tibell"-                    , styleAuthor       = "Johan Tibell"-                    , styleDescription  = "Johan Tibell's style"-                    , styleInitialState = johanTibellCfg+johanTibell = Style { styleName        = "johan-tibell"+                    , styleAuthor      = "Johan Tibell"+                    , styleDescription = "Johan Tibell's style"+                    , styleConfig      = johanTibellCfg                     }  -- | Styles list, useful for programmatically choosing.
src/Floskell/Types.hs view
@@ -4,6 +4,7 @@ -- | All types. module Floskell.Types     ( OutputRestriction(..)+    , TypeLayout(..)     , Penalty(..)     , TabStop(..)     , Printer(..)@@ -13,37 +14,40 @@     , psLine     , psColumn     , psNewline-    , Style(..)-    , FlexConfig(..)+    , initialPrintState+    , Config(..)+    , SrcSpan(..)+    , CommentType(..)+    , Comment(..)     , NodeInfo(..)-    , ComInfo(..)+    , noNodeInfo+    , nodeSpan     , Location(..)     ) where  import           Control.Applicative import           Control.Monad- import           Control.Monad.Search                  ( MonadSearch, Search, runSearchBest ) import           Control.Monad.State.Strict                  ( MonadState(..), StateT, execStateT, runStateT ) -import           Data.Int                       ( Int64 )-import           Data.Map.Strict                ( Map )--import           Data.Semigroup                 as Sem-import           Data.Text                      ( Text )+import qualified Data.Map.Strict              as Map+import           Data.Semigroup               as Sem -import           Floskell.Buffer                ( Buffer )-import qualified Floskell.Buffer                as Buffer-import           Floskell.Config                ( FlexConfig(..), Location(..) )+import           Floskell.Buffer              ( Buffer )+import qualified Floskell.Buffer              as Buffer+import           Floskell.Config              ( Config(..), Location(..) ) -import           Language.Haskell.Exts.Comments-import           Language.Haskell.Exts.SrcLoc+import           Language.Haskell.Exts.SrcLoc ( SrcSpan(..), mkSrcSpan, noLoc )+import           Language.Haskell.Exts.Syntax ( Annotated(..) )  data OutputRestriction = Anything | NoOverflow | NoOverflowOrLinebreak     deriving ( Eq, Ord, Show ) +data TypeLayout = TypeFree | TypeFlex | TypeVertical+    deriving ( Eq, Ord, Show )+ newtype Penalty = Penalty Int     deriving ( Eq, Ord, Num, Show ) @@ -55,8 +59,8 @@  instance Monoid Penalty where     mempty = 0-#if !(MIN_VERSION_base(4,11,0)) +#if !(MIN_VERSION_base(4,11,0))     mappend = (<>) #endif @@ -75,41 +79,48 @@ -- | The state of the pretty printer. data PrintState =     PrintState { psBuffer :: !Buffer -- ^ Output buffer-               , psIndentLevel :: !Int64 -- ^ Current indentation level.-               , psOnside :: !Int64 -- ^ Extra indentation is necessary with next line break.-               , psTabStops :: !(Map TabStop Int64) -- ^ Tab stops for alignment.-               , psUserState :: !FlexConfig -- ^ User state.+               , psIndentLevel :: !Int -- ^ Current indentation level.+               , psOnside :: !Int -- ^ Extra indentation is necessary with next line break.+               , psTabStops :: !(Map.Map TabStop Int) -- ^ Tab stops for alignment.+               , psConfig :: !Config -- ^ Style definition.                , psEolComment :: !Bool -- ^ An end of line comment has just been outputted.-               , psOutputRestriction :: OutputRestriction+               , psOutputRestriction :: !OutputRestriction+               , psTypeLayout :: !TypeLayout                } -psLine :: PrintState -> Int64+psLine :: PrintState -> Int psLine = Buffer.line . psBuffer -psColumn :: PrintState -> Int64+psColumn :: PrintState -> Int psColumn = Buffer.column . psBuffer  psNewline :: PrintState -> Bool psNewline = (== 0) . Buffer.column . psBuffer --- | A printer style.-data Style =-    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 :: !FlexConfig -- ^ User state, if needed.-          }+initialPrintState :: Config -> PrintState+initialPrintState config =+    PrintState Buffer.empty 0 0 Map.empty config False Anything TypeFree +data CommentType = InlineComment | LineComment | PreprocessorDirective+    deriving ( Show )++data Comment = Comment { commentType :: !CommentType+                       , commentSpan :: !SrcSpan+                       , commentText :: !String+                       }+    deriving ( Show )+ -- | Information for each node in the AST. data NodeInfo =-    NodeInfo { nodeInfoSpan     :: !SrcSpanInfo -- ^ Location info from the parser.-             , nodeInfoComments :: ![ComInfo] -- ^ Comments which are attached to this node.+    NodeInfo { nodeInfoSpan :: !SrcSpan               -- ^ Location info from the parser.+             , nodeInfoLeadingComments :: ![Comment]  -- ^ Leading comments attached to this node.+             , nodeInfoTrailingComments :: ![Comment] -- ^ Trailing comments attached to this node.              }     deriving ( Show ) --- | Comment with some more info.-data ComInfo =-    ComInfo { comInfoComment  :: !Comment          -- ^ The normal comment type.-            , comInfoLocation :: !(Maybe Location) -- ^ Where the comment lies relative to the node.-            }-    deriving ( Show )+-- | Empty NodeInfo+noNodeInfo :: NodeInfo+noNodeInfo = NodeInfo (mkSrcSpan noLoc noLoc) [] []++nodeSpan :: Annotated ast => ast NodeInfo -> SrcSpan+nodeSpan = nodeInfoSpan . ann
src/main/Benchmark.hs view
@@ -9,40 +9,40 @@ import           Criterion import           Criterion.Main -import qualified Data.ByteString       as S-import qualified Data.ByteString.Char8 as S8-import qualified Data.ByteString.UTF8  as UTF8-import qualified Data.Text             as T+import qualified Data.ByteString.Lazy.Char8 as L8+import qualified Data.ByteString.Lazy.UTF8  as UTF8+import qualified Data.Text                  as T  import           Floskell -import           Language.Haskell.Exts ( Language(Haskell2010) )+import           Language.Haskell.Exts      ( Language(Haskell2010) )  import           Markdone  -- | Main benchmarks. main :: IO () main = do-    bytes <- S.readFile "BENCHMARK.md"+    bytes <- L8.readFile "BENCHMARK.md"     !forest <- fmap force (parse (tokenize bytes))     defaultMain [ bgroup (T.unpack $ styleName style) $-                    toCriterion style forest+                    toCriterion (AppConfig style+                                           Haskell2010+                                           defaultExtensions+                                           [])+                                forest                 | style <- styles                 ]  -- | Convert the Markdone document to Criterion benchmarks.-toCriterion :: Style -> [Markdone] -> [Benchmark]-toCriterion style = go+toCriterion :: AppConfig -> [Markdone] -> [Benchmark]+toCriterion config = go   where-    go (Section name children : next) = bgroup (S8.unpack name) (go children)+    go (Section name children : next) = bgroup (L8.unpack name) (go children)         : go next     go (PlainText desc : CodeFence lang code : next) =         if lang == "haskell"         then bench (UTF8.toString desc)-                   (nf (either error id . reformat style-                                                   Haskell2010-                                                   defaultExtensions-                                                   (Just "BENCHMARK.md"))+                   (nf (either error id . reformat config (Just "BENCHMARK.md"))                        code) : go next         else go next     go (PlainText{} : next) = go next
src/main/Main.hs view
@@ -4,35 +4,30 @@ -- | Main entry point to floskell. module Main ( main ) where -import           Control.Applicative             ( (<|>), many, optional )+import           Control.Applicative             ( many, optional ) import           Control.Exception               ( catch, throw ) -import           Data.Aeson-                 ( (.:?), (.=), FromJSON(..), ToJSON(..) )-import qualified Data.Aeson                      as JSON import qualified Data.Aeson.Encode.Pretty        as JSON ( encodePretty )-import qualified Data.Aeson.Types                as JSON ( typeMismatch )-import qualified Data.ByteString                 as BS import qualified Data.ByteString.Lazy            as BL-import qualified Data.HashMap.Lazy               as HashMap-import           Data.List                       ( inits, sort )+import           Data.List                       ( sort ) import           Data.Maybe                      ( isJust ) import           Data.Monoid                     ( (<>) )- import qualified Data.Text                       as T import           Data.Version                    ( showVersion ) -import           Floskell                        ( reformat, styles )-import           Floskell.Types-                 ( Style(styleName, styleInitialState) )+import           Floskell+                 ( AppConfig(..), Style(..), defaultAppConfig, findAppConfig+                 , readAppConfig, reformat, setExtensions, setFixities+                 , setLanguage, setStyle, styles )+import           Floskell.ConfigFile             ( showFixity )+import           Floskell.Fixities               ( packageFixities )  import           Foreign.C.Error                 ( Errno(..), eXDEV )  import           GHC.IO.Exception                ( ioe_errno )  import           Language.Haskell.Exts-                 ( Extension(..), Language(..), classifyExtension-                 , classifyLanguage, knownExtensions, knownLanguages )+                 ( Extension(..), knownExtensions, knownLanguages )  import           Options.Applicative                  ( ParseError(..), abortOption, argument, execParser, footerDoc@@ -43,69 +38,22 @@ import           Paths_floskell                  ( version )  import           System.Directory-                 ( XdgDirectory(..), copyFile, copyPermissions, doesFileExist-                 , findFileWith, getAppUserDataDirectory, getCurrentDirectory-                 , getHomeDirectory, getTemporaryDirectory, getXdgDirectory-                 , removeFile, renameFile )-import           System.FilePath                 ( joinPath, splitDirectories )+                 ( copyFile, copyPermissions, getTemporaryDirectory, removeFile+                 , renameFile ) import           System.IO-                 ( FilePath, hClose, hFlush, openTempFile )+                 ( FilePath, hClose, hFlush, openTempFile, stdout )  -- | Program options.-data Options = Options { optStyle       :: Maybe String-                       , optLanguage    :: Maybe String-                       , optExtensions  :: [String]-                       , optConfig      :: Maybe FilePath-                       , optPrintConfig :: Bool-                       , optFiles       :: [FilePath]+data Options = Options { optStyle         :: Maybe String+                       , optLanguage      :: Maybe String+                       , optExtensions    :: [String]+                       , optFixities      :: [String]+                       , optConfig        :: Maybe FilePath+                       , optPrintConfig   :: Bool+                       , optPrintFixities :: Bool+                       , optFiles         :: [FilePath]                        } --- | Program configuration.-data Config = Config { cfgStyle      :: Style-                     , cfgLanguage   :: Language-                     , cfgExtensions :: [Extension]-                     }--instance ToJSON Config where-    toJSON Config{..} = JSON.object [ "style" .= styleName cfgStyle-                                    , "language" .= show cfgLanguage-                                    , "extensions" .= map showExt cfgExtensions-                                    , "formatting" .= styleInitialState cfgStyle-                                    ]-      where-        showExt (EnableExtension x) = show x-        showExt (DisableExtension x) = "No" ++ show x-        showExt (UnknownExtension x) = x--instance FromJSON Config where-    parseJSON (JSON.Object o) = do-        style <- maybe (cfgStyle defaultConfig) lookupStyle <$> o .:? "style"-        language <- maybe (cfgLanguage defaultConfig) lookupLanguage-            <$> o .:? "language"-        extensions <- maybe (cfgExtensions defaultConfig) (map lookupExtension)-            <$> o .:? "extensions"-        let flex = styleInitialState style-        flex' <- maybe flex (updateFlexConfig flex) <$> o .:? "formatting"-        let style' = style { styleInitialState = flex' }-        return $ Config style' language extensions-      where-        updateFlexConfig cfg v =-            case JSON.fromJSON $ mergeJSON (toJSON cfg) v of-                JSON.Error e -> error e-                JSON.Success x -> x--        mergeJSON JSON.Null r = r-        mergeJSON l JSON.Null = l-        mergeJSON (JSON.Object l) (JSON.Object r) =-            JSON.Object (HashMap.unionWith mergeJSON l r)-        mergeJSON _ r = r--    parseJSON v = JSON.typeMismatch "Config" v---- | Default program configuration.-defaultConfig :: Config-defaultConfig = Config (head styles) Haskell2010 []- -- | Main entry point. main :: IO () main = do@@ -113,14 +61,17 @@     mconfig <- case optConfig opts of         Just c -> return $ Just c         Nothing ->-            if isJust (optStyle opts) then return Nothing else findConfig+            if isJust (optStyle opts) then return Nothing else findAppConfig     baseConfig <- case mconfig of-        Just path -> readConfig path-        Nothing -> return defaultConfig-    let config = mergeConfig baseConfig opts-    if optPrintConfig opts-        then BL.putStr $ JSON.encodePretty config-        else run config (optFiles opts)+        Just path -> readAppConfig path+        Nothing -> return defaultAppConfig+    let config = mergeAppConfig baseConfig opts+    if optPrintFixities opts+        then PP.displayIO stdout . PP.renderPretty 1.0 80 $+            docFixities packageFixities <> PP.linebreak+        else if optPrintConfig opts+             then BL.putStr $ JSON.encodePretty config+             else run config (optFiles opts)   where     parser = info (helper <*> versioner <*> options)                   (fullDesc@@ -143,10 +94,15 @@         <*> many (option str                          (long "extension" <> short 'X' <> metavar "EXTENSION"                           <> help "Enable or disable language extensions"))+        <*> many (option str+                         (long "fixity" <> short 'F' <> metavar "FIXITY"+                          <> help "Add fixity declaration"))         <*> optional (option str                              (long "config" <> short 'c' <> metavar "FILE"                               <> help "Configuration file"))         <*> switch (long "print-config" <> help "Print configuration")+        <*> switch (long "print-fixities"+                    <> help "Print all built-in fixity declarations")         <*> many (argument str                            (metavar "FILES"                             <> help "Input files (will be replaced)"))@@ -166,25 +122,30 @@                                               . PP.punctuate PP.comma                                               . map PP.text $ sort xs) +    docFixities = PP.vcat . PP.punctuate PP.linebreak+        . map (uncurry docPackageFixities)++    docPackageFixities p fs = PP.text (p ++ ":")+        PP.<$$> (PP.indent 2 . PP.fillSep . PP.punctuate PP.comma+                 . map (PP.text . showFixity) $ sort fs)+ -- | Reformat files or stdin based on provided configuration.-run :: Config -> [FilePath] -> IO ()-run Config{..} files = case files of-    [] -> reformatStdin cfgStyle cfgLanguage cfgExtensions-    _ -> mapM_ (reformatFile cfgStyle cfgLanguage cfgExtensions) files+run :: AppConfig -> [FilePath] -> IO ()+run config files = case files of+    [] -> reformatStdin config+    _ -> mapM_ (reformatFile config) files  -- | Reformat stdin according to Style, Language, and Extensions.-reformatStdin :: Style -> Language -> [Extension] -> IO ()-reformatStdin style language extensions = BL.interact $-    reformatByteString style language extensions Nothing . BL.toStrict+reformatStdin :: AppConfig -> IO ()+reformatStdin config = BL.interact $ reformatByteString config Nothing  -- | Reformat a file according to Style, Language, and Extensions.-reformatFile :: Style -> Language -> [Extension] -> FilePath -> IO ()-reformatFile style language extensions file = do-    text <- BS.readFile file+reformatFile :: AppConfig -> FilePath -> IO ()+reformatFile config file = do+    text <- BL.readFile file     tmpDir <- getTemporaryDirectory     (fp, h) <- openTempFile tmpDir "floskell.hs"-    BL.hPutStr h $-        reformatByteString style language extensions (Just file) text+    BL.hPutStr h $ reformatByteString config (Just file) text     hFlush h     hClose h     let exdev e = if ioe_errno e == Just ((\(Errno a) -> a) eXDEV)@@ -194,58 +155,13 @@     renameFile fp file `catch` exdev  -- | Reformat a ByteString according to Style, Language, and Extensions.-reformatByteString :: Style-                   -> Language-                   -> [Extension]-                   -> Maybe FilePath-                   -> BS.ByteString-                   -> BL.ByteString-reformatByteString style language extensions mpath text =-    either error id $ reformat style language extensions mpath text---- | Try to find a configuration file based on current working--- directory, or in one of the application configuration directories.-findConfig :: IO (Maybe FilePath)-findConfig = do-    dotfilePaths <- sequence [ getHomeDirectory, getXdgDirectory XdgConfig "" ]-    dotfileConfig <- findFileWith doesFileExist dotfilePaths ".floskell.json"-    userPaths <- sequence [ getAppUserDataDirectory "floskell"-                          , getXdgDirectory XdgConfig "floskell"-                          ]-    userConfig <- findFileWith doesFileExist userPaths "config.json"-    localPaths <- map joinPath . reverse . drop 1 . inits . splitDirectories-        <$> getCurrentDirectory-    localConfig <- findFileWith doesFileExist localPaths "floskell.json"-    return $ localConfig <|> userConfig <|> dotfileConfig---- | Load a configuration file.-readConfig :: FilePath -> IO Config-readConfig file = do-    text <- BS.readFile file-    either (error . (++) (file ++ ": ")) return $ JSON.eitherDecodeStrict text+reformatByteString+    :: AppConfig -> Maybe FilePath -> BL.ByteString -> BL.ByteString+reformatByteString config mpath text =+    either error id $ reformat config mpath text  -- | Update the program configuration from the program options.-mergeConfig :: Config -> Options -> Config-mergeConfig cfg@Config{..} Options{..} =-    cfg { cfgStyle      = maybe cfgStyle lookupStyle optStyle-        , cfgLanguage   = maybe cfgLanguage lookupLanguage optLanguage-        , cfgExtensions = cfgExtensions ++ map lookupExtension optExtensions-        }---- | Lookup a style by name.-lookupStyle :: String -> Style-lookupStyle name = case filter ((== T.pack name) . styleName) styles of-    [] -> error $ "Unknown style: " ++ name-    x : _ -> x---- | Lookup a language by name.-lookupLanguage :: String -> Language-lookupLanguage name = case classifyLanguage name of-    UnknownLanguage _ -> error $ "Unknown language: " ++ name-    x -> x---- | Lookup an extension by name.-lookupExtension :: String -> Extension-lookupExtension name = case classifyExtension name of-    UnknownExtension _ -> error $ "Unkown extension: " ++ name-    x -> x+mergeAppConfig :: AppConfig -> Options -> AppConfig+mergeAppConfig cfg Options{..} =+    cfg `setStyle` optStyle `setLanguage` optLanguage+    `setExtensions` optExtensions `setFixities` optFixities
src/main/Markdone.hs view
@@ -13,11 +13,12 @@ import           Control.DeepSeq import           Control.Monad.Catch -import           Data.ByteString         ( ByteString )-import           Data.ByteString.Builder as B-import qualified Data.ByteString.Char8   as S8+import           Data.ByteString.Builder    as B+import qualified Data.ByteString.Char8      as S8+import           Data.ByteString.Lazy       ( ByteString )+import qualified Data.ByteString.Lazy.Char8 as L8 import           Data.Char-import           Data.Monoid             ( (<>) )+import           Data.Monoid                ( (<>) ) import           Data.Typeable  import           GHC.Generics@@ -45,17 +46,17 @@  -- | Tokenize the bytestring. tokenize :: ByteString -> [Token]-tokenize = map token . S8.lines+tokenize = map token . L8.lines   where     token line-        | S8.isPrefixOf "#" line =-            let (hashes, title) = S8.span (== '#') line-            in-                Heading (S8.length hashes) (S8.dropWhile isSpace title)-        | S8.isPrefixOf "```" line =+        | L8.isPrefixOf "#" line = let (hashes, title) = L8.span (== '#') line+                                   in+                                       Heading (fromIntegral $ L8.length hashes)+                                               (L8.dropWhile isSpace title)+        | L8.isPrefixOf "```" line =             if line == "```"             then EndFence-            else BeginFence (S8.dropWhile (\c -> c == '`' || c == ' ') line)+            else BeginFence (L8.dropWhile (\c -> c == '`' || c == ' ') line)         | otherwise = PlainLine line  -- | Parse into a forest.@@ -83,7 +84,7 @@                     case rest' of                         (EndFence : rest'') ->                             fmap (CodeFence label-                                            (S8.intercalate "\n"+                                            (L8.intercalate "\n"                                                             (map getPlain                                                                  content)) :)                                  (go level rest'')@@ -95,7 +96,7 @@                                                  _ -> False)                                             (PlainLine p : rest)                 in-                    fmap (PlainText (S8.intercalate "\n" (map getPlain content)) :)+                    fmap (PlainText (L8.intercalate "\n" (map getPlain content)) :)                          (go level rest')         [] -> return []         _ -> throwM ExpectedSection@@ -111,8 +112,8 @@             let level' = level + 1             in                 B.byteString (S8.replicate level' '#') <> B.char7 ' '-                <> B.byteString heading <> B.byteString "\n"+                <> B.lazyByteString heading <> B.byteString "\n"                 <> mconcat (map (go level') children)-        (CodeFence lang code) -> B.byteString "``` " <> B.byteString lang-            <> B.char7 '\n' <> B.byteString code <> B.byteString "\n```\n"-        (PlainText text) -> B.byteString text <> B.byteString "\n"+        (CodeFence lang code) -> B.byteString "``` " <> B.lazyByteString lang+            <> B.char7 '\n' <> B.lazyByteString code <> B.byteString "\n```\n"+        (PlainText text) -> B.lazyByteString text <> B.byteString "\n"
src/main/Test.hs view
@@ -1,16 +1,17 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}  -- | Test the pretty printer. module Main where +import           Control.Applicative          ( (<|>) ) import           Control.Monad                ( forM_, guard ) -import           Data.ByteString              ( ByteString )-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.UTF8         as UTF8+import qualified Data.ByteString.Lazy.Builder as B+import qualified Data.ByteString.Lazy.UTF8    as UTF8 import           Data.Maybe                   ( mapMaybe ) import qualified Data.Text                    as T @@ -50,12 +51,12 @@  loadMarkdone :: String -> IO [Markdone] loadMarkdone filename = do-    bytes <- S.readFile filename+    bytes <- L.readFile filename     MD.parse (MD.tokenize bytes)  saveMarkdone :: String -> [Markdone] -> IO () saveMarkdone filename doc =-    S.writeFile filename $ L.toStrict $ L.toLazyByteString $ MD.print doc+    L.writeFile filename . B.toLazyByteString $ MD.print doc  -- | Extract code snippets from a Markdone document. extractSnippets :: ByteString -> [Markdone] -> [TestTree]@@ -75,29 +76,47 @@     doc <- loadMarkdone filename     return $ extractSnippets haskell doc --- | Some styles are broken and will fail the idempotency test.-expectedFailures :: [(T.Text, [Int])]-expectedFailures = []+disabled :: T.Text -> [Int] -> Maybe String+disabled style path = lookup (Just style, path) disabledTests+    <|> lookup (Nothing :: Maybe T.Text, path) disabledTests+  where+    disabledTests = []+#if MIN_VERSION_haskell_src_exts(1,21,0)+#else+        ++ [ ((Nothing, [ 2, 3, 4, 1 ]), "requires haskell-src-exts >=1.21.0")+           ]+#if MIN_VERSION_haskell_src_exts(1,20,0)+#else+        ++ [ ((Nothing, [ 2, 3, 6, 1 ]), "requires haskell-src-exts >=1.20.0")+           , ((Nothing, [ 2, 3, 11, 1 ]), "requires haskell-src-exts >=1.20.0")+           , ((Nothing, [ 2, 3, 12, 1 ]), "requires haskell-src-exts >=1.20.0")+           , ((Nothing, [ 2, 4, 1, 1 ]), "requires haskell-src-exts >=1.20.0")+           , ((Nothing, [ 2, 4, 9, 1 ]), "requires haskell-src-exts >=1.20.0")+           ]+#endif+#endif  -- | Convert the Markdone document to Spec benchmarks. toSpec :: Style -> [Int] -> [TestTree] -> [TestTree] -> Spec toSpec style path inp ref =     forM_ (zip3 [ 1 :: Int .. ] inp (ref ++ repeat TestMismatchMarker)) $ \case         (n, TestSection title children, TestSection _ children') ->-            describe title $ toSpec style (path ++ [ n ]) children children'-        (n, TestSnippet code, TestSnippet code') -> do-            let path' = (styleName style, path ++ [ n ])-            it (name n "formats as expected") $-                case reformatSnippet style code of-                    Left e -> error e-                    Right b -> b `shouldBeReadable` code'-            it (name n "formatting is idempotent") $-                if path' `elem` expectedFailures-                then pending-                else case reformatSnippet style-                                          code >>= reformatSnippet style of-                    Left e -> error e-                    Right b -> b `shouldBeReadable` code'+            describe (title ++ show (path ++ [ n ])) $+            toSpec style (path ++ [ n ]) children children'+        (n, TestSnippet code, TestSnippet code') ->+            case disabled (styleName style) (path ++ [ n ]) of+                Just msg -> it "Disabled" $ pendingWith msg+                Nothing -> do+                    it (name n "formats as expected") $+                        case reformatSnippet style code of+                            Left e -> error e+                            Right b -> b `shouldBeReadable` code'+                    it (name n "formatting is idempotent") $+                        case reformatSnippet style code of+                            Left e -> error e+                            Right b -> case reformatSnippet style b of+                                Left e -> error e+                                Right b' -> b' `shouldBeReadable` b         (n, _, _) -> error $ name n "structure mismatch in reference file"   where     name n desc = "Snippet " ++ show n ++ " - " ++ desc@@ -116,8 +135,9 @@         return (name, style, tree)  reformatSnippet :: Style -> ByteString -> Either String ByteString-reformatSnippet style code = L.toStrict-    <$> reformat style Haskell2010 defaultExtensions (Just "TEST.md") code+reformatSnippet style =+    reformat (AppConfig style Haskell2010 defaultExtensions [])+             (Just "TEST.md")  regenerate :: Style -> [Markdone] -> [Markdone] regenerate style = map fmt
+ stack.yaml view
@@ -0,0 +1,6 @@+resolver: lts-13.6+packages:+- '.'+extra-deps:+- haskell-src-exts-1.21.0+- monad-dijkstra-0.1.1.2