pandoc 3.1.10 → 3.1.11
raw patch · 7 files changed
+203/−129 lines, 7 filesdep ~texmathdep ~typstPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: texmath, typst
API changes (from Hackage documentation)
+ Text.Pandoc.Logging: MakePDFInfo :: Text -> Text -> LogMessage
+ Text.Pandoc.Logging: MakePDFWarning :: Text -> LogMessage
Files
- MANUAL.txt +1/−1
- changelog.md +43/−0
- pandoc.cabal +3/−3
- src/Text/Pandoc/Logging.hs +15/−0
- src/Text/Pandoc/PDF.hs +94/−87
- src/Text/Pandoc/Writers/Typst.hs +16/−7
- test/writer.typst +31/−31
MANUAL.txt view
@@ -1,7 +1,7 @@ --- title: Pandoc User's Guide author: John MacFarlane-date: December 11, 2023+date: December 15, 2023 --- # Synopsis
changelog.md view
@@ -1,5 +1,48 @@ # Revision history for pandoc +## pandoc 3.1.11 (2023-12-15)++ * Typst writer:++ + Emit `;` after typst code, unless followed by space (#9252).+ Otherwise there's the potential that the typst code will swallow+ up a following character.++ * Text.Pandoc.Logging:++ + Add `MakePDFWarning` constructor to LogMessage [API change].+ + Add `MakePDFInfo` constructor to LogMessage [API change].++ * Text.Pandoc.PDF:++ + LaTeX warnings are passed on to the user as warnings.+ + Use `report` with `MakePDFWarning` and `MakePDFInfo` to relay+ verbose information and warnings, instead of writing directly+ to stderr.+ + Parse logs to determine whether additional runs needed, instead of+ running a fixed number of times (#9255). (The number of times+ that was appropriate given pandoc's default templates didn't+ always work for custom templates, and thus pandoc 3.1.10's+ change in the number of runs led to some regressions in PDF+ production.)++ * Makefile: in `make prelease`, add checks that pandoc-cli and+ pandoc have the same version, that pandoc-cli depends on this+ exact version of pandoc, that there is an entry for this version+ in the changelog, and that the version numbers in the+ generated man pages are correct.++ * Regenerate man pages with pandoc 3.1.10. This properly escapes hyphens+ and fixes version numbers in man pages for `pandoc-server` and+ `pandoc-lua`.++ * Depend on texmath 0.12.8.6. This omits unneeded `lr`s in typst+ math output.++ * Depend on typst 0.5. This allows the typst reader to support+ multiline strings, the version type, and the `as`+ keyword with `import`.+ ## pandoc 3.1.10 (2023-12-12) * Link pandoc-cli version to pandoc version. Henceforth pandoc-cli's
pandoc.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: pandoc-version: 3.1.10+version: 3.1.11 build-type: Simple license: GPL-2.0-or-later license-file: COPYING.md@@ -512,7 +512,7 @@ syb >= 0.1 && < 0.8, tagsoup >= 0.14.6 && < 0.15, temporary >= 1.1 && < 1.4,- texmath >= 0.12.8.5 && < 0.13,+ texmath >= 0.12.8.6 && < 0.13, text >= 1.1.1.0 && < 2.2, text-conversions >= 0.3 && < 0.4, time >= 1.5 && < 1.14,@@ -522,7 +522,7 @@ zip-archive >= 0.4.3 && < 0.5, zlib >= 0.5 && < 0.7, xml >= 1.3.12 && < 1.4,- typst >= 0.4 && < 0.4.1,+ typst >= 0.5 && < 0.5.1, vector >= 0.12 && < 0.14 if !os(windows)
src/Text/Pandoc/Logging.hs view
@@ -99,6 +99,8 @@ | EnvironmentVariableUndefined Text | DuplicateAttribute Text Text | NotUTF8Encoded FilePath+ | MakePDFInfo Text Text+ | MakePDFWarning Text deriving (Show, Eq, Data, Ord, Typeable, Generic) instance ToJSON LogMessage where@@ -253,6 +255,11 @@ ,"value" .= val] NotUTF8Encoded src -> ["source" .= src]+ MakePDFInfo description contents ->+ ["description" .= description+ ,"contents" .= contents]+ MakePDFWarning message ->+ ["message" .= message] showPos :: SourcePos -> Text showPos pos = Text.pack $ sn ++ "line " ++@@ -387,6 +394,12 @@ NotUTF8Encoded src -> Text.pack src <> " is not UTF-8 encoded: falling back to latin1."+ MakePDFInfo description contents ->+ "[makePDF] " <> description <>+ if Text.null contents+ then mempty+ else "\n" <> contents+ MakePDFWarning message -> "[makePDF] " <> message messageVerbosity :: LogMessage -> Verbosity messageVerbosity msg =@@ -440,3 +453,5 @@ EnvironmentVariableUndefined{}-> WARNING DuplicateAttribute{} -> WARNING NotUTF8Encoded{} -> WARNING+ MakePDFInfo{} -> INFO+ MakePDFWarning{} -> WARNING
src/Text/Pandoc/PDF.hs view
@@ -18,8 +18,8 @@ import qualified Codec.Picture as JP import qualified Control.Exception as E-import Control.Monad (when) import Control.Monad.Trans (MonadIO (..))+import Control.Monad (foldM_) import qualified Data.ByteString as BS import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as BL@@ -35,11 +35,11 @@ import System.Environment import System.Exit (ExitCode (..)) import System.FilePath-import System.IO (stderr, hClose)+import System.IO (hClose) import System.IO.Temp (withSystemTempDirectory, withTempDirectory, withTempFile) import qualified System.IO.Error as IE-import Text.DocLayout (literal)+import Text.DocLayout (literal, render, hsep) import Text.Pandoc.Definition import Text.Pandoc.Error (PandocError (PandocPDFProgramNotFoundError)) import Text.Pandoc.MIME (getMimeType)@@ -57,9 +57,9 @@ import Data.List (intercalate) #endif import Data.List (isPrefixOf, find)-import Text.Pandoc.Class (fillMediaBag, getVerbosity,+import Text.Pandoc.Class (fillMediaBag, getVerbosity, setVerbosity, readFileLazy, readFileStrict, fileExists,- report, extractMedia, PandocMonad)+ report, extractMedia, PandocMonad, runIOorExplode) import Text.Pandoc.Logging import Text.DocTemplates ( FromContext(lookupContext) ) @@ -264,11 +264,17 @@ -> FilePath -- ^ temp directory for output -> Text -- ^ tex source -> m (Either ByteString ByteString)-tex2pdf program args tmpDir source = do- let numruns | takeBaseName program == "latexmk" = 1- | "\\tableofcontents" `T.isInfixOf` source = 3 -- to get page numbers- | otherwise = 1- (exit, log', mbPdf) <- runTeXProgram program args numruns tmpDir source+tex2pdf program args tmpDir' source = do+ let isOutdirArg x = "-outdir=" `isPrefixOf` x ||+ "-output-directory=" `isPrefixOf` x+ let tmpDir =+ case find isOutdirArg args of+ Just x -> drop 1 $ dropWhile (/='=') x+ Nothing -> tmpDir'+ liftIO $ createDirectoryIfMissing True tmpDir+ let file = tmpDir ++ "/input.tex" -- note: tmpDir has / path separators+ liftIO $ BS.writeFile file $ UTF8.fromText source+ (exit, log', mbPdf) <- runTeXProgram program args tmpDir case (exit, mbPdf) of (ExitFailure _, _) -> do let logmsg = extractMsg log'@@ -281,13 +287,14 @@ return $ Left $ logmsg <> extramsg (ExitSuccess, Nothing) -> return $ Left "" (ExitSuccess, Just pdf) -> do+ latexWarnings log' missingCharacterWarnings log' return $ Right pdf missingCharacterWarnings :: PandocMonad m => ByteString -> m () missingCharacterWarnings log' = do let ls = BC.lines log'- let isMissingCharacterWarning = BC.isPrefixOf "Missing character: "+ let isMissingCharacterWarning = BC.isPrefixOf "Missing character:" let toCodePoint c | isAscii c = T.singleton c | otherwise = T.pack $ c : " (U+" ++ printf "%04X" (ord c) ++ ")"@@ -298,6 +305,20 @@ ] mapM_ (report . MissingCharacter) warnings +latexWarnings :: PandocMonad m => ByteString -> m ()+latexWarnings log' = foldM_ go Nothing (BC.lines log')+ where+ go Nothing ln+ | BC.isPrefixOf "LaTeX Warning:" ln =+ pure $ Just ln+ | otherwise = pure Nothing+ go (Just msg) ln+ | ln == "" = do -- emit report and reset accumulator+ report $ MakePDFWarning $ render (Just 60) $+ hsep $ map literal $ T.words $ UTF8.toText $ BC.toStrict msg+ pure Nothing+ | otherwise = pure $ Just (msg <> ln)+ -- parsing output extractMsg :: ByteString -> ByteString@@ -334,17 +355,11 @@ let sourceBL = BL.fromStrict $ UTF8.fromText source let programArgs = ["--outdir", tmpDir] ++ args ++ ["-"] env <- liftIO getEnvironment- verbosity <- getVerbosity- when (verbosity >= INFO) $ liftIO $- showVerboseInfo (Just tmpDir) program programArgs env- (utf8ToText sourceBL)+ showVerboseInfo (Just tmpDir) program programArgs env (utf8ToText sourceBL) (exit, out) <- liftIO $ E.catch (pipeProcess (Just env) program programArgs sourceBL) (handlePDFProgramNotFound program)- when (verbosity >= INFO) $ liftIO $ do- UTF8.hPutStrLn stderr "[makePDF] Running"- BL.hPutStr stderr out- UTF8.hPutStr stderr "\n"+ report $ MakePDFInfo "tectonic output" (UTF8.toText $ BL.toStrict out) let pdfFile = tmpDir ++ "/texput.pdf" (_, pdf) <- getResultingPDF Nothing pdfFile return (exit, out, pdf)@@ -374,22 +389,13 @@ Nothing -> return Nothing return (log', pdf) --- Run a TeX program on an input bytestring and return (exit code,--- contents of stdout, contents of produced PDF if any). Rerun--- a fixed number of times to resolve references.+-- Run a TeX program once in a temp directory (on input.tex) and return (exit code,+-- contents of stdout, contents of produced PDF if any). runTeXProgram :: (PandocMonad m, MonadIO m)- => String -> [String] -> Int -> FilePath- -> Text -> m (ExitCode, ByteString, Maybe ByteString)-runTeXProgram program args numRuns tmpDir' source = do- let isOutdirArg x = "-outdir=" `isPrefixOf` x ||- "-output-directory=" `isPrefixOf` x- let tmpDir =- case find isOutdirArg args of- Just x -> drop 1 $ dropWhile (/='=') x- Nothing -> tmpDir'- liftIO $ createDirectoryIfMissing True tmpDir- let file = tmpDir ++ "/input.tex" -- note: tmpDir has / path separators- liftIO $ BS.writeFile file $ UTF8.fromText source+ => String -> [String] -> FilePath+ -> m (ExitCode, ByteString, Maybe ByteString)+runTeXProgram program args tmpDir = do+ let file = tmpDir ++ "/input.tex" let isLatexMk = takeBaseName program == "latexmk" programArgs | isLatexMk = ["-interaction=batchmode", "-halt-on-error", "-pdf", "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]@@ -403,27 +409,35 @@ ("TEXMFOUTPUT", tmpDir) : [(k,v) | (k,v) <- env' , k /= "TEXINPUTS" && k /= "TEXMFOUTPUT"]- verbosity <- getVerbosity- when (verbosity >= INFO) $ liftIO $- UTF8.readFile file >>=- showVerboseInfo (Just tmpDir) program programArgs env''- let runTeX runNumber = do- (exit, out) <- liftIO $ E.catch- (pipeProcess (Just env'') program programArgs BL.empty)- (handlePDFProgramNotFound program)- when (verbosity >= INFO) $ liftIO $ do- UTF8.hPutStrLn stderr $ "[makePDF] Run #" <> tshow runNumber- BL.hPutStr stderr out- UTF8.hPutStr stderr "\n"- if runNumber < numRuns- then runTeX (runNumber + 1)- else do- let logFile = replaceExtension file ".log"- let pdfFile = replaceExtension file ".pdf"- (log', pdf) <- getResultingPDF (Just logFile) pdfFile- return (exit, fromMaybe out log', pdf)- runTeX 1+ liftIO (UTF8.readFile file) >>=+ showVerboseInfo (Just tmpDir) program programArgs env''+ go file env'' programArgs (1 :: Int)+ where+ go file env'' programArgs runNumber = do+ report $ MakePDFInfo ("LaTeX run number " <> tshow runNumber) mempty+ (exit, out) <- liftIO $ E.catch+ (pipeProcess (Just env'') program programArgs BL.empty)+ (handlePDFProgramNotFound program)+ report $ MakePDFInfo "LaTeX output" (UTF8.toText $ BL.toStrict out)+ -- parse log to see if we need to rerun LaTeX+ let logFile = replaceExtension file ".log"+ logExists <- fileExists logFile+ logContents <- if logExists+ then readFileLazy logFile+ else return mempty+ needsRerun <- checkForRerun logContents+ if needsRerun && runNumber < 3+ then go file env'' programArgs (runNumber + 1)+ else do+ let pdfFile = replaceExtension file ".pdf"+ (log', pdf) <- getResultingPDF (Just logFile) pdfFile+ return (exit, fromMaybe out log', pdf) + checkForRerun log' = pure $ any isRerunWarning $ BC.lines log'++ isRerunWarning ln = BC.isPrefixOf "LaTeX Warning:" ln &&+ BS.isInfixOf "Rerun to" (BL.toStrict ln)+ generic2pdf :: (PandocMonad m, MonadIO m) => String -> [String]@@ -431,9 +445,7 @@ -> m (Either ByteString ByteString) generic2pdf program args source = do env' <- liftIO getEnvironment- verbosity <- getVerbosity- when (verbosity >= INFO) $- liftIO $ showVerboseInfo Nothing program args env' source+ showVerboseInfo Nothing program args env' source (exit, out) <- liftIO $ E.catch (pipeProcess (Just env') program args (BL.fromStrict $ UTF8.fromText source))@@ -457,15 +469,16 @@ BS.writeFile file $ UTF8.fromText source let programArgs = args ++ [file] ++ mkOutArgs pdfFile env' <- getEnvironment- when (verbosity >= INFO) $- UTF8.readFile file >>=- showVerboseInfo Nothing program programArgs env'+ fileContents <- UTF8.readFile file+ runIOorExplode $ do+ setVerbosity verbosity+ showVerboseInfo Nothing program programArgs env' fileContents (exit, out) <- E.catch (pipeProcess (Just env') program programArgs BL.empty) (handlePDFProgramNotFound program)- when (verbosity >= INFO) $ do- BL.hPutStr stderr out- UTF8.hPutStr stderr "\n"+ runIOorExplode $ do+ setVerbosity verbosity+ report $ MakePDFInfo "pdf-engine output" (UTF8.toText $ BL.toStrict out) pdfExists <- doesFileExist pdfFile mbPdf <- if pdfExists -- We read PDF as a strict bytestring to make sure that the@@ -485,21 +498,20 @@ -> Text -- ^ ConTeXt source -> m (Either ByteString ByteString) context2pdf program pdfargs tmpDir source = do+ let file = "input.tex"+ let programArgs = "--batchmode" : pdfargs ++ [file]+ env' <- liftIO getEnvironment verbosity <- getVerbosity+ liftIO $ BS.writeFile (tmpDir </> file) $ UTF8.fromText source+ liftIO (UTF8.readFile (tmpDir </> file)) >>=+ showVerboseInfo (Just tmpDir) program programArgs env' liftIO $ inDirectory tmpDir $ do- let file = "input.tex"- BS.writeFile file $ UTF8.fromText source- let programArgs = "--batchmode" : pdfargs ++ [file]- env' <- getEnvironment- when (verbosity >= INFO) $ liftIO $- UTF8.readFile file >>=- showVerboseInfo (Just tmpDir) program programArgs env' (exit, out) <- E.catch (pipeProcess (Just env') program programArgs BL.empty) (handlePDFProgramNotFound program)- when (verbosity >= INFO) $ do- BL.hPutStr stderr out- UTF8.hPutStr stderr "\n"+ runIOorExplode $ do+ setVerbosity verbosity+ report $ MakePDFInfo "ConTeXt run output" (UTF8.toText $ BL.toStrict out) let pdfFile = replaceExtension file ".pdf" pdfExists <- doesFileExist pdfFile mbPdf <- if pdfExists@@ -516,23 +528,19 @@ (ExitSuccess, Just pdf) -> return $ Right pdf -showVerboseInfo :: Maybe FilePath+showVerboseInfo :: PandocMonad m+ => Maybe FilePath -> String -> [String] -> [(String, String)] -> Text- -> IO ()+ -> m () showVerboseInfo mbTmpDir program programArgs env source = do case mbTmpDir of- Just tmpDir -> do- UTF8.hPutStrLn stderr "[makePDF] temp dir:"- UTF8.hPutStrLn stderr (T.pack tmpDir)+ Just tmpDir -> report $ MakePDFInfo "Temp dir:" (T.pack tmpDir) Nothing -> return ()- UTF8.hPutStrLn stderr "[makePDF] Command line:"- UTF8.hPutStrLn stderr $- T.pack program <> " " <> T.pack (unwords (map show programArgs))- UTF8.hPutStr stderr "\n"- UTF8.hPutStrLn stderr "[makePDF] Relevant environment variables:"+ report $ MakePDFInfo "Command line:"+ (T.pack program <> " " <> T.pack (unwords (map show programArgs))) -- we filter out irrelevant stuff to avoid leaking passwords and keys! let isRelevant ("PATH",_) = True isRelevant ("TMPDIR",_) = True@@ -545,10 +553,9 @@ isRelevant ("TEXINPUTS",_) = True isRelevant ("TEXMFOUTPUT",_) = True isRelevant _ = False- mapM_ (UTF8.hPutStrLn stderr . tshow) (filter isRelevant env)- UTF8.hPutStr stderr "\n"- UTF8.hPutStrLn stderr "[makePDF] Source:"- UTF8.hPutStrLn stderr source+ report $ MakePDFInfo "Relevant environment variables:"+ (T.intercalate "\n" $ map tshow $ filter isRelevant env)+ report $ MakePDFInfo "Source:" source handlePDFProgramNotFound :: String -> IE.IOError -> IO a handlePDFProgramNotFound program e
src/Text/Pandoc/Writers/Typst.hs view
@@ -243,8 +243,9 @@ Code (_,cls,_) code -> return $ case cls of (lang:_) -> "#raw(lang:" <> doubleQuoted lang <>- ", " <> doubleQuoted code <> ")"+ ", " <> doubleQuoted code <> ")" <> endCode _ | T.any (=='`') code -> "#raw(" <> doubleQuoted code <> ")"+ <> endCode | otherwise -> "`" <> literal code <> "`" RawInline fmt str -> case fmt of@@ -273,6 +274,7 @@ [] -> pure mempty suff -> brackets <$> inlinesToTypst suff pure $ "#cite" <> parens (toLabel (citationId cite)) <> suppl+ <> endCode if isEnabled Ext_citations opts -- Note: this loses prefix then mconcat <$> mapM toCite citations@@ -283,9 +285,9 @@ Just ('#', ident) -> "<" <> literal ident <> ">" _ -> doubleQuoted src return $ "#link" <> parens dest <>- if inlines == [Str src]- then mempty- else nowrap $ brackets contents+ (if inlines == [Str src]+ then mempty+ else nowrap $ brackets contents) <> endCode Image (_,_,kvs) _inlines (src,_tit) -> do opts <- gets stOptions let mbHeight = lookup "height" kvs@@ -304,17 +306,21 @@ case realWidth of Just w -> return $ "#box" <> parens ("width: " <> literal w <> ", " <> coreImage)- Nothing -> return $ "#" <> coreImage+ <> endCode+ Nothing -> return $ "#" <> coreImage <> endCode (Just w, _) -> return $ "#box" <> parens ("width: " <> literal w <> ", " <> coreImage)+ <> endCode (_, Just h) -> return $ "#box" <> parens ("height: " <> literal h <> ", " <> coreImage)+ <> endCode Note blocks -> do contents <- blocksToTypst blocks- return $ "#footnote" <> brackets (chomp contents)+ return $ "#footnote" <> brackets (chomp contents) <> endCode textstyle :: PandocMonad m => Doc Text -> [Inline] -> TW m (Doc Text)-textstyle s inlines = (s <>) . brackets <$> inlinesToTypst inlines+textstyle s inlines =+ (<> endCode) . (s <>) . brackets <$> inlinesToTypst inlines escapeTypst :: EscapeContext -> Text -> Text escapeTypst context t =@@ -360,3 +366,6 @@ escapeChar '\\' = "\\\\" escapeChar '"' = "\\\"" escapeChar c = T.singleton c++endCode :: Doc Text+endCode = beforeNonBlank ";"
test/writer.typst view
@@ -435,13 +435,13 @@ 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 ```@@ -571,27 +571,27 @@ = 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.@@ -609,7 +609,7 @@ '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. @@ -628,7 +628,7 @@ - $223$ - $p$-Tree - Here’s some display math:- $ frac(d, d x) f lr((x)) = lim_(h arrow.r 0) frac(f lr((x + h)) - f lr((x)), h) $+ $ frac(d, d x) f (x) = lim_(h arrow.r 0) frac(f (x + h) - f (x), h) $ - Here’s one that has a line break in it: $alpha + omega times x^2$. These shouldn’t be math:@@ -701,13 +701,13 @@ <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] @@ -717,21 +717,21 @@ #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. @@ -739,20 +739,20 @@ [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>@@ -780,7 +780,7 @@ <images> From "Voyage dans la Lune" by Georges Melies \(1902): -#figure([#box(width: 150.0pt, image("lalune.jpg"))],+#figure([#box(width: 150.0pt, image("lalune.jpg"));], caption: [ lalune ]