packages feed

hfmt 0.0.2.3 → 0.1.0

raw patch · 17 files changed

+346/−177 lines, 17 filesdep +bytestringdep +exceptionsdep +pathdep ~hindentdep ~hlintdep ~stylish-haskellPVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring, exceptions, path, path-io, transformers, yaml

Dependency ranges changed: hindent, hlint, stylish-haskell

API changes (from Hackage documentation)

- Language.Haskell.Format: data Formatter
+ Language.Haskell.Format: newtype Formatter

Files

README.md view
@@ -12,11 +12,11 @@  with [stack](https://www.haskellstack.org/) -    $ cabal install hfmt+    $ stack install hfmt  with [cabal](https://www.haskell.org/haskellwiki/Cabal/How_to_install_a_Cabal_package) -    $ stack install hfmt+    $ cabal install hfmt  ## Usage 
app/Actions.hs view
@@ -1,4 +1,6 @@-module Actions (act) where+module Actions+  ( act+  ) where  import Language.Haskell.Format import OptionsParser@@ -16,7 +18,8 @@   return r act options r@(Reformat input source result) = act' (optAction options)   where-    act' PrintDiffs = when wasReformatted (printDiff input source result) >> return r+    act' PrintDiffs =+      when wasReformatted (printDiff input source result) >> return r     act' PrintSources = undefined     act' PrintFilePaths = when wasReformatted (print input) >> return r     act' WriteSources = do@@ -26,7 +29,8 @@  sourceChangedOrHasSuggestions :: HaskellSource -> Reformatted -> Bool sourceChangedOrHasSuggestions source reformatted =-  not (null (suggestions reformatted)) || source /= reformattedSource reformatted+  not (null (suggestions reformatted)) ||+  source /= reformattedSource reformatted  printDiff :: InputFile -> HaskellSource -> Reformatted -> IO () printDiff (InputFilePath path) source reformatted = do
app/Main.hs view
@@ -1,4 +1,6 @@-module Main (main) where+module Main+  ( main+  ) where  import           Actions import           Language.Haskell.Format@@ -28,7 +30,9 @@  runFormatter :: Formatter -> Options -> IO Bool runFormatter formatter options =-  anyStrict sourceChangedOrHasSuggestions (inputFiles >-> P.map reformat >-> P.mapM writeOutput)+  anyStrict+    sourceChangedOrHasSuggestions+    (inputFiles >-> P.map reformat >-> P.mapM writeOutput)   where     anyStrict :: Monad m => (a -> Bool) -> Producer a m () -> m Bool     anyStrict f = P.fold (\acc x -> acc || f x) False id@@ -37,15 +41,18 @@     writeOutput = Actions.act options  readInputFiles :: Options -> Producer InputFileWithSource IO ()-readInputFiles options = determineInputFilePaths (optPaths options) >-> P.mapM readInputFile+readInputFiles options =+  determineInputFilePaths (optPaths options) >-> P.mapM readInputFile  determineInputFilePaths :: [FilePath] -> Producer InputFile IO () determineInputFilePaths [] = enumeratePath "." >-> P.map InputFilePath determineInputFilePaths ["-"] = yield InputFromStdIn-determineInputFilePaths paths = for (each paths) enumeratePath >-> P.map InputFilePath+determineInputFilePaths paths =+  for (each paths) enumeratePath >-> P.map InputFilePath  readInputFile :: InputFile -> IO InputFileWithSource-readInputFile (InputFilePath path) = InputFileWithSource (InputFilePath path) <$> readSource path+readInputFile (InputFilePath path) =+  InputFileWithSource (InputFilePath path) <$> readSource path readInputFile InputFromStdIn = InputFileWithSource InputFromStdIn <$> readStdin  applyFormatter :: Formatter -> InputFileWithSource -> ReformatResult@@ -62,4 +69,5 @@  sourceChangedOrHasSuggestions :: ReformatResult -> Bool sourceChangedOrHasSuggestions (Reformat input source reformatted) =-  not (null (suggestions reformatted)) || source /= reformattedSource reformatted+  not (null (suggestions reformatted)) ||+  source /= reformattedSource reformatted
app/OptionsParser.hs view
@@ -1,4 +1,9 @@-module OptionsParser (Options, optAction, optPaths, parser) where+module OptionsParser+  ( Options+  , optAction+  , optPaths+  , parser+  ) where  import Types @@ -10,14 +15,13 @@ import Options.Applicative.Extra import Text.PrettyPrint.ANSI.Leijen hiding (empty, (<$>), (<>)) -data Options =-       Options-         { optPrintDiffs     :: Bool-         , optPrintSources   :: Bool-         , optPrintFilePaths :: Bool-         , optWriteSources   :: Bool-         , optPaths          :: [FilePath]-         }+data Options = Options+  { optPrintDiffs     :: Bool+  , optPrintSources   :: Bool+  , optPrintFilePaths :: Bool+  , optWriteSources   :: Bool+  , optPaths          :: [FilePath]+  }  optAction :: Options -> Action optAction options@@ -29,49 +33,53 @@   | otherwise = PrintDiffs  optionParser :: Parser Options-optionParser = Options <$> switch-                             (long "print-diffs" <>-                              short 'd' <>-                              help "If a file's formatting is different, print a diff.")-                       <*> switch-                             (long "print-sources" <>-                              short 's' <>-                              help "If a file's formatting is different, print its source.")-                       <*> switch-                             (long "print-paths" <>-                              short 'l' <>-                              help "If a file's formatting is different, print its path.")-                       <*> switch-                             (long "write-sources" <>-                              short 'w' <>-                              help "If a file's formatting is different, overwrite it.")-                       <*> many pathOption+optionParser =+  Options <$>+  switch+    (long "print-diffs" <> short 'd' <>+     help "If a file's formatting is different, print a diff.") <*>+  switch+    (long "print-sources" <> short 's' <>+     help "If a file's formatting is different, print its source.") <*>+  switch+    (long "print-paths" <> short 'l' <>+     help "If a file's formatting is different, print its path.") <*>+  switch+    (long "write-sources" <> short 'w' <>+     help "If a file's formatting is different, overwrite it.") <*>+  many pathOption   where     pathOption = strArgument (metavar "PATH" <> pathOptionHelp)-    pathOptionHelp = helpDoc $ Just $-      paragraph "Explicit paths to process." <> hardline-      <> unorderdedList " - "-           [ paragraph "A single '-' will process standard input."-           , paragraph "Files will be processed directly."-           , paragraph "Directories will be recursively searched for source files to process."-           , paragraph-               ".cabal files will be parsed and all specified source directories and files processed."-           , paragraph-               "If no paths are given, the current directory will be searched for .cabal files to process, if none are found the current directory will be recursively searched for source files to process."-           ]+    pathOptionHelp =+      helpDoc $+      Just $+      paragraph "Explicit paths to process." <> hardline <>+      unorderdedList+        " - "+        [ paragraph "A single '-' will process standard input."+        , paragraph "Files will be processed directly."+        , paragraph+            "Directories will be recursively searched for source files to process."+        , paragraph+            ".cabal files will be parsed and all specified source directories and files processed."+        , paragraph+            "If no paths are given, the current directory will be searched for .cabal files to process, if none are found the current directory will be recursively searched for source files to process."+        ]  paragraph :: String -> Doc paragraph = mconcat . intersperse softline . map text . words  unorderdedList :: String -> [Doc] -> Doc-unorderdedList prefix = encloseSep (text prefix) mempty (text prefix) . map (hang 0)+unorderdedList prefix =+  encloseSep (text prefix) mempty (text prefix) . map (hang 0)  optionParserInfo :: ParserInfo Options-optionParserInfo = info (helper <*> optionParser)-                     (fullDesc-                      <> header "hfmt - format Haskell programs"-                      <> progDesc-                           "Operates on Haskell source files, reformatting them by applying suggestions from HLint, hindent, and stylish-haskell. Inspired by the gofmt utility.")+optionParserInfo =+  info+    (helper <*> optionParser)+    (fullDesc <> header "hfmt - format Haskell programs" <>+     progDesc+       "Operates on Haskell source files, reformatting them by applying suggestions from HLint, hindent, and stylish-haskell. Inspired by the gofmt utility.")  parser :: ParserInfo Options parser = optionParserInfo
app/Types.hs view
@@ -1,31 +1,39 @@-module Types (-    Action(..),-    InputFile(..),-    InputFileWithSource(..),-    ErrorString,-    ReformatResult(..),-    HaskellSourceFilePath,-    HaskellSource(..),-    ) where+module Types+  ( Action(..)+  , InputFile(..)+  , InputFileWithSource(..)+  , ErrorString+  , ReformatResult(..)+  , HaskellSourceFilePath+  , HaskellSource(..)+  ) where  import Language.Haskell.Format import Language.Haskell.Source.Enumerator (HaskellSourceFilePath) -data Action = PrintDiffs-            | PrintSources-            | PrintFilePaths-            | WriteSources+data Action+  = PrintDiffs+  | PrintSources+  | PrintFilePaths+  | WriteSources -data InputFile = InputFilePath HaskellSourceFilePath-               | InputFromStdIn+data InputFile+  = InputFilePath HaskellSourceFilePath+  | InputFromStdIn  instance Show InputFile where   show (InputFilePath path) = path-  show InputFromStdIn = "-"+  show InputFromStdIn       = "-" -data InputFileWithSource = InputFileWithSource InputFile HaskellSource+data InputFileWithSource =+  InputFileWithSource InputFile+                      HaskellSource  type ErrorString = String -data ReformatResult = InvalidReformat InputFile ErrorString-                    | Reformat InputFile HaskellSource Reformatted+data ReformatResult+  = InvalidReformat InputFile+                    ErrorString+  | Reformat InputFile+             HaskellSource+             Reformatted
hfmt.cabal view
@@ -1,5 +1,5 @@ name:                hfmt-version:             0.0.2.3+version:             0.1.0 synopsis:            Haskell source code formatter description:         Inspired by gofmt. Built using hlint, hindent, and stylish-haskell. license:             MIT@@ -25,18 +25,25 @@                      , Language.Haskell.Format.HIndent                      , Language.Haskell.Format.HLint                      , Language.Haskell.Format.Stylish+                     , Path.Find   GHC-Options:       -Wall   Build-Depends:     base >= 4.8 && < 5+                     , bytestring                      , Cabal                      , directory+                     , exceptions                      , filepath                      , haskell-src-exts-                     , hindent >= 4.5 , hindent < 5-                     , hlint >= 1.9.13 , hlint < 2+                     , hindent >= 5.0.0+                     , hlint >= 1.9                      , HUnit+                     , path+                     , path-io                      , pipes-                     , stylish-haskell >= 0.5 , stylish-haskell < 0.6+                     , stylish-haskell >= 0.7                      , text+                     , transformers+                     , yaml  executable hfmt   Hs-Source-Dirs:    app
src/Language/Haskell/Format.hs view
@@ -1,16 +1,16 @@-module Language.Haskell.Format (-    autoSettings,-    format,-    formatters,-    hlint,-    hindent,-    stylish,-    Settings,-    Formatter(..),-    Suggestion(..),-    HaskellSource(..),-    Reformatted(..),-    ) where+module Language.Haskell.Format+  ( autoSettings+  , format+  , formatters+  , hlint+  , hindent+  , stylish+  , Settings+  , Formatter(..)+  , Suggestion(..)+  , HaskellSource(..)+  , Reformatted(..)+  ) where  import           Language.Haskell.Format.Definitions import qualified Language.Haskell.Format.HIndent     as HIndent@@ -20,7 +20,8 @@ import           Control.Applicative import           Data.Maybe -data Settings = Settings+data Settings =+  Settings  autoSettings :: IO Settings autoSettings = return Settings
src/Language/Haskell/Format/Definitions.hs view
@@ -1,4 +1,9 @@-module Language.Haskell.Format.Definitions (HaskellSource(..), Reformatted(..), Formatter(..), Suggestion(..)) where+module Language.Haskell.Format.Definitions+  ( HaskellSource(..)+  , Reformatted(..)+  , Formatter(..)+  , Suggestion(..)+  ) where  import Control.Applicative import Control.Monad@@ -6,26 +11,36 @@  type ErrorString = String -newtype HaskellSource = HaskellSource String-  deriving Eq+newtype HaskellSource =+  HaskellSource String+  deriving (Eq) -newtype Suggestion = Suggestion String+newtype Suggestion =+  Suggestion String  instance Show Suggestion where   show (Suggestion text) = text -data Reformatted = Reformatted { reformattedSource :: HaskellSource, suggestions :: [Suggestion] }+data Reformatted = Reformatted+  { reformattedSource :: HaskellSource+  , suggestions       :: [Suggestion]+  }  instance Monoid Reformatted where   mempty = Reformatted undefined []-  (Reformatted _ suggestionsA) `mappend` (Reformatted sourceB suggestionsB) = Reformatted sourceB-                                                                                (suggestionsA <> suggestionsB)+  (Reformatted _ suggestionsA) `mappend` (Reformatted sourceB suggestionsB) =+    Reformatted sourceB (suggestionsA <> suggestionsB) -data Formatter = Formatter { unFormatter :: HaskellSource -> Either ErrorString Reformatted }+newtype Formatter = Formatter+  { unFormatter :: HaskellSource -> Either ErrorString Reformatted+  }  instance Monoid Formatter where   mempty = Formatter (\source -> Right (Reformatted source []))   (Formatter f) `mappend` (Formatter g) = Formatter (asReformatter g <=< f) -asReformatter :: (HaskellSource -> Either ErrorString Reformatted) -> Reformatted -> Either ErrorString Reformatted+asReformatter ::+     (HaskellSource -> Either ErrorString Reformatted)+  -> Reformatted+  -> Either ErrorString Reformatted asReformatter formatter r = (r <>) <$> formatter (reformattedSource r)
src/Language/Haskell/Format/HIndent.hs view
@@ -1,28 +1,66 @@-module Language.Haskell.Format.HIndent (autoSettings, formatter, defaultFormatter) where+module Language.Haskell.Format.HIndent+  ( autoSettings+  , formatter+  , defaultFormatter+  ) where -import Control.Applicative-import Data.Maybe-import Data.Text.Lazy                      as L-import Data.Text.Lazy.Builder-import HIndent-import Language.Haskell.Exts.Extension     (Extension)+import           Control.Applicative+import           Data.ByteString.Builder+import           Data.ByteString.Lazy                as L+import           Data.Maybe+import qualified Data.Text                           as Text+import           Data.Text.Encoding                  as Encoding+import           Data.Text.Lazy                      as TL+import           Data.Text.Lazy.Builder+import qualified Data.Yaml                           as Y+import           HIndent+import           HIndent.Types+import           Language.Haskell.Exts.Extension     (Extension)+import           Path+import qualified Path.Find                           as Path+import qualified Path.IO                             as Path -import Language.Haskell.Format.Definitions-import Language.Haskell.Format.Internal+import           Language.Haskell.Format.Definitions+import           Language.Haskell.Format.Internal -data Settings = Settings Style (Maybe [Extension])+data Settings =+  Settings Config+           (Maybe [Extension])  defaultFormatter :: IO Formatter defaultFormatter = formatter <$> autoSettings  autoSettings :: IO Settings-autoSettings = return (Settings gibiansky Nothing)+autoSettings = do+  config <- getConfig+  return (Settings config Nothing) +-- | Read config from a config file, or return 'defaultConfig'.+getConfig :: IO Config+getConfig = do+  cur <- Path.getCurrentDir+  homeDir <- Path.getHomeDir+  mfile <-+    Path.findFileUp+      cur+      ((== ".hindent.yaml") . toFilePath . filename)+      (Just homeDir)+  case mfile of+    Nothing -> return defaultConfig+    Just file -> do+      result <- Y.decodeFileEither (toFilePath file)+      case result of+        Left e       -> error (show e)+        Right config -> return config+ formatter :: Settings -> Formatter formatter = mkFormatter . hindent  hindent :: Settings -> HaskellSource -> Either String HaskellSource-hindent (Settings style extensions) (HaskellSource source) =-  HaskellSource . L.unpack . toLazyText <$> reformat style extensions sourceText+hindent (Settings config extensions) (HaskellSource source) =+  toHaskellSource <$> reformat config extensions Nothing sourceText   where-    sourceText = L.pack source+    sourceText = Encoding.encodeUtf8 . Text.pack $ source+    toHaskellSource =+      HaskellSource .+      Text.unpack . Encoding.decodeUtf8 . L.toStrict . toLazyByteString
src/Language/Haskell/Format/HLint.hs view
@@ -1,40 +1,36 @@-module Language.Haskell.Format.HLint (autoSettings, formatter, suggester) where+module Language.Haskell.Format.HLint+  ( autoSettings+  , suggester+  ) where  import           Language.Haskell.Format.Definitions import           Language.Haskell.Format.Internal  import           Control.Applicative-import           Language.Haskell.Exts.Annotated     as Hse+import           Language.Haskell.HLint3             (Classify, Hint,+                                                      ParseError (..),+                                                      ParseFlags, applyHints,+                                                      parseModuleEx) import qualified Language.Haskell.HLint3             as HLint3--formatter = undefined+import           System.IO.Unsafe                    (unsafePerformIO) -suggester :: (ParseMode, [HLint3.Classify], HLint3.Hint) -> Formatter+suggester :: (ParseFlags, [Classify], Hint) -> Formatter suggester = mkSuggester . hlint -hlint :: (ParseMode, [HLint3.Classify], HLint3.Hint) -> HaskellSource -> Either String [Suggestion]-hlint (parseMode, classifications, hint) (HaskellSource source) =-  getSuggestions <$> parseResultAsEither (parse source)+hlint ::+     (ParseFlags, [Classify], Hint)+  -> HaskellSource+  -> Either String [Suggestion]+hlint (flags, classify, hint) (HaskellSource source) =+  case unsafePerformIO (parseModuleEx flags filepath (Just source)) of+    Right m         -> Right . map ideaToSuggestion . ideas $ m+    Left parseError -> Left . parseErrorMessage $ parseError   where-    parse = Hse.parseFileContentsWithComments parseMode-    getSuggestions moduleSource = map ideaToSuggestion $ HLint3.applyHints classifications hint-                                                           [moduleSource]--autoSettings :: IO (ParseMode, [HLint3.Classify], HLint3.Hint)-autoSettings = do-  (fixities, classify, hints) <- HLint3.findSettings (HLint3.readSettingsFile Nothing) Nothing-  return-    (HLint3.hseFlags (HLint3.parseFlagsAddFixities fixities HLint3.defaultParseFlags), classify, HLint3.resolveHints-                                                                                                   hints)+    filepath = ""+    ideas m = applyHints classify hint [m] -parseResultAsEither :: ParseResult a -> Either String a-parseResultAsEither (ParseOk a) = Right a-parseResultAsEither (ParseFailed loc error) =-  Left ("Parse failed at " ++ location ++ ": " ++ error)-  where-    location = filename ++ " " ++ linecol-    filename = "[" ++ srcFilename loc ++ "]"-    linecol = "(" ++ show (srcLine loc) ++ ":" ++ show (srcColumn loc) ++ ")"+autoSettings :: IO (ParseFlags, [Classify], Hint)+autoSettings = HLint3.autoSettings  ideaToSuggestion :: HLint3.Idea -> Suggestion ideaToSuggestion = Suggestion . show
src/Language/Haskell/Format/Internal.hs view
@@ -1,4 +1,7 @@-module Language.Haskell.Format.Internal (mkFormatter, mkSuggester) where+module Language.Haskell.Format.Internal+  ( mkFormatter+  , mkSuggester+  ) where  import Language.Haskell.Format.Definitions 
src/Language/Haskell/Format/Stylish.hs view
@@ -1,4 +1,7 @@-module Language.Haskell.Format.Stylish (autoSettings, formatter) where+module Language.Haskell.Format.Stylish+  ( autoSettings+  , formatter+  ) where  import Control.Applicative import Language.Haskell.Stylish            as Stylish@@ -6,17 +9,20 @@ import Language.Haskell.Format.Definitions import Language.Haskell.Format.Internal -data Settings = Settings Stylish.Config+newtype Settings =+  Settings Stylish.Config  autoSettings :: IO Settings-autoSettings = Settings <$> Stylish.loadConfig (Stylish.makeVerbose False) Nothing+autoSettings =+  Settings <$> Stylish.loadConfig (Stylish.makeVerbose False) Nothing  formatter :: Settings -> Formatter formatter = mkFormatter . stylish  stylish :: Settings -> HaskellSource -> Either String HaskellSource stylish (Settings config) (HaskellSource source) =-  HaskellSource . unlines <$> Stylish.runSteps extensions Nothing steps sourceLines+  HaskellSource . unlines <$>+  Stylish.runSteps extensions Nothing steps sourceLines   where     sourceLines = lines source     extensions = Stylish.configLanguageExtensions config
src/Language/Haskell/Format/Utilities.hs view
@@ -1,4 +1,8 @@-module Language.Haskell.Format.Utilities (wasReformatted, hunitTest, defaultFormatter) where+module Language.Haskell.Format.Utilities+  ( wasReformatted+  , hunitTest+  , defaultFormatter+  ) where  import           Language.Haskell.Format import           Language.Haskell.Format.Definitions@@ -13,32 +17,36 @@  type ErrorString = String -data CheckResult = InvalidCheckResult ErrorString-                 | CheckResult HaskellSource Reformatted+data CheckResult+  = InvalidCheckResult ErrorString+  | CheckResult HaskellSource+                Reformatted  hunitTest :: FilePath -> Test hunitTest filepath = TestLabel filepath $ makeTestCase filepath  makeTestCase :: FilePath -> Test-makeTestCase filepath = TestCase $ do-  formatter <- defaultFormatter-  runEffect $ check formatter filepath >-> assertResults+makeTestCase filepath =+  TestCase $ do+    formatter <- defaultFormatter+    runEffect $ check formatter filepath >-> assertResults  assertResults :: Consumer CheckResult IO ()-assertResults = forever $ do-  result <- await-  case result of-    (InvalidCheckResult errorString) -> lift $ assertFailure ("Error: " ++ errorString)-    (CheckResult source reformatted) -> when (wasReformatted source reformatted) $ lift $ assertFailure-                                                                                            ("Incorrect formatting: " ++ concatMap-                                                                                                                           show-                                                                                                                           (suggestions-                                                                                                                              reformatted))+assertResults =+  forever $ do+    result <- await+    case result of+      (InvalidCheckResult errorString) ->+        lift $ assertFailure ("Error: " ++ errorString)+      (CheckResult source reformatted) ->+        when (wasReformatted source reformatted) $+        lift $+        assertFailure+          ("Incorrect formatting: " ++ concatMap show (suggestions reformatted))  check :: Formatter -> FilePath -> Producer CheckResult IO ()-check formatter path = enumeratePath path >->-                       P.mapM readSource >->-                       P.map (checkFormatting formatter)+check formatter path =+  enumeratePath path >-> P.mapM readSource >-> P.map (checkFormatting formatter)  readSource :: HaskellSourceFilePath -> IO HaskellSource readSource path = HaskellSource <$> readFile path@@ -57,4 +65,5 @@  wasReformatted :: HaskellSource -> Reformatted -> Bool wasReformatted source reformatted =-  not (null (suggestions reformatted)) || source /= reformattedSource reformatted+  not (null (suggestions reformatted)) ||+  source /= reformattedSource reformatted
src/Language/Haskell/Source/Enumerator.hs view
@@ -1,4 +1,7 @@-module Language.Haskell.Source.Enumerator (enumeratePath, HaskellSourceFilePath) where+module Language.Haskell.Source.Enumerator+  ( enumeratePath+  , HaskellSourceFilePath+  ) where  import           Control.Applicative import           Control.Monad@@ -63,7 +66,8 @@     else directory path  getDirectoryContentsFullPaths :: FilePath -> IO [FilePath]-getDirectoryContentsFullPaths path = mkFull . notHidden . notMeta <$> getDirectoryContents path+getDirectoryContentsFullPaths path =+  mkFull . notHidden . notMeta <$> getDirectoryContents path   where     mkFull = map (path </>)     notHidden = filter (not . isPrefixOf ".")@@ -84,8 +88,12 @@ sourcePaths :: GenericPackageDescription -> [FilePath] sourcePaths pkg = nub $ concatMap ($ pkg) pathExtractors   where-    pathExtractors = [ maybe [] (hsSourceDirs . libBuildInfo . condTreeData) . condLibrary-                     , concatMap (hsSourceDirs . buildInfo . condTreeData . snd) . condExecutables-                     , concatMap (hsSourceDirs . testBuildInfo . condTreeData . snd) . condTestSuites-                     , concatMap (hsSourceDirs . benchmarkBuildInfo . condTreeData . snd) . condBenchmarks-                     ]+    pathExtractors =+      [ maybe [] (hsSourceDirs . libBuildInfo . condTreeData) . condLibrary+      , concatMap (hsSourceDirs . buildInfo . condTreeData . snd) .+        condExecutables+      , concatMap (hsSourceDirs . testBuildInfo . condTreeData . snd) .+        condTestSuites+      , concatMap (hsSourceDirs . benchmarkBuildInfo . condTreeData . snd) .+        condBenchmarks+      ]
+ src/Path/Find.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE DataKinds #-}++-- | Finding files.+-- Lifted from Stack.+module Path.Find+  ( findFileUp+  ) where++import Control.Exception      (evaluate)+import Control.Monad+import Control.Monad.Catch+import Control.Monad.IO.Class+import Data.List+import Path+import Path.IO                hiding (findFiles)+import System.IO.Error        (isPermissionError)++-- | Find the location of a file matching the given predicate.+findFileUp ::+     (MonadIO m, MonadThrow m)+  => Path Abs Dir -- ^ Start here.+  -> (Path Abs File -> Bool) -- ^ Predicate to match the file.+  -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory.+  -> m (Maybe (Path Abs File)) -- ^ Absolute file path.+findFileUp = findPathUp snd++-- | Find the location of a directory matching the given predicate.+findDirUp ::+     (MonadIO m, MonadThrow m)+  => Path Abs Dir -- ^ Start here.+  -> (Path Abs Dir -> Bool) -- ^ Predicate to match the directory.+  -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory.+  -> m (Maybe (Path Abs Dir)) -- ^ Absolute directory path.+findDirUp = findPathUp fst++-- | Find the location of a path matching the given predicate.+findPathUp ::+     (MonadIO m, MonadThrow m)+  => (([Path Abs Dir], [Path Abs File]) -> [Path Abs t])+              -- ^ Choose path type from pair.+  -> Path Abs Dir -- ^ Start here.+  -> (Path Abs t -> Bool) -- ^ Predicate to match the path.+  -> Maybe (Path Abs Dir) -- ^ Do not ascend above this directory.+  -> m (Maybe (Path Abs t)) -- ^ Absolute path.+findPathUp pathType dir p upperBound = do+  entries <- listDir dir+  case find p (pathType entries) of+    Just path -> return (Just path)+    Nothing+      | Just dir == upperBound -> return Nothing+      | parent dir == dir -> return Nothing+      | otherwise -> findPathUp pathType (parent dir) p upperBound
test/pure/Spec.hs view
@@ -1,4 +1,6 @@-module Main where+module Main+  ( main+  ) where  import Test.Framework                 (defaultMain, testGroup) import Test.Framework.Providers.HUnit
test/self-formatting/Spec.hs view
@@ -1,4 +1,6 @@-module Main where+module Main+  ( main+  ) where  import Language.Haskell.Format.Utilities @@ -7,7 +9,9 @@ import Test.HUnit                        hiding (Test)  main :: IO ()-main = defaultMain-         [ testGroup "Check formatting of package sources"-             (hUnitTestToTests $ hunitTest "hfmt.cabal")-         ]+main =+  defaultMain+    [ testGroup+        "Check formatting of package sources"+        (hUnitTestToTests $ hunitTest "hfmt.cabal")+    ]