module Taskell.IO where
import ClassyPrelude
import Control.Monad.Reader (runReader)
import Data.Text.Encoding (decodeUtf8With)
import System.Directory (doesFileExist, doesDirectoryExist, canonicalizePath, makeRelativeToCurrentDirectory)
import Data.Either (fromRight)
import Data.Time.Zones (TZ)
import Taskell.Config (githubUsage, trelloUsage, usage, version)
import Taskell.Data.Lists (Lists, analyse, initial)
import Taskell.IO.Config (Config, general, getDir, github, markdown, templatePath,
trello)
import Taskell.IO.Config.General (filename)
import qualified Taskell.IO.Config.GitHub as GitHub (token)
import qualified Taskell.IO.Config.Trello as Trello (token)
import Taskell.IO.Markdown (MarkdownInfo (MarkdownInfo), parse, serialize)
import qualified Taskell.IO.HTTP.GitHub as GitHub (GitHubIdentifier, getLists)
import qualified Taskell.IO.HTTP.Trello as Trello (TrelloBoardID, getLists)
import Taskell.UI.CLI (PromptYN (PromptYes), promptYN)
data IOInfo = IOInfo
{ IOInfo -> TZ
ioTZ :: TZ
, IOInfo -> Config
ioConfig :: Config
}
type ReaderConfig a = ReaderT IOInfo IO a
data Next
= Output Text
| Error Text
| Load FilePath
Lists
| Exit
getPath :: Text -> ReaderConfig FilePath
getPath :: Text -> ReaderConfig FilePath
getPath Text
path = do
Config
config <- (IOInfo -> Config) -> ReaderT IOInfo IO Config
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks IOInfo -> Config
ioConfig
FilePath
canonicial <- IO FilePath -> ReaderConfig FilePath
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO FilePath -> ReaderConfig FilePath)
-> IO FilePath -> ReaderConfig FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> IO FilePath
canonicalizePath (Text -> [Element Text]
forall mono. MonoFoldable mono => mono -> [Element mono]
unpack Text
path)
let defaultFilename :: FilePath
defaultFilename = Config -> FilePath
filename (Config -> Config
general Config
config)
Bool
isDir <- IO Bool -> ReaderT IOInfo IO Bool
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO Bool -> ReaderT IOInfo IO Bool)
-> IO Bool -> ReaderT IOInfo IO Bool
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesDirectoryExist FilePath
canonicial
FilePath -> ReaderConfig FilePath
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FilePath -> ReaderConfig FilePath)
-> FilePath -> ReaderConfig FilePath
forall a b. (a -> b) -> a -> b
$ if Bool
isDir then FilePath
canonicial FilePath -> FilePath -> FilePath
</> FilePath
defaultFilename else FilePath
canonicial
parseArgs :: [Text] -> ReaderConfig Next
parseArgs :: [Text] -> ReaderConfig Next
parseArgs [Text
"-v"] = Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Output Text
version
parseArgs [Text
"-h"] = Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Output Text
usage
parseArgs [Text
"-t", Text
boardID, Text
file] = Text -> ReaderConfig FilePath
getPath Text
file ReaderConfig FilePath
-> (FilePath -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> FilePath -> ReaderConfig Next
loadTrello Text
boardID
parseArgs [Text
"-g", Text
identifier, Text
file] = Text -> ReaderConfig FilePath
getPath Text
file ReaderConfig FilePath
-> (FilePath -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Text -> FilePath -> ReaderConfig Next
loadGitHub Text
identifier
parseArgs [Text
"-i", Text
file] = Text -> ReaderConfig FilePath
getPath Text
file ReaderConfig FilePath
-> (FilePath -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FilePath -> ReaderConfig Next
fileInfo
parseArgs [Text
file] = Text -> ReaderConfig FilePath
getPath Text
file ReaderConfig FilePath
-> (FilePath -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FilePath -> ReaderConfig Next
loadFile
parseArgs [] = Text -> ReaderConfig FilePath
getPath Text
"" ReaderConfig FilePath
-> (FilePath -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FilePath -> ReaderConfig Next
loadFile
parseArgs [Text]
_ = Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Error ([Text] -> Text
forall t seq.
(Textual t, Element seq ~ t, MonoFoldable seq) =>
seq -> t
unlines [Text
"Invalid options", Text
"", Text
usage])
load :: ReaderConfig Next
load :: ReaderConfig Next
load = ReaderT IOInfo IO [Text]
forall (m :: * -> *). MonadIO m => m [Text]
getArgs ReaderT IOInfo IO [Text]
-> ([Text] -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [Text] -> ReaderConfig Next
parseArgs
colonic :: FilePath -> Text -> Text
colonic :: FilePath -> Text -> Text
colonic FilePath
path = (([Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack FilePath
[Element Text]
path Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
": ") Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>)
createLoad :: FilePath -> Lists -> ReaderConfig Next
createLoad :: FilePath -> Lists -> ReaderConfig Next
createLoad FilePath
path Lists
lists = do
FilePath
relative <- IO FilePath -> ReaderConfig FilePath
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO FilePath -> ReaderConfig FilePath)
-> IO FilePath -> ReaderConfig FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> IO FilePath
makeRelativeToCurrentDirectory FilePath
path
Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ FilePath -> Lists -> Next
Load FilePath
relative Lists
lists
loadFile :: FilePath -> ReaderConfig Next
loadFile :: FilePath -> ReaderConfig Next
loadFile FilePath
filepath = do
Maybe FilePath
mPath <- FilePath -> ReaderConfig (Maybe FilePath)
exists FilePath
filepath
case Maybe FilePath
mPath of
Maybe FilePath
Nothing -> Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure Next
Exit
Just FilePath
path -> do
Either Text Lists
lists <- FilePath -> ReaderConfig (Either Text Lists)
readData FilePath
path
case Either Text Lists
lists of
Left Text
err -> Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Error (FilePath -> Text -> Text
colonic FilePath
path Text
err)
Right Lists
ls -> FilePath -> Lists -> ReaderConfig Next
createLoad FilePath
path Lists
ls
loadRemote :: (token -> FilePath -> ReaderConfig Next) -> token -> FilePath -> ReaderConfig Next
loadRemote :: (token -> FilePath -> ReaderConfig Next)
-> token -> FilePath -> ReaderConfig Next
loadRemote token -> FilePath -> ReaderConfig Next
createFn token
identifier FilePath
path = do
Bool
exists' <- FilePath -> ReaderT IOInfo IO Bool
fileExists FilePath
path
if Bool
exists'
then Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Error ([Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack FilePath
[Element Text]
path Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" already exists")
else token -> FilePath -> ReaderConfig Next
createFn token
identifier FilePath
path
loadTrello :: Trello.TrelloBoardID -> FilePath -> ReaderConfig Next
loadTrello :: Text -> FilePath -> ReaderConfig Next
loadTrello = (Text -> FilePath -> ReaderConfig Next)
-> Text -> FilePath -> ReaderConfig Next
forall token.
(token -> FilePath -> ReaderConfig Next)
-> token -> FilePath -> ReaderConfig Next
loadRemote Text -> FilePath -> ReaderConfig Next
createTrello
loadGitHub :: GitHub.GitHubIdentifier -> FilePath -> ReaderConfig Next
loadGitHub :: Text -> FilePath -> ReaderConfig Next
loadGitHub = (Text -> FilePath -> ReaderConfig Next)
-> Text -> FilePath -> ReaderConfig Next
forall token.
(token -> FilePath -> ReaderConfig Next)
-> token -> FilePath -> ReaderConfig Next
loadRemote Text -> FilePath -> ReaderConfig Next
createGitHub
fileInfo :: FilePath -> ReaderConfig Next
fileInfo :: FilePath -> ReaderConfig Next
fileInfo FilePath
path = do
Bool
exists' <- FilePath -> ReaderT IOInfo IO Bool
fileExists FilePath
path
if Bool
exists'
then (Text -> Next) -> (Lists -> Next) -> Either Text Lists -> Next
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Text -> Next
Error (Text -> Next) -> (Text -> Text) -> Text -> Next
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilePath -> Text -> Text
colonic FilePath
path) (Text -> Next
Output (Text -> Next) -> (Lists -> Text) -> Lists -> Next
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Lists -> Text
analyse ([Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack FilePath
[Element Text]
path)) (Either Text Lists -> Next)
-> ReaderConfig (Either Text Lists) -> ReaderConfig Next
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> ReaderConfig (Either Text Lists)
readData FilePath
path
else Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Error ([Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack FilePath
[Element Text]
path Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" does not exist")
createRemote ::
(Config -> Maybe token)
-> Text
-> (token -> ReaderT token IO (Either Text Lists))
-> token
-> FilePath
-> ReaderConfig Next
createRemote :: (Config -> Maybe token)
-> Text
-> (token -> ReaderT token IO (Either Text Lists))
-> token
-> FilePath
-> ReaderConfig Next
createRemote Config -> Maybe token
tokenFn Text
missingToken token -> ReaderT token IO (Either Text Lists)
getFn token
identifier FilePath
path = do
Config
config <- (IOInfo -> Config) -> ReaderT IOInfo IO Config
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks IOInfo -> Config
ioConfig
TZ
tz <- (IOInfo -> TZ) -> ReaderT IOInfo IO TZ
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks IOInfo -> TZ
ioTZ
case Config -> Maybe token
tokenFn Config
config of
Maybe token
Nothing -> Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Error Text
missingToken
Just token
token -> do
Either Text Lists
lists <- IO (Either Text Lists) -> ReaderConfig (Either Text Lists)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO (Either Text Lists) -> ReaderConfig (Either Text Lists))
-> IO (Either Text Lists) -> ReaderConfig (Either Text Lists)
forall a b. (a -> b) -> a -> b
$ ReaderT token IO (Either Text Lists)
-> token -> IO (Either Text Lists)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (token -> ReaderT token IO (Either Text Lists)
getFn token
identifier) token
token
case Either Text Lists
lists of
Left Text
txt -> Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Next -> ReaderConfig Next) -> Next -> ReaderConfig Next
forall a b. (a -> b) -> a -> b
$ Text -> Next
Error Text
txt
Right Lists
ls -> do
FilePath -> ReaderT IOInfo IO Bool
promptCreate FilePath
path ReaderT IOInfo IO Bool
-> (Bool -> ReaderConfig Next) -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ReaderConfig Next -> ReaderConfig Next -> Bool -> ReaderConfig Next
forall a. a -> a -> Bool -> a
bool (Next -> ReaderConfig Next
forall (f :: * -> *) a. Applicative f => a -> f a
pure Next
Exit) (IO () -> ReaderT IOInfo IO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TZ -> Config -> Lists -> FilePath -> IO ()
writeData TZ
tz Config
config Lists
ls FilePath
path) ReaderT IOInfo IO () -> ReaderConfig Next -> ReaderConfig Next
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FilePath -> Lists -> ReaderConfig Next
createLoad FilePath
path Lists
ls)
createTrello :: Trello.TrelloBoardID -> FilePath -> ReaderConfig Next
createTrello :: Text -> FilePath -> ReaderConfig Next
createTrello = (Config -> Maybe Text)
-> Text
-> (Text -> ReaderT Text IO (Either Text Lists))
-> Text
-> FilePath
-> ReaderConfig Next
forall token.
(Config -> Maybe token)
-> Text
-> (token -> ReaderT token IO (Either Text Lists))
-> token
-> FilePath
-> ReaderConfig Next
createRemote (Config -> Maybe Text
Trello.token (Config -> Maybe Text)
-> (Config -> Config) -> Config -> Maybe Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Config -> Config
trello) Text
trelloUsage Text -> ReaderT Text IO (Either Text Lists)
Trello.getLists
createGitHub :: GitHub.GitHubIdentifier -> FilePath -> ReaderConfig Next
createGitHub :: Text -> FilePath -> ReaderConfig Next
createGitHub = (Config -> Maybe Text)
-> Text
-> (Text -> ReaderT Text IO (Either Text Lists))
-> Text
-> FilePath
-> ReaderConfig Next
forall token.
(Config -> Maybe token)
-> Text
-> (token -> ReaderT token IO (Either Text Lists))
-> token
-> FilePath
-> ReaderConfig Next
createRemote (Config -> Maybe Text
GitHub.token (Config -> Maybe Text)
-> (Config -> Config) -> Config -> Maybe Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Config -> Config
github) Text
githubUsage Text -> ReaderT Text IO (Either Text Lists)
GitHub.getLists
exists :: FilePath -> ReaderConfig (Maybe FilePath)
exists :: FilePath -> ReaderConfig (Maybe FilePath)
exists FilePath
path = do
Bool
exists' <- FilePath -> ReaderT IOInfo IO Bool
fileExists FilePath
path
if Bool
exists'
then Maybe FilePath -> ReaderConfig (Maybe FilePath)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe FilePath -> ReaderConfig (Maybe FilePath))
-> Maybe FilePath -> ReaderConfig (Maybe FilePath)
forall a b. (a -> b) -> a -> b
$ FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
path
else FilePath -> ReaderT IOInfo IO Bool
promptCreate FilePath
path ReaderT IOInfo IO Bool
-> (Bool -> ReaderConfig (Maybe FilePath))
-> ReaderConfig (Maybe FilePath)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ReaderConfig (Maybe FilePath)
-> ReaderConfig (Maybe FilePath)
-> Bool
-> ReaderConfig (Maybe FilePath)
forall a. a -> a -> Bool -> a
bool (Maybe FilePath -> ReaderConfig (Maybe FilePath)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe FilePath
forall a. Maybe a
Nothing) (FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
path Maybe FilePath
-> ReaderT IOInfo IO () -> ReaderConfig (Maybe FilePath)
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ FilePath -> ReaderT IOInfo IO ()
createPath FilePath
path)
fileExists :: FilePath -> ReaderConfig Bool
fileExists :: FilePath -> ReaderT IOInfo IO Bool
fileExists FilePath
path = IO Bool -> ReaderT IOInfo IO Bool
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO Bool -> ReaderT IOInfo IO Bool)
-> IO Bool -> ReaderT IOInfo IO Bool
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
path
promptCreate :: FilePath -> ReaderConfig Bool
promptCreate :: FilePath -> ReaderT IOInfo IO Bool
promptCreate FilePath
path = IO Bool -> ReaderT IOInfo IO Bool
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO Bool -> ReaderT IOInfo IO Bool)
-> IO Bool -> ReaderT IOInfo IO Bool
forall a b. (a -> b) -> a -> b
$ PromptYN -> Text -> IO Bool
promptYN PromptYN
PromptYes (Text -> IO Bool) -> Text -> IO Bool
forall a b. (a -> b) -> a -> b
$ [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat [Text
"Create ", [Element Text] -> Text
forall seq. IsSequence seq => [Element seq] -> seq
pack FilePath
[Element Text]
path, Text
"?"]
createPath :: FilePath -> ReaderConfig ()
createPath :: FilePath -> ReaderT IOInfo IO ()
createPath FilePath
path = do
Config
config <- (IOInfo -> Config) -> ReaderT IOInfo IO Config
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks IOInfo -> Config
ioConfig
TZ
tz <- (IOInfo -> TZ) -> ReaderT IOInfo IO TZ
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks IOInfo -> TZ
ioTZ
Either Text Lists
template <- FilePath -> ReaderConfig (Either Text Lists)
readData (FilePath -> ReaderConfig (Either Text Lists))
-> (FilePath -> FilePath)
-> FilePath
-> ReaderConfig (Either Text Lists)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilePath -> FilePath
templatePath (FilePath -> ReaderConfig (Either Text Lists))
-> ReaderConfig FilePath -> ReaderConfig (Either Text Lists)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO FilePath -> ReaderConfig FilePath
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift IO FilePath
getDir
let ls :: Lists
ls = Lists -> Either Text Lists -> Lists
forall b a. b -> Either a b -> b
fromRight Lists
initial Either Text Lists
template
IO () -> ReaderT IOInfo IO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (TZ -> Config -> Lists -> FilePath -> IO ()
writeData TZ
tz Config
config Lists
ls FilePath
path)
writeData :: TZ -> Config -> Lists -> FilePath -> IO ()
writeData :: TZ -> Config -> Lists -> FilePath -> IO ()
writeData TZ
tz Config
config Lists
tasks FilePath
path = IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (FilePath -> ByteString -> IO ()
forall (m :: * -> *). MonadIO m => FilePath -> ByteString -> m ()
writeFile FilePath
path ByteString
output)
where
output :: ByteString
output = Text -> ByteString
forall textual binary. Utf8 textual binary => textual -> binary
encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Reader MarkdownInfo Text -> MarkdownInfo -> Text
forall r a. Reader r a -> r -> a
runReader (Lists -> Reader MarkdownInfo Text
serialize Lists
tasks) (TZ -> Config -> MarkdownInfo
MarkdownInfo TZ
tz (Config -> Config
markdown Config
config))
decodeError :: String -> Maybe Word8 -> Maybe Char
decodeError :: FilePath -> Maybe Word8 -> Maybe Char
decodeError FilePath
_ Maybe Word8
_ = Char -> Maybe Char
forall a. a -> Maybe a
Just Char
'\65533'
readData :: FilePath -> ReaderConfig (Either Text Lists)
readData :: FilePath -> ReaderConfig (Either Text Lists)
readData FilePath
path =
Config -> Text -> Either Text Lists
parse (Config -> Text -> Either Text Lists)
-> ReaderT IOInfo IO Config
-> ReaderT IOInfo IO (Text -> Either Text Lists)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Config -> Config
markdown (Config -> Config)
-> ReaderT IOInfo IO Config -> ReaderT IOInfo IO Config
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (IOInfo -> Config) -> ReaderT IOInfo IO Config
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks IOInfo -> Config
ioConfig) ReaderT IOInfo IO (Text -> Either Text Lists)
-> ReaderT IOInfo IO Text -> ReaderConfig (Either Text Lists)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ((FilePath -> Maybe Word8 -> Maybe Char) -> ByteString -> Text
decodeUtf8With FilePath -> Maybe Word8 -> Maybe Char
decodeError (ByteString -> Text)
-> ReaderT IOInfo IO ByteString -> ReaderT IOInfo IO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> ReaderT IOInfo IO ByteString
forall (m :: * -> *). MonadIO m => FilePath -> m ByteString
readFile FilePath
path)