@@ -9,13 +9,13 @@ module Development.IDE.Core.Debouncer
9
9
) where
10
10
11
11
import Control.Concurrent.Async
12
- import Control.Concurrent.Strict
12
+ import Control.Concurrent.STM
13
+ import Control.Concurrent.STM.Stats (atomicallyNamed )
13
14
import Control.Exception
14
- import Control.Monad (join )
15
- import Data.Foldable (traverse_ )
16
- import Data.HashMap.Strict (HashMap )
17
- import qualified Data.HashMap.Strict as Map
15
+ import Control.Monad (join )
18
16
import Data.Hashable
17
+ import GHC.Conc (unsafeIOToSTM )
18
+ import qualified StmContainers.Map as STM
19
19
import System.Time.Extra
20
20
21
21
-- | A debouncer can be used to avoid triggering many events
@@ -31,28 +31,29 @@ newtype Debouncer k = Debouncer { registerEvent :: Seconds -> k -> IO () -> IO (
31
31
32
32
-- | Debouncer used in the IDE that delays events as expected.
33
33
newAsyncDebouncer :: (Eq k , Hashable k ) => IO (Debouncer k )
34
- newAsyncDebouncer = Debouncer . asyncRegisterEvent <$> newVar Map. empty
34
+ newAsyncDebouncer = Debouncer . asyncRegisterEvent <$> STM. newIO
35
35
36
36
-- | Register an event that will fire after the given delay if no other event
37
37
-- for the same key gets registered until then.
38
38
--
39
39
-- If there is a pending event for the same key, the pending event will be killed.
40
40
-- Events are run unmasked so it is up to the user of `registerEvent`
41
41
-- to mask if required.
42
- asyncRegisterEvent :: (Eq k , Hashable k ) => Var (HashMap k (Async () )) -> Seconds -> k -> IO () -> IO ()
43
- asyncRegisterEvent d 0 k fire = do
44
- join $ modifyVar d $ \ m -> do
45
- (cancel, ! m') <- evaluate $ Map. alterF (\ prev -> (traverse_ cancel prev, Nothing )) k m
46
- return (m', cancel)
47
- fire
42
+ asyncRegisterEvent :: (Eq k , Hashable k ) => STM. Map k (TVar (Seconds , IO () )) -> Seconds -> k -> IO () -> IO ()
48
43
asyncRegisterEvent d delay k fire = mask_ $ do
49
- a <- asyncWithUnmask $ \ unmask -> unmask $ do
50
- sleep delay
51
- fire
52
- modifyVar_ d (evaluate . Map. delete k)
53
- join $ modifyVar d $ \ m -> do
54
- (cancel, ! m') <- evaluate $ Map. alterF (\ prev -> (traverse_ cancel prev, Just a)) k m
55
- return (m', cancel)
44
+ prev <- atomically $ STM. lookup k d
45
+ case prev of
46
+ Just v -> do
47
+ atomicallyNamed " debouncer - reset" $ writeTVar v (delay, fire)
48
+ Nothing -> do
49
+ var <- newTVarIO (delay, fire)
50
+ _ <- asyncWithUnmask $ \ unmask -> unmask $ do
51
+ join $ atomicallyNamed " debouncer - sleep" $ do
52
+ (s,act) <- readTVar var
53
+ unsafeIOToSTM $ sleep s
54
+ STM. delete k d
55
+ return act
56
+ atomicallyNamed " debouncer2" $ STM. insert var k d
56
57
57
58
-- | Debouncer used in the DAML CLI compiler that emits events immediately.
58
59
noopDebouncer :: Debouncer k
0 commit comments