newtype App a = App { runApp :: ReaderT (Config Run) (ExceptT AppError IO) a }
deriving stock (Functor)
deriving newtype (MonadReader (Config Run), Applicative, Monad, MonadIO, MonadError AppError, MonadFail)
"ffxwt"
do
(configBuild, command) <- execParser opts
datadir <- getUserDataDir applicationName
let config = Options.configBuild datadir configBuild
result <- runExceptT . flip runReaderT config . runApp $ dispatch command
either handleError return result
where
opts = info (Options.mainOpts <**> helper)
(fullDesc
<> progDesc "Track your progress in Final Fantasy X"
<> header "ffxwt - Final Fantasy X WalkThrough")
handleError = putStrLn . ("error: " ++)
primerDispatch x
do
config <- ask
primers <- loadIndex
case command of
(Primer.Add vol loc) ->
case getPrimer vol primers of
Nothing -> throwError "Primer not found"
Just x -> saveIndex $ addLocation x loc primers
(Primer.New vol from to loc) ->
let newPrimer = Primer vol from to
index = case getPrimer vol primers of
Nothing -> Right $ addLocation newPrimer loc primers
Just x ->
if x == newPrimer
then Right $ addLocation newPrimer loc primers
else Left "The primer already exists and they differ in some fields"
in liftEither index >>= saveIndex
Primer.List opts ->
let doc = case opts of
Primer.OneLine -> toDoc oneline
Primer.MultiLine -> toDoc id
in liftIO . print . doc $ primers
type AppError = String
do
config <- ask
let filename = Options.fromRun $ Options.dataFile config
liftIO $ withFile filename WriteMode
(\handle -> let json = toJson index in TextIO.hPutStr handle $ Text.toStrict json)
do
config <- ask
let filename = Options.fromRun $ Options.dataFile config
fileExists <- liftIO $ doesFileExist filename
if fileExists
then liftIO (withFile filename ReadMode (ByteStringLazy.hGetContents >=> tryJust catchError . loadContent))
>>= liftEither
else
loadContent "[]"
where
catchError e = case ioe_type e of
UserError -> Just $ ioe_description e
_ -> Nothing
either fail pure . fromJson' @AlBhedIndex