Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debounce to fsnotify #1882

Merged
merged 2 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 35 additions & 17 deletions IHP/IDE/FileWatcher.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,39 @@ import IHP.IDE.Types
import qualified Data.Time.Clock as Clock
import qualified Data.List as List
import IHP.IDE.LiveReloadNotificationServer (notifyAssetChange)
import qualified Control.Debounce as Debounce

withFileWatcher :: (?context :: Context) => IO () -> IO ()
withFileWatcher inner = withAsync callback \_ -> inner
withFileWatcher inner =
withAsync callback \_ -> inner
where
callback = FS.withManagerConf fileWatcherConfig \manager -> do
callback = do
dispatchHaskellFileChanged <- Debounce.mkDebounce Debounce.defaultDebounceSettings
{ Debounce.debounceAction = dispatch HaskellFileChanged
, Debounce.debounceFreq = 50000 -- 50ms
, Debounce.debounceEdge = Debounce.leadingEdge
}
dispatchSchemaChanged <- Debounce.mkDebounce Debounce.defaultDebounceSettings
{ Debounce.debounceAction = dispatch SchemaChanged
, Debounce.debounceFreq = 50000 -- 50ms
, Debounce.debounceEdge = Debounce.leadingEdge
}
let
handleFileChangeDebounced :: FS.Event -> IO ()
handleFileChangeDebounced = handleFileChange dispatchHaskellFileChanged dispatchSchemaChanged
FS.withManagerConf fileWatcherConfig \manager -> do
state <- newFileWatcherState
watchRootDirectoryFiles manager state
watchSubDirectories manager state
watchRootDirectoryFiles handleFileChangeDebounced manager state
watchSubDirectories handleFileChangeDebounced manager state
forever (threadDelay maxBound) `finally` FS.stopManager manager
watchRootDirectoryFiles manager state =
FS.watchDir manager "." shouldActOnRootFileChange (handleRootFileChange manager state)
watchSubDirectories manager state = do

watchRootDirectoryFiles handleFileChange manager state =
FS.watchDir manager "." shouldActOnRootFileChange (handleRootFileChange handleFileChange manager state)

watchSubDirectories handleFileChange manager state = do
directories <- listWatchableDirectories
forM_ directories \directory -> do
startWatchingSubDirectory manager state directory
startWatchingSubDirectory handleFileChange manager state directory

type WatchedDirectories = Map FilePath FS.StopListening

Expand All @@ -35,8 +53,8 @@ type FileWatcherState = MVar WatchedDirectories
newFileWatcherState :: IO FileWatcherState
newFileWatcherState = newMVar mempty

startWatchingSubDirectory :: (?context :: Context) => FS.WatchManager -> FileWatcherState -> FilePath -> IO ()
startWatchingSubDirectory manager state path = do
startWatchingSubDirectory :: (FS.Event -> IO ()) -> FS.WatchManager -> FileWatcherState -> FilePath -> IO ()
startWatchingSubDirectory handleFileChange manager state path = do
watchedDirectories <- readMVar state
case Map.lookup path watchedDirectories of
Just _ -> pure ()
Expand Down Expand Up @@ -70,23 +88,23 @@ isDirectoryWatchable path =
fileWatcherConfig :: FS.WatchConfig
fileWatcherConfig = FS.defaultConfig

handleFileChange :: (?context :: Context) => FS.Event -> IO ()
handleFileChange event = do
handleFileChange :: (?context :: Context) => IO () -> IO () -> FS.Event -> IO ()
handleFileChange dispatchHaskellFileChanged dispatchSchemaChanged event = do
let filePath = event.eventPath
if isHaskellFile filePath
then dispatch HaskellFileChanged
then dispatchHaskellFileChanged
else if isSchemaSQL filePath
then dispatch SchemaChanged
then dispatchSchemaChanged
else if isAssetFile filePath
then notifyAssetChange
else mempty

handleRootFileChange :: (?context :: Context) => FS.WatchManager -> FileWatcherState -> FS.Event -> IO ()
handleRootFileChange manager state event =
handleRootFileChange :: (FS.Event -> IO ()) -> FS.WatchManager -> FileWatcherState -> FS.Event -> IO ()
handleRootFileChange handleFileChange manager state event =
case event of
FS.Added filePath _ true ->
if isDirectoryWatchable filePath then do
startWatchingSubDirectory manager state filePath
startWatchingSubDirectory handleFileChange manager state filePath
else pure ()
FS.Removed filePath _ true ->
stopWatchingSubDirectory state filePath
Expand Down
1 change: 1 addition & 0 deletions ihp.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ common shared-properties
, with-utf8
, ihp-hsx
, ihp-postgresql-simple-extra
, auto-update
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this related to the debounce?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the Control.Debounce module is part of that package

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a comment to indicate it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, added 👍

default-extensions:
OverloadedStrings
, NoImplicitPrelude
Expand Down
Loading