module Require where

import qualified Data.Text as Text
import Options.Generic
import Relude
import System.Directory
import qualified Require.Error as Error
import qualified Require.File as File
import Require.Transform
import Require.Types


data CommandArguments
  = CommandArguments Text Text Text
  deriving ((forall x. CommandArguments -> Rep CommandArguments x)
-> (forall x. Rep CommandArguments x -> CommandArguments)
-> Generic CommandArguments
forall x. Rep CommandArguments x -> CommandArguments
forall x. CommandArguments -> Rep CommandArguments x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep CommandArguments x -> CommandArguments
$cfrom :: forall x. CommandArguments -> Rep CommandArguments x
Generic)

instance ParseRecord CommandArguments

findRequires :: IO (Maybe File.Name)
findRequires :: IO (Maybe Name)
findRequires = do
  FilePath
currentDir <- IO FilePath
getCurrentDirectory
  [FilePath]
files <- FilePath -> IO [FilePath]
getDirectoryContents FilePath
currentDir
  let textFiles :: [Text]
textFiles = (FilePath -> Text) -> [FilePath] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> Text
forall a. ToText a => a -> Text
toText [FilePath]
files
  Maybe Name -> IO (Maybe Name)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Name -> IO (Maybe Name)) -> Maybe Name -> IO (Maybe Name)
forall a b. (a -> b) -> a -> b
$ Text -> Name
File.Name (Text -> Name) -> (NonEmpty Text -> Text) -> NonEmpty Text -> Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty Text -> Text
forall (f :: * -> *) a. IsNonEmpty f a a "head" => f a -> a
head (NonEmpty Text -> Name) -> Maybe (NonEmpty Text) -> Maybe Name
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text] -> Maybe (NonEmpty Text)
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty ((Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (Text -> Text -> Bool
Text.isSuffixOf Text
"Requires") [Text]
textFiles)

requireMain :: IO ()
requireMain :: IO ()
requireMain = do
  CommandArguments Text
inputFile Text
_ Text
outputFile <- Text -> IO CommandArguments
forall (io :: * -> *) a.
(MonadIO io, ParseRecord a) =>
Text -> io a
getRecord Text
"Require Haskell preprocessor" :: IO CommandArguments
  Maybe Name
requiresFile <- IO (Maybe Name)
findRequires
  AutorequireMode Name -> Name -> Name -> IO ()
run (Maybe Name -> AutorequireMode Name
forall a. Maybe a -> AutorequireMode a
AutorequireOnDirective Maybe Name
requiresFile) (Text -> Name
File.Name Text
inputFile) (Text -> Name
File.Name Text
outputFile)

autorequireMain :: IO ()
autorequireMain :: IO ()
autorequireMain = do
  CommandArguments Text
inputFile Text
_ Text
outputFile <- Text -> IO CommandArguments
forall (io :: * -> *) a.
(MonadIO io, ParseRecord a) =>
Text -> io a
getRecord Text
"Require Haskell preprocessor" :: IO CommandArguments
  Maybe Name
requiresFile <- IO (Maybe Name)
findRequires
  case Maybe Name
requiresFile of
    Maybe Name
Nothing -> Name -> Error -> IO ()
forall a. Name -> Error -> IO a
Error.die (Text -> Name
File.Name Text
inputFile) Error
Error.MissingRequiresFile
    Just Name
fn -> AutorequireMode Name -> Name -> Name -> IO ()
run (Name -> AutorequireMode Name
forall a. a -> AutorequireMode a
AutorequireEnabled Name
fn) (Text -> Name
File.Name Text
inputFile) (Text -> Name
File.Name Text
outputFile)

run :: AutorequireMode File.Name -> File.Name -> File.Name -> IO ()
run :: AutorequireMode Name -> Name -> Name -> IO ()
run AutorequireMode Name
autoMode Name
inputFile Name
outputFile = do
  Input
input <- Name -> IO Input
File.read Name
inputFile
  AutorequireMode Input
autoInput <- (Name -> IO Input)
-> AutorequireMode Name -> IO (AutorequireMode Input)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Name -> IO Input
File.read AutorequireMode Name
autoMode
  case AutorequireMode Input -> Input -> Either Error [Text]
transform AutorequireMode Input
autoInput Input
input of
    Left Error
err -> Name -> Error -> IO ()
forall a. Name -> Error -> IO a
Error.die Name
inputFile Error
err
    Right [Text]
ls -> Name -> [Text] -> IO ()
File.writeLines Name
outputFile [Text]
ls