{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-} {- | Module : Neovim.RPC.FunctionCall Description : Functions for calling functions Copyright : (c) Sebastian Witte License : Apache-2.0 Maintainer : woozletoff@gmail.com Stability : experimental -} module Neovim.RPC.FunctionCall ( acall, scall, scall', scallThrow, atomically', wait, wait', respond, ) where import Neovim.Classes import Neovim.Context import qualified Neovim.Context.Internal as Internal import Neovim.Plugin.Classes (FunctionName) import Neovim.Plugin.IPC.Classes import qualified Neovim.RPC.Classes as MsgpackRPC import Control.Applicative import Control.Monad (void, (<=<)) import Control.Monad.Reader import Data.MessagePack import UnliftIO (STM, atomically, newEmptyTMVarIO, readTMVar, throwIO) import Prelude -- | Helper function that concurrently puts a 'Message' in the event queue and returns an 'STM' action that returns the result. acall :: (NvimObject result) => FunctionName -> [Object] -> Neovim env (STM (Either NeovimException result)) acall fn parameters = do q <- Internal.asks' Internal.eventQueue mv <- liftIO newEmptyTMVarIO timestamp <- liftIO getCurrentTime writeMessage q $ FunctionCall fn parameters mv timestamp return $ convertObject <$> readTMVar mv where convertObject :: (NvimObject result) => Either Object Object -> Either NeovimException result convertObject = \case Left e -> Left $ ErrorResult (pretty fn) e Right o -> case fromObject o of Left e -> Left $ ErrorMessage e Right r -> Right r {- | Call a neovim function synchronously. This function blocks until the result is available. -} scall :: (NvimObject result) => FunctionName -> -- | Parameters in an 'Object' array [Object] -> -- | result value of the call or the thrown exception Neovim env (Either NeovimException result) scall fn parameters = acall fn parameters >>= atomically' -- | Similar to 'scall', but throw a 'NeovimException' instead of returning it. scallThrow :: (NvimObject result) => FunctionName -> [Object] -> Neovim env result scallThrow fn parameters = scall fn parameters >>= either throwIO return {- | Helper function similar to 'scall' that throws a runtime exception if the result is an error object. -} scall' :: NvimObject result => FunctionName -> [Object] -> Neovim env result scall' fn = either throwIO pure <=< scall fn -- | Lifted variant of 'atomically'. atomically' :: (MonadIO io) => STM result -> io result atomically' = liftIO . atomically {- | Wait for the result of the STM action. This action possibly blocks as it is an alias for @ \ioSTM -> ioSTM >>= liftIO . atomically@. -} wait :: Neovim env (STM result) -> Neovim env result wait = (=<<) atomically' -- | Variant of 'wait' that discards the result. wait' :: Neovim env (STM result) -> Neovim env () wait' = void . wait -- | Send the result back to the neovim instance. respond :: (NvimObject result) => Request -> Either String result -> Neovim env () respond Request{..} result = do q <- Internal.asks' Internal.eventQueue writeMessage q . MsgpackRPC.Response reqId $ either (Left . toObject) (Right . toObject) result