{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Miso.Reload
(
reload
, reloadWithContext
, live
, liveWithContext
) where
import Control.Concurrent
import Control.Monad
import Miso.DSL ((!), jsg, setField)
import qualified Miso.FFI.Internal as FFI
import Miso.Types (Component(..), Events)
import Miso.String (MisoString)
import Miso.Runtime (componentModel, componentContext, initComponent, topLevelComponentId, Hydrate(..))
import Miso.Runtime.Internal (components, schedulerThread)
import Miso.Lens
import qualified Data.IntMap.Strict as IM
import Data.IORef
import Foreign hiding (void)
import Foreign.C.Types
#ifdef NATIVE
import Miso.JSON
#endif
foreign import ccall unsafe "miso_x_store"
x_store :: StablePtr a -> IO ()
foreign import ccall unsafe "miso_x_get"
x_get :: IO (StablePtr a)
foreign import ccall unsafe "miso_x_exists"
x_exists :: IO CInt
foreign import ccall unsafe "miso_x_clear"
x_clear :: IO ()
#define MISO_JS_PATH "js/miso.js"
reload
#ifdef NATIVE
:: (FromJSON action, ToJSON model, ToJSON action, Eq model)
#else
:: (Eq model)
#endif
=> Events
-> Component () () model action
-> IO ()
reload :: forall model action.
Eq model =>
Events -> Component () () model action -> IO ()
reload Events
events = Events -> () -> Component () () model action -> IO ()
forall context model action.
(Eq context, Eq model) =>
Events -> context -> Component context () model action -> IO ()
reloadWithContext Events
events ()
reloadWithContext
#ifdef NATIVE
:: (FromJSON action, ToJSON model, Eq context, Eq model, ToJSON action)
#else
:: (Eq context, Eq model)
#endif
=> Events
-> context
-> Component context () model action
-> IO ()
reloadWithContext :: forall context model action.
(Eq context, Eq model) =>
Events -> context -> Component context () model action -> IO ()
reloadWithContext Events
events context
initialContext Component context () model action
comp = do
CInt
exists <- IO CInt
x_exists
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
exists CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
1) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
(Any
_, IORef ThreadId
oldSchedulerRef) <- StablePtr (Any, IORef ThreadId) -> IO (Any, IORef ThreadId)
forall a. StablePtr a -> IO a
deRefStablePtr (StablePtr (Any, IORef ThreadId) -> IO (Any, IORef ThreadId))
-> IO (StablePtr (Any, IORef ThreadId)) -> IO (Any, IORef ThreadId)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (StablePtr (Any, IORef ThreadId))
forall a. IO (StablePtr a)
x_get
ThreadId -> IO ()
killThread (ThreadId -> IO ()) -> IO ThreadId -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IORef ThreadId -> IO ThreadId
forall a. IORef a -> IO a
readIORef IORef ThreadId
oldSchedulerRef
IO ()
x_clear
IO ()
clearPage
IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Events
-> Hydrate
-> Bool
-> context
-> Component context () model action
-> Maybe Key
-> ()
-> Maybe StaticKey
-> IO ()
forall context props model action.
(Eq context, Eq model, Eq props) =>
Events
-> Hydrate
-> Bool
-> context
-> Component context props model action
-> Maybe Key
-> props
-> Maybe StaticKey
-> IO ()
initComponent Events
events Hydrate
Draw Bool
False context
initialContext Component context () model action
comp Maybe Key
forall a. Maybe a
Nothing () Maybe StaticKey
forall a. Maybe a
Nothing)
StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO ()
forall a. StablePtr a -> IO ()
x_store (StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO ())
-> IO
(StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId))
-> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO
(StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId))
forall a. a -> IO (StablePtr a)
newStablePtr (IORef (IntMap (ComponentState Any Any Any Any))
forall context props model action.
IORef (IntMap (ComponentState context props model action))
components, IORef ThreadId
schedulerThread)
live
#ifdef NATIVE
:: (Eq model, ToJSON model, ToJSON action, FromJSON action)
#else
:: Eq model
#endif
=> Events
-> Component () () model action
-> IO ()
live :: forall model action.
Eq model =>
Events -> Component () () model action -> IO ()
live Events
events Component () () model action
vcomp_ = Events -> () -> Component () () model action -> IO ()
forall context model action.
(Eq context, Eq model) =>
Events -> context -> Component context () model action -> IO ()
liveWithContext Events
events () Component () () model action
vcomp_
liveWithContext
#ifdef NATIVE
:: (Eq context, Eq model, ToJSON model, ToJSON action, FromJSON action)
#else
:: (Eq context, Eq model)
#endif
=> Events
-> context
-> Component context () model action
-> IO ()
liveWithContext :: forall context model action.
(Eq context, Eq model) =>
Events -> context -> Component context () model action -> IO ()
liveWithContext Events
events context
initialContext Component context () model action
vcomp_ = do
CInt
exists <- IO CInt
x_exists
if CInt
exists CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
1
then do
IO ()
clearBody
(IORef (IntMap (ComponentState context Any model Any))
oldComponentsRef, IORef ThreadId
oldSchedulerRef) <- StablePtr
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId)
-> IO
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId)
forall a. StablePtr a -> IO a
deRefStablePtr (StablePtr
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId)
-> IO
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId))
-> IO
(StablePtr
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId))
-> IO
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO
(StablePtr
(IORef (IntMap (ComponentState context Any model Any)),
IORef ThreadId))
forall a. IO (StablePtr a)
x_get
ThreadId -> IO ()
killThread (ThreadId -> IO ()) -> IO ThreadId -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IORef ThreadId -> IO ThreadId
forall a. IORef a -> IO a
readIORef IORef ThreadId
oldSchedulerRef
IntMap (ComponentState context Any model Any)
_oldState <- IORef (IntMap (ComponentState context Any model Any))
-> IO (IntMap (ComponentState context Any model Any))
forall a. IORef a -> IO a
readIORef IORef (IntMap (ComponentState context Any model Any))
oldComponentsRef
let oldModel :: model
oldModel = (IntMap (ComponentState context Any model Any)
_oldState IntMap (ComponentState context Any model Any)
-> Key -> ComponentState context Any model Any
forall a. IntMap a -> Key -> a
IM.! Key
topLevelComponentId) ComponentState context Any model Any
-> Lens (ComponentState context Any model Any) model -> model
forall record field. record -> Lens record field -> field
^. Lens (ComponentState context Any model Any) model
forall context props model action.
Lens (ComponentState context props model action) model
componentModel
initialVComp :: Component context () model action
initialVComp = Component context () model action
vcomp_ { model = oldModel }
context
oldContext <- IORef context -> IO context
forall a. IORef a -> IO a
readIORef ((IntMap (ComponentState context Any model Any)
_oldState IntMap (ComponentState context Any model Any)
-> Key -> ComponentState context Any model Any
forall a. IntMap a -> Key -> a
IM.! Key
topLevelComponentId) ComponentState context Any model Any
-> Lens (ComponentState context Any model Any) (IORef context)
-> IORef context
forall record field. record -> Lens record field -> field
^. Lens (ComponentState context Any model Any) (IORef context)
forall context props model action.
Lens (ComponentState context props model action) (IORef context)
componentContext)
IORef (IntMap (ComponentState context Any model Any))
-> IntMap (ComponentState context Any model Any) -> IO ()
forall a. IORef a -> a -> IO ()
atomicWriteIORef IORef (IntMap (ComponentState context Any model Any))
forall context props model action.
IORef (IntMap (ComponentState context props model action))
components IntMap (ComponentState context Any model Any)
_oldState
Events
-> Hydrate
-> Bool
-> context
-> Component context () model action
-> Maybe Key
-> ()
-> Maybe StaticKey
-> IO ()
forall context props model action.
(Eq context, Eq model, Eq props) =>
Events
-> Hydrate
-> Bool
-> context
-> Component context props model action
-> Maybe Key
-> props
-> Maybe StaticKey
-> IO ()
initComponent Events
events Hydrate
Draw Bool
True context
oldContext Component context () model action
initialVComp Maybe Key
forall a. Maybe a
Nothing () Maybe StaticKey
forall a. Maybe a
Nothing
IntMap (ComponentState Any Any Any Any)
newState <- IORef (IntMap (ComponentState Any Any Any Any))
-> IO (IntMap (ComponentState Any Any Any Any))
forall a. IORef a -> IO a
readIORef IORef (IntMap (ComponentState Any Any Any Any))
forall context props model action.
IORef (IntMap (ComponentState context props model action))
components
Maybe (ComponentState Any Any Any Any)
-> (ComponentState Any Any Any Any -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Key
-> IntMap (ComponentState Any Any Any Any)
-> Maybe (ComponentState Any Any Any Any)
forall a. Key -> IntMap a -> Maybe a
IM.lookup Key
topLevelComponentId IntMap (ComponentState Any Any Any Any)
newState) ((ComponentState Any Any Any Any -> IO ()) -> IO ())
-> (ComponentState Any Any Any Any -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ComponentState Any Any Any Any
root -> do
let newCell :: IORef Any
newCell = ComponentState Any Any Any Any
root ComponentState Any Any Any Any
-> Lens (ComponentState Any Any Any Any) (IORef Any) -> IORef Any
forall record field. record -> Lens record field -> field
^. Lens (ComponentState Any Any Any Any) (IORef Any)
forall context props model action.
Lens (ComponentState context props model action) (IORef context)
componentContext
IORef (IntMap (ComponentState Any Any Any Any))
-> (IntMap (ComponentState Any Any Any Any)
-> (IntMap (ComponentState Any Any Any Any), ()))
-> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef (IntMap (ComponentState Any Any Any Any))
forall context props model action.
IORef (IntMap (ComponentState context props model action))
components ((IntMap (ComponentState Any Any Any Any)
-> (IntMap (ComponentState Any Any Any Any), ()))
-> IO ())
-> (IntMap (ComponentState Any Any Any Any)
-> (IntMap (ComponentState Any Any Any Any), ()))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \IntMap (ComponentState Any Any Any Any)
m ->
((ComponentState Any Any Any Any -> ComponentState Any Any Any Any)
-> IntMap (ComponentState Any Any Any Any)
-> IntMap (ComponentState Any Any Any Any)
forall a b. (a -> b) -> IntMap a -> IntMap b
IM.map (Lens (ComponentState Any Any Any Any) (IORef Any)
forall context props model action.
Lens (ComponentState context props model action) (IORef context)
componentContext Lens (ComponentState Any Any Any Any) (IORef Any)
-> IORef Any
-> ComponentState Any Any Any Any
-> ComponentState Any Any Any Any
forall record field. Lens record field -> field -> record -> record
.~ IORef Any
newCell) IntMap (ComponentState Any Any Any Any)
m, ())
IO ()
FFI.flush
IO ()
x_clear
StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO ()
forall a. StablePtr a -> IO ()
x_store (StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO ())
-> IO
(StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId))
-> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO
(StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId))
forall a. a -> IO (StablePtr a)
newStablePtr (IORef (IntMap (ComponentState Any Any Any Any))
forall context props model action.
IORef (IntMap (ComponentState context props model action))
components, IORef ThreadId
schedulerThread)
else do
IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Events
-> Hydrate
-> Bool
-> context
-> Component context () model action
-> Maybe Key
-> ()
-> Maybe StaticKey
-> IO ()
forall context props model action.
(Eq context, Eq model, Eq props) =>
Events
-> Hydrate
-> Bool
-> context
-> Component context props model action
-> Maybe Key
-> props
-> Maybe StaticKey
-> IO ()
initComponent Events
events Hydrate
Draw Bool
False context
initialContext Component context () model action
vcomp_ Maybe Key
forall a. Maybe a
Nothing () Maybe StaticKey
forall a. Maybe a
Nothing)
StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO ()
forall a. StablePtr a -> IO ()
x_store (StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO ())
-> IO
(StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId))
-> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId)
-> IO
(StablePtr
(IORef (IntMap (ComponentState Any Any Any Any)), IORef ThreadId))
forall a. a -> IO (StablePtr a)
newStablePtr (IORef (IntMap (ComponentState Any Any Any Any))
forall context props model action.
IORef (IntMap (ComponentState context props model action))
components, IORef ThreadId
schedulerThread)
clearPage, clearBody, clearHead :: IO ()
clearPage :: IO ()
clearPage = IO ()
clearBody IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
clearHead
clearBody :: IO ()
clearBody = do
JSVal
body_ <- MisoString -> IO JSVal
jsg MisoString
"document" IO JSVal -> MisoString -> IO JSVal
forall o. ToObject o => o -> MisoString -> IO JSVal
! (MisoString
"body" :: MisoString)
JSVal -> MisoString -> MisoString -> IO ()
forall o v.
(ToObject o, ToJSVal v) =>
o -> MisoString -> v -> IO ()
setField JSVal
body_ MisoString
"innerHTML" (MisoString
"" :: MisoString)
clearHead :: IO ()
clearHead = do
JSVal
head_ <- MisoString -> IO JSVal
jsg MisoString
"document" IO JSVal -> MisoString -> IO JSVal
forall o. ToObject o => o -> MisoString -> IO JSVal
! (MisoString
"head" :: MisoString)
JSVal -> MisoString -> MisoString -> IO ()
forall o v.
(ToObject o, ToJSVal v) =>
o -> MisoString -> v -> IO ()
setField JSVal
head_ MisoString
"innerHTML" (MisoString
"" :: MisoString)