# Revision history for pandoc
## pandoc 3.12.1 (2026-10-07)
* New input and output format: `fodt` (#4010). This is ODF's
"flat" representation of a text document: a single XML file
instead of a zip package (ODT). It supports the same options
as `odt`, including `--reference-doc` (which should be a
zipped `odt`) and `--link-images`.
* Resolve keywords after loading a syntax definition (#11921, #11923).
This fixes a 3.12 regression in `--syntax-definition` that was due to a
change in skylighting. As the skylighting changelog indicates, users must
now apply `resolveKeywords` after parsing a syntax definition.
* With `--citeproc`, we no longer extract particles from given and
family names in structured CSL JSON or CSL YAML references (#11911).
Thus, for example, `family: de Gaulle` should not create a
non-dropping particle "de"; "de Gaulle" should be considered
the integral family name. This is a behavior change that
could affect some bibliography processing.
* Commonmark reader:
+ Make task lists work in `commonmark_x`. Previously `task_lists`
would not work if `fancy_lists` was enabled, for any
`commonmark` variant.
* Markdown reader:
+ Put `alert` after `tip`, etc. in classes (#11919). Some of
the writers (gfm, docbook, asciidoc, rst) check for the
admonition name as the first class, so the change putting
`alert` first broke the output. (Regression from 3.12.)
+ Don't trim spaces in inline span. Previously we trimmed the
space in e.g. `[ test ]{.class}`. This behavior has no good rationale,
and it made it impossible to represent insertions and deletions properly.
+ Make lookahead for setext header line more efficient.
* Docx reader:
+ Keep bookmark when stripping caption label (#11918).
This allows us to preserve internal links to figures.
+ Add map of table styles to the reader environment.
+ Fix double strikethrough being dropped (Kyohei Takahashi).
`w:dstrike` was not parsed at all, so text marked with Word's double
strikethrough was read as plain text, with no indication that it had
been struck out. Treat it as Strikeout.
+ Keep spaces at the edges of tracked changes in the span (#11904,
Raffaele Mancuso). This is important for tracking insertions/deletions.
* ODT reader:
+ Don't crash on a table with no rows.
+ Don't loop forever on cyclic style inheritance.
+ Make `getStyleFamily` linear in the inheritance depth. A style
whose family had to be inherited took time exponential in the
chain length.
+ Cap the number of spaces produced by `text:s`. `text:c` is
unbounded in ODF, so `` let an
832-byte document allocate until the OOM killer stepped in.
+ Keep the set of used anchors in the reader state.
+ Look up used anchors in a Set in `uniqueIdentFrom`.
+ Keep the archive's media in a Map rather than an association list.
+ Attach table captions wherever they occur. `post_process'` matched
a table followed by a caption only at the very head of the block list
and then stopped, so a caption was picked up only if its table was
the first block of the document; anywhere else the caption was dropped
and the internal marker Div leaked into the output. Walk
the whole document instead, so captions nested in sections,
cells and list items are found too. Accept the caption before
its table as well as after it.
+ Don't add a bogus media entry for a missing image.
+ Only treat font weights of 700 and up as bold. Every numeric
`fo:font-weight` from 100 to 900 was mapped to bold, so text
in a hairline or light weight was read as Strong.
+ Read text wrapped in metadata elements and fields.
Content of an element the reader did not recognize was discarded along
with the element, which silently lost text: fields such as
`text:page-number`, `text:author-name` or `text:chapter`, the RDFa
wrapper `text:meta`, the bibliographic wrapper `text:meta-field`,
and ruby annotations. Add matchers for those; for ruby, keep the base
text and drop the gloss, which pandoc cannot represent.
+ Honour `table:number-{columns,rows}-repeated`. ODF abbreviates a
run of identical cells or rows with a repeat count. The
reader ignored both counts, so a row of five cells written as three
elements came out three cells wide. Also count a cell
spanning several columns as occupying all of them when
working out the number of columns, rather than as one.
+ Read rows wrapped in `table:table-row-group`. Rows need not be
immediate children of the table.
+ Read blocks nested in list items, footnotes and cells. ODF allows
the same block-level content wherever it allows a paragraph,
but the reader spelled the list of block matchers out
separately at each site and each spelling was missing
something: a table in a list item was dropped, a list or
table in a footnote was dropped, and a heading or nested
table in a table cell was dropped. Keep a single list and
use it everywhere, so the sites cannot drift apart again.
+ Read images embedded in `office:binary-data`.
+ Read MathML embedded inline in `draw:object`. A flat OpenDocument file
cannot refer to a separate formula document, so
the MathML is a descendant of the draw:object instead.
+ Add `readFODT` for flat OpenDocument input [API change].
+ Fix formula lookup when the href has a trailing slash.
+ Trim the alt text of an image.
+ Look up the image mime type on the `draw:image` element instead of guessing
from magic bytes.
* RTF reader:
+ Combine UTF-16 surrogate pairs (#11920).
* Typst reader:
+ Do not emit mixed table column widths (#11898, Samuel Huang).
Previously we evenly split the remaining width, but generally
it looks better just to make every column `auto` if any column
is default width.
+ Treat zero-width table fractions as unspecified (#11898, Samuel Huang).
* Org reader:
+ Improve performance: use a jump table to find the end of plain text
runs, and dispatch on the next character in `inline`.
* Creole reader:
+ Use jump tables to find the end of plain text runs.
+ Use `takeWhile1P` in `str`.
* RST reader:
+ Use `takeWhile1P` for raw field list items.
* Textile, Vimwiki, MediaWiki, Txt2Tags readers:
+ Use jump tables to find the end of plain text runs.
* Roff readers:
+ Use `takeWhile1P` for `regularText`.
* Mdoc reader:
+ Use `takeWhile1P` in lexer.
* Docx writer:
+ Use table style `id` in the `tblStyle` element (#11932).
Previously we used the table style `name`. This happened to work
for the default table style, but only because its name and id matched.
It failed for custom styles whose names did not match their ids.
+ Put a heading's bookmark in its paragraph (Robert Szarka,
#11845, cf. #8825). The bookmark for a section's id
surrounded the whole section, at body level, so a screen
reader met it at the section's last line rather than at the
heading. Moreover, the docx reader looks for bookmarks only
inside paragraphs, so the ids did not round-trip.
+ Improve highlighting of `marked` spans containing math (#11885,
Samuel Huang).
* OpenDocument writer:
+ Use `literal` instead of `text . T.unpack`.
+ Emit whitespace runs in one piece.
+ Count styles and notes in O(1).
+ Give nested notes distinct ids.
+ Use valid column style names past column 26 (`AA`, `AB`, etc.).
+ Apply the requested style to `Plain` blocks. `withParagraphStyle`
only wrapped `Para` in a paragraph with the requested
style; a `Plain` fell through to `blockToOpenDocument` and came
out with the default style.
+ Render the abstract as blocks. The abstract was wrapped in a Div
with `custom-style` set to `Abstract`, but then handed to
`metaToContext`, which renders metadata fields with the inline writer.
The style was lost, as well as any block-level formatting.
Regression from 013351f602.
+ Reuse identical automatic paragraph styles. Every blockquote,
every explicitly aligned table cell, and every direction-adjusted
style got a fresh `Pn` automatic style, even when an
identical one already existed.
+ Look up cross-reference targets in a Map. Skip the collecting walk
altogether unless `xrefs_name` or `xrefs_number` is enabled, since
nothing reads the result otherwise and neither is on by default.
Elements with an empty identifier are no longer collected, so a link to
"#" can no longer resolve to a reference with an empty ref-name.
+ Sort automatic text styles numerically rather than alphabetically
(`T9`, `T10`, ...).
* ODT writer:
+ Always render `content.xml` with a template. `writeOpenDocument`
returns a bare body fragment when writerTemplate is
Nothing. This is needed mainly for the `fodt` writer.
+ Have `pandocToODT` return an Archive instead of a ByteString.
This lets an alternative entry point post-process the archive.
+ Add `writeFODT` for flat OpenDocument output [API change].
* LaTeX writer:
+ Allow alt text in figure to wrap (#11924).
* Commonmark writer:
+ Fix escaping bug (#11927). A non-alphanumeric after an
escaped backslash would be omitted.
* Typst writer:
+ Revert pandoc 3.12 change that omitted a blank line at the end
of a `block`. The blank line actually is semantically significant;
without it, styling of `par` will have no effect.
+ Support `hanging-indent` and `entry-spacing` in CSL bibliography
entries (#11926). Instead of hard-coding the formatting in
the block, we use a show rule on ``, included
conditionally by the default template. Values will be set
for `csl-hanging-indent` and `csl-entry-spacing` based on
the CSL style, but these variables can be overridden on the
command line using `--variable`. It is also possible to
include a new show rule in header-includes, which will take
priority over the other.
* Markdown writer:
+ Put `<..>` around link or image destinations containing
spaces (rca-umb).
+ Escape list markers after a line break (#11863, Aslak Hellesøy).
+ Don't use a multiline table for a header-only table (#11939).
* Text.Pandoc.XML:
+ Make `escapeStringForXML` and `escapeNls` more efficient.
+ Build XML tags with a single doclayout allocation rather than
several.
* Text.Pandoc.SelfContained:
+ Fix regression in escaping of data URIs (#11942). A change
in 3.12 broke escaping of data URIs, so that `--embed-resources`
no longer worked properly.
* Text.Pandoc.Parsing:
+ `mathDisplay`, `mathInline`: respect TeX groups and comments (#11887,
Erik Demaine). Prevent math delimiters inside TeX brace groups
and percent comments from prematurely closing an equation.
* Text.Pandoc.XML.Light:
+ Build the root element from the event stream.
Instead of using xml-conduit's DOM parser and then converting
the result back to our Element type, just reuse
`parseXMLContentsWithEntities`, which folds the event stream
directly into our types. This speeds up every XML-based reader.
Behavior change: Attributes now preserve document order instead of
being sorted alphabetically, as was already the case for
`parseXMLContentsWithEntities`.
* Bump version of reveal.js to 6. Version 6 is required for the
changes in plugin locations incorporated in pandoc 3.12.
* `reference.docx`: don't make Table style `semiHidden` (#11931).
This allows it to appear in the table styles gallery.
* Benchmark improvements:
+ Include the benchmark sample in the benchmark directory, to ensure
that it doesn't change between releases. Include images too.
+ Change the benchmark sample to a mix of markup-heavy and prose-heavy
text, including tables.
* Use latest citeproc, texmath.
## pandoc 3.12 (2026-09-27)
* Markdown reader:
+ Make alert keywords case-insensitive (#11836, Hendrik Erz).
In addition, the class `alert` is now added to the produced
Divs.
+ Fix stream position handling in `base64DataURI`.
+ Cheaply reject `bareURL` before trying uri/emailAddress.
+ Reset sourcepos in `parseWithString'` when parsing a block
quote or list item. Otherwise it can happen that by the
time `parseWithString'` is called, the position has already
been set to the next file on the command line. Fixes an
odd bug with `rebase_relative_paths` (#11888).
+ `rebase_relative_paths`: recognize URLs with unknown schemes
(#11858).
+ Use `takeWhile1P` in the hot inline parsers `str`, `code`,
`enclosure`, and `mmdShortSubscript`.
+ Reset sourcepos in `parseWithString'` when parsing a block quote
or list item (#11888). This ensures that `rebase_relative_paths`
will see the right source file.
* Typst reader:
+ Map `form: "prose"` citations to AuthorInText (#11846,
Samuel Huang).
+ Make the handler maps monomorphic by wrapping the handlers
in newtypes with polymorphic fields (BlockHandler, InlineHandler).
+ Store document labels in a Set instead of a list.
+ In `pInline`, only perform the label-target check for
`ref` elements, not for every inline element.
+ Handle `highlight` as a mark span (#11879, Samuel Huang).
+ Collapse citations around soft break (#11897).
+ Handle block content in inline element bodies (#11881,
Samuel Huang).
+ Handle `#par` (explicit paragraph element).
* LaTeX reader:
+ Support LaTeX3 (xparse) document commands (#7540).
Support the features described in the LaTeX usrguide.
+ Fix `\qed` to produce U+00A0 (nbsp) instead of BEL.
+ Fix `unescapeURL` handling of escaped backslash.
+ Require that `\newif` names begin with "if".
+ Fix position off-by-one after `##` in tokenizer.
+ Fix doubled source positions in `retokenizeComment`.
+ Make raw token capture O(1) per token.
+ Make `untokenize` linear instead of quadratic.
+ Fail `macroDef` fast on non-macro-defining commands.
+ Peek at next token directly in `peekTok` instead of going
through `satisfyTok`.
+ Skip `doMacros` state update for non-macro tokens.
+ Build command dispatch maps (`inlineCommands`, etc.) once per parse.
+ Keep ASCII quotes when ligatures are disabled.
+ Don't discard state changes made in optional arguments.
+ Keep nested conditionals balanced in `\iftrue` etc.
* Docx reader:
+ Read ScreenTips as link titles (#11869, Robert Szarka).
+ Use `comment-id` instead of `id` in AST for comments.
* ODT reader:
+ Rewrite in monadic style. Net -994 lines. No changes to test output.
+ Handle `textProperties` on paragraph styles (#2623).
Previously these just got ignored, not applied to the
paragraph's text.
* HTML reader:
+ Don't require a closing tag for checkbox inputs.
`` is a void element.
+ Allow omitted `` in tables. The `` closing
tag is optional in HTML.
+ Don't drop cells when there are too few `
` elements.
+ Let the first of duplicate attributes win. HTML specifies that
the first occurrence wins.
+ Respect `raw_html` for inline `