packages feed

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