{-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RecordWildCards #-} #if !MIN_VERSION_base(4,8,0) import Control.Applicative #endif import Banner import System.Environment import Control.Exception import Control.Monad import Control.Concurrent import Data.IORef import Control.Concurrent.STM import Halive.SubHalive import Halive.Recompiler import Halive.Args import System.FilePath main :: IO () main = do args <- parseArgs <$> getArgs case args of Nothing -> putStrLn usage Just Args {..} -> do let mainFilePath = dropFileName mainFileName setEnv "Halive Active" "Yes" putStrLn banner withArgs targetArgs $ startRecompiler (fileTypes ++ defaultFileTypes) mainFileName (mainFilePath:includeDirs) shouldCompile defaultFileTypes :: [FileType] defaultFileTypes = ["hs", "pd", "frag", "vert"] printBanner :: String -> IO () printBanner title = putStrLn $ ribbon ++ " " ++ title ++ " " ++ ribbon where ribbon = replicate 25 '*' startRecompiler :: [FileType] -> FilePath -> [FilePath] -> Bool -> IO b startRecompiler fileTypes mainFileName includeDirs shouldCompile = do ghc <- startGHC (defaultGHCSessionConfig { gscImportPaths = includeDirs , gscCompilationMode = if shouldCompile then Compiled else Interpreted , gscUseColor = True }) recompiler <- recompilerWithConfig ghc RecompilerConfig { rccWatchAll = Just (".", fileTypes) , rccExpressions = ["main"] , rccFilePath = mainFileName } mainThreadId <- myThreadId newCodeTChan <- newTChanIO isMainRunning <- newIORef False _ <- forkIO $ forever $ do result <- atomically $ readTChan (recResultTChan recompiler) case result of Left errors -> do printBanner "Compilation Errors, Waiting... " putStrLn errors Right values -> do printBanner "Compilation Success, Relaunching..." case values of [newCode] -> do atomically $ writeTChan newCodeTChan newCode mainIsRunning <- readIORef isMainRunning when mainIsRunning $ killThread mainThreadId _ -> error "Unexpected number of values received on recResultTChan" forever $ do newCode <- atomically $ readTChan newCodeTChan case getCompiledValue newCode of Just (mainFunc :: IO ()) -> do writeIORef isMainRunning True mainFunc `catch` (\x -> putStrLn ("App killed: " ++ show (x :: SomeException))) writeIORef isMainRunning False Nothing -> do putStrLn "main was not of type IO ()"