hinit-0.1.0: src/Control/Effect/Terminal.hs
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Effect.Terminal where
import Control.Algebra
import Control.Monad.Catch (MonadMask)
import Control.Monad.IO.Class
import Data.Functor
import Data.Kind
import Data.Text (Text, pack)
import Data.Text.Prettyprint.Doc
import Prettyprinter.Render.Terminal
import System.Console.Haskeline
import System.IO
data Terminal (m :: Type -> Type) a where
PrettyPrint :: Handle -> Doc AnsiStyle -> Terminal m ()
Prompt :: String -> Terminal m (Maybe Text)
prettyPrint :: Has Terminal sig m => Handle -> Doc AnsiStyle -> m ()
prettyPrint handle doc = send $ PrettyPrint handle $ doc <> "\n"
prompt :: Has Terminal sig m => String -> m (Maybe Text)
prompt = send . Prompt
newtype TerminalC m a = TerminalC {runTerminalC :: InputT m a}
deriving newtype (Functor, Applicative, Monad, MonadIO)
runTerminal' :: (MonadIO m, MonadMask m) => Settings m -> TerminalC m a -> m a
runTerminal' s = runInputT s . runTerminalC
runTerminal :: (MonadIO m, MonadMask m) => TerminalC m a -> m a
runTerminal = runTerminal' $ setComplete noCompletion defaultSettings
instance (MonadMask m, MonadIO m, Algebra sig m) => Algebra (Terminal :+: sig) (TerminalC m) where
alg hdl sig ctx = TerminalC $
case sig of
L (PrettyPrint handle doc) -> do
liftIO $ renderIO handle $ layoutSmart defaultLayoutOptions doc
pure $ ctx $> ()
L (Prompt p) -> do
res <- getInputLine p
pure $ ctx $> fmap pack res
R other -> withRunInBase $ \runInput -> alg (runInput . runTerminalC . hdl) other ctx