{-# LANGUAGE FlexibleContexts, TypeOperators, Trustworthy #-}
{-# LANGUAGE UndecidableInstances #-}
module System.Console.Wizard
(
Wizard (..)
, PromptString (..)
, run
, (:<:)
, (:+:)
, Line
, line
, LinePrewritten
, linePrewritten
, Password
, password
, Character
, character
, Output
, output
, OutputLn
, outputLn
, ArbitraryIO
, retry
, retryMsg
, defaultTo
, parser
, validator
, nonEmpty
, inRange
, parseRead
, liftMaybe
, ensure
, readP
) where
import System.Console.Wizard.Internal
import Control.Applicative
import Control.Monad.Trans.Maybe
import Control.Monad.Trans
import Control.Monad.Free
import Control.Monad.Reader
import Data.Maybe
import Data.Monoid
output :: (Output :<: b) => String -> Wizard b ()
output s = Wizard $ lift $ inject (Output s (Pure ()))
outputLn :: (OutputLn :<: b) => String -> Wizard b ()
outputLn s = Wizard $ lift $ inject (OutputLn s (Pure ()))
line :: (Line :<: b) => PromptString -> Wizard b String
line s = Wizard $ lift $ inject (Line s Pure)
character :: (Character :<: b)
=> PromptString
-> Wizard b Char
character p = Wizard $ lift $ inject (Character p Pure)
instance (ArbitraryIO :<: b) => MonadIO (Wizard b) where
liftIO v = Wizard $ lift $ inject (ArbitraryIO v Pure)
linePrewritten :: (LinePrewritten :<: b)
=> PromptString
-> String
-> String
-> Wizard b String
linePrewritten p s1 s2 = Wizard $ lift $ inject (LinePrewritten p s1 s2 Pure)
password :: (Password :<: b)
=> PromptString
-> Maybe Char
-> Wizard b String
password p mc = Wizard $ lift $ inject (Password p mc Pure)
retry :: Functor b => Wizard b a -> Wizard b a
retry x = x <|> retry x
retryMsg :: (OutputLn :<: b) => String -> Wizard b a -> Wizard b a
retryMsg msg x = x <|> (outputLn msg >> retryMsg msg x)
defaultTo :: Functor b => Wizard b a -> a -> Wizard b a
defaultTo wz d = wz <|> pure d
parser :: Functor b => (a -> Maybe c) -> Wizard b a -> Wizard b c
parser f a = a >>= liftMaybe . f
validator :: Functor b => (a -> Bool) -> Wizard b a -> Wizard b a
validator = parser . ensure
nonEmpty :: Functor b => Wizard b [a] -> Wizard b [a]
nonEmpty = validator (not . null)
inRange :: (Ord a, Functor b) => (a,a) -> Wizard b a -> Wizard b a
inRange (b,t) = validator (\x -> b <= x && x <= t)
parseRead :: (Read a, Functor b) => Wizard b String -> Wizard b a
parseRead = parser (readP)
liftMaybe :: Functor b => Maybe a -> Wizard b a
liftMaybe (Just v) = pure v
liftMaybe (Nothing) = mzero
ensure :: (a -> Bool) -> a -> Maybe a
ensure p v | p v = Just v
| otherwise = Nothing
readP :: Read a => String -> Maybe a
readP = fmap fst . listToMaybe . reads