stylish-haskell 0.13.0.0 → 0.14.0.0
raw patch · 34 files changed
+2276/−2604 lines, 34 filesdep +ghc-lib-parser-exdep ~Cabaldep ~aesondep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: ghc-lib-parser-ex
Dependency ranges changed: Cabal, aeson, bytestring, ghc-lib-parser, optparse-applicative
API changes (from Hackage documentation)
- Language.Haskell.Stylish: Config :: [Step] -> Maybe Int -> [String] -> Newline -> Bool -> ExitCodeBehavior -> Config
- Language.Haskell.Stylish: ErrorOnFormatExitBehavior :: ExitCodeBehavior
- Language.Haskell.Stylish: NormalExitBehavior :: ExitCodeBehavior
- Language.Haskell.Stylish: [configCabal] :: Config -> Bool
- Language.Haskell.Stylish: [configColumns] :: Config -> Maybe Int
- Language.Haskell.Stylish: [configExitCode] :: Config -> ExitCodeBehavior
- Language.Haskell.Stylish: [configLanguageExtensions] :: Config -> [String]
- Language.Haskell.Stylish: [configNewline] :: Config -> Newline
- Language.Haskell.Stylish: [configSteps] :: Config -> [Step]
- Language.Haskell.Stylish: configFilePath :: Verbose -> Maybe FilePath -> IO (Maybe FilePath)
- Language.Haskell.Stylish: data Config
- Language.Haskell.Stylish: data ExitCodeBehavior
- Language.Haskell.Stylish: defaultConfigBytes :: ByteString
- Language.Haskell.Stylish: loadConfig :: Verbose -> Maybe FilePath -> IO Config
- Language.Haskell.Stylish: parseConfig :: Value -> Parser Config
- Language.Haskell.Stylish: type Extensions = [String]
- Language.Haskell.Stylish.GHC: compareOutputable :: Outputable a => a -> a -> Ordering
- Language.Haskell.Stylish.GHC: unLocated :: Located a -> a
- Language.Haskell.Stylish.Module: Module :: [RealLocated AnnotationComment] -> [(ApiAnnKey, [SrcSpan])] -> Map RealSrcSpan [AnnKeywordId] -> Located (HsModule GhcPs) -> Module
- Language.Haskell.Stylish.Module: [parsedAnnotSrcs] :: Module -> Map RealSrcSpan [AnnKeywordId]
- Language.Haskell.Stylish.Module: [parsedAnnotations] :: Module -> [(ApiAnnKey, [SrcSpan])]
- Language.Haskell.Stylish.Module: [parsedComments] :: Module -> [RealLocated AnnotationComment]
- Language.Haskell.Stylish.Module: [parsedModule] :: Module -> Located (HsModule GhcPs)
- Language.Haskell.Stylish.Module: data Comments
- Language.Haskell.Stylish.Module: data Decls
- Language.Haskell.Stylish.Module: data Import
- Language.Haskell.Stylish.Module: data Module
- Language.Haskell.Stylish.Module: data ModuleHeader
- Language.Haskell.Stylish.Module: instance Data.Data.Data Language.Haskell.Stylish.Module.Module
- Language.Haskell.Stylish.Module: instance GHC.Classes.Eq Language.Haskell.Stylish.Module.Import
- Language.Haskell.Stylish.Module: instance GHC.Classes.Ord Language.Haskell.Stylish.Module.Import
- Language.Haskell.Stylish.Module: instance Outputable.Outputable Language.Haskell.Stylish.Module.Import
- Language.Haskell.Stylish.Module: lookupAnnotation :: SrcSpan -> Module -> [AnnKeywordId]
- Language.Haskell.Stylish.Module: makeModule :: PState -> Located (HsModule GhcPs) -> Module
- Language.Haskell.Stylish.Module: moduleComments :: Module -> Comments
- Language.Haskell.Stylish.Module: moduleDecls :: Module -> Decls
- Language.Haskell.Stylish.Module: moduleHeader :: Module -> ModuleHeader
- Language.Haskell.Stylish.Module: moduleImports :: Module -> [Located Import]
- Language.Haskell.Stylish.Module: rawComments :: Comments -> [RealLocated AnnotationComment]
- Language.Haskell.Stylish.Module: rawImport :: Import -> ImportDecl GhcPs
- Language.Haskell.Stylish.Module: rawModuleAnnotations :: Module -> [(ApiAnnKey, [SrcSpan])]
- Language.Haskell.Stylish.Module: rawModuleDecls :: Decls -> [LHsDecl GhcPs]
- Language.Haskell.Stylish.Module: rawModuleExports :: ModuleHeader -> Maybe (Located [LIE GhcPs])
- Language.Haskell.Stylish.Module: rawModuleHaddocks :: ModuleHeader -> Maybe LHsDocString
- Language.Haskell.Stylish.Module: rawModuleName :: ModuleHeader -> Maybe (Located ModuleName)
- Language.Haskell.Stylish.Printer: [parsedModule] :: PrinterState -> !Module
- Language.Haskell.Stylish.Printer: [pendingComments] :: PrinterState -> ![RealLocated AnnotationComment]
- Language.Haskell.Stylish.Printer: getAnnot :: SrcSpan -> P [AnnKeywordId]
- Language.Haskell.Stylish.Printer: getDocstrPrev :: SrcSpan -> P (Maybe AnnotationComment)
- Language.Haskell.Stylish.Printer: groupAttachedComments :: [Located a] -> P [([AnnotationComment], NonEmpty (Located a))]
- Language.Haskell.Stylish.Printer: groupWithoutComments :: [([AnnotationComment], NonEmpty (Located a))] -> Maybe [Located a]
- Language.Haskell.Stylish.Printer: peekNextCommentPos :: P (Maybe SrcSpan)
- Language.Haskell.Stylish.Printer: putAllSpanComments :: P () -> SrcSpan -> P ()
- Language.Haskell.Stylish.Printer: putEolComment :: SrcSpan -> P ()
- Language.Haskell.Stylish.Printer: removeCommentTo :: SrcSpan -> P [AnnotationComment]
- Language.Haskell.Stylish.Printer: removeCommentToEnd :: SrcSpan -> P [AnnotationComment]
- Language.Haskell.Stylish.Printer: removeLineComment :: Int -> P (Maybe AnnotationComment)
+ Language.Haskell.Stylish.Config: Config :: [Step] -> Maybe Int -> [String] -> Newline -> Bool -> ExitCodeBehavior -> Config
+ Language.Haskell.Stylish.Config: ErrorOnFormatExitBehavior :: ExitCodeBehavior
+ Language.Haskell.Stylish.Config: NormalExitBehavior :: ExitCodeBehavior
+ Language.Haskell.Stylish.Config: [configCabal] :: Config -> Bool
+ Language.Haskell.Stylish.Config: [configColumns] :: Config -> Maybe Int
+ Language.Haskell.Stylish.Config: [configExitCode] :: Config -> ExitCodeBehavior
+ Language.Haskell.Stylish.Config: [configLanguageExtensions] :: Config -> [String]
+ Language.Haskell.Stylish.Config: [configNewline] :: Config -> Newline
+ Language.Haskell.Stylish.Config: [configSteps] :: Config -> [Step]
+ Language.Haskell.Stylish.Config: configFilePath :: Verbose -> Maybe FilePath -> IO (Maybe FilePath)
+ Language.Haskell.Stylish.Config: data Config
+ Language.Haskell.Stylish.Config: data ExitCodeBehavior
+ Language.Haskell.Stylish.Config: defaultConfigBytes :: ByteString
+ Language.Haskell.Stylish.Config: instance Data.Aeson.Types.FromJSON.FromJSON Language.Haskell.Stylish.Config.Config
+ Language.Haskell.Stylish.Config: instance GHC.Classes.Eq Language.Haskell.Stylish.Config.ExitCodeBehavior
+ Language.Haskell.Stylish.Config: instance GHC.Show.Show Language.Haskell.Stylish.Config.ExitCodeBehavior
+ Language.Haskell.Stylish.Config: loadConfig :: Verbose -> Maybe FilePath -> IO Config
+ Language.Haskell.Stylish.Config: parseConfig :: Value -> Parser Config
+ Language.Haskell.Stylish.Config: type Extensions = [String]
+ Language.Haskell.Stylish.GHC: deepAnnComments :: (Data a, Typeable a) => a -> [LEpaComment]
+ Language.Haskell.Stylish.GHC: epAnnComments :: EpAnn a -> [LEpaComment]
+ Language.Haskell.Stylish.Module: Comments :: [RealLocated EpaComment] -> Comments
+ Language.Haskell.Stylish.Module: importModuleName :: ImportDecl GhcPs -> String
+ Language.Haskell.Stylish.Module: newtype Comments
+ Language.Haskell.Stylish.Module: type Module = Located HsModule
+ Language.Haskell.Stylish.Parse: parseModule :: Extensions -> Maybe FilePath -> String -> Either String Module
+ Language.Haskell.Stylish.Printer: putMaybeLineComment :: Maybe EpaComment -> P ()
+ Language.Haskell.Stylish.Step: Step :: String -> (Lines -> Module -> Lines) -> Step
+ Language.Haskell.Stylish.Step: [stepFilter] :: Step -> Lines -> Module -> Lines
+ Language.Haskell.Stylish.Step: [stepName] :: Step -> String
+ Language.Haskell.Stylish.Step: data Step
+ Language.Haskell.Stylish.Step: makeStep :: String -> (Lines -> Module -> Lines) -> Step
+ Language.Haskell.Stylish.Step: type Lines = [String]
+ Language.Haskell.Stylish.Step.UnicodeSyntax: instance GHC.Base.Monoid Language.Haskell.Stylish.Step.UnicodeSyntax.Replacement
+ Language.Haskell.Stylish.Step.UnicodeSyntax: instance GHC.Base.Semigroup Language.Haskell.Stylish.Step.UnicodeSyntax.Replacement
+ Language.Haskell.Stylish.Step.UnicodeSyntax: instance GHC.Show.Show Language.Haskell.Stylish.Step.UnicodeSyntax.Replacement
- Language.Haskell.Stylish.Module: canMergeImport :: Import -> Import -> Bool
+ Language.Haskell.Stylish.Module: canMergeImport :: ImportDecl GhcPs -> ImportDecl GhcPs -> Bool
- Language.Haskell.Stylish.Module: mergeModuleImport :: Located Import -> Located Import -> Located Import
+ Language.Haskell.Stylish.Module: mergeModuleImport :: LImportDecl GhcPs -> LImportDecl GhcPs -> LImportDecl GhcPs
- Language.Haskell.Stylish.Module: moduleImportGroups :: Module -> [NonEmpty (Located Import)]
+ Language.Haskell.Stylish.Module: moduleImportGroups :: Module -> [NonEmpty (LImportDecl GhcPs)]
- Language.Haskell.Stylish.Module: moduleLanguagePragmas :: Module -> [(RealSrcSpan, NonEmpty Text)]
+ Language.Haskell.Stylish.Module: moduleLanguagePragmas :: Module -> [(RealSrcSpan, NonEmpty String)]
- Language.Haskell.Stylish.Printer: PrinterState :: !Lines -> !Int -> !String -> ![RealLocated AnnotationComment] -> !Module -> PrinterState
+ Language.Haskell.Stylish.Printer: PrinterState :: !Lines -> !Int -> !String -> PrinterState
- Language.Haskell.Stylish.Printer: putComment :: AnnotationComment -> P ()
+ Language.Haskell.Stylish.Printer: putComment :: EpaComment -> P ()
- Language.Haskell.Stylish.Printer: putRdrName :: Located RdrName -> P ()
+ Language.Haskell.Stylish.Printer: putRdrName :: GenLocated SrcSpanAnnN RdrName -> P ()
- Language.Haskell.Stylish.Printer: putType :: Located (HsType GhcPs) -> P ()
+ Language.Haskell.Stylish.Printer: putType :: LHsType GhcPs -> P ()
- Language.Haskell.Stylish.Printer: runPrinter :: PrinterConfig -> [RealLocated AnnotationComment] -> Module -> Printer a -> (a, Lines)
+ Language.Haskell.Stylish.Printer: runPrinter :: PrinterConfig -> Printer a -> (a, Lines)
- Language.Haskell.Stylish.Printer: runPrinter_ :: PrinterConfig -> [RealLocated AnnotationComment] -> Module -> Printer a -> Lines
+ Language.Haskell.Stylish.Printer: runPrinter_ :: PrinterConfig -> Printer a -> Lines
Files
- CHANGELOG +5/−0
- data/stylish-haskell.yaml +1/−1
- lib/Language/Haskell/Stylish/Align.hs +11/−11
- lib/Language/Haskell/Stylish/Block.hs +16/−4
- lib/Language/Haskell/Stylish/Comments.hs +145/−0
- lib/Language/Haskell/Stylish/Config.hs +8/−11
- lib/Language/Haskell/Stylish/Config/Cabal.hs +0/−1
- lib/Language/Haskell/Stylish/Editor.hs +3/−1
- lib/Language/Haskell/Stylish/GHC.hs +41/−58
- lib/Language/Haskell/Stylish/Module.hs +63/−197
- lib/Language/Haskell/Stylish/Ordering.hs +32/−21
- lib/Language/Haskell/Stylish/Parse.hs +56/−81
- lib/Language/Haskell/Stylish/Printer.hs +110/−227
- lib/Language/Haskell/Stylish/Step/Data.hs +326/−322
- lib/Language/Haskell/Stylish/Step/Imports.hs +231/−242
- lib/Language/Haskell/Stylish/Step/LanguagePragmas.hs +25/−29
- lib/Language/Haskell/Stylish/Step/ModuleHeader.hs +139/−214
- lib/Language/Haskell/Stylish/Step/SimpleAlign.hs +50/−53
- lib/Language/Haskell/Stylish/Step/Squash.hs +22/−25
- lib/Language/Haskell/Stylish/Step/UnicodeSyntax.hs +75/−53
- lib/Language/Haskell/Stylish/Util.hs +11/−22
- stylish-haskell.cabal +48/−101
- tests/Language/Haskell/Stylish/Config/Tests.hs +1/−1
- tests/Language/Haskell/Stylish/Regressions.hs +5/−6
- tests/Language/Haskell/Stylish/Step/Data/Tests.hs +436/−446
- tests/Language/Haskell/Stylish/Step/Imports/FelixTests.hs +267/−329
- tests/Language/Haskell/Stylish/Step/Imports/Tests.hs +23/−16
- tests/Language/Haskell/Stylish/Step/LanguagePragmas/Tests.hs +16/−20
- tests/Language/Haskell/Stylish/Step/ModuleHeader/Tests.hs +26/−0
- tests/Language/Haskell/Stylish/Step/Tabs/Tests.hs +15/−18
- tests/Language/Haskell/Stylish/Step/TrailingWhitespace/Tests.hs +15/−18
- tests/Language/Haskell/Stylish/Step/UnicodeSyntax/Tests.hs +20/−27
- tests/Language/Haskell/Stylish/Tests.hs +15/−7
- tests/Language/Haskell/Stylish/Tests/Util.hs +19/−42
CHANGELOG view
@@ -1,5 +1,10 @@ # CHANGELOG +- 0.14.0.0 (2022-03-16)+ * Port to GHC 9.2 AST (by jaspervdj)+ * Case insensitive import sort (by vlatkoB)+ * Fix issue with dissappearing GADT kind signatures (by Łukasz Gołębiewski)+ - 0.13.0.0 (2021-09-15) * Don't remove ticks on promoted data types (by Jim McStanton) * Add break_only_where option (by 1Computer1)
data/stylish-haskell.yaml view
@@ -85,7 +85,7 @@ # # Sort typeclass names in the "deriving" list alphabetically. # sort_deriving: true #- # # Wheter or not to break enums onto several lines+ # # Whether or not to break enums onto several lines # # # # Default: false # break_enums: false
lib/Language/Haskell/Stylish/Align.hs view
@@ -8,7 +8,7 @@ -------------------------------------------------------------------------------- import Data.List (nub)-import qualified SrcLoc as S+import qualified GHC.Types.SrcLoc as GHC --------------------------------------------------------------------------------@@ -55,9 +55,9 @@ -- | Create changes that perform the alignment. align- :: Maybe Int -- ^ Max columns- -> [Alignable S.RealSrcSpan] -- ^ Alignables- -> [Change String] -- ^ Changes performing the alignment+ :: Maybe Int -- ^ Max columns+ -> [Alignable GHC.RealSrcSpan] -- ^ Alignables+ -> [Change String] -- ^ Changes performing the alignment align _ [] = [] align maxColumns alignment -- Do not make an changes if we would go past the maximum number of columns@@ -70,17 +70,17 @@ Just c -> i > c -- The longest thing in the left column- longestLeft = maximum $ map (S.srcSpanEndCol . aLeft) alignment+ longestLeft = maximum $ map (GHC.srcSpanEndCol . aLeft) alignment -- The longest thing in the right column longestRight = maximum- [ S.srcSpanEndCol (aRight a) - S.srcSpanStartCol (aRight a)+ [ GHC.srcSpanEndCol (aRight a) - GHC.srcSpanStartCol (aRight a) + aRightLead a | a <- alignment ] - align' a = changeLine (S.srcSpanStartLine $ aContainer a) $ \str ->- let column = S.srcSpanEndCol $ aLeft a+ align' a = changeLine (GHC.srcSpanStartLine $ aContainer a) $ \str ->+ let column = GHC.srcSpanEndCol $ aLeft a (pre, post) = splitAt column str in [padRight longestLeft (trimRight pre) ++ trimLeft post] @@ -88,11 +88,11 @@ -- | Checks that all the alignables appear on a single line, and that they do -- not overlap. -fixable :: [Alignable S.RealSrcSpan] -> Bool+fixable :: [Alignable GHC.RealSrcSpan] -> Bool fixable [] = False fixable [_] = False fixable fields = all singleLine containers && nonOverlapping containers where containers = map aContainer fields- singleLine s = S.srcSpanStartLine s == S.srcSpanEndLine s- nonOverlapping ss = length ss == length (nub $ map S.srcSpanStartLine ss)+ singleLine s = GHC.srcSpanStartLine s == GHC.srcSpanEndLine s+ nonOverlapping ss = length ss == length (nub $ map GHC.srcSpanStartLine ss)
lib/Language/Haskell/Stylish/Block.hs view
@@ -2,6 +2,7 @@ module Language.Haskell.Stylish.Block ( Block (..) , LineBlock+ , realSrcSpanToLineBlock , SpanBlock , blockLength , moveBlock@@ -14,7 +15,8 @@ ---------------------------------------------------------------------------------import qualified Data.IntSet as IS+import qualified Data.IntSet as IS+import qualified GHC.Types.SrcLoc as GHC --------------------------------------------------------------------------------@@ -22,11 +24,15 @@ data Block a = Block { blockStart :: Int , blockEnd :: Int- }- deriving (Eq, Ord, Show)+ } deriving (Eq, Ord, Show) --------------------------------------------------------------------------------+instance Semigroup (Block a) where+ (<>) = merge+++-------------------------------------------------------------------------------- type LineBlock = Block String @@ -35,9 +41,15 @@ --------------------------------------------------------------------------------+realSrcSpanToLineBlock :: GHC.RealSrcSpan -> Block String+realSrcSpanToLineBlock s = Block (GHC.srcSpanStartLine s) (GHC.srcSpanEndLine s)+++-------------------------------------------------------------------------------- blockLength :: Block a -> Int blockLength (Block start end) = end - start + 1 + -------------------------------------------------------------------------------- moveBlock :: Int -> Block a -> Block a moveBlock offset (Block start end) = Block (start + offset) (end + offset)@@ -47,7 +59,7 @@ adjacent :: Block a -> Block a -> Bool adjacent b1 b2 = follows b1 b2 || follows b2 b1 where- follows (Block _ e1) (Block s2 _) = e1 + 1 == s2+ follows (Block _ e1) (Block s2 _) = e1 == s2 || e1 + 1 == s2 --------------------------------------------------------------------------------
+ lib/Language/Haskell/Stylish/Comments.hs view
@@ -0,0 +1,145 @@+--------------------------------------------------------------------------------+-- | Utilities for assocgating comments with things in a list.+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Language.Haskell.Stylish.Comments+ ( CommentGroup (..)+ , commentGroups+ , commentGroupHasComments+ , commentGroupSort+ ) where+++--------------------------------------------------------------------------------+import Data.Function (on)+import Data.List (sortBy, sortOn)+import Data.Maybe (isNothing, maybeToList)+import qualified GHC.Hs as GHC+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Utils.Outputable as GHC+++--------------------------------------------------------------------------------+import Language.Haskell.Stylish.Block+import Language.Haskell.Stylish.GHC+++--------------------------------------------------------------------------------+data CommentGroup a = CommentGroup+ { cgBlock :: LineBlock+ , cgPrior :: [GHC.LEpaComment]+ , cgItems :: [(a, Maybe GHC.LEpaComment)]+ , cgFollowing :: [GHC.LEpaComment]+ }+++--------------------------------------------------------------------------------+instance GHC.Outputable a => Show (CommentGroup a) where+ show CommentGroup {..} = "(CommentGroup (" +++ show cgBlock ++ ") (" +++ showOutputable cgPrior ++ ") (" +++ showOutputable cgItems ++ ") (" +++ showOutputable cgFollowing ++ "))"+++--------------------------------------------------------------------------------+commentGroups+ :: forall a.+ (a -> Maybe GHC.RealSrcSpan)+ -> [a]+ -> [GHC.LEpaComment]+ -> [CommentGroup a]+commentGroups getSpan allItems allComments =+ work Nothing (sortOn fst allItemsWithLines) (sortOn fst commentsWithLines)+ where+ allItemsWithLines :: [(LineBlock, a)]+ allItemsWithLines = do+ item <- allItems+ s <- maybeToList $ getSpan item+ pure (realSrcSpanToLineBlock s, item)++ commentsWithLines :: [(LineBlock, GHC.LEpaComment)]+ commentsWithLines = do+ comment <- allComments+ let s = GHC.anchor $ GHC.getLoc comment+ pure (realSrcSpanToLineBlock s, comment)++ work+ :: Maybe (CommentGroup a)+ -> [(LineBlock, a)]+ -> [(LineBlock, GHC.LEpaComment)]+ -> [CommentGroup a]+ work mbCurrent items comments = case takeNext items comments of+ Nothing -> maybeToList mbCurrent+ Just (b, next, items', comments') ->+ let (flush, current) = case mbCurrent of+ Just c | adjacent (cgBlock c) b+ , nextThingItem next+ , following@(_ : _) <- cgFollowing c ->+ ([c {cgFollowing = []}], CommentGroup b following [] [])+ Just c | adjacent (cgBlock c) b ->+ ([], c {cgBlock = cgBlock c <> b})+ _ -> (maybeToList mbCurrent, CommentGroup b [] [] [])+ current' = case next of+ NextItem i -> current {cgItems = cgItems current <> [(i, Nothing)]}+ NextComment c+ | null (cgItems current) -> current {cgPrior = cgPrior current <> [c]}+ | otherwise -> current {cgFollowing = cgFollowing current <> [c]}+ NextItemWithComment i c ->+ current {cgItems = cgItems current <> [(i, Just c)]} in+ flush ++ work (Just current') items' comments'++++--------------------------------------------------------------------------------+takeNext+ :: [(LineBlock, a)]+ -> [(LineBlock, GHC.LEpaComment)]+ -> Maybe (LineBlock, NextThing a, [(LineBlock, a)], [(LineBlock, GHC.LEpaComment)])+takeNext [] [] = Nothing+takeNext [] ((cb, c) : comments) =+ Just (cb, NextComment c, [], comments)+takeNext ((ib, i) : items) [] =+ Just (ib, NextItem i, items, [])+takeNext ((ib, i) : items) ((cb, c) : comments)+ | blockStart ib == blockStart cb =+ Just (ib <> cb, NextItemWithComment i c, items, comments)+ | blockStart ib < blockStart cb =+ Just (ib, NextItem i, items, (cb, c) : comments)+ | otherwise =+ Just (cb, NextComment c, (ib, i) : items, comments)+++--------------------------------------------------------------------------------+data NextThing a+ = NextComment GHC.LEpaComment+ | NextItem a+ | NextItemWithComment a GHC.LEpaComment+++--------------------------------------------------------------------------------+instance GHC.Outputable a => Show (NextThing a) where+ show (NextComment c) = "NextComment " ++ showOutputable c+ show (NextItem i) = "NextItem " ++ showOutputable i+ show (NextItemWithComment i c) =+ "NextItemWithComment " ++ showOutputable i ++ " " ++ showOutputable c+++--------------------------------------------------------------------------------+nextThingItem :: NextThing a -> Bool+nextThingItem (NextComment _) = False+nextThingItem (NextItem _) = True+nextThingItem (NextItemWithComment _ _) = True+++--------------------------------------------------------------------------------+commentGroupHasComments :: CommentGroup a -> Bool+commentGroupHasComments CommentGroup {..} = not $+ null cgPrior && all (isNothing . snd) cgItems && null cgFollowing+++--------------------------------------------------------------------------------+commentGroupSort :: (a -> a -> Ordering) -> CommentGroup a -> CommentGroup a+commentGroupSort cmp cg = cg+ { cgItems = sortBy (cmp `on` fst) (cgItems cg)+ }
lib/Language/Haskell/Stylish/Config.hs view
@@ -260,17 +260,14 @@ maybe Data.NoMaxColumns Data.MaxColumns (configColumns c) parseIndent :: A.Value -> A.Parser Data.Indent-parseIndent = A.withText "Indent" $ \t ->- if t == "same_line"- then return Data.SameLine- else- if "indent " `T.isPrefixOf` t- then- case readMaybe (T.unpack $ T.drop 7 t) of- Just n -> return $ Data.Indent n- Nothing -> fail $ "Indent: not a number" <> T.unpack (T.drop 7 t)- else fail $ "can't parse indent setting: " <> T.unpack t-+parseIndent = \case+ A.String "same_line" -> return Data.SameLine+ A.String t | "indent " `T.isPrefixOf` t ->+ case readMaybe (T.unpack $ T.drop 7 t) of+ Just n -> return $ Data.Indent n+ Nothing -> fail $ "Indent: not a number" <> T.unpack (T.drop 7 t)+ A.String t -> fail $ "can't parse indent setting: " <> T.unpack t+ _ -> fail "Expected string for indent value" -------------------------------------------------------------------------------- parseSquash :: Config -> A.Object -> A.Parser Step
lib/Language/Haskell/Stylish/Config/Cabal.hs view
@@ -11,7 +11,6 @@ import qualified Distribution.PackageDescription as Cabal import qualified Distribution.PackageDescription.Parsec as Cabal import qualified Distribution.Simple.Utils as Cabal-import qualified Distribution.Types.CondTree as Cabal import qualified Distribution.Verbosity as Cabal import qualified Language.Haskell.Extension as Language import Language.Haskell.Stylish.Verbose
lib/Language/Haskell/Stylish/Editor.hs view
@@ -9,7 +9,9 @@ -- when this is evaluated, we take into account that 4th line will become the -- 3rd line before it needs changing. module Language.Haskell.Stylish.Editor- ( Change+ ( module Language.Haskell.Stylish.Block++ , Change , applyChanges , change
lib/Language/Haskell/Stylish/GHC.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wno-missing-fields #-} -- | Utility functions for working with the GHC AST module Language.Haskell.Stylish.GHC@@ -11,35 +12,39 @@ , getStartLineUnsafe -- * Standard settings , baseDynFlags- -- * Positions- , unLocated -- * Outputable operators , showOutputable- , compareOutputable- ) where ----------------------------------------------------------------------------------import Data.Function (on)+ -- * Deconstruction+ , epAnnComments+ , deepAnnComments+ ) where ---------------------------------------------------------------------------------import DynFlags (Settings (..), defaultDynFlags)-import qualified DynFlags as GHC-import FileSettings (FileSettings (..))-import GHC.Fingerprint (fingerprint0)-import GHC.Platform-import GHC.Version (cProjectVersion)-import GhcNameVersion (GhcNameVersion (..))-import qualified Outputable as GHC-import PlatformConstants (PlatformConstants (..))-import SrcLoc (GenLocated (..), Located, RealLocated,- RealSrcSpan, SrcSpan (..), srcSpanEndLine,- srcSpanStartLine)-import ToolSettings (ToolSettings (..))+import Data.Generics (Data,+ Typeable,+ everything,+ mkQ)+import Data.List (sortOn)+import qualified GHC.Driver.Ppr as GHC (showPpr)+import GHC.Driver.Session (defaultDynFlags)+import qualified GHC.Driver.Session as GHC+import qualified GHC.Hs as GHC+import GHC.Types.SrcLoc (GenLocated (..),+ Located,+ RealLocated,+ RealSrcSpan,+ SrcSpan (..),+ srcSpanEndLine,+ srcSpanStartLine)+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Utils.Outputable as GHC+import qualified Language.Haskell.GhclibParserEx.GHC.Settings.Config as GHCEx unsafeGetRealSrcSpan :: Located a -> RealSrcSpan unsafeGetRealSrcSpan = \case- (L (RealSrcSpan s) _) -> s- _ -> error "could not get source code location"+ (L (RealSrcSpan s _) _) -> s+ _ -> error "could not get source code location" getStartLineUnsafe :: Located a -> Int getStartLineUnsafe = srcSpanStartLine . unsafeGetRealSrcSpan@@ -49,13 +54,13 @@ dropAfterLocated :: Maybe (Located a) -> [RealLocated b] -> [RealLocated b] dropAfterLocated loc xs = case loc of- Just (L (RealSrcSpan rloc) _) ->+ Just (L (RealSrcSpan rloc _) _) -> filter (\(L x _) -> srcSpanEndLine rloc >= srcSpanStartLine x) xs _ -> xs dropBeforeLocated :: Maybe (Located a) -> [RealLocated b] -> [RealLocated b] dropBeforeLocated loc xs = case loc of- Just (L (RealSrcSpan rloc) _) ->+ Just (L (RealSrcSpan rloc _) _) -> filter (\(L x _) -> srcSpanStartLine rloc <= srcSpanEndLine x) xs _ -> xs @@ -63,41 +68,19 @@ dropBeforeAndAfter loc = dropBeforeLocated (Just loc) . dropAfterLocated (Just loc) baseDynFlags :: GHC.DynFlags-baseDynFlags = defaultDynFlags fakeSettings llvmConfig- where- fakeSettings = GHC.Settings- { sGhcNameVersion = GhcNameVersion "stylish-haskell" cProjectVersion- , sFileSettings = FileSettings {}- , sToolSettings = ToolSettings- { toolSettings_opt_P_fingerprint = fingerprint0,- toolSettings_pgm_F = ""- }- , sPlatformConstants = PlatformConstants- { pc_DYNAMIC_BY_DEFAULT = False- , pc_WORD_SIZE = 8- }- , sTargetPlatform = Platform- { platformMini = PlatformMini- { platformMini_arch = ArchUnknown- , platformMini_os = OSUnknown- }- , platformWordSize = PW8- , platformUnregisterised = True- , platformHasIdentDirective = False- , platformHasSubsectionsViaSymbols = False- , platformIsCrossCompiling = False- }- , sPlatformMisc = PlatformMisc {}- , sRawSettings = []- }-- llvmConfig = GHC.LlvmConfig [] []--unLocated :: Located a -> a-unLocated (L _ a) = a+baseDynFlags = defaultDynFlags GHCEx.fakeSettings GHCEx.fakeLlvmConfig showOutputable :: GHC.Outputable a => a -> String showOutputable = GHC.showPpr baseDynFlags -compareOutputable :: GHC.Outputable a => a -> a -> Ordering-compareOutputable = compare `on` showOutputable+epAnnComments :: GHC.EpAnn a -> [GHC.LEpaComment]+epAnnComments GHC.EpAnnNotUsed = []+epAnnComments GHC.EpAnn {..} = priorAndFollowing comments++deepAnnComments :: (Data a, Typeable a) => a -> [GHC.LEpaComment]+deepAnnComments = everything (++) (mkQ [] priorAndFollowing)++priorAndFollowing :: GHC.EpAnnComments -> [GHC.LEpaComment]+priorAndFollowing = sortOn (GHC.anchor . GHC.getLoc) . \case+ GHC.EpaComments {..} -> priorComments+ GHC.EpaCommentsBalanced {..} -> priorComments ++ followingComments
lib/Language/Haskell/Stylish/Module.hs view
@@ -1,199 +1,89 @@-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-} module Language.Haskell.Stylish.Module ( -- * Data types- Module (..)- , ModuleHeader- , Import- , Decls- , Comments+ Module+ , Comments (..) , Lines- , makeModule -- * Getters- , moduleHeader- , moduleImports , moduleImportGroups- , moduleDecls- , moduleComments- , moduleLanguagePragmas , queryModule , groupByLine -- * Imports , canMergeImport , mergeModuleImport-- -- * Annotations- , lookupAnnotation+ , importModuleName - -- * Internal API getters- , rawComments- , rawImport- , rawModuleAnnotations- , rawModuleDecls- , rawModuleExports- , rawModuleHaddocks- , rawModuleName+ -- * Pragmas+ , moduleLanguagePragmas ) where ----------------------------------------------------------------------------------import Data.Function ((&), on)-import Data.Functor ((<&>))-import Data.Generics (Typeable, everything, mkQ)-import Data.Maybe (mapMaybe)-import Data.Map (Map)-import qualified Data.Map as Map-import Data.List (nubBy, sort)-import Data.List.NonEmpty (NonEmpty (..), nonEmpty)-import Data.Text (Text)-import qualified Data.Text as T-import Data.Data (Data) ---------------------------------------------------------------------------------import qualified ApiAnnotation as GHC-import qualified Lexer as GHC-import GHC.Hs (ImportDecl(..), ImportDeclQualifiedStyle(..))-import qualified GHC.Hs as GHC-import GHC.Hs.Extension (GhcPs)-import GHC.Hs.Decls (LHsDecl)-import Outputable (Outputable)-import SrcLoc (GenLocated(..), RealLocated)-import SrcLoc (RealSrcSpan(..), SrcSpan(..))-import SrcLoc (Located)-import qualified SrcLoc as GHC-import qualified Module as GHC+import Data.Char (toLower)+import Data.Function (on)+import Data.Generics (Typeable, everything, mkQ)+import qualified Data.List as L+import Data.List.NonEmpty (NonEmpty (..))+import Data.Maybe (fromMaybe, mapMaybe)+import GHC.Hs (ImportDecl (..),+ ImportDeclQualifiedStyle (..))+import qualified GHC.Hs as GHC+import GHC.Hs.Extension (GhcPs)+import GHC.Types.SrcLoc (GenLocated (..),+ RealSrcSpan (..), unLoc)+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Unit.Module.Name as GHC + -------------------------------------------------------------------------------- import Language.Haskell.Stylish.GHC + -------------------------------------------------------------------------------- type Lines = [String] -------------------------------------------------------------------------------- -- | Concrete module type-data Module = Module- { parsedComments :: [GHC.RealLocated GHC.AnnotationComment]- , parsedAnnotations :: [(GHC.ApiAnnKey, [GHC.SrcSpan])]- , parsedAnnotSrcs :: Map RealSrcSpan [GHC.AnnKeywordId]- , parsedModule :: GHC.Located (GHC.HsModule GhcPs)- } deriving (Data)---- | Declarations in module-newtype Decls = Decls [LHsDecl GhcPs]+type Module = GHC.Located GHC.HsModule --- | Import declaration in module-newtype Import = Import { unImport :: ImportDecl GhcPs }- deriving newtype (Outputable)+importModuleName :: ImportDecl GhcPs -> String+importModuleName = GHC.moduleNameString . GHC.unLoc . GHC.ideclName -- | Returns true if the two import declarations can be merged-canMergeImport :: Import -> Import -> Bool-canMergeImport (Import i0) (Import i1) = and $ fmap (\f -> f i0 i1)- [ (==) `on` unLocated . ideclName+canMergeImport :: ImportDecl GhcPs -> ImportDecl GhcPs -> Bool+canMergeImport i0 i1 = and $ fmap (\f -> f i0 i1)+ [ (==) `on` unLoc . ideclName , (==) `on` ideclPkgQual , (==) `on` ideclSource , hasMergableQualified `on` ideclQualified , (==) `on` ideclImplicit- , (==) `on` fmap unLocated . ideclAs+ , (==) `on` fmap unLoc . ideclAs , (==) `on` fmap fst . ideclHiding -- same 'hiding' flags ] where hasMergableQualified QualifiedPre QualifiedPost = True hasMergableQualified QualifiedPost QualifiedPre = True- hasMergableQualified q0 q1 = q0 == q1--instance Eq Import where- i0 == i1 = canMergeImport i0 i1 && hasSameImports (unImport i0) (unImport i1)- where- hasSameImports = (==) `on` fmap snd . ideclHiding--instance Ord Import where- compare (Import i0) (Import i1) =- ideclName i0 `compareOutputable` ideclName i1 <>- fmap showOutputable (ideclPkgQual i0) `compare`- fmap showOutputable (ideclPkgQual i1) <>- compareOutputable i0 i1+ hasMergableQualified q0 q1 = q0 == q1 -- | Comments associated with module-newtype Comments = Comments [GHC.RealLocated GHC.AnnotationComment]---- | A module header is its name, exports and haddock docstring-data ModuleHeader = ModuleHeader- { name :: Maybe (GHC.Located GHC.ModuleName)- , exports :: Maybe (GHC.Located [GHC.LIE GhcPs])- , haddocks :: Maybe GHC.LHsDocString- }---- | Create a module from GHC internal representations-makeModule :: GHC.PState -> GHC.Located (GHC.HsModule GHC.GhcPs) -> Module-makeModule pstate = Module comments annotations annotationMap- where- comments- = sort- . filterRealLocated- $ GHC.comment_q pstate ++ (GHC.annotations_comments pstate >>= snd)-- filterRealLocated = mapMaybe \case- GHC.L (GHC.RealSrcSpan s) e -> Just (GHC.L s e)- GHC.L (GHC.UnhelpfulSpan _) _ -> Nothing-- annotations- = GHC.annotations pstate-- annotationMap- = GHC.annotations pstate- & mapMaybe x- & Map.fromListWith (++)-- x = \case- ((RealSrcSpan rspan, annot), _) -> Just (rspan, [annot])- _ -> Nothing---- | Get all declarations in module-moduleDecls :: Module -> Decls-moduleDecls = Decls . GHC.hsmodDecls . unLocated . parsedModule---- | Get comments in module-moduleComments :: Module -> Comments-moduleComments = Comments . parsedComments---- | Get module language pragmas-moduleLanguagePragmas :: Module -> [(RealSrcSpan, NonEmpty Text)]-moduleLanguagePragmas = mapMaybe toLanguagePragma . parsedComments- where- toLanguagePragma :: RealLocated GHC.AnnotationComment -> Maybe (RealSrcSpan, NonEmpty Text)- toLanguagePragma = \case- L pos (GHC.AnnBlockComment s) ->- Just (T.pack s)- >>= T.stripPrefix "{-#"- >>= T.stripSuffix "#-}"- <&> T.strip- <&> T.splitAt 8 -- length "LANGUAGE"- <&> fmap (T.splitOn ",")- <&> fmap (fmap T.strip)- <&> fmap (filter (not . T.null))- >>= (\(T.toUpper . T.strip -> lang, xs) -> (lang,) <$> nonEmpty xs)- >>= (\(lang, nel) -> if lang == "LANGUAGE" then Just (pos, nel) else Nothing)- _ -> Nothing---- | Get module imports-moduleImports :: Module -> [Located Import]-moduleImports m- = parsedModule m- & unLocated- & GHC.hsmodImports- & fmap \(L pos i) -> L pos (Import i)+newtype Comments = Comments [GHC.RealLocated GHC.EpaComment] -- | Get groups of imports from module-moduleImportGroups :: Module -> [NonEmpty (Located Import)]-moduleImportGroups = groupByLine unsafeGetRealSrcSpan . moduleImports+moduleImportGroups :: Module -> [NonEmpty (GHC.LImportDecl GHC.GhcPs)]+moduleImportGroups =+ groupByLine (fromMaybe err . GHC.srcSpanToRealSrcSpan . GHC.getLocA) .+ GHC.hsmodImports . GHC.unLoc+ where+ err = error "moduleImportGroups: import without soure span" -- The same logic as 'Language.Haskell.Stylish.Module.moduleImportGroups'. groupByLine :: (a -> RealSrcSpan) -> [a] -> [NonEmpty a]@@ -223,9 +113,11 @@ -- comment imports themselves. It _is_ however, systemic and it'd be better -- if we processed comments beforehand and attached them to all AST nodes in -- our own representation.-mergeModuleImport :: Located Import -> Located Import -> Located Import-mergeModuleImport (L p0 (Import i0)) (L _p1 (Import i1)) =- L p0 $ Import i0 { ideclHiding = newImportNames }+mergeModuleImport+ :: GHC.LImportDecl GHC.GhcPs -> GHC.LImportDecl GHC.GhcPs+ -> GHC.LImportDecl GHC.GhcPs+mergeModuleImport (L p0 i0) (L _p1 i1) =+ L p0 $ i0 { ideclHiding = newImportNames } where newImportNames = case (ideclHiding i0, ideclHiding i1) of@@ -234,50 +126,24 @@ (Just x, Nothing) -> Just x (Nothing, Just x) -> Just x merge xs ys- = nubBy ((==) `on` showOutputable) (xs ++ ys)---- | Get module header-moduleHeader :: Module -> ModuleHeader-moduleHeader (Module _ _ _ (GHC.L _ m)) = ModuleHeader- { name = GHC.hsmodName m- , exports = GHC.hsmodExports m- , haddocks = GHC.hsmodHaddockModHeader m- }---- | Query for annotations associated with a 'SrcSpan'-lookupAnnotation :: SrcSpan -> Module -> [GHC.AnnKeywordId]-lookupAnnotation (RealSrcSpan rspan) m = Map.findWithDefault [] rspan (parsedAnnotSrcs m)-lookupAnnotation (UnhelpfulSpan _) _ = []+ = L.nubBy ((==) `on` showOutputable) (xs ++ ys) -- | Query the module AST using @f@ queryModule :: Typeable a => (a -> [b]) -> Module -> [b]-queryModule f = everything (++) (mkQ [] f) . parsedModule------------------------------------------------------------------------------------- | Getter for internal components in imports newtype-rawImport :: Import -> ImportDecl GhcPs-rawImport (Import i) = i---- | Getter for internal module name representation-rawModuleName :: ModuleHeader -> Maybe (GHC.Located GHC.ModuleName)-rawModuleName = name---- | Getter for internal module exports representation-rawModuleExports :: ModuleHeader -> Maybe (GHC.Located [GHC.LIE GhcPs])-rawModuleExports = exports---- | Getter for internal module haddocks representation-rawModuleHaddocks :: ModuleHeader -> Maybe GHC.LHsDocString-rawModuleHaddocks = haddocks---- | Getter for internal module decls representation-rawModuleDecls :: Decls -> [LHsDecl GhcPs]-rawModuleDecls (Decls xs) = xs+queryModule f = everything (++) (mkQ [] f) --- | Getter for internal module comments representation-rawComments :: Comments -> [GHC.RealLocated GHC.AnnotationComment]-rawComments (Comments xs) = xs+moduleLanguagePragmas :: Module -> [(RealSrcSpan, NonEmpty String)]+moduleLanguagePragmas =+ mapMaybe prag . epAnnComments . GHC.hsmodAnn . GHC.unLoc+ where+ prag :: GHC.LEpaComment -> Maybe (GHC.RealSrcSpan, NonEmpty String)+ prag comment = case GHC.ac_tok (GHC.unLoc comment) of+ GHC.EpaBlockComment str+ | lang : p1 : ps <- tokenize str, map toLower lang == "language" ->+ pure (GHC.anchor (GHC.getLoc comment), p1 :| ps)+ _ -> Nothing --- | Getter for internal module annotation representation-rawModuleAnnotations :: Module -> [(GHC.ApiAnnKey, [GHC.SrcSpan])]-rawModuleAnnotations = parsedAnnotations+ tokenize = words .+ map (\c -> if c == ',' then ' ' else c) .+ takeWhile (/= '#') .+ drop 1 . dropWhile (/= '#')
lib/Language/Haskell/Stylish/Ordering.hs view
@@ -4,23 +4,36 @@ -- utilities. {-# LANGUAGE LambdaCase #-} module Language.Haskell.Stylish.Ordering- ( compareLIE+ ( compareImports+ , compareLIE , compareWrappedName- , unwrapName+ , compareOutputableCI ) where ---------------------------------------------------------------------------------import Data.Char (isUpper)-import Data.Ord (comparing)+import Data.Char (isUpper, toLower)+import Data.Function (on)+import Data.Ord (comparing) import GHC.Hs-import RdrName (RdrName)-import SrcLoc (unLoc)+import qualified GHC.Hs as GHC+import GHC.Types.Name.Reader (RdrName)+import GHC.Types.SrcLoc (unLoc)+import GHC.Utils.Outputable (Outputable)+import qualified GHC.Utils.Outputable as GHC+import Language.Haskell.Stylish.GHC (showOutputable) ---------------------------------------------------------------------------------import Language.Haskell.Stylish.GHC (showOutputable)-import Outputable (Outputable)+-- | Compare imports for sorting. Cannot easily be a lawful instance due to+-- case insensitivity.+compareImports+ :: GHC.ImportDecl GHC.GhcPs -> GHC.ImportDecl GHC.GhcPs -> Ordering+compareImports i0 i1 =+ ideclName i0 `compareOutputableCI` ideclName i1 <>+ fmap showOutputable (ideclPkgQual i0) `compare`+ fmap showOutputable (ideclPkgQual i1) <>+ compareOutputableCI i0 i1 --------------------------------------------------------------------------------@@ -33,12 +46,12 @@ -- constructors first, followed by functions, and then operators. ieKey :: IE GhcPs -> (Int, String) ieKey = \case- IEVar _ n -> nameKey n- IEThingAbs _ n -> nameKey n- IEThingAll _ n -> nameKey n- IEThingWith _ n _ _ _ -> nameKey n- IEModuleContents _ n -> nameKey n- _ -> (2, "")+ IEVar _ n -> nameKey n+ IEThingAbs _ n -> nameKey n+ IEThingAll _ n -> nameKey n+ IEThingWith _ n _ _ -> nameKey n+ IEModuleContents _ n -> nameKey n+ _ -> (2, "") --------------------------------------------------------------------------------@@ -47,15 +60,13 @@ ---------------------------------------------------------------------------------unwrapName :: IEWrappedName n -> n-unwrapName (IEName n) = unLoc n-unwrapName (IEPattern n) = unLoc n-unwrapName (IEType n) = unLoc n----------------------------------------------------------------------------------- nameKey :: Outputable name => name -> (Int, String) nameKey n = case showOutputable n of o@('(' : _) -> (2, o) o@(o0 : _) | isUpper o0 -> (0, o) o -> (1, o)+++--------------------------------------------------------------------------------+compareOutputableCI :: GHC.Outputable a => a -> a -> Ordering+compareOutputableCI = compare `on` (map toLower . showOutputable)
lib/Language/Haskell/Stylish/Parse.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE LambdaCase #-} -------------------------------------------------------------------------------- module Language.Haskell.Stylish.Parse ( parseModule@@ -6,35 +5,36 @@ ---------------------------------------------------------------------------------import Data.Function ((&))-import Data.Maybe (fromMaybe, listToMaybe)-import System.IO.Unsafe (unsafePerformIO)+import Control.Monad ((>=>))+import Data.List (foldl',+ stripPrefix)+import Data.Maybe (fromMaybe,+ listToMaybe,+ mapMaybe)+import Data.Traversable (for)+import qualified GHC.Data.StringBuffer as GHC+import GHC.Driver.Ppr as GHC+import qualified GHC.Driver.Session as GHC+import qualified GHC.LanguageExtensions.Type as LangExt+import qualified GHC.Parser.Errors.Ppr as GHC+import qualified GHC.Parser.Header as GHC+import qualified GHC.Parser.Lexer as GHC+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Utils.Error as GHC+import qualified GHC.Utils.Outputable as GHC+import qualified Language.Haskell.GhclibParserEx.GHC.Driver.Session as GHCEx+import qualified Language.Haskell.GhclibParserEx.GHC.Parser as GHCEx ----------------------------------------------------------------------------------import Bag (bagToList)-import qualified DynFlags as GHC-import qualified ErrUtils as GHC-import FastString (mkFastString)-import qualified GHC.Hs as GHC-import qualified GHC.LanguageExtensions as GHC-import qualified HeaderInfo as GHC-import qualified HscTypes as GHC-import Lexer (ParseResult (..))-import Lexer (mkPState, unP)-import qualified Lexer as GHC-import qualified Panic as GHC-import qualified Parser as GHC-import SrcLoc (mkRealSrcLoc)-import qualified SrcLoc as GHC-import StringBuffer (stringToStringBuffer)-import qualified StringBuffer as GHC ---------------------------------------------------------------------------------import Language.Haskell.Stylish.GHC (baseDynFlags)+import Language.Haskell.Stylish.GHC import Language.Haskell.Stylish.Module ++-------------------------------------------------------------------------------- type Extensions = [String] + -------------------------------------------------------------------------------- -- | Filter out lines which use CPP macros unCpp :: String -> String@@ -46,6 +46,7 @@ nextMultiline = isCpp && not (null x) && last x == '\\' in (if isCpp then "" else x) : go nextMultiline xs + -------------------------------------------------------------------------------- -- | If the given string is prefixed with an UTF-8 Byte Order Mark, drop it -- because haskell-src-exts can't handle it.@@ -57,67 +58,41 @@ -------------------------------------------------------------------------------- -- | Abstraction over GHC lib's parsing parseModule :: Extensions -> Maybe FilePath -> String -> Either String Module-parseModule exts fp string =- parsePragmasIntoDynFlags baseDynFlags userExtensions filePath string >>= \dynFlags ->- dropBom string- & removeCpp dynFlags- & runParser dynFlags- & toModule dynFlags- where- toModule :: GHC.DynFlags -> GHC.ParseResult (GHC.Located (GHC.HsModule GHC.GhcPs)) -> Either String Module- toModule dynFlags res = case res of- POk ps m ->- Right (makeModule ps m)- PFailed failureState ->- let- withFileName x = maybe "" (<> ": ") fp <> x- in- Left . withFileName . unlines . getParserStateErrors dynFlags $ failureState-- removeCpp dynFlags s =- if GHC.xopt GHC.Cpp dynFlags then unCpp s- else s-- userExtensions =- fmap toLocatedExtensionFlag ("Haskell2010" : exts) -- FIXME: do we need `Haskell2010` here?+parseModule externalExts0 fp string = do+ -- Parse extensions.+ externalExts1 <- for externalExts0 $ \s -> case GHCEx.readExtension s of+ Nothing -> Left $ "Unknown extension: " ++ show s+ Just e -> Right e - toLocatedExtensionFlag flag- = "-X" <> flag- & GHC.L GHC.noSrcSpan+ -- Build first dynflags.+ let dynFlags0 = foldl' turnOn baseDynFlags externalExts1 - getParserStateErrors dynFlags state- = GHC.getErrorMessages state dynFlags- & bagToList- & fmap (\errMsg -> show (GHC.errMsgSpan errMsg) <> ": " <> show errMsg)+ -- Parse options from file+ let fileOptions = fmap GHC.unLoc $ GHC.getOptions dynFlags0+ (GHC.stringToStringBuffer string)+ (fromMaybe "-" fp)+ fileExtensions = mapMaybe+ (stripPrefix "-X" >=> GHCEx.readExtension)+ fileOptions - filePath =- fromMaybe "<interactive>" fp+ -- Set further dynflags.+ let dynFlags1 = foldl' turnOn dynFlags0 fileExtensions+ `GHC.gopt_set` GHC.Opt_KeepRawTokenStream - runParser :: GHC.DynFlags -> String -> GHC.ParseResult (GHC.Located (GHC.HsModule GHC.GhcPs))- runParser flags str =- let- filename = mkFastString filePath- parseState = mkPState flags (stringToStringBuffer str) (mkRealSrcLoc filename 1 1)- in- unP GHC.parseModule parseState+ -- Possibly strip CPP.+ let removeCpp s = if GHC.xopt LangExt.Cpp dynFlags1 then unCpp s else s+ input = removeCpp $ dropBom string --- | Parse 'DynFlags' from the extra options------ /Note:/ this function would be IO, but we're not using any of the internal--- features that constitute side effectful computation. So I think it's fine--- if we run this to avoid changing the interface too much.-parsePragmasIntoDynFlags ::- GHC.DynFlags- -> [GHC.Located String]- -> FilePath- -> String- -> Either String GHC.DynFlags-{-# NOINLINE parsePragmasIntoDynFlags #-}-parsePragmasIntoDynFlags originalFlags extraOpts filepath str = unsafePerformIO $ catchErrors $ do- let opts = GHC.getOptions originalFlags (GHC.stringToStringBuffer str) filepath- (parsedFlags, _invalidFlags, _warnings) <- GHC.parseDynamicFilePragma originalFlags (opts <> extraOpts)- -- FIXME: have a look at 'leftovers' since it should be empty- return $ Right $ parsedFlags `GHC.gopt_set` GHC.Opt_KeepRawTokenStream+ -- Actual parse.+ case GHCEx.parseModule input dynFlags1 of+ GHC.POk _ m -> Right m+ GHC.PFailed ps -> Left . withFileName . GHC.showSDoc dynFlags1 .+ GHC.vcat . GHC.pprMsgEnvelopeBagWithLoc . fmap GHC.pprError . snd $+ GHC.getMessages ps where- catchErrors act = GHC.handleGhcException reportErr (GHC.handleSourceError reportErr act)- reportErr e = return $ Left (show e)+ withFileName x = maybe "" (<> ": ") fp <> x++ turnOn dynFlags ext = foldl'+ turnOn+ (GHC.xopt_set dynFlags ext)+ [rhs | (lhs, True, rhs) <- GHC.impliedXFlags, lhs == ext]
lib/Language/Haskell/Stylish/Printer.hs view
@@ -1,10 +1,10 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DoAndIfThenElse #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-} module Language.Haskell.Stylish.Printer ( Printer(..) , PrinterConfig(..)@@ -20,28 +20,19 @@ -- ** Combinators , comma , dot- , getAnnot , getCurrentLine , getCurrentLineLength- , getDocstrPrev , newline , parenthesize- , peekNextCommentPos , prefix , putComment- , putEolComment+ , putMaybeLineComment , putOutputable- , putAllSpanComments , putCond , putType , putRdrName , putText- , removeCommentTo- , removeCommentToEnd- , removeLineComment , sep- , groupAttachedComments- , groupWithoutComments , space , spaces , suffix@@ -57,31 +48,26 @@ import Prelude hiding (lines) ---------------------------------------------------------------------------------import ApiAnnotation (AnnKeywordId(..), AnnotationComment(..))-import BasicTypes (PromotionFlag(..))-import GHC.Hs.Extension (GhcPs, NoExtField(..))-import GHC.Hs.Types (HsType(..))-import Module (ModuleName, moduleNameString)-import RdrName (RdrName(..))-import SrcLoc (GenLocated(..), RealLocated)-import SrcLoc (Located, SrcSpan(..))-import SrcLoc (srcSpanStartLine, srcSpanEndLine)-import Outputable (Outputable)+import qualified GHC.Hs as GHC+import GHC.Hs.Extension (GhcPs)+import qualified GHC.Types.Basic as GHC+import GHC.Types.Name.Reader (RdrName (..))+import GHC.Types.SrcLoc (GenLocated (..))+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Unit.Module.Name as GHC+import GHC.Utils.Outputable (Outputable) -------------------------------------------------------------------------------- import Control.Monad (forM_, replicateM_)-import Control.Monad.Reader (MonadReader, ReaderT(..), asks, local)-import Control.Monad.State (MonadState, State)-import Control.Monad.State (runState)-import Control.Monad.State (get, gets, modify, put)-import Data.Foldable (find, toList)-import Data.Functor ((<&>))-import Data.List (delete, isPrefixOf)-import Data.List.NonEmpty (NonEmpty(..))+import Control.Monad.Reader (MonadReader, ReaderT (..),+ asks, local)+import Control.Monad.State (MonadState, State, get, gets,+ modify, put, runState)+import Data.List (foldl') ---------------------------------------------------------------------------------import Language.Haskell.Stylish.Module (Module, Lines, lookupAnnotation)-import Language.Haskell.Stylish.GHC (showOutputable, unLocated)+import Language.Haskell.Stylish.GHC (showOutputable)+import Language.Haskell.Stylish.Module (Lines) -- | Shorthand for 'Printer' monad type P = Printer@@ -97,24 +83,22 @@ -- | State of printer data PrinterState = PrinterState- { lines :: !Lines- , linePos :: !Int+ { lines :: !Lines+ , linePos :: !Int , currentLine :: !String- , pendingComments :: ![RealLocated AnnotationComment]- , parsedModule :: !Module } -- | Run printer to get printed lines out of module as well as return value of monad-runPrinter :: PrinterConfig -> [RealLocated AnnotationComment] -> Module -> Printer a -> (a, Lines)-runPrinter cfg comments m (Printer printer) =+runPrinter :: PrinterConfig -> Printer a -> (a, Lines)+runPrinter cfg (Printer printer) = let- (a, PrinterState parsedLines _ startedLine _ _) = runReaderT printer cfg `runState` PrinterState [] 0 "" comments m+ (a, PrinterState parsedLines _ startedLine) = runReaderT printer cfg `runState` PrinterState [] 0 "" in (a, parsedLines <> if startedLine == [] then [] else [startedLine]) -- | Run printer to get printed lines only-runPrinter_ :: PrinterConfig -> [RealLocated AnnotationComment] -> Module -> Printer a -> Lines-runPrinter_ cfg comments m printer = snd (runPrinter cfg comments m printer)+runPrinter_ :: PrinterConfig -> Printer a -> Lines+runPrinter_ cfg printer = snd (runPrinter cfg printer) -- | Print text putText :: String -> P ()@@ -137,6 +121,7 @@ -- | Put all comments that has positions within 'SrcSpan' and separate by -- passed @P ()@+{- putAllSpanComments :: P () -> SrcSpan -> P () putAllSpanComments suff = \case UnhelpfulSpan _ -> pure ()@@ -146,150 +131,143 @@ srcSpanEndLine rloc <= srcSpanEndLine rspan forM_ cmts (\c -> putComment c >> suff)+-} -- | Print any comment-putComment :: AnnotationComment -> P ()-putComment = \case- AnnLineComment s -> putText s- AnnDocCommentNext s -> putText s- AnnDocCommentPrev s -> putText s- AnnDocCommentNamed s -> putText s- AnnDocSection _ s -> putText s- AnnDocOptions s -> putText s- AnnBlockComment s -> putText s+putComment :: GHC.EpaComment -> P ()+putComment epaComment = case GHC.ac_tok epaComment of+ GHC.EpaLineComment s -> putText s+ GHC.EpaDocCommentNext s -> putText s+ GHC.EpaDocCommentPrev s -> putText s+ GHC.EpaDocCommentNamed s -> putText s+ GHC.EpaDocSection _ s -> putText s+ GHC.EpaDocOptions s -> putText s+ GHC.EpaBlockComment s -> putText s+ GHC.EpaEofComment -> pure () --- | Given the current start line of 'SrcSpan', remove and put EOL comment for same line-putEolComment :: SrcSpan -> P ()-putEolComment = \case- RealSrcSpan rspan -> do- cmt <- removeComment \case- L rloc (AnnLineComment s) ->- and- [ srcSpanStartLine rspan == srcSpanStartLine rloc- , not ("-- ^" `isPrefixOf` s)- , not ("-- |" `isPrefixOf` s)- ]- _ -> False- forM_ cmt (\c -> space >> putComment c)- UnhelpfulSpan _ -> pure ()+putMaybeLineComment :: Maybe GHC.EpaComment -> P ()+putMaybeLineComment = \case+ Nothing -> pure ()+ Just cmt -> space >> putComment cmt -- | Print a 'RdrName'-putRdrName :: Located RdrName -> P ()-putRdrName (L pos n) = case n of- Unqual name -> do- annots <- getAnnot pos- if AnnOpenP `elem` annots then do- putText "("- putText (showOutputable name)- putText ")"- else if AnnBackquote `elem` annots then do- putText "`"+putRdrName :: GenLocated GHC.SrcSpanAnnN RdrName -> P ()+putRdrName rdrName = case GHC.unLoc rdrName of+ Unqual name -> do+ let (pre, post) = nameAnnAdornments $+ GHC.epAnnAnnsL $ GHC.ann $ GHC.getLoc rdrName+ putText pre putText (showOutputable name)- putText "`"- else if AnnSimpleQuote `elem` annots then do- putText "'"+ putText post+ Qual modulePrefix name ->+ putModuleName modulePrefix >> dot >> putText (showOutputable name)+ Orig _ name -> putText (showOutputable name)- else+ Exact name -> putText (showOutputable name)- Qual modulePrefix name ->- putModuleName modulePrefix >> dot >> putText (showOutputable name)- Orig _ name ->- putText (showOutputable name)- Exact name ->- putText (showOutputable name) +nameAnnAdornments :: [GHC.NameAnn] -> (String, String)+nameAnnAdornments = foldl'+ (\(accl, accr) nameAnn ->+ let (l, r) = nameAnnAdornment nameAnn in (accl ++ l, r ++ accr))+ (mempty, mempty)++nameAnnAdornment :: GHC.NameAnn -> (String, String)+nameAnnAdornment = \case+ GHC.NameAnn {..} -> fromAdornment nann_adornment+ GHC.NameAnnCommas {..} -> fromAdornment nann_adornment+ GHC.NameAnnOnly {..} -> fromAdornment nann_adornment+ GHC.NameAnnRArrow {} -> (mempty, mempty)+ GHC.NameAnnQuote {} -> ("'", mempty)+ GHC.NameAnnTrailing {} -> (mempty, mempty)+ where+ fromAdornment GHC.NameParens = ("(", ")")+ fromAdornment GHC.NameBackquotes = ("`", "`")+ fromAdornment GHC.NameParensHash = ("#(", "#)")+ fromAdornment GHC.NameSquare = ("[", "]")+ -- | Print module name-putModuleName :: ModuleName -> P ()-putModuleName = putText . moduleNameString+putModuleName :: GHC.ModuleName -> P ()+putModuleName = putText . GHC.moduleNameString -- | Print type-putType :: Located (HsType GhcPs) -> P ()-putType ltp = case unLocated ltp of- HsFunTy NoExtField argTp funTp -> do+putType :: GHC.LHsType GhcPs -> P ()+putType ltp = case GHC.unLoc ltp of+ GHC.HsFunTy _ arrowTp argTp funTp -> do putOutputable argTp space- putText "->"+ case arrowTp of+ GHC.HsUnrestrictedArrow {} -> putText "->"+ GHC.HsLinearArrow {} -> putText "%1 ->"+ GHC.HsExplicitMult {} -> putOutputable arrowTp space putType funTp- HsAppTy NoExtField t1 t2 ->+ GHC.HsAppTy _ t1 t2 -> putType t1 >> space >> putType t2- HsExplicitListTy NoExtField _ xs -> do+ GHC.HsExplicitListTy _ _ xs -> do putText "'[" sep (comma >> space) (fmap putType xs) putText "]"- HsExplicitTupleTy NoExtField xs -> do+ GHC.HsExplicitTupleTy _ xs -> do putText "'(" sep (comma >> space) (fmap putType xs) putText ")"- HsOpTy NoExtField lhs op rhs -> do+ GHC.HsOpTy _ lhs op rhs -> do putType lhs space putRdrName op space putType rhs- HsTyVar NoExtField flag rdrName -> do+ GHC.HsTyVar _ flag rdrName -> do case flag of- IsPromoted -> putText "'"- NotPromoted -> pure ()+ GHC.IsPromoted -> putText "'"+ GHC.NotPromoted -> pure () putRdrName rdrName- HsTyLit _ tp ->+ GHC.HsTyLit _ tp -> putOutputable tp- HsParTy _ tp -> do+ GHC.HsParTy _ tp -> do putText "(" putType tp putText ")"- HsTupleTy NoExtField _ xs -> do+ GHC.HsTupleTy _ _ xs -> do putText "(" sep (comma >> space) (fmap putType xs) putText ")"- HsForAllTy NoExtField _ _ _ ->+ GHC.HsForAllTy {} -> putOutputable ltp- HsQualTy NoExtField _ _ ->+ GHC.HsQualTy {} -> putOutputable ltp- HsAppKindTy _ _ _ ->+ GHC.HsAppKindTy _ _ _ -> putOutputable ltp- HsListTy _ _ ->+ GHC.HsListTy _ _ -> putOutputable ltp- HsSumTy _ _ ->+ GHC.HsSumTy _ _ -> putOutputable ltp- HsIParamTy _ _ _ ->+ GHC.HsIParamTy _ _ _ -> putOutputable ltp- HsKindSig _ _ _ ->+ GHC.HsKindSig _ _ _ -> putOutputable ltp- HsStarTy _ _ ->+ GHC.HsStarTy _ _ -> putOutputable ltp- HsSpliceTy _ _ ->+ GHC.HsSpliceTy _ _ -> putOutputable ltp- HsDocTy _ _ _ ->+ GHC.HsDocTy _ _ _ -> putOutputable ltp- HsBangTy _ _ _ ->+ GHC.HsBangTy _ _ _ -> putOutputable ltp- HsRecTy _ _ ->+ GHC.HsRecTy _ _ -> putOutputable ltp- HsWildCardTy _ ->+ GHC.HsWildCardTy _ -> putOutputable ltp- XHsType _ ->+ GHC.XHsType _ -> putOutputable ltp --- | Get a docstring on the start line of 'SrcSpan' that is a @-- ^@ comment-getDocstrPrev :: SrcSpan -> P (Maybe AnnotationComment)-getDocstrPrev = \case- UnhelpfulSpan _ -> pure Nothing- RealSrcSpan rspan -> do- removeComment \case- L rloc (AnnLineComment s) ->- and- [ srcSpanStartLine rspan == srcSpanStartLine rloc- , "-- ^" `isPrefixOf` s- ]- _ -> False- -- | Print a newline newline :: P () newline = do@@ -318,7 +296,7 @@ -- | Add separator between each element of the given printers sep :: P a -> [P a] -> P ()-sep _ [] = pure ()+sep _ [] = pure () sep s (first : rest) = first >> forM_ rest ((>>) s) -- | Prefix a printer with another one@@ -336,62 +314,6 @@ len <- length <$> getCurrentLine spaces $ n - len --- | Gets comment on supplied 'line' and removes it from the state-removeLineComment :: Int -> P (Maybe AnnotationComment)-removeLineComment line =- removeComment (\(L rloc _) -> srcSpanStartLine rloc == line)---- | Removes comments from the state up to start line of 'SrcSpan' and returns--- the ones that were removed-removeCommentTo :: SrcSpan -> P [AnnotationComment]-removeCommentTo = \case- UnhelpfulSpan _ -> pure []- RealSrcSpan rspan -> removeCommentTo' (srcSpanStartLine rspan)---- | Removes comments from the state up to end line of 'SrcSpan' and returns--- the ones that were removed-removeCommentToEnd :: SrcSpan -> P [AnnotationComment]-removeCommentToEnd = \case- UnhelpfulSpan _ -> pure []- RealSrcSpan rspan -> removeCommentTo' (srcSpanEndLine rspan)---- | Removes comments to the line number given and returns the ones removed-removeCommentTo' :: Int -> P [AnnotationComment]-removeCommentTo' line =- removeComment (\(L rloc _) -> srcSpanStartLine rloc < line) >>= \case- Nothing -> pure []- Just c -> do- rest <- removeCommentTo' line- pure (c : rest)---- | Removes comments from the state while given predicate 'p' is true-removeComments :: (RealLocated AnnotationComment -> Bool) -> P [AnnotationComment]-removeComments p =- removeComment p >>= \case- Just c -> do- rest <- removeComments p- pure (c : rest)- Nothing -> pure []---- | Remove a comment from the state given predicate 'p'-removeComment :: (RealLocated AnnotationComment -> Bool) -> P (Maybe AnnotationComment)-removeComment p = do- comments <- gets pendingComments-- let- foundComment =- find p comments-- newPendingComments =- maybe comments (`delete` comments) foundComment-- modify \s -> s { pendingComments = newPendingComments }- pure $ fmap (\(L _ c) -> c) foundComment---- | Get all annotations for 'SrcSpan'-getAnnot :: SrcSpan -> P [AnnKeywordId]-getAnnot spn = gets (lookupAnnotation spn . parsedModule)- -- | Get current line getCurrentLine :: P String getCurrentLine = gets currentLine@@ -399,45 +321,6 @@ -- | Get current line length getCurrentLineLength :: P Int getCurrentLineLength = fmap length getCurrentLine---- | Peek at the next comment in the state-peekNextCommentPos :: P (Maybe SrcSpan)-peekNextCommentPos = do- gets pendingComments <&> \case- (L next _ : _) -> Just (RealSrcSpan next)- [] -> Nothing---- | Get attached comments belonging to '[Located a]' given-groupAttachedComments :: [Located a] -> P [([AnnotationComment], NonEmpty (Located a))]-groupAttachedComments = go- where- go :: [Located a] -> P [([AnnotationComment], NonEmpty (Located a))]- go (L rspan x : xs) = do- comments <- removeCommentTo rspan- nextGroupStartM <- peekNextCommentPos-- let- sameGroupOf = maybe xs \nextGroupStart ->- takeWhile (\(L p _)-> p < nextGroupStart) xs-- restOf = maybe [] \nextGroupStart ->- dropWhile (\(L p _) -> p <= nextGroupStart) xs-- restGroups <- go (restOf nextGroupStartM)- pure $ (comments, L rspan x :| sameGroupOf nextGroupStartM) : restGroups-- go _ = pure []---- | A view on 'groupAttachedComments': return 'Just' when there is just a--- one big group without any comments.-groupWithoutComments- :: [([AnnotationComment], NonEmpty (Located a))]- -> Maybe [Located a]-groupWithoutComments grouped- | all (null . fst) grouped- = Just $ concatMap (toList . snd) grouped- | otherwise- = Nothing modifyCurrentLine :: (String -> String) -> P () modifyCurrentLine f = do
lib/Language/Haskell/Stylish/Step/Data.hs view
@@ -1,8 +1,11 @@-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE DoAndIfThenElse #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-} module Language.Haskell.Stylish.Step.Data ( Config(..) , defaultConfig@@ -12,45 +15,30 @@ , step ) where ----------------------------------------------------------------------------------import Prelude hiding (init) ---------------------------------------------------------------------------------import Control.Monad (forM_, unless, when)-import Data.Function ((&))-import Data.Functor ((<&>))-import Data.List (sortBy)-import Data.Maybe (listToMaybe)+import Control.Monad (forM_, unless, when)+import Data.List (sortBy)+import Data.Maybe (listToMaybe, maybeToList)+import qualified GHC.Hs as GHC+import qualified GHC.Types.Fixity as GHC+import qualified GHC.Types.Name.Reader as GHC+import qualified GHC.Types.SrcLoc as GHC+import Prelude hiding (init) ----------------------------------------------------------------------------------import ApiAnnotation (AnnotationComment)-import BasicTypes (LexicalFixity (..))-import GHC.Hs.Decls (ConDecl (..),- DerivStrategy (..),- HsDataDefn (..), HsDecl (..),- HsDerivingClause (..),- NewOrData (..),- TyClDecl (..))-import GHC.Hs.Extension (GhcPs, NoExtField (..),- noExtCon)-import GHC.Hs.Types (ConDeclField (..),- ForallVisFlag (..),- HsConDetails (..), HsContext,- HsImplicitBndrs (..),- HsTyVarBndr (..),- HsType (..), LHsQTyVars (..))-import RdrName (RdrName)-import SrcLoc (GenLocated (..), Located,- RealLocated) ---------------------------------------------------------------------------------import Language.Haskell.Stylish.Block import Language.Haskell.Stylish.Editor+import Language.Haskell.Stylish.Comments import Language.Haskell.Stylish.GHC import Language.Haskell.Stylish.Module+import Language.Haskell.Stylish.Ordering import Language.Haskell.Stylish.Printer import Language.Haskell.Stylish.Step+import Language.Haskell.Stylish.Util ++-------------------------------------------------------------------------------- data Indent = SameLine | Indent !Int@@ -102,208 +90,214 @@ step cfg = makeStep "Data" \ls m -> applyChanges (changes m) ls where changes :: Module -> [ChangeLine]- changes m = fmap (formatDataDecl cfg m) (dataDecls m)+ changes m = formatDataDecl cfg <$> dataDecls m - dataDecls :: Module -> [Located DataDecl]- dataDecls = queryModule \case- L pos (TyClD _ (DataDecl _ name tvars fixity defn)) -> pure . L pos $ MkDataDecl- { dataDeclName = name- , dataTypeVars = tvars- , dataDefn = defn- , dataFixity = fixity- }- _ -> []+ dataDecls :: Module -> [DataDecl]+ dataDecls m = do+ ldecl <- GHC.hsmodDecls $ GHC.unLoc m+ GHC.TyClD _ tycld <- pure $ GHC.unLoc ldecl+ loc <- maybeToList $ GHC.srcSpanToRealSrcSpan $ GHC.getLocA ldecl+ case tycld of+ GHC.DataDecl {..} -> pure $ MkDataDecl+ { dataComments = epAnnComments tcdDExt+ , dataLoc = loc+ , dataDeclName = tcdLName+ , dataTypeVars = tcdTyVars+ , dataDefn = tcdDataDefn+ , dataFixity = tcdFixity+ }+ _ -> [] type ChangeLine = Change String -formatDataDecl :: Config -> Module -> Located DataDecl -> ChangeLine-formatDataDecl cfg@Config{..} m ldecl@(L declPos decl) =- change originalDeclBlock (const printedDecl)- where- relevantComments :: [RealLocated AnnotationComment]- relevantComments- = moduleComments m- & rawComments- & dropBeforeAndAfter ldecl+data DataDecl = MkDataDecl+ { dataComments :: [GHC.LEpaComment]+ , dataLoc :: GHC.RealSrcSpan+ , dataDeclName :: GHC.LocatedN GHC.RdrName+ , dataTypeVars :: GHC.LHsQTyVars GHC.GhcPs+ , dataDefn :: GHC.HsDataDefn GHC.GhcPs+ , dataFixity :: GHC.LexicalFixity+ } - defn = dataDefn decl - originalDeclBlock =- Block (getStartLineUnsafe ldecl) (getEndLineUnsafe ldecl)+formatDataDecl :: Config -> DataDecl -> ChangeLine+formatDataDecl cfg@Config{..} decl@MkDataDecl {..} =+ change originalDeclBlock (const printedDecl)+ where+ originalDeclBlock = Block+ (GHC.srcSpanStartLine dataLoc)+ (GHC.srcSpanEndLine dataLoc) printerConfig = PrinterConfig- { columns = case cMaxColumns of- NoMaxColumns -> Nothing- MaxColumns n -> Just n- }+ { columns = case cMaxColumns of+ NoMaxColumns -> Nothing+ MaxColumns n -> Just n+ } - printedDecl = runPrinter_ printerConfig relevantComments m do- putText (newOrData decl)- space- putName decl+ printedDecl = runPrinter_ printerConfig $ putDataDecl cfg decl - when (isGADT decl) (space >> putText "where")+putDataDecl :: Config -> DataDecl -> P ()+putDataDecl cfg@Config {..} decl = do+ let defn = dataDefn decl+ constructorComments = commentGroups+ (GHC.srcSpanToRealSrcSpan . GHC.getLocA)+ (GHC.dd_cons defn)+ (dataComments decl) - when (hasConstructors decl) do- breakLineBeforeEq <- case (cEquals, cFirstField) of- (_, Indent x) | isEnum decl && cBreakEnums -> do- putEolComment declPos- newline >> spaces x- pure True- (_, _) | not (isNewtype decl) && singleConstructor decl && not cBreakSingleConstructors ->- False <$ space- (Indent x, _)- | isEnum decl && not cBreakEnums -> False <$ space- | otherwise -> do- putEolComment declPos- newline >> spaces x- pure True- (SameLine, _) -> False <$ space+ onelineEnum =+ isEnum decl && not cBreakEnums &&+ all (not . commentGroupHasComments) constructorComments + putText $ newOrData decl+ space+ putName decl++ when (isGADT decl) (space >> putText "where")++ when (hasConstructors decl) do+ case (cEquals, cFirstField) of+ (_, Indent x) | isEnum decl && cBreakEnums -> newline >> spaces x+ (_, _)+ | not (isNewtype decl)+ , singleConstructor decl && not cBreakSingleConstructors ->+ space+ (Indent x, _)+ | onelineEnum -> space+ | otherwise -> newline >> spaces x+ (SameLine, _) -> space+ lineLengthAfterEq <- fmap (+2) getCurrentLineLength - if isEnum decl && not cBreakEnums then- putText "=" >> space >> putUnbrokenEnum cfg decl- else if isNewtype decl then- putText "=" >> space >> forM_ (dd_cons defn) (putNewtypeConstructor cfg)- else- case dd_cons defn of- [] -> pure ()- lcon@(L pos _) : consRest -> do- when breakLineBeforeEq do- removeCommentTo pos >>= mapM_ \c -> putComment c >> consIndent lineLengthAfterEq+ if | onelineEnum ->+ putText "=" >> space >> putUnbrokenEnum cfg decl+ | isNewtype decl -> do+ putText "=" >> space+ forM_ (GHC.dd_cons defn) $ putNewtypeConstructor cfg+ | not . null $ GHC.dd_cons defn -> do+ forM_ (flagEnds constructorComments) $ \(CommentGroup {..}, firstGroup, lastGroup) -> do+ forM_ cgPrior $ \lc -> do+ putComment $ GHC.unLoc lc+ consIndent lineLengthAfterEq - unless- (isGADT decl)- (putText "=" >> space)+ forM_ (flagEnds cgItems) $ \((lcon, mbInlineComment), firstItem, lastItem) -> do+ unless (isGADT decl) $ do+ putText $ if firstGroup && firstItem then "=" else "|"+ space+ putConstructor cfg lineLengthAfterEq lcon+ putMaybeLineComment $ GHC.unLoc <$> mbInlineComment+ unless (lastGroup && lastItem) $+ consIndent lineLengthAfterEq - putConstructor cfg lineLengthAfterEq lcon- forM_ consRest \con@(L conPos _) -> do- unless (cFirstField == SameLine) do- removeCommentTo conPos >>= mapM_ \c -> consIndent lineLengthAfterEq >> putComment c- consIndent lineLengthAfterEq+ forM_ cgFollowing $ \lc -> do+ consIndent lineLengthAfterEq+ putComment $ GHC.unLoc lc - unless- (isGADT decl)- (putText "|" >> space)+ | otherwise ->+ pure () - putConstructor cfg lineLengthAfterEq con- putEolComment conPos+ let derivingComments = deepAnnComments (GHC.dd_derivs defn) - when (hasDeriving decl) do- if isEnum decl && not cBreakEnums then+ when (hasDeriving decl) do+ if onelineEnum && null derivingComments then space- else do- removeCommentTo (defn & dd_derivs & \(L pos _) -> pos) >>=- mapM_ \c -> newline >> spaces cDeriving >> putComment c+ else do+ forM_ derivingComments $ \lc -> do+ newline+ spaces cDeriving+ putComment $ GHC.unLoc lc newline spaces cDeriving - sep (newline >> spaces cDeriving) $ defn & dd_derivs & \(L pos ds) -> ds <&> \d -> do- putAllSpanComments (newline >> spaces cDeriving) pos- putDeriving cfg d-+ sep (newline >> spaces cDeriving) $ map+ (putDeriving cfg)+ (GHC.dd_derivs defn)+ where consIndent eqIndent = newline >> case (cEquals, cFirstField) of- (SameLine, SameLine) -> spaces (eqIndent - 2)- (SameLine, Indent y) -> spaces (eqIndent + y - 4)- (Indent x, Indent _) -> spaces x- (Indent x, SameLine) -> spaces x+ (SameLine, SameLine) -> spaces (eqIndent - 2)+ (SameLine, Indent y) -> spaces (eqIndent + y - 4)+ (Indent x, Indent _) -> spaces x+ (Indent x, SameLine) -> spaces x -data DataDecl = MkDataDecl- { dataDeclName :: Located RdrName- , dataTypeVars :: LHsQTyVars GhcPs- , dataDefn :: HsDataDefn GhcPs- , dataFixity :: LexicalFixity- }+derivingClauseTypes+ :: GHC.HsDerivingClause GHC.GhcPs -> [GHC.LHsSigType GHC.GhcPs]+derivingClauseTypes GHC.HsDerivingClause {..} =+ case GHC.unLoc deriv_clause_tys of+ GHC.DctSingle _ t -> [t]+ GHC.DctMulti _ ts -> ts -putDeriving :: Config -> Located (HsDerivingClause GhcPs) -> P ()-putDeriving Config{..} (L pos clause) = do- putText "deriving"+putDeriving :: Config -> GHC.LHsDerivingClause GHC.GhcPs -> P ()+putDeriving Config{..} lclause = do+ let clause@GHC.HsDerivingClause {..} = GHC.unLoc lclause+ tys = (if cSortDeriving then sortBy compareOutputableCI else id) $+ map (GHC.sig_body . GHC.unLoc) $+ derivingClauseTypes clause+ headTy = listToMaybe tys+ tailTy = drop 1 tys - forM_ (deriv_clause_strategy clause) \case- L _ StockStrategy -> space >> putText "stock"- L _ AnyclassStrategy -> space >> putText "anyclass"- L _ NewtypeStrategy -> space >> putText "newtype"- L _ (ViaStrategy _) -> pure ()+ putText "deriving" - putCond- withinColumns- oneLinePrint- multilinePrint+ forM_ deriv_clause_strategy $ \lstrat -> case GHC.unLoc lstrat of+ GHC.StockStrategy {} -> space >> putText "stock"+ GHC.AnyclassStrategy {} -> space >> putText "anyclass"+ GHC.NewtypeStrategy {} -> space >> putText "newtype"+ GHC.ViaStrategy {} -> pure () - forM_ (deriv_clause_strategy clause) \case- L _ (ViaStrategy tp) -> do- case cVia of- SameLine -> space- Indent x -> newline >> spaces (x + cDeriving)+ putCond+ withinColumns+ do+ space+ putText "("+ sep+ (comma >> space)+ (fmap putOutputable tys)+ putText ")"+ do+ newline+ spaces indentation+ putText "(" - putText "via"- space- putType (getType tp)- _ -> pure ()+ forM_ headTy \t ->+ space >> putOutputable t - putEolComment pos+ forM_ tailTy \t -> do+ newline+ spaces indentation+ comma+ space+ putOutputable t - where- getType = \case- HsIB _ tp -> tp- XHsImplicitBndrs x -> noExtCon x+ newline+ spaces indentation+ putText ")" + forM_ deriv_clause_strategy $ \lstrat -> case GHC.unLoc lstrat of+ GHC.ViaStrategy tp -> do+ case cVia of+ SameLine -> space+ Indent x -> newline >> spaces (x + cDeriving)++ putText "via"+ space+ putType $ case tp of+ GHC.XViaStrategyPs _ ty -> GHC.sig_body $ GHC.unLoc ty+ _ -> pure ()++ -- putEolComment pos+ where withinColumns PrinterState{currentLine} = case cMaxColumns of MaxColumns maxCols -> length currentLine <= maxCols NoMaxColumns -> True - oneLinePrint = do- space- putText "("- sep- (comma >> space)- (fmap putOutputable tys)- putText ")"-- multilinePrint = do- newline- spaces indentation- putText "("-- forM_ headTy \t ->- space >> putOutputable t-- forM_ tailTy \t -> do- newline- spaces indentation- comma- space- putOutputable t-- newline- spaces indentation- putText ")"- indentation = cDeriving + case cFirstField of Indent x -> x SameLine -> 0 - tys- = clause- & deriv_clause_tys- & unLocated- & (if cSortDeriving then sortBy compareOutputable else id)- & fmap hsib_body-- headTy =- listToMaybe tys-- tailTy =- drop 1 tys- putUnbrokenEnum :: Config -> DataDecl -> P ()-putUnbrokenEnum cfg decl =- sep+putUnbrokenEnum cfg decl = sep (space >> putText "|" >> space)- (fmap (putConstructor cfg 0) . dd_cons . dataDefn $ decl)+ (fmap (putConstructor cfg 0) . GHC.dd_cons . dataDefn $ decl) putName :: DataDecl -> P () putName decl@MkDataDecl{..} =@@ -312,42 +306,32 @@ putRdrName dataDeclName space forM_ secondTvar putOutputable+ maybePutKindSig else do putRdrName dataDeclName- forM_ (hsq_explicit dataTypeVars) (\t -> space >> putOutputable t)+ forM_ (GHC.hsq_explicit dataTypeVars) (\t -> space >> putOutputable t)+ maybePutKindSig where- firstTvar :: Maybe (Located (HsTyVarBndr GhcPs))- firstTvar- = dataTypeVars- & hsq_explicit- & listToMaybe+ firstTvar :: Maybe (GHC.LHsTyVarBndr () GHC.GhcPs)+ firstTvar = listToMaybe $ GHC.hsq_explicit dataTypeVars - secondTvar :: Maybe (Located (HsTyVarBndr GhcPs))- secondTvar- = dataTypeVars- & hsq_explicit- & drop 1- & listToMaybe+ secondTvar :: Maybe (GHC.LHsTyVarBndr () GHC.GhcPs)+ secondTvar = listToMaybe . drop 1 $ GHC.hsq_explicit dataTypeVars -putConstructor :: Config -> Int -> Located (ConDecl GhcPs) -> P ()-putConstructor cfg consIndent (L _ cons) = case cons of- ConDeclGADT{..} -> do- -- Put argument to constructor first:- case con_args of- PrefixCon _ -> do- sep- (comma >> space)- (fmap putRdrName con_names)+ maybePutKindSig :: Printer ()+ maybePutKindSig = forM_ maybeKindSig (\k -> space >> putText "::" >> space >> putOutputable k) - InfixCon arg1 arg2 -> do- putType arg1- space- forM_ con_names putRdrName- space- putType arg2- RecCon _ ->- error . mconcat $+ maybeKindSig :: Maybe (GHC.LHsKind GHC.GhcPs)+ maybeKindSig = GHC.dd_kindSig dataDefn++putConstructor :: Config -> Int -> GHC.LConDecl GHC.GhcPs -> P ()+putConstructor cfg consIndent lcons = case GHC.unLoc lcons of+ GHC.ConDeclGADT {..} -> do+ -- Put argument to constructor first:+ case con_g_args of+ GHC.PrefixConGADT _ -> sep (comma >> space) $ fmap putRdrName con_names+ GHC.RecConGADT _ -> error . mconcat $ [ "Language.Haskell.Stylish.Step.Data.putConstructor: " , "encountered a GADT with record constructors, not supported yet" ]@@ -357,27 +341,39 @@ putText "::" space - putForAll con_forall $ hsq_explicit con_qvars- forM_ con_mb_cxt (putContext cfg . unLocated)+ putForAll+ (case GHC.unLoc con_bndrs of+ GHC.HsOuterImplicit {} -> False+ GHC.HsOuterExplicit {} -> True)+ (case GHC.unLoc con_bndrs of+ GHC.HsOuterImplicit {} -> []+ GHC.HsOuterExplicit {..} -> hso_bndrs)+ forM_ con_mb_cxt $ putContext cfg+ case con_g_args of+ GHC.PrefixConGADT scaledTys -> forM_ scaledTys $ \scaledTy -> do+ putType $ GHC.hsScaledThing scaledTy+ space >> putText "->" >> space+ GHC.RecConGADT _ -> error . mconcat $+ [ "Language.Haskell.Stylish.Step.Data.putConstructor: "+ , "encountered a GADT with record constructors, not supported yet"+ ] putType con_res_ty - XConDecl x ->- noExtCon x- ConDeclH98{..} -> do+ GHC.ConDeclH98 {..} -> do putForAll con_forall con_ex_tvs- forM_ con_mb_cxt (putContext cfg . unLocated)+ forM_ con_mb_cxt $ putContext cfg case con_args of- InfixCon arg1 arg2 -> do- putType arg1+ GHC.InfixCon arg1 arg2 -> do+ putType $ GHC.hsScaledThing arg1 space putRdrName con_name space- putType arg2- PrefixCon xs -> do+ putType $ GHC.hsScaledThing arg2+ GHC.PrefixCon _tyargs args -> do putRdrName con_name- unless (null xs) space- sep space (fmap putOutputable xs)- RecCon (L recPos (L posFirst firstArg : args)) -> do+ unless (null args) space+ sep space (fmap putOutputable args)+ GHC.RecCon largs | _ : _ <- GHC.unLoc largs -> do putRdrName con_name skipToBrace bracePos <- getCurrentLineLength@@ -385,32 +381,42 @@ let fieldPos = bracePos + 2 space + let commented = commentGroups+ (GHC.srcSpanToRealSrcSpan . GHC.getLocA)+ (GHC.unLoc largs)+ (epAnnComments . GHC.ann $ GHC.getLoc largs)++ forM_ (flagEnds commented) $ \(CommentGroup {..}, firstCommentGroup, _) -> do+ -- Unless everything's configured to be on the same line, put pending -- comments- unless (cFirstField cfg == SameLine) do- removeCommentTo posFirst >>= mapM_ \c -> putComment c >> sepDecl bracePos-- -- Put first decl field- pad fieldPos >> putConDeclField cfg firstArg- unless (cFirstField cfg == SameLine) (putEolComment posFirst)+ forM_ cgPrior $ \lc -> do+ pad fieldPos+ putComment $ GHC.unLoc lc+ sepDecl bracePos - -- Put tail decl fields- forM_ args \(L pos arg) -> do- sepDecl bracePos- removeCommentTo pos >>= mapM_ \c ->- spaces (cFieldComment cfg) >> putComment c >> sepDecl bracePos- comma- space- putConDeclField cfg arg- putEolComment pos+ forM_ (flagEnds cgItems) $ \((item, mbInlineComment), firstItem, _) -> do+ if firstCommentGroup && firstItem+ then pad fieldPos+ else do+ comma+ space+ putConDeclField cfg $ GHC.unLoc item+ case mbInlineComment of+ Just c -> do+ sepDecl bracePos >> spaces (cFieldComment cfg)+ putComment $ GHC.unLoc c+ _ -> pure ()+ sepDecl bracePos - -- Print docstr after final field- removeCommentToEnd recPos >>= mapM_ \c ->- sepDecl bracePos >> spaces (cFieldComment cfg) >> putComment c+ forM_ cgFollowing $ \lc -> do+ spaces $ cFieldComment cfg+ putComment $ GHC.unLoc lc+ sepDecl bracePos -- Print whitespace to closing brace- sepDecl bracePos >> putText "}"- RecCon (L _ []) -> do+ putText "}"+ GHC.RecCon _ -> do skipToBrace >> putText "{" skipToBrace >> putText "}" @@ -426,126 +432,124 @@ -- Jump to the next declaration. sepDecl bracePos = newline >> spaces case (cEquals cfg, cFirstField cfg) of (_, Indent y) | not (cBreakSingleConstructors cfg) -> y- (SameLine, SameLine) -> bracePos- (Indent x, Indent y) -> x + y + 2- (SameLine, Indent y) -> bracePos + y - 2- (Indent x, SameLine) -> bracePos + x - 2+ (SameLine, SameLine) -> bracePos+ (Indent x, Indent y) -> x + y + 2+ (SameLine, Indent y) -> bracePos + y - 2+ (Indent x, SameLine) -> bracePos + x - 2 -putNewtypeConstructor :: Config -> Located (ConDecl GhcPs) -> P ()-putNewtypeConstructor cfg (L _ cons) = case cons of- ConDeclH98{..} ->+putNewtypeConstructor :: Config -> GHC.LConDecl GHC.GhcPs -> P ()+putNewtypeConstructor cfg lcons = case GHC.unLoc lcons of+ GHC.ConDeclH98{..} -> putRdrName con_name >> case con_args of- PrefixCon xs -> do- unless (null xs) space- sep space (fmap putOutputable xs)- RecCon (L _ [L _posFirst firstArg]) -> do+ GHC.PrefixCon _ args -> do+ unless (null args) space+ sep space (fmap putOutputable args)+ GHC.RecCon largs | [firstArg] <- GHC.unLoc largs -> do space putText "{" space- putConDeclField cfg firstArg+ putConDeclField cfg $ GHC.unLoc firstArg space putText "}"- RecCon (L _ _args) ->+ GHC.RecCon {} -> error . mconcat $ [ "Language.Haskell.Stylish.Step.Data.putNewtypeConstructor: " , "encountered newtype with several arguments" ]- InfixCon {} ->+ GHC.InfixCon {} -> error . mconcat $ [ "Language.Haskell.Stylish.Step.Data.putNewtypeConstructor: " , "infix newtype constructor" ]- XConDecl x ->- noExtCon x- ConDeclGADT{} ->+ GHC.ConDeclGADT{} -> error . mconcat $ [ "Language.Haskell.Stylish.Step.Data.putNewtypeConstructor: " , "GADT encountered in newtype" ] -putForAll :: Located Bool -> [Located (HsTyVarBndr GhcPs)] -> P ()-putForAll forall ex_tvs =- when (unLocated forall) do+putForAll+ :: GHC.OutputableBndrFlag s 'GHC.Parsed+ => Bool -> [GHC.LHsTyVarBndr s GHC.GhcPs] -> P ()+putForAll forall ex_tvs = when forall do putText "forall" space- sep space (fmap putOutputable ex_tvs)+ sep space $ putOutputable . GHC.unLoc <$> ex_tvs dot space -putContext :: Config -> HsContext GhcPs -> P ()-putContext Config{..} = suffix (space >> putText "=>" >> space) . \case- [L _ (HsParTy _ tp)] | cCurriedContext ->- putType tp- [ctx] ->- putType ctx- ctxs | cCurriedContext ->- sep (space >> putText "=>" >> space) (fmap putType ctxs)- ctxs ->- parenthesize $ sep (comma >> space) (fmap putType ctxs)+putContext :: Config -> GHC.LHsContext GHC.GhcPs -> P ()+putContext Config{..} lctx = suffix (space >> putText "=>" >> space) $+ case ltys of+ [lty] | GHC.HsParTy _ tp <- GHC.unLoc lty, cCurriedContext ->+ putType tp+ [ctx] ->+ putType ctx+ ctxs | cCurriedContext ->+ sep (space >> putText "=>" >> space) (fmap putType ctxs)+ ctxs ->+ parenthesize $ sep (comma >> space) (fmap putType ctxs)+ where+ ltys = GHC.unLoc lctx :: [GHC.LHsType GHC.GhcPs] -putConDeclField :: Config -> ConDeclField GhcPs -> P ()-putConDeclField cfg = \case- ConDeclField{..} -> do+putConDeclField :: Config -> GHC.ConDeclField GHC.GhcPs -> P ()+putConDeclField cfg GHC.ConDeclField {..} = do sep- (comma >> space)- (fmap putOutputable cd_fld_names)+ (comma >> space)+ (fmap putOutputable cd_fld_names) space putText "::" space putType' cfg cd_fld_type- XConDeclField{} ->- error . mconcat $- [ "Language.Haskell.Stylish.Step.Data.putConDeclField: "- , "XConDeclField encountered"- ] -- | A variant of 'putType' that takes 'cCurriedContext' into account-putType' :: Config -> Located (HsType GhcPs) -> P ()-putType' cfg = \case- L _ (HsForAllTy NoExtField vis bndrs tp) -> do- putText "forall"- space- sep space (fmap putOutputable bndrs)- putText- if vis == ForallVis then "->"- else "."- space- putType' cfg tp- L _ (HsQualTy NoExtField ctx tp) -> do- putContext cfg (unLocated ctx)- putType' cfg tp- other -> putType other+putType' :: Config -> GHC.LHsType GHC.GhcPs -> P ()+putType' cfg lty = case GHC.unLoc lty of+ GHC.HsForAllTy GHC.NoExtField tele tp -> do+ putText "forall"+ space+ sep space $ case tele of+ GHC.HsForAllVis {..} -> putOutputable . GHC.unLoc <$> hsf_vis_bndrs+ GHC.HsForAllInvis {..} -> putOutputable . GHC.unLoc <$> hsf_invis_bndrs+ case tele of+ GHC.HsForAllVis {} -> space >> putText "->"+ GHC.HsForAllInvis {} -> putText "."+ space+ putType' cfg tp+ GHC.HsQualTy GHC.NoExtField ctx tp -> do+ forM_ ctx $ putContext cfg+ putType' cfg tp+ _ -> putType lty newOrData :: DataDecl -> String newOrData decl = if isNewtype decl then "newtype" else "data" isGADT :: DataDecl -> Bool-isGADT = any isGADTCons . dd_cons . dataDefn+isGADT = any isGADTCons . GHC.dd_cons . dataDefn where- isGADTCons = \case- L _ (ConDeclGADT {}) -> True- _ -> False+ isGADTCons c = case GHC.unLoc c of+ GHC.ConDeclGADT {} -> True+ _ -> False isNewtype :: DataDecl -> Bool-isNewtype = (== NewType) . dd_ND . dataDefn+isNewtype = (== GHC.NewType) . GHC.dd_ND . dataDefn isInfix :: DataDecl -> Bool-isInfix = (== Infix) . dataFixity+isInfix = (== GHC.Infix) . dataFixity isEnum :: DataDecl -> Bool-isEnum = all isUnary . dd_cons . dataDefn+isEnum = all isUnary . GHC.dd_cons . dataDefn where- isUnary = \case- L _ (ConDeclH98 {..}) -> case con_args of- PrefixCon [] -> True- _ -> False+ isUnary c = case GHC.unLoc c of+ GHC.ConDeclH98 {..} -> case con_args of+ GHC.PrefixCon tyargs args -> null tyargs && null args+ _ -> False _ -> False hasConstructors :: DataDecl -> Bool-hasConstructors = not . null . dd_cons . dataDefn+hasConstructors = not . null . GHC.dd_cons . dataDefn singleConstructor :: DataDecl -> Bool-singleConstructor = (== 1) . length . dd_cons . dataDefn+singleConstructor = (== 1) . length . GHC.dd_cons . dataDefn hasDeriving :: DataDecl -> Bool-hasDeriving = not . null . unLocated . dd_derivs . dataDefn+hasDeriving = not . null . GHC.dd_derivs . dataDefn
lib/Language/Haskell/Stylish/Step/Imports.hs view
@@ -17,51 +17,45 @@ -------------------------------------------------------------------------------- import Control.Monad (forM_, when, void)+import Data.Foldable (toList) import Data.Function ((&), on) import Data.Functor (($>))-import Data.Foldable (toList)-import Data.Maybe (isJust)-import Data.List (sortBy) import Data.List.NonEmpty (NonEmpty(..))+import Data.List (sortBy)+import Data.Maybe (fromMaybe, isJust) import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map as Map import qualified Data.Set as Set------------------------------------------------------------------------------------import BasicTypes (StringLiteral (..),- SourceText (..))-import qualified FastString as FS-import GHC.Hs.Extension (GhcPs)-import qualified GHC.Hs.Extension as GHC-import GHC.Hs.ImpExp-import Module (moduleNameString)-import RdrName (RdrName)-import SrcLoc (Located, GenLocated(..), unLoc)+import qualified GHC.Data.FastString as GHC+import qualified GHC.Hs as GHC+import qualified GHC.Types.Name.Reader as GHC+import qualified GHC.Types.SourceText as GHC+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Unit.Module.Name as GHC+import qualified GHC.Unit.Types as GHC -------------------------------------------------------------------------------- import Language.Haskell.Stylish.Block+import Language.Haskell.Stylish.Editor import Language.Haskell.Stylish.Module import Language.Haskell.Stylish.Ordering import Language.Haskell.Stylish.Printer import Language.Haskell.Stylish.Step-import Language.Haskell.Stylish.Editor-import Language.Haskell.Stylish.GHC import Language.Haskell.Stylish.Util -------------------------------------------------------------------------------- data Options = Options- { importAlign :: ImportAlign- , listAlign :: ListAlign- , padModuleNames :: Bool- , longListAlign :: LongListAlign- , emptyListAlign :: EmptyListAlign- , listPadding :: ListPadding- , separateLists :: Bool- , spaceSurround :: Bool- , postQualified :: Bool+ { importAlign :: ImportAlign+ , listAlign :: ListAlign+ , padModuleNames :: Bool+ , longListAlign :: LongListAlign+ , emptyListAlign :: EmptyListAlign+ , listPadding :: ListPadding+ , separateLists :: Bool+ , spaceSurround :: Bool+ , postQualified :: Bool } deriving (Eq, Show) defaultOptions :: Options@@ -120,38 +114,40 @@ printImports maxCols align ls m = applyChanges changes ls where groups = moduleImportGroups m- moduleStats = foldMap importStats . fmap unLoc $ concatMap toList groups+ moduleStats = foldMap importStats . fmap GHC.unLoc $ concatMap toList groups changes = do group <- groups- pure $ formatGroup maxCols align m moduleStats group+ pure $ formatGroup maxCols align moduleStats group formatGroup- :: Maybe Int -> Options -> Module -> ImportStats- -> NonEmpty (Located Import) -> Change String-formatGroup maxCols options m moduleStats imports =- let newLines = formatImports maxCols options m moduleStats imports in+ :: Maybe Int -> Options -> ImportStats+ -> NonEmpty (GHC.LImportDecl GHC.GhcPs) -> Change String+formatGroup maxCols options moduleStats imports =+ let newLines = formatImports maxCols options moduleStats imports in change (importBlock imports) (const newLines) -importBlock :: NonEmpty (Located a) -> Block String+importBlock :: NonEmpty (GHC.LImportDecl GHC.GhcPs) -> Block String importBlock group = Block- (getStartLineUnsafe $ NonEmpty.head group)- (getEndLineUnsafe $ NonEmpty.last group)+ (GHC.srcSpanStartLine . src $ NonEmpty.head group)+ (GHC.srcSpanEndLine . src $ NonEmpty.last group)+ where+ src = fromMaybe (error "importBlock: missing location") .+ GHC.srcSpanToRealSrcSpan . GHC.getLocA formatImports :: Maybe Int -- ^ Max columns. -> Options -- ^ Options.- -> Module -- ^ Module. -> ImportStats -- ^ Module stats.- -> NonEmpty (Located Import) -> Lines-formatImports maxCols options m moduleStats rawGroup =- runPrinter_ (PrinterConfig maxCols) [] m do+ -> NonEmpty (GHC.LImportDecl GHC.GhcPs) -> Lines+formatImports maxCols options moduleStats rawGroup =+ runPrinter_ (PrinterConfig maxCols) do let-+ group :: NonEmpty (GHC.LImportDecl GHC.GhcPs) group- = NonEmpty.sortWith unLocated rawGroup+ = NonEmpty.sortBy (compareImports `on` GHC.unLoc) rawGroup & mergeImports - unLocatedGroup = fmap unLocated $ toList group+ unLocatedGroup = fmap GHC.unLoc $ toList group align' = importAlign options padModuleNames' = padModuleNames options@@ -165,151 +161,160 @@ forM_ group \imp -> printQualified options padNames stats imp >> newline + ---------------------------------------------------------------------------------printQualified :: Options -> Bool -> ImportStats -> Located Import -> P ()-printQualified Options{..} padNames stats (L _ decl) = do- let decl' = rawImport decl+printQualified+ :: Options -> Bool -> ImportStats -> GHC.LImportDecl GHC.GhcPs -> P ()+printQualified Options{..} padNames stats ldecl = do+ putText "import" >> space - putText "import" >> space+ case (isSource decl, isAnySource stats) of+ (True, _) -> putText "{-# SOURCE #-}" >> space+ (_, True) -> putText " " >> space+ _ -> pure () - case (isSource decl, isAnySource stats) of- (True, _) -> putText "{-# SOURCE #-}" >> space- (_, True) -> putText " " >> space- _ -> pure ()+ when (GHC.ideclSafe decl) (putText "safe" >> space) - when (isSafe decl) (putText "safe" >> space)+ let module_ = do+ moduleNamePosition <- length <$> getCurrentLine+ forM_ (GHC.ideclPkgQual decl) $ \pkg ->+ putText (stringLiteral pkg) >> space+ putText (importModuleName decl) - let- module_ = do- moduleNamePosition <- length <$> getCurrentLine- forM_ (ideclPkgQual decl') $ \pkg -> putText (stringLiteral pkg) >> space- putText (moduleName decl)- -- Only print spaces if something follows.- when padNames $- when (isJust (ideclAs decl') || isHiding decl ||- not (null $ ideclHiding decl')) $- putText $- replicate (isLongestImport stats - importModuleNameLength decl) ' '- pure moduleNamePosition+ -- Only print spaces if something follows.+ let somethingFollows =+ isJust (GHC.ideclAs decl) || isHiding decl ||+ not (null $ GHC.ideclHiding decl)+ when (padNames && somethingFollows) $ putText $ replicate+ (isLongestImport stats - importModuleNameLength decl)+ ' '+ pure moduleNamePosition - moduleNamePosition <-- case (postQualified, isQualified decl, isAnyQualified stats) of- (False, True , _ ) -> putText "qualified" *> space *> module_- (False, _ , True) -> putText " " *> space *> module_- (True , True , _ ) -> module_ <* space <* putText "qualified"- _ -> module_+ moduleNamePosition <-+ case (postQualified, isQualified decl, isAnyQualified stats) of+ (False, True , _ ) -> putText "qualified" *> space *> module_+ (False, _ , True) -> putText " " *> space *> module_+ (True , True , _ ) -> module_ <* space <* putText "qualified"+ _ -> module_ - beforeAliasPosition <- length <$> getCurrentLine+ beforeAliasPosition <- length <$> getCurrentLine+ forM_ (GHC.ideclAs decl) $ \lname -> do+ space >> putText "as" >> space+ putText . GHC.moduleNameString $ GHC.unLoc lname - forM_ (ideclAs decl') \(L _ name) -> do- space >> putText "as" >> space >> putText (moduleNameString name)+ afterAliasPosition <- length <$> getCurrentLine - afterAliasPosition <- length <$> getCurrentLine+ when (isHiding decl) (space >> putText "hiding") - when (isHiding decl) (space >> putText "hiding")+ let putOffset = putText $ replicate offset ' '+ offset = case listPadding of+ LPConstant n -> n+ LPModuleName -> moduleNamePosition - let putOffset = putText $ replicate offset ' '- offset = case listPadding of- LPConstant n -> n- LPModuleName -> moduleNamePosition+ pure () - case snd <$> ideclHiding decl' of- Nothing -> pure ()- Just (L _ []) -> case emptyListAlign of- RightAfter -> modifyCurrentLine trimRight >> space >> putText "()"- Inherit -> case listAlign of- NewLine ->- modifyCurrentLine trimRight >> newline >> putOffset >> putText "()"- _ -> space >> putText "()"- Just (L _ imports) -> do- let printedImports = flagEnds $ -- [P ()]- fmap ((printImport separateLists) . unLocated)- (prepareImportList imports)+ case snd <$> GHC.ideclHiding decl of+ Nothing -> pure ()+ Just limports | null (GHC.unLoc limports) -> case emptyListAlign of+ RightAfter -> modifyCurrentLine trimRight >> space >> putText "()"+ Inherit -> case listAlign of+ NewLine -> do+ modifyCurrentLine trimRight+ newline >> putOffset >> putText "()"+ _ -> space >> putText "()" - -- Since we might need to output the import module name several times, we- -- need to save it to a variable:- wrapPrefix <- case listAlign of- AfterAlias -> pure $ replicate (afterAliasPosition + 1) ' '- WithAlias -> pure $ replicate (beforeAliasPosition + 1) ' '- Repeat -> fmap (++ " (") getCurrentLine- WithModuleName -> pure $ replicate (moduleNamePosition + offset) ' '- NewLine -> pure $ replicate offset ' '+ Just limports -> do+ let imports = GHC.unLoc limports+ printedImports = flagEnds $ -- [P ()]+ (printImport separateLists) . GHC.unLoc <$>+ prepareImportList imports - let -- Helper- doSpaceSurround = when spaceSurround space+ -- Since we might need to output the import module name several times, we+ -- need to save it to a variable:+ wrapPrefix <- case listAlign of+ AfterAlias -> pure $ replicate (afterAliasPosition + 1) ' '+ WithAlias -> pure $ replicate (beforeAliasPosition + 1) ' '+ Repeat -> fmap (++ " (") getCurrentLine+ WithModuleName -> pure $ replicate (moduleNamePosition + offset) ' '+ NewLine -> pure $ replicate offset ' ' - -- Try to put everything on one line.- printAsSingleLine = forM_ printedImports $ \(imp, start, end) -> do- when start $ putText "(" >> doSpaceSurround- imp- if end then doSpaceSurround >> putText ")" else comma >> space+ -- Helper+ let doSpaceSurround = when spaceSurround space - -- Try to put everything one by one, wrapping if that fails.- printAsInlineWrapping wprefix = forM_ printedImports $- \(imp, start, end) ->- patchForRepeatHiding $ wrapping- (do- if start then putText "(" >> doSpaceSurround else space- imp- if end then doSpaceSurround >> putText ")" else comma)- (do- case listAlign of- -- In 'Repeat' mode, end lines with ')' rather than ','.- Repeat | not start -> modifyCurrentLine . withLast $- \c -> if c == ',' then ')' else c- _ | start && spaceSurround ->- -- Only necessary if spaceSurround is enabled.- modifyCurrentLine trimRight- _ -> pure ()- newline- void wprefix- case listAlign of- -- '(' already included in repeat- Repeat -> pure ()- -- Print the much needed '('- _ | start -> putText "(" >> doSpaceSurround- -- Don't bother aligning if we're not in inline mode.- _ | longListAlign /= Inline -> pure ()- -- 'Inline + AfterAlias' is really where we want to be careful- -- with spacing.- AfterAlias -> space >> doSpaceSurround- WithModuleName -> pure ()- WithAlias -> pure ()- NewLine -> pure ()- imp- if end then doSpaceSurround >> putText ")" else comma)+ -- Try to put everything on one line.+ let printAsSingleLine = forM_ printedImports $ \(imp, start, end) -> do+ when start $ putText "(" >> doSpaceSurround+ imp+ if end then doSpaceSurround >> putText ")" else comma >> space - -- Put everything on a separate line. 'spaceSurround' can be- -- ignored.- printAsMultiLine = forM_ printedImports $ \(imp, start, end) -> do- when start $ modifyCurrentLine trimRight -- We added some spaces.- newline- putOffset- if start then putText "( " else putText ", "- imp- when end $ newline >> putOffset >> putText ")"+ -- Try to put everything one by one, wrapping if that fails.+ let printAsInlineWrapping wprefix = forM_ printedImports $+ \(imp, start, end) ->+ patchForRepeatHiding $ wrapping+ (do+ if start then putText "(" >> doSpaceSurround else space+ imp+ if end then doSpaceSurround >> putText ")" else comma)+ (do+ case listAlign of+ -- In 'Repeat' mode, end lines with ')' rather than ','.+ Repeat | not start -> modifyCurrentLine . withLast $+ \c -> if c == ',' then ')' else c+ _ | start && spaceSurround ->+ -- Only necessary if spaceSurround is enabled.+ modifyCurrentLine trimRight+ _ -> pure ()+ newline+ void wprefix+ case listAlign of+ -- '(' already included in repeat+ Repeat -> pure ()+ -- Print the much needed '('+ _ | start -> putText "(" >> doSpaceSurround+ -- Don't bother aligning if we're not in inline mode.+ _ | longListAlign /= Inline -> pure ()+ -- 'Inline + AfterAlias' is really where we want to be careful+ -- with spacing.+ AfterAlias -> space >> doSpaceSurround+ WithModuleName -> pure ()+ WithAlias -> pure ()+ NewLine -> pure ()+ imp+ if end then doSpaceSurround >> putText ")" else comma) - case longListAlign of- Multiline -> wrapping- (space >> printAsSingleLine)- printAsMultiLine- Inline | NewLine <- listAlign -> do- modifyCurrentLine trimRight- newline >> putOffset >> printAsInlineWrapping (putText wrapPrefix)- Inline -> space >> printAsInlineWrapping (putText wrapPrefix)- InlineWithBreak -> wrapping- (space >> printAsSingleLine)- (do- modifyCurrentLine trimRight- newline >> putOffset >> printAsInlineWrapping putOffset)- InlineToMultiline -> wrapping- (space >> printAsSingleLine)- (wrapping- (do- modifyCurrentLine trimRight- newline >> putOffset >> printAsSingleLine)- printAsMultiLine)+ -- Put everything on a separate line. 'spaceSurround' can be+ -- ignored.+ let printAsMultiLine = forM_ printedImports $ \(imp, start, end) -> do+ when start $ modifyCurrentLine trimRight -- We added some spaces.+ newline+ putOffset+ if start then putText "( " else putText ", "+ imp+ when end $ newline >> putOffset >> putText ")"++ case longListAlign of+ Multiline -> wrapping+ (space >> printAsSingleLine)+ printAsMultiLine+ Inline | NewLine <- listAlign -> do+ modifyCurrentLine trimRight+ newline >> putOffset >> printAsInlineWrapping (putText wrapPrefix)+ Inline -> space >> printAsInlineWrapping (putText wrapPrefix)+ InlineWithBreak -> wrapping+ (space >> printAsSingleLine)+ (do+ modifyCurrentLine trimRight+ newline >> putOffset >> printAsInlineWrapping putOffset)+ InlineToMultiline -> wrapping+ (space >> printAsSingleLine)+ (wrapping+ (do+ modifyCurrentLine trimRight+ newline >> putOffset >> printAsSingleLine)+ printAsMultiLine) where+ decl = GHC.unLoc ldecl+ -- We cannot wrap/repeat 'hiding' imports since then we would get multiple -- imports hiding different things. patchForRepeatHiding = case listAlign of@@ -318,63 +323,57 @@ ---------------------------------------------------------------------------------printImport :: Bool -> IE GhcPs -> P ()-printImport _ (IEVar _ name) = do+printImport :: Bool -> GHC.IE GHC.GhcPs -> P ()+printImport _ (GHC.IEVar _ name) = do printIeWrappedName name-printImport _ (IEThingAbs _ name) = do+printImport _ (GHC.IEThingAbs _ name) = do printIeWrappedName name-printImport separateLists (IEThingAll _ name) = do+printImport separateLists (GHC.IEThingAll _ name) = do printIeWrappedName name when separateLists space putText "(..)"-printImport _ (IEModuleContents _ (L _ m)) = do+printImport _ (GHC.IEModuleContents _ modu) = do putText "module" space- putText (moduleNameString m)-printImport separateLists (IEThingWith _ name wildcard imps _) = do+ putText . GHC.moduleNameString $ GHC.unLoc modu+printImport separateLists (GHC.IEThingWith _ name wildcard imps) = do printIeWrappedName name when separateLists space let ellipsis = case wildcard of- IEWildcard _position -> [putText ".."]- NoIEWildcard -> []+ GHC.IEWildcard _position -> [putText ".."]+ GHC.NoIEWildcard -> [] parenthesize $ sep (comma >> space) (ellipsis <> fmap printIeWrappedName imps)-printImport _ (IEGroup _ _ _ ) =+printImport _ (GHC.IEGroup _ _ _ ) = error "Language.Haskell.Stylish.Printer.Imports.printImportExport: unhandled case 'IEGroup'"-printImport _ (IEDoc _ _) =+printImport _ (GHC.IEDoc _ _) = error "Language.Haskell.Stylish.Printer.Imports.printImportExport: unhandled case 'IEDoc'"-printImport _ (IEDocNamed _ _) =+printImport _ (GHC.IEDocNamed _ _) = error "Language.Haskell.Stylish.Printer.Imports.printImportExport: unhandled case 'IEDocNamed'"-printImport _ (XIE ext) =- GHC.noExtCon ext ---------------------------------------------------------------------------------printIeWrappedName :: LIEWrappedName RdrName -> P ()-printIeWrappedName lie = unLocated lie & \case- IEName n -> putRdrName n- IEPattern n -> putText "pattern" >> space >> putRdrName n- IEType n -> putText "type" >> space >> putRdrName n+printIeWrappedName :: GHC.LIEWrappedName GHC.RdrName -> P ()+printIeWrappedName lie = case GHC.unLoc lie of+ GHC.IEName n -> putRdrName n+ GHC.IEPattern _ n -> putText "pattern" >> space >> putRdrName n+ GHC.IEType _ n -> putText "type" >> space >> putRdrName n -mergeImports :: NonEmpty (Located Import) -> NonEmpty (Located Import)++mergeImports+ :: NonEmpty (GHC.LImportDecl GHC.GhcPs)+ -> NonEmpty (GHC.LImportDecl GHC.GhcPs) mergeImports (x :| []) = x :| [] mergeImports (h :| (t : ts))- | canMergeImport (unLocated h) (unLocated t) = mergeImports (mergeModuleImport h t :| ts)+ | canMergeImport (GHC.unLoc h) (GHC.unLoc t) = mergeImports (mergeModuleImport h t :| ts) | otherwise = h :| mergeImportsTail (t : ts) where mergeImportsTail (x : y : ys)- | canMergeImport (unLocated x) (unLocated y) = mergeImportsTail ((mergeModuleImport x y) : ys)+ | canMergeImport (GHC.unLoc x) (GHC.unLoc y) = mergeImportsTail ((mergeModuleImport x y) : ys) | otherwise = x : mergeImportsTail (y : ys) mergeImportsTail xs = xs -moduleName :: Import -> String-moduleName- = moduleNameString- . unLocated- . ideclName- . rawImport - -------------------------------------------------------------------------------- data ImportStats = ImportStats { isLongestImport :: !Int@@ -395,49 +394,37 @@ mappend = (<>) mempty = ImportStats 0 False False False -importStats :: Import -> ImportStats+importStats :: GHC.ImportDecl GHC.GhcPs -> ImportStats importStats i =- ImportStats (importModuleNameLength i) (isSource i) (isQualified i) (isSafe i)+ ImportStats (importModuleNameLength i) (isSource i) (isQualified i) (GHC.ideclSafe i) -- Computes length till module name, includes package name. -- TODO: this should reuse code with the printer-importModuleNameLength :: Import -> Int+importModuleNameLength :: GHC.ImportDecl GHC.GhcPs -> Int importModuleNameLength imp =- (case ideclPkgQual (rawImport imp) of+ (case GHC.ideclPkgQual imp of Nothing -> 0 Just sl -> 1 + length (stringLiteral sl)) +- (length $ moduleName imp)+ (length $ importModuleName imp) ---------------------------------------------------------------------------------stringLiteral :: StringLiteral -> String-stringLiteral sl = case sl_st sl of- NoSourceText -> FS.unpackFS $ sl_fs sl- SourceText s -> s+stringLiteral :: GHC.StringLiteral -> String+stringLiteral sl = case GHC.sl_st sl of+ GHC.NoSourceText -> show . GHC.unpackFS $ GHC.sl_fs sl+ GHC.SourceText s -> s ---------------------------------------------------------------------------------isQualified :: Import -> Bool-isQualified- = (/=) NotQualified- . ideclQualified- . rawImport+isQualified :: GHC.ImportDecl GHC.GhcPs -> Bool+isQualified = (/=) GHC.NotQualified . GHC.ideclQualified -isHiding :: Import -> Bool-isHiding- = maybe False fst- . ideclHiding- . rawImport+isHiding :: GHC.ImportDecl GHC.GhcPs -> Bool+isHiding = maybe False fst . GHC.ideclHiding -isSource :: Import -> Bool-isSource- = ideclSource- . rawImport+isSource :: GHC.ImportDecl GHC.GhcPs -> Bool+isSource = (==) GHC.IsBoot . GHC.ideclSource -isSafe :: Import -> Bool-isSafe- = ideclSafe- . rawImport -------------------------------------------------------------------------------- -- | Cleans up an import item list.@@ -445,42 +432,44 @@ -- * Sorts import items. -- * Sort inner import lists, e.g. `import Control.Monad (Monad (return, join))` -- * Removes duplicates from import lists.-prepareImportList :: [LIE GhcPs] -> [LIE GhcPs]+prepareImportList :: [GHC.LIE GHC.GhcPs] -> [GHC.LIE GHC.GhcPs] prepareImportList = sortBy compareLIE . map (fmap prepareInner) . concatMap (toList . snd) . Map.toAscList . mergeByName where- mergeByName :: [LIE GhcPs] -> Map.Map RdrName (NonEmpty (LIE GhcPs))+ mergeByName+ :: [GHC.LIE GHC.GhcPs]+ -> Map.Map GHC.RdrName (NonEmpty (GHC.LIE GHC.GhcPs)) mergeByName imports0 = Map.fromListWith -- Note that ideally every NonEmpty will just have a single entry and we -- will be able to merge everything into that entry. Exotic imports can -- mess this up, though. So they end up in the tail of the list.- (\(x :| xs) (y :| ys) -> case ieMerge (unLocated x) (unLocated y) of- Just z -> (x $> z) :| (xs ++ ys) -- Keep source from `x`+ (\(x :| xs) (y :| ys) -> case ieMerge (GHC.unLoc x) (GHC.unLoc y) of+ Just z -> (x $> z) :| (xs ++ ys) -- Keep source from `x` Nothing -> x :| (xs ++ y : ys))- [(ieName $ unLocated imp, imp :| []) | imp <- imports0]+ [(GHC.ieName $ GHC.unLoc imp, imp :| []) | imp <- imports0] - prepareInner :: IE GhcPs -> IE GhcPs+ prepareInner :: GHC.IE GHC.GhcPs -> GHC.IE GHC.GhcPs prepareInner = \case -- Simplify `A ()` to `A`.- IEThingWith x n NoIEWildcard [] [] -> IEThingAbs x n- IEThingWith x n w ns fs ->- IEThingWith x n w (sortBy (compareWrappedName `on` unLoc) ns) fs+ GHC.IEThingWith x n GHC.NoIEWildcard [] -> GHC.IEThingAbs x n+ GHC.IEThingWith x n w ns ->+ GHC.IEThingWith x n w (sortBy (compareWrappedName `on` GHC.unLoc) ns) ie -> ie -- Merge two import items, assuming they have the same name.- ieMerge :: IE GhcPs -> IE GhcPs -> Maybe (IE GhcPs)- ieMerge l@(IEVar _ _) _ = Just l- ieMerge _ r@(IEVar _ _) = Just r- ieMerge (IEThingAbs _ _) r = Just r- ieMerge l (IEThingAbs _ _) = Just l- ieMerge l@(IEThingAll _ _) _ = Just l- ieMerge _ r@(IEThingAll _ _) = Just r- ieMerge (IEThingWith x0 n0 w0 ns0 []) (IEThingWith _ _ w1 ns1 [])+ ieMerge :: GHC.IE GHC.GhcPs -> GHC.IE GHC.GhcPs -> Maybe (GHC.IE GHC.GhcPs)+ ieMerge l@(GHC.IEVar _ _) _ = Just l+ ieMerge _ r@(GHC.IEVar _ _) = Just r+ ieMerge (GHC.IEThingAbs _ _) r = Just r+ ieMerge l (GHC.IEThingAbs _ _) = Just l+ ieMerge l@(GHC.IEThingAll _ _) _ = Just l+ ieMerge _ r@(GHC.IEThingAll _ _) = Just r+ ieMerge (GHC.IEThingWith x0 n0 w0 ns0) (GHC.IEThingWith _ _ w1 ns1) | w0 /= w1 = Nothing | otherwise = Just $ -- TODO: sort the `ns0 ++ ns1`?- IEThingWith x0 n0 w0 (nubOn (unwrapName . unLoc) $ ns0 ++ ns1) []+ GHC.IEThingWith x0 n0 w0 (nubOn GHC.lieWrappedName $ ns0 ++ ns1) ieMerge _ _ = Nothing
lib/Language/Haskell/Stylish/Step/LanguagePragmas.hs view
@@ -13,15 +13,11 @@ -------------------------------------------------------------------------------- import Data.List.NonEmpty (NonEmpty, fromList, toList) import qualified Data.Set as S-import Data.Text (Text)-import qualified Data.Text as T ---------------------------------------------------------------------------------import qualified GHC.Hs as Hs-import SrcLoc (RealSrcSpan, realSrcSpanStart,- srcLocLine, srcSpanEndLine,- srcSpanStartLine)+import qualified GHC.Hs as GHC+import qualified GHC.Types.SrcLoc as GHC --------------------------------------------------------------------------------@@ -103,9 +99,9 @@ -------------------------------------------------------------------------------- -- | Filter redundant (and duplicate) pragmas out of the groups. As a side -- effect, we also sort the pragmas in their group...-filterRedundant :: (Text -> Bool)- -> [(l, NonEmpty Text)]- -> [(l, [Text])]+filterRedundant :: (String -> Bool)+ -> [(l, NonEmpty String)]+ -> [(l, [String])] filterRedundant isRedundant' = snd . foldr filterRedundant' (S.empty, []) . fmap (fmap toList) where filterRedundant' (l, xs) (known, zs)@@ -133,9 +129,9 @@ languagePragmas = moduleLanguagePragmas m - convertFstToBlock :: [(RealSrcSpan, a)] -> [(Block String, a)]+ convertFstToBlock :: [(GHC.RealSrcSpan, a)] -> [(Block String, a)] convertFstToBlock = fmap \(rspan, a) ->- (Block (srcSpanStartLine rspan) (srcSpanEndLine rspan), a)+ (Block (GHC.srcSpanStartLine rspan) (GHC.srcSpanEndLine rspan), a) groupAdjacent' = fmap turnSndBackToNel . groupAdjacent . fmap (fmap toList)@@ -143,16 +139,17 @@ turnSndBackToNel (a, bss) = (a, fromList . concat $ bss) longest :: Int- longest = maximum $ map T.length $ toList . snd =<< languagePragmas+ longest = maximum $ map length $ toList . snd =<< languagePragmas - groups :: [(Block String, NonEmpty Text)]+ groups :: [(Block String, NonEmpty String)] groups = [(b, pgs) | (b, pgs) <- groupAdjacent' (convertFstToBlock languagePragmas)] changes =- [ change b (const $ prettyPragmas lngPrefix columns longest align style (fmap T.unpack pg))+ [ change b (const $ prettyPragmas lngPrefix columns longest align style pg) | (b, pg) <- filterRedundant isRedundant' groups ] + -------------------------------------------------------------------------------- -- | Add a LANGUAGE pragma to a module if it is not present already. addLanguagePragma :: String -> String -> Module -> [Change String]@@ -161,16 +158,16 @@ | otherwise = [insert line ["{-# " ++ lg ++ " " ++ prag ++ " #-}"]] where pragmas' = moduleLanguagePragmas modu- present = concatMap ((fmap T.unpack) . toList . snd) pragmas'+ present = concatMap (toList . snd) pragmas' line = if null pragmas' then 1 else firstLocation pragmas'- firstLocation :: [(RealSrcSpan, NonEmpty Text)] -> Int- firstLocation = minimum . fmap (srcLocLine . realSrcSpanStart . fst)+ firstLocation :: [(GHC.RealSrcSpan, NonEmpty String)] -> Int+ firstLocation = minimum . fmap (GHC.srcLocLine . GHC.realSrcSpanStart . fst) -------------------------------------------------------------------------------- -- | Check if a language pragma is redundant. We can't do this for all pragmas, -- but we do a best effort.-isRedundant :: Module -> Text -> Bool+isRedundant :: Module -> String -> Bool isRedundant m "ViewPatterns" = isRedundantViewPatterns m isRedundant m "BangPatterns" = isRedundantBangPatterns m isRedundant _ _ = False@@ -181,10 +178,10 @@ isRedundantViewPatterns :: Module -> Bool isRedundantViewPatterns = null . queryModule getViewPat where- getViewPat :: Hs.Pat Hs.GhcPs -> [()]+ getViewPat :: GHC.Pat GHC.GhcPs -> [()] getViewPat = \case- Hs.ViewPat{} -> [()]- _ -> []+ GHC.ViewPat{} -> [()]+ _ -> [] --------------------------------------------------------------------------------@@ -194,13 +191,12 @@ (null $ queryModule getBangPat modul) && (null $ queryModule getMatchStrict modul) where- getBangPat :: Hs.Pat Hs.GhcPs -> [()]+ getBangPat :: GHC.Pat GHC.GhcPs -> [()] getBangPat = \case- Hs.BangPat{} -> [()]- _ -> []+ GHC.BangPat{} -> [()]+ _ -> [] - getMatchStrict :: Hs.Match Hs.GhcPs (Hs.LHsExpr Hs.GhcPs) -> [()]- getMatchStrict (Hs.XMatch m) = Hs.noExtCon m- getMatchStrict (Hs.Match _ ctx _ _) = case ctx of- Hs.FunRhs _ _ Hs.SrcStrict -> [()]- _ -> []+ getMatchStrict :: GHC.Match GHC.GhcPs (GHC.LHsExpr GHC.GhcPs) -> [()]+ getMatchStrict (GHC.Match _ ctx _ _) = case ctx of+ GHC.FunRhs _ _ GHC.SrcStrict -> [()]+ _ -> []
lib/Language/Haskell/Stylish/Step/ModuleHeader.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-} module Language.Haskell.Stylish.Step.ModuleHeader ( Config (..) , BreakWhere (..)@@ -8,30 +9,20 @@ , step ) where + ---------------------------------------------------------------------------------import ApiAnnotation (AnnKeywordId (..),- AnnotationComment (..))-import Control.Monad (forM_, join, when)-import Data.Bifunctor (second)-import Data.Foldable (find, toList)-import Data.Function ((&))-import qualified Data.List as L-import Data.List.NonEmpty (NonEmpty (..))-import qualified Data.List.NonEmpty as NonEmpty-import Data.Maybe (isJust, listToMaybe)-import qualified GHC.Hs.Doc as GHC-import GHC.Hs.Extension (GhcPs)-import qualified GHC.Hs.ImpExp as GHC-import qualified Module as GHC-import SrcLoc (GenLocated (..),- Located, RealLocated,- SrcSpan (..),- srcSpanEndLine,- srcSpanStartLine, unLoc)-import Util (notNull)+import Control.Applicative ((<|>))+import Control.Monad (guard, unless, when)+import Data.Foldable (forM_)+import Data.Maybe (fromMaybe, isJust,+ listToMaybe)+import qualified GHC.Hs as GHC+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Unit.Module.Name as GHC + ---------------------------------------------------------------------------------import Language.Haskell.Stylish.Block+import Language.Haskell.Stylish.Comments import Language.Haskell.Stylish.Editor import Language.Haskell.Stylish.GHC import Language.Haskell.Stylish.Module@@ -39,6 +30,7 @@ import Language.Haskell.Stylish.Printer import Language.Haskell.Stylish.Step import qualified Language.Haskell.Stylish.Step.Imports as Imports+import Language.Haskell.Stylish.Util (flagEnds) data Config = Config@@ -74,229 +66,162 @@ step maxCols = makeStep "Module header" . printModuleHeader maxCols printModuleHeader :: Maybe Int -> Config -> Lines -> Module -> Lines-printModuleHeader maxCols conf ls m =- let- header = moduleHeader m- name = rawModuleName header- haddocks = rawModuleHaddocks header- exports = rawModuleExports header- annotations = rawModuleAnnotations m-- relevantComments :: [RealLocated AnnotationComment]- relevantComments- = moduleComments m- & rawComments- & dropAfterLocated exports- & dropBeforeLocated name-- printedModuleHeader = runPrinter_ (PrinterConfig maxCols) relevantComments- m (printHeader conf name exports haddocks)+printModuleHeader maxCols conf ls lmodul =+ let modul = GHC.unLoc lmodul+ name = GHC.unLoc <$> GHC.hsmodName modul+ haddocks = GHC.hsmodHaddockModHeader modul - getBlock loc =- Block <$> fmap getStartLineUnsafe loc <*> fmap getEndLineUnsafe loc+ startLine = fromMaybe 1 $ moduleLine <|>+ (fmap GHC.srcSpanStartLine . GHC.srcSpanToRealSrcSpan $+ GHC.getLoc lmodul) - adjustOffsetFrom :: Block a -> Block a -> Maybe (Block a)- adjustOffsetFrom (Block s0 _) b2@(Block s1 e1)- | s0 >= s1 && s0 >= e1 = Nothing- | s0 >= s1 = Just (Block (s0 + 1) e1)- | otherwise = Just b2+ endLine = fromMaybe 1 $ whereLine <|>+ (do+ loc <- GHC.getLocA <$> GHC.hsmodExports modul+ GHC.srcSpanEndLine <$> GHC.srcSpanToRealSrcSpan loc) - nameBlock =- getBlock name+ keywordLine kw = listToMaybe $ do+ GHC.EpAnn {..} <- pure $ GHC.hsmodAnn modul+ GHC.AddEpAnn kw' (GHC.EpaSpan s) <- GHC.am_main anns+ guard $ kw == kw'+ pure $ GHC.srcSpanEndLine s - exportsBlock =- join $ adjustOffsetFrom <$> nameBlock <*> getBlock exports+ moduleLine = keywordLine GHC.AnnModule+ whereLine = keywordLine GHC.AnnWhere - whereM :: Maybe SrcSpan- whereM- = annotations- & filter (\(((_, w), _)) -> w == AnnWhere)- & fmap (head . snd) -- get position of annot- & L.sort- & listToMaybe+ commentOnLine l = listToMaybe $ do+ comment <- epAnnComments $ GHC.hsmodAnn modul+ guard $ GHC.srcSpanStartLine (GHC.anchor $ GHC.getLoc comment) == l+ pure comment - isModuleHeaderWhere :: Block a -> Bool- isModuleHeaderWhere w- = not- . overlapping- $ [w] <> toList nameBlock <> toList exportsBlock+ moduleComment = moduleLine >>= commentOnLine+ whereComment =+ guard (whereLine /= moduleLine) >> whereLine >>= commentOnLine - toLineBlock :: SrcSpan -> Block a- toLineBlock (RealSrcSpan s) = Block (srcSpanStartLine s) (srcSpanEndLine s)- toLineBlock s- = error- $ "'where' block was not a RealSrcSpan" <> show s+ exportGroups = case GHC.hsmodExports modul of+ Nothing -> Nothing+ Just lexports -> Just $ doSort $ commentGroups+ (GHC.srcSpanToRealSrcSpan . GHC.getLocA)+ (GHC.unLoc lexports)+ (epAnnComments . GHC.ann $ GHC.getLoc lexports) - whereBlock- = whereM- & fmap toLineBlock- & find isModuleHeaderWhere+ printedModuleHeader = runPrinter_+ (PrinterConfig maxCols)+ (printHeader+ conf name exportGroups haddocks moduleComment whereComment) - deletes =- fmap delete $ mergeAdjacent $ toList nameBlock <> toList exportsBlock <> toList whereBlock+ deletes = delete (Block startLine endLine) - startLine =- maybe 1 blockStart nameBlock+ additions = [insert startLine printedModuleHeader] - additions = [insert startLine printedModuleHeader]+ changes = deletes : additions in - changes = deletes <> additions- in applyChanges changes ls -printHeader- :: Config- -> Maybe (Located GHC.ModuleName)- -> Maybe (Located [GHC.LIE GhcPs])- -> Maybe GHC.LHsDocString- -> P ()-printHeader conf mname mexps _ = do- forM_ mname \(L _ name) -> do- putText "module"- space- putText (showOutputable name)-- case mexps of- Nothing -> when (isJust mname) do- forM_ mname \(L nloc _) -> attachEolComment nloc- case breakWhere conf of- Always -> do- newline- spaces (indent conf)- _ -> space- putText "where"- Just (L loc exps) -> do- moduleComment <- getModuleComment- exportsWithComments <- fmap (second doSort) <$> groupAttachedComments exps- case breakWhere conf of- Single- | Just exportsWithoutComments <- groupWithoutComments exportsWithComments- , length exportsWithoutComments <= 1- -> do- attachModuleComment moduleComment- printSingleLineExportList conf (L loc exportsWithoutComments)- Inline- | Just exportsWithoutComments <- groupWithoutComments exportsWithComments- -> do- wrapping- ( attachModuleComment moduleComment- >> printSingleLineExportList conf (L loc exportsWithoutComments))- ( attachOpenBracket- >> attachModuleComment moduleComment- >> printMultiLineExportList conf (L loc exportsWithComments))- _ -> do- attachOpenBracket- attachModuleComment moduleComment- printMultiLineExportList conf (L loc exportsWithComments) where+ doSort = if sort conf then fmap (commentGroupSort compareLIE) else id - getModuleComment = do- maybemaybeComment <- traverse (\(L nloc _) -> removeModuleComment nloc) mname- pure $ join maybemaybeComment+printHeader+ :: Config+ -> Maybe GHC.ModuleName+ -> Maybe [CommentGroup (GHC.LIE GHC.GhcPs)]+ -> Maybe GHC.LHsDocString+ -> Maybe GHC.LEpaComment -- Comment attached to 'module'+ -> Maybe GHC.LEpaComment -- Comment attached to 'where'+ -> P ()+printHeader conf mbName mbExps _ mbModuleComment mbWhereComment = do+ forM_ mbName $ \name -> do+ putText "module"+ space+ putText (showOutputable name) - attachModuleComment moduleComment =- mapM_ (\c -> space >> putComment c) moduleComment+ case mbExps of+ Nothing -> do+ when (isJust mbName) $ case breakWhere conf of+ Always -> do+ attachModuleComment+ newline+ spaces (indent conf)+ _ -> space+ putText "where"+ Just exports -> case breakWhere conf of+ Single | [] <- exports -> do+ printSingleLineExportList conf []+ attachModuleComment+ Single | [egroup] <- exports+ , not (commentGroupHasComments egroup)+ , [(export, _)] <- (cgItems egroup) -> do+ printSingleLineExportList conf [export]+ attachModuleComment+ Inline | [] <- exports -> do+ printSingleLineExportList conf []+ attachModuleComment+ Inline | [egroup] <- exports, not (commentGroupHasComments egroup) -> do+ wrapping+ (printSingleLineExportList conf $ map fst $ cgItems egroup)+ (do+ attachOpenBracket+ attachModuleComment+ printMultiLineExportList conf exports)+ _ -> do+ attachOpenBracket+ attachModuleComment+ printMultiLineExportList conf exports - doSort = if sort conf then NonEmpty.sortBy compareLIE else id+ putMaybeLineComment $ GHC.unLoc <$> mbWhereComment+ where+ attachModuleComment = putMaybeLineComment $ GHC.unLoc <$> mbModuleComment attachOpenBracket- | openBracket conf == SameLine = putText " ("- | otherwise = pure ()--removeModuleComment :: SrcSpan -> P (Maybe AnnotationComment)-removeModuleComment = \case- UnhelpfulSpan _ -> pure Nothing- RealSrcSpan rspan ->- removeLineComment (srcSpanStartLine rspan)--attachEolComment :: SrcSpan -> P ()-attachEolComment = \case- UnhelpfulSpan _ -> pure ()- RealSrcSpan rspan ->- removeLineComment (srcSpanStartLine rspan) >>= mapM_ \c -> space >> putComment c--attachEolCommentEnd :: SrcSpan -> P ()-attachEolCommentEnd = \case- UnhelpfulSpan _ -> pure ()- RealSrcSpan rspan ->- removeLineComment (srcSpanEndLine rspan) >>= mapM_ \c -> space >> putComment c+ | openBracket conf == SameLine = putText " ("+ | otherwise = pure () -printSingleLineExportList :: Config -> Located [GHC.LIE GhcPs] -> P ()-printSingleLineExportList conf (L srcLoc exports) = do- space >> putText "("- printInlineExports exports- putText ")" >> space >> putText "where" >> attachEolCommentEnd srcLoc+printSingleLineExportList+ :: Config -> [GHC.LIE GHC.GhcPs] -> P ()+printSingleLineExportList conf exports = do+ space >> putText "("+ printExports exports+ putText ")" >> space >> putText "where" where- printInlineExports :: [GHC.LIE GhcPs] -> P ()- printInlineExports = \case- [] -> pure ()- [e] -> printExport conf e- (e:es) -> printExport conf e >> comma >> space >> printInlineExports es+ printExports :: [GHC.LIE GHC.GhcPs] -> P ()+ printExports = \case+ [] -> pure ()+ [e] -> putExport conf e+ (e:es) -> putExport conf e >> comma >> space >> printExports es printMultiLineExportList :: Config- -> Located [([AnnotationComment], NonEmpty (GHC.LIE GhcPs))]+ -> [CommentGroup (GHC.LIE GHC.GhcPs)] -> P ()-printMultiLineExportList conf (L srcLoc exportsWithComments) = do- newline- doIndent >> putText firstChar >> when (notNull exportsWithComments) space- printExports exportsWithComments-- putText ")" >> space >> putText "where" >> attachEolCommentEnd srcLoc+printMultiLineExportList conf exports = do+ newline+ doIndent >> putText firstChar >> unless (null exports) space+ mapM_ printExport $ flagEnds exports+ when (null exports) $ newline >> doIndent+ putText ")" >> space >> putText "where" where- -- 'doIndent' is @x@:- --- -- > module Foo- -- > xxxx( foo- -- > xxxx, bar- -- > xxxx) where- --- -- 'doHang' is @y@:- --- -- > module Foo- -- > xxxx( -- Some comment- -- > xxxxyyfoo- -- > xxxx) where+ printExport (CommentGroup {..}, firstGroup, _lastGroup) = do+ forM_ (flagEnds cgPrior) $ \(cmt, start, _end) -> do+ unless (firstGroup && start) $ space >> space+ putComment $ GHC.unLoc cmt+ newline >> doIndent - firstChar =- case openBracket conf of+ forM_ (flagEnds cgItems) $ \((export, mbComment), start, _end) -> do+ if firstGroup && start then+ unless (null cgPrior) $ space >> space+ else+ comma >> space+ putExport conf export+ putMaybeLineComment $ GHC.unLoc <$> mbComment+ newline >> doIndent++ firstChar = case openBracket conf of SameLine -> " " NextLine -> "(" doIndent = spaces (indent conf)- doHang = pad (indent conf + 2) - printExports :: [([AnnotationComment], NonEmpty (GHC.LIE GhcPs))] -> P ()- printExports (([], firstInGroup :| groupRest) : rest) = do- printExport conf firstInGroup- newline- doIndent- printExportsGroupTail groupRest- printExportsTail rest- printExports ((firstComment : comments, firstExport :| groupRest) : rest) = do- putComment firstComment >> newline >> doIndent- forM_ comments \c -> doHang >> putComment c >> newline >> doIndent- doHang- printExport conf firstExport- newline- doIndent- printExportsGroupTail groupRest- printExportsTail rest- printExports [] =- newline >> doIndent-- printExportsTail :: [([AnnotationComment], NonEmpty (GHC.LIE GhcPs))] -> P ()- printExportsTail = mapM_ \(comments, exported) -> do- forM_ comments \c -> doHang >> putComment c >> newline >> doIndent- forM_ exported \export -> do- comma >> space >> printExport conf export- newline >> doIndent-- printExportsGroupTail :: [GHC.LIE GhcPs] -> P ()- printExportsGroupTail (x : xs) = printExportsTail [([], x :| xs)]- printExportsGroupTail [] = pure ()- -- NOTE(jaspervdj): This code is almost the same as the import printing in -- 'Imports' and should be merged.-printExport :: Config -> GHC.LIE GhcPs -> P ()-printExport conf = Imports.printImport (separateLists conf) . unLoc+putExport :: Config -> GHC.LIE GHC.GhcPs -> P ()+putExport conf = Imports.printImport (separateLists conf) . GHC.unLoc
lib/Language/Haskell/Stylish/Step/SimpleAlign.hs view
@@ -15,7 +15,8 @@ import Data.List (foldl', foldl1', sortOn) import Data.Maybe (fromMaybe) import qualified GHC.Hs as Hs-import qualified SrcLoc as S+import qualified GHC.Parser.Annotation as GHC+import qualified GHC.Types.SrcLoc as GHC --------------------------------------------------------------------------------@@ -48,49 +49,47 @@ , cMultiWayIf = Always } -groupAlign :: Align -> [Alignable S.RealSrcSpan] -> [[Alignable S.RealSrcSpan]]+groupAlign :: Align -> [Alignable GHC.RealSrcSpan] -> [[Alignable GHC.RealSrcSpan]] groupAlign a xs = case a of Never -> []- Adjacent -> byLine . sortOn (S.srcSpanStartLine . aLeft) $ xs+ Adjacent -> byLine . sortOn (GHC.srcSpanStartLine . aLeft) $ xs Always -> [xs] where byLine = map toList . groupByLine aLeft ---------------------------------------------------------------------------------type Record = [S.Located (Hs.ConDeclField Hs.GhcPs)]+type Record = [GHC.LocatedA (Hs.ConDeclField Hs.GhcPs)] ---------------------------------------------------------------------------------records :: S.Located (Hs.HsModule Hs.GhcPs) -> [Record]+records :: GHC.Located Hs.HsModule -> [Record] records modu = do- let decls = map S.unLoc (Hs.hsmodDecls (S.unLoc modu))+ let decls = map GHC.unLoc (Hs.hsmodDecls (GHC.unLoc modu)) tyClDecls = [ tyClDecl | Hs.TyClD _ tyClDecl <- decls ] dataDecls = [ d | d@(Hs.DataDecl _ _ _ _ _) <- tyClDecls ] dataDefns = map Hs.tcdDataDefn dataDecls d@Hs.ConDeclH98 {} <- concatMap getConDecls dataDefns case Hs.con_args d of- Hs.RecCon rec -> [S.unLoc rec]+ Hs.RecCon rec -> [GHC.unLoc rec] _ -> [] where getConDecls :: Hs.HsDataDefn Hs.GhcPs -> [Hs.ConDecl Hs.GhcPs]- getConDecls d@Hs.HsDataDefn {} = map S.unLoc $ Hs.dd_cons d- getConDecls (Hs.XHsDataDefn x) = Hs.noExtCon x+ getConDecls d@Hs.HsDataDefn {} = map GHC.unLoc $ Hs.dd_cons d ---------------------------------------------------------------------------------recordToAlignable :: Config -> Record -> [[Alignable S.RealSrcSpan]]+recordToAlignable :: Config -> Record -> [[Alignable GHC.RealSrcSpan]] recordToAlignable conf = groupAlign (cRecords conf) . fromMaybe [] . traverse fieldDeclToAlignable -------------------------------------------------------------------------------- fieldDeclToAlignable- :: S.Located (Hs.ConDeclField Hs.GhcPs) -> Maybe (Alignable S.RealSrcSpan)-fieldDeclToAlignable (S.L _ (Hs.XConDeclField x)) = Hs.noExtCon x-fieldDeclToAlignable (S.L matchLoc (Hs.ConDeclField _ names ty _)) = do- matchPos <- toRealSrcSpan matchLoc- leftPos <- toRealSrcSpan $ S.getLoc $ last names- tyPos <- toRealSrcSpan $ S.getLoc ty+ :: GHC.LocatedA (Hs.ConDeclField Hs.GhcPs) -> Maybe (Alignable GHC.RealSrcSpan)+fieldDeclToAlignable (GHC.L matchLoc (Hs.ConDeclField _ names ty _)) = do+ matchPos <- GHC.srcSpanToRealSrcSpan $ GHC.locA matchLoc+ leftPos <- GHC.srcSpanToRealSrcSpan $ GHC.getLoc $ last names+ tyPos <- GHC.srcSpanToRealSrcSpan $ GHC.getLocA ty Just $ Alignable { aContainer = matchPos , aLeft = leftPos@@ -103,60 +102,58 @@ matchGroupToAlignable :: Config -> Hs.MatchGroup Hs.GhcPs (Hs.LHsExpr Hs.GhcPs)- -> [[Alignable S.RealSrcSpan]]-matchGroupToAlignable _conf (Hs.XMatchGroup x) = Hs.noExtCon x+ -> [[Alignable GHC.RealSrcSpan]] matchGroupToAlignable conf (Hs.MG _ alts _) = cases' ++ patterns' where- (cases, patterns) = partitionEithers . fromMaybe [] $ traverse matchToAlignable (S.unLoc alts)+ (cases, patterns) = partitionEithers . fromMaybe [] $ traverse matchToAlignable (GHC.unLoc alts) cases' = groupAlign (cCases conf) cases patterns' = groupAlign (cTopLevelPatterns conf) patterns -------------------------------------------------------------------------------- matchToAlignable- :: S.Located (Hs.Match Hs.GhcPs (Hs.LHsExpr Hs.GhcPs))- -> Maybe (Either (Alignable S.RealSrcSpan) (Alignable S.RealSrcSpan))-matchToAlignable (S.L matchLoc m@(Hs.Match _ Hs.CaseAlt pats@(_ : _) grhss)) = do- let patsLocs = map S.getLoc pats+ :: GHC.LocatedA (Hs.Match Hs.GhcPs (Hs.LHsExpr Hs.GhcPs))+ -> Maybe (Either (Alignable GHC.RealSrcSpan) (Alignable GHC.RealSrcSpan))+matchToAlignable (GHC.L matchLoc m@(Hs.Match _ Hs.CaseAlt pats@(_ : _) grhss)) = do+ let patsLocs = map GHC.getLocA pats pat = last patsLocs guards = getGuards m- guardsLocs = map S.getLoc guards- left = foldl' S.combineSrcSpans pat guardsLocs+ guardsLocs = map GHC.getLocA guards+ left = foldl' GHC.combineSrcSpans pat guardsLocs body <- rhsBody grhss- matchPos <- toRealSrcSpan matchLoc- leftPos <- toRealSrcSpan left- rightPos <- toRealSrcSpan $ S.getLoc body+ matchPos <- GHC.srcSpanToRealSrcSpan $ GHC.locA matchLoc+ leftPos <- GHC.srcSpanToRealSrcSpan left+ rightPos <- GHC.srcSpanToRealSrcSpan $ GHC.getLocA body Just . Left $ Alignable { aContainer = matchPos , aLeft = leftPos , aRight = rightPos , aRightLead = length "-> " }-matchToAlignable (S.L matchLoc (Hs.Match _ (Hs.FunRhs name _ _) pats@(_ : _) grhss)) = do+matchToAlignable (GHC.L matchLoc (Hs.Match _ (Hs.FunRhs name _ _) pats@(_ : _) grhss)) = do body <- unguardedRhsBody grhss- let patsLocs = map S.getLoc pats- nameLoc = S.getLoc name+ let patsLocs = map GHC.getLocA pats+ nameLoc = GHC.getLocA name left = last (nameLoc : patsLocs)- bodyLoc = S.getLoc body- matchPos <- toRealSrcSpan matchLoc- leftPos <- toRealSrcSpan left- bodyPos <- toRealSrcSpan bodyLoc+ bodyLoc = GHC.getLocA body+ matchPos <- GHC.srcSpanToRealSrcSpan $ GHC.locA matchLoc+ leftPos <- GHC.srcSpanToRealSrcSpan left+ bodyPos <- GHC.srcSpanToRealSrcSpan bodyLoc Just . Right $ Alignable { aContainer = matchPos , aLeft = leftPos , aRight = bodyPos , aRightLead = length "= " }-matchToAlignable (S.L _ (Hs.XMatch x)) = Hs.noExtCon x-matchToAlignable (S.L _ (Hs.Match _ _ _ _)) = Nothing+matchToAlignable (GHC.L _ (Hs.Match _ _ _ _)) = Nothing -------------------------------------------------------------------------------- multiWayIfToAlignable :: Config -> Hs.LHsExpr Hs.GhcPs- -> [[Alignable S.RealSrcSpan]]-multiWayIfToAlignable conf (S.L _ (Hs.HsMultiIf _ grhss)) =+ -> [[Alignable GHC.RealSrcSpan]]+multiWayIfToAlignable conf (GHC.L _ (Hs.HsMultiIf _ grhss)) = groupAlign (cMultiWayIf conf) as where as = fromMaybe [] $ traverse grhsToAlignable grhss@@ -165,34 +162,34 @@ -------------------------------------------------------------------------------- grhsToAlignable- :: S.Located (Hs.GRHS Hs.GhcPs (Hs.LHsExpr Hs.GhcPs))- -> Maybe (Alignable S.RealSrcSpan)-grhsToAlignable (S.L grhsloc (Hs.GRHS _ guards@(_ : _) body)) = do- let guardsLocs = map S.getLoc guards- bodyLoc = S.getLoc body- left = foldl1' S.combineSrcSpans guardsLocs- matchPos <- toRealSrcSpan grhsloc- leftPos <- toRealSrcSpan left- bodyPos <- toRealSrcSpan bodyLoc+ :: GHC.Located (Hs.GRHS Hs.GhcPs (Hs.LHsExpr Hs.GhcPs))+ -> Maybe (Alignable GHC.RealSrcSpan)+grhsToAlignable (GHC.L grhsloc (Hs.GRHS _ guards@(_ : _) body)) = do+ let guardsLocs = map GHC.getLocA guards+ bodyLoc = GHC.getLocA $ body+ left = foldl1' GHC.combineSrcSpans guardsLocs+ matchPos <- GHC.srcSpanToRealSrcSpan grhsloc+ leftPos <- GHC.srcSpanToRealSrcSpan left+ bodyPos <- GHC.srcSpanToRealSrcSpan bodyLoc Just $ Alignable { aContainer = matchPos , aLeft = leftPos , aRight = bodyPos , aRightLead = length "-> " }-grhsToAlignable (S.L _ (Hs.XGRHS x)) = Hs.noExtCon x-grhsToAlignable (S.L _ _) = Nothing+grhsToAlignable (GHC.L _ _) = Nothing -------------------------------------------------------------------------------- step :: Maybe Int -> Config -> Step step maxColumns config = makeStep "Cases" $ \ls module' -> let changes- :: (S.Located (Hs.HsModule Hs.GhcPs) -> [a])- -> (a -> [[Alignable S.RealSrcSpan]])+ :: (GHC.Located Hs.HsModule -> [a])+ -> (a -> [[Alignable GHC.RealSrcSpan]]) -> [Change String] changes search toAlign =- (concatMap . concatMap) (align maxColumns) . map toAlign $ search (parsedModule module')+ (concatMap . concatMap) (align maxColumns) . map toAlign $+ search module' configured :: [Change String] configured = concat $
lib/Language/Haskell/Stylish/Step/Squash.hs view
@@ -8,9 +8,10 @@ ---------------------------------------------------------------------------------import Data.Maybe (mapMaybe)-import qualified GHC.Hs as Hs-import qualified SrcLoc as S+import Control.Monad (guard)+import Data.Maybe (mapMaybe)+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Hs as GHC --------------------------------------------------------------------------------@@ -20,38 +21,34 @@ ---------------------------------------------------------------------------------squash- :: (S.HasSrcSpan l, S.HasSrcSpan r)- => l -> r -> Maybe (Change String)+squash :: GHC.SrcSpan -> GHC.SrcSpan -> Maybe (Change String) squash left right = do- lAnn <- toRealSrcSpan $ S.getLoc left- rAnn <- toRealSrcSpan $ S.getLoc right- if S.srcSpanEndLine lAnn == S.srcSpanStartLine rAnn ||- S.srcSpanEndLine lAnn + 1 == S.srcSpanStartLine rAnn- then Just $- changeLine (S.srcSpanEndLine lAnn) $ \str ->- let (pre, post) = splitAt (S.srcSpanEndCol lAnn) str- in [trimRight pre ++ " " ++ trimLeft post]- else Nothing+ l <- GHC.srcSpanToRealSrcSpan left+ r <- GHC.srcSpanToRealSrcSpan right+ guard $+ GHC.srcSpanEndLine l == GHC.srcSpanStartLine r ||+ GHC.srcSpanEndLine l + 1 == GHC.srcSpanStartLine r+ pure $ changeLine (GHC.srcSpanEndLine l) $ \str ->+ let (pre, post) = splitAt (GHC.srcSpanEndCol l) str+ in [trimRight pre ++ " " ++ trimLeft post] ---------------------------------------------------------------------------------squashFieldDecl :: Hs.ConDeclField Hs.GhcPs -> Maybe (Change String)-squashFieldDecl (Hs.ConDeclField _ names type' _)+squashFieldDecl :: GHC.ConDeclField GHC.GhcPs -> Maybe (Change String)+squashFieldDecl (GHC.ConDeclField _ names type' _) | null names = Nothing- | otherwise = squash (last names) type'-squashFieldDecl (Hs.XConDeclField x) = Hs.noExtCon x+ | otherwise = squash (GHC.getLoc $ last names) (GHC.getLocA type') ---------------------------------------------------------------------------------squashMatch :: Hs.Match Hs.GhcPs (Hs.LHsExpr Hs.GhcPs) -> Maybe (Change String)-squashMatch (Hs.Match _ (Hs.FunRhs name _ _) [] grhss) = do+squashMatch+ :: GHC.Match GHC.GhcPs (GHC.LHsExpr GHC.GhcPs) -> Maybe (Change String)+squashMatch (GHC.Match _ (GHC.FunRhs name _ _) [] grhss) = do body <- unguardedRhsBody grhss- squash name body-squashMatch (Hs.Match _ _ pats grhss) = do+ squash (GHC.getLocA name) (GHC.getLocA body)+squashMatch (GHC.Match _ _ pats grhss) = do body <- unguardedRhsBody grhss- squash (last pats) body-squashMatch (Hs.XMatch x) = Hs.noExtCon x+ squash (GHC.getLocA $ last pats) (GHC.getLocA body) --------------------------------------------------------------------------------
lib/Language/Haskell/Stylish/Step/UnicodeSyntax.hs view
@@ -5,22 +5,20 @@ ---------------------------------------------------------------------------------import Data.List (isPrefixOf,- sort)-import Data.Map (Map)-import qualified Data.Map as M-import Data.Maybe (maybeToList)-import GHC.Hs.Binds-import GHC.Hs.Extension (GhcPs)-import GHC.Hs.Types+import qualified Data.Map as M+import qualified GHC.Hs as GHC+import qualified GHC.Types.SrcLoc as GHC++ ---------------------------------------------------------------------------------import Language.Haskell.Stylish.Block import Language.Haskell.Stylish.Editor import Language.Haskell.Stylish.Module import Language.Haskell.Stylish.Step import Language.Haskell.Stylish.Step.LanguagePragmas (addLanguagePragma)-import Language.Haskell.Stylish.Util+import Language.Haskell.Stylish.Util (everything) ++{- -------------------------------------------------------------------------------- unicodeReplacements :: Map String String unicodeReplacements = M.fromList@@ -32,66 +30,90 @@ , ("-<", "↢") , (">-", "↣") ]+-} +--------------------------------------------------------------------------------+-- Simple type that can do replacments on single lines (not spanning, removing+-- or adding lines).+newtype Replacement = Replacement+ { unReplacement :: M.Map Int [(Int, Int, String)]+ } deriving (Show) + ---------------------------------------------------------------------------------replaceAll :: [(Int, [(Int, String)])] -> [Change String]-replaceAll = map changeLine'- where- changeLine' (r, ns) = changeLine r $ \str -> return $- applyChanges- [ change (Block c ec) (const repl)- | (c, needle) <- sort ns- , let ec = c + length needle - 1- , repl <- maybeToList $ M.lookup needle unicodeReplacements- ] str+instance Semigroup Replacement where+ Replacement l <> Replacement r = Replacement $ M.unionWith (++) l r ---------------------------------------------------------------------------------groupPerLine :: [((Int, Int), a)] -> [(Int, [(Int, a)])]-groupPerLine = M.toList . M.fromListWith (++) .- map (\((r, c), x) -> (r, [(c, x)]))+instance Monoid Replacement where+ mempty = Replacement mempty --- | Find symbol positions in the module. Currently only searches in type--- signatures.-findSymbol :: Module -> Lines -> String -> [((Int, Int), String)]-findSymbol module' ls sym =- [ (pos, sym)- | TypeSig _ funLoc typeLoc <- everything (rawModuleDecls $ moduleDecls module') :: [Sig GhcPs]- , (funStart, _) <- infoPoints funLoc- , (_, typeEnd) <- infoPoints [hsSigWcType typeLoc]- , pos <- maybeToList $ between funStart typeEnd sym ls- ] ----------------------------------------------------------------------------------- | Search for a needle in a haystack of lines. Only part the inside (startRow,--- startCol), (endRow, endCol) is searched. The return value is the position of--- the needle.-between :: (Int, Int) -> (Int, Int) -> String -> Lines -> Maybe (Int, Int)-between (startRow, startCol) (endRow, endCol) needle =- search (startRow, startCol) .- withLast (take endCol) .- withHead (drop $ startCol - 1) .- take (endRow - startRow + 1) .- drop (startRow - 1)+mkReplacement :: GHC.RealSrcSpan -> String -> Replacement+mkReplacement rss repl+ | GHC.srcSpanStartLine rss /= GHC.srcSpanEndLine rss = Replacement mempty+ | otherwise = Replacement $+ M.singleton+ (GHC.srcSpanStartLine rss)+ [(GHC.srcSpanStartCol rss, GHC.srcSpanEndCol rss, repl)]+++--------------------------------------------------------------------------------+applyReplacement :: Replacement -> [String] -> [String]+applyReplacement (Replacement repl) ls = do+ (i, l) <- zip [1 ..] ls+ case M.lookup i repl of+ Nothing -> pure l+ Just repls -> pure $ go repls l where- search _ [] = Nothing- search (r, _) ([] : xs) = search (r + 1, 1) xs- search (r, c) (x : xs)- | needle `isPrefixOf` x = Just (r, c)- | otherwise = search (r, c + 1) (tail x : xs)+ go [] l = l+ go ((xstart, xend, x) : repls) l =+ let l' = take (xstart - 1) l ++ x ++ drop (xend - 1) l in+ go (adjust (xstart, xend, x) <$> repls) l' + adjust (xstart, xend, x) (ystart, yend, y)+ | ystart > xend =+ let offset = length x - (xend - xstart) in+ (ystart + offset, yend + offset, y)+ | otherwise = (ystart, yend, y) + --------------------------------------------------------------------------------+hsTyReplacements :: GHC.HsType GHC.GhcPs -> Replacement+hsTyReplacements (GHC.HsFunTy xann arr _ _)+ | GHC.HsUnrestrictedArrow GHC.NormalSyntax <- arr+ , GHC.AddRarrowAnn (GHC.EpaSpan loc) <- GHC.anns xann =+ mkReplacement loc "→"+hsTyReplacements (GHC.HsQualTy _ (Just ctx) _)+ | Just arrow <- GHC.ac_darrow . GHC.anns . GHC.ann $ GHC.getLoc ctx+ , (GHC.NormalSyntax, GHC.EpaSpan loc) <- arrow =+ mkReplacement loc "⇒"+hsTyReplacements _ = mempty+++--------------------------------------------------------------------------------+hsSigReplacements :: GHC.Sig GHC.GhcPs -> Replacement+hsSigReplacements (GHC.TypeSig ann _ _)+ | GHC.AddEpAnn GHC.AnnDcolon epaLoc <- GHC.asDcolon $ GHC.anns ann+ , GHC.EpaSpan loc <- epaLoc =+ mkReplacement loc "∷"+hsSigReplacements _ = mempty+++-------------------------------------------------------------------------------- step :: Bool -> String -> Step step = (makeStep "UnicodeSyntax" .) . step' -------------------------------------------------------------------------------- step' :: Bool -> String -> Lines -> Module -> Lines-step' alp lg ls module' = applyChanges changes ls+step' alp lg ls modu =+ applyChanges+ (if alp then addLanguagePragma lg "UnicodeSyntax" modu else []) $+ applyReplacement replacement ls where- changes = (if alp then addLanguagePragma lg "UnicodeSyntax" module' else []) ++- replaceAll perLine- toReplace = [ "::", "=>", "->" ]- perLine = sort $ groupPerLine $ concatMap (findSymbol module' ls) toReplace+ replacement =+ foldMap hsTyReplacements (everything modu) <>+ foldMap hsSigReplacements (everything modu)
lib/Language/Haskell/Stylish/Util.hs view
@@ -5,7 +5,6 @@ ( indent , padRight , everything- , infoPoints , trimLeft , trimRight , wrap@@ -20,8 +19,6 @@ , withLast , flagEnds - , toRealSrcSpan- , traceOutputable , traceOutputableM @@ -40,12 +37,13 @@ import Data.Typeable (cast) import Debug.Trace (trace) import qualified GHC.Hs as Hs-import qualified Outputable-import qualified SrcLoc as S+import qualified GHC.Types.SrcLoc as GHC+import qualified GHC.Utils.Outputable as GHC -------------------------------------------------------------------------------- import Language.Haskell.Stylish.Step+import Language.Haskell.Stylish.GHC (showOutputable) --------------------------------------------------------------------------------@@ -69,6 +67,7 @@ --------------------------------------------------------------------------------+{- infoPoints :: [S.Located pass] -> [((Int, Int), (Int, Int))] infoPoints = fmap (helper . S.getLoc) where@@ -79,7 +78,7 @@ end = S.realSrcSpanEnd s ((S.srcLocLine start, S.srcLocCol start), (S.srcLocLine end, S.srcLocCol end)) helper _ = ((-1,-1), (-1,-1))-+-} -------------------------------------------------------------------------------- trimLeft :: String -> String@@ -213,35 +212,28 @@ ---------------------------------------------------------------------------------traceOutputable :: Outputable.Outputable a => String -> a -> b -> b+traceOutputable :: GHC.Outputable a => String -> a -> b -> b traceOutputable title x =- trace (title ++ ": " ++ (Outputable.showSDocUnsafe $ Outputable.ppr x))+ trace (title ++ ": " ++ (showOutputable x)) ---------------------------------------------------------------------------------traceOutputableM :: (Outputable.Outputable a, Monad m) => String -> a -> m ()+traceOutputableM :: (GHC.Outputable a, Monad m) => String -> a -> m () traceOutputableM title x = traceOutputable title x $ pure () ----------------------------------------------------------------------------------- take the (Maybe) RealSrcSpan out of the SrcSpan-toRealSrcSpan :: S.SrcSpan -> Maybe S.RealSrcSpan-toRealSrcSpan (S.RealSrcSpan s) = Just s-toRealSrcSpan _ = Nothing----------------------------------------------------------------------------------- -- Utility: grab the body out of guarded RHSs if it's a single unguarded one. unguardedRhsBody :: Hs.GRHSs Hs.GhcPs a -> Maybe a unguardedRhsBody (Hs.GRHSs _ [grhs] _)- | Hs.GRHS _ [] body <- S.unLoc grhs = Just body+ | Hs.GRHS _ [] body <- GHC.unLoc grhs = Just body unguardedRhsBody _ = Nothing -- Utility: grab the body out of guarded RHSs rhsBody :: Hs.GRHSs Hs.GhcPs a -> Maybe a rhsBody (Hs.GRHSs _ [grhs] _)- | Hs.GRHS _ _ body <- S.unLoc grhs = Just body+ | Hs.GRHS _ _ body <- GHC.unLoc grhs = Just body rhsBody _ = Nothing @@ -251,17 +243,14 @@ getGuards (Hs.Match _ _ _ grhss) = let lgrhs = getLocGRHS grhss -- []- grhs = map S.unLoc lgrhs+ grhs = map GHC.unLoc lgrhs in concatMap getGuardLStmts grhs-getGuards (Hs.XMatch x) = Hs.noExtCon x getLocGRHS :: Hs.GRHSs Hs.GhcPs (Hs.LHsExpr Hs.GhcPs) -> [Hs.LGRHS Hs.GhcPs (Hs.LHsExpr Hs.GhcPs)] getLocGRHS (Hs.GRHSs _ guardeds _) = guardeds-getLocGRHS (Hs.XGRHSs x) = Hs.noExtCon x getGuardLStmts :: Hs.GRHS Hs.GhcPs (Hs.LHsExpr Hs.GhcPs) -> [Hs.GuardLStmt Hs.GhcPs] getGuardLStmts (Hs.GRHS _ guards _) = guards-getGuardLStmts (Hs.XGRHS x) = Hs.noExtCon x
stylish-haskell.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.4 Name: stylish-haskell-Version: 0.13.0.0+Version: 0.14.0.0 Synopsis: Haskell code prettifier Homepage: https://github.com/haskell/stylish-haskell License: BSD-3-Clause@@ -23,20 +23,47 @@ README.markdown, data/stylish-haskell.yaml -Library- Hs-source-dirs: lib+Common depends Ghc-options: -Wall Default-language: Haskell2010 + Build-depends:+ aeson >= 0.6 && < 2.1,+ base >= 4.8 && < 5,+ bytestring >= 0.9 && < 0.11,+ Cabal >= 3.4 && < 3.7,+ containers >= 0.3 && < 0.7,+ directory >= 1.2.3 && < 1.4,+ filepath >= 1.1 && < 1.5,+ file-embed >= 0.0.10 && < 0.1,+ ghc-lib-parser >= 9.2 && < 9.3,+ ghc-lib-parser-ex >= 9.2 && < 9.3,+ mtl >= 2.0 && < 2.3,+ syb >= 0.3 && < 0.8,+ text >= 1.2 && < 1.3,+ HsYAML-aeson >=0.2.0 && < 0.3,+ HsYAML >=0.2.0 && < 0.3++ if impl(ghc < 8.0)+ Build-depends:+ semigroups >= 0.18 && < 0.20++Library+ Import: depends+ Hs-source-dirs: lib+ Exposed-modules: Language.Haskell.Stylish+ Language.Haskell.Stylish.Config Language.Haskell.Stylish.GHC Language.Haskell.Stylish.Module+ Language.Haskell.Stylish.Parse Language.Haskell.Stylish.Printer+ Language.Haskell.Stylish.Step Language.Haskell.Stylish.Step.Data Language.Haskell.Stylish.Step.Imports- Language.Haskell.Stylish.Step.ModuleHeader Language.Haskell.Stylish.Step.LanguagePragmas+ Language.Haskell.Stylish.Step.ModuleHeader Language.Haskell.Stylish.Step.SimpleAlign Language.Haskell.Stylish.Step.Squash Language.Haskell.Stylish.Step.Tabs@@ -46,13 +73,11 @@ Other-modules: Language.Haskell.Stylish.Align Language.Haskell.Stylish.Block- Language.Haskell.Stylish.Config+ Language.Haskell.Stylish.Comments Language.Haskell.Stylish.Config.Cabal Language.Haskell.Stylish.Config.Internal Language.Haskell.Stylish.Editor Language.Haskell.Stylish.Ordering- Language.Haskell.Stylish.Parse- Language.Haskell.Stylish.Step Language.Haskell.Stylish.Util Language.Haskell.Stylish.Verbose Paths_stylish_haskell@@ -60,123 +85,45 @@ Autogen-modules: Paths_stylish_haskell - Build-depends:- aeson >= 0.6 && < 1.6,- base >= 4.8 && < 5,- bytestring >= 0.9 && < 0.11,- Cabal >= 2.4 && < 3.3,- containers >= 0.3 && < 0.7,- directory >= 1.2.3 && < 1.4,- filepath >= 1.1 && < 1.5,- file-embed >= 0.0.10 && < 0.1,- ghc-lib-parser >= 8.10 && < 8.12,- mtl >= 2.0 && < 2.3,- syb >= 0.3 && < 0.8,- text >= 1.2 && < 1.3,- HsYAML-aeson >=0.2.0 && < 0.3,- HsYAML >=0.2.0 && < 0.3-- if impl(ghc < 8.0)- Build-depends:- semigroups >= 0.18 && < 0.20- Executable stylish-haskell- Ghc-options: -Wall- Hs-source-dirs: src- Main-is: Main.hs- Default-language: Haskell2010+ Import: depends+ Hs-source-dirs: src+ Main-is: Main.hs Build-depends: stylish-haskell, strict >= 0.3 && < 0.5,- optparse-applicative >= 0.12 && < 0.17,- -- Copied from regular dependencies...- aeson >= 0.6 && < 1.6,- base >= 4.8 && < 5,- bytestring >= 0.9 && < 0.11,- Cabal >= 2.4 && < 3.3,- containers >= 0.3 && < 0.7,- directory >= 1.2.3 && < 1.4,- filepath >= 1.1 && < 1.5,- file-embed >= 0.0.10 && < 0.1,- ghc-lib-parser >= 8.10 && < 8.12,- mtl >= 2.0 && < 2.3,- syb >= 0.3 && < 0.8,- HsYAML-aeson >=0.2.0 && < 0.3,- HsYAML >=0.2.0 && < 0.3+ optparse-applicative >= 0.12 && < 0.18 Test-suite stylish-haskell-tests- Ghc-options: -Wall- Hs-source-dirs: tests lib- Main-is: TestSuite.hs- Type: exitcode-stdio-1.0- Default-language: Haskell2010+ Import: depends+ Hs-source-dirs: tests+ Main-is: TestSuite.hs+ Type: exitcode-stdio-1.0 Other-modules:- Language.Haskell.Stylish- Language.Haskell.Stylish.Align- Language.Haskell.Stylish.Block- Language.Haskell.Stylish.Config- Language.Haskell.Stylish.Config.Cabal- Language.Haskell.Stylish.Config.Internal Language.Haskell.Stylish.Config.Tests- Language.Haskell.Stylish.Editor- Language.Haskell.Stylish.GHC- Language.Haskell.Stylish.Ordering- Language.Haskell.Stylish.Module- Language.Haskell.Stylish.Parse Language.Haskell.Stylish.Parse.Tests- Language.Haskell.Stylish.Printer- Language.Haskell.Stylish.Step- Language.Haskell.Stylish.Step.Imports- Language.Haskell.Stylish.Step.Imports.Tests- Language.Haskell.Stylish.Step.Imports.FelixTests- Language.Haskell.Stylish.Step.Data+ Language.Haskell.Stylish.Regressions Language.Haskell.Stylish.Step.Data.Tests- Language.Haskell.Stylish.Step.ModuleHeader- Language.Haskell.Stylish.Step.ModuleHeader.Tests- Language.Haskell.Stylish.Step.LanguagePragmas+ Language.Haskell.Stylish.Step.Imports.FelixTests+ Language.Haskell.Stylish.Step.Imports.Tests Language.Haskell.Stylish.Step.LanguagePragmas.Tests- Language.Haskell.Stylish.Step.SimpleAlign+ Language.Haskell.Stylish.Step.ModuleHeader.Tests Language.Haskell.Stylish.Step.SimpleAlign.Tests- Language.Haskell.Stylish.Step.Squash Language.Haskell.Stylish.Step.Squash.Tests- Language.Haskell.Stylish.Step.Tabs Language.Haskell.Stylish.Step.Tabs.Tests- Language.Haskell.Stylish.Step.TrailingWhitespace Language.Haskell.Stylish.Step.TrailingWhitespace.Tests- Language.Haskell.Stylish.Step.UnicodeSyntax Language.Haskell.Stylish.Step.UnicodeSyntax.Tests- Language.Haskell.Stylish.Regressions Language.Haskell.Stylish.Tests Language.Haskell.Stylish.Tests.Util- Language.Haskell.Stylish.Util- Language.Haskell.Stylish.Verbose- Paths_stylish_haskell - Autogen-modules:- Paths_stylish_haskell- Build-depends:- HUnit >= 1.2 && < 1.7,- test-framework >= 0.4 && < 0.9,- test-framework-hunit >= 0.2 && < 0.4,+ stylish-haskell,+ HUnit >= 1.2 && < 1.7, random >= 1.1,- -- Copied from regular dependencies...- aeson >= 0.6 && < 1.6,- base >= 4.8 && < 5,- bytestring >= 0.9 && < 0.11,- Cabal >= 2.4 && < 3.3,- containers >= 0.3 && < 0.7,- directory >= 1.2.3 && < 1.4,- filepath >= 1.1 && < 1.5,- file-embed >= 0.0.10 && < 0.1,- ghc-lib-parser >= 8.10 && < 8.12,- mtl >= 2.0 && < 2.3,- syb >= 0.3 && < 0.8,- text >= 1.2 && < 1.3,- HsYAML-aeson >=0.2.0 && < 0.3,- HsYAML >=0.2.0 && < 0.3+ test-framework >= 0.4 && < 0.9,+ test-framework-hunit >= 0.2 && < 0.4, Source-repository head Type: git
tests/Language/Haskell/Stylish/Config/Tests.hs view
@@ -137,7 +137,7 @@ , "license: BSD3" , "author: Angela Author" , "build-type: Simple"- , "cabal-version: >= 1.2"+ , "cabal-version: >= 1.10" , "" , "library" , " build-depends: HUnit"
tests/Language/Haskell/Stylish/Regressions.hs view
@@ -5,31 +5,30 @@ ) where import Language.Haskell.Stylish.Step.Imports-import Language.Haskell.Stylish.Tests.Util (testStep)+import Language.Haskell.Stylish.Tests.Util (assertSnippet) import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.HUnit (Assertion) tests :: Test tests = testGroup "Language.Haskell.Stylish.Regressions" [ testCase "case 00 (#198)" case00 ]+ -- | Error parsing '(,) #198 -- -- See https://github.com/haskell/stylish-haskell/issues/198 case00 :: Assertion-case00 = expected @=? testStep (step (Just 80) $ importStepConfig Global) input+case00 = assertSnippet (step (Just 80) $ importStepConfig Global) input input where- input = unlines+ input = [ "{-# LANGUAGE TemplateHaskell #-}" , "" , "import Language.Haskell.TH.Syntax" , "" , "main = print $ showName '(,)" ]-- expected = input importStepConfig :: ImportAlign -> Options importStepConfig align = defaultOptions { importAlign = align }
tests/Language/Haskell/Stylish/Step/Data/Tests.hs view
@@ -5,10 +5,10 @@ ) where import Language.Haskell.Stylish.Step.Data-import Language.Haskell.Stylish.Tests.Util (assertSnippet, testStep)+import Language.Haskell.Stylish.Tests.Util (assertSnippet) import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.HUnit (Assertion) tests :: Test tests = testGroup "Language.Haskell.Stylish.Step.Data.Tests"@@ -75,182 +75,159 @@ , testCase "case 60" case60 , testCase "case 61 (issue 282)" case61 , testCase "case 62 (issue 273)" case62+ , testCase "case 63 (issue 338)" case63+ , testCase "case 64" case64+ , testCase "case 65" case65 ] case00 :: Assertion-case00 = expected @=? testStep (step sameSameStyle) input+case00 = assertSnippet (step sameSameStyle) input input where- input = unlines- [ "module Herp where"- , ""- , "data Foo"- ]-- expected = input+ input =+ [ "module Herp where"+ , ""+ , "data Foo"+ ] case01 :: Assertion-case01 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo = Foo { a :: Int }"- ]-- expected = unlines- [ "module Herp where"- , ""- , "data Foo"- , " = Foo"- , " { a :: Int"- , " }"- ]+case01 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo = Foo { a :: Int }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo"+ , " = Foo"+ , " { a :: Int"+ , " }"+ ] case02 :: Assertion-case02 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo = Foo { a :: Int, a2 :: String }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo"- , " = Foo"- , " { a :: Int"- , " , a2 :: String"- , " }"- ]+case02 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo = Foo { a :: Int, a2 :: String }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo"+ , " = Foo"+ , " { a :: Int"+ , " , a2 :: String"+ , " }"+ ] case03 :: Assertion-case03 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a = Foo { a :: a, a2 :: String }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a"- , " = Foo"- , " { a :: a"- , " , a2 :: String"- , " }"- ]+case03 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo a = Foo { a :: a, a2 :: String }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a"+ , " = Foo"+ , " { a :: a"+ , " , a2 :: String"+ , " }"+ ] case04 :: Assertion-case04 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a = Foo { a :: a, a2 :: String } | Bar { b :: a }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a"- , " = Foo"- , " { a :: a"- , " , a2 :: String"- , " }"- , " | Bar"- , " { b :: a"- , " }"- ]+case04 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo a = Foo { a :: a, a2 :: String } | Bar { b :: a }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a"+ , " = Foo"+ , " { a :: a"+ , " , a2 :: String"+ , " }"+ , " | Bar"+ , " { b :: a"+ , " }"+ ] case05 :: Assertion-case05 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo = Foo {"- , " a :: Int"- , " , a2 :: String"- , " }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo"- , " = Foo"- , " { a :: Int"- , " , a2 :: String"- , " }"- ]+case05 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo = Foo {"+ , " a :: Int"+ , " , a2 :: String"+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo"+ , " = Foo"+ , " { a :: Int"+ , " , a2 :: String"+ , " }"+ ] case06 :: Assertion-case06 = expected @=? testStep (step sameSameStyle) input+case06 = assertSnippet (step sameSameStyle) input input where- input = unlines- [ "module Herp where"- , ""- , "data Foo = Foo Int String"- ]- expected = input+ input =+ [ "module Herp where"+ , ""+ , "data Foo = Foo Int String"+ ] case07 :: Assertion-case07 = expected @=? testStep (step sameSameStyle) input+case07 = assertSnippet (step sameSameStyle) input input where- input = unlines- [ "module Herp where"- , ""- , "data Phantom a = Phantom"- ]- expected = input+ input =+ [ "module Herp where"+ , ""+ , "data Phantom a = Phantom"+ ] case08 :: Assertion-case08 = expected @=? testStep (step sameSameStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Phantom a ="- , " Phantom"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Phantom a = Phantom"- ]+case08 = assertSnippet (step sameSameStyle)+ [ "module Herp where"+ , ""+ , "data Phantom a ="+ , " Phantom"+ ]+ [ "module Herp where"+ , ""+ , "data Phantom a = Phantom"+ ] case09 :: Assertion-case09 = expected @=? testStep (step indentIndentStyle4) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a b = Foo { a :: a, a2 :: String } | Bar { b :: a, c:: b }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a b"- , " = Foo"- , " { a :: a"- , " , a2 :: String"- , " }"- , " | Bar"- , " { b :: a"- , " , c :: b"- , " }"- ]+case09 = assertSnippet (step indentIndentStyle4)+ [ "module Herp where"+ , ""+ , "data Foo a b = Foo { a :: a, a2 :: String } | Bar { b :: a, c:: b }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a b"+ , " = Foo"+ , " { a :: a"+ , " , a2 :: String"+ , " }"+ , " | Bar"+ , " { b :: a"+ , " , c :: b"+ , " }"+ ] case10 :: Assertion-case10 = expected @=? testStep (step indentIndentStyle) input+case10 = assertSnippet (step indentIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , "" , "data Foo = Foo { a :: Int } deriving (Eq, Generic) deriving (Show)" ] - expected = unlines+ expected = [ "module Herp where" , "" , "data Foo"@@ -262,16 +239,16 @@ ] case11 :: Assertion-case11 = expected @=? testStep (step indentIndentStyle) input+case11 = assertSnippet (step indentIndentStyle) input expected where- input = unlines+ input = [ "{-# LANGUAGE DerivingStrategies #-}" , "module Herp where" , "" , "data Foo = Foo { a :: Int } deriving stock (Show)" ] - expected = unlines+ expected = [ "{-# LANGUAGE DerivingStrategies #-}" , "module Herp where" , ""@@ -283,15 +260,15 @@ ] case12 :: Assertion-case12 = expected @=? testStep (step indentIndentStyle4) input+case12 = assertSnippet (step indentIndentStyle4) input expected where- input = unlines+ input = [ "module Herp where" , "" , "data Point = Point { pointX, pointY :: Double , pointName :: String} deriving (Show)" ] - expected = unlines+ expected = [ "module Herp where" , "" , "data Point"@@ -303,15 +280,15 @@ ] case13 :: Assertion-case13 = expected @=? testStep (step indentIndentStyle) input+case13 = assertSnippet (step indentIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , "" , "-- this is a comment" , "data Foo = Foo { a :: Int }" ]- expected = unlines+ expected = [ "module Herp where" , "" , "-- this is a comment"@@ -322,16 +299,16 @@ ] case14 :: Assertion-case14 = expected @=? testStep (step indentIndentStyle) input+case14 = assertSnippet (step indentIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , "" , "{- this is" , " a comment -}" , "data Foo = Foo { a :: Int }" ]- expected = unlines+ expected = [ "module Herp where" , "" , "{- this is"@@ -343,122 +320,108 @@ ] case15 :: Assertion-case15 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a = Foo"- , " { a :: a, -- comment"- , " a2 :: String"- , " }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a"- , " = Foo"- , " { a :: a -- comment"- , " , a2 :: String"- , " }"- ]+case15 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo a = Foo"+ , " { a :: a, -- comment"+ , " a2 :: String"+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a"+ , " = Foo"+ , " { a :: a"+ , " -- comment"+ , " , a2 :: String"+ , " }"+ ] case16 :: Assertion-case16 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo = Foo {"- , " a :: Int -- ^ comment"- , " }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo"- , " = Foo"- , " { a :: Int"- , " -- ^ comment"- , " }"- ]+case16 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo = Foo {"+ , " a :: Int -- ^ comment"+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo"+ , " = Foo"+ , " { a :: Int"+ , " -- ^ comment"+ , " }"+ ] case17 :: Assertion-case17 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a = Foo"- , " { a :: a,"- , "-- comment"- , " a2 :: String"- , " }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a"- , " = Foo"- , " { a :: a"- , " -- comment"- , " , a2 :: String"- , " }"- ]+case17 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo a = Foo"+ , " { a :: a,"+ , "-- comment"+ , " a2 :: String"+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a"+ , " = Foo"+ , " { a :: a"+ , " -- comment"+ , " , a2 :: String"+ , " }"+ ] case18 :: Assertion-case18 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a = Foo"- , " { a :: a,"- , "-- ^ comment"- , " a2 :: String"- , " }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a"- , " = Foo"- , " { a :: a"- , " -- ^ comment"- , " , a2 :: String"- , " }"- ]+case18 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo a = Foo"+ , " { a :: a,"+ , "-- ^ comment"+ , " a2 :: String"+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a"+ , " = Foo"+ , " { a :: a"+ , " -- ^ comment"+ , " , a2 :: String"+ , " }"+ ] case19 :: Assertion-case19 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "module Herp where"- , ""- , "data Foo a = Foo"- , " { firstName, lastName :: String,"- , "-- ^ names"- , " age :: Int"- , " }"- ]- expected = unlines- [ "module Herp where"- , ""- , "data Foo a"- , " = Foo"- , " { firstName, lastName :: String"- , " -- ^ names"- , " , age :: Int"- , " }"- ]+case19 = assertSnippet (step indentIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo a = Foo"+ , " { firstName, lastName :: String,"+ , "-- ^ names"+ , " age :: Int"+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo a"+ , " = Foo"+ , " { firstName, lastName :: String"+ , " -- ^ names"+ , " , age :: Int"+ , " }"+ ] -- | Should not break Enums (data without records) formatting -- -- See https://github.com/haskell/stylish-haskell/issues/262 case20 :: Assertion-case20 = input @=? testStep (step indentIndentStyle) input+case20 = assertSnippet (step indentIndentStyle) input input where- input = unlines+ input = [ "module Herp where" , "" , "data Tag = Title | Text deriving (Eq, Show)"@@ -466,98 +429,94 @@ case21 :: Assertion case21 = assertSnippet (step sameSameStyle)- [ "data Foo a"- , " = Foo { a :: Int,"- , " a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar { b :: a } deriving (Eq, Show)"- , " deriving (ToJSON)"- ]- [ "data Foo a = Foo { a :: Int"- , " , a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar { b :: a"- , " }"- , " deriving (Eq, Show)"- , " deriving (ToJSON)"- ]+ [ "data Foo a"+ , " = Foo { a :: Int,"+ , " a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar { b :: a } deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ]+ [ "data Foo a = Foo { a :: Int"+ , " , a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar { b :: a"+ , " }"+ , " deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ] case22 :: Assertion case22 = assertSnippet (step sameIndentStyle)- [ "data Foo a"- , " = Foo { a :: Int,"- , " a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar { b :: a } deriving (Eq, Show)"- , " deriving (ToJSON)"- ]- [ "data Foo a = Foo"- , " { a :: Int"- , " , a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar"- , " { b :: a"- , " }"- , " deriving (Eq, Show)"- , " deriving (ToJSON)"- ]+ [ "data Foo a"+ , " = Foo { a :: Int,"+ , " a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar { b :: a } deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ]+ [ "data Foo a = Foo"+ , " { a :: Int"+ , " , a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar"+ , " { b :: a"+ , " }"+ , " deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ] case23 :: Assertion case23 = assertSnippet (step indentSameStyle)- [ "data Foo a"- , " = Foo { a :: Int,"- , " a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar { b :: a } deriving (Eq, Show)"- , " deriving (ToJSON)"- ]- [ "data Foo a"- , " = Foo { a :: Int"- , " , a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar { b :: a"- , " }"- , " deriving (Eq, Show)"- , " deriving (ToJSON)"- ]+ [ "data Foo a"+ , " = Foo { a :: Int,"+ , " a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar { b :: a } deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ]+ [ "data Foo a"+ , " = Foo { a :: Int"+ , " , a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar { b :: a"+ , " }"+ , " deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ] case24 :: Assertion-case24 = expected @=? testStep (step indentIndentStyle) input- where- input = unlines- [ "data Foo a"- , " = Foo { a :: Int,"- , " a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar { b :: a } deriving (Eq, Show)"- , " deriving (ToJSON)"- ]-- expected = unlines- [ "data Foo a"- , " = Foo"- , " { a :: Int"- , " , a2 :: String"- , " -- ^ some haddock"- , " }"- , " | Bar"- , " { b :: a"- , " }"- , " deriving (Eq, Show)"- , " deriving (ToJSON)"- ]+case24 = assertSnippet (step indentIndentStyle)+ [ "data Foo a"+ , " = Foo { a :: Int,"+ , " a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar { b :: a } deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ]+ [ "data Foo a"+ , " = Foo"+ , " { a :: Int"+ , " , a2 :: String"+ , " -- ^ some haddock"+ , " }"+ , " | Bar"+ , " { b :: a"+ , " }"+ , " deriving (Eq, Show)"+ , " deriving (ToJSON)"+ ] case25 :: Assertion-case25 = expected @=? testStep (step indentIndentStyle { cBreakSingleConstructors = False }) input+case25 = assertSnippet (step indentIndentStyle { cBreakSingleConstructors = False }) input expected where- input = unlines+ input = [ "data Foo a" , " = Foo { a :: Int," , " a2 :: String"@@ -567,7 +526,7 @@ , " deriving (ToJSON)" ] - expected = unlines+ expected = [ "data Foo a = Foo" , " { a :: Int" , " , a2 :: String"@@ -578,15 +537,15 @@ ] case26 :: Assertion-case26 = expected @=? testStep (step indentIndentStyle) input+case26 = assertSnippet (step indentIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , "" , "data Foo = Foo { a :: Int } deriving (FromJSON) via Bla Foo" ] - expected = unlines+ expected = [ "module Herp where" , "" , "data Foo"@@ -597,15 +556,15 @@ ] case27 :: Assertion-case27 = expected @=? testStep (step sameIndentStyle { cBreakEnums = True }) input+case27 = assertSnippet (step sameIndentStyle { cBreakEnums = True }) input expected where- input = unlines+ input = [ "module Herp where" , "" , "data Foo = Foo | Bar | Baz deriving (Eq, Show)" ] - expected = unlines+ expected = [ "module Herp where" , "" , "data Foo"@@ -616,9 +575,9 @@ ] case28 :: Assertion-case28 = expected @=? testStep (step sameIndentStyle { cBreakEnums = True }) input+case28 = assertSnippet (step sameIndentStyle { cBreakEnums = True }) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "newtype BankCode = BankCode {"@@ -644,7 +603,7 @@ , " deriving (ToJSON, FromJSON) via SnakeCaseCapsEnumEncoding MandateStatus" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "newtype BankCode = BankCode { unBankCode :: Text }"@@ -669,26 +628,26 @@ ] case29 :: Assertion-case29 = expected @=? testStep (step sameIndentStyle) input+case29 = assertSnippet (step sameIndentStyle) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "data NonEmpty a" , " = a :| [a]" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "data NonEmpty a = a :| [a]" ] case30 :: Assertion-case30 = expected @=? testStep (step sameIndentStyle { cBreakEnums = True }) input+case30 = assertSnippet (step sameIndentStyle { cBreakEnums = True }) input expected where expected = input- input = unlines+ input = [ "data ReasonCode" , " = MissingTenantId" , " -- Transaction errors:"@@ -709,10 +668,10 @@ case31 :: Assertion-case31 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True }) input+case31 = assertSnippet (step indentIndentStyle { cBreakEnums = True }) input expected where expected = input- input = unlines+ input = [ "data ConfiguredLogger" , " -- | Logs to file" , " = LogTo FilePath"@@ -724,10 +683,10 @@ ] case32 :: Assertion-case32 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True }) input+case32 = assertSnippet (step indentIndentStyle { cBreakEnums = True }) input expected where expected = input- input = unlines+ input = [ "data RejectionReason" , " -- InvalidState" , " = CancellationFailed"@@ -742,15 +701,15 @@ ] case33 :: Assertion-case33 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input+case33 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "newtype NonEmpty a = NonEmpty { unNonEmpty :: a }" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "newtype NonEmpty a"@@ -758,16 +717,16 @@ ] case34 :: Assertion-case34 = expected @=? testStep (step indentIndentStyle { cVia = Indent 2 }) input+case34 = assertSnippet (step indentIndentStyle { cVia = Indent 2 }) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "newtype NonEmpty a = NonEmpty { unNonEmpty :: a }" , " deriving (ToJSON, FromJSON) via Something Magic (NonEmpty a)" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "newtype NonEmpty a"@@ -777,9 +736,9 @@ ] case35 :: Assertion-case35 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input+case35 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "data Foo = Foo"@@ -789,7 +748,7 @@ , " }" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "data Foo = Foo"@@ -798,9 +757,9 @@ ] case36 :: Assertion-case36 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input+case36 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "data Foo = Foo"@@ -810,7 +769,7 @@ , " }" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "data Foo = Foo"@@ -819,9 +778,9 @@ ] case37 :: Assertion-case37 = expected @=? testStep (step indentIndentStyle { cVia = Indent 2 }) input+case37 = assertSnippet (step indentIndentStyle { cVia = Indent 2 }) input expected where- input = unlines+ input = [ "module Some.Types where" , "" , "newtype UndoFlowData"@@ -833,7 +792,7 @@ , " \"reversal_indicator\" := \"Undo\"] FlowDataDetails" ] - expected = unlines+ expected = [ "module Some.Types where" , "" , "newtype UndoFlowData"@@ -844,9 +803,9 @@ ] case38 :: Assertion-case38 = expected @=? testStep (step indentIndentStyle { cVia = Indent 2 }) input+case38 = assertSnippet (step indentIndentStyle { cVia = Indent 2 }) input expected where- input = unlines+ input = [ "data Flat = Flat" , " { foo :: Int" , " , bar :: Text"@@ -865,7 +824,7 @@ , " Flat" ] - expected = unlines+ expected = [ "data Flat" , " = Flat" , " { foo :: Int"@@ -879,9 +838,9 @@ ] case39 :: Assertion-case39 = expected @=? testStep (step indentIndentStyle { cVia = Indent 2 }) input+case39 = assertSnippet (step indentIndentStyle { cVia = Indent 2 }) input expected where- input = unlines+ input = [ "data CreditTransfer = CreditTransfer" , " { nestedCreditorInfo :: CreditorInfo" , " }"@@ -902,7 +861,7 @@ , " )" ] - expected = unlines+ expected = [ "data CreditTransfer" , " = CreditTransfer" , " { nestedCreditorInfo :: CreditorInfo"@@ -913,27 +872,27 @@ ] case40 :: Assertion-case40 = expected @=? testStep (step indentIndentStyle { cBreakSingleConstructors = False }) input+case40 = assertSnippet (step indentIndentStyle { cBreakSingleConstructors = False }) input expected where- input = unlines+ input = [ "module X where" , "" , "data a :==> b =" , " Arr a b" ] - expected = unlines+ expected = [ "module X where" , "" , "data a :==> b = Arr a b" ] case41 :: Assertion-case41 = expected @=? testStep (step indentIndentStyle) input+case41 = assertSnippet (step indentIndentStyle) input expected where input = expected - expected = unlines+ expected = [ "module X where" , "" , "data Callback"@@ -956,11 +915,11 @@ ] case42 :: Assertion-case42 = expected @=? testStep (step indentIndentStyle) input+case42 = assertSnippet (step indentIndentStyle) input expected where input = expected - expected = unlines+ expected = [ "module X where" , "" , "data SignupError"@@ -970,11 +929,11 @@ ] case43 :: Assertion-case43 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input+case43 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False }) input expected where input = expected - expected = unlines+ expected = [ "module X where" , "" , "data CallbackResult"@@ -993,9 +952,9 @@ -- This means that we've needed to make the decision to put all inline comments -- before the deriving clause itself case44 :: Assertion-case44 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False, cVia = Indent 2 }) input+case44 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False, cVia = Indent 2 }) input expected where- input = unlines+ input = [ "module X where" , "" , " data CreditTransfer = CreditTransfer"@@ -1012,7 +971,7 @@ , " ]" , " (UntaggedEncoded CreditTransfer)" ]- expected = unlines+ expected = [ "module X where" , "" , "data CreditTransfer = CreditTransfer"@@ -1029,10 +988,10 @@ ] case45 :: Assertion-case45 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False, cVia = Indent 2 }) input+case45 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False, cVia = Indent 2 }) input expected where input = expected- expected = unlines+ expected = [ "module X where" , "" , "data CreditTransfer = CreditTransfer"@@ -1049,10 +1008,10 @@ ] case46 :: Assertion-case46 = expected @=? testStep (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False, cVia = Indent 2 }) input+case46 = assertSnippet (step indentIndentStyle { cBreakEnums = True, cBreakSingleConstructors = False, cVia = Indent 2 }) input expected where input = expected- expected = unlines+ expected = [ "module X where" , "" , "-- | A format detailing which encoding to use for the settlement events"@@ -1067,10 +1026,10 @@ ] case47 :: Assertion-case47 = expected @=? testStep (step indentIndentStyle) input+case47 = assertSnippet (step indentIndentStyle) input expected where input = expected- expected = unlines+ expected = [ "module X where" , "" , "-- | A GADT example"@@ -1081,10 +1040,10 @@ ] case48 :: Assertion-case48 = expected @=? testStep (step indentIndentStyle) input+case48 = assertSnippet (step indentIndentStyle) input expected where input = expected- expected = unlines+ expected = [ "module X where" , "" , "-- | A GADT example"@@ -1095,10 +1054,10 @@ ] case49 :: Assertion-case49 = expected @=? testStep (step indentIndentStyle) input+case49 = assertSnippet (step indentIndentStyle) input expected where input = expected- expected = unlines+ expected = [ "module X where" , "" , "-- | A GADT example"@@ -1109,10 +1068,10 @@ ] case50 :: Assertion-case50 = expected @=? testStep (step indentIndentStyle { cCurriedContext = True }) input+case50 = assertSnippet (step indentIndentStyle { cCurriedContext = True }) input expected where input = expected- expected = unlines+ expected = [ "module X where" , "" , "-- | A GADT example"@@ -1123,9 +1082,9 @@ ] case51 :: Assertion-case51 = expected @=? testStep (step indentIndentStyle { cCurriedContext = True }) input+case51 = assertSnippet (step indentIndentStyle { cCurriedContext = True }) input expected where- input = unlines+ input = [ "module X where" , "" , "-- | A GADT example"@@ -1134,7 +1093,7 @@ , " D2 :: T Bool" , " D3 :: forall a. (Eq a) => (a, a) -> T [a]" ]- expected = unlines+ expected = [ "module X where" , "" , "-- | A GADT example"@@ -1145,16 +1104,16 @@ ] case52 :: Assertion-case52 = expected @=? testStep (step indentIndentStyle { cBreakSingleConstructors = False, cCurriedContext = True }) input+case52 = assertSnippet (step indentIndentStyle { cBreakSingleConstructors = False, cCurriedContext = True }) input expected where- input = unlines+ input = [ "module X where" , "" , "data Foo = Foo" , " { foo :: forall a b. (Eq a, Bounded b) => a -> b -> [(a, b)]" , " }" ]- expected = unlines+ expected = [ "module X where" , "" , "data Foo = Foo"@@ -1163,14 +1122,14 @@ ] case53 :: Assertion-case53 = expected @=? testStep (step indentIndentStyle { cMaxColumns = MaxColumns 80 }) input+case53 = assertSnippet (step indentIndentStyle { cMaxColumns = MaxColumns 80 }) input expected where- input = unlines+ input = [ "newtype Foo m a" , " = Foo (m a)" , " deriving newtype (Functor, Applicative, Monad, MonadError, MonadCatch, Foldable, Monoid)" ]- expected = unlines+ expected = [ "newtype Foo m a" , " = Foo (m a)" , " deriving newtype"@@ -1185,23 +1144,23 @@ ] case54 :: Assertion-case54 = expected @=? testStep (step indentIndentStyle { cMaxColumns = MaxColumns 80 }) input+case54 = assertSnippet (step indentIndentStyle { cMaxColumns = MaxColumns 80 }) input expected where- input = unlines+ input = [ "newtype Foo m a" , " = Foo (m a)" , " deriving newtype (Functor, Applicative, Monad)" ]- expected = unlines+ expected = [ "newtype Foo m a" , " = Foo (m a)" , " deriving newtype (Applicative, Functor, Monad)" ] case55 :: Assertion-case55 = expected @=? testStep (step sameSameNoSortStyle) input+case55 = assertSnippet (step sameSameNoSortStyle) input expected where- input = unlines+ input = [ "data Foo = Foo deriving (Z, Y, X, Bar, Abcd)" ] @@ -1283,9 +1242,9 @@ -- -- See https://github.com/haskell/stylish-haskell/issues/330 case58 :: Assertion-case58 = expected @=? testStep (step sameIndentStyle) input+case58 = assertSnippet (step sameIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , "" , "data Foo a = Foo"@@ -1315,9 +1274,9 @@ -- -- Regression test for https://github.com/haskell/stylish-haskell/issues/282 case61 :: Assertion-case61 = expected @=? testStep (step sameIndentStyle) input+case61 = assertSnippet (step sameIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , "" , "data Game = Game { _board :: Board -- ^ Board state"@@ -1328,7 +1287,7 @@ , " }" ] - expected = unlines+ expected = [ "module Herp where" , "" , "data Game = Game"@@ -1349,33 +1308,64 @@ -- -- Regression test for https://github.com/haskell/stylish-haskell/issues/273 case62 :: Assertion-case62 = expected @=? testStep (step sameIndentStyle) input+case62 = assertSnippet (step sameIndentStyle)+ [ "module Herp where"+ , ""+ , "data Foo = Foo"+ , " { -- | This is a comment above some line."+ , " -- It can span multiple lines."+ , " fooName :: String"+ , " , fooAge :: Int"+ , " -- ^ This is a comment below some line."+ , " -- It can span multiple lines."+ , " }"+ ]+ [ "module Herp where"+ , ""+ , "data Foo = Foo"+ , " { -- | This is a comment above some line."+ , " -- It can span multiple lines."+ , " fooName :: String"+ , " , fooAge :: Int"+ , " -- ^ This is a comment below some line."+ , " -- It can span multiple lines."+ , " }"+ ]++case63 :: Assertion+case63 = assertSnippet (step indentIndentStyle) input expected where- input = unlines+ input = [ "module Herp where" , ""- , "data Foo = Foo"- , " { -- | This is a comment above some line."- , " -- It can span multiple lines."- , " fooName :: String"- , " , fooAge :: Int"- , " -- ^ This is a comment below some line."- , " -- It can span multiple lines."- , " }"+ , "data Foo :: * -> * where"+ , " Bar :: () -> Foo ()" ]+ expected = input - expected = unlines- [ "module Herp where"- , ""- , "data Foo = Foo"- , " { -- | This is a comment above some line."- , " -- It can span multiple lines."- , " fooName :: String"- , " , fooAge :: Int"- , " -- ^ This is a comment below some line."- , " -- It can span multiple lines."- , " }"- ]+case64 :: Assertion+case64 = assertSnippet (step indentIndentStyle) input input+ where+ input =+ [ "data Foo"+ , " = Bar Int"+ , " -- ^ Following comment"+ , " | Qux Int"+ , " -- ^ Second following comment"+ , " deriving (Show)"+ ]++case65 :: Assertion+case65 = assertSnippet (step indentIndentStyle) input input+ where+ input =+ [ "data Foo"+ , " = Bar"+ , " -- ^ Following comment"+ , " | Qux"+ , " -- ^ Second following comment"+ , " deriving (Show)"+ ] sameSameStyle :: Config sameSameStyle = Config SameLine SameLine 2 2 False True SameLine False True NoMaxColumns
tests/Language/Haskell/Stylish/Step/Imports/FelixTests.hs view
@@ -1,383 +1,321 @@+-------------------------------------------------------------------------------- -- | Tests contributed by Felix Mulder as part of -- <https://github.com/haskell/stylish-haskell/pull/293>.+{-# LANGUAGE OverloadedLists #-} module Language.Haskell.Stylish.Step.Imports.FelixTests ( tests ) where + ---------------------------------------------------------------------------------import GHC.Stack (HasCallStack,- withFrozenCallStack) import Prelude hiding (lines) import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase) import Test.HUnit (Assertion) + ---------------------------------------------------------------------------------import Language.Haskell.Stylish.Module import Language.Haskell.Stylish.Step.Imports-import Language.Haskell.Stylish.Tests.Util (testStep', (@=??))-+import Language.Haskell.Stylish.Tests.Util (assertSnippet) -------------------------------------------------------------------------------- tests :: Test-tests = testGroup "Language.Haskell.Stylish.Step.ImportsGHC"- [ testCase "Hello world" ex0- , testCase "Sorted simple" ex1- , testCase "Sorted import lists" ex2- , testCase "Sorted import lists and import decls" ex3- , testCase "Import constructor all" ex4- , testCase "Import constructor specific" ex5- , testCase "Import constructor specific sorted" ex6- , testCase "Imports step does not change rest of file" ex7- , testCase "Imports respect groups" ex8- , testCase "Imports respects whitespace between groups" ex9- , testCase "Doesn't add extra space after 'hiding'" ex10- , testCase "Should be able to format symbolic imports" ex11- , testCase "Able to merge equivalent imports" ex12- , testCase "Obeys max columns setting" ex13- , testCase "Obeys max columns setting with two in each" ex14- , testCase "Respects multiple groups" ex15- , testCase "Doesn't delete nullary imports" ex16- ]+tests = testGroup "Language.Haskell.Stylish.Step.Imports.FelixTests"+ [ testCase "Hello world" ex0+ , testCase "Sorted simple" ex1+ , testCase "Sorted import lists" ex2+ , testCase "Sorted import lists and import decls" ex3+ , testCase "Import constructor all" ex4+ , testCase "Import constructor specific" ex5+ , testCase "Import constructor specific sorted" ex6+ , testCase "Imports step does not change rest of file" ex7+ , testCase "Imports respect groups" ex8+ , testCase "Imports respects whitespace between groups" ex9+ , testCase "Doesn't add extra space after 'hiding'" ex10+ , testCase "Should be able to format symbolic imports" ex11+ , testCase "Able to merge equivalent imports" ex12+ , testCase "Obeys max columns setting" ex13+ , testCase "Obeys max columns setting with two in each" ex14+ , testCase "Respects multiple groups" ex15+ , testCase "Doesn't delete nullary imports" ex16+ ] + -------------------------------------------------------------------------------- ex0 :: Assertion-ex0 = input `assertFormatted` output- where- input =- [ "import B"- , "import A"- ]- output =- [ "import A"- , "import B"- ]+ex0 = assertSnippet (step Nothing felixOptions)+ [ "import B"+ , "import A"+ ]+ [ "import A"+ , "import B"+ ] ex1 :: Assertion-ex1 = input `assertFormatted` output- where- input =- [ "import B"- , "import A"- , "import C"- , "import qualified A"- , "import qualified B as X"- ]- output =- [ "import A"- , "import qualified A"- , "import B"- , "import qualified B as X"- , "import C"- ]+ex1 = assertSnippet (step Nothing felixOptions)+ [ "import B"+ , "import A"+ , "import C"+ , "import qualified A"+ , "import qualified B as X"+ ]+ [ "import A"+ , "import qualified A"+ , "import B"+ , "import qualified B as X"+ , "import C"+ ] ex2 :: Assertion-ex2 = input `assertFormatted` output- where- input =- [ "import B"- , "import A (X)"- , "import C"- , "import qualified A as Y (Y)"- ]- output =- [ "import A (X)"- , "import qualified A as Y (Y)"- , "import B"- , "import C"- ]+ex2 = assertSnippet (step Nothing felixOptions)+ [ "import B"+ , "import A (X)"+ , "import C"+ , "import qualified A as Y (Y)"+ ]+ [ "import A (X)"+ , "import qualified A as Y (Y)"+ , "import B"+ , "import C"+ ] ex3 :: Assertion-ex3 = input `assertFormatted` output- where- input =- [ "import B"- , "import A (X, Z, Y)"- , "import C"- , "import qualified A as A0 (b, Y, a)"- , "import qualified D as D0 (Y, b, a)"- , "import qualified E as E0 (b, a, Y)"- ]- output =- [ "import A (X, Y, Z)"- , "import qualified A as A0 (Y, a, b)"- , "import B"- , "import C"- , "import qualified D as D0 (Y, a, b)"- , "import qualified E as E0 (Y, a, b)"- ]+ex3 = assertSnippet (step Nothing felixOptions)+ [ "import B"+ , "import A (X, Z, Y)"+ , "import C"+ , "import qualified A as A0 (b, Y, a)"+ , "import qualified D as D0 (Y, b, a)"+ , "import qualified E as E0 (b, a, Y)"+ ]+ [ "import A (X, Y, Z)"+ , "import qualified A as A0 (Y, a, b)"+ , "import B"+ , "import C"+ , "import qualified D as D0 (Y, a, b)"+ , "import qualified E as E0 (Y, a, b)"+ ] ex4 :: Assertion-ex4 = input `assertFormatted` output- where- input =- [ "import A (X, Z(..), Y)"- ]- output =- [ "import A (X, Y, Z (..))"- ]+ex4 = assertSnippet (step Nothing felixOptions)+ [ "import A (X, Z(..), Y)"+ ]+ [ "import A (X, Y, Z (..))"+ ] ex5 :: Assertion-ex5 = input `assertFormatted` output- where- input =- [ "import A (X, Z(Z), Y)"- ]- output =- [ "import A (X, Y, Z (Z))"- ]+ex5 = assertSnippet (step Nothing felixOptions)+ [ "import A (X, Z(Z), Y)"+ ]+ [ "import A (X, Y, Z (Z))"+ ] ex6 :: Assertion-ex6 = input `assertFormatted` output- where- input =- [ "import A (X, Z(X, Z, Y), Y)"- ]- output =- [ "import A (X, Y, Z (X, Y, Z))"- ]+ex6 = assertSnippet (step Nothing felixOptions)+ [ "import A (X, Z(X, Z, Y), Y)"+ ]+ [ "import A (X, Y, Z (X, Y, Z))"+ ] ex7 :: Assertion-ex7 = input `assertFormatted` output- where- input =- [ "module Foo (tests) where"- , "import B"- , "import A (X, Z, Y)"- , "import C"- , "import qualified A as A0 (b, Y, a)"- , "import qualified D as D0 (Y, b, a)"- , "import qualified E as E0 (b, a, Y)"- , "-- hello"- , "foo :: Int"- , "foo = 1"- ]- output =- [ "module Foo (tests) where"- , "import A (X, Y, Z)"- , "import qualified A as A0 (Y, a, b)"- , "import B"- , "import C"- , "import qualified D as D0 (Y, a, b)"- , "import qualified E as E0 (Y, a, b)"- , "-- hello"- , "foo :: Int"- , "foo = 1"- ]+ex7 = assertSnippet (step Nothing felixOptions)+ [ "module Foo (tests) where"+ , "import B"+ , "import A (X, Z, Y)"+ , "import C"+ , "import qualified A as A0 (b, Y, a)"+ , "import qualified D as D0 (Y, b, a)"+ , "import qualified E as E0 (b, a, Y)"+ , "-- hello"+ , "foo :: Int"+ , "foo = 1"+ ]+ [ "module Foo (tests) where"+ , "import A (X, Y, Z)"+ , "import qualified A as A0 (Y, a, b)"+ , "import B"+ , "import C"+ , "import qualified D as D0 (Y, a, b)"+ , "import qualified E as E0 (Y, a, b)"+ , "-- hello"+ , "foo :: Int"+ , "foo = 1"+ ] ex8 :: Assertion-ex8 = input `assertFormatted` output- where- input =- [ "import B"- , "-- Group divisor"- , "import A (X)"- , "import C"- , "import qualified A as Y (Y)"- ]- output =- [ "import B"- , "-- Group divisor"- , "import A (X)"- , "import qualified A as Y (Y)"- , "import C"- ]+ex8 = assertSnippet (step Nothing felixOptions)+ [ "import B"+ , "-- Group divisor"+ , "import A (X)"+ , "import C"+ , "import qualified A as Y (Y)"+ ]+ [ "import B"+ , "-- Group divisor"+ , "import A (X)"+ , "import qualified A as Y (Y)"+ , "import C"+ ] ex9 :: Assertion-ex9 = input `assertFormatted` output- where- input =- [ "--------"- , "import B"- , ""- , "-- Group divisor"- , "import A (X)"- , "import C"- , "import qualified A as Y (Y)"- ]- output =- [ "--------"- , "import B"- , ""- , "-- Group divisor"- , "import A (X)"- , "import qualified A as Y (Y)"- , "import C"- ]+ex9 = assertSnippet (step Nothing felixOptions)+ [ "--------"+ , "import B"+ , ""+ , "-- Group divisor"+ , "import A (X)"+ , "import C"+ , "import qualified A as Y (Y)"+ ]+ [ "--------"+ , "import B"+ , ""+ , "-- Group divisor"+ , "import A (X)"+ , "import qualified A as Y (Y)"+ , "import C"+ ] ex10 :: Assertion-ex10 = input `assertFormatted` output- where- input =- [ "import B hiding (X)"- , "import A hiding (X)"- ]- output =- [ "import A hiding (X)"- , "import B hiding (X)"- ]+ex10 = assertSnippet (step Nothing felixOptions)+ [ "import B hiding (X)"+ , "import A hiding (X)"+ ]+ [ "import A hiding (X)"+ , "import B hiding (X)"+ ] ex11 :: Assertion-ex11 = input `assertFormatted` output- where- input =- [ "import Data.Aeson ((.=))"- , "import A hiding (X)"- ]- output =- [ "import A hiding (X)"- , "import Data.Aeson ((.=))"- ]+ex11 = assertSnippet (step Nothing felixOptions)+ [ "import Data.Aeson ((.=))"+ , "import A hiding (X)"+ ]+ [ "import A hiding (X)"+ , "import Data.Aeson ((.=))"+ ] ex12 :: Assertion-ex12 = input `assertFormatted` output- where- input =- [ "import Data.Aeson ((.=))"- , "import Data.Aeson ((.=))"- , "import A hiding (X)"- ]- output =- [ "import A hiding (X)"- , "import Data.Aeson ((.=))"- ]+ex12 = assertSnippet (step Nothing felixOptions)+ [ "import Data.Aeson ((.=))"+ , "import Data.Aeson ((.=))"+ , "import A hiding (X)"+ ]+ [ "import A hiding (X)"+ , "import Data.Aeson ((.=))"+ ] ex13 :: Assertion-ex13 = input `assertFormattedCols` output- where- assertFormattedCols =- assertFormatted' (Just 10)- input =- [ "import Foo (A, B, C, D)"- , "import A hiding (X)"- ]- output =- [ "import A hiding (X)"- , "import Foo (A)"- , "import Foo (B)"- , "import Foo (C)"- , "import Foo (D)"- ]+ex13 = assertSnippet (step (Just 10) felixOptions)+ [ "import Foo (A, B, C, D)"+ , "import A hiding (X)"+ ]+ [ "import A hiding (X)"+ , "import Foo (A)"+ , "import Foo (B)"+ , "import Foo (C)"+ , "import Foo (D)"+ ] ex14 :: Assertion-ex14 = input `assertFormattedCols` output- where- assertFormattedCols =- assertFormatted' (Just 27)- input =- [ "import Foo (A, B, C, D)"- , "import A hiding (X)"- ]- output =- [ "import A hiding (X)"- , "import Foo (A, B)"- , "import Foo (C, D)"- ]+ex14 = assertSnippet (step (Just 27) felixOptions)+ [ "import Foo (A, B, C, D)"+ , "import A hiding (X)"+ ]+ [ "import A hiding (X)"+ , "import Foo (A, B)"+ , "import Foo (C, D)"+ ] ex15 :: Assertion-ex15 = input `assertFormattedCols` output- where- assertFormattedCols =- assertFormatted' (Just 100)- input =- [ "module Custom.Prelude"- , " ( LazyByteString"- , " , UUID"- , " , decodeUtf8Lenient"- , " , error"- , " , headMay"- , " , module X"- , " , nextRandomUUID"- , " , onChars"- , " , proxyOf"- , " , show"- , " , showStr"- , " , toLazyByteString"- , " , toStrictByteString"- , " , type (~>)"- , " , uuidToText"- , " ) where"- , ""- , "--------------------------------------------------------------------------------"- , "import Prelude as X hiding ((!!), appendFile, error, foldl, head, putStrLn, readFile, show, tail, take, unlines, unwords, words, writeFile)"- , "import qualified Prelude"- , ""- , "--------------------------------------------------------------------------------"- , "import Control.Lens as X ((%~), (&), (.~), (?~), (^.), (^?), _Left, _Right, iat, over, preview, sans, set, to, view)"- , "import Control.Lens.Extras as X (is)"- , ""- , "--------------------------------------------------------------------------------"- , "import Control.Applicative as X ((<|>))"- , "import Control.Monad as X ((<=<), (>=>), guard, unless, when)"- , "import Control.Monad.Except as X (ExceptT (..), MonadError (..), liftEither, runExceptT, withExceptT)"- , "import Control.Monad.IO.Unlift as X"- , "import Control.Monad.Reader as X (MonadReader (..), ReaderT (..), asks)"- , "import Control.Monad.Trans.Class as X (MonadTrans (lift))"- , "--------------------------------------------------------------------------------"- ]- output =- [ "module Custom.Prelude"- , " ( LazyByteString"- , " , UUID"- , " , decodeUtf8Lenient"- , " , error"- , " , headMay"- , " , module X"- , " , nextRandomUUID"- , " , onChars"- , " , proxyOf"- , " , show"- , " , showStr"- , " , toLazyByteString"- , " , toStrictByteString"- , " , type (~>)"- , " , uuidToText"- , " ) where"- , ""- , "--------------------------------------------------------------------------------"- , "import Prelude as X hiding (appendFile, error, foldl, head, putStrLn, readFile, show, tail, take, unlines, unwords, words, writeFile, (!!))"- , "import qualified Prelude"- , ""- , "--------------------------------------------------------------------------------"- , "import Control.Lens as X (_Left, _Right, iat, over, preview, sans, set, to)"- , "import Control.Lens as X (view, (%~), (&), (.~), (?~), (^.), (^?))"- , "import Control.Lens.Extras as X (is)"- , ""- , "--------------------------------------------------------------------------------"- , "import Control.Applicative as X ((<|>))"- , "import Control.Monad as X (guard, unless, when, (<=<), (>=>))"- , "import Control.Monad.Except as X (ExceptT (..), MonadError (..), liftEither)"- , "import Control.Monad.Except as X (runExceptT, withExceptT)"- , "import Control.Monad.IO.Unlift as X"- , "import Control.Monad.Reader as X (MonadReader (..), ReaderT (..), asks)"- , "import Control.Monad.Trans.Class as X (MonadTrans (lift))"- , "--------------------------------------------------------------------------------"- ]+ex15 = assertSnippet (step (Just 100) felixOptions)+ [ "module Custom.Prelude"+ , " ( LazyByteString"+ , " , UUID"+ , " , decodeUtf8Lenient"+ , " , error"+ , " , headMay"+ , " , module X"+ , " , nextRandomUUID"+ , " , onChars"+ , " , proxyOf"+ , " , show"+ , " , showStr"+ , " , toLazyByteString"+ , " , toStrictByteString"+ , " , type (~>)"+ , " , uuidToText"+ , " ) where"+ , ""+ , "--------------------------------------------------------------------------------"+ , "import Prelude as X hiding ((!!), appendFile, error, foldl, head, putStrLn, readFile, show, tail, take, unlines, unwords, words, writeFile)"+ , "import qualified Prelude"+ , ""+ , "--------------------------------------------------------------------------------"+ , "import Control.Lens as X ((%~), (&), (.~), (?~), (^.), (^?), _Left, _Right, iat, over, preview, sans, set, to, view)"+ , "import Control.Lens.Extras as X (is)"+ , ""+ , "--------------------------------------------------------------------------------"+ , "import Control.Applicative as X ((<|>))"+ , "import Control.Monad as X ((<=<), (>=>), guard, unless, when)"+ , "import Control.Monad.Except as X (ExceptT (..), MonadError (..), liftEither, runExceptT, withExceptT)"+ , "import Control.Monad.IO.Unlift as X"+ , "import Control.Monad.Reader as X (MonadReader (..), ReaderT (..), asks)"+ , "import Control.Monad.Trans.Class as X (MonadTrans (lift))"+ , "--------------------------------------------------------------------------------"+ ]+ [ "module Custom.Prelude"+ , " ( LazyByteString"+ , " , UUID"+ , " , decodeUtf8Lenient"+ , " , error"+ , " , headMay"+ , " , module X"+ , " , nextRandomUUID"+ , " , onChars"+ , " , proxyOf"+ , " , show"+ , " , showStr"+ , " , toLazyByteString"+ , " , toStrictByteString"+ , " , type (~>)"+ , " , uuidToText"+ , " ) where"+ , ""+ , "--------------------------------------------------------------------------------"+ , "import Prelude as X hiding (appendFile, error, foldl, head, putStrLn, readFile, show, tail, take, unlines, unwords, words, writeFile, (!!))"+ , "import qualified Prelude"+ , ""+ , "--------------------------------------------------------------------------------"+ , "import Control.Lens as X (_Left, _Right, iat, over, preview, sans, set, to)"+ , "import Control.Lens as X (view, (%~), (&), (.~), (?~), (^.), (^?))"+ , "import Control.Lens.Extras as X (is)"+ , ""+ , "--------------------------------------------------------------------------------"+ , "import Control.Applicative as X ((<|>))"+ , "import Control.Monad as X (guard, unless, when, (<=<), (>=>))"+ , "import Control.Monad.Except as X (ExceptT (..), MonadError (..), liftEither)"+ , "import Control.Monad.Except as X (runExceptT, withExceptT)"+ , "import Control.Monad.IO.Unlift as X"+ , "import Control.Monad.Reader as X (MonadReader (..), ReaderT (..), asks)"+ , "import Control.Monad.Trans.Class as X (MonadTrans (lift))"+ , "--------------------------------------------------------------------------------"+ ] ex16 :: Assertion-ex16 = input `assertFormatted` output- where- input =- [ "module Foo where"- , ""- , "import B ()"- , "import A ()"- ]- output =- [ "module Foo where"- , ""- , "import A ()"- , "import B ()"- ]--assertFormatted :: HasCallStack => Lines -> Lines -> Assertion-assertFormatted = withFrozenCallStack $ assertFormatted' Nothing+ex16 = assertSnippet (step Nothing felixOptions)+ [ "module Foo where"+ , ""+ , "import B ()"+ , "import A ()"+ ]+ [ "module Foo where"+ , ""+ , "import A ()"+ , "import B ()"+ ] -assertFormatted' :: HasCallStack => Maybe Int -> Lines -> Lines -> Assertion-assertFormatted' maxColumns input expected =- withFrozenCallStack $ expected @=?? testStep' (step maxColumns felixOptions) input- where- felixOptions = defaultOptions- { listAlign = Repeat- }+felixOptions :: Options+felixOptions = defaultOptions+ { listAlign = Repeat+ }
tests/Language/Haskell/Stylish/Step/Imports/Tests.hs view
@@ -8,7 +8,7 @@ -------------------------------------------------------------------------------- import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.HUnit (Assertion) --------------------------------------------------------------------------------@@ -69,6 +69,7 @@ , testCase "case 35" case35 , testCase "case 36" case36 , testCase "case 37" case37+ , testCase "case 38" case38 ] @@ -600,21 +601,17 @@ -------------------------------------------------------------------------------- case20 :: Assertion-case20 = expected- @=? testSnippet (step (Just 80) defaultOptions) input'- where- expected = Snippet- [ "import {-# SOURCE #-} Data.ByteString as BS"- , "import qualified Data.Map as Map"- , "import Data.Set (empty)"- , "import {-# SOURCE #-} qualified Data.Text as T"- ]- input' = Snippet- [ "import {-# SOURCE #-} Data.ByteString as BS"- , "import {-# SOURCE #-} qualified Data.Text as T"- , "import qualified Data.Map as Map"- , "import Data.Set (empty)"- ]+case20 = assertSnippet (step (Just 80) defaultOptions)+ [ "import {-# SOURCE #-} Data.ByteString as BS"+ , "import {-# SOURCE #-} qualified Data.Text as T"+ , "import qualified Data.Map as Map"+ , "import Data.Set (empty)"+ ]+ [ "import {-# SOURCE #-} Data.ByteString as BS"+ , "import qualified Data.Map as Map"+ , "import Data.Set (empty)"+ , "import {-# SOURCE #-} qualified Data.Text as T"+ ] --------------------------------------------------------------------------------@@ -922,4 +919,14 @@ , "import Data.Aeson qualified as JSON (encode, decode)" ] [ "import Data.Aeson qualified as JSON (Value, decode, encode)"+ ]++--------------------------------------------------------------------------------+case38 :: Assertion+case38 = assertSnippet (step (Just 80) $ fromImportAlign File)+ [ "import HSP"+ , "import Happstack.Server"+ ]+ [ "import Happstack.Server"+ , "import HSP" ]
tests/Language/Haskell/Stylish/Step/LanguagePragmas/Tests.hs view
@@ -8,7 +8,7 @@ -------------------------------------------------------------------------------- import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.HUnit (Assertion) --------------------------------------------------------------------------------@@ -231,22 +231,18 @@ -------------------------------------------------------------------------------- case14 :: Assertion-case14 = expected @=? testStep (step Nothing VerticalCompact False False "language") input- where- input = unlines- [ "{-# LANGUAGE ViewPatterns, OverloadedStrings #-}"- , "{-# LANGUAGE TemplateHaskell, ViewPatterns #-}"- , "{-# LANGUAGE ScopedTypeVariables, NoImplicitPrelude #-}"- , "module Main where"- ]-- expected = unlines- [ "{-# language"- , " NoImplicitPrelude"- , " , OverloadedStrings"- , " , ScopedTypeVariables"- , " , TemplateHaskell"- , " , ViewPatterns"- , " #-}"- , "module Main where"- ]+case14 = assertSnippet (step Nothing VerticalCompact False False "language")+ [ "{-# LANGUAGE ViewPatterns, OverloadedStrings #-}"+ , "{-# LANGUAGE TemplateHaskell, ViewPatterns #-}"+ , "{-# LANGUAGE ScopedTypeVariables, NoImplicitPrelude #-}"+ , "module Main where"+ ]+ [ "{-# language"+ , " NoImplicitPrelude"+ , " , OverloadedStrings"+ , " , ScopedTypeVariables"+ , " , TemplateHaskell"+ , " , ViewPatterns"+ , " #-}"+ , "module Main where"+ ]
tests/Language/Haskell/Stylish/Step/ModuleHeader/Tests.hs view
@@ -79,6 +79,8 @@ , testCase "Single two exports, open_bracket = same_line" ex30a , testCase "Single one export with comment" ex31 , testCase "Single one export with comment, open_bracket = same_line" ex31a+ , testCase "Single one module comment" ex32+ , testCase "Inline comments" ex33 ] --------------------------------------------------------------------------------@@ -882,6 +884,30 @@ [ "module Foo (" , " -- * Foo" , " Foo"+ , " ) where"+ ]++ex32 :: Assertion+ex32 = assertSnippet (step Nothing $ defaultConfig {breakWhere = Single})+ [ "module Foo (bar) where -- Foo"+ ]+ [ "module Foo (bar) where -- Foo"+ ]++ex33 :: Assertion+ex33 = assertSnippet (step Nothing $ defaultConfig)+ [ "module Foo ("+ , " -- Bar"+ , " bar, -- Inline bar"+ , " -- Foo"+ , " foo -- Inline foo"+ , ") where"+ ]+ [ "module Foo"+ , " ( -- Bar"+ , " bar -- Inline bar"+ , " -- Foo" -- NOTE(jaspervdj): I would prefer to have the `,` here+ , " , foo -- Inline foo" , " ) where" ]
tests/Language/Haskell/Stylish/Step/Tabs/Tests.hs view
@@ -1,4 +1,5 @@ --------------------------------------------------------------------------------+{-# LANGUAGE OverloadedLists #-} module Language.Haskell.Stylish.Step.Tabs.Tests ( tests ) where@@ -7,7 +8,7 @@ -------------------------------------------------------------------------------- import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.HUnit (Assertion) --------------------------------------------------------------------------------@@ -24,20 +25,16 @@ -------------------------------------------------------------------------------- case01 :: Assertion-case01 = expected @=? testStep (step 4) input- where- input = unlines- [ "module Main"- , "\t\twhere"- , "data Foo"- , "\t= Bar"- , " | Qux"- ]-- expected = unlines- [ "module Main"- , " where"- , "data Foo"- , " = Bar"- , " | Qux"- ]+case01 = assertSnippet (step 4)+ [ "module Main"+ , "\t\twhere"+ , "data Foo"+ , "\t= Bar"+ , " | Qux"+ ]+ [ "module Main"+ , " where"+ , "data Foo"+ , " = Bar"+ , " | Qux"+ ]
tests/Language/Haskell/Stylish/Step/TrailingWhitespace/Tests.hs view
@@ -1,4 +1,5 @@ --------------------------------------------------------------------------------+{-# LANGUAGE OverloadedLists #-} module Language.Haskell.Stylish.Step.TrailingWhitespace.Tests ( tests ) where@@ -7,7 +8,7 @@ -------------------------------------------------------------------------------- import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.HUnit (Assertion) --------------------------------------------------------------------------------@@ -24,20 +25,16 @@ -------------------------------------------------------------------------------- case01 :: Assertion-case01 = expected @=? testStep step input- where- input = unlines- [ "module Main where"- , " \t"- , "data Foo = Bar | Qux\t "- , "\12" -- page break- , " \12" -- malformed page break- ]-- expected = unlines- [ "module Main where"- , ""- , "data Foo = Bar | Qux"- , "\12" -- page break- , ""- ]+case01 = assertSnippet step+ [ "module Main where"+ , " \t"+ , "data Foo = Bar | Qux\t "+ , "\12" -- page break+ , " \12" -- malformed page break+ ]+ [ "module Main where"+ , ""+ , "data Foo = Bar | Qux"+ , "\12" -- page break+ , ""+ ]
tests/Language/Haskell/Stylish/Step/UnicodeSyntax/Tests.hs view
@@ -1,13 +1,14 @@ --------------------------------------------------------------------------------+{-# LANGUAGE OverloadedLists #-} module Language.Haskell.Stylish.Step.UnicodeSyntax.Tests ( tests ) where ---------------------------------------------------------------------------------import Test.Framework (Test, testGroup)-import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@=?))+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (Assertion) --------------------------------------------------------------------------------@@ -25,31 +26,23 @@ -------------------------------------------------------------------------------- case01 :: Assertion-case01 = expected @=? testStep (step True "LANGUAGE") input- where- input = unlines- [ "sort :: Ord a => [a] -> [a]"- , "sort _ = []"- ]-- expected = unlines- [ "{-# LANGUAGE UnicodeSyntax #-}"- , "sort ∷ Ord a ⇒ [a] → [a]"- , "sort _ = []"- ]+case01 = assertSnippet (step True "LANGUAGE")+ [ "sort :: Ord a => [a] -> [a]"+ , "sort _ = []"+ ]+ [ "{-# LANGUAGE UnicodeSyntax #-}"+ , "sort ∷ Ord a ⇒ [a] → [a]"+ , "sort _ = []"+ ] -------------------------------------------------------------------------------- case02 :: Assertion-case02 = expected @=? testStep (step True "LaNgUaGe") input- where- input = unlines- [ "sort :: Ord a => [a] -> [a]"- , "sort _ = []"- ]-- expected = unlines- [ "{-# LaNgUaGe UnicodeSyntax #-}"- , "sort ∷ Ord a ⇒ [a] → [a]"- , "sort _ = []"- ]+case02 = assertSnippet (step True "LaNgUaGe")+ [ "sort :: Ord a => [a] -> [a]"+ , "sort _ = []"+ ]+ [ "{-# LaNgUaGe UnicodeSyntax #-}"+ , "sort ∷ Ord a ⇒ [a] → [a]"+ , "sort _ = []"+ ]
tests/Language/Haskell/Stylish/Tests.hs view
@@ -1,16 +1,18 @@ --------------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-} module Language.Haskell.Stylish.Tests ( tests ) where ---------------------------------------------------------------------------------import Data.List (sort)+import Data.List (isInfixOf, sort) import System.Directory (createDirectory) import System.FilePath (normalise, (</>)) import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, (@?=))+import Test.HUnit (Assertion, assertFailure,+ (@?=)) --------------------------------------------------------------------------------@@ -93,15 +95,21 @@ , " }" ] + -------------------------------------------------------------------------------- case04 :: Assertion-case04 = (@?= result) =<< format Nothing (Just fileLocation) input+case04 = format Nothing (Just fileLocation) input >>= \case+ Right _ -> assertFailure "expected error"+ Left err+ | fileLocation `isInfixOf` err+ , needle `isInfixOf` err -> pure ()+ | otherwise ->+ assertFailure $ "Unexpected error: " ++ show err where- fileLocation = "directory/File.hs" input = "module Herp"- result = Left $- fileLocation <> ": RealSrcSpan SrcSpanPoint \"directory/File.hs\" 2 1:" - <> " parse error (possibly incorrect indentation or mismatched brackets)\n"+ fileLocation = "directory/File.hs"+ needle = "possibly incorrect indentation or mismatched brackets"+ -------------------------------------------------------------------------------- -- | When providing current dir including folders and files.
tests/Language/Haskell/Stylish/Tests/Util.hs view
@@ -3,40 +3,34 @@ module Language.Haskell.Stylish.Tests.Util ( dumpAst , dumpModule- , testStep- , testStep' , Snippet (..)- , testSnippet , assertSnippet , withTestDirTree- , (@=??) ) where ---------------------------------------------------------------------------------import Control.Exception (bracket, try)-import Control.Monad.Writer (execWriter, tell)-import Data.List (intercalate)-import GHC.Exts (IsList (..))-import GHC.Hs.Dump (showAstData, BlankSrcSpan(..))-import Language.Haskell.Stylish.GHC (baseDynFlags)-import System.Directory (createDirectory,- getCurrentDirectory,- getTemporaryDirectory,- removeDirectoryRecursive,- setCurrentDirectory)-import System.FilePath ((</>))-import System.IO.Error (isAlreadyExistsError)-import System.Random (randomIO)-import Test.HUnit (Assertion, assertFailure,- (@=?))-import Outputable (showSDoc)-import Data.Data (Data(..))+import Control.Exception (bracket, try)+import Data.Data (Data (..))+import GHC.Exts (IsList (..))+import GHC.Hs.Dump (BlankEpAnnotations (..),+ BlankSrcSpan (..),+ showAstData)+import System.Directory (createDirectory,+ getCurrentDirectory,+ getTemporaryDirectory,+ removeDirectoryRecursive,+ setCurrentDirectory)+import System.FilePath ((</>))+import System.IO.Error (isAlreadyExistsError)+import System.Random (randomIO)+import Test.HUnit (Assertion, (@=?)) --------------------------------------------------------------------------------+import Language.Haskell.Stylish.GHC (showOutputable)+import Language.Haskell.Stylish.Module (Module) import Language.Haskell.Stylish.Parse import Language.Haskell.Stylish.Step-import Language.Haskell.Stylish.Module (Module) -------------------------------------------------------------------------------- -- | Takes a Haskell source as an argument and parse it into a Module.@@ -49,8 +43,8 @@ dumpAst extract str = let Right(theModule) = parseModule [] Nothing str ast = extract theModule- sdoc = showAstData BlankSrcSpan ast- in showSDoc baseDynFlags sdoc+ sdoc = showAstData BlankSrcSpan BlankEpAnnotations ast+ in showOutputable sdoc dumpModule :: String -> String dumpModule = dumpAst id@@ -67,11 +61,6 @@ ---------------------------------------------------------------------------------testStep' :: Step -> Lines -> Lines-testStep' s ls = lines $ testStep s (unlines ls)----------------------------------------------------------------------------------- -- | 'Lines' that show as a normal string. newtype Snippet = Snippet {unSnippet :: Lines} deriving (Eq) @@ -124,15 +113,3 @@ setCurrentDirectory current *> removeDirectoryRecursive temp) (\(_, temp) -> setCurrentDirectory temp *> action)--(@=??) :: Lines -> Lines -> Assertion-expected @=?? actual =- if expected == actual then pure ()- else assertFailure $ intercalate "\n" $ execWriter do- tell ["Expected:"]- printLines expected- tell ["Got:"]- printLines actual- where- printLines =- mapM_ \line -> tell [" " <> line]