module System.REPL.Prompt (
module Data.ListLike.IO,
putErr,
putErrLn,
prompt,
prompt',
promptAbort,
) where
import Prelude hiding (putStrLn, putStr, getLine, reverse)
import Control.Monad.Catch
import Control.Monad.IO.Class (MonadIO(liftIO))
import Data.ListLike(ListLike(empty, cons, reverse))
import Data.ListLike.IO (ListLikeIO(..))
import qualified System.IO as IO
import System.REPL.Types
putErr :: ListLikeIO full item => full -> IO ()
putErr = hPutStr IO.stderr
putErrLn :: ListLikeIO full item => full -> IO ()
putErrLn = hPutStrLn IO.stderr
prompt :: (MonadIO m, ListLikeIO full item) => m full
prompt = prompt' ("> " :: String)
prompt' :: (MonadIO m, ListLikeIO full item, ListLikeIO full' item')
=> full -> m full'
prompt' s = liftIO (putStr s >> IO.hFlush IO.stdout >> getLine)
promptAbort :: (MonadIO m, ListLikeIO full item, ListLikeIO full' Char,
MonadCatch m)
=> Char -> full -> m full'
promptAbort abortChar s = do
liftIO $ putStr s
liftIO $ IO.hFlush IO.stdout
bufMode <- liftIO $ IO.hGetBuffering IO.stdin
liftIO $ IO.hSetBuffering IO.stdin IO.NoBuffering
input <- getUntil empty
`catch` (\(e :: SomeAskerError) ->
liftIO (IO.hSetBuffering IO.stdin bufMode) >> throwM e)
liftIO $ IO.hSetBuffering IO.stdin bufMode
return $ reverse input
where
getUntil acc = do c <- liftIO $ getChar
if c == abortChar then throwM AskerInputAbortedError
else if c == '\n' then return acc
else getUntil (cons c acc)