module Data.Yaml.Pretty.Extras ( module Data.Yaml , module Data.Yaml.Pretty , ToPrettyYaml(..) , encodeFilePretty , displayPrettyYaml , PrettyYamlException(..) , decodeFileThrow , decodeFileThrowLogged , encodeFilePrettyLogged ) where import Control.Error.Safe import Control.Monad.Except import Data.Typeable import Data.Yaml import Data.Yaml.Pretty import RIO hiding ( tryJust ) import qualified RIO.ByteString as BS import RIO.List data PrettyYamlException = FieldNotListed Text [Text] deriving (Typeable) instance Show PrettyYamlException where show (FieldNotListed x as) = "Could not find field " ++ show x ++ "in " ++ show as exceptElemIndex x as = tryJust (FieldNotListed x as) (elemIndex x as) listElemCmp as x y = either (error . show) id $ runExcept $ liftA2 compare (exceptElemIndex x as) (exceptElemIndex y as) class ToJSON a => ToPrettyYaml a where fieldOrder :: a -> [Text] dropNull :: a -> Bool dropNull = const True toPrettyYaml :: a -> BS.ByteString toPrettyYaml = encodePretty =<< liftM2 setConfDropNull dropNull (flip setConfCompare defConfig . listElemCmp . fieldOrder) encodeFilePretty :: (MonadIO m) => ToPrettyYaml a => FilePath -> a -> m () encodeFilePretty f x = BS.writeFile f (toPrettyYaml x) displayPrettyYaml :: ToPrettyYaml a => a -> Utf8Builder displayPrettyYaml = displayBytesUtf8 . toPrettyYaml decodeFileThrow :: (MonadIO m, FromJSON c, MonadThrow m) => FilePath -> m c decodeFileThrow = liftIO . decodeFileEither >=> either throwM return decodeFileThrowLogged :: ( MonadReader env m , MonadThrow m , MonadIO m , HasLogFunc env , FromJSON b , ToPrettyYaml b , Typeable b ) => FilePath -> m b decodeFileThrowLogged x = do logInfo $ "Loading " <> displayShow x (t :: b) <- decodeFileThrow x logInfo $ mconcat [ "Loaded " , displayShow x , " as " , displayShow (typeOf t) , " with contents\n" , displayPrettyYaml t ] return t encodeFilePrettyLogged :: ( MonadReader env m , MonadThrow m , MonadIO m , HasLogFunc env , ToPrettyYaml b , Typeable b ) => FilePath -> b -> m () encodeFilePrettyLogged x d = do logInfo $ mconcat [ "Saving " , displayShow (typeOf d) , " with contents:\n" , displayPrettyYaml d , " to " , displayShow x ] encodeFilePretty x d logInfo $ "Saved " <> displayShow x