Typst writer: don't add semicolons as much.

Previously we added semicolons after inline commands not
followed by spaces, but mainly this was to deal with one issue:
the presence of a semicolon after an inline command, which
would be swallowed as a command separator (#9252).

This commits adopts an approach that should avoid so many
superfluous semicolons: it escapes semicolons that might come
right after a command.  See #11196.
This commit is contained in:
John MacFarlane
2025-10-05 16:33:03 +02:00
parent 208142fcf2
commit e87b86261f
5 changed files with 38 additions and 42 deletions
+6 -10
View File
@@ -443,9 +443,8 @@ inlineToTypst inline =
case cls of
(lang:_) | writerHighlightMethod opts /= NoHighlighting
-> "#raw(lang:" <> doubleQuoted lang <>
", " <> doubleQuoted code <> ")" <> endCode
", " <> doubleQuoted code <> ")"
_ | T.any (=='`') code -> "#raw(" <> doubleQuoted code <> ")"
<> endCode
| otherwise -> "`" <> literal code <> "`"
case writerHighlightMethod opts of
Skylighting _ ->
@@ -503,7 +502,6 @@ inlineToTypst inline =
-> if T.all isIdentChar ident
then pure $ literal $ "@" <> ident
else pure $ "#ref" <> parens (toLabel ArgumentLabel ident)
<> endCode
_ -> do
contents <- inlinesToTypst inlines
let dest = case T.uncons src of
@@ -512,13 +510,13 @@ inlineToTypst inline =
pure $ "#link" <> parens dest <>
(if inlines == [Str src]
then mempty
else nowrap $ brackets contents) <> endCode
else nowrap $ brackets contents)
Image attr _inlines (src,_tit) -> do
opts <- gets stOptions
pure $ mkImage opts True src attr
Note blocks -> do
contents <- blocksToTypst blocks
return $ "#footnote" <> brackets (chomp contents) <> endCode
return $ "#footnote" <> brackets (chomp contents)
-- see #9104; need box or image is treated as block-level
mkImage :: WriterOptions -> Bool -> Text -> Attr -> Doc Text
@@ -544,7 +542,7 @@ mkImage opts useBox src attr
textstyle :: PandocMonad m => Doc Text -> [Inline] -> TW m (Doc Text)
textstyle s inlines = do
(<> endCode) . (s <>) . brackets . fixInitialAfterBreakEscape
(s <>) . brackets . fixInitialAfterBreakEscape
<$> inlinesToTypst inlines
fixInitialAfterBreakEscape :: Doc Text -> Doc Text
@@ -564,6 +562,7 @@ escapeTypst :: Bool -> EscapeContext -> Text -> Doc Text
escapeTypst smart context t =
(case T.uncons t of
Just (c, _)
| c == ';' -> char '\\' -- see #9252
| needsEscapeAtLineStart c || isOrderedListMarker t
-> afterBreak "\\"
_ -> mempty) <>
@@ -654,7 +653,7 @@ toCite cite = do
pure $ (if citationMode cite == SuppressAuthor -- see #11044
then parens
else id)
$ "#cite" <> parens (label <> form <> suppl) <> endCode
$ "#cite" <> parens (label <> form <> suppl)
doubleQuoted :: Text -> Doc Text
doubleQuoted = doubleQuotes . literal . escape
@@ -664,9 +663,6 @@ doubleQuoted = doubleQuotes . literal . escape
escapeChar '"' = "\\\""
escapeChar c = T.singleton c
endCode :: Doc Text
endCode = beforeNonBlank ";"
extractLabel :: Text -> Maybe Text
extractLabel = go . T.unpack
where
+1 -1
View File
@@ -9,7 +9,7 @@
test
] #label("my label")
See #link(label("my label"))[my label];.
See #link(label("my label"))[my label].
```
+1 -1
View File
@@ -14,6 +14,6 @@ Here is a sentence @something2024.
With supplement @something2024[p.~3].
And just the year (#cite(<something2024>, form: "year");).
And just the year (#cite(<something2024>, form: "year")).
```
+1 -1
View File
@@ -5,7 +5,7 @@
table.header(table.cell(align: center)[Name], table.cell(align: center)[Capital], table.cell(align: center)[Population
\
(in 2018)], table.cell(align: center)[Area \
(in km#super[2];)],),
(in km#super[2])],),
table.hline(),
[Denmark], [Copenhagen], [5,809,502], [43,094],
[Finland], [Helsinki], [5,537,364], [338,145],
+29 -29
View File
@@ -490,13 +490,13 @@ yellow fruit
Multiple blocks with italics:
/ #emph[apple];: #block[
/ #emph[apple]: #block[
red fruit
contains seeds, crisp, pleasant to taste
]
/ #emph[orange];: #block[
/ #emph[orange]: #block[
orange fruit
```
@@ -628,27 +628,27 @@ Hr's:
= Inline Markup
<inline-markup>
This is #emph[emphasized];, and so #emph[is this];.
This is #emph[emphasized], and so #emph[is this].
This is #strong[strong];, and so #strong[is this];.
This is #strong[strong], and so #strong[is this].
An #emph[#link("/url")[emphasized link];];.
An #emph[#link("/url")[emphasized link]].
#strong[#emph[This is strong and em.];]
#strong[#emph[This is strong and em.]]
So is #strong[#emph[this];] word.
So is #strong[#emph[this]] word.
#strong[#emph[This is strong and em.];]
#strong[#emph[This is strong and em.]]
So is #strong[#emph[this];] word.
So is #strong[#emph[this]] word.
This is code: `>`, `$`, `\`, `\$`, `<html>`.
#strike[This is #emph[strikeout];.]
#strike[This is #emph[strikeout].]
Superscripts: a#super[bc];d a#super[#emph[hello];] a#super[hello~there];.
Superscripts: a#super[bc]d a#super[#emph[hello]] a#super[hello~there].
Subscripts: H#sub[2];O, H#sub[23];O, H#sub[many~of~them];O.
Subscripts: H#sub[2]O, H#sub[23]O, H#sub[many~of~them]O.
These should not be superscripts or subscripts, because of the unescaped spaces:
a^b c^d, a\~b c\~d.
@@ -666,7 +666,7 @@ a^b c^d, a\~b c\~d.
'He said, "I want to go."' Were you alive in the 70's?
Here is some quoted '`code`' and a
"#link("http://example.com/?foo=1&bar=2")[quoted link];".
"#link("http://example.com/?foo=1&bar=2")[quoted link]".
Some dashes: one---two --- three---four --- five.
@@ -758,13 +758,13 @@ Minus: -
<links>
== Explicit
<explicit>
Just a #link("/url/")[URL];.
Just a #link("/url/")[URL].
#link("/url/")[URL and title];.
#link("/url/")[URL and title].
#link("/url/")[URL and title];.
#link("/url/")[URL and title].
#link("/url/")[URL and title];.
#link("/url/")[URL and title].
#link("/url/")[URL and title]
@@ -774,21 +774,21 @@ Just a #link("/url/")[URL];.
#link("mailto:nobody@nowhere.net")[Email link]
#link("")[Empty];.
#link("")[Empty].
== Reference
<reference>
Foo #link("/url/")[bar];.
Foo #link("/url/")[bar].
With #link("/url/")[embedded \[brackets\]];.
With #link("/url/")[embedded \[brackets\]].
#link("/url/")[b] by itself should be a link.
Indented #link("/url")[once];.
Indented #link("/url")[once].
Indented #link("/url")[twice];.
Indented #link("/url")[twice].
Indented #link("/url")[thrice];.
Indented #link("/url")[thrice].
This should \[not\]\[\] be a link.
@@ -796,20 +796,20 @@ This should \[not\]\[\] be a link.
[not]: /url
```
Foo #link("/url/")[bar];.
Foo #link("/url/")[bar].
Foo #link("/url/")[biz];.
Foo #link("/url/")[biz].
== With ampersands
<with-ampersands>
Here's a
#link("http://example.com/?foo=1&bar=2")[link with an ampersand in the URL];.
#link("http://example.com/?foo=1&bar=2")[link with an ampersand in the URL].
Here's a link with an amersand in the link text: #link("http://att.com/")[AT&T];.
Here's a link with an amersand in the link text: #link("http://att.com/")[AT&T].
Here's an #link("/script?foo=1&bar=2")[inline link];.
Here's an #link("/script?foo=1&bar=2")[inline link].
Here's an #link("/script?foo=1&bar=2")[inline link in pointy braces];.
Here's an #link("/script?foo=1&bar=2")[inline link in pointy braces].
== Autolinks
<autolinks>