packages feed

typst 0.12 → 0.12.1

raw patch · 19 files changed

+868/−83 lines, 19 filesdep +yamletdep −yamlPVP ok

version bump matches the API change (PVP)

Dependencies added: yamlet

Dependencies removed: yaml

API changes (from Hackage documentation)

+ Typst.Types: instance Yamlet.Internal.FromYaml.FromYaml Typst.Types.Val

Files

CHANGELOG.md view
@@ -1,5 +1,30 @@ # Revision history for typst-hs +## 0.12.1++  * Tests: read top-level test files as raw bytes. This matches how+    imports and the executable read files. Previously the tests read+    them through a text handle, which should strip CRs on Windows.++  * Tests: handle Windows paths and line endings. Golden files record+    paths with forward slashes, and git converts them to CRLF when+    checking them out on Windows.++  * Switch to yamlet (#110, Théophile Choutri de Tarlé). This gives us+    order-preserving mappings, as in typst itself, as well as correct+    YAML semantics.++  * Identify filepath in package relative to package root (#111).+    This ensures that when we are interpreting modules that+    don't reside at the package root, we get the right `evalLocalDir`+    and resolve relative imports correctly.++  * Fix path of entry point module for imports.++  * Match Typst shorthand reference lexing (#108, Samuel Huang).+    Require a label character after @, greedily consume internal+    punctuation, and keep supplement failures fatal.+ ## 0.12    * Support 'in' operator on modules (#106).
src/Typst/Evaluate.hs view
@@ -29,8 +29,7 @@ import qualified Data.Text.Encoding as TE import qualified Data.Vector as V import GHC.Generics (Generic)-import System.FilePath (replaceFileName, takeBaseName,-                        takeFileName, takeDirectory, (</>))+import System.FilePath (takeBaseName, makeRelative, takeDirectory, (</>)) import Text.Parsec import Typst.Bind (destructuringBind, doBind) import Typst.Constructors (getConstructor)@@ -1061,7 +1060,7 @@   case Toml.decode tomlString of     Toml.Failure e -> fail (unlines ("Failure loading typst.toml" : e))     Toml.Success _warnings cfg -> -- ignores warnings like unused keys in TOML-      pure (replaceFileName tomlPath (entrypoint (package cfg)))+      pure (takeDirectory tomlPath </> entrypoint (package cfg))  loadModule :: Monad m => Text            -> MP m (Seq Content, (Identifier, M.Map Identifier Val))@@ -1080,7 +1079,7 @@                      then pure dir'                      else findPkgRoot (takeDirectory dir')             pkgroot <- findPkgRoot (takeDirectory fp')-            pure ( takeFileName fp',+            pure ( makeRelative pkgroot fp',                    Identifier                     (T.pack $ takeWhile (/= ':') . takeBaseName $                        T.unpack modname),
src/Typst/Module/Standard.hs view
@@ -21,6 +21,7 @@ import qualified Data.Aeson as Aeson import qualified Data.ByteString.Lazy as BL import qualified Data.Csv as Csv+import qualified Data.List.NonEmpty as NE import qualified Data.Map as M import qualified Data.Map.Ordered as OM import Data.Maybe (mapMaybe)@@ -30,7 +31,7 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as TE import qualified Data.Vector as V-import qualified Data.Yaml as Yaml+import qualified Yamlet import Text.Parsec (getPosition, getState, updateState, runParserT) import Text.Read (readMaybe) import qualified Text.XML as XML@@ -583,19 +584,19 @@           Just VAuto -> pure Nothing           Just VNone -> pure Nothing           Just v -> Just <$> f v-    paint <- override paint asColor mbPaint-    thickness <- override thickness asLength mbThickness-    cap <- override cap asLineCap mbCap-    join <- override join asLineJoin mbJoin-    miterLimit <- override miterLimit asMiterLimit mbMiterLimit+    paintValue <- override paint asColor mbPaint+    thicknessValue <- override thickness asLength mbThickness+    capValue <- override cap asLineCap mbCap+    joinValue <- override join asLineJoin mbJoin+    miterLimitValue <- override miterLimit asMiterLimit mbMiterLimit     pure $       VStroke $         emptyStroke-          { paint = paint,-            thickness = thickness,-            cap = cap,-            join = join,-            miterLimit = miterLimit+          { paint = paintValue,+            thickness = thicknessValue,+            cap = capValue,+            join = joinValue,+            miterLimit = miterLimitValue           }  loremWords :: [Text]@@ -710,8 +711,8 @@     ( "yaml",       makeFunction $ do         bs <- getFileOrBytes-        case Yaml.decodeEither' (BL.toStrict bs) of-          Left e -> fail $ show e+        case Yamlet.decode (BL.toStrict bs) of+          Left es -> fail $ unlines $ map (Yamlet.prettyError "yaml") $ NE.toList es           Right (v :: Val) -> pure v     ),     ( "read",@@ -800,20 +801,20 @@         Just VAuto -> pure Nothing         Just VNone -> pure Nothing         Just v -> Just <$> f v-  paint <- field "paint" asColor-  thickness <- field "thickness" asLength-  cap <- field "cap" asLineCap-  join <- field "join" asLineJoin-  miterLimit <- field "miter-limit" asMiterLimit+  paintValue <- field "paint" asColor+  thicknessValue <- field "thickness" asLength+  capValue <- field "cap" asLineCap+  joinValue <- field "join" asLineJoin+  miterLimitValue <- field "miter-limit" asMiterLimit   -- Unknown keys (e.g. `dash` until it is supported) are ignored;   -- typst rejects them.   pure $     emptyStroke-      { paint = paint,-        thickness = thickness,-        cap = cap,-        join = join,-        miterLimit = miterLimit+      { paint = paintValue,+        thickness = thicknessValue,+        cap = capValue,+        join = joinValue,+        miterLimit = miterLimitValue       }  asColor :: MonadFail m => Val -> m Color
src/Typst/Parse.hs view
@@ -761,10 +761,13 @@       ))  pRef :: P Markup-pRef =-  Ref-    <$> (char '@' *> (T.pack <$> many1 (satisfy isIdentContinue <|> char '_')))-    <*> option (Literal Auto) (Block <$> pContent)+pRef = do+  let labelChars = many1 (satisfy isIdentContinue)+      labelMore = (++) <$> many1 (oneOf ".:") <*> labelChars+      labelRest = mconcat <$> many (try labelMore)+  target <- try (char '@' *> ((++) <$> labelChars <*> labelRest))+  supplement <- option (Literal Auto) (Block <$> pContent)+  pure $ Ref (T.pack target) supplement  -- "If a character would continue the expression but should be interpreted as -- text, the expression can forcibly be ended with a semicolon (;)."
src/Typst/Regex.hs view
@@ -21,7 +21,6 @@ import qualified Data.Array as Array import Data.Text (Text) import qualified Data.Text as T-import Data.Typeable (Typeable) import Text.Regex.TDFA (Regex, extract) import qualified Text.Regex.TDFA as TDFA import qualified Text.Regex.TDFA.Text as TDFA@@ -31,7 +30,6 @@ -- | A regular expression. Note that typst-hs does not use the same Regex engine -- as Typst. See issue [#28](https://github.com/jgm/typst-hs/issues/28). data RE = RE !Text !Regex-  deriving (Typeable)  instance Eq RE where   RE t1 _ == RE t2 _ = t1 == t2@@ -48,7 +46,7 @@     matchText :: Text,     matchCaptures :: [Text]   }-  deriving (Eq, Ord, Typeable)+  deriving (Eq, Ord)  replaceRegex :: RE -> Maybe Int -> (RegexMatch -> Text) -> Text -> Text replaceRegex (RE _ re) mbCount replaceFn strIn =
src/Typst/Syntax.hs view
@@ -17,7 +17,7 @@   ) where -import Data.Data (Data, Typeable)+import Data.Data (Data) import Data.String import Data.Text (Text) import qualified Data.Text as T@@ -52,10 +52,10 @@   | MFrac Markup Markup   | MAttach (Maybe Markup) (Maybe Markup) Markup -- bottom then top   | MGroup (Maybe Text) (Maybe Text) [Markup] -- maybes are open/cloes delims-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  newtype Identifier = Identifier Text-  deriving (Show, Eq, Ord, Data, Typeable, Semigroup, Monoid)+  deriving (Show, Eq, Ord, Data, Semigroup, Monoid)  instance IsString Identifier where   fromString = Identifier . T.pack@@ -66,7 +66,7 @@   | ArrayArg [[Markup]]   | SpreadArg Expr   | BlockArg [Markup]-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Param   = DefaultParam Identifier Expr@@ -74,23 +74,23 @@   | DestructuringParam [BindPart]   | SinkParam (Maybe Identifier)   | SkipParam -- _-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Bind   = BasicBind (Maybe Identifier)   | DestructuringBind [BindPart]   | ExprBind Expr-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data BindPart   = Simple Bind   | WithKey Identifier Bind   | Sink (Maybe Identifier)   | ExprSink Expr-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Unit = Pt | Mm | Cm | In | Deg | Rad | Em | Fr | Percent-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Literal   = String Text@@ -100,17 +100,17 @@   | Numeric Double Unit   | None   | Auto-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Block   = Content [Markup]   | CodeBlock [Expr]-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Spreadable a =     Spr Expr   | Reg a-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  -- binary-op ::= --   '+' | '-' | '*' | '/' | 'and' | 'or' | '==' | '!=' |@@ -157,10 +157,10 @@   | Break   | Continue   | Underscore-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)  data Imports   = AllIdentifiers   | SomeIdentifiers [(Identifier, Maybe Identifier)] -- Maybe is the 'as'   | NoIdentifiers (Maybe Identifier)  -- Maybe is the 'as'-  deriving (Show, Ord, Eq, Data, Typeable)+  deriving (Show, Ord, Eq, Data)
src/Typst/Types.hs view
@@ -57,13 +57,12 @@ import Data.Aeson (FromJSON, parseJSON) import qualified Data.Aeson as Aeson import qualified Data.ByteString as BS-import Data.Data (Typeable) import qualified Data.Foldable as F import Data.Functor.Classes (Ord1 (liftCompare)) import qualified Data.Map as M import qualified Data.Map.Ordered as OM import Data.Maybe (fromMaybe, isJust, isNothing, catMaybes)-import Data.Scientific (floatingOrInteger)+import Data.Scientific (floatingOrInteger, toRealFloat) import Data.Sequence (Seq) import qualified Data.Sequence as Seq import qualified Data.Set as Set@@ -79,6 +78,15 @@ import qualified Toml.Pretty as Toml import qualified Text.PrettyPrint as P import Text.Read (readMaybe)+import Yamlet+  ( FloatValue (..),+    FromYaml (..),+    View (..),+    parseItems,+    parseNode,+    typeMismatch,+    view,+  ) import Typst.Regex (RE, makeLiteralRE) import Typst.Syntax (Identifier (..), Markup) import Data.Time (UTCTime, Day, DiffTime, timeOfDayToTime, localDay, localTimeOfDay)@@ -154,7 +162,7 @@   -- already resolved (relative to the file in which it was constructed).   | VPath !FilePath   | VType !ValType-  deriving (Show, Eq, Typeable)+  deriving (Show, Eq)  instance FromJSON Val where   parseJSON v@(Aeson.Object {}) =@@ -166,6 +174,26 @@   parseJSON (Aeson.Bool b) = pure $ VBoolean b   parseJSON Aeson.Null = pure VNone +-- | Like Typst, keeps the order of the keys of a mapping and drops the+-- keys that are not strings.+instance FromYaml Val where+  parseYaml = parseNode $ \n -> case view n of+    NullView -> pure VNone+    BoolView b -> pure $ VBoolean b+    IntView i -> pure $ VInteger i+    FloatView f -> pure $ VFloat $ case f of+      Finite s -> toRealFloat s+      NegativeZero -> -0.0+      Infinity -> 1 / 0+      NegativeInfinity -> -1 / 0+      NaN -> 0 / 0+    StringView t -> pure $ VString t+    SequenceView xs -> VArray . V.fromList <$> parseItems parseYaml xs+    MappingView kvs -> do+      let (ks, vs) = unzip [(Identifier k, v) | (kn, v) <- kvs, StringView k <- [view kn]]+      VDict . OM.fromList . zip ks <$> parseItems parseYaml vs+    AliasView _ -> typeMismatch "a value" n+ instance Toml.FromValue Val where   fromValue = pure . tomlToVal @@ -219,7 +247,7 @@   | TType   | TAny   | ValType :|: ValType-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  valType :: Val -> ValType valType v =@@ -370,14 +398,14 @@   | SelectAnd Selector Selector   | SelectBefore Selector Selector   | SelectAfter Selector Selector-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  data Symbol = Symbol   { symDefault :: !Text,     symAccent :: !Bool,     symVariants :: [(Set.Set Text, Text)]   }-  deriving (Show, Eq, Typeable)+  deriving (Show, Eq)  joinVals :: MonadFail m => Val -> Val -> m Val joinVals = go@@ -587,7 +615,7 @@         eltPos :: Maybe SourcePos,         eltFields :: M.Map Identifier Val       }-  deriving (Show, Typeable)+  deriving (Show)  instance Eq Content where   Txt t1 == Txt t2 = t1 == t2@@ -610,7 +638,6 @@   fromString x = Txt (T.pack x)  newtype Function = Function (forall m. Monad m => Arguments -> MP m Val)-  deriving (Typeable)  instance Show Function where   show _ = "<function>"@@ -679,7 +706,7 @@ data Attempt a   = Success a   | Failure String-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  instance Functor Attempt where   fmap f (Success x) = Success (f x)@@ -715,7 +742,7 @@   { positional :: [Val],     named :: OM.OMap Identifier Val   }-  deriving (Show, Eq, Typeable)+  deriving (Show, Eq)  instance Semigroup Arguments where   Arguments ps1 ns1 <> Arguments ps2 ns2 =@@ -756,16 +783,16 @@   | CounterLabel !Text   | CounterSelector !Selector   | CounterPage-  deriving (Eq, Ord, Show, Typeable)+  deriving (Eq, Ord, Show)  data LUnit = LEm | LPt | LIn | LCm | LMm-  deriving (Show, Eq, Typeable)+  deriving (Show, Eq)  data Length   = LExact Double LUnit   | LRatio !Rational   | LSum Length Length-  deriving (Show, Eq, Typeable)+  deriving (Show, Eq)  instance Semigroup Length where   (LExact x xu) <> (LExact y yu)@@ -842,16 +869,16 @@ negateLength (LSum x y) = LSum (negateLength x) (negateLength y)  data Horiz = HorizStart | HorizEnd | HorizLeft | HorizCenter | HorizRight-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  data Vert = VertTop | VertHorizon | VertBottom-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  data Color   = RGB Rational Rational Rational Rational   | CMYK Rational Rational Rational Rational   | Luma Rational-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  data Stroke = Stroke   { paint :: !(Maybe Color), -- Nothing = auto (default: black)@@ -860,7 +887,7 @@     join :: !(Maybe Text), -- Nothing = auto (default: "miter")     miterLimit :: !(Maybe Double) -- Nothing = auto (default: 4.0)   }-  deriving (Show, Eq, Typeable)+  deriving (Show, Eq)  -- | A stroke with every field unset (auto). emptyStroke :: Stroke@@ -883,7 +910,7 @@   | Rtl -- ^ Right to left   | Ttb -- ^ Top to bottom   | Btt -- ^ Bottom to top-  deriving (Show, Eq, Ord, Typeable)+  deriving (Show, Eq, Ord)  -- | Render a set stroke field for the parenthesized stroke repr. strokeField :: Text -> Maybe P.Doc -> [P.Doc]
src/Typst/Util.hs view
@@ -20,7 +20,7 @@  import Control.Monad (foldM) import Control.Monad.Reader (ReaderT (runReaderT), asks)-import Data.List (foldl')+import qualified Data.List as List import qualified Data.Map as M import qualified Data.Map.Ordered as OM import qualified Data.Sequence as Seq@@ -157,7 +157,7 @@ allArgs = asks positional  makeSymbolMap :: [Sym] -> M.Map Identifier Symbol-makeSymbolMap = foldl' go mempty+makeSymbolMap = List.foldl' go mempty   where     go :: M.Map Identifier Symbol -> Sym -> M.Map Identifier Symbol     go m (Sym{ symName = name,
test/Main.hs view
@@ -7,8 +7,8 @@ import qualified Data.ByteString.Lazy as BL import qualified Data.Text as T import qualified Data.Text.Encoding as TE-import Data.Text.IO as TIO import System.FilePath (replaceExtension)+import System.Info (os) import Test.Tasty (TestTree, Timeout (..), defaultMain, localOption, testGroup) import Test.Tasty.Golden (findByExtension, goldenVsStringDiff) import Text.Show.Pretty (ppShow)@@ -41,7 +41,11 @@   inputs <- findByExtension [".typ"] "typ"   pure $     localOption (Timeout 1000000 "1s") $-      testGroup "golden tests" (map (runTest testParse) inputs)+      testGroup "golden tests" (map (runTest testParse . map fixSeparator) inputs)+  where+    -- Golden files record paths with forward slashes.+    fixSeparator '\\' = '/'+    fixSeparator c = c  runTest :: [Markup] -> FilePath -> TestTree runTest testParse input =@@ -53,8 +57,8 @@  writeTest :: [Markup] -> FilePath -> IO BL.ByteString writeTest testParse input = do-  let fromText = BL.fromStrict . TE.encodeUtf8 . (<> "\n")-  contents <- TIO.readFile input+  let fromText = BL.fromStrict . TE.encodeUtf8 . nativeNewlines . (<> "\n")+  contents <- TE.decodeUtf8 <$> BS.readFile input   if "// Error"     `T.isInfixOf` contents     || "cycle1.typ"@@ -77,3 +81,9 @@             Right c -> do               let evalOutput = "--- evaluated ---\n" <> repr (VContent [c])               pure $ fromText $ parseOutput <> evalOutput++-- Git converts golden files to CRLF when checking them out on Windows.+nativeNewlines :: T.Text -> T.Text+nativeNewlines+  | os == "mingw32" = T.replace "\n" "\r\n"+  | otherwise = id
test/typ/compute/data-10.out view
@@ -133,11 +133,7 @@ ]),                   text(body: [ ]), -                 text(body: [❌(]), -                 text(body: [8]), -                 text(body: [ /= ]), -                 text(body: [7]), -                 text(body: [)]), +                 text(body: [✅]),                   text(body: [ ]),                   text(body: [✅]), @@ -161,9 +157,5 @@                  text(body: [✅]),                   text(body: [ ]), -                 text(body: [❌(]), -                 text(body: [true]), -                 text(body: [ /= ]), -                 text(body: [false]), -                 text(body: [)]), +                 text(body: [✅]),                   parbreak() })
+ test/typ/regression/issue108-colon.out view
@@ -0,0 +1,71 @@+--- parse tree ---+[ Heading 1 [ Text "First" ]+, Space+, Code+    "typ/regression/issue108-colon.typ"+    ( line 1 , column 9 )+    (Label "my-anchor::")+, ParBreak+, Heading 1 [ Text "Second" ]+, Space+, Code+    "typ/regression/issue108-colon.typ"+    ( line 3 , column 10 )+    (Label "my-anchor")+, ParBreak+, Text "Please"+, Space+, Text "see"+, Space+, Code+    "typ/regression/issue108-colon.typ"+    ( line 5 , column 13 )+    (FuncCall+       (Ident (Identifier "ref")) [ NormalArg (Label "my-anchor::") ])+, Text "."+, ParBreak+, Text "Please"+, Space+, Text "see"+, Space+, Code+    "typ/regression/issue108-colon.typ"+    ( line 7 , column 13 )+    (FuncCall+       (Ident (Identifier "ref")) [ NormalArg (Label "my-anchor") ])+, Text "."+, ParBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text ":"+, Text "."+, ParBreak+]+--- evaluated ---+document(body: { heading(body: text(body: [First]), +                         level: 1), +                 text(body: [ ]), +                 <my-anchor::>, +                 parbreak(), +                 heading(body: text(body: [Second]), +                         level: 1), +                 text(body: [ ]), +                 <my-anchor>, +                 parbreak(), +                 text(body: [Please see ]), +                 ref(target: <my-anchor::>), +                 text(body: [.]), +                 parbreak(), +                 text(body: [Please see ]), +                 ref(target: <my-anchor>), +                 text(body: [.]), +                 parbreak(), +                 text(body: [Please see ]), +                 ref(supplement: auto, +                     target: <my-anchor>), +                 text(body: [::.]), +                 parbreak() })
+ test/typ/regression/issue108-colon.typ view
@@ -0,0 +1,9 @@+= First <my-anchor::>++= Second <my-anchor>++Please see #ref(<my-anchor::>).++Please see #ref(<my-anchor>).++Please see @my-anchor::.
+ test/typ/regression/issue108-differential.out view
@@ -0,0 +1,540 @@+--- parse tree ---+[ Code+    "typ/regression/issue108-differential.typ"+    ( line 1 , column 2 )+    (Show+       (Just (Ident (Identifier "ref")))+       (FuncExpr+          [ NormalParam (Identifier "it") ]+          (Block+             (Content+                [ Code+                    "typ/regression/issue108-differential.typ"+                    ( line 1 , column 20 )+                    (FuncCall+                       (Ident (Identifier "str"))+                       [ NormalArg+                           (FieldAccess+                              (Ident (Identifier "target")) (Ident (Identifier "it")))+                       ])+                ]))))+, SoftBreak+, Heading 1 [ Text "First" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 2 , column 9 )+    (Label "my-anchor::")+, SoftBreak+, Heading 1 [ Text "Second" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 3 , column 10 )+    (Label "my-anchor")+, SoftBreak+, Heading 1 [ Text "Colon" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 4 , column 9 )+    (Label "tab:attributes")+, SoftBreak+, Heading 1 [ Text "Dot" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 5 , column 7 )+    (Label "fig:sub.1")+, SoftBreak+, Heading 1 [ Text "Unicode" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 6 , column 11 )+    (Label "\945:\946.\947")+, SoftBreak+, Heading 1 [ Text "Multi" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 7 , column 9 )+    (Label "a:b.c:d")+, SoftBreak+, Heading 1 [ Text "Short" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 8 , column 9 )+    (Label "fig")+, SoftBreak+, Heading 1 [ Text "Longer" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 9 , column 10 )+    (Label "fig:alpha")+, SoftBreak+, Heading 1 [ Text "Dotted" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 10 , column 10 )+    (Label "a.b.")+, SoftBreak+, Heading 1 [ Text "Run" , Space , Text "One" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 11 , column 11 )+    (Label "a..b")+, SoftBreak+, Heading 1 [ Text "Run" , Space , Text "Two" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 12 , column 11 )+    (Label "a.:b")+, SoftBreak+, Heading 1 [ Text "Run" , Space , Text "Three" ]+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 13 , column 13 )+    (Label "a::b")+, ParBreak+, Text "Please"+, Space+, Text "see"+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 15 , column 13 )+    (FuncCall+       (Ident (Identifier "ref")) [ NormalArg (Label "my-anchor::") ])+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 16 , column 13 )+    (FuncCall+       (Ident (Identifier "ref")) [ NormalArg (Label "my-anchor") ])+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text ":"+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "tab:attributes" (Literal Auto)+, Text ","+, Space+, Ref "fig:sub.1" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "\945:\946.\947" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "a:b.c:d" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "fig" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "fig:alpha" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "fig:alpha" (Literal Auto)+, Space+, Text "and"+, Space+, Ref "fig:alpha" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text ":"+, Space+, Text "trailing"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Space+, Text "trailing"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text "."+, Space+, Text "trailing"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text ":"+, Space+, Text "trailing"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text "["+, Text "note"+, Text "]"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text "."+, Space+, Text "["+, Text "note"+, Text "]"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Space+, Text "["+, Text "note"+, Text "]"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor" (Literal Auto)+, Space+, Text "["+, Text "note"+, Text "]"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Text "@"+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Text "@"+, Text ":"+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "unknown:x" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "unknown:x" (Literal Auto)+, Space+, Text "and"+, Space+, Ref "unknown:y" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "a.b" (Literal Auto)+, Text "."+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Text "@"+, Text "."+, Text "x"+, Space+, Text "and"+, Space+, Text "@"+, Text ":"+, Text "x"+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "a..b" (Literal Auto)+, Text ","+, Space+, Ref "a.:b" (Literal Auto)+, Text ","+, Space+, Ref "a::b" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "a" (Literal Auto)+, Text "."+, Text "."+, Space+, Text "and"+, Space+, Ref "a:b" (Literal Auto)+, Text ":"+, Text "."+, ParBreak+, Text "See"+, Space+, Ref "my-anchor" (Literal Auto)+, Text ":"+, Text "."+, Space+, Code+    "typ/regression/issue108-differential.typ"+    ( line 43 , column 19 )+    (Let (BasicBind (Just (Identifier "z"))) (Literal (Int 1)))+, ParBreak+]+--- evaluated ---+document(body: { text(body: [+]), +                 heading(body: text(body: [First]), +                         level: 1), +                 text(body: [ ]), +                 <my-anchor::>, +                 text(body: [+]), +                 heading(body: text(body: [Second]), +                         level: 1), +                 text(body: [ ]), +                 <my-anchor>, +                 text(body: [+]), +                 heading(body: text(body: [Colon]), +                         level: 1), +                 text(body: [ ]), +                 <tab:attributes>, +                 text(body: [+]), +                 heading(body: text(body: [Dot]), +                         level: 1), +                 text(body: [ ]), +                 <fig:sub.1>, +                 text(body: [+]), +                 heading(body: text(body: [Unicode]), +                         level: 1), +                 text(body: [ ]), +                 <α:β.γ>, +                 text(body: [+]), +                 heading(body: text(body: [Multi]), +                         level: 1), +                 text(body: [ ]), +                 <a:b.c:d>, +                 text(body: [+]), +                 heading(body: text(body: [Short]), +                         level: 1), +                 text(body: [ ]), +                 <fig>, +                 text(body: [+]), +                 heading(body: text(body: [Longer]), +                         level: 1), +                 text(body: [ ]), +                 <fig:alpha>, +                 text(body: [+]), +                 heading(body: text(body: [Dotted]), +                         level: 1), +                 text(body: [ ]), +                 <a.b.>, +                 text(body: [+]), +                 heading(body: text(body: [Run One]), +                         level: 1), +                 text(body: [ ]), +                 <a..b>, +                 text(body: [+]), +                 heading(body: text(body: [Run Two]), +                         level: 1), +                 text(body: [ ]), +                 <a.:b>, +                 text(body: [+]), +                 heading(body: text(body: [Run Three]), +                         level: 1), +                 text(body: [ ]), +                 <a::b>, +                 parbreak(), +                 text(body: [Please see ]), +                 text(body: [<my-anchor::>]), +                 text(body: [.+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [.+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [::.+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [:.+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [.+Please see ]), +                 text(body: [<tab:attributes>]), +                 text(body: [, ]), +                 text(body: [<fig:sub.1>]), +                 text(body: [.+Please see ]), +                 text(body: [<α:β.γ>]), +                 text(body: [.+Please see ]), +                 text(body: [<a:b.c:d>]), +                 text(body: [.+Please see ]), +                 text(body: [<fig>]), +                 text(body: [.+Please see ]), +                 text(body: [<fig:alpha>]), +                 text(body: [.+Please see ]), +                 text(body: [<fig:alpha>]), +                 text(body: [ and ]), +                 text(body: [<fig:alpha>]), +                 text(body: [.+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [:: trailing+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [: trailing+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [. trailing+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [:: trailing+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [:[note]+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [. [note]+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [: [note]+Please see ]), +                 text(body: [<my-anchor>]), +                 text(body: [ [note]+Please see @.+Please see @:+Please see ]), +                 text(body: [<unknown:x>]), +                 text(body: [.+Please see ]), +                 text(body: [<unknown:x>]), +                 text(body: [ and ]), +                 text(body: [<unknown:y>]), +                 text(body: [.+Please see ]), +                 text(body: [<a.b>]), +                 text(body: [..+Please see @.x and @:x.+Please see ]), +                 text(body: [<a..b>]), +                 text(body: [, ]), +                 text(body: [<a.:b>]), +                 text(body: [, ]), +                 text(body: [<a::b>]), +                 text(body: [.+Please see ]), +                 text(body: [<a>]), +                 text(body: [.. and ]), +                 text(body: [<a:b>]), +                 text(body: [:.]), +                 parbreak(), +                 text(body: [See ]), +                 text(body: [<my-anchor>]), +                 text(body: [:. ]), +                 parbreak() })
+ test/typ/regression/issue108-differential.typ view
@@ -0,0 +1,43 @@+#show ref: it => [#str(it.target)]+= First <my-anchor::>+= Second <my-anchor>+= Colon <tab:attributes>+= Dot <fig:sub.1>+= Unicode <α:β.γ>+= Multi <a:b.c:d>+= Short <fig>+= Longer <fig:alpha>+= Dotted <a.b.>+= Run One <a..b>+= Run Two <a.:b>+= Run Three <a::b>++Please see #ref(<my-anchor::>).+Please see #ref(<my-anchor>).+Please see @my-anchor::.+Please see @my-anchor:.+Please see @my-anchor.+Please see @tab:attributes, @fig:sub.1.+Please see @α:β.γ.+Please see @a:b.c:d.+Please see @fig.+Please see @fig:alpha.+Please see @fig:alpha and @fig:alpha.+Please see @my-anchor:: trailing+Please see @my-anchor: trailing+Please see @my-anchor. trailing+Please see @my-anchor:: trailing+Please see @my-anchor:[note]+Please see @my-anchor. [note]+Please see @my-anchor: [note]+Please see @my-anchor [note]+Please see @.+Please see @:+Please see @unknown:x.+Please see @unknown:x and @unknown:y.+Please see @a.b..+Please see @.x and @:x.+Please see @a..b, @a.:b, @a::b.+Please see @a.. and @a:b:.++See @my-anchor:. #let z = 1
+ test/typ/regression/issue108-hyphen.out view
@@ -0,0 +1,56 @@+--- parse tree ---+[ Code+    "typ/regression/issue108-hyphen.typ"+    ( line 1 , column 2 )+    (Show+       (Just (Ident (Identifier "ref")))+       (FuncExpr+          [ NormalParam (Identifier "it") ]+          (Block+             (Content+                [ Code+                    "typ/regression/issue108-hyphen.typ"+                    ( line 1 , column 20 )+                    (FuncCall+                       (Ident (Identifier "str"))+                       [ NormalArg+                           (FieldAccess+                              (Ident (Identifier "target")) (Ident (Identifier "it")))+                       ])+                ]))))+, SoftBreak+, Heading 1 [ Text "Hyphen" ]+, Space+, Code+    "typ/regression/issue108-hyphen.typ"+    ( line 2 , column 10 )+    (Label "my-anchor-")+, ParBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor-" (Literal Auto)+, Text "."+, SoftBreak+, Text "Please"+, Space+, Text "see"+, Space+, Ref "my-anchor-" (Block (Content [ Text "note" ]))+, ParBreak+]+--- evaluated ---+document(body: { text(body: [+]), +                 heading(body: text(body: [Hyphen]), +                         level: 1), +                 text(body: [ ]), +                 <my-anchor->, +                 parbreak(), +                 text(body: [Please see ]), +                 text(body: [<my-anchor->]), +                 text(body: [.+Please see ]), +                 text(body: [<my-anchor->]), +                 parbreak() })
+ test/typ/regression/issue108-hyphen.typ view
@@ -0,0 +1,5 @@+#show ref: it => [#str(it.target)]+= Hyphen <my-anchor->++Please see @my-anchor-.+Please see @my-anchor-[note]
+ test/typ/regression/issue108-unclosed.out view
@@ -0,0 +1,3 @@+"typ/regression/issue108-unclosed.typ" (line 4, column 1):+unexpected end of input+expecting "*/", "//", "/*", new-line, "=", "\\", "*", "_", "$", "-", "+", digit, "/", "http://", "https://", letter or digit, "```", "`", "~", ".", "'", "\"", "<", "@", "#" or unclosed delimiter at"typ/regression/issue108-unclosed.typ" (line 3, column 22)
+ test/typ/regression/issue108-unclosed.typ view
@@ -0,0 +1,3 @@+= Anchor <my-anchor>++Please see @my-anchor[unclosed
typst.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               typst-version:            0.12+version:            0.12.1 synopsis:           Parsing and evaluating typst syntax. description:        A library for parsing and evaluating typst syntax.                     Typst (<https://typst.app>) is a document layout and@@ -76,7 +76,7 @@                       aeson,                       scientific,                       xml-conduit,-                      yaml,+                      yamlet >= 1.0 && < 2,                       toml-parser ^>= 2.0.0.0,                       regex-tdfa,                       array,