{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RecursiveDo #-}
module Reflex.Data.Sequence
( DynamicSeq(..)
, DynamicSeqConfig(..)
, defaultDynamicSeqConfig
, dynamicSeq_attachEndPos
, holdDynamicSeq
)
where
import Relude hiding (empty, splitAt)
import Reflex
import Reflex.Potato.Helpers
import Control.Monad.Fix
import Data.Sequence as Seq
import Data.Wedge
data DynamicSeq t a = DynamicSeq {
_dynamicSeq_inserted :: Event t (Int, Seq a)
, _dynamicSeq_removed :: Event t (Int, Seq a)
, _dynamicSeq_contents :: Dynamic t (Seq a)
}
data DynamicSeqConfig t a = DynamicSeqConfig {
_dynamicSeqConfig_insert :: Event t (Int, Seq a)
, _dynamicSeqConfig_remove :: Event t (Int, Int)
, _dynamicSeqConfig_clear :: Event t ()
}
defaultDynamicSeqConfig :: (Reflex t) => DynamicSeqConfig t a
defaultDynamicSeqConfig = DynamicSeqConfig { _dynamicSeqConfig_insert = never
, _dynamicSeqConfig_remove = never
, _dynamicSeqConfig_clear = never
}
dynamicSeq_attachEndPos
:: (Reflex t) => DynamicSeq t a -> Event t b -> Event t (Int, b)
dynamicSeq_attachEndPos DynamicSeq {..} =
attach (Seq.length <$> current _dynamicSeq_contents)
type DSState a = (Wedge (Int, Seq a) (Int, Seq a), Seq a)
data DSCmd t a = DSCAdd (Int, Seq a) | DSCRemove (Int, Int) | DSCClear
holdDynamicSeq
:: forall t m a
. (Reflex t, MonadHold t m, MonadFix m)
=> Seq a
-> DynamicSeqConfig t a
-> m (DynamicSeq t a)
holdDynamicSeq initial DynamicSeqConfig {..} = mdo
let changeEvent :: Event t (DSCmd t a)
changeEvent = leftmostwarn
"WARNING: multiple Seq events firing at once"
[ fmap DSCAdd _dynamicSeqConfig_insert
, fmap DSCRemove _dynamicSeqConfig_remove
, fmap (const DSCClear) _dynamicSeqConfig_clear
]
foldfn :: (DSCmd t a) -> DSState a -> PushM t (DSState a)
foldfn (DSCAdd (i, ys)) (_, xs) = return (Here (i, ys), newSeq) where
(l, r) = splitAt i xs
newSeq = l >< ys >< r
foldfn (DSCRemove (i, n)) (_, xs) = return (There (i, removed), newSeq) where
(keepl , rs ) = splitAt i xs
(removed, keepr) = splitAt n rs
newSeq = keepl >< keepr
foldfn DSCClear (_, xs) = return (There (0, xs), empty)
asdyn :: Dynamic t (DSState a) <- foldDynM foldfn
(Nowhere, initial)
changeEvent
return $ DynamicSeq
{ _dynamicSeq_inserted = fmapMaybe (getHere . fst) $ updated asdyn
, _dynamicSeq_removed = fmapMaybe (getThere . fst) $ updated asdyn
, _dynamicSeq_contents = snd <$> asdyn
}