{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, FlexibleInstances, TypeOperators, DoAndIfThenElse, GeneralizedNewtypeDeriving, Trustworthy #-} module System.Console.Wizard.Pure ( Pure , UnexpectedEOI (..) , runPure , PureState (..) ) where import System.Console.Wizard import System.Console.Wizard.Internal import Control.Monad.Trans import Control.Monad.State.Lazy import Control.Monad.Trans.Maybe import Control.Applicative((<$>)) import Data.Typeable import Data.Sequence(Seq, (|>), (><), fromList, empty) import Control.Monad import Control.Exception import Control.Arrow import Data.Foldable(toList) -- | Thrown if the wizard ever unexpectedly runs out of input. data UnexpectedEOI = UnexpectedEOI deriving (Show, Typeable) instance Exception UnexpectedEOI -- | The pure backend is actually just a simple state monad, with the following state. type PureState = ([String], Seq Char) -- | Run a wizard in the Pure backend runPure :: Wizard Pure a -> String -> (Maybe a, String) runPure wz input = let (a,(_,o)) = runState (run wz) (lines input, empty) in (a, toList o) getPureLine :: State PureState String getPureLine = do crashIfNull x <- head . fst <$> get modify (first tail) return x crashIfNull :: State PureState () crashIfNull = do (x, y ) <- get when (null x) $ throw UnexpectedEOI getPureChar :: State PureState Char getPureChar = do crashIfNull x <- null . head . fst <$> get if x then do modify (first tail) return '\n' else do r <- head . head . fst <$> get modify (first (\ (x : r) -> tail x : r)) return r outputPure :: String -> State PureState () outputPure s = modify (second (>< fromList s)) >> modify (\s -> s `seq` s) outputLnPure :: String -> State PureState () outputLnPure s = modify (second $ (|> '\n') . (>< fromList s)) >> modify (\s -> s `seq` s) instance Run (State PureState) Output where runAlgebra (Output s w) = outputPure s >> w instance Run (State PureState) OutputLn where runAlgebra (OutputLn s w) = outputLnPure s >> w instance Run (State PureState) Line where runAlgebra (Line s w) = getPureLine >>= w instance Run (State PureState) Character where runAlgebra (Character s w) = getPureChar >>= w -- | The 'Pure' backend supports only simple input and output. -- Support for 'Password' and 'LinePrewritten' features can be added with -- a shim from "System.Console.Wizard.Shim". newtype Pure a = Pure ((Output :+: OutputLn :+: Line :+: Character) a) deriving ( (:<:) Output , (:<:) OutputLn , (:<:) Line , (:<:) Character , Functor , Run (State PureState) )