{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, GADTs #-} module System.Console.Wizard.Haskeline ( Haskeline , UnexpectedEOF (..) , runHaskeline , withSettings ) where import System.Console.Wizard import System.Console.Wizard.Internal import System.Console.Haskeline import Control.Monad.Trans import Control.Monad.Prompt import Control.Monad.Trans.Maybe import Control.Exception import Data.Typeable -- | A Haskeline backend for @wizards@, supporting input, output, default text, and password input. -- In addition, Haskeline settings can be modified for a single wizard, and arbitrary IO can be -- performed using the 'MonadIO' instance. data Haskeline m r = SetSettings (Settings IO) (m r) | ArbitraryIO (IO r) -- | The Haskeline back-end will throw this exception if EOF is encountered -- when it is not expected. Specifically, when actions such as 'getInputLine' return 'Nothing'. data UnexpectedEOF = UnexpectedEOF deriving (Show, Typeable) instance Exception UnexpectedEOF -- | Runs a Wizard action in the Haskeline backend. runHaskeline :: Wizard Haskeline a -> InputT IO (Maybe a) runHaskeline (Wizard c) = runRecPromptM f $ runMaybeT c where f :: WizardAction Haskeline (RecPrompt (WizardAction Haskeline) ) a -> InputT IO a f (Line s) = getInputLine s >>= maybeToException UnexpectedEOF f (Character s) = getInputChar s >>= maybeToException UnexpectedEOF f (Password s m) = getPassword m s >>= maybeToException UnexpectedEOF f (LinePreset s f b) = getInputLineWithInitial s (f,b) >>= maybeToException UnexpectedEOF f (Output s) = outputStr s f (OutputLn s) = outputStrLn s f (Backend (SetSettings s v)) = liftIO $ runInputT s (runRecPromptM f v) f (Backend (ArbitraryIO a)) = liftIO $ a -- | Modifies a wizard so that it will run with different Haskeline 'Settings' to the top level input monad. withSettings :: Settings IO -> Wizard Haskeline a -> Wizard Haskeline a withSettings sets (Wizard (MaybeT v)) = Wizard $ MaybeT $ prompt $ Backend $ SetSettings sets $ v instance MonadIO (Wizard Haskeline) where liftIO = prompt . Backend . ArbitraryIO maybeToException :: (Monad m, Exception e) => e -> Maybe a -> m a maybeToException e (Just v) = return v maybeToException e (Nothing) = throw e