hfmt 0.2.0 → 0.2.1
raw patch · 6 files changed
+78/−57 lines, 6 filesdep +conduit
Dependencies added: conduit
Files
- README.md +15/−14
- app/ExitCode.hs +11/−7
- app/Main.hs +29/−34
- app/Types.hs +19/−0
- hfmt.cabal +3/−1
- src/Language/Haskell/Format/HIndent.hs +1/−1
README.md view
@@ -33,26 +33,27 @@ λ hfmt --help hfmt - format Haskell programs - Usage: hfmt.exe [-d|--print-diffs] [-s|--print-sources] [-l|--print-paths]- [-w|--write-sources] [PATH]- Operates on Haskell source files, reformatting them by applying suggestions- from HLint, hindent, and stylish-haskell. Inspired by the gofmt utility.+ Usage: hfmt [-d|--print-diffs] [FILE]+ Reformats Haskell source files by applying HLint, hindent, and+ stylish-haskell. Available options: -h,--help Show this help text -d,--print-diffs If a file's formatting is different, print a diff. -s,--print-sources If a file's formatting is different, print its- source.+ source. -l,--print-paths If a file's formatting is different, print its path. -w,--write-sources If a file's formatting is different, overwrite it.- PATH Explicit paths to process.+ FILE Explicit paths to process. - A single '-' will process standard input. - Files will be processed directly.- - Directories will be recursively searched for- source files to process.- - .cabal files will be parsed and all specified- source directories and files processed.- - 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.+ - Directories will be recursively searched for source files to process.+ - .cabal files will be parsed and all specified source directories and files processed.+ - 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.++ Exit Codes:+ 0 = No error+ 1 = Encountered I/O or other operational error+ 2 = Failed to parse a source code file+ 3 = Source code was parsed but cannot be formatted properly+ 4 = Formatted code differs from existing source (--print-diffs only)
app/ExitCode.hs view
@@ -2,6 +2,7 @@ ( exitCode , helpDoc , operationalFailureCode+ , sourceParseFailureCode ) where import Types@@ -15,13 +16,12 @@ -- should exit with failure if any format differences were found. Otherwise -- assume we are being run in a context where non-zero exit indicates -- failure of the tool to operate properly.-exitCode :: Action -> Bool -> ExitCode-exitCode action formattedCodeDiffers =- if formattedCodeDiffers && failOnDifferences- then ExitFailure formattedCodeDiffersFailureCode- else ExitSuccess- where- failOnDifferences = action == PrintDiffs+exitCode :: Action -> RunResult -> ExitCode+exitCode _ NoDifferences = ExitSuccess+exitCode PrintDiffs HadDifferences = ExitFailure formattedCodeDiffersFailureCode+exitCode _ HadDifferences = ExitSuccess+exitCode _ SourceParseFailure = ExitFailure sourceParseFailureCode+exitCode _ OperationalFailure = ExitFailure operationalFailureCode helpDoc :: Doc helpDoc =@@ -38,6 +38,10 @@ -- | Encountered I/O or other operational error operationalFailureCode :: Int operationalFailureCode = 1++-- | Failed to parse a source code file+sourceParseFailureCode :: Int+sourceParseFailureCode = 2 -- | Formatted code differs from existing source code formattedCodeDiffersFailureCode :: Int
app/Main.hs view
@@ -16,36 +16,44 @@ import Options.Applicative.Extra as OptApp import System.Directory import System.Exit+import System.IO main :: IO () main = do options <- execParser Options.parser- formattedCodeDiffers <- run options- exitWith $ exitCode (optAction options) formattedCodeDiffers+ result <- run options+ exitWith $ exitCode (optAction options) result -run :: Options -> IO Bool-run options =+run :: Options -> IO RunResult+run opt = runConduit $- sources .| mapMC readSource .| mapMC formatSource .| handleFormatErrors .|- mapMC action .|- summarize+ sources opt .| mapMC readSource .| mapMC formatSource .| mapMC doAction .|+ foldMapMC toRunResult where- paths = do- let explicitPaths = optPaths options+ formatSource source = do+ formatter <- defaultFormatter+ return $ applyFormatter formatter source+ doAction :: FormatResult -> IO FormatResult+ doAction = bimapM return (Actions.act opt)+ toRunResult :: FormatResult -> IO RunResult+ toRunResult (Left err) = do+ hPrint stderr (show err)+ return SourceParseFailure+ toRunResult (Right (Formatted _ source result)) =+ if wasReformatted source result+ then return HadDifferences+ else return NoDifferences++sources :: Options -> Source IO SourceFile+sources opt = lift paths >>= mapM_ sourcesFromPath+ where+ explicitPaths = optPaths opt+ paths = if null explicitPaths then do currentPath <- getCurrentDirectory return [currentPath] else return explicitPaths- sources :: Source IO SourceFile- sources = lift paths >>= mapM_ sourcesFromPath- formatSource source = do- formatter <- defaultFormatter- return $ applyFormatter formatter source- handleFormatErrors = concatMapMC handleFormatError- action = Actions.act options- summarize =- anyC' (\(Formatted _ source result) -> wasReformatted source result) sourcesFromPath :: FilePath -> Source IO SourceFile sourcesFromPath "-" = yield StdinSource@@ -63,19 +71,6 @@ Left err -> Left (FormatError file err) Right reformat -> Right (Formatted file contents reformat) -handleFormatError :: FormatResult -> IO (Maybe Formatted)-handleFormatError (Left err) = printFormatError err >> return Nothing-handleFormatError (Right formatted) = return $ Just formatted--printFormatError :: FormatError -> IO ()-printFormatError (FormatError input errorString) =- putStrLn ("Error reformatting " ++ show input ++ ": " ++ errorString)---- | Check that at least one value in the stream returns True.------ Does not shortcut, entire stream is always consumed-anyC' :: Monad m => (a -> Bool) -> Consumer a m Bool-anyC' f = do- result <- anyC f -- Check for at least one value, may shortcut- sinkNull -- consume any remaining input skipped by a shortcut- return result+bimapM :: Monad m => (a -> m c) -> (b -> m d) -> Either a b -> m (Either c d)+bimapM f _ (Left a) = Left <$> f a+bimapM _ g (Right b) = Right <$> g b
app/Types.hs view
@@ -4,6 +4,7 @@ , FormatError(..) , Formatted(..) , HaskellSource(..)+ , RunResult(..) , SourceFile(..) , SourceFileWithContents(..) ) where@@ -35,7 +36,25 @@ FormatError SourceFile String +instance Show FormatError where+ show (FormatError input errorString) =+ "Error reformatting " ++ show input ++ ": " ++ errorString+ data Formatted = Formatted SourceFile HaskellSource Reformatted++data RunResult+ = OperationalFailure+ | SourceParseFailure+ | HadDifferences+ | NoDifferences++instance Monoid RunResult where+ mempty = NoDifferences+ x `mappend` NoDifferences = x+ NoDifferences `mappend` x = x+ OperationalFailure `mappend` _ = OperationalFailure+ SourceParseFailure `mappend` _ = SourceParseFailure+ HadDifferences `mappend` _ = HadDifferences
hfmt.cabal view
@@ -1,5 +1,5 @@ name: hfmt-version: 0.2.0+version: 0.2.1 synopsis: Haskell source code formatter description: Inspired by gofmt. Built using hlint, hindent, and stylish-haskell. license: MIT@@ -30,6 +30,7 @@ Build-Depends: base >= 4.8 && < 5 , bytestring , Cabal+ , conduit , conduit-combinators , Diff , directory@@ -56,6 +57,7 @@ , Types GHC-Options: -Wall Build-Depends: base >= 4.8 && < 5+ , conduit , conduit-combinators , directory , hfmt
src/Language/Haskell/Format/HIndent.hs view
@@ -29,7 +29,7 @@ autoSettings :: IO Settings autoSettings = do config <- getConfig- return (Settings config Nothing)+ return $ Settings config $ Just defaultExtensions -- | Read config from a config file, or return 'defaultConfig'. getConfig :: IO Config