packages feed

typst 0.9.0.1 → 0.10

raw patch · 9 files changed

+112/−65 lines, 9 filesdep +optparse-applicativedep ~typst-symbols

Dependencies added: optparse-applicative

Dependency ranges changed: typst-symbols

Files

CHANGELOG.md view
@@ -1,5 +1,25 @@ # Revision history for typst-hs +## 0.10++  * Add --input option to cli for passing key-value pairs to the+    evaluator (as can be done with `typst`).++  * Use optparse-applicative for CLI option parsing.++  * Add `inputs` parameter to `evalTypst`.++  * Remove `sysModule` from `Module.Standard` [API change].+    We now generate `sys` in `initialEvalState`, since only then+    do we know the inputs.++  * Properly locate package root for imports (#98).+    We need to go up the directory hierarchy til we find typst.toml.++  * Use released version of typst-symbols-0.2 with new typst-symbols API.++  * app/Main: remove unused options.+ ## 0.9.0.1    * Fix typo that caused close single quote to be parsed as double
app/Main.hs view
@@ -4,17 +4,19 @@  module Main where -import Control.Monad (foldM, when)+import Control.Monad (when) import qualified Data.ByteString as BS import Data.Maybe (fromMaybe)+import Data.Text (Text)+import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Text.IO as TIO+import Options.Applicative import System.Directory (doesFileExist)-import System.Environment (getArgs, lookupEnv)+import System.Environment (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(..))@@ -25,10 +27,9 @@   { optShowParse :: Bool,     optShowEval :: Bool,     optShowRepr :: Bool,-    optShowLaTeX :: Bool,-    optShowHtml :: Bool,-    optStandalone :: Bool,-    optTimeout :: Maybe (Maybe Int)+    optTimeout :: Maybe Int,+    optInputs :: [(Text, Text)],+    optFile :: Maybe FilePath   }   deriving (Show, Eq) @@ -37,22 +38,29 @@   hPutStrLn stderr msg   exitWith (ExitFailure 1) -parseArgs :: [String] -> IO (Maybe FilePath, Opts)-parseArgs = foldM go (Nothing, Opts False False False False False False Nothing)+optsParser :: Parser Opts+optsParser =+  Opts+    <$> switch (long "parse" <> help "Show parse tree")+    <*> switch (long "eval" <> help "Show evaluated result")+    <*> switch (long "repr" <> help "Show repr output")+    <*> optional (option auto (long "timeout" <> metavar "MS" <> help "Timeout in milliseconds"))+    <*> many (option (eitherReader parseInput)+          (long "input" <> metavar "KEY=VALUE" <> help "Set an input key-value pair (repeatable)"))+    <*> optional (argument str (metavar "FILE" <> help "Input file (reads stdin if omitted)"))++parseInput :: String -> Either String (Text, Text)+parseInput s =+  case break (== '=') s of+    (_, []) -> Left "Expected KEY=VALUE format"+    (k, '=' : v) -> Right (T.pack k, T.pack (unquote v))+    _ -> Left "Expected KEY=VALUE format"   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."+    unquote ('"' : rest)+      | not (null rest) && last rest == '"' = init rest+    unquote ('\'' : rest)+      | not (null rest) && last rest == '\'' = init rest+    unquote x = x  operations :: Operations IO operations = Operations@@ -65,14 +73,15 @@ main :: IO () main =   () <$ do-    (mbfile, opts) <- getArgs >>= parseArgs+    opts <- execParser (info (optsParser <**> helper)+              (fullDesc <> progDesc "Parse and evaluate Typst documents"))+    let mbfile = optFile opts     let showAll = case opts of-          Opts False False False False False False _ -> True+          Opts False False False _ _ _ -> True           _ -> False     ( case optTimeout opts of         Nothing -> fmap Just-        Just Nothing -> timeout 1000-        Just (Just ms) -> timeout (ms * 1000)+        Just ms -> timeout (ms * 1000)       )       $ do         bs <- maybe B.getContents B.readFile mbfile@@ -83,7 +92,7 @@             when (optShowParse opts || showAll) $ do               when showAll $ putStrLn "--- parse tree ---"               pPrint parseResult-            result <- evaluateTypst operations "stdin" parseResult+            result <- evaluateTypst operations (optInputs opts) "stdin" parseResult             case result of               Left e -> err $ show e               Right c -> do
src/Typst/Evaluate.hs view
@@ -46,6 +46,8 @@ import Typst.Util (makeFunction, nthArg) import qualified Toml as Toml import qualified Toml.Schema as Toml+import Paths_typst (version)+import Data.Version (showVersion)  -- import Debug.Trace @@ -55,12 +57,14 @@   Monad m =>   -- | Dictionary of functions for IO operations   Operations m ->+  -- | Parameters that would be set with --input in typst, for sys.inputs+  [(Text, Text)] ->   -- | Path of parsed content   FilePath ->   -- | Markup produced by 'parseTypst'   [Markup] ->   m (Either ParseError Content)-evaluateTypst operations fp =+evaluateTypst operations inputs fp =   runParserT     (do contents <- mconcat <$> many pContent <* eof         -- "All documents are automatically wrapped in a document element."@@ -70,27 +74,38 @@         case toList els of           [e] -> pure e           _ -> fail "element returned something other than a singleton")-    initialEvalState { evalOperations = operations,-                       evalLocalDir = takeDirectory fp }+    (initialEvalState inputs) { evalOperations = operations,+                                evalLocalDir = takeDirectory fp }     fp -initialEvalState :: EvalState m-initialEvalState =+initialEvalState :: [(Text, Text)] -> EvalState m+initialEvalState inputs =   emptyEvalState { evalIdentifiers = [(BlockScope, mempty)]                  , evalMathIdentifiers = [(BlockScope, mathModule <> symModule)]-                 , evalStandardIdentifiers = [(BlockScope, standardModule'')]+                 , evalStandardIdentifiers = [(BlockScope, standardModule''')]                  , evalPackageRoot = "."+                 , evalInputs = inputs                  }   where     standardModule' = M.insert "eval" evalFunction standardModule-    standardModule'' = M.insert "std" (VModule "std" standardModule') standardModule'+    standardModule'' = M.insert+                        "sys"+                        (VModule "sys" $ M.fromList+                         [ ("version", VVersion [0,14,0])+                         , ("inputs", VDict $+                              OM.fromList (map (\(k,v) -> (Identifier k, VString v))+                                           inputs'))+                         ])+                      standardModule'+    standardModule''' = M.insert "std" (VModule "std" standardModule') standardModule''+    inputs' = ("typst-hs-version", T.pack (showVersion version)) : inputs     evalFunction = makeFunction $ do       code :: Text <- nthArg 1       case parseTypst "eval" ("#{\n" <> code <> "\n}") of         Left e -> fail $ "eval: " <> show e         Right [Code _ expr] ->           -- run in Either monad so we can't access file system-          case runParserT (evalExpr expr) initialEvalState "eval" [] of+          case runParserT (evalExpr expr) (initialEvalState inputs) "eval" [] of             Failure e -> fail $ "eval: " <> e             Success (Left e) -> fail $ "eval: " <> show e             Success (Right val) -> pure val@@ -940,7 +955,7 @@ findPackageEntryPoint modname = do   let (namespace, rest) = break (=='/') (drop 1 $ T.unpack modname)   let (name, rest') = break (==':') $ drop 1 rest-  let version = drop 1 rest'+  let pkgversion = drop 1 rest'   operations <- evalOperations <$> getState   let getEnv var = do         mbv <- lift $ lookupEnvVar operations var@@ -965,7 +980,7 @@   let localDir = dataDir </> "typst"   let cacheDir = cacheDir' </> "typst" #endif-  let subpath = "packages" </> namespace </> name </> version+  let subpath = "packages" </> namespace </> name </> pkgversion   inLocal <- lift $ checkExistence operations (localDir </> subpath </> "typst.toml")   tomlPath <-      if inLocal@@ -993,11 +1008,19 @@             fp' <- findPackageEntryPoint modname             operations <- evalOperations <$> getState             txt <- lift $ TE.decodeUtf8 <$> loadBytes operations fp'+            let findPkgRoot "" = fail $ "Could not find package root for " <> fp'+                findPkgRoot dir' = do+                  exists <- lift $ checkExistence operations+                                       (dir' </> "typst.toml")+                  if exists+                     then pure dir'+                     else findPkgRoot (takeDirectory dir')+            pkgroot <- findPkgRoot (takeDirectory fp')             pure ( takeFileName fp',                    Identifier                     (T.pack $ takeWhile (/= ':') . takeBaseName $                        T.unpack modname),-                   Just (takeDirectory fp'),+                   Just pkgroot,                    txt )            else do              let fp = T.unpack modname@@ -1013,6 +1036,7 @@       operations <- evalOperations <$> getState       currentLocalDir <- evalLocalDir <$> getState       currentPackageRoot <- evalPackageRoot <$> getState+      inputs <- evalInputs <$> getState       let (pkgroot , localdir) =             case mbPackageRoot of               Just r -> (r , takeDirectory fp)@@ -1027,9 +1051,9 @@                 s <- getState                 pure (cs, s)             )-            initialEvalState{evalOperations = operations,-                             evalLocalDir = localdir,-                             evalPackageRoot = pkgroot }+            (initialEvalState inputs){evalOperations = operations,+                                      evalLocalDir = localdir,+                                      evalPackageRoot = pkgroot }             fp             ms       case res of
src/Typst/Module/Standard.hs view
@@ -7,15 +7,12 @@ module Typst.Module.Standard   ( standardModule,     symModule,-    sysModule,     loadFileText,     getPath,     applyPureFunction   ) where -import Paths_typst (version)-import Data.Version (showVersion) import Control.Applicative ((<|>)) import Control.Monad (mplus, unless) import Control.Monad.Reader (lift, ReaderT)@@ -36,10 +33,9 @@ import Text.Read (readMaybe) import qualified Text.XML as XML import qualified Toml-import Typst.Emoji (typstEmojis) import Typst.Module.Calc (calcModule) import Typst.Module.Math (mathModule)-import Typst.Symbols (typstSymbols)+import Typst.Symbols (typstSymbols, typstEmojis) import Typst.Types import Typst.Util import System.FilePath.Posix ((</>), normalise)@@ -52,9 +48,9 @@   M.fromList $     [ ("math", VModule "math" mathModule),       ("sym", VModule "sym" symModule),-      ("sys", VModule "sys" sysModule),       ("emoji", VModule "emoji" emojiModule),       ("calc", VModule "calc" calcModule)+      -- sys module is added in initialEvalState     ]       ++ types       ++ colors@@ -68,14 +64,6 @@       ++ construct       ++ time       ++ dataLoading--sysModule :: M.Map Identifier Val-sysModule =-  M.fromList [ ("version", VVersion [0,12,0])-             , ("inputs", VDict (OM.fromList-                                  [("typst-hs-version",-                                    VString (T.pack (showVersion version)))]))-             ]  symModule :: M.Map Identifier Val symModule = M.map VSymbol $ makeSymbolMap typstSymbols
src/Typst/Parse.hs view
@@ -20,7 +20,7 @@ import Text.Parsec.Expr import Text.Read (readMaybe) import Typst.Syntax-import Typst.Shorthands (mathSymbolShorthands)+import Typst.Symbols (mathSymbolShorthands)  -- import Debug.Trace 
src/Typst/Types.hs view
@@ -624,7 +624,8 @@     evalFlowDirective :: FlowDirective,     evalPackageRoot :: FilePath,     evalLocalDir :: FilePath,-    evalOperations :: Operations m+    evalOperations :: Operations m,+    evalInputs :: [(Text, Text)]   }  emptyEvalState :: EvalState m@@ -640,7 +641,8 @@       evalFlowDirective = FlowNormal,       evalPackageRoot = mempty,       evalLocalDir = mempty,-      evalOperations = undefined+      evalOperations = undefined,+      evalInputs = []     }  data Attempt a
src/Typst/Util.hs view
@@ -29,6 +29,7 @@ import qualified Data.Vector as V import Text.Parsec (getPosition) import Typst.Types+import Typst.Symbols (Sym(..))  data TypeSpec   = One ValType@@ -148,11 +149,13 @@ allArgs :: Monad m => ReaderT Arguments (MP m) [Val] allArgs = asks positional -makeSymbolMap :: [(Text, Bool, Text)] -> M.Map Identifier Symbol+makeSymbolMap :: [Sym] -> M.Map Identifier Symbol makeSymbolMap = foldl' go mempty   where-    go :: M.Map Identifier Symbol -> (Text, Bool, Text) -> M.Map Identifier Symbol-    go m (name, accent, v) =+    go :: M.Map Identifier Symbol -> Sym -> M.Map Identifier Symbol+    go m (Sym{ symName = name,+               symIsAccent = accent,+               symText = v }) =       case T.split (== '.') name of         [] -> m         (k : ks) ->
test/Main.hs view
@@ -67,7 +67,7 @@       case parseResult of         Left e -> pure $ fromText $ T.pack $ show e         Right parsed -> do-          evalResult <- evaluateTypst operations input (testParse <> parsed)+          evalResult <- evaluateTypst operations [] input (testParse <> parsed)           let parseOutput = "--- parse tree ---\n" <> T.pack (ppShow parsed) <> "\n"           case evalResult of             Left e ->
typst.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               typst-version:            0.9.0.1+version:            0.10 synopsis:           Parsing and evaluating typst syntax. description:        A library for parsing and evaluating typst syntax.                     Typst (<https://typst.app>) is a document layout and@@ -62,7 +62,7 @@      -- other-extensions:     build-depends:    base >= 4.14 && < 5,-                      typst-symbols >= 0.1.9 && < 0.1.10,+                      typst-symbols >= 0.2 && < 0.3,                       mtl,                       vector,                       parsec,@@ -112,7 +112,8 @@         bytestring,         time,         pretty-show,-        ordered-containers+        ordered-containers,+        optparse-applicative     else       Buildable:         False