diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Revision history for typst-hs
 
+## 0.3.2.1
+
+  * Fix resolution of symbols (#15). Symbols like `dot`, which only have
+    variants, were not being properly resolved: we were getting the
+    last matching variant rather than the first.
+
+  * Avoid text's `readFile` in cli app (#13). Instead read as bytestring and
+    force interpretation as UTF-8.
+
+  * Fix some parser edge cases involving emphasis after `'` (#12).
+
 ## 0.3.2.0
 
   * Add metadata element.
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -6,6 +6,7 @@
 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.Environment (getArgs)
 import System.Directory (doesFileExist)
@@ -18,6 +19,7 @@
 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,
@@ -73,7 +75,8 @@
         Just (Just ms) -> timeout (ms * 1000)
       )
       $ do
-        t <- maybe TIO.getContents TIO.readFile mbfile
+        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
diff --git a/src/Typst/Parse.hs b/src/Typst/Parse.hs
--- a/src/Typst/Parse.hs
+++ b/src/Typst/Parse.hs
@@ -558,12 +558,13 @@
     <|> pure []
 
 pText :: P Markup
-pText =
-  Text . T.pack
-    <$> some
-      ( satisfy (\c -> not (isSpace c || isSpecial c))
-          <|> try ((char '*' <|> char '_') <* lookAhead alphaNum)
-      )
+pText = Text . mconcat <$> some
+  ((do xs <- some alphaNum
+       T.pack . (xs <>) <$>
+             try (some (char '*' <|> char '_') <* lookAhead alphaNum)
+        <|> pure (T.pack xs))
+ <|> (T.pack <$> some (satisfy (\c -> not (isSpace c || isSpecial c))))
+  )
 
 pEscaped :: P Markup
 pEscaped = Text . T.singleton <$> pEsc
diff --git a/src/Typst/Util.hs b/src/Typst/Util.hs
--- a/src/Typst/Util.hs
+++ b/src/Typst/Util.hs
@@ -161,7 +161,17 @@
                 Nothing ->
                   Just $ Symbol v accent (addVariant ks v mempty)
                 Just (Symbol dv da vs) ->
-                  Just $ Symbol dv da (addVariant ks v vs)
+                  Just $ Symbol dv' da variants
+                  where variants = addVariant ks v vs
+                        minModifiers = minimum $ map (Set.size . fst) variants
+                        shortestVariants =
+                          filter ((== minModifiers) . Set.size . fst) variants
+                         -- "When displaying a symbol, Typst selects the first
+                         -- from the variants that have all attached modifiers
+                         -- and the minimum number of other modifiers."
+                        dv' = case map snd shortestVariants of
+                                  [] -> dv
+                                  (x:_) -> x
             )
             (Identifier k)
             m
@@ -170,4 +180,4 @@
       Text ->
       [(Set.Set Text, Text)] ->
       [(Set.Set Text, Text)]
-    addVariant ks v = ((Set.fromList ks, v) :)
+    addVariant ks v = (++ [(Set.fromList ks, v)])
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -33,7 +33,7 @@
 goldenTests = do
   inputs <- findByExtension [".typ"] "test/typ"
   pure $
-    localOption (Timeout 100000 "100ms") $
+    localOption (Timeout 1000000 "1s") $
       testGroup "golden tests" (map runTest inputs)
 
 runTest :: FilePath -> TestTree
diff --git a/test/out/math/syntax-02.out b/test/out/math/syntax-02.out
--- a/test/out/math/syntax-02.out
+++ b/test/out/math/syntax-02.out
@@ -75,7 +75,7 @@
   math.equation(block: true, 
                 body: { text(body: [⋅]), 
                         linebreak(), 
-                        text(body: [⋯]), 
+                        text(body: […]), 
                         linebreak(), 
                         text(body: [∗]), 
                         linebreak(), 
diff --git a/test/out/regression/issue12.out b/test/out/regression/issue12.out
new file mode 100644
--- /dev/null
+++ b/test/out/regression/issue12.out
@@ -0,0 +1,61 @@
+--- parse tree ---
+[ Code
+    "test/typ/regression/issue12.typ"
+    ( line 1 , column 2 )
+    (Let
+       (BasicBind (Just (Identifier "test")))
+       (FuncExpr
+          [ NormalParam (Identifier "x") , NormalParam (Identifier "y") ]
+          (Block
+             (CodeBlock
+                [ If
+                    [ ( Equals (Ident (Identifier "x")) (Ident (Identifier "y"))
+                      , Block (Content [ Text "\9989" ])
+                      )
+                    , ( Literal (Boolean True)
+                      , Block
+                          (Content
+                             [ Text "\10060"
+                             , Text "("
+                             , Code
+                                 "test/typ/regression/issue12.typ"
+                                 ( line 1 , column 47 )
+                                 (FuncCall
+                                    (Ident (Identifier "repr"))
+                                    [ NormalArg (Ident (Identifier "x")) ])
+                             , Space
+                             , Text "/"
+                             , Text "="
+                             , Space
+                             , Code
+                                 "test/typ/regression/issue12.typ"
+                                 ( line 1 , column 59 )
+                                 (FuncCall
+                                    (Ident (Identifier "repr"))
+                                    [ NormalArg (Ident (Identifier "y")) ])
+                             , Text ")"
+                             ])
+                      )
+                    ]
+                ]))))
+, SoftBreak
+, Text "he"
+, Quote '\''
+, Strong [ Text "llo" , Space , Text "World" ]
+, ParBreak
+, Text "l\8217"
+, Strong [ Text "exactitude" ]
+, ParBreak
+, Text "a*b_c_e"
+, ParBreak
+]
+--- evaluated ---
+{ text(body: [
+he’]), 
+  strong(body: text(body: [llo World])), 
+  parbreak(), 
+  text(body: [l’]), 
+  strong(body: text(body: [exactitude])), 
+  parbreak(), 
+  text(body: [a*b_c_e]), 
+  parbreak() }
diff --git a/test/out/regression/issue15.out b/test/out/regression/issue15.out
new file mode 100644
--- /dev/null
+++ b/test/out/regression/issue15.out
@@ -0,0 +1,70 @@
+--- parse tree ---
+[ Code
+    "test/typ/regression/issue15.typ"
+    ( line 1 , column 2 )
+    (Let
+       (BasicBind (Just (Identifier "test")))
+       (FuncExpr
+          [ NormalParam (Identifier "x") , NormalParam (Identifier "y") ]
+          (Block
+             (CodeBlock
+                [ If
+                    [ ( Equals (Ident (Identifier "x")) (Ident (Identifier "y"))
+                      , Block (Content [ Text "\9989" ])
+                      )
+                    , ( Literal (Boolean True)
+                      , Block
+                          (Content
+                             [ Text "\10060"
+                             , Text "("
+                             , Code
+                                 "test/typ/regression/issue15.typ"
+                                 ( line 1 , column 47 )
+                                 (FuncCall
+                                    (Ident (Identifier "repr"))
+                                    [ NormalArg (Ident (Identifier "x")) ])
+                             , Space
+                             , Text "/"
+                             , Text "="
+                             , Space
+                             , Code
+                                 "test/typ/regression/issue15.typ"
+                                 ( line 1 , column 59 )
+                                 (FuncCall
+                                    (Ident (Identifier "repr"))
+                                    [ NormalArg (Ident (Identifier "y")) ])
+                             , Text ")"
+                             ])
+                      )
+                    ]
+                ]))))
+, SoftBreak
+, Equation
+    False
+    [ Code
+        "test/typ/regression/issue15.typ"
+        ( line 2 , column 2 )
+        (Ident (Identifier "dots"))
+    ]
+, SoftBreak
+, Equation
+    False
+    [ Code
+        "test/typ/regression/issue15.typ"
+        ( line 3 , column 2 )
+        (FieldAccess (Ident (Identifier "l")) (Ident (Identifier "quote")))
+    ]
+, ParBreak
+]
+--- evaluated ---
+{ text(body: [
+]), 
+  math.equation(block: false, 
+                body: text(body: […]), 
+                numbering: none), 
+  text(body: [
+]), 
+  math.equation(block: false, 
+                body: text(body: [“]), 
+                numbering: none), 
+  parbreak() }
diff --git a/test/typ/regression/issue12.typ b/test/typ/regression/issue12.typ
new file mode 100644
--- /dev/null
+++ b/test/typ/regression/issue12.typ
@@ -0,0 +1,5 @@
+he'*llo World*
+
+l’*exactitude*
+
+a*b_c_e
diff --git a/test/typ/regression/issue15.typ b/test/typ/regression/issue15.typ
new file mode 100644
--- /dev/null
+++ b/test/typ/regression/issue15.typ
@@ -0,0 +1,2 @@
+$dots$
+$quote.l$
diff --git a/typst.cabal b/typst.cabal
--- a/typst.cabal
+++ b/typst.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               typst
-version:            0.3.2.0
+version:            0.3.2.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
