{-# language ExistentialQuantification, Rank2Types, ScopedTypeVariables #-} module Rasa (rasa) where import Rasa.Internal.Editor import Rasa.Internal.Action import Rasa.Internal.Events import Rasa.Internal.Scheduler import Control.Lens import Control.Concurrent.Async import Control.Monad import Control.Monad.State import Control.Monad.Reader import Data.Default (def) import Data.Foldable -- | The main function to run rasa. -- -- @rasa eventProviders extensions@ -- -- This should be imported by a user-config and called with extension event providers and extension event hooks as -- arguments. e.g.: -- -- > rasa [slateEvent] $ do -- > cursor -- > vim rasa :: [Action [Keypress]] -> Scheduler () -> IO () rasa eventProviders scheduler = evalAction def hooks $ do dispatchEvent Init eventLoop eventProviders dispatchEvent Exit where hooks = getHooks scheduler -- | This is the main event loop, it runs recursively forever until something -- sets 'Rasa.Editor.exiting'. It runs the pre-event hooks, then listens for an -- event from the event providers, then runs the post event hooks and repeats. eventLoop :: [Action [Keypress]] -> Action () eventLoop eventProviders = do dispatchEvent BeforeRender dispatchEvent OnRender dispatchEvent AfterRender dispatchEvent BeforeEvent currentEditor <- get hooks <- ask -- This is a little weird, but I think it needs to be this way to execute providers in parallel asyncEventProviders <- liftIO $ traverse (async.evalAction currentEditor hooks) eventProviders (_, nextEvents) <- liftIO $ waitAny asyncEventProviders traverse_ dispatchEvent nextEvents isExiting <- use exiting unless isExiting $ eventLoop eventProviders