module Development.IDE.Core.Debouncer
( Debouncer
, registerEvent
, newAsyncDebouncer
, noopDebouncer
) where
import Control.Concurrent.Extra
import Control.Concurrent.Async
import Control.Exception
import Control.Monad.Extra
import Data.Hashable
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as Map
import System.Time.Extra
newtype Debouncer k = Debouncer { Debouncer k -> Seconds -> k -> IO () -> IO ()
registerEvent :: Seconds -> k -> IO () -> IO () }
newAsyncDebouncer :: (Eq k, Hashable k) => IO (Debouncer k)
newAsyncDebouncer :: IO (Debouncer k)
newAsyncDebouncer = (Seconds -> k -> IO () -> IO ()) -> Debouncer k
forall k. (Seconds -> k -> IO () -> IO ()) -> Debouncer k
Debouncer ((Seconds -> k -> IO () -> IO ()) -> Debouncer k)
-> (Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ())
-> Var (HashMap k (Async ()))
-> Debouncer k
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ()
forall k.
(Eq k, Hashable k) =>
Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ()
asyncRegisterEvent (Var (HashMap k (Async ())) -> Debouncer k)
-> IO (Var (HashMap k (Async ()))) -> IO (Debouncer k)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HashMap k (Async ()) -> IO (Var (HashMap k (Async ())))
forall a. a -> IO (Var a)
newVar HashMap k (Async ())
forall k v. HashMap k v
Map.empty
asyncRegisterEvent :: (Eq k, Hashable k) => Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ()
asyncRegisterEvent :: Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ()
asyncRegisterEvent Var (HashMap k (Async ()))
d Seconds
0 k
k IO ()
fire = do
Var (HashMap k (Async ()))
-> (HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ()
forall a. Var a -> (a -> IO a) -> IO ()
modifyVar_ Var (HashMap k (Async ()))
d ((HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ())
-> (HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ()
forall a b. (a -> b) -> a -> b
$ \HashMap k (Async ())
m -> IO (HashMap k (Async ())) -> IO (HashMap k (Async ()))
forall a. IO a -> IO a
mask_ (IO (HashMap k (Async ())) -> IO (HashMap k (Async ())))
-> IO (HashMap k (Async ())) -> IO (HashMap k (Async ()))
forall a b. (a -> b) -> a -> b
$ do
Maybe (Async ()) -> (Async () -> IO ()) -> IO ()
forall (m :: * -> *) a.
Applicative m =>
Maybe a -> (a -> m ()) -> m ()
whenJust (k -> HashMap k (Async ()) -> Maybe (Async ())
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookup k
k HashMap k (Async ())
m) Async () -> IO ()
forall a. Async a -> IO ()
cancel
HashMap k (Async ()) -> IO (HashMap k (Async ()))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HashMap k (Async ()) -> IO (HashMap k (Async ())))
-> HashMap k (Async ()) -> IO (HashMap k (Async ()))
forall a b. (a -> b) -> a -> b
$ k -> HashMap k (Async ()) -> HashMap k (Async ())
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
Map.delete k
k HashMap k (Async ())
m
IO ()
fire
asyncRegisterEvent Var (HashMap k (Async ()))
d Seconds
delay k
k IO ()
fire = Var (HashMap k (Async ()))
-> (HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ()
forall a. Var a -> (a -> IO a) -> IO ()
modifyVar_ Var (HashMap k (Async ()))
d ((HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ())
-> (HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ()
forall a b. (a -> b) -> a -> b
$ \HashMap k (Async ())
m -> IO (HashMap k (Async ())) -> IO (HashMap k (Async ()))
forall a. IO a -> IO a
mask_ (IO (HashMap k (Async ())) -> IO (HashMap k (Async ())))
-> IO (HashMap k (Async ())) -> IO (HashMap k (Async ()))
forall a b. (a -> b) -> a -> b
$ do
Maybe (Async ()) -> (Async () -> IO ()) -> IO ()
forall (m :: * -> *) a.
Applicative m =>
Maybe a -> (a -> m ()) -> m ()
whenJust (k -> HashMap k (Async ()) -> Maybe (Async ())
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookup k
k HashMap k (Async ())
m) Async () -> IO ()
forall a. Async a -> IO ()
cancel
Async ()
a <- ((forall a. IO a -> IO a) -> IO ()) -> IO (Async ())
forall a. ((forall a. IO a -> IO a) -> IO a) -> IO (Async a)
asyncWithUnmask (((forall a. IO a -> IO a) -> IO ()) -> IO (Async ()))
-> ((forall a. IO a -> IO a) -> IO ()) -> IO (Async ())
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
unmask -> IO () -> IO ()
forall a. IO a -> IO a
unmask (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Seconds -> IO ()
sleep Seconds
delay
IO ()
fire
Var (HashMap k (Async ()))
-> (HashMap k (Async ()) -> IO (HashMap k (Async ()))) -> IO ()
forall a. Var a -> (a -> IO a) -> IO ()
modifyVar_ Var (HashMap k (Async ()))
d (HashMap k (Async ()) -> IO (HashMap k (Async ()))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HashMap k (Async ()) -> IO (HashMap k (Async ())))
-> (HashMap k (Async ()) -> HashMap k (Async ()))
-> HashMap k (Async ())
-> IO (HashMap k (Async ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. k -> HashMap k (Async ()) -> HashMap k (Async ())
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
Map.delete k
k)
HashMap k (Async ()) -> IO (HashMap k (Async ()))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HashMap k (Async ()) -> IO (HashMap k (Async ())))
-> HashMap k (Async ()) -> IO (HashMap k (Async ()))
forall a b. (a -> b) -> a -> b
$ k -> Async () -> HashMap k (Async ()) -> HashMap k (Async ())
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
Map.insert k
k Async ()
a HashMap k (Async ())
m
noopDebouncer :: Debouncer k
noopDebouncer :: Debouncer k
noopDebouncer = (Seconds -> k -> IO () -> IO ()) -> Debouncer k
forall k. (Seconds -> k -> IO () -> IO ()) -> Debouncer k
Debouncer ((Seconds -> k -> IO () -> IO ()) -> Debouncer k)
-> (Seconds -> k -> IO () -> IO ()) -> Debouncer k
forall a b. (a -> b) -> a -> b
$ \Seconds
_ k
_ IO ()
a -> IO ()
a