hs-0.1.0.0: src/HS/Cfg/CfgFile.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module HS.Cfg.CfgFile where
import Data.Default
import Data.Text(Text)
import qualified Data.Text.IO as T
import Fmt
import System.Directory
import System.FilePath
import System.IO
import Text.Enum.Text
-- | enumeration for the @hs@ configuration files
data CfgFile
= CF_managers
| CF_mode
| CF_compiler
deriving stock (Bounded,Enum,Eq,Ord,Show)
deriving anyclass (EnumText)
deriving (Buildable,TextParsable) via UsingEnumText CfgFile
-- | load a configuration file
load :: forall a . (Default a,TextParsable a) => CfgFile -> IO a
load cf = rd =<< cfgFile cf
where
rd :: FilePath -> IO a
rd fp = do
yup <- doesFileExist fp
if | yup -> prs fp =<< T.readFile fp
| otherwise -> return def
prs :: FilePath -> Text -> IO a
prs fp = either (oops fp) return . parseText
oops :: FilePath -> String -> IO a
oops fp msg = do
hPutStr stderr $
"hs: warning: failed to parse "+||fp||+" with "+||msg||+"; using default"
return def
-- | save a configuration file
save :: Buildable a => CfgFile -> a -> IO ()
save cf x = flip T.writeFile (fmt $ build x) =<< cfgFile cf
-- | generate the 'FilePath' for a 'CfgFile'
cfgFile :: CfgFile -> IO FilePath
cfgFile cf = (</> (fmt $ build cf)) <$> dotHs
-- | generate the @hs@ configuration directory 'FilePath'
dotHs :: IO FilePath
dotHs = do
dhs <- (</> ".hs") <$> getHomeDirectory
const dhs <$> createDirectoryIfMissing True dhs