module Rasa.Internal.Listeners
( dispatchEvent
, addListener
, addListener_
, removeListener
, dispatchBufEvent
, addBufListener
, addBufListener_
, removeBufListener
, Dispatcher
, ListenerId
, onInit
, dispatchInit
, afterInit
, dispatchAfterInit
, beforeEveryRender
, beforeEveryRender_
, dispatchBeforeRender
, beforeEveryEvent
, beforeEveryEvent_
, dispatchBeforeEvent
, onEveryRender
, onEveryRender_
, dispatchOnRender
, afterEveryRender
, afterEveryRender_
, dispatchAfterRender
, onExit
, dispatchExit
, onBufAdded
, onBufAdded_
, dispatchBufAdded
, onEveryNewBuffer
, onEveryNewBuffer_
, onBufTextChanged
, dispatchBufTextChanged
, onKeypress
, dispatchKeypress
, asyncEventProvider
, dispatchEventAsync
) where
import Rasa.Internal.Action
import Rasa.Internal.Actions
import Rasa.Internal.BufAction
import Rasa.Internal.Events
import Rasa.Internal.Extensions
import Control.Lens
import Control.Monad
import Data.Default
import Data.Typeable
import Data.Maybe
import qualified Data.Map as M
data Listener where
Listener :: (Typeable eventType, Typeable result, Monoid result, HasExtMonad m) => TypeRep -> ListenerId -> (eventType -> m result) -> Listener
instance Show Listener where
show (Listener rep (ListenerId n _) _) = "<Listener #" ++ show n ++ ", " ++ show rep ++ ">"
data ListenerId =
ListenerId Int TypeRep
deriving Show
instance Eq ListenerId where
ListenerId a _ == ListenerId b _ = a == b
type Listeners = M.Map TypeRep [Listener]
data LocalListeners =
LocalListeners Int Listeners
deriving Show
instance Default LocalListeners where
def = LocalListeners 0 M.empty
matchingListeners :: forall eventType result m. (Typeable eventType, Typeable result, HasExtMonad m) => Listeners -> [eventType -> m result]
matchingListeners listeners = catMaybes $ (getListener :: Listener -> Maybe (eventType -> m result)) <$> (listeners^.at (typeRep (Proxy :: Proxy eventType))._Just)
getListener :: Typeable expected => Listener -> Maybe expected
getListener (Listener _ _ x) = cast x
onKeypress :: (Keypress -> Action result) -> Action ListenerId
onKeypress actionF = addListener (void <$> actionF)
dispatchKeypress :: Keypress -> Action ()
dispatchKeypress = dispatchEvent
onInit :: Action result -> Action ()
onInit action = void $ addListener (const (void action) :: Init -> Action ())
dispatchInit :: Action ()
dispatchInit = dispatchEvent Init
afterInit :: Action a -> Action ()
afterInit action = void $ addListener (const (void action) :: AfterInit -> Action ())
dispatchAfterInit :: Action ()
dispatchAfterInit = dispatchEvent AfterInit
beforeEveryEvent :: Action a -> Action ListenerId
beforeEveryEvent action = addListener (const (void action) :: BeforeEvent -> Action ())
beforeEveryEvent_ :: Action a -> Action ()
beforeEveryEvent_ = void . beforeEveryEvent
dispatchBeforeEvent :: Action ()
dispatchBeforeEvent = dispatchEvent BeforeEvent
beforeEveryRender :: Action a -> Action ListenerId
beforeEveryRender action = addListener (const (void action) :: BeforeRender -> Action ())
beforeEveryRender_ :: Action a -> Action ()
beforeEveryRender_ = void . beforeEveryRender
dispatchBeforeRender :: Action ()
dispatchBeforeRender = dispatchEvent BeforeRender
onEveryRender :: Action a -> Action ListenerId
onEveryRender action = addListener (const $ void action :: OnRender -> Action ())
onEveryRender_ :: Action a -> Action ()
onEveryRender_ = void . onEveryRender
dispatchOnRender :: Action ()
dispatchOnRender = dispatchEvent OnRender
afterEveryRender :: Action a -> Action ListenerId
afterEveryRender action = addListener (const $ void action :: AfterRender -> Action ())
afterEveryRender_ :: Action a -> Action ()
afterEveryRender_ = void . afterEveryRender
dispatchAfterRender :: Action ()
dispatchAfterRender = dispatchEvent AfterRender
onExit :: Action a -> Action ()
onExit action = void $ addListener (const $ void action :: Exit -> Action ())
dispatchExit :: Action ()
dispatchExit = dispatchEvent Exit
onBufAdded :: (BufAdded -> Action result) -> Action ListenerId
onBufAdded actionF = addListener (void . actionF)
onBufAdded_ :: (BufAdded -> Action result) -> Action ()
onBufAdded_ = void . onBufAdded
onEveryNewBuffer :: BufAction a -> Action ListenerId
onEveryNewBuffer bufAction = onBufAdded $
\(BufAdded br) -> bufDo_ br bufAction
onEveryNewBuffer_ :: BufAction a -> Action ()
onEveryNewBuffer_ = void . onEveryNewBuffer
dispatchBufAdded :: BufAdded -> Action ()
dispatchBufAdded = dispatchEvent
onBufTextChanged :: (BufTextChanged -> BufAction result) -> BufAction ListenerId
onBufTextChanged bufActionF = addBufListener (void . bufActionF)
dispatchBufTextChanged :: BufTextChanged -> BufAction ()
dispatchBufTextChanged = dispatchBufEvent
type Dispatcher = forall event. Typeable event => event -> IO ()
asyncEventProvider :: (Dispatcher -> IO ()) -> Action ()
asyncEventProvider asyncEventProv =
asyncActionProvider $ eventsToActions asyncEventProv
where
eventsToActions :: (Dispatcher -> IO ()) -> (Action () -> IO ()) -> IO ()
eventsToActions aEventProv dispatcher = aEventProv (dispatcher . dispatchEvent)
dispatchEventAsync :: Typeable event => IO event -> Action ()
dispatchEventAsync ioEvent = dispatchActionAsync $ dispatchEvent <$> ioEvent
dispatchEventG :: forall m result eventType. (Monoid result, Typeable eventType, Typeable result, HasExtMonad m) => eventType -> m result
dispatchEventG evt = do
LocalListeners _ listeners <- getExt
results <- traverse ($ evt) (matchingListeners listeners :: [eventType -> m result])
return (mconcat results :: result)
addListenerG :: forall result eventType m. (Typeable eventType, Typeable result, Monoid result, HasExtMonad m) => (eventType -> m result) -> m ListenerId
addListenerG lFunc = do
LocalListeners nextListenerId listeners <- getExt
let (listener, listenerId, eventType) = mkListener nextListenerId lFunc
newListeners = M.insertWith mappend eventType [listener] listeners
setExt $ LocalListeners (nextListenerId + 1) newListeners
return listenerId
where
mkListener :: forall event r. (Typeable event, Typeable r, Monoid r) => Int -> (event -> m r) -> (Listener, ListenerId, TypeRep)
mkListener n listenerFunc =
let list = Listener (typeOf listenerFunc) listId listenerFunc
listId = ListenerId n (typeRep (Proxy :: Proxy event))
prox = typeRep (Proxy :: Proxy event)
in (list, listId, prox)
removeListenerG :: HasExtMonad m => ListenerId -> m ()
removeListenerG listenerId@(ListenerId _ eventType) =
overExt remover
where
remover (LocalListeners nextListenerId listeners) =
let newListeners = listeners & at eventType._Just %~ filter (notMatch listenerId)
in LocalListeners nextListenerId newListeners
notMatch idA (Listener _ idB _) = idA /= idB
dispatchEvent :: forall result eventType. (Monoid result, Typeable eventType, Typeable result) => eventType -> Action result
dispatchEvent = dispatchEventG
addListener :: (Typeable eventType, Typeable result, Monoid result) => (eventType -> Action result) -> Action ListenerId
addListener = addListenerG
addListener_ :: (Typeable eventType, Typeable result, Monoid result) => (eventType -> Action result) -> Action ()
addListener_ = void . addListener
removeListener :: ListenerId -> Action ()
removeListener = removeListenerG
dispatchBufEvent :: (Monoid result, Typeable eventType, Typeable result) => (eventType -> BufAction result)
dispatchBufEvent = dispatchEventG
addBufListener :: (Typeable eventType, Typeable result, Monoid result) => (eventType -> BufAction result) -> BufAction ListenerId
addBufListener = addListenerG
addBufListener_ :: (Typeable eventType, Typeable result, Monoid result) => (eventType -> BufAction result) -> BufAction ()
addBufListener_ = void . addBufListener
removeBufListener :: ListenerId -> BufAction ()
removeBufListener = removeListenerG