ribosome-0.4.0.0: lib/Ribosome/Control/Monad/Ribo.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Ribosome.Control.Monad.Ribo where
import Control.Exception.Lifted (onException)
import Control.Lens (Lens')
import qualified Control.Lens as Lens (mapMOf, over, view)
import Control.Monad.Base (MonadBase(..))
import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
import Control.Monad.Error.Class (MonadError(..))
import qualified Control.Monad.Reader as ReaderT
import Control.Monad.Trans.Free (FreeT)
import Control.Monad.Trans.Resource (MonadResource(..), runResourceT)
import qualified Control.Monad.Trans.State.Strict as StateT (gets, modify)
import Data.DeepLenses (DeepLenses(deepLens))
import Data.DeepPrisms (DeepPrisms)
import Neovim.Context.Internal (Neovim(..))
import Ribosome.Control.Ribosome (Ribosome, RibosomeInternal, RibosomeState)
import qualified Ribosome.Control.Ribosome as Ribosome (_errors, errors, name, state)
import qualified Ribosome.Control.Ribosome as RibosomeState (internal, public)
import Ribosome.Control.StrictRibosome (StrictRibosome)
import qualified Ribosome.Control.StrictRibosome as StrictRibosome (name, state)
import Ribosome.Data.Errors (Errors)
import Ribosome.Nvim.Api.RpcCall (Rpc, RpcError)
import qualified Ribosome.Nvim.Api.RpcCall as Rpc (Rpc(..))
import Ribosome.Orphans ()
import Ribosome.Plugin.RpcHandler (RpcHandler(..))
type RNeovim s = Neovim (Ribosome s)
instance MonadBase IO (Neovim e) where
liftBase = liftIO
instance MonadBaseControl IO (Neovim e) where
type StM (Neovim e) a = a
liftBaseWith f =
Neovim (lift $ ReaderT $ \r -> f (peel r))
where
peel r ma =
runReaderT (runResourceT (unNeovim ma)) r
restoreM = return
newtype Ribo s e a =
Ribo { unRibo :: ExceptT e (RNeovim s) a }
deriving newtype (Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch, MonadMask, MonadFail, MonadBase IO)
deriving newtype instance MonadError e (Ribo s e)
modifyTMVar ::
MonadIO m =>
(a -> a) ->
TMVar a ->
m a
modifyTMVar f tmvar = do
a <- f <$> atomically (takeTMVar tmvar)
atomically $ putTMVar tmvar a
return a
safeModifyTMVarM ::
MonadIO m =>
MonadBaseControl IO m =>
(a -> m a) ->
TMVar a ->
m a
safeModifyTMVarM f tmvar =
process =<< atomically (takeTMVar tmvar)
where
process a =
onException (restore =<< f a) (restore a)
restore a =
a <$ (atomically . putTMVar tmvar $ a)
deriving newtype instance MonadReader (Ribosome s) (Ribo s e)
riboStateVar ::
MonadReader (Ribosome s) m =>
m (TMVar (RibosomeState s))
riboStateVar =
ReaderT.asks (Lens.view Ribosome.state)
public ::
DeepLenses s s' =>
Lens' (RibosomeState s) s'
public =
RibosomeState.public . deepLens
instance DeepLenses s s' => MonadDeepState s s' (Ribo s e) where
get =
Lens.view public <$> (atomically . readTMVar =<< riboStateVar)
modifyM' f =
Lens.view public <$> (safeModifyTMVarM trans =<< riboStateVar)
where
trans = Lens.mapMOf public f
put =
modify . const
class Monad m => Nvim m where
call :: Rpc c a => c -> m (Either RpcError a)
instance Nvim (Neovim e) where
call = Rpc.call
instance (MonadTrans t, Monad (t m), Nvim m) => Nvim (t m) where
call = lift . call
instance Nvim (Ribo s e) where
call = Ribo . call
class (Nvim m, MonadDeepError e RpcError m) => NvimE e m where
instance DeepPrisms e RpcError => NvimE e (Ribo s e) where
instance (DeepPrisms e RpcError, Nvim m, Monad m) => NvimE e (ExceptT e m) where
instance (Functor f, MonadDeepError e RpcError m, Nvim m, Monad m) => NvimE e (FreeT f m) where
instance MonadBaseControl IO (Ribo s e) where
type StM (Ribo s e) a = Either e a
liftBaseWith f =
Ribo $ liftBaseWith $ \ q -> f (q . unRibo)
{-# INLINABLE liftBaseWith #-}
restoreM =
Ribo . restoreM
{-# INLINABLE restoreM #-}
instance MonadResource (Ribo s e) where
liftResourceT = Ribo . liftResourceT
instance RpcHandler e (Ribosome s) (Ribo s e) where
native = runRiboE
acall :: (Monad m, Nvim m, Rpc c ()) => c -> m ()
acall c = fromRight () <$> call c
readTv :: Lens' (RibosomeState s) s' -> TMVar (RibosomeState s) -> IO s'
readTv l t = Lens.view l <$> atomically (readTMVar t)
runRibo :: Ribo s e a -> RNeovim s (Either e a)
runRibo =
runExceptT . unRibo
runRiboE :: Ribo s e a -> ExceptT e (RNeovim s) a
runRiboE =
unRibo
class PluginName m where
pluginName1 :: m Text
instance PluginName IO where
pluginName1 = pure "io"
instance PluginName (RNeovim s) where
pluginName1 =
ReaderT.asks (Lens.view Ribosome.name)
class MonadIO m => MonadRibo m where
pluginName :: m Text
pluginInternal :: m RibosomeInternal
pluginInternalModify :: (RibosomeInternal -> RibosomeInternal) -> m ()
pluginInternals :: MonadRibo m => (RibosomeInternal -> a) -> m a
pluginInternals = (<$> pluginInternal)
pluginInternalL :: MonadRibo m => Lens' RibosomeInternal a -> m a
pluginInternalL = pluginInternals . Lens.view
pluginInternalPut' :: MonadRibo m => RibosomeInternal -> m ()
pluginInternalPut' s =
pluginInternalModify (const s)
pluginInternalModifyL :: MonadRibo m => Lens' RibosomeInternal a -> (a -> a) -> m ()
pluginInternalModifyL l f =
pluginInternalModify $ Lens.over l f
instance MonadRibo (RNeovim s) where
pluginName =
ReaderT.asks (Lens.view Ribosome.name)
pluginInternal =
Lens.view RibosomeState.internal <$$> atomically . readTMVar =<< ReaderT.asks (Lens.view Ribosome.state)
pluginInternalModify f =
void . modifyTMVar (Lens.over RibosomeState.internal f) =<< riboStateVar
instance MonadRibo (Ribo s e) where
pluginName = Ribo pluginName
pluginInternal = Ribo pluginInternal
pluginInternalModify = Ribo . pluginInternalModify
instance {-# OVERLAPPABLE #-} (MonadTrans t, MonadIO (t m), MonadRibo m) => MonadRibo (t m) where
pluginName = lift pluginName
pluginInternal = lift pluginInternal
pluginInternalModify = lift . pluginInternalModify
instance {-# OVERLAPPING #-} MonadIO m => MonadRibo (StateT (StrictRibosome s) m) where
pluginName =
StateT.gets (Lens.view StrictRibosome.name)
pluginInternal =
StateT.gets (Lens.view $ StrictRibosome.state . RibosomeState.internal)
pluginInternalModify =
StateT.modify . Lens.over (StrictRibosome.state . RibosomeState.internal)
getErrors :: MonadRibo m => m Errors
getErrors =
pluginInternals Ribosome._errors
inspectErrors :: MonadRibo m => (Errors -> a) -> m a
inspectErrors = (<$> getErrors)
modifyErrors :: MonadRibo m => (Errors -> Errors) -> m ()
modifyErrors =
pluginInternalModifyL Ribosome.errors
prepend :: ∀s' s m a. MonadDeepState s s' m => Lens' s' [a] -> a -> m ()
prepend lens a =
modify $ Lens.over lens (a:)
prependUnique ::
∀ s' s m a .
Eq a =>
MonadDeepState s s' m =>
Lens' s' [a] ->
a ->
m ()
prependUnique lens a =
modify $ Lens.over lens modder
where
modder as =
a : filter (a /=) as
prependUniqueBy ::
∀ s' s m a b .
Eq b =>
MonadDeepState s s' m =>
Lens' a b ->
Lens' s' [a] ->
a ->
m ()
prependUniqueBy attr lens a =
modify $ Lens.over lens modder
where
modder as =
a : filter pred' as
pred' b =
Lens.view attr a /= Lens.view attr b
inspectHeadE ::
∀ s' s e e' m a .
(MonadDeepState s s' m, MonadDeepError e e' m) =>
e' ->
Lens' s' [a] ->
m a
inspectHeadE err lens = do
as <- gets $ Lens.view lens
case as of
(a : _) -> return a
_ -> throwHoist err