purview-0.2.0.0: src/Diffing.hs
{-# LANGUAGE DeriveGeneric #-}
module Diffing where
import GHC.Generics
import Data.Aeson
import Component
import Unsafe.Coerce (unsafeCoerce)
{-
Since events target specific locations, we can't stop going the tree early
because changes may have happened beneath the top level. kind of the
downside not having a single, passed down, state.
We still need render, but render needs to be targeted to specific locations.
I dunno how it should work lol.
Let's start at the basics, with dumb tests. If there's a div in the new
tree, and not one in the old tree, it should produce something saying
to add that div.
To know where to make a change, I guess you need a location and a command.
-}
type Location = [Int]
data Change a = Update Location a | Delete Location a | Add Location a
deriving (Show, Eq, Generic)
instance ToJSON a => ToJSON (Change a) where
toEncoding = genericToEncoding defaultOptions
diff
:: Maybe Location
-> Location
-> Purview event m
-> Purview event m
-> [Change (Purview event m)]
diff target location oldGraph newGraph = case (oldGraph, newGraph) of
(Html kind children, Html kind' children') ->
concatMap
(\(index, oldChild, newChild) -> diff target (index:location) oldChild newChild)
(zip3 [0..] children children')
(Text str, Text str') ->
[Update location (Text str') | str /= str']
(Html kind children, unknown) ->
[Update location newGraph]
(unknown, Html kind children) ->
[Update location newGraph]
-- TODO: add Handler
(EffectHandler _ loc initEvents state _ cont, EffectHandler _ loc' initEvents' newState _ newCont) ->
[Update location newGraph | unsafeCoerce state /= newState && loc == loc']
-- TODO: this is weak, instead of walking the whole tree it should be targetted
-- to specific effect handlers
-- if we hit the target, we're already saying update the whole tree
<> if Just location == target
then []
else diff target (0:location) (unsafeCoerce cont state) (unsafeCoerce newCont newState)
(Attribute attr a, Attribute attr' b) ->
[Update location newGraph | attr /= attr']
(Value _, _) ->
[Update location newGraph]
(EffectHandler _ _ _ _ _ _, _) ->
[Update location newGraph]
(_, _) -> [Update location newGraph]
-- (a, b) -> error (show a <> "\n" <> show b)