{-# LANGUAGE LambdaCase #-}
module Haskell.Debug.Adapter.Watch where
import Control.Monad.IO.Class
import qualified System.FSNotify as S
import Control.Lens
import Control.Concurrent (threadDelay)
import Control.Concurrent.MVar
import Control.Monad.State.Lazy
import qualified System.Log.Logger as L
import Control.Monad.Except
import qualified Data.List as L
import Haskell.Debug.Adapter.Type
import Haskell.Debug.Adapter.Utility
import Haskell.Debug.Adapter.Constant
run :: AppStores -> IO ()
run appData = do
L.debugM _LOG_WATCH "start watch app"
_ <- runApp appData app
L.debugM _LOG_WATCH "end watch app"
app :: AppContext ()
app = flip catchError errHdl $ do
liftIO $ L.infoM _LOG_WATCH "wait getting workspace path."
ws <- getWS
liftIO $ L.infoM _LOG_WATCH $ "start watching " ++ ws
reqStore <- view reqStoreAppStores <$> get
let conf = S.defaultConfig { S.confDebounce = S.Debounce 1}
liftIO $ S.withManagerConf conf $ goIO ws reqStore
where
errHdl msg = do
criticalEV _LOG_REQUEST msg
addEvent CriticalExitEvent
goIO ws reqStore mgr = do
S.watchTree mgr ws hsFilter (action reqStore)
forever $ threadDelay _1_SEC
hsFilter ev = L.isSuffixOf _HS_FILE_EXT $ S.eventPath ev
action mvar ev@(S.Added{}) = sendRequest mvar ev
action mvar ev@(S.Modified{}) = sendRequest mvar ev
action _ _ = return ()
sendRequest mvar ev = do
L.debugM _LOG_WATCH $ "detect. " ++ show ev
let req = WrapRequest $ InternalLoadRequest
$ HdaInternalLoadRequest $ S.eventPath ev
reqs <- takeMVar mvar
putMVar mvar (req : reqs)
getWS :: AppContext FilePath
getWS = do
wsMVar <- view workspaceAppStores <$> get
ws <- liftIO $ readMVar wsMVar
if not (null ws) then return ws
else do
liftIO $ threadDelay _1_SEC
getWS