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
"?"]

-- creates taskell file
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)

-- writes Tasks to json file
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))

-- reads json file
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)