packages feed

hfmt-0.1.0: app/Main.hs

module Main
  ( main
  ) where

import           Actions
import           Language.Haskell.Format
import           Language.Haskell.Format.Utilities  hiding (wasReformatted)
import           Language.Haskell.Source.Enumerator
import           OptionsParser                      as Options
import           Types

import           Control.Applicative
import           Control.Monad
import           Data.List
import           Data.Maybe
import           Data.Monoid
import           Options.Applicative.Extra          as OptApp
import           Pipes
import qualified Pipes.Prelude                      as P
import           System.Exit

main :: IO ()
main = do
  options <- execParser Options.parser
  formatter <- defaultFormatter
  reformatNeeded <- runFormatter formatter options
  if reformatNeeded
    then exitFailure
    else exitSuccess

runFormatter :: Formatter -> Options -> IO Bool
runFormatter formatter options =
  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
    inputFiles = readInputFiles options
    reformat = applyFormatter formatter
    writeOutput = Actions.act options

readInputFiles :: Options -> Producer InputFileWithSource IO ()
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

readInputFile :: InputFile -> IO InputFileWithSource
readInputFile (InputFilePath path) =
  InputFileWithSource (InputFilePath path) <$> readSource path
readInputFile InputFromStdIn = InputFileWithSource InputFromStdIn <$> readStdin

applyFormatter :: Formatter -> InputFileWithSource -> ReformatResult
applyFormatter (Formatter format) (InputFileWithSource input source) =
  case format source of
    Left error        -> InvalidReformat input error
    Right reformatted -> Reformat input source reformatted

readSource :: HaskellSourceFilePath -> IO HaskellSource
readSource path = HaskellSource <$> readFile path

readStdin :: IO HaskellSource
readStdin = HaskellSource <$> getContents

sourceChangedOrHasSuggestions :: ReformatResult -> Bool
sourceChangedOrHasSuggestions (Reformat input source reformatted) =
  not (null (suggestions reformatted)) ||
  source /= reformattedSource reformatted