module Main where import Paths_spade (version) import Control.Concurrent import Control.Concurrent.STM import Control.Monad import Control.Monad.IO.Class import Data.Text as T import Data.Text.IO as T import System.Environment import System.IO as SIO import qualified System.Terminal as TERM import Common import Compiler.Parser import IDE.IDE import Interpreter import UI.Widgets.Common data CommandLineOptions = StartIDE FilePath | RunProgram FilePath | Version getCommandLineOption :: IO CommandLineOptions getCommandLineOption = do getArgs >>= \case ["version"] -> pure Version ["run", filePath] -> pure $ RunProgram filePath [filePath] -> pure $ StartIDE filePath [] -> pure $ StartIDE "untitled.spd" _ -> do error "Unrecognized cmd line arguments. Pass a file name (existing or new) to load the program in the IDE, or using 'spade run filename.spd' command to just run the program without starting the IDE." main :: IO () main = do SIO.hSetEcho stdin False SIO.hSetBuffering stdin NoBuffering SIO.hSetBuffering stdout (BlockBuffering Nothing) interpreterThreadRef <- newEmptyTMVarIO -- Storing the thred id for the interpreter thread that runs the program -- in the IDE seems to be the most simple way to handle ctrl-c termination of the -- interpreted program. We catch the signal in the intputForwardingThread below -- and just kills the thread id stored in this reference (which will be populated -- on starting the interpreter thread, in the IDE) let inputForwardingThread :: (TerminalEvent -> IO ()) -> IO () inputForwardingThread writeFn = do void $ forkIO $ TERM.withTerminal $ TERM.runTerminalT (do TERM.Size h w <- TERM.getWindowSize liftIO $ mapM_ writeFn [TerminalResize w h] forever $ do keys' <- readTerminalEvent case keys' of (TerminalInterrupt : _) -> liftIO $ do (atomically $ tryReadTMVar interpreterThreadRef) >>= \case Just threadId -> killThread threadId Nothing -> pass _ -> pass liftIO $ mapM_ writeFn keys' ) getCommandLineOption >>= \case Version -> T.putStrLn $ T.pack $ show version RunProgram filePath -> do content <- T.readFile filePath program <- compile content void $ interpret id program StartIDE filePath -> do inputChan <- liftIO newTChanIO inputForwardingThread (atomically . writeTChan inputChan) runIDE filePath inputChan interpreterThreadRef