ribosome-0.2.0.0: lib/Ribosome/Control/Monad/Trans/Ribo.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
module Ribosome.Control.Monad.Trans.Ribo where
import Control.Concurrent.STM.TVar (swapTVar)
import Control.Monad.Error.Class (MonadError(..))
import Control.Monad.State (MonadState(..))
import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT, mapExceptT)
import Control.Monad.Trans.Class
import Control.Monad.IO.Class (MonadIO)
import qualified Control.Monad.Trans.Except as Except (catchE)
import Data.Bifunctor (Bifunctor(..))
import Data.Either.Combinators (mapLeft)
import Data.Functor (void)
import UnliftIO.Exception (throwString)
import UnliftIO.STM (TVar, atomically, readTVarIO)
import Neovim (ask)
import Neovim.Context.Internal (Neovim)
import Ribosome.Control.Ribosome (Ribosome)
import qualified Ribosome.Control.Ribosome as Ribosome (env)
type Ribo e = Neovim (Ribosome (TVar e))
newtype RiboT t s e a =
RiboT { unRiboT :: ExceptT e (t (Ribo s)) a }
deriving instance Functor (t (Ribo s)) => Functor (RiboT t s e)
deriving instance Monad (t (Ribo s)) => Applicative (RiboT t s e)
deriving instance Monad (t (Ribo s)) => Monad (RiboT t s e)
deriving instance MonadIO (t (Ribo s)) => MonadIO (RiboT t s e)
deriving instance Monad (t (Ribo s)) => MonadError e (RiboT t s e)
nvim :: MonadTrans t => Neovim (Ribosome (TVar s)) a -> RiboT t s e a
nvim = RiboT . ExceptT . lift . fmap Right
asNeovim :: RiboT t s e a -> t (Ribo s) (Either e a)
asNeovim = runExceptT . unRiboT
asNeovimWith :: (∀ b. t (Ribo s) b -> Ribo s b) -> RiboT t s e a -> Ribo s (Either e a)
asNeovimWith run = run . runExceptT . unRiboT
mapE :: (Functor (t (Ribo s))) => (e -> e') -> RiboT t s e a -> RiboT t s e' a
mapE f =
RiboT . trans . unRiboT
where
trans = mapExceptT (fmap $ mapLeft f)
liftEither :: (Monad (t (Ribo s))) => Either e a -> RiboT t s e a
liftEither = RiboT . ExceptT . return
catchE :: (Monad (t (Ribo s))) => (e -> RiboT t s e' a) -> RiboT t s e a -> RiboT t s e' a
catchE f = RiboT . flip Except.catchE (unRiboT . f) . unRiboT
stateTVar :: (MonadTrans t, Functor (t (Ribo s))) => RiboT t s e (TVar s)
stateTVar =
Ribosome.env <$> nvim ask
toException :: Show e => Ribo s (Either e a) -> Ribo s a
toException ma = ma >>= either (throwString . show) return
unsafeToNeovim :: (MonadTrans t, Monad (t (Ribo s)), Show e) => RiboT t s e a -> t (Ribo s) a
unsafeToNeovim ra = do
r <- asNeovim ra
lift $ either (throwString . show) return r
unsafeToNeovimWith :: Show e => (∀ b. t (Ribo s) b -> Ribo s b) -> RiboT t s e a -> Ribo s a
unsafeToNeovimWith run =
toException . run . asNeovim
instance (MonadTrans t, Monad (t (Ribo s))) => MonadState s (RiboT t s e) where
get = do
t <- stateTVar
nvim $ readTVarIO t
put newState = do
t <- stateTVar
void $ nvim $ atomically $ swapTVar t newState
instance (Functor (t (Ribo s))) => Bifunctor (RiboT t s) where
first = mapE
second = fmap