{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE ScopedTypeVariables #-} module Main where import Control.Monad (foldM, when) import qualified Data.ByteString as BS import Data.Maybe (fromMaybe) import qualified Data.Text.Encoding as TE import qualified Data.Text.IO as TIO import System.Directory (doesFileExist) import System.Environment (getArgs, lookupEnv) import System.Exit import System.IO (hPutStrLn, stderr) import System.Timeout (timeout) import Text.Read (readMaybe) import Text.Show.Pretty (pPrint) import Typst (evaluateTypst, parseTypst) import Typst.Types (Val (..), repr, Operations(..)) import Data.Time (getCurrentTime) import qualified Data.ByteString as B data Opts = Opts { optShowParse :: Bool, optShowEval :: Bool, optShowRepr :: Bool, optShowLaTeX :: Bool, optShowHtml :: Bool, optStandalone :: Bool, optTimeout :: Maybe (Maybe Int) } deriving (Show, Eq) err :: String -> IO a err msg = do hPutStrLn stderr msg exitWith (ExitFailure 1) parseArgs :: [String] -> IO (Maybe FilePath, Opts) parseArgs = foldM go (Nothing, Opts False False False False False False Nothing) where go (f, opts) "--parse" = pure (f, opts {optShowParse = True}) go (f, opts) "--eval" = pure (f, opts {optShowEval = True}) go (f, opts) "--repr" = pure (f, opts {optShowRepr = True}) go (f, opts) "--latex" = pure (f, opts {optShowLaTeX = True}) go (f, opts) "--html" = pure (f, opts {optShowHtml = True}) go (f, opts) "--standalone" = pure (f, opts {optStandalone = True}) go (f, opts) "--timeout" = pure (f, opts {optTimeout = Just Nothing }) go (f, opts) x | optTimeout opts == Just Nothing = pure (f, opts {optTimeout = Just (readMaybe x) }) go _ ('-' : xs) = err $ "Unknown option -" ++ xs go (Nothing, opts) f = pure (Just f, opts) go _ _ = err $ "Only one file can be specified as input." operations :: Operations IO operations = Operations { loadBytes = BS.readFile , currentUTCTime = getCurrentTime , lookupEnvVar = lookupEnv , checkExistence = doesFileExist } main :: IO () main = () <$ do (mbfile, opts) <- getArgs >>= parseArgs let showAll = case opts of Opts False False False False False False _ -> True _ -> False ( case optTimeout opts of Nothing -> fmap Just Just Nothing -> timeout 1000 Just (Just ms) -> timeout (ms * 1000) ) $ do bs <- maybe B.getContents B.readFile mbfile let t = TE.decodeUtf8 bs case parseTypst (fromMaybe "stdin" mbfile) t of Left e -> err $ show e Right parseResult -> do when (optShowParse opts || showAll) $ do when showAll $ putStrLn "--- parse tree ---" pPrint parseResult result <- evaluateTypst operations "stdin" parseResult case result of Left e -> err $ show e Right c -> do when (optShowEval opts || showAll) $ do when showAll $ putStrLn "--- evaluated ---" pPrint c when (optShowRepr opts || showAll) $ do when showAll $ putStrLn "--- repr ---" TIO.putStrLn $ repr $ VContent [c] exitSuccess