halive 0.1.1 → 0.1.2
raw patch · 4 files changed
+84/−16 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Halive.FileListener: forkEventListenerThread :: FilePath -> ShouldReadFile -> TChan (Either Event String) -> TVar (Maybe UTCTime) -> IO (MVar ())
+ Halive.FileListener: eventListenerForDirectory :: MonadIO m => FilePath -> [String] -> m FileEventListener
+ Halive.FileListener: forkDirectoryListenerThread :: FilePath -> [String] -> TChan (Either Event String) -> IO (MVar ())
+ Halive.FileListener: forkFileListenerThread :: FilePath -> ShouldReadFile -> TChan (Either Event String) -> TVar (Maybe UTCTime) -> IO (MVar ())
+ Halive.FileListener: modifiedWithExtensionPredicate :: [String] -> Event -> Bool
+ Halive.Recompiler: RecompilerConfig :: Maybe (FilePath, [String]) -> String -> FilePath -> Bool -> RecompilerConfig
+ Halive.Recompiler: [rccCompileImmediately] :: RecompilerConfig -> Bool
+ Halive.Recompiler: [rccExpression] :: RecompilerConfig -> String
+ Halive.Recompiler: [rccFilePath] :: RecompilerConfig -> FilePath
+ Halive.Recompiler: [rccWatchAll] :: RecompilerConfig -> Maybe (FilePath, [String])
+ Halive.Recompiler: data RecompilerConfig
+ Halive.Recompiler: recompilerWithConfig :: MonadIO m => TChan CompilationRequest -> RecompilerConfig -> m Recompiler
- Halive.FileListener: eventListenerForFile :: (MonadIO m) => FilePath -> ShouldReadFile -> m FileEventListener
+ Halive.FileListener: eventListenerForFile :: MonadIO m => FilePath -> ShouldReadFile -> m FileEventListener
- Halive.FileListener: killFileEventListener :: (MonadIO m) => FileEventListener -> m ()
+ Halive.FileListener: killFileEventListener :: MonadIO m => FileEventListener -> m ()
Files
- exec/HaliveMain.hs +9/−1
- halive.cabal +1/−1
- src/Halive/FileListener.hs +48/−9
- src/Halive/Recompiler.hs +26/−5
exec/HaliveMain.hs view
@@ -44,7 +44,15 @@ -- , gscCompilationMode = Compiled , gscCompilationMode = Interpreted })- recompiler <- recompilerForExpression ghc mainFileName "main" True++ let fileTypes = ["hs", "pd", "frag", "vert"]++ recompiler <- recompilerWithConfig ghc RecompilerConfig+ { rccWatchAll = Just (".", fileTypes)+ , rccExpression = "main"+ , rccFilePath = mainFileName+ , rccCompileImmediately = True+ } mainThreadId <- myThreadId
halive.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: halive-version: 0.1.1+version: 0.1.2 synopsis: A live recompiler description: Live recompiler for Haskell
src/Halive/FileListener.hs view
@@ -43,12 +43,12 @@ Modified path _ -> path == fileName _ -> False -eventListenerForFile :: (MonadIO m) => FilePath -> ShouldReadFile -> m FileEventListener+eventListenerForFile :: MonadIO m => FilePath -> ShouldReadFile -> m FileEventListener eventListenerForFile fileName shouldReadFile = liftIO $ do eventChan <- newTChanIO ignoreEventsNear <- newTVarIO Nothing - stopMVar <- forkEventListenerThread fileName shouldReadFile eventChan ignoreEventsNear+ stopMVar <- forkFileListenerThread fileName shouldReadFile eventChan ignoreEventsNear return FileEventListener { felEventTChan = eventChan@@ -56,15 +56,54 @@ , felStopMVar = stopMVar } -killFileEventListener :: (MonadIO m) => FileEventListener -> m ()+eventListenerForDirectory :: MonadIO m => FilePath -> [String] -> m FileEventListener+eventListenerForDirectory watchDirectory fileTypes = liftIO $ do+ eventChan <- newTChanIO+ ignoreEventsNear <- newTVarIO Nothing++ stopMVar <- forkDirectoryListenerThread watchDirectory fileTypes eventChan++ return FileEventListener+ { felEventTChan = eventChan+ , felIgnoreNextEventsNear = ignoreEventsNear+ , felStopMVar = stopMVar+ }++killFileEventListener :: MonadIO m => FileEventListener -> m () killFileEventListener eventListener = liftIO $ putMVar (felStopMVar eventListener) () -forkEventListenerThread :: FilePath- -> ShouldReadFile- -> TChan (Either FSNotify.Event String)- -> TVar (Maybe UTCTime)- -> IO (MVar ())-forkEventListenerThread fileName shouldReadFile eventChan ignoreEventsNear = do+-- Pass a list like ["hs", "pd", "frag", "vert"] to match only those filetypes,+-- or an empty list to match all+modifiedWithExtensionPredicate :: [String] -> FSNotify.Event -> Bool+modifiedWithExtensionPredicate fileTypes event = case event of+ Modified path _ -> null fileTypes || drop 1 (takeExtension path) `elem` fileTypes+ _ -> False++forkDirectoryListenerThread :: FilePath+ -> [String]+ -> TChan (Either FSNotify.Event String)+ -> IO (MVar ())+forkDirectoryListenerThread watchDirectory fileTypes eventChan = do+ let predicate = modifiedWithExtensionPredicate fileTypes++ -- Configures debounce time for fsnotify+ let watchConfig = defaultConfig+ { confDebounce = Debounce 0.1 }+ stopMVar <- newEmptyMVar+ _ <- forkIO . withManagerConf watchConfig $ \manager -> do++ stop <- watchTree manager watchDirectory predicate $ \e -> do+ writeTChanIO eventChan (Left e)+ () <- takeMVar stopMVar+ stop+ return stopMVar++forkFileListenerThread :: FilePath+ -> ShouldReadFile+ -> TChan (Either FSNotify.Event String)+ -> TVar (Maybe UTCTime)+ -> IO (MVar ())+forkFileListenerThread fileName shouldReadFile eventChan ignoreEventsNear = do predicate <- fileModifiedPredicate <$> canonicalizePath fileName -- If an ignore time is set, ignore file changes for the next 100 ms let ignoreTime = 0.1
src/Halive/Recompiler.hs view
@@ -78,22 +78,43 @@ -> String -> Bool -> m Recompiler-recompilerForExpression ghcChan filePath expressionString compileOnce = liftIO $ do+recompilerForExpression ghcChan filePath expressionString compileImmediately =+ recompilerWithConfig ghcChan RecompilerConfig+ { rccWatchAll = Nothing+ , rccExpression = expressionString+ , rccFilePath = filePath+ , rccCompileImmediately = compileImmediately+ }++data RecompilerConfig = RecompilerConfig+ { rccWatchAll :: Maybe (FilePath, [String]) -- if Nothing, just watch given file+ , rccExpression :: String+ , rccFilePath :: FilePath+ , rccCompileImmediately :: Bool+ }++recompilerWithConfig :: MonadIO m+ => TChan CompilationRequest+ -> RecompilerConfig+ -> m Recompiler+recompilerWithConfig ghcChan RecompilerConfig{..} = liftIO $ do resultTChan <- newTChanIO let compilationRequest = CompilationRequest- { crFilePath = filePath- , crExpressionString = expressionString+ { crFilePath = rccFilePath+ , crExpressionString = rccExpression , crResultTChan = resultTChan , crFileContents = Nothing } -- Compile for the first time immediately- when compileOnce $+ when rccCompileImmediately $ writeTChanIO ghcChan compilationRequest -- Recompile on file event notifications- fileEventListener <- eventListenerForFile filePath JustReportEvents+ fileEventListener <- case rccWatchAll of + Nothing -> eventListenerForFile rccFilePath JustReportEvents+ Just (watchDir, fileTypes) -> eventListenerForDirectory watchDir fileTypes listenerThread <- forkIO . forever $ do _ <- readFileEvent fileEventListener writeTChanIO ghcChan compilationRequest