diff --git a/AUTHORS.md b/AUTHORS.md
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -458,6 +458,7 @@
 - William Rusnack
 - Winnie Hellmann
 - Wout Gevaert
+- Wrong-Code
 - Xavier Olive
 - Yan Pashkovsky
 - Yann Trividic
@@ -547,4 +548,5 @@
 - wiefling
 - willj-dev
 - wuffi
+- wzy
 - λx.x
diff --git a/MANUAL.txt b/MANUAL.txt
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1,7 +1,7 @@
 ---
 title: Pandoc User's Guide
 author: John MacFarlane
-date: 2026-08-11
+date: 2026-08-28
 ---
 
 # Synopsis
@@ -431,13 +431,31 @@
     overridden or extended by subsequent options on the command
     line.
 
-`--bash-completion`
+`--completion=`*SHELL*
 
-:   Generate a bash completion script.  To enable bash completion
-    with pandoc, add this to your `.bashrc`:
+:   Generate a shell completion script for the given shell, one of
+    `bash`, `zsh`, or `fish`.  To enable completion with pandoc,
+    evaluate the output of this command in your shell's startup
+    file.  For example, for bash, add this to your `.bashrc`:
 
-        eval "$(pandoc --bash-completion)"
+        eval "$(pandoc --completion=bash)"
 
+    For zsh, you will need to create a directory to store zsh
+    completions (e.g., `~/.local/share/zsh/site-functions`) or use
+    one of the existing directories listed by `zsh --pathdirs`.
+    Create the pandoc completion script in that directory:
+
+        pandoc --completion=zsh > ~/.local/share/zsh/site-functions/_pandoc
+
+    Then add these lines to your `.zshrc`:
+
+        fpath=(~/.local/share/zsh $fpath)
+        autoload -Uz compinit && compinit
+
+`--bash-completion`
+
+:   *Deprecated.  Use `--completion=bash` instead.*
+
 `--sandbox[=true|false]`
 
 :   Run pandoc in a sandbox, limiting IO operations in readers
@@ -1114,7 +1132,7 @@
     link to will not be incorporated in the document.
     Limitation: resources that are loaded dynamically through
     JavaScript cannot be incorporated; as a result, fonts may
-    be missing when `--mathjax` is used, and some
+    be missing when `--math-method=mathjax` is used, and some
     advanced features (e.g.  zoom or speaker notes) may not work
     in an offline "self-contained" `reveal.js` slide show.
 
@@ -1645,60 +1663,85 @@
     output. It is intended for use in producing a LaTeX file
     that can be processed with [`bibtex`] or [`biber`].
 
-## Math rendering in HTML {.options}
+## Math rendering {.options}
 
-The default is to render TeX math as far as possible using
-Unicode characters.  Formulas are put inside a `span` with
-`class="math"`, so that they may be styled differently from the
-surrounding text if needed. However, this gives acceptable
-results only for basic math, usually you will want to use
-`--mathjax` or another of the following options.
+`--math-method`=*METHOD*[`:`*URL*]
 
+:   Specify the method used to display TeX math. The following
+    methods are possible (some take an optional URL, separated
+    from the method name by a colon). The default value is `mathml`.
+
+    `plain`
+
+      : Render math using Unicode characters, to the extent possible.
+        When this is not possible, fall back to plain TeX.
+
+    `mathjax`[`:`*URL*]
+
+      : Render math using [MathJaX]. TeX math will be put between
+        `\(...\)` (for inline math) or `\[...\]` (for display
+        math) and wrapped in `<span>` tags with class `math`.
+        Then the MathJax JavaScript will render it. The *URL*
+        should point to the `MathJax.js` load script. If a *URL*
+        is not provided, a link to the Cloudflare CDN will be
+        inserted. This method works in HTML and HTML-derived formats.
+
+    `mathml`
+
+      : Convert TeX math to [MathML]. MathML is supported
+        natively by the main web browsers and most e-book
+        readers. This option works in HTML and XML formats.
+
+    `webtex`[`:`*URL*]
+
+      : Convert TeX formulas to `<img>` tags that link to an external script
+        that converts formulas to images. The formula will be URL-encoded
+        and concatenated with the URL provided. For SVG images you can for
+        example use
+        `--math-method=webtex:https://latex.codecogs.com/svg.latex?`.
+        If no URL is specified, the CodeCogs URL generating PNGs
+        will be used (`https://latex.codecogs.com/png.latex?`).
+        Note:  this method works not just in HTML but in Markdown,
+        which is useful if you're targeting a version of Markdown
+        without native math support.
+
+    `katex`[`:`*URL*]
+
+      : Use [KaTeX] to display embedded TeX math in HTML output.
+        The *URL* is the base URL for the KaTeX library. That directory
+        should contain a `katex.min.js` and a `katex.min.css` file.
+        If a *URL* is not provided, a link to the KaTeX CDN will be inserted.
+        This method works in HTML and HTML-derived formats.
+
+    `gladtex`
+
+    : Enclose TeX math in `<eq>` tags in HTML output.  The resulting HTML
+      can then be processed by [GladTeX] to produce SVG images of the typeset
+      formulas and an HTML file with these images embedded.
+
+          pandoc -s --math-method=gladtex input.md -o myfile.htex
+          gladtex -d image_dir myfile.htex
+          # produces myfile.html and images in image_dir
+
 `--mathjax`[`=`*URL*]
 
-:   Use [MathJax] to display embedded TeX math in HTML output.
-    TeX math will be put between `\(...\)` (for inline math)
-    or `\[...\]` (for display math) and wrapped in `<span>` tags
-    with class `math`. Then the MathJax JavaScript will render it.
-    The *URL* should point to the `MathJax.js` load script.
-    If a *URL* is not provided, a link to the Cloudflare CDN will
-    be inserted.
+:   *Deprecated.  Use `--math-method=mathjax`[`:`*URL*] instead.*
 
 `--mathml`
 
-:   Convert TeX math to [MathML] (in `epub3`, `docbook4`,
-    `docbook5`, `jats`, `html4` and `html5`).  This is the
-    default in `odt` output. MathML is supported natively by
-    the main web browsers and select e-book readers.
+:   *Deprecated.  Use `--math-method=mathml` instead.*
 
 `--webtex`[`=`*URL*]
 
-:   Convert TeX formulas to `<img>` tags that link to an external script
-    that converts formulas to images. The formula will be URL-encoded
-    and concatenated with the URL provided. For SVG images you can for
-    example use `--webtex https://latex.codecogs.com/svg.latex?`.
-    If no URL is specified, the CodeCogs URL generating PNGs
-    will be used (`https://latex.codecogs.com/png.latex?`).
-    Note:  the `--webtex` option will affect Markdown output
-    as well as HTML, which is useful if you're targeting a
-    version of Markdown without native math support.
+:   *Deprecated.  Use `--math-method=webtex`[`:`*URL*] instead.*
 
 `--katex`[`=`*URL*]
 
-:   Use [KaTeX] to display embedded TeX math in HTML output.
-    The *URL* is the base URL for the KaTeX library. That directory
-    should contain a `katex.min.js` and a `katex.min.css` file.
-    If a *URL* is not provided, a link to the KaTeX CDN will be inserted.
+:   *Deprecated.  Use `--math-method=katex`[`:`*URL*] instead.*
 
 `--gladtex`
 
-:   Enclose TeX math in `<eq>` tags in HTML output.  The resulting HTML
-    can then be processed by [GladTeX] to produce SVG images of the typeset
-    formulas and an HTML file with these images embedded.
-
-        pandoc -s --gladtex input.md -o myfile.htex
-        gladtex -d image_dir myfile.htex
-        # produces myfile.html and images in image_dir
+:   *Deprecated.  Use `--math-method=gladtex` instead.*
 
 [MathML]: https://www.w3.org/Math/
 [MathJax]: https://www.mathjax.org
@@ -2299,36 +2342,24 @@
 | command line                     | defaults file                     |
 +:=================================+:==================================+
 | ```                              | ``` yaml                          |
-| --mathjax                        | html-math-method:                 |
+| --math-method=mathjax            | math-method     :                 |
 |                                  |   method: mathjax                 |
 | ```                              | ```                               |
 +----------------------------------+-----------------------------------+
 | ```                              | ``` yaml                          |
-| --mathml                         | html-math-method:                 |
-|                                  |   method: mathml                  |
-| ```                              | ```                               |
-+----------------------------------+-----------------------------------+
-| ```                              | ``` yaml                          |
-| --webtex                         | html-math-method:                 |
+| --math-method=webtex:URL         | math-method:                      |
 |                                  |   method: webtex                  |
-| ```                              | ```                               |
-+----------------------------------+-----------------------------------+
-| ```                              | ``` yaml                          |
-| --katex                          | html-math-method:                 |
-|                                  |   method: katex                   |
+|                                  |   url: mathjax                    |
 | ```                              | ```                               |
 +----------------------------------+-----------------------------------+
 | ```                              | ``` yaml                          |
-| --gladtex                        | html-math-method:                 |
-|                                  |   method: gladtex                 |
+| --math-method=mathml             | math-method:                      |
+|                                  |   method: mathml                  |
 | ```                              | ```                               |
 +----------------------------------+-----------------------------------+
 
-In addition to the values listed above, `method` can have the
-value `plain`.
-
 If the command line option accepts a URL argument, an `url:` field can
-be added to `html-math-method:`.
+be added to `math-method:`.
 
 ## Options for wrapper scripts
 
@@ -2957,9 +2988,9 @@
 ### Variables for HTML math
 
 `classoption`
-:   when using `--katex`, you can render display math equations
-    flush left using [YAML metadata](#layout) or with `-M
-    classoption=fleqn`.
+  : when using `--math-method=katex`, you can render display
+    math equations flush left using [YAML metadata](#layout) or
+    with `-M classoption=fleqn`.
 
 ### Variables for HTML slides
 
@@ -3505,7 +3536,9 @@
 :    Number of columns for body text.
 
 `thanks`
-:   contents of acknowledgments footnote after document title
+:   contents of acknowledgments footnote after document title.
+    (Note: as of typst 0.15, this does not work properly,
+    due to an upstream issue; see jgm/pandoc#11807.)
 
 `mathfont`, `codefont`
 :    Name of system font to use for math and code, respectively.
@@ -4706,6 +4739,17 @@
 by itself, because each numbered example list will be numbered
 continuously from its starting number.
 
+In a longer (book-length) work, one might need to reset the example
+list counter at the beginning of each chapter. One can do that using the
+following syntax:
+
+    (1@foo) This item will be numbered 1, and subsequent example
+        list items will be numbered 2, 3, etc.
+
+Any number may be used instead of `1`. Note that if there are several
+example list items in a row, the number only has an effect if placed
+on the first of them.
+
 ### Ending a list ###
 
 What if you want to put an indented code block after a list?
@@ -5479,7 +5523,7 @@
   ~ It will be rendered, if possible, using MathML.
 
 DocBook
-  ~ If the `--mathml` flag is used, it will be rendered using MathML
+  ~ If `--math-method=mathml` is used, it will be rendered using MathML
     in an `inlineequation` or `informalequation` tag.  Otherwise it
     will be rendered, if possible, using Unicode characters.
 
@@ -5487,7 +5531,7 @@
   ~ It will be rendered using OMML math markup.
 
 FictionBook2
-  ~ If the `--webtex` option is used, formulas are rendered as images
+  ~ If `--math-method=webtex` is used, formulas are rendered as images
     using CodeCogs or other compatible web service, downloaded
     and embedded in the e-book. Otherwise, they will appear verbatim.
 
@@ -6332,7 +6376,7 @@
 
 ### Extension: `sourcepos` ###
 
-Include source position attributes when parsing `commonmark`.
+Include source position attributes when parsing `commonmark` or `djot`.
 For elements that accept attributes, a `data-pos` attribute
 is added; other elements are placed in a surrounding
 Div or Span element with a `data-pos` attribute.
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,124 @@
 # Revision history for pandoc
 
+## pandoc 3.11 (2026-08-28)
+
+  * Add `--math-method` option. This replaces (now deprecated but
+    still functional) options `--mathml`, `--mathjax`, `--gladtex`,
+    `--katex`, `--webtex`. The `plain` style can now be specified
+    explicitly. In defaults files, `html-math-method` is now
+    `math-method` (though `html-math-method` will still work).
+
+  * Make `mathml` the default math-method (#11751).
+
+  * Add `--completion={bash,zsh,fish}` (#8542, wzy).
+    Make `--bash-completion` an alias of `--completion=bash`.
+    See the manual for instructions on how to use these completions.
+
+  * Text.Pandoc.Options [API change]:
+
+    - Rename HTMLMathMethod type to MathMethod.
+    - Rename `writerHTMLMathMethod` field of WriterOptions to
+      `writerMathMethod`.
+
+  * Markdown reader:
+
+    + Add a syntax `(1@label)` for resetting example list counter
+      (#10940). This is needed often at the beginning of a chapter.
+
+  * MediaWiki writer:
+
+    + Put `<nowiki>` around possible URLs (#11834). Otherwise they get
+      linkified automatically.
+
+  * Docx reader:
+
+    + Handle case where non-header rows come before header rows (#11833).
+    + Improve handling of tables with uneven rows (#11833).
+
+  * RTF Reader:
+
+    + Add support for nested tables (#11218, Alex).
+
+  * Typst reader:
+
+    + Remove handling of 'block' as an inline-level element (#11814).
+
+  * HTML reader:
+
+    + Handle `pre` without `code` (#11810). Preserve whitespace as
+      nonbreaking spaces.
+
+  * ODT/OpenDocument writers:
+
+    + Support RTL text direction (#11301). RTL is now properly handled
+      in these cases: `dir: rtl` (or `ltr`) in document metadata; an
+      RTL `lang` in metadata (e.g. `he`, `ar`), unless overridden by
+      `dir`; a `dir` attribute on a Div. Code blocks remain ltr
+      regardless.
+    + Use `style:language-complex` rather than `fo:language` for RTL
+      languages (#11301).
+    + Fix treatment of DefaultHighlighting (#11829).
+
+  * Docx writer:
+
+    + Initialize envLang from `lang` metadata (#11301).
+      This ensures that setting `lang` will affect the whole document.
+      Previously, setting `lang` to `he` was not sufficient to make
+      the document RTL.
+
+  * JATS writer:
+
+    + Fix illegal use of `p` element inside `p` (#11809).
+
+  * Ms writer:
+
+    + Fix treatment of DefaultHighlighting (#11829).
+      (Regression from 3.8.)
+
+  * ConTeXt writer:
+
+    + Fix bug in syntax highlighting (#11829). (Regression from 3.8.)
+
+  * Text.Pandoc.App.Opt:
+
+    + In Opt, change `optHTMLMathMethod` to `optMathMethod`. [API  change]
+
+  * MSI installer: Fix upgrade detection for per-machine installations
+    (#11827, Wrong-Code). Previously, registry records of previous
+    versions were not being removed.
+
+  * Text.Pandoc.Templates:
+
+    + Fix bug in `getTemplate`. When calling `fetchItem` in
+      `getTemplate`, we temporarily reset the `stSourceURL` in
+      CommonState so that the template is sought locally. Previously, an
+      exception in `fetchItem` would prevent `stSourceURL` from being
+      set back to its original value. This could result in a local file
+      being fetched instead of a remote one. Note that an exception is
+      triggered when one uses e.g. `--template default.html5`; in that
+      case `getTemplate` handles the exception by looking for the file
+      in the user data directory. This patch fixes the bug so that the
+      `stSourceURL` is reset regardless of whether `fetchItem` raises an
+      exception. Thanks to Yingjie Su for identifying the problem.
+
+  * beamer template: remove spurious extra tableofcontents (#11819).
+
+  * Text.Pandoc.App.CommandLineOptions:
+
+    + Export OptionSpec, which can encode the type of completion
+      needed by each option (wzy).
+
+  * Add new unexported module Text.Pandoc.Completion (wzy).
+
+  * Replace a use of `nub` with `nubOrd`.
+
+  * Use latest releases of djot, asciidoc, typst, texmath.
+
+  * MANUAL.txt:
+
+    + Add a note that `thanks` in typst doesn't currently work (#11807).
+    + Note that sourcepos extension works for djot too.
+
 ## pandoc 3.10.2 (2026-08-11)
 
   * Markdown reader:
diff --git a/data/bash_completion.tpl b/data/bash_completion.tpl
deleted file mode 100644
--- a/data/bash_completion.tpl
+++ /dev/null
@@ -1,90 +0,0 @@
-# This script enables bash autocompletion for pandoc.  To enable
-# bash completion, add this to your .bashrc:
-# eval "$(pandoc --bash-completion)"
-
-_pandoc()
-{
-    local cur prev opts lastc informats outformats highlight_styles datafiles
-    COMPREPLY=()
-    cur="${COMP_WORDS[COMP_CWORD]}"
-    prev="${COMP_WORDS[COMP_CWORD-1]}"
-
-    # These should be filled in by pandoc:
-    opts="%s"
-    informats="%s"
-    outformats="%s"
-    highlight_styles="%s"
-    datafiles="%s"
-
-    case "${prev}" in
-         --from|-f|--read|-r)
-             COMPREPLY=( $(compgen -W "${informats}" -- ${cur}) )
-             return 0
-             ;;
-         --to|-t|--write|-w|-D|--print-default-template)
-             COMPREPLY=( $(compgen -W "${outformats}" -- ${cur}) )
-             return 0
-             ;;
-         --email-obfuscation)
-             COMPREPLY=( $(compgen -W "references javascript none" -- ${cur}) )
-             return 0
-             ;;
-         --ipynb-output)
-             COMPREPLY=( $(compgen -W "all none best" -- ${cur}) )
-             return 0
-             ;;
-         --pdf-engine)
-             COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk tectonic wkhtmltopdf weasyprint prince context pdfroff groff" -- ${cur}) )
-             return 0
-             ;;
-         --print-default-data-file)
-             COMPREPLY=( $(compgen -W "${datafiles}" -- ${cur}) )
-             return 0
-             ;;
-         --wrap)
-             COMPREPLY=( $(compgen -W "auto none preserve" -- ${cur}) )
-             return 0
-             ;;
-         --track-changes)
-             COMPREPLY=( $(compgen -W "accept reject all" -- ${cur}) )
-             return 0
-             ;;
-         --reference-location)
-             COMPREPLY=( $(compgen -W "block section document" -- ${cur}) )
-             return 0
-             ;;
-         --top-level-division)
-             COMPREPLY=( $(compgen -W "section chapter part" -- ${cur}) )
-             return 0
-             ;;
-         --highlight-style|--print-highlight-style)
-             COMPREPLY=( $(compgen -W "${highlight_styles}" -- ${cur}) )
-             return 0
-             ;;
-         --eol)
-             COMPREPLY=( $(compgen -W "crlf lf native" -- ${cur}) )
-             return 0
-             ;;
-         --markdown-headings)
-             COMPREPLY=( $(compgen -W "setext atx" -- ${cur}) )
-             return 0
-             ;;
-         *)
-             ;;
-    esac
-
-    case "${cur}" in
-         -*)
-             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
-             return 0
-             ;;
-         *)
-             local IFS=$'\n'
-             COMPREPLY=( $(compgen -X '' -f "${cur}") )
-             return 0
-             ;;
-    esac
-
-}
-
-complete -o filenames -o bashdefault -F _pandoc pandoc
diff --git a/data/odt/styles.xml b/data/odt/styles.xml
--- a/data/odt/styles.xml
+++ b/data/odt/styles.xml
@@ -62,7 +62,7 @@
       draw:end-line-spacing-vertical="0.1114in"
       style:flow-with-text="false" />
       <style:paragraph-properties style:text-autospace="ideograph-alpha"
-      style:line-break="strict" style:writing-mode="lr-tb"
+      style:line-break="strict" style:writing-mode="page"
       style:font-independent-line-spacing="false">
         <style:tab-stops />
       </style:paragraph-properties>
@@ -292,6 +292,8 @@
       style:font-family-generic="modern"
       style:font-pitch="fixed"
       fo:font-size="10pt"
+      style:writing-mode="lr-tb"
+      fo:text-align="left"
       style:font-name-asian="Courier New"
       style:font-family-asian="&apos;Courier New&apos;"
       style:font-family-generic-asian="modern"
diff --git a/data/templates/default.beamer b/data/templates/default.beamer
--- a/data/templates/default.beamer
+++ b/data/templates/default.beamer
@@ -153,9 +153,6 @@
   \setcounter{tocdepth}{$toc-depth$}
   \tableofcontents
 \end{frame}
-\setcounter{tocdepth}{$toc-depth$}
-\tableofcontents
-}
 $endif$
 $if(lof)$
 \listoffigures
diff --git a/pandoc.cabal b/pandoc.cabal
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,6 +1,6 @@
 cabal-version:   2.4
 name:            pandoc
-version:         3.10.2
+version:         3.11
 build-type:      Simple
 license:         GPL-2.0-or-later
 license-file:    COPYING.md
@@ -201,8 +201,6 @@
                  data/creole.lua
                  -- lua init script
                  data/init.lua
-                 -- bash completion template
-                 data/bash_completion.tpl
                  -- citeproc
                  data/default.csl
                  citeproc/biblatex-localization/*.lbx.strings
@@ -228,6 +226,7 @@
                  test/command/9603.docx
                  test/command/11113.docx
                  test/command/11689.docx
+                 test/command/11833.docx
                  test/command/biblio.bib
                  test/command/averroes.bib
                  test/command/A.txt
@@ -281,6 +280,7 @@
                  test/command/7861/metadata/placeholder
                  test/command/11486/scroll.revealjs
                  test/command/11498.png
+                 test/command/11301-styles.opendocument
                  test/asciidoc-reader.adoc
                  test/asciidoc-reader.native
                  test/asciidoc-reader-include.rb
@@ -546,7 +546,7 @@
                  ipynb                 >= 0.2      && < 0.3,
                  jira-wiki-markup      >= 1.5.1    && < 1.6,
                  mime-types            >= 0.1.1    && < 0.2,
-                 mtl                   >= 2.2      && < 2.4,
+                 mtl                   >= 2.3      && < 2.4,
                  network-uri           >= 2.6      && < 2.8,
                  pandoc-types          >= 1.23.1.2 && < 1.24,
                  parsec                >= 3.1      && < 3.2,
@@ -562,7 +562,7 @@
                  syb                   >= 0.1      && < 0.8,
                  tagsoup               >= 0.14.6   && < 0.15,
                  temporary             >= 1.1      && < 1.4,
-                 texmath               >= 0.13.2.1 && < 0.14,
+                 texmath               >= 0.13.2.2 && < 0.14,
                  text                  >= 1.1.1.0  && < 2.2,
                  text-conversions      >= 0.3      && < 0.4,
                  time                  >= 1.5      && < 1.17,
@@ -574,10 +574,10 @@
                  zip-archive           >= 0.4.3.1  && < 0.5,
                  zlib                  >= 0.5      && < 0.8,
                  xml                   >= 1.3.12   && < 1.4,
-                 typst                 >= 0.11     && < 0.12,
+                 typst                 >= 0.11.0.1 && < 0.12,
                  vector                >= 0.12     && < 0.14,
-                 djot                  >= 0.1.4.1  && < 0.2,
-                 asciidoc              >= 0.1.0.4  && < 0.2
+                 djot                  >= 0.1.4.2  && < 0.2,
+                 asciidoc              >= 0.1.0.5  && < 0.2
 
   if !os(windows)
     build-depends:  unix >= 2.4 && < 2.9
@@ -719,6 +719,7 @@
                    Text.Pandoc.Transforms,
                    Text.Pandoc.Version
   other-modules:   Text.Pandoc.App.CommandLineOptions,
+                   Text.Pandoc.App.Completion,
                    Text.Pandoc.App.Input,
                    Text.Pandoc.App.Opt,
                    Text.Pandoc.App.OutputSettings,
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs
--- a/src/Text/Pandoc/App/CommandLineOptions.hs
+++ b/src/Text/Pandoc/App/CommandLineOptions.hs
@@ -19,6 +19,7 @@
           , parseOptionsFromArgs
           , handleOptInfo
           , options
+          , OptionSpec(..)
           , engines
           , setVariable
           , versionInfo
@@ -26,7 +27,7 @@
 import Control.Monad.Trans
 import Control.Monad.State.Strict
 import Data.Containers.ListUtils (nubOrd)
-import Data.Aeson (eitherDecode)
+import Data.Aeson (eitherDecode, decode)
 import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder,
          defConfig, Indent(..), NumberFormat(..))
 import Data.Bifunctor (second)
@@ -49,14 +50,16 @@
 import Text.Pandoc
 import Text.Pandoc.Builder (setMeta)
 import Data.Version (showVersion)
+import Text.Pandoc.App.Completion (generateCompletion)
 import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), IpynbOutput (..),
                             DefaultsState (..), applyDefaults,
-                            fullDefaultsPath, OptInfo(..))
+                            fullDefaultsPath, OptInfo(..), CompletionShell(..),
+                            OptionSpec(..), option, toOptDescr,
+                            CompletionKind(..))
 import Text.Pandoc.Filter (Filter (..))
 import Text.Pandoc.Highlighting (highlightingStyles, lookupHighlightingStyle)
 import Text.Pandoc.Scripting (ScriptingEngine (..), customTemplate)
 import Text.Pandoc.Shared (safeStrRead)
-import Text.Printf
 import qualified Control.Exception as E
 import Control.Monad.Except (ExceptT(..), runExceptT, throwError)
 import qualified Data.ByteString as BS
@@ -66,7 +69,7 @@
 import qualified Data.Text as T
 import qualified Text.Pandoc.UTF8 as UTF8
 
-parseOptions :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)]
+parseOptions :: [OptionSpec]
              -> Opt -> IO (Either OptInfo Opt)
 parseOptions options' defaults = do
   rawArgs <- liftIO getArgs
@@ -74,11 +77,11 @@
   parseOptionsFromArgs options' defaults prg rawArgs
 
 parseOptionsFromArgs
-  :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)]
+  :: [OptionSpec]
   -> Opt -> String -> [String] -> IO (Either OptInfo Opt)
 parseOptionsFromArgs options' defaults prg rawArgs = do
   let (actions, args, unrecognizedOpts, errors) =
-           getOpt' Permute options' (preprocessArgs rawArgs)
+           getOpt' Permute (map toOptDescr options') (preprocessArgs rawArgs)
 
   let unknownOptionErrors =
        foldr (handleUnrecognizedOption . takeWhile (/= '=')) []
@@ -111,20 +114,13 @@
 handleOptInfo :: ScriptingEngine -> OptInfo -> IO ()
 handleOptInfo engine info = E.handle (handleError . Left) $ do
   case info of
-    BashCompletion -> do
+    Completion shell -> do
       datafiles <- getDataFileNames
-      tpl <- runIOorExplode $
-               UTF8.toString <$>
-                 readDefaultDataFile "bash_completion.tpl"
-      let optnames (Option shorts longs _ _) =
-            map (\c -> ['-',c]) shorts ++
-            map ("--" ++) longs
-      let allopts = unwords (concatMap optnames options)
-      UTF8.hPutStrLn stdout $ T.pack $ printf tpl allopts
-          (T.unpack $ T.unwords readersNames)
-          (T.unpack $ T.unwords writersNames)
-          (T.unpack $ T.unwords $ map fst highlightingStyles)
-          (unwords datafiles)
+      script <- generateCompletion shell options
+        readersNames writersNames
+        (map fst highlightingStyles)
+        mathMethods pdfEngines datafiles
+      UTF8.hPutStrLn stdout script
     ListInputFormats -> mapM_ (UTF8.hPutStrLn stdout) readersNames
     ListOutputFormats -> mapM_ (UTF8.hPutStrLn stdout) writersNames
     ListExtensions mbfmt -> do
@@ -200,7 +196,7 @@
     Help -> do
       prg <- getProgName
       mapM_ (UTF8.hPutStrLn stdout . T.stripEnd . T.pack) $
-        lines $ usageMessage prg options
+        lines $ usageMessage prg (map toOptDescr options)
     OptError e -> E.throwIO e
   exitSuccess
 
@@ -253,12 +249,12 @@
 isShortBooleanOpt = (`Set.member` shortBooleanOpts)
  where
   shortBooleanOpts =
-     Set.fromList [c | Option [c] _ (OptArg _ "true|false") _ <- options]
+     Set.fromList [c | OptionSpec [c] _ (OptArg _ "true|false") _ _ <- options]
 
 isShortOpt :: Char -> Bool
 isShortOpt = (`Set.member` shortOpts)
  where
-  shortOpts = Set.fromList $ concat [cs | Option cs _ _ _ <- options]
+  shortOpts = Set.fromList $ concat [cs | OptionSpec cs _ _ _ _ <- options]
 
 splitArg :: String -> [String]
 splitArg (c:d:cs)
@@ -270,51 +266,57 @@
 
 -- | A list of functions, each transforming the options data structure
 --   in response to a command-line option.
-options :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)]
+options :: [OptionSpec]
 options =
-    [ Option "fr" ["from","read"]
+    [ option "fr" ["from","read"]
                  (ReqArg
                   (\arg opt -> return opt { optFrom = Just $ T.pack arg })
                   "FORMAT")
-                 ""
+                 InputFormats
+                 (T.pack "Reader format")
 
-    , Option "tw" ["to","write"]
+    , option "tw" ["to","write"]
                  (ReqArg
                   (\arg opt -> return opt { optTo = Just $ T.pack arg })
                   "FORMAT")
-                 ""
+                 OutputFormats
+                 (T.pack "Writer format")
 
-    , Option "o" ["output"]
+    , option "o" ["output"]
                  (ReqArg
                   (\arg opt -> return opt { optOutputFile =
                                              Just (normalizePath arg) })
                   "FILE")
-                 "" -- "Name of output file"
+                 Files
+                 (T.pack "Output file")
 
-    , Option "" ["data-dir"]
+    , option "" ["data-dir"]
                  (ReqArg
                   (\arg opt -> return opt { optDataDir =
                                   Just (normalizePath arg) })
                  "DIRECTORY") -- "Directory containing pandoc data files."
-                ""
+                Files
+                (T.pack "Directory for data files")
 
-    , Option "M" ["metadata"]
+    , option "M" ["metadata"]
                  (ReqArg
                   (\arg opt -> do
                      let (key, val) = splitField arg
                      return opt{ optMetadata = addMeta key val $
                                                  optMetadata opt })
                   "KEY[=VALUE]")
-                 ""
+                 Files
+                 (T.pack "Metadata field KEY=VALUE")
 
-    , Option "" ["metadata-file"]
+    , option "" ["metadata-file"]
                  (ReqArg
                   (\arg opt -> return opt{ optMetadataFiles =
                       optMetadataFiles opt ++ [normalizePath arg] })
                   "FILE")
-                 ""
+                 Files
+                 (T.pack "Metadata file")
 
-    , Option "d" ["defaults"]
+    , option "d" ["defaults"]
                  (ReqArg
                   (\arg opt -> do
                      res <- liftIO $ runIO $ do
@@ -328,40 +330,45 @@
                        Right x -> return x
                   )
                   "FILE")
-                ""
+                Files
+                (T.pack "Defaults file")
 
-    , Option "" ["file-scope"]
+    , option "" ["file-scope"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--file-scope" arg
                         return opt { optFileScope = boolValue })
                   "true|false")
-                 "" -- "Parse input files before combining"
+                 OptFlag
+                 (T.pack "Parse files before combining")
 
-    , Option "" ["sandbox"]
+    , option "" ["sandbox"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--sandbox" arg
                         return opt { optSandbox = boolValue })
                   "true|false")
-                 ""
+                 OptFlag
+                 (T.pack "Run pandoc in a sandbox")
 
-     , Option "s" ["standalone"]
+     , option "s" ["standalone"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--standalone/-s" arg
                         return opt { optStandalone = boolValue })
                   "true|false")
-                 "" -- "Include needed header and footer on output"
+                 OptFlag
+                 (T.pack "Include header and footer")
 
-    , Option "" ["template"]
+    , option "" ["template"]
                  (ReqArg
                   (\arg opt ->
                      return opt{ optTemplate = Just (normalizePath arg) })
                   "FILE")
-                 "" -- "Use custom template"
+                 Files
+                 (T.pack "Custom template file")
 
-    , Option "V" ["variable"]
+    , option "V" ["variable"]
                  (ReqArg
                   (\arg opt -> do
                      let (key, val) = splitField arg
@@ -369,9 +376,10 @@
                                   setVariable (T.pack key) (T.pack val) $
                                     optVariables opt })
                   "KEY[=VALUE]")
-                 ""
+                 Files
+                 (T.pack "Template variable KEY=VALUE")
 
-    , Option "" ["variable-json"]
+    , option "" ["variable-json"]
                  (ReqArg
                   (\arg opt -> do
                      let (key, json) = splitField arg
@@ -386,9 +394,10 @@
                           "Could not parse '" <> T.pack json <> "' as JSON:\n" <>
                            T.pack err')
                   "KEY[:JSON]")
-                 ""
+                 Files
+                 (T.pack "Template variable KEY=JSON")
 
-    , Option "" ["wrap"]
+    , option "" ["wrap"]
                  (ReqArg
                   (\arg opt ->
                     case arg of
@@ -398,25 +407,28 @@
                       _      -> optError $ PandocOptionError
                                  "--wrap must be auto, none, or preserve")
                  "auto|none|preserve")
-                 "" -- "Option for wrapping text in output"
+                 (Fixed ["auto","none","preserve"])
+                 (T.pack "Text wrapping mode")
 
-    , Option "" ["ascii"]
+    , option "" ["ascii"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--ascii" arg
                         return opt { optAscii = boolValue })
                   "true|false")
-                 ""  -- "Prefer ASCII output"
+                 OptFlag
+                 (T.pack "Prefer ASCII output")
 
-    , Option "" ["toc", "table-of-contents"]
+    , option "" ["toc", "table-of-contents"]
                 (OptArg
                  (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--toc/--table-of-contents" arg
                         return opt { optTableOfContents = boolValue })
                  "true|false")
-               "" -- "Include table of contents"
+               OptFlag
+               (T.pack "Include table of contents")
 
-    , Option "" ["toc-depth"]
+    , option "" ["toc-depth"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead arg of
@@ -425,33 +437,37 @@
                            _ -> optError $ PandocOptionError
                                 "Argument of --toc-depth must be a number 1-6")
                  "NUMBER")
-                 "" -- "Number of levels to include in TOC"
+                 Files
+                 (T.pack "Number of TOC levels")
 
-    , Option "" ["lof", "list-of-figures"]
+    , option "" ["lof", "list-of-figures"]
                 (OptArg
                  (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--lof/--list-of-figures" arg
                         return opt { optListOfFigures = boolValue })
                  "true|false")
-               "" -- "Include list of figures"
+               OptFlag
+               (T.pack "Include list of figures")
 
-    , Option "" ["lot", "list-of-tables"]
+    , option "" ["lot", "list-of-tables"]
                 (OptArg
                  (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--lot/--list-of-tables" arg
                         return opt { optListOfTables = boolValue })
                  "true|false")
-               "" -- "Include list of tables"
+               OptFlag
+               (T.pack "Include list of tables")
 
-    , Option "N" ["number-sections"]
+    , option "N" ["number-sections"]
                   (OptArg
                    (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--number-sections/-N" arg
                         return opt { optNumberSections = boolValue })
                   "true|false")
-                 "" -- "Number sections"
+                 OptFlag
+                 (T.pack "Number section headings")
 
-    , Option "" ["number-offset"]
+    , option "" ["number-offset"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead ("[" <> arg <> "]") of
@@ -460,9 +476,10 @@
                            _      -> optError $ PandocOptionError
                                        "could not parse argument of --number-offset")
                  "NUMBERS")
-                 "" -- "Starting number for sections, subsections, etc."
+                 Files
+                 (T.pack "Starting number for sections")
 
-    , Option "" ["top-level-division"]
+    , option "" ["top-level-division"]
                  (ReqArg
                   (\arg opt ->
                       case arg of
@@ -478,57 +495,64 @@
                                 "Argument of --top-level division must be " <>
                                 "section,  chapter, part, or default" )
                    "section|chapter|part")
-                 "" -- "Use top-level division type in LaTeX, ConTeXt, DocBook"
+                 (Fixed ["section","chapter","part"])
+                 (T.pack "Top-level document division")
 
-    , Option "" ["extract-media"]
+    , option "" ["extract-media"]
                  (ReqArg
                   (\arg opt ->
                     return opt { optExtractMedia =
                                   Just (normalizePath arg) })
                   "PATH")
-                 "" -- "Directory to which to extract embedded media"
+                 Files
+                 (T.pack "Directory to extract media into")
 
-    , Option "" ["resource-path"]
+    , option "" ["resource-path"]
                 (ReqArg
                   (\arg opt -> return opt { optResourcePath =
                                    splitSearchPath arg ++
                                     optResourcePath opt })
                    "SEARCHPATH")
-                  "" -- "Paths to search for images and other resources"
+                  Files
+                  (T.pack "Search path for resources")
 
-    , Option "H" ["include-in-header"]
+    , option "H" ["include-in-header"]
                  (ReqArg
                   (\arg opt -> return opt{ optIncludeInHeader =
                                              optIncludeInHeader opt ++
                                              [normalizePath arg] })
                   "FILE")
-                 "" -- "File to include at end of header (implies -s)"
+                 Files
+                 (T.pack "File to include in the header")
 
-    , Option "B" ["include-before-body"]
+    , option "B" ["include-before-body"]
                  (ReqArg
                   (\arg opt -> return opt{ optIncludeBeforeBody =
                                             optIncludeBeforeBody opt ++
                                             [normalizePath arg] })
                   "FILE")
-                 "" -- "File to include before document body"
+                 Files
+                 (T.pack "File to include before the body")
 
-    , Option "A" ["include-after-body"]
+    , option "A" ["include-after-body"]
                  (ReqArg
                   (\arg opt -> return opt{ optIncludeAfterBody =
                                             optIncludeAfterBody opt ++
                                             [normalizePath arg] })
                   "FILE")
-                 "" -- "File to include after document body"
+                 Files
+                 (T.pack "File to include after the body")
 
-    , Option "" ["no-highlight"]
+    , option "" ["no-highlight"]
                 (NoArg
                  (\opt -> do
                      deprecatedOption "--no-highlight"
                        "Use --syntax-highlighting=none instead."
                      return opt { optSyntaxHighlighting = NoHighlightingString }))
-                 "" -- "Don't highlight source code"
+                 OptFlag
+                 (T.pack "Disable syntax highlighting")
 
-    , Option "" ["highlight-style"]
+    , option "" ["highlight-style"]
                 (ReqArg
                  (\arg opt -> do
                      deprecatedOption "--highlight-style"
@@ -536,25 +560,28 @@
                      return opt{ optSyntaxHighlighting =
                                  T.pack $ normalizePath arg })
                  "STYLE|FILE")
-                 "" -- "Style for highlighted code"
+                 HighlightStyles
+                 (T.pack "Highlighting style")
 
-    , Option "" ["syntax-definition"]
+    , option "" ["syntax-definition"]
                 (ReqArg
                  (\arg opt ->
                    return opt{ optSyntaxDefinitions = normalizePath arg :
                                 optSyntaxDefinitions opt })
                  "FILE")
-                "" -- "Syntax definition (xml) file"
+                Files
+                (T.pack "Syntax definition XML file")
 
-    , Option "" ["syntax-highlighting"]
+    , option "" ["syntax-highlighting"]
                 (ReqArg
                  (\arg opt -> return opt{ optSyntaxHighlighting =
                                  T.pack $ normalizePath arg })
                  "none|default|idiomatic|<stylename>|<themepath>")
-                 "" -- "syntax highlighting method for code"
+                 (Fixed ["none","default","idiomatic"])
+                 (T.pack "Syntax highlighting method")
 
 
-    , Option "" ["dpi"]
+    , option "" ["dpi"]
                  (ReqArg
                   (\arg opt ->
                     case safeStrRead arg of
@@ -562,9 +589,10 @@
                          _              -> optError $ PandocOptionError
                                         "Argument of --dpi must be a number greater than 0")
                   "NUMBER")
-                 "" -- "Dpi (default 96)"
+                 Files
+                 (T.pack "DPI for imported images")
 
-    , Option "" ["eol"]
+    , option "" ["eol"]
                  (ReqArg
                   (\arg opt ->
                     case toLower <$> arg of
@@ -575,9 +603,10 @@
                       _      -> optError $ PandocOptionError
                                 "Argument of --eol must be crlf, lf, or native")
                   "crlf|lf|native")
-                 "" -- "EOL (default OS-dependent)"
+                 (Fixed ["crlf","lf","native"])
+                 (T.pack "End-of-line characters")
 
-    , Option "" ["columns"]
+    , option "" ["columns"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead arg of
@@ -585,17 +614,19 @@
                            _              -> optError $ PandocOptionError
                                    "Argument of --columns must be a number greater than 0")
                  "NUMBER")
-                 "" -- "Length of line in characters"
+                 Files
+                 (T.pack "Line length in characters")
 
-    , Option "p" ["preserve-tabs"]
+    , option "p" ["preserve-tabs"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--preserve-tabs/-p" arg
                         return opt { optPreserveTabs = boolValue })
                   "true|false")
-                 "" -- "Preserve tabs instead of converting to spaces"
+                 OptFlag
+                 (T.pack "Preserve tabs")
 
-    , Option "" ["tab-stop"]
+    , option "" ["tab-stop"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead arg of
@@ -603,9 +634,10 @@
                            _              -> optError $ PandocOptionError
                                   "Argument of --tab-stop must be a number greater than 0")
                   "NUMBER")
-                 "" -- "Tab stop (default 4)"
+                 Files
+                 (T.pack "Tab stop width")
 
-    , Option "" ["pdf-engine"]
+    , option "" ["pdf-engine"]
                  (ReqArg
                   (\arg opt -> do
                      let b = takeBaseName arg
@@ -616,109 +648,124 @@
                               "Argument of --pdf-engine must be one of\n"
                                ++ concatMap (\e -> "\t" <> e <> "\n") pdfEngines)
                   "PROGRAM")
-                 "" -- "Name of program to use in generating PDF"
+                 Engines
+                 (T.pack "Program used to produce PDF")
 
-    , Option "" ["pdf-engine-opt"]
+    , option "" ["pdf-engine-opt"]
                  (ReqArg
                   (\arg opt -> do
                       let oldArgs = optPdfEngineOpts opt
                       return opt { optPdfEngineOpts = oldArgs ++ [arg]})
                   "STRING")
-                 "" -- "Flags to pass to the PDF-engine, all instances of this option are accumulated and used"
+                 Files
+                 (T.pack "Flag to pass to the PDF engine")
 
-    , Option "" ["reference-doc"]
+    , option "" ["reference-doc"]
                  (ReqArg
                   (\arg opt ->
                     return opt { optReferenceDoc = Just $ normalizePath arg })
                   "FILE")
-                 "" -- "Path of custom reference doc"
+                 Files
+                 (T.pack "Custom reference doc")
 
-    , Option "" ["self-contained"]
+    , option "" ["self-contained"]
                  (OptArg
                   (\arg opt -> do
-                        deprecatedOption "--self-contained" "use --embed-resources --standalone"
+                        deprecatedOption "--self-contained"
+                          "Use --embed-resources --standalone instead."
                         boolValue <- readBoolFromOptArg "--self-contained" arg
                         return opt { optSelfContained = boolValue })
                     "true|false")
-                 "" -- "Make slide shows include all the needed js and css (deprecated)"
+                 OptFlag
+                 (T.pack "Embed resources (deprecated)")
 
-    , Option "" ["embed-resources"] -- maybe True (\argStr -> argStr == "true") arg
+    , option "" ["embed-resources"] -- maybe True (\argStr -> argStr == "true") arg
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--embed-resources" arg
                         return opt { optEmbedResources =  boolValue })
                   "true|false")
-                 "" -- "Make slide shows include all the needed js and css"
+                 OptFlag
+                 (T.pack "Embed referenced resources")
 
-    , Option "" ["link-images"] -- maybe True (\argStr -> argStr == "true") arg
+    , option "" ["link-images"] -- maybe True (\argStr -> argStr == "true") arg
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--link-images" arg
                         return opt { optLinkImages =  boolValue })
                   "true|false")
-                 "" -- "Link images in ODT rather than embedding them"
+                 OptFlag
+                 (T.pack "Link images in ODT rather than embedding")
 
-    , Option "" ["request-header"]
+    , option "" ["request-header"]
                  (ReqArg
                   (\arg opt -> do
                      let (key, val) = splitField arg
                      return opt{ optRequestHeaders =
                        (T.pack key, T.pack val) : optRequestHeaders opt })
                   "NAME=VALUE")
-                 ""
+                 Files
+                 (T.pack "HTTP header NAME=VALUE")
 
-    , Option "" ["no-check-certificate"]
+    , option "" ["no-check-certificate"]
                 (OptArg
                  (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--no-check-certificate" arg
                         return opt { optNoCheckCertificate = boolValue })
                  "true|false")
-                "" -- "Disable certificate validation"
+                OptFlag
+                (T.pack "Disable certificate validation")
 
-    , Option "" ["abbreviations"]
+    , option "" ["abbreviations"]
                 (ReqArg
                  (\arg opt -> return opt { optAbbreviations =
                                             Just $ normalizePath arg })
                 "FILE")
-                "" -- "Specify file for custom abbreviations"
+                Files
+                (T.pack "File with abbreviations")
 
-    , Option "" ["typst-input"]
+    , option "" ["typst-input"]
                  (ReqArg
                   (\arg opt -> do
                      let (key, val) = splitField arg
                      return opt{ optTypstInputs = (T.pack key, T.pack val) : optTypstInputs opt })
                   "KEY=VALUE")
-                 ""
+                 Files
+                 (T.pack "Typst variable KEY=VALUE")
 
-    , Option "" ["indented-code-classes"]
+    , option "" ["indented-code-classes"]
                   (ReqArg
                    (\arg opt -> return opt { optIndentedCodeClasses = T.words $
                                              T.map (\c -> if c == ',' then ' ' else c) $
                                              T.pack arg })
                    "STRING")
-                  "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
+                  Files
+                  (T.pack "Classes for indented code blocks")
 
-    , Option "" ["default-image-extension"]
+    , option "" ["default-image-extension"]
                  (ReqArg
                   (\arg opt -> return opt { optDefaultImageExtension = T.pack arg })
                    "extension")
-                  "" -- "Default extension for extensionless images"
+                  Files
+                  (T.pack "Default extension for images")
 
-    , Option "F" ["filter"]
+    , option "F" ["filter"]
                  (ReqArg
                   (\arg opt -> return opt { optFilters =
                       optFilters opt ++ [JSONFilter (normalizePath arg)] })
                   "PROGRAM")
-                 "" -- "External JSON filter"
+                 Files
+                 (T.pack "External JSON filter")
 
-    , Option "L" ["lua-filter"]
+    , option "L" ["lua-filter"]
                  (ReqArg
                   (\arg opt -> return opt { optFilters =
                       optFilters opt ++ [LuaFilter (normalizePath arg)] })
                   "SCRIPTPATH")
-                 "" -- "Lua filter"
+                 Files
+                 (T.pack "Lua filter script")
 
-    , Option "" ["shift-heading-level-by"]
+    , option "" ["shift-heading-level-by"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead arg of
@@ -727,9 +774,10 @@
                            _              -> optError $ PandocOptionError
                                                "Argument of --shift-heading-level-by must be an integer")
                   "NUMBER")
-                 "" -- "Shift heading level"
+                 Files
+                 (T.pack "Shift heading level by N")
 
-    , Option "" ["base-header-level"]
+    , option "" ["base-header-level"]
                  (ReqArg
                   (\arg opt -> do
                       deprecatedOption "--base-header-level"
@@ -740,9 +788,10 @@
                            _              -> optError $ PandocOptionError
                                                "Argument of --base-header-level must be 1-5")
                   "NUMBER")
-                 "" -- "Headers base level"
+                 Files
+                 (T.pack "Base header level (deprecated)")
 
-    , Option "" ["track-changes"]
+    , option "" ["track-changes"]
                  (ReqArg
                   (\arg opt -> do
                      action <- case arg of
@@ -753,25 +802,28 @@
                                "Argument of --track-changes must be accept, reject, or all"
                      return opt { optTrackChanges = action })
                   "accept|reject|all")
-                 "" -- "Accepting or reject MS Word track-changes.""
+                 (Fixed ["accept","reject","all"])
+                 (T.pack "Handling of Word track-changes")
 
-    , Option "" ["strip-comments"]
+    , option "" ["strip-comments"]
                 (OptArg
                  (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--strip-comments" arg
                         return opt { optStripComments = boolValue })
                  "true|false")
-               "" -- "Strip HTML comments"
+               OptFlag
+               (T.pack "Strip HTML comments")
 
-    , Option "" ["reference-links"]
+    , option "" ["reference-links"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--reference-links" arg
                         return opt { optReferenceLinks = boolValue })
                   "true|false")
-                 "" -- "Use reference links in parsing HTML"
+                 OptFlag
+                 (T.pack "Use reference links in HTML")
 
-    , Option "" ["reference-location"]
+    , option "" ["reference-location"]
                  (ReqArg
                   (\arg opt -> do
                      action <- case arg of
@@ -782,9 +834,10 @@
                                "Argument of --reference-location must be block, section, or document"
                      return opt { optReferenceLocation = action })
                   "block|section|document")
-                 "" -- "Specify where reference links and footnotes go"
+                 (Fixed ["block","section","document"])
+                 (T.pack "Location of references")
 
-    , Option "" ["figure-caption-position"]
+    , option "" ["figure-caption-position"]
                  (ReqArg
                   (\arg opt -> do
                      pos <- case arg of
@@ -794,9 +847,10 @@
                                "Argument of --figure-caption-position must be above or below"
                      return opt { optFigureCaptionPosition = pos })
                   "above|below")
-                 "" -- "Specify where figure captions go"
+                 (Fixed ["above","below"])
+                 (T.pack "Figure caption position")
 
-    , Option "" ["table-caption-position"]
+    , option "" ["table-caption-position"]
                  (ReqArg
                   (\arg opt -> do
                      pos <- case arg of
@@ -806,9 +860,10 @@
                                "Argument of --table-caption-position must be above or below"
                      return opt { optTableCaptionPosition = pos })
                   "above|below")
-                 "" -- "Specify where table captions go"
+                 (Fixed ["above","below"])
+                 (T.pack "Table caption position")
 
-    , Option "" ["markdown-headings"]
+    , option "" ["markdown-headings"]
                   (ReqArg
                     (\arg opt -> do
                       headingFormat <- case arg of
@@ -819,17 +874,19 @@
                       pure opt { optSetextHeaders = headingFormat }
                     )
                   "setext|atx")
-                  ""
+                  (Fixed ["setext","atx"])
+                  (T.pack "Markdown heading style")
 
-    , Option "" ["list-tables"]
+    , option "" ["list-tables"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--list-tables" arg
                         return opt { optListTables = boolValue })
                   "true|false")
-                 "" -- "Use list tables for RST"
+                 OptFlag
+                 (T.pack "Use list tables for RST")
 
-    , Option "" ["listings"]
+    , option "" ["listings"]
                  (OptArg
                   (\arg opt -> do
                       deprecatedOption "--listings"
@@ -841,17 +898,19 @@
                                    IdiomaticHighlightingString }
                         else opt)
                   "true|false")
-                 "" -- "Use listings package for LaTeX code blocks"
+                 OptFlag
+                 (T.pack "Use listings package (deprecated)")
 
-    , Option "i" ["incremental"]
+    , option "i" ["incremental"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--incremental/-i" arg
                         return opt { optIncremental = boolValue })
                   "true|false")
-                 "" -- "Make list items display incrementally in Slidy/Slideous/S5"
+                 OptFlag
+                 (T.pack "Make list items display incrementally")
 
-    , Option "" ["slide-level"]
+    , option "" ["slide-level"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead arg of
@@ -860,25 +919,28 @@
                            _      -> optError $ PandocOptionError
                                     "Argument of --slide-level must be a number between 0 and 6")
                  "NUMBER")
-                 "" -- "Force header level for slides"
+                 Files
+                 (T.pack "Header level used for slides")
 
-    , Option "" ["section-divs"]
+    , option "" ["section-divs"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--section-divs" arg
                         return opt { optSectionDivs = boolValue })
                   "true|false")
-                 "" -- "Put sections in div tags in HTML"
+                 OptFlag
+                 (T.pack "Wrap sections in div tags")
 
-    , Option "" ["html-q-tags"]
+    , option "" ["html-q-tags"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--html-q-tags" arg
                         return opt { optHtmlQTags = boolValue })
                   "true|false")
-                 "" -- "Use <q> tags for quotes in HTML"
+                 OptFlag
+                 (T.pack "Use q tags for quotes in HTML")
 
-    , Option "" ["email-obfuscation"]
+    , option "" ["email-obfuscation"]
                  (ReqArg
                   (\arg opt -> do
                      method <- case arg of
@@ -889,15 +951,17 @@
                                "Argument of --email-obfuscation must be references, javascript, or none"
                      return opt { optEmailObfuscation = method })
                   "none|javascript|references")
-                 "" -- "Method for obfuscating email in HTML"
+                 (Fixed ["references","javascript","none"])
+                 (T.pack "Email obfuscation method")
 
-     , Option "" ["id-prefix"]
+     , option "" ["id-prefix"]
                   (ReqArg
                    (\arg opt -> return opt { optIdentifierPrefix = T.pack arg })
                    "STRING")
-                  "" -- "Prefix to add to automatically generated HTML identifiers"
+                  Files
+                  (T.pack "Prefix for auto identifiers")
 
-    , Option "T" ["title-prefix"]
+    , option "T" ["title-prefix"]
                  (ReqArg
                   (\arg opt ->
                     return opt {
@@ -906,23 +970,26 @@
                            optVariables opt,
                        optStandalone = True })
                   "STRING")
-                 "" -- "String to prefix to HTML window title"
+                 Files
+                 (T.pack "Window title prefix")
 
-    , Option "c" ["css"]
+    , option "c" ["css"]
                  (ReqArg
                   (\arg opt -> return opt{ optCss = optCss opt ++ [arg] })
                   -- add new link to end, so it is included in proper order
                   "URL")
-                 "" -- "Link to CSS style sheet"
+                 Files
+                 (T.pack "CSS style sheet")
 
-    , Option "" ["epub-subdirectory"]
+    , option "" ["epub-subdirectory"]
              (ReqArg
                   (\arg opt ->
                      return opt { optEpubSubdirectory = arg })
                   "DIRNAME")
-                 "" -- "Name of subdirectory for epub content in OCF container"
+                 Files
+                 (T.pack "EPUB content subdirectory")
 
-    , Option "" ["epub-cover-image"]
+    , option "" ["epub-cover-image"]
                  (ReqArg
                   (\arg opt ->
                      return opt { optVariables =
@@ -930,32 +997,36 @@
                          (T.pack $ normalizePath arg) $
                          optVariables opt })
                   "FILE")
-                 "" -- "Path of epub cover image"
+                 Files
+                 (T.pack "EPUB cover image")
 
-    , Option "" ["epub-title-page"]
+    , option "" ["epub-title-page"]
                  (OptArg
                   (\arg opt -> do
                      boolValue <- readBoolFromOptArg "--epub-title-page" arg
                      return opt{ optEpubTitlePage = boolValue })
                  "true|false")
-                 ""
+                 Files
+                 (T.pack "URL or file for EPUB title page")
 
-    , Option "" ["epub-metadata"]
+    , option "" ["epub-metadata"]
                  (ReqArg
                   (\arg opt -> return opt { optEpubMetadata = Just $
                                              normalizePath arg })
                   "FILE")
-                 "" -- "Path of epub metadata file"
+                 Files
+                 (T.pack "EPUB metadata file")
 
-    , Option "" ["epub-embed-font"]
+    , option "" ["epub-embed-font"]
                  (ReqArg
                   (\arg opt ->
                      return opt{ optEpubFonts = normalizePath arg :
                                                 optEpubFonts opt })
                   "FILE")
-                 "" -- "Directory of fonts to embed"
+                 Files
+                 (T.pack "Font file to embed in EPUB")
 
-    , Option "" ["split-level"]
+    , option "" ["split-level"]
                  (ReqArg
                   (\arg opt ->
                       case safeStrRead arg of
@@ -964,29 +1035,32 @@
                            _      -> optError $ PandocOptionError
                                     "Argument of --split-level must be a number between 1 and 6")
                  "NUMBER")
-                 "" -- "Header level at which to split documents in chunked HTML or EPUB"
+                 Files
+                 (T.pack "Split level for chunked HTML or EPUB")
 
-    , Option "" ["chunk-template"]
+    , option "" ["chunk-template"]
                  (ReqArg
                   (\arg opt ->
                      return opt{ optChunkTemplate = Just (T.pack arg) })
                  "PATHTEMPLATE")
-                 "" -- "Template for file paths in chunkedhtml"
+                 Files
+                 (T.pack "Template for chunked HTML paths")
 
-    , Option "" ["epub-chapter-level"]
+    , option "" ["epub-chapter-level"]
                  (ReqArg
                   (\arg opt -> do
                       deprecatedOption "--epub-chapter-level"
-                                       "use --split-level"
+                                       "Use --split-level instead."
                       case safeStrRead arg of
                            Just t | t >= 1 && t <= 6 ->
                                     return opt { optSplitLevel = t }
                            _      -> optError $ PandocOptionError
                                     "Argument of --epub-chapter-level must be a number between 1 and 6")
                  "NUMBER")
-                 "" -- "Header level at which to split documents in chunked HTML or EPUB"
+                 Files
+                 (T.pack "Split level (deprecated)")
 
-    , Option "" ["ipynb-output"]
+    , option "" ["ipynb-output"]
                  (ReqArg
                   (\arg opt ->
                     case arg of
@@ -996,188 +1070,258 @@
                       _ -> optError $ PandocOptionError
                              "Argument of --ipynb-output must be all, none, or best")
                  "all|none|best")
-                 "" -- "Starting number for sections, subsections, etc."
+                 (Fixed ["all","none","best"])
+                 (T.pack "Handling of ipynb output cells")
 
-    , Option "C" ["citeproc"]
+    , option "C" ["citeproc"]
                  (NoArg
                   (\opt -> return opt { optFilters =
                       optFilters opt ++ [CiteprocFilter] }))
-                 "" -- "Process citations"
+                 OptFlag
+                 (T.pack "Process citations")
 
-    , Option "" ["bibliography"]
+    , option "" ["bibliography"]
                  (ReqArg
                   (\arg opt -> return opt{ optBibliography =
                                             optBibliography opt ++
                                               [normalizePath arg] })
                    "FILE")
-                 ""
+                 Files
+                 (T.pack "Bibliography file")
 
-     , Option "" ["csl"]
+     , option "" ["csl"]
                  (ReqArg
                   (\arg opt -> do
                     return opt{ optCSL = Just (normalizePath arg) })
                    "FILE")
-                 ""
+                 Files
+                 (T.pack "CSL style file")
 
-     , Option "" ["citation-abbreviations"]
+     , option "" ["citation-abbreviations"]
                  (ReqArg
                   (\arg opt ->
                      return opt{ optMetadata =
                                   addMeta "citation-abbreviations"
                                     (normalizePath arg) $ optMetadata opt })
                    "FILE")
-                 ""
+                 Files
+                 (T.pack "Citation abbreviations file")
 
-    , Option "" ["natbib"]
+    , option "" ["natbib"]
                  (NoArg
                   (\opt -> return opt { optCiteMethod = Natbib }))
-                 "" -- "Use natbib cite commands in LaTeX output"
+                 OptFlag
+                 (T.pack "Use natbib citations in LaTeX")
 
-    , Option "" ["biblatex"]
+    , option "" ["biblatex"]
                  (NoArg
                   (\opt -> return opt { optCiteMethod = Biblatex }))
-                 "" -- "Use biblatex cite commands in LaTeX output"
+                 OptFlag
+                 (T.pack "Use biblatex citations in LaTeX")
 
-    , Option "" ["mathml"]
+    , option "" ["math-method"]
+                 (ReqArg
+                  (\arg opt -> do
+                     let (key, val) = splitField arg
+                     let json = if val == "true"
+                                then show key
+                                else "{\"method\":" <> show key
+                                     <> ",\"url\": " <> show val <> "}"
+                     case decode (UTF8.fromStringLazy json) of
+                       Just method ->
+                         return opt { optMathMethod = method }
+                       Nothing -> optError $ PandocOptionError $
+                           "Unknown math-method '" <> T.pack arg <>
+                           "'.  Expected one of: " <>
+                           "plain, mathml, webtex, mathjax, katex, gladtex."
+                         )
+                 "METHOD")
+                 MathMethods
+                 (T.pack "Specify method for rendering math in HTML")
+
+    , option "" ["mathml"]
                  (NoArg
-                  (\opt ->
-                      return opt { optHTMLMathMethod = MathML }))
-                 "" -- "Use mathml for HTML math"
+                  (\opt -> do
+                      deprecatedOption "--mathml"
+                        "Use --math-method=mathml instead."
+                      return opt { optMathMethod = MathML }))
+                 OptFlag
+                 (T.pack "Use MathML for HTML math")
 
-    , Option "" ["webtex"]
+    , option "" ["webtex"]
                  (OptArg
                   (\arg opt -> do
+                      deprecatedOption "--webtex"
+                        "Use --math-method=webtex[:URL] instead."
                       let url' = maybe defaultWebTeXURL T.pack arg
-                      return opt { optHTMLMathMethod = WebTeX url' })
+                      return opt { optMathMethod = WebTeX url' })
                   "URL")
-                 "" -- "Use web service for HTML math"
+                 OptFlag
+                 (T.pack "Use WebTeX for HTML math")
 
-    , Option "" ["mathjax"]
+    , option "" ["mathjax"]
                  (OptArg
                   (\arg opt -> do
+                      deprecatedOption "--mathjax"
+                        "Use --math-method=mathjax[:URL] instead."
                       let url' = maybe defaultMathJaxURL T.pack arg
-                      return opt { optHTMLMathMethod = MathJax url'})
+                      return opt { optMathMethod = MathJax url'})
                   "URL")
-                 "" -- "Use MathJax for HTML math"
+                 OptFlag
+                 (T.pack "Use MathJax for HTML math")
 
-    , Option "" ["katex"]
+    , option "" ["katex"]
                  (OptArg
-                  (\arg opt ->
+                  (\arg opt -> do
+                      deprecatedOption "--katex"
+                        "Use --math-method=katex[:URL] instead."
                       return opt
-                        { optHTMLMathMethod = KaTeX $
+                        { optMathMethod = KaTeX $
                            maybe defaultKaTeXURL T.pack arg })
                   "URL")
-                  "" -- Use KaTeX for HTML Math
+                  OptFlag
+                  (T.pack "Use KaTeX for HTML math")
 
-    , Option "" ["gladtex"]
+    , option "" ["gladtex"]
                  (NoArg
-                  (\opt ->
-                      return opt { optHTMLMathMethod = GladTeX }))
-                 "" -- "Use gladtex for HTML math"
+                  (\opt -> do
+                      deprecatedOption "--gladtex"
+                        "Use --math-method=gladtex[:URL] instead."
+                      return opt { optMathMethod = GladTeX }))
+                 OptFlag
+                 (T.pack "Use gladTeX for HTML math")
 
-    , Option "" ["trace"]
+    , option "" ["trace"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--trace" arg
                         return opt { optTrace = boolValue })
                   "true|false")
-                 "" -- "Turn on diagnostic tracing in readers."
+                 OptFlag
+                 (T.pack "Turn on diagnostic tracing")
 
-    , Option "" ["dump-args"]
+    , option "" ["dump-args"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--dump-args" arg
                         return opt { optDumpArgs = boolValue })
                   "true|false")
-                 "" -- "Print output filename and arguments to stdout."
+                 OptFlag
+                 (T.pack "Print output filename and arguments")
 
-    , Option "" ["ignore-args"]
+    , option "" ["ignore-args"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--ignore-args" arg
                         return opt { optIgnoreArgs = boolValue })
                   "true|false")
-                 "" -- "Ignore command-line arguments."
+                 OptFlag
+                 (T.pack "Ignore command-line arguments")
 
-    , Option "" ["verbose"]
+    , option "" ["verbose"]
                  (NoArg
                   (\opt -> return opt { optVerbosity = INFO }))
-                 "" -- "Verbose diagnostic output."
+                 OptFlag
+                 (T.pack "Verbose diagnostic output")
 
-    , Option "" ["quiet"]
+    , option "" ["quiet"]
                  (NoArg
                   (\opt -> return opt { optVerbosity = ERROR }))
-                 "" -- "Suppress warnings."
+                 OptFlag
+                 (T.pack "Suppress warning messages")
 
-    , Option "" ["fail-if-warnings"]
+    , option "" ["fail-if-warnings"]
                  (OptArg
                   (\arg opt -> do
                         boolValue <- readBoolFromOptArg "--fail-if-warnings" arg
                         return opt { optFailIfWarnings = boolValue })
                   "true|false")
-                 "" -- "Exit with error status if there were  warnings."
+                 OptFlag
+                 (T.pack "Exit with error status if there were warnings")
 
-    , Option "" ["log"]
+    , option "" ["log"]
                  (ReqArg
                   (\arg opt -> return opt{ optLogFile = Just $
                                             normalizePath arg })
                 "FILE")
-                "" -- "Log messages in JSON format to this file."
+                Files
+                (T.pack "Log messages in JSON format to this file")
 
-    , Option "" ["bash-completion"]
-                 (NoArg (\_ -> optInfo BashCompletion))
-                 "" -- "Print bash completion script"
+    , option "" ["completion"]
+                 (ReqArg
+                  (\arg _opt -> optInfo $ parseCompletionShell arg)
+                  "SHELL")
+                 OptFlag
+                 (T.pack "Shell for which to print the completion script")
 
-    , Option "" ["list-input-formats"]
+    , option "" ["bash-completion"]
+                 (NoArg (\_ -> do
+                    deprecatedOption "--bash-completion"
+                       "Use --completion=bash instead."
+                    optInfo $ Completion Bash))
+                 OptFlag
+                 (T.pack "Print bash completion script (deprecated)")
+
+    , option "" ["list-input-formats"]
                  (NoArg (\_ -> optInfo ListInputFormats))
-                 ""
+                 OptFlag
+                 (T.pack "List supported input formats")
 
-    , Option "" ["list-output-formats"]
+    , option "" ["list-output-formats"]
                  (NoArg (\_ -> optInfo ListOutputFormats))
-                 ""
+                 OptFlag
+                 (T.pack "List supported output formats")
 
-    , Option "" ["list-extensions"]
+    , option "" ["list-extensions"]
                  (OptArg (\arg _ -> optInfo $ ListExtensions $ T.pack <$> arg)
                  "FORMAT")
-                 ""
+                 OptFlag
+                 (T.pack "List supported extensions")
 
-    , Option "" ["list-highlight-languages"]
+    , option "" ["list-highlight-languages"]
                  (NoArg (\_ -> optInfo ListHighlightLanguages))
-                 ""
+                 OptFlag
+                 (T.pack "List highlighting languages")
 
-    , Option "" ["list-highlight-styles"]
+    , option "" ["list-highlight-styles"]
                  (NoArg (\_ -> optInfo ListHighlightStyles))
-                 ""
+                 OptFlag
+                 (T.pack "List highlighting styles")
 
-    , Option "D" ["print-default-template"]
+    , option "D" ["print-default-template"]
                  (ReqArg
                   (\arg opts -> optInfo $
                     PrintDefaultTemplate (optOutputFile opts) (T.pack arg))
                  "FORMAT")
-                 "" -- "Print default template for FORMAT"
+                 OutputFormats
+                 (T.pack "Format to print template for")
 
-    , Option "" ["print-default-data-file"]
+    , option "" ["print-default-data-file"]
                  (ReqArg
                   (\arg opts -> optInfo $
                     PrintDefaultDataFile (optOutputFile opts) (T.pack arg))
                  "FILE")
-                  "" -- "Print default data file"
+                  DataFiles
+                  (T.pack "Data file to print")
 
-    , Option "" ["print-highlight-style"]
+    , option "" ["print-highlight-style"]
                  (ReqArg
                   (\arg opts ->
                     optInfo $ PrintHighlightStyle (optOutputFile opts)
                                (T.pack arg))
                   "STYLE|FILE")
-                 "" -- "Print default template for FORMAT"
+                 HighlightStyles
+                 (T.pack "Highlighting style")
 
-    , Option "v" ["version"]
+    , option "v" ["version"]
                  (NoArg (\_ -> optInfo VersionInfo))
-                 "" -- "Print version"
+                 OptFlag
+                 (T.pack "Print version")
 
-    , Option "h" ["help"]
+    , option "h" ["help"]
                  (NoArg (\_ -> optInfo Help))
-                 "" -- "Show help"
+                 OptFlag
+                 (T.pack "Show help")
     ]
 
 optError :: PandocError -> ExceptT OptInfo IO a
@@ -1186,6 +1330,15 @@
 optInfo :: OptInfo -> ExceptT OptInfo IO a
 optInfo = throwError
 
+parseCompletionShell :: String -> OptInfo
+parseCompletionShell "bash" = Completion Bash
+parseCompletionShell "zsh"  = Completion Zsh
+parseCompletionShell "fish" = Completion Fish
+parseCompletionShell s =
+  OptError $ PandocOptionError $
+    "Unknown completion shell '" <> T.pack s <>
+    "'.  Expected one of: bash, zsh, fish."
+
 -- Returns usage message
 usageMessage :: String -> [OptDescr (Opt -> ExceptT OptInfo IO Opt)] -> String
 usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
@@ -1224,6 +1377,9 @@
 handleUnrecognizedOption "-R" = handleUnrecognizedOption "--parse-raw"
 handleUnrecognizedOption x =
   (("Unknown option " ++ x ++ ".") :)
+
+mathMethods :: [Text]
+mathMethods = ["plain", "mathml", "webtex", "mathjax", "katex", "gladtex"]
 
 readersNames :: [Text]
 readersNames = sort (map fst (readers :: [(Text, Reader PandocIO)]))
diff --git a/src/Text/Pandoc/App/Completion.hs b/src/Text/Pandoc/App/Completion.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Pandoc/App/Completion.hs
@@ -0,0 +1,284 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{- |
+   Module      : Text.Pandoc.App.Completion
+   Copyright   : Copyright (C) 2006-2024 John MacFarlane
+   License     : GNU GPL, version 2 or above
+
+   Maintainer  : John MacFarlane <jgm@berkeley@edu>
+   Stability   : alpha
+   Portability : portable
+
+Generation of shell completion scripts for bash, zsh and fish.
+The scripts are generated at runtime from pandoc's single list of
+command-line options ('OptionSpec'), together with the completion
+metadata that each option carries (its 'CompletionKind' and a short
+description).  All completions are static: the lists of formats,
+styles, engines and data files are embedded into the generated script,
+so no call to pandoc is made while completing.
+-}
+module Text.Pandoc.App.Completion ( generateCompletion ) where
+
+import Data.List (intercalate)
+import Data.Text (Text)
+import qualified Data.List as L
+import qualified Data.Text as T
+import System.Console.GetOpt (ArgDescr (..))
+import Text.Pandoc.App.Opt (CompletionShell (..), OptionSpec (..),
+                            CompletionKind (..))
+
+-- | Generate a completion script for the given shell.  The completion
+-- behaviour and descriptions are taken from the per-option 'OptionSpec'
+-- data, so the script cannot drift from the actual options.
+generateCompletion :: CompletionShell
+                   -> [OptionSpec]   -- ^ the option list
+                   -> [Text]         -- ^ input formats
+                   -> [Text]         -- ^ output formats
+                   -> [Text]         -- ^ highlighting style names
+                   -> [Text]         -- ^ math methods
+                   -> [String]       -- ^ PDF engines
+                   -> [String]       -- ^ data files
+                   -> IO Text
+generateCompletion Bash   = bashScript
+generateCompletion Zsh    = zshScript
+generateCompletion Fish   = fishScript
+
+-- | The list of all option names (short and long), space separated.
+allOptionNames :: [OptionSpec] -> String
+allOptionNames opts =
+  unwords [ name | OptionSpec shorts longs _ _ _ <- opts
+                 , name <- map (\c -> '-' : [c]) shorts ++
+                             map ("--" ++) longs ]
+
+-- | The completion kind and description for an option.  This is taken
+-- directly from the 'OptionSpec'; there is no separate specification to
+-- keep in sync.
+optionKindDesc :: OptionSpec -> (CompletionKind, Text)
+optionKindDesc (OptionSpec _ _ _ k desc) = (k, desc)
+
+placeholder :: ArgDescr a -> Maybe String
+placeholder (ReqArg _ s) = Just s
+placeholder (OptArg _ s) = Just s
+placeholder _ = Nothing
+
+-- | Whether an option needs an explicit @case "${prev}"@ arm in the bash
+-- script.  Options that just take a file or are boolean flags fall
+-- through to the default file completion, so they need no arm.
+isCompletableKind :: CompletionKind -> Bool
+isCompletableKind OptFlag = False
+isCompletableKind Files   = False
+isCompletableKind _       = True
+
+-- | The argument passed to @compgen -W@ for an option of the given kind.
+-- Dynamic kinds reference the shell variables that pandoc fills in;
+-- fixed enumerations are listed verbatim.
+prevSource :: CompletionKind  -- ^ completion kind
+           -> String          -- ^ engine list (already space-joined)
+           -> String
+prevSource InputFormats    _ = "${informats}"
+prevSource OutputFormats   _ = "${outformats}"
+prevSource HighlightStyles _ = "${highlight_styles}"
+prevSource MathMethods _     = "${math_methods}"
+prevSource DataFiles       _ = "${datafiles}"
+prevSource Engines         e = e
+prevSource (Fixed vs)      _ = unwords vs
+prevSource OptFlag         _ = ""
+prevSource Files           _ = ""
+
+----------------------------------------------------------------------
+-- bash
+----------------------------------------------------------------------
+
+-- | The bash completion script reproduces the historical script that
+-- was previously generated from @data/bash_completion.tpl@.  The list
+-- of options completed per value (the @case "${prev}"@ arms) is derived
+-- from the option list, so it cannot drift from the actual options.
+bashScript :: [OptionSpec] -> [Text] -> [Text] -> [Text] ->
+              [Text] -> [String] -> [String] -> IO Text
+bashScript opts informats outformats hstyles mmethods engines datafiles = do
+  let optsStr   = allOptionNames opts
+      infStr    = unwords (map T.unpack informats)
+      outfStr   = unwords (map T.unpack outformats)
+      hsStr     = unwords (map T.unpack hstyles)
+      mmStr     = unwords (map T.unpack mmethods)
+      dfStr     = unwords datafiles
+      engStr    = unwords engines
+      caseBody  = concatMap armToLines (bashCaseArms opts engStr)
+  return $ T.unlines $
+    [ "# This script enables bash autocompletion for pandoc.  To enable"
+    , "# bash completion, add this to your .bashrc:"
+    , "# eval \"$(pandoc --completion=bash)\""
+    , ""
+    , "_pandoc()"
+    , "{"
+    , "    local cur prev opts informats outformats highlight_styles math_methods datafiles"
+    , "    COMPREPLY=()"
+    , "    cur=\"${COMP_WORDS[COMP_CWORD]}\""
+    , "    prev=\"${COMP_WORDS[COMP_CWORD-1]}\""
+    , ""
+    , "    # These should be filled in by pandoc:"
+    , T.pack $ "    opts=\"" ++ optsStr ++ "\""
+    , T.pack $ "    informats=\"" ++ infStr ++ "\""
+    , T.pack $ "    outformats=\"" ++ outfStr ++ "\""
+    , T.pack $ "    highlight_styles=\"" ++ hsStr ++ "\""
+    , T.pack $ "    math_methods=\"" ++ mmStr ++ "\""
+    , T.pack $ "    datafiles=\"" ++ dfStr ++ "\""
+    , ""
+    , "    case \"${prev}\" in"
+    ]
+    ++ caseBody ++
+    [ "         *)"
+    , "             ;;"
+    , "    esac"
+    , ""
+    , "    case \"${cur}\" in"
+    , "         -*)"
+    , "             COMPREPLY=( $(compgen -W \"${opts}\" -- ${cur}) )"
+    , "             return 0"
+    , "             ;;"
+    , "         *)"
+    , "             local IFS=$'\\n'"
+    , "             COMPREPLY=( $(compgen -X '' -f \"${cur}\") )"
+    , "             return 0"
+    , "             ;;"
+    , "    esac"
+    , ""
+    , "}"
+    , ""
+    , "complete -o filenames -o bashdefault -F _pandoc pandoc"
+    ]
+
+-- | The @case "${prev}"@ arms, one per distinct completion source,
+-- merging all options that share the same source so that (for example)
+-- @--from@ and @--read@ end up in a single arm.
+bashCaseArms :: [OptionSpec] -> String -> [(String, [String])]
+bashCaseArms opts engStr =
+  let arms = [ (prevSource k engStr, names)
+             | o@(OptionSpec shorts longs _ _ _) <- opts
+             , let (k, _) = optionKindDesc o
+             , isCompletableKind k
+             , let names = map (\c -> '-' : [c]) shorts ++
+                           map ("--" ++) longs ]
+  in mergeArms arms
+
+-- | Merge arms that share the same completion source, preserving the
+-- order in which the sources first appear in the option list.
+mergeArms :: [(String, [String])] -> [(String, [String])]
+mergeArms = L.foldl' go []
+  where go [] (src, ns) = [(src, ns)]
+        go (x@(s, ns0) : xs) (src, ns)
+          | s == src  = (s, ns0 ++ ns) : xs
+          | otherwise = x : go xs (src, ns)
+
+-- | Render one merged arm as the four lines of a bash @case@ body.
+armToLines :: (String, [String]) -> [Text]
+armToLines (src, names) =
+  let pat = intercalate "|" names
+  in [ T.pack ("         " ++ pat ++ ")")
+     , T.pack ("             COMPREPLY=( $(compgen -W \"" ++ src ++
+              "\" -- ${cur}) )")
+     , "             return 0"
+     , "             ;;" ]
+
+----------------------------------------------------------------------
+-- zsh
+----------------------------------------------------------------------
+
+zshScript :: [OptionSpec] -> [Text] -> [Text] -> [Text] -> [Text] -> [String]
+          -> [String] -> IO Text
+zshScript opts informats outformats hstyles mmethods engines datafiles = do
+  let action k mbP =
+        case k of
+           OptFlag -> ""
+           Files -> ":" <> maybe "FILE" T.pack mbP <> ":_files"
+           Fixed vs -> ":" <> maybe "VALUE" T.pack mbP
+                          <> ":(" <> T.pack (unwords vs) <> ")"
+           InputFormats -> ":FORMAT:(" <> T.unwords informats <> ")"
+           OutputFormats -> ":FORMAT:(" <> T.unwords outformats <> ")"
+           HighlightStyles -> ":STYLE:(" <> T.unwords hstyles <> ")"
+           MathMethods -> ":METHOD:(" <> T.unwords mmethods <> ")"
+           DataFiles -> ":FILE:(" <> T.pack (unwords datafiles) <> ")"
+           Engines -> ":PROGRAM:(" <> T.pack (unwords engines) <> ")"
+      optLines = concat
+        [ zshOptionLine o action
+        | o@(OptionSpec _shorts _longs _ad _ _) <- opts ]
+  return $ T.unlines $
+    [ "#compdef pandoc"
+    , ""
+    , "_pandoc() {"
+    , "  local -a args"
+    , "  args=("
+    ]
+    ++ optLines
+    ++ [ "    '*:files:_files'"
+       , "  )"
+       , "  _arguments -s -S $args"
+       , "}"
+       , ""
+       , "_pandoc \"$@\""
+       ]
+
+-- | Produce one or more @_arguments@ spec lines (one per name) for an
+-- option.  The description and action are embedded in single quotes.
+zshOptionLine :: OptionSpec
+              -> (CompletionKind -> Maybe String -> Text)
+              -> [Text]
+zshOptionLine (OptionSpec shorts longs ad k desc) action =
+  let desc' = escapeZshDesc desc
+      act   = action k (placeholder ad)
+      line name = T.pack ("    '" ++ name ++ "[") <> desc' <>
+                  T.pack ("]") <> act <> T.pack "'"
+  in map line (map (\c -> '-' : [c]) shorts ++ map ("--" ++) longs)
+
+-- | Escape a description for embedding inside a single-quoted zsh
+-- @_arguments@ spec.  Single quotes are the only character that needs
+-- special treatment; the descriptions are kept free of colons and
+-- square brackets.
+escapeZshDesc :: Text -> Text
+escapeZshDesc = T.replace "'" "'\\''"
+
+----------------------------------------------------------------------
+-- fish
+----------------------------------------------------------------------
+
+fishScript :: [OptionSpec] -> [Text] -> [Text] -> [Text] -> [Text]
+           -> [String] -> [String] -> IO Text
+fishScript opts informats outformats hstyles mmethods engines datafiles = do
+  let argPart k _mbP =
+         case k of
+           OptFlag -> ""
+           Files -> " -r"
+           Fixed vs -> " -r -a \"" <> T.pack (unwords vs) <> "\""
+           InputFormats -> " -r -a \"" <> T.unwords informats <> "\""
+           OutputFormats -> " -r -a \"" <> T.unwords outformats <> "\""
+           HighlightStyles -> " -r -a \"" <> T.unwords hstyles <> "\""
+           MathMethods -> " -r -a \"" <> T.unwords mmethods <> "\""
+           DataFiles -> " -r -a \"" <> T.pack (unwords datafiles) <> "\""
+           Engines -> " -r -a \"" <> T.pack (unwords engines) <> "\""
+      optLines = concat
+        [ fishOptionLine o argPart
+        | o@(OptionSpec _shorts _longs _ad _ _) <- opts ]
+  return $ T.unlines optLines
+
+fishOptionLine :: OptionSpec
+               -> (CompletionKind -> Maybe String -> Text)
+               -> [Text]
+fishOptionLine (OptionSpec shorts longs ad k desc) argPart =
+  let shortPart = case shorts of
+                   [c] -> T.pack (" -s " ++ [c])
+                   _   -> ""
+      descPart = if T.null desc
+                   then ""
+                   else T.pack " -d \"" <> escapeFishDesc desc <> T.pack "\""
+  in [ T.pack "complete -c pandoc" <> shortPart <>
+       T.pack (" -l " ++ l) <> descPart <>
+       argPart k (placeholder ad)
+     | l <- take 1 longs ]
+
+-- | Escape a description for a fish completion @-d@ argument, which is
+-- wrapped in double quotes.
+escapeFishDesc :: Text -> Text
+escapeFishDesc = T.replace "\\" "\\\\"
+               . T.replace "\"" "\\\""
+               . T.replace "$" "\\$"
diff --git a/src/Text/Pandoc/App/Opt.hs b/src/Text/Pandoc/App/Opt.hs
--- a/src/Text/Pandoc/App/Opt.hs
+++ b/src/Text/Pandoc/App/Opt.hs
@@ -20,14 +20,20 @@
 module Text.Pandoc.App.Opt (
             Opt(..)
           , OptInfo(..)
+          , CompletionShell(..)
           , LineEnding (..)
           , IpynbOutput (..)
           , DefaultsState (..)
           , defaultOpts
           , applyDefaults
           , fullDefaultsPath
+          , CompletionKind(..)
+          , OptionSpec(..)
+          , toOptDescr
+          , option
           ) where
-import Control.Monad.Except (throwError)
+import System.Console.GetOpt (OptDescr (..), ArgDescr (..))
+import Control.Monad.Except (ExceptT, throwError)
 import Control.Monad.Trans (MonadIO, liftIO, lift)
 import Control.Monad ((>=>), foldM)
 import Control.Monad.State.Strict (StateT, modify, gets)
@@ -40,7 +46,7 @@
 import Text.Pandoc.Logging (Verbosity (WARNING), LogMessage(..))
 import Text.Pandoc.Options (TopLevelDivision (TopLevelDefault),
                             TrackChanges (AcceptChanges),
-                            WrapOption (WrapAuto), HTMLMathMethod (PlainMath),
+                            WrapOption (WrapAuto), MathMethod (MathML),
                             ReferenceLocation (EndOfDocument),
                             CaptionPosition (..),
                             ObfuscationMethod (NoObfuscation),
@@ -85,9 +91,58 @@
 $(deriveJSON
    defaultOptions{ fieldLabelModifier = map toLower . drop 11 } ''IpynbOutput)
 
+-- | The shell for which a completion script is requested.
+data CompletionShell = Bash | Zsh | Fish
+  deriving (Show, Generic)
+
+-- | What kind of value an option expects, and hence how it should be
+-- completed in zsh/fish/bash.
+data CompletionKind
+  = OptFlag          -- ^ a boolean flag, no value
+  | InputFormats     -- ^ an input (reader) format
+  | OutputFormats    -- ^ an output (writer) format
+  | HighlightStyles  -- ^ a highlighting style
+  | MathMethods      -- ^ an html math method
+  | DataFiles        -- ^ a pandoc data file
+  | Engines          -- ^ a PDF engine program
+  | Files            -- ^ a file path
+  | Fixed [String]   -- ^ one of a fixed set of values
+  deriving (Show)
+
+-- | The single source of truth for a command-line option: its short and
+-- long names, its argument parser, and the metadata needed to generate
+-- shell completions.  Everything else (option parsing, usage messages,
+-- and completion scripts) is derived from this one structure, so an
+-- option is declared in exactly one place.
+data OptionSpec = OptionSpec
+  { optShorts     :: [Char]
+  , optLongs      :: [String]
+  , optArgument   :: ArgDescr (Opt -> ExceptT OptInfo IO Opt)
+  , optCompletion :: CompletionKind
+  , optCompDesc   :: Text
+  }
+
+-- | Convert an 'OptionSpec' into the 'OptDescr' that GetOpt consumes.
+-- The GetOpt usage description is left empty (the help text is
+-- documented in the manual, not the --help summary).
+toOptDescr :: OptionSpec -> OptDescr (Opt -> ExceptT OptInfo IO Opt)
+toOptDescr (OptionSpec shorts longs arg _ _) =
+  Option shorts longs arg ""
+
+-- | Smart constructor for an 'OptionSpec'.  The completion kind and
+-- description are supplied alongside the rest of the option, so the
+-- single declaration fully describes both parsing and completion.
+option :: [Char]
+       -> [String]
+       -> ArgDescr (Opt -> ExceptT OptInfo IO Opt)
+       -> CompletionKind
+       -> Text
+       -> OptionSpec
+option = OptionSpec
+
 -- | Option parser results requesting informational output.
 data OptInfo =
-     BashCompletion
+     Completion CompletionShell
    | ListInputFormats
    | ListOutputFormats
    | ListExtensions (Maybe Text)
@@ -129,7 +184,7 @@
     , optSyntaxDefinitions     :: [FilePath]  -- ^ xml syntax defs to load
     , optSyntaxHighlighting    :: Text -- ^ Syntax highlighting method for code
     , optTopLevelDivision      :: TopLevelDivision -- ^ Type of the top-level divisions
-    , optHTMLMathMethod        :: HTMLMathMethod -- ^ Method to print HTML math
+    , optMathMethod            :: MathMethod -- ^ Method to print HTML math
     , optAbbreviations         :: Maybe FilePath -- ^ Path to abbrevs file
     , optReferenceDoc          :: Maybe FilePath -- ^ Path of reference doc
     , optSplitLevel            :: Int     -- ^ Header level at which to split documents in epub and chunkedhtml
@@ -216,7 +271,8 @@
        <*> o .:? "syntax-definitions" .!= optSyntaxDefinitions defaultOpts
        <*> o .:? "syntax-highlighting" .!= optSyntaxHighlighting defaultOpts
        <*> o .:? "top-level-division" .!= optTopLevelDivision defaultOpts
-       <*> o .:? "html-math-method" .!= optHTMLMathMethod defaultOpts
+       <*> ((o .: "math-method") <|> (o .: "html-math-method") <|>
+              pure (optMathMethod defaultOpts))
        <*> o .:? "abbreviations"
        <*> o .:? "reference-doc"
        <*> ((o .:? "split-level") <|> (o .:? "epub-chapter-level"))
@@ -587,8 +643,10 @@
       parseJSON v >>= \x -> return (\o -> o{ optSyntaxHighlighting = x })
     "top-level-division" ->
       parseJSON v >>= \x -> return (\o -> o{ optTopLevelDivision = x })
+    "math-method" ->
+      parseJSON v >>= \x -> return (\o -> o{ optMathMethod = x })
     "html-math-method" ->
-      parseJSON v >>= \x -> return (\o -> o{ optHTMLMathMethod = x })
+      parseJSON v >>= \x -> return (\o -> o{ optMathMethod = x })
     "abbreviations" ->
       parseJSON v >>= \x ->
              return (\o -> o{ optAbbreviations = unpack <$> x })
@@ -795,7 +853,7 @@
     , optSyntaxDefinitions     = []
     , optSyntaxHighlighting    = DefaultHighlightingString
     , optTopLevelDivision      = TopLevelDefault
-    , optHTMLMathMethod        = PlainMath
+    , optMathMethod            = MathML
     , optAbbreviations         = Nothing
     , optReferenceDoc          = Nothing
     , optSplitLevel            = 1
diff --git a/src/Text/Pandoc/App/OutputSettings.hs b/src/Text/Pandoc/App/OutputSettings.hs
--- a/src/Text/Pandoc/App/OutputSettings.hs
+++ b/src/Text/Pandoc/App/OutputSettings.hs
@@ -237,7 +237,7 @@
         , writerTableOfContents  = optTableOfContents opts
         , writerListOfFigures    = optListOfFigures opts
         , writerListOfTables     = optListOfTables opts
-        , writerHTMLMathMethod   = optHTMLMathMethod opts
+        , writerMathMethod       = optMathMethod opts
         , writerIncremental      = optIncremental opts
         , writerCiteMethod       = optCiteMethod opts
         , writerNumberSections   = optNumberSections opts
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -19,7 +19,7 @@
 -}
 module Text.Pandoc.Options ( module Text.Pandoc.Extensions
                            , ReaderOptions(..)
-                           , HTMLMathMethod (..)
+                           , MathMethod (..)
                            , CiteMethod (..)
                            , ObfuscationMethod (..)
                            , HighlightMethod (..)
@@ -108,17 +108,17 @@
 
 data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read, Data, Typeable, Generic)
 
-data HTMLMathMethod = PlainMath
-                    | WebTeX Text               -- url of TeX->image script.
-                    | GladTeX
-                    | MathML
-                    | MathJax Text              -- url of MathJax.js
-                    | KaTeX Text                -- url of KaTeX files
-                    deriving (Show, Read, Eq, Data, Typeable, Generic)
+data MathMethod = PlainMath
+                | WebTeX Text               -- url of TeX->image script.
+                | GladTeX
+                | MathML
+                | MathJax Text              -- url of MathJax.js
+                | KaTeX Text                -- url of KaTeX files
+                deriving (Show, Read, Eq, Data, Typeable, Generic)
 
-instance FromJSON HTMLMathMethod where
+instance FromJSON MathMethod where
    parseJSON node =
-     (withObject "HTMLMathMethod" $ \m -> do
+     (withObject "MathMethod" $ \m -> do
         method <- m .: "method"
         mburl <- m .:? "url"
         case method :: Text of
@@ -142,7 +142,7 @@
                _ -> fail $ "Unknown HTML math method " <>
                              toStringLazy (encode node))
 
-instance ToJSON HTMLMathMethod where
+instance ToJSON MathMethod where
   toJSON PlainMath = String "plain"
   toJSON (WebTeX "") = String "webtex"
   toJSON (WebTeX url) = object ["method" .= String "webtex",
@@ -359,7 +359,7 @@
   , writerListOfFigures     :: Bool   -- ^ Include list of figures
   , writerListOfTables      :: Bool   -- ^ Include list of tables
   , writerIncremental       :: Bool   -- ^ True if lists should be incremental
-  , writerHTMLMathMethod    :: HTMLMathMethod  -- ^ How to print math in HTML
+  , writerMathMethod        :: MathMethod  -- ^ How to print math in HTML
   , writerNumberSections    :: Bool   -- ^ Number sections in LaTeX
   , writerNumberOffset      :: [Int]  -- ^ Starting number for section, subsection, ...
   , writerSectionDivs       :: Bool   -- ^ Put sections in div tags in HTML
@@ -402,7 +402,7 @@
                       , writerListOfFigures    = False
                       , writerListOfTables     = False
                       , writerIncremental      = False
-                      , writerHTMLMathMethod   = PlainMath
+                      , writerMathMethod       = MathML
                       , writerNumberSections   = False
                       , writerNumberOffset     = [0,0,0,0,0,0]
                       , writerSectionDivs      = False
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -45,7 +45,7 @@
 import Text.Pandoc.Error (PandocError (PandocPDFProgramNotFoundError))
 import Text.Pandoc.SelfContained (makeSelfContained)
 import Text.Pandoc.MIME (getMimeType)
-import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..))
+import Text.Pandoc.Options (MathMethod (..), WriterOptions (..))
 import Text.Pandoc.Extensions (disableExtension, Extension(Ext_smart))
 import Text.Pandoc.Process (pipeProcess)
 import System.Process (readProcessWithExitCode)
@@ -189,7 +189,7 @@
                     -> Pandoc              -- ^ document
                     -> m (Either ByteString ByteString)
 makeWithWkhtmltopdf program pdfargs writer opts doc@(Pandoc meta _) = do
-  let mathArgs = case writerHTMLMathMethod opts of
+  let mathArgs = case writerMathMethod opts of
                  -- with MathJax, wait til all math is rendered:
                       MathJax _ -> ["--run-script", "MathJax.Hub.Register.StartupHook('End Typeset', function() { window.status = 'mathjax_loaded' });",
                                     "--window-status", "mathjax_loaded"]
diff --git a/src/Text/Pandoc/Parsing/Lists.hs b/src/Text/Pandoc/Parsing/Lists.hs
--- a/src/Text/Pandoc/Parsing/Lists.hs
+++ b/src/Text/Pandoc/Parsing/Lists.hs
@@ -112,12 +112,16 @@
 exampleNum :: (Stream s m Char, UpdateSourcePos s Char)
            => ParsecT s ParserState m (ListNumberStyle, Int)
 exampleNum = do
+  mbNum <- safeRead . T.pack <$> many digit
   char '@'
   lab <- T.pack . concat <$>
                     many (many1 alphaNum <|>
                           try (do c <- char '_' <|> char '-'
                                   cs <- many1 alphaNum
                                   return (c:cs)))
+  case mbNum of
+      Nothing -> pure ()
+      Just n -> updateState $ \s -> s{ stateNextExample = n }
   st <- getState
   case M.lookup lab (stateExamples st) of
     Nothing -> do -- new label
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -99,7 +99,6 @@
 import qualified Text.Pandoc.Class.PandocMonad as P
 import Text.Pandoc.Error
 import Text.Pandoc.Logging
-import Data.List.NonEmpty (nonEmpty)
 import Data.Aeson (eitherDecode)
 import qualified Data.Text.Lazy as TL
 import Text.Pandoc.UTF8 (fromTextLazy)
@@ -628,14 +627,20 @@
   return (fmap (Pandoc.Row nullAttr) cells)
 
 splitHeaderRows :: Bool -> [Docx.Row] -> ([Docx.Row], [Docx.Row])
-splitHeaderRows hasFirstRowFormatting rs = bimap reverse reverse $ fst
-  $ if hasFirstRowFormatting
-    then L.foldl' f ((take 1 rs, []), True) (drop 1 rs)
-    else L.foldl' f (([], []), False) rs
+splitHeaderRows hasFirstRowFormatting rs =
+  bimap reverse reverse $ fst $
+  if hasFirstRowFormatting
+     then L.foldl' f ((take 1 rs, []), True) (drop 1 rs)
+     else L.foldl' f (([], []), False) rs
   where
     f ((headerRows, bodyRows), previousRowWasHeader) r@(Docx.Row h cs)
       | h == HasTblHeader || (previousRowWasHeader && any isContinuationCell cs)
-        = ((r : headerRows, bodyRows), True)
+        = if null headerRows
+             -- in rare cases we have non-header rows before a header row.
+             -- in this case it's important to retain the order of rows,
+             -- so we promote the preceeding body rows to header rows:
+             then ((r : bodyRows, []), True)
+             else ((r : headerRows, bodyRows), True)
       | otherwise
         = ((headerRows, r : bodyRows), False)
 
@@ -834,22 +839,22 @@
       cap' = caption shortCaption fullCaption
       (hdr, rows) = splitHeaderRows (firstRowFormatting look) parts
 
-  let width = maybe 0 maximum $ nonEmpty $ map rowLength parts
-      rowLength :: Docx.Row -> Int
-      rowLength (Docx.Row _ c) = sum (fmap (\(Docx.Cell _ gridSpan _ _) -> fromIntegral gridSpan) c)
-
   headerCells <- rowsToRows hdr
   bodyCells <- rowsToRows rows
 
-      -- Horizontal column alignment is taken from the first row's cells.
-  let getAlignment (Docx.Cell al colspan _ _) = replicate (fromIntegral colspan)
-                   $ convertAlign al
-      alignments = case rows of
-                     [] -> replicate width Pandoc.AlignDefault
-                     Docx.Row _ cs : _ -> concatMap getAlignment cs
-      widths = map (\n -> if n == 0
+  let widths = map (\n -> if n == 0
                              then ColWidthDefault
                              else ColWidth n) grid
+      -- Horizontal column alignment is taken from the first row's cells.
+      numcols = length widths
+      getAlignment (Docx.Cell al colspan _ _) =
+        take numcols $ replicate (fromIntegral colspan) (convertAlign al) ++
+                       repeat Pandoc.AlignDefault
+      getAlignments (Docx.Row _ cs) = concatMap getAlignment cs
+      alignments = take numcols $
+                   case hdr ++ rows of
+                     [] -> repeat Pandoc.AlignDefault
+                     r : _ -> getAlignments r
 
   extStylesEnabled <- asks (isEnabled Ext_styles . docxOptions)
   let attr = case mbsty of
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -92,7 +92,7 @@
   result <- flip runReaderT def $
        runParserT parseDoc
        (HTMLState def{ stateOptions = opts }
-         [] Nothing Set.empty [] M.empty opts False)
+         [] Nothing Set.empty [] M.empty opts False False)
        "source" tags
   case result of
     Right doc -> return doc
@@ -222,7 +222,7 @@
         "h5" -> pHeader
         "h6" -> pHeader
         "blockquote" -> pBlockQuote
-        "pre" -> pCodeBlock
+        "pre" -> pCodeBlock <|> pPreBlock
         "ul" -> pBulletList
         "ol" -> pOrderedList
         "dl" -> pDefinitionList
@@ -646,6 +646,15 @@
                         (B.simpleCaption (mconcat captions))
                         (mconcat rest)
 
+pPreBlock :: PandocMonad m => TagParser m Blocks
+pPreBlock = try $ do
+  pSatisfy (matchTagOpen "pre" [])
+  oldInPre <- inPre <$> getState
+  updateState $ \st -> st{ inPre = True }
+  contents <- mconcat <$> manyTill block (pCloses "pre" <|> eof)
+  updateState $ \st -> st{ inPre = oldInPre }
+  return contents
+
 pCodeBlock :: PandocMonad m => TagParser m Blocks
 pCodeBlock = try $ do
   TagOpen _ attr' <- pSatisfy (matchTagOpen "pre" [])
@@ -1062,10 +1071,20 @@
   return $ B.str $ T.singleton c'
 
 pSpace :: PandocMonad m => InlinesParser m Inlines
-pSpace = many1 (satisfy isSpace) >>= \xs ->
-            if '\n' `elem` xs
-               then return B.softbreak
-               else return B.space
+pSpace = do
+  inpre <- inPre <$> getState
+  xs <- many1 (satisfy isSpace)
+  if inpre
+     then return $ makePreInlines xs
+     else if '\n' `elem` xs
+             then return B.softbreak
+             else return B.space
+ where
+  makePreInlines cs =
+    let chunks = splitWhen (=='\n') cs
+        tostr = B.str . T.pack . map (\c -> if c == ' ' then '\160' else c)
+    in  mconcat $ filter (/= B.str "")
+                $ L.intersperse B.linebreak (map tostr chunks)
 
 getTagName :: Tag Text -> Maybe Text
 getTagName (TagOpen t _) = Just t
diff --git a/src/Text/Pandoc/Readers/HTML/Types.hs b/src/Text/Pandoc/Readers/HTML/Types.hs
--- a/src/Text/Pandoc/Readers/HTML/Types.hs
+++ b/src/Text/Pandoc/Readers/HTML/Types.hs
@@ -53,6 +53,7 @@
   , macros      :: Map Text Macro
   , readerOpts  :: ReaderOptions
   , inFootnotes :: Bool
+  , inPre       :: Bool
   }
 
 -- | Local HTML parser state
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -21,7 +21,7 @@
 import Data.Char (isHexDigit, isSpace, toUpper, isAlphaNum, generalCategory,
                   GeneralCategory(OpenPunctuation, InitialQuote, FinalQuote,
                                   DashPunctuation, OtherSymbol))
-import Data.List (deleteFirstsBy, elemIndex, nub, partition, sort, transpose)
+import Data.List (deleteFirstsBy, elemIndex, partition, sort, transpose)
 import qualified Data.Map as M
 import Data.Maybe (fromMaybe, maybeToList, isJust, isNothing, catMaybes)
 import Data.Sequence (ViewR (..), viewr)
@@ -45,6 +45,7 @@
 import qualified Text.Pandoc.UTF8 as UTF8
 import Data.Time.Format
 import System.FilePath (takeDirectory)
+import Data.Containers.ListUtils (nubOrd)
 
 -- TODO:
 -- [ ] .. parsed-literal
@@ -1088,7 +1089,7 @@
           classFieldClasses = maybe [role] T.words (lookup "class" fields)
 
           -- nub in case role name & language class are the same
-          in nub (classFieldClasses ++ codeLanguageClass ++ oldClasses)
+          in nubOrd (classFieldClasses ++ codeLanguageClass ++ oldClasses)
 
         attr = let (ident, baseClasses, keyValues) = baseAttr
                in (ident, updateClasses baseClasses, keyValues)
diff --git a/src/Text/Pandoc/Readers/RTF.hs b/src/Text/Pandoc/Readers/RTF.hs
--- a/src/Text/Pandoc/Readers/RTF.hs
+++ b/src/Text/Pandoc/Readers/RTF.hs
@@ -67,8 +67,7 @@
                           , sCharSet     :: CharSet
                           , sGroupStack  :: [Properties]
                           , sListStack   :: [List]
-                          , sCurrentCell :: Blocks
-                          , sTableRows   :: [TableRow] -- reverse order
+                          , sTables      :: IntMap.IntMap TableState
                           , sTextContent :: [(Properties, Text)]
                           , sMetadata    :: [(Text, Inlines)]
                           , sFontTable   :: FontTable
@@ -90,8 +89,7 @@
                 , sCharSet = ANSI
                 , sGroupStack = []
                 , sListStack = []
-                , sCurrentCell = mempty
-                , sTableRows = []
+                , sTables = mempty
                 , sTextContent = []
                 , sMetadata = []
                 , sFontTable = mempty
@@ -170,6 +168,7 @@
   , gListOverride :: Maybe Override
   , gListLevel :: Maybe Int
   , gInTable :: Bool
+  , gTableLevel :: Int
   } deriving (Show, Eq)
 
 instance Default Properties where
@@ -192,6 +191,7 @@
                     , gListOverride = Nothing
                     , gListLevel = Nothing
                     , gInTable = False
+                    , gTableLevel = 0
                     }
 
 type RTFParser m = ParsecT Sources RTFState m
@@ -210,6 +210,17 @@
 newtype TableRow = TableRow [Blocks] -- cells in reverse order
     deriving (Show, Eq)
 
+data TableState = TableState
+  { tableCurrentCell :: Blocks
+  , tableRows :: [TableRow] -- reverse order, current row first
+  } deriving (Show, Eq)
+
+emptyTableState :: TableState
+emptyTableState = TableState
+  { tableCurrentCell = mempty
+  , tableRows = []
+  }
+
 parseRTF :: PandocMonad m => RTFParser m Pandoc
 parseRTF = do
   skipMany nl
@@ -462,6 +473,8 @@
         Tok _ (ControlWord "shppict" _) -> inGroup (foldM processTok bs toks)
         Tok _ (ControlWord "shpinst" _) -> inGroup (foldM processTok bs toks)
         Tok _ (ControlWord "pn" _) -> bs <$ handlePn toks
+        Tok _ (ControlWord "nesttableprops" _) ->
+          bs <$ inGroup (handleNestedTableProperties toks)
         _ -> bs <$ (do oldTextContent <- sTextContent <$> getState
                        processTok mempty (Tok pos (Grouped toks))
                        updateState $ \st -> st{ sTextContent = oldTextContent })
@@ -538,6 +551,9 @@
       return bs
     Grouped (Tok _ (ControlWord "info" _) : toks) ->
       bs <$ inGroup (processDestinationToks toks)
+    -- Fallback text for RTF readers which do not support nested tables.
+    -- Supporting readers must ignore this destination.
+    Grouped (Tok _ (ControlWord "nonesttables" _) : _) -> pure bs
     Grouped (Tok _ (ControlWord f _) : toks) | isMetadataField f -> inGroup $ do
       foldM_ processTok mempty toks
       annotatedToks <- reverse . sTextContent <$> getState
@@ -584,26 +600,33 @@
       modifyGroup (\g -> g{ gListOverride = mbp })
     ControlWord "ilvl" mbp -> bs <$
       modifyGroup (\g -> g{ gListLevel = mbp })
+    ControlWord "itap" (Just level) -> do
+      let level' = max 0 level
+      bs' <- emitBlocks bs
+      closed <- closeTablesAbove level'
+      modifyGroup (\g -> g{ gInTable = level' > 0
+                          , gTableLevel = level' })
+      pure $ bs' <> closed
     ControlSymbol '\\' -> bs <$ addText "\\"
     ControlSymbol '{' -> bs <$ addText "{"
     ControlSymbol '}' -> bs <$ addText "}"
     ControlSymbol '~' -> bs <$ addText "\x00a0"
     ControlSymbol '-' -> bs <$ addText "\x00ad"
     ControlSymbol '_' -> bs <$ addText "\x2011"
-    ControlWord "trowd" _ -> bs <$ beginTableRow -- begin new row
-    ControlWord "row" _ -> bs <$ beginTableRow -- end current row
-    ControlWord "cell" _ -> bs <$ do
-      new <- emitBlocks mempty
-      curCell <- (<> new) . sCurrentCell <$> getState
-      updateState $ \s -> s{ sTableRows =
-                                case sTableRows s of
-                                  TableRow cs : rs ->
-                                    TableRow (curCell : cs) : rs
-                                  [] -> [TableRow [curCell]] -- shouldn't happen
-                           , sCurrentCell = mempty }
+    ControlWord "trowd" _ -> bs <$ beginTableRow 1 -- begin top-level row
+    ControlWord "row" _ -> bs <$ beginTableRow 1 -- end top-level row
+    ControlWord "cell" _ -> bs <$ endTableCell 1
+    ControlWord "nestcell" _ -> bs <$ do
+      level <- getTableLevel 2
+      endTableCell level
+    ControlWord "nestrow" _ -> bs <$ do
+      level <- getTableLevel 2
+      beginTableRow level
     ControlWord "intbl" _ -> do
       ls <- closeLists 0 -- see #11364
-      ((ls <>) <$> emitBlocks bs) <* modifyGroup (\g -> g{ gInTable = True })
+      ((ls <>) <$> emitBlocks bs) <*
+        modifyGroup (\g -> g{ gInTable = True
+                            , gTableLevel = max 1 (gTableLevel g) })
     ControlWord "plain" _ -> bs <$ modifyGroup resetCharProps
     ControlWord "lquote" _ -> bs <$ addText "\x2018"
     ControlWord "rquote" _ -> bs <$ addText "\x2019"
@@ -719,37 +742,112 @@
           closeLists lvl
     _ -> pure mempty
 
--- Begin a new table row.  Both @\\trowd@ (which sets row defaults) and
--- @\\row@ (which ends a row) start a fresh row to be filled by subsequent
--- @\\cell@s.  We only push a new empty row when the current one already has
--- cells, so that documents repeating @\\trowd@ after @\\row@ (or omitting
--- @\\trowd@ between rows) both produce the same flat structure.
-beginTableRow :: PandocMonad m => RTFParser m ()
-beginTableRow =
+-- Return the current paragraph's table nesting level.  Nested-table control
+-- words should never occur without @\\itapN@, but the supplied default lets us
+-- handle malformed input without accidentally modifying the top-level table.
+getTableLevel :: PandocMonad m => Int -> RTFParser m Int
+getTableLevel fallback = do
+  groups <- sGroupStack <$> getState
+  pure $ case groups of
+    g : _ | gTableLevel g > 0 -> gTableLevel g
+    _ -> fallback
+
+modifyTable :: PandocMonad m
+            => Int
+            -> (TableState -> TableState)
+            -> RTFParser m ()
+modifyTable level f =
   updateState $ \s ->
-    s{ sTableRows = case sTableRows s of
-                      TableRow [] : _ -> sTableRows s
-                      rs -> TableRow [] : rs
-     , sCurrentCell = mempty }
+    s{ sTables = IntMap.alter
+          (Just . f . fromMaybe emptyTableState)
+          level
+          (sTables s) }
 
-closeTable :: PandocMonad m => RTFParser m Blocks
-closeTable = do
-  rawrows <- sTableRows <$> getState
-  if null rawrows
-     then return mempty
-     else do
-       let getCells (TableRow cs) = reverse cs
-       -- drop empty rows produced by row terminators
-       let rows = filter (not . null) . map getCells . reverse $ rawrows
-       updateState $ \s -> s{ sCurrentCell = mempty
-                            , sTableRows = [] }
-       if null rows
-          then return mempty
-          else return $ B.simpleTable [] rows
+appendToTableCell :: PandocMonad m => Int -> Blocks -> RTFParser m ()
+appendToTableCell level blocks =
+  modifyTable level $ \tbl ->
+    tbl{ tableCurrentCell = tableCurrentCell tbl <> blocks }
 
+-- Begin a new table row.  Both @\\trowd@ (which sets row defaults) and
+-- @\\row@/@\\nestrow@ (which end a row) start a fresh row to be filled by
+-- subsequent cells.  Only push a new empty row when the current one already
+-- has cells, so repeated row definitions do not create blank rows.
+beginTableRow :: PandocMonad m => Int -> RTFParser m ()
+beginTableRow level =
+  modifyTable level $ \tbl ->
+    tbl{ tableRows = case tableRows tbl of
+                       TableRow [] : _ -> tableRows tbl
+                       rs -> TableRow [] : rs
+       , tableCurrentCell = mempty }
+
+-- Close all tables deeper than the given level.  Each completed nested table
+-- becomes a block in the current cell of the nearest active enclosing level.
+-- Some real-world RTF jumps directly from (for example) @\\itap3@ to
+-- @\\itap5@, so the numeric predecessor is not necessarily the parent.
+closeTablesAbove :: PandocMonad m => Int -> RTFParser m Blocks
+closeTablesAbove target = do
+  tables <- sTables <$> getState
+  case IntMap.lookupMax tables of
+    Just (level, _) | level > target -> do
+      mbTable <- closeTable level
+      remaining <- sTables <$> getState
+      let mbParent =
+            case IntMap.lookupMax remaining of
+              Just (parent, _) | parent >= target -> Just parent
+              _ | target > 0 -> Just target
+                | otherwise -> Nothing
+      here <- case mbTable of
+        Nothing -> pure mempty
+        Just table -> case mbParent of
+          Just parent -> mempty <$ appendToTableCell parent table
+          Nothing -> pure table
+      rest <- closeTablesAbove target
+      pure $ here <> rest
+    _ -> pure mempty
+
+closeTable :: PandocMonad m => Int -> RTFParser m (Maybe Blocks)
+closeTable level = do
+  mbTable <- IntMap.lookup level . sTables <$> getState
+  updateState $ \s -> s{ sTables = IntMap.delete level (sTables s) }
+  case mbTable of
+    Nothing -> pure Nothing
+    Just tbl -> do
+      let getCells (TableRow cs) = reverse cs
+      -- Drop empty rows produced by row terminators.
+      let rows = filter (not . null) . map getCells . reverse $
+                   tableRows tbl
+      pure $ if null rows
+                then Nothing
+                else Just $ B.simpleTable [] rows
+
+endTableCell :: PandocMonad m => Int -> RTFParser m ()
+endTableCell level = do
+  -- Flush pending paragraph text first.  emitBlocks appends it to the table
+  -- level recorded on the paragraph properties.
+  void $ emitBlocks mempty
+  -- A parent cell may end immediately after a nested row, without another
+  -- explicit @\\itap@ transition back to the parent.
+  void $ closeTablesAbove level
+  modifyTable level $ \tbl ->
+    let cell = tableCurrentCell tbl
+    in tbl{ tableRows =
+              case tableRows tbl of
+                TableRow cells : rows -> TableRow (cell : cells) : rows
+                [] -> [TableRow [cell]]
+          , tableCurrentCell = mempty }
+
+handleNestedTableProperties :: PandocMonad m => [Tok] -> RTFParser m ()
+handleNestedTableProperties toks =
+  when (any isNestedRowEnd toks) $ do
+    level <- getTableLevel 2
+    beginTableRow level
+ where
+  isNestedRowEnd (Tok _ (ControlWord "nestrow" _)) = True
+  isNestedRowEnd _ = False
+
 closeContainers :: PandocMonad m => RTFParser m Blocks
 closeContainers = do
-  tbl <- closeTable
+  tbl <- closeTablesAbove 0
   lists <- closeLists 0
   return $ tbl <> lists
 
@@ -773,7 +871,7 @@
                ((p,_):_) -> p
   tbl <- if gInTable prop || null annotatedToks
             then pure mempty
-            else closeTable
+            else closeTablesAbove 0
   new <-
     case annotatedToks of
       [] -> pure mempty
@@ -838,7 +936,7 @@
                 $ map addFormatting annotatedToks)
   if gInTable prop
      then do
-       updateState $ \s -> s{ sCurrentCell = sCurrentCell s <> new }
+       appendToTableCell (max 1 $ gTableLevel prop) new
        pure bs
      else do
        pure $ bs <> tbl <> new
diff --git a/src/Text/Pandoc/Readers/Typst.hs b/src/Text/Pandoc/Readers/Typst.hs
--- a/src/Text/Pandoc/Readers/Typst.hs
+++ b/src/Text/Pandoc/Readers/Typst.hs
@@ -575,9 +575,6 @@
       (if display then B.displayMath else B.math) . writeTeX <$> pMathMany body)
   ,("pad", \_ _ fields ->  -- ignore paddingy
       getField "body" fields >>= pWithContents pInlines)
-  ,("block", \_ mbident fields ->
-      maybe id (\ident -> B.spanWith (ident, [], [])) mbident
-        <$> (getField "body" fields >>= pWithContents pInlines))
   ,("rotate", \_ _ fields -> do
       body <- getField "body" fields >>= pWithContents pInlines
       let kvs = case M.lookup "angle" fields of
diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs
--- a/src/Text/Pandoc/Templates.hs
+++ b/src/Text/Pandoc/Templates.hs
@@ -47,7 +47,7 @@
                                       getCommonState, modifyCommonState,
                                       toTextM)
 import Text.Pandoc.Data (readDataFile)
-import Control.Monad.Except (catchError, throwError)
+import Control.Monad.Except (throwError, tryError)
 import Data.Text (Text)
 import qualified Data.Text as T
 import Text.Pandoc.Error
@@ -74,24 +74,22 @@
 -- | Retrieve text for a template.
 getTemplate :: PandocMonad m => FilePath -> m Text
 getTemplate tp =
-  ((do surl <- stSourceURL <$> getCommonState
+   (do surl <- stSourceURL <$> getCommonState
        -- we don't want to look for templates remotely
        -- unless the full URL is specified:
-       modifyCommonState $ \st -> st{
-         stSourceURL = Nothing }
-       (bs, _) <- fetchItem $ T.pack tp
-       modifyCommonState $ \st -> st{
-         stSourceURL = surl }
-       return bs)
-   `catchError`
-   (\e -> case e of
+       modifyCommonState $ \st -> st{ stSourceURL = Nothing }
+       res <- tryError $ fetchItem $ T.pack tp
+       modifyCommonState $ \st -> st{ stSourceURL = surl }
+       case res of
+         Right (bs, _) -> return bs
+         Left e -> case e of
              PandocResourceNotFound _ ->
                 -- see #5987 on reason for takeFileName
                 readDataFile ("templates" </> takeFileName tp)
              PandocIOError _ ioe | isDoesNotExistError ioe ->
                 -- see #5987 on reason for takeFileName
                 readDataFile ("templates" </> takeFileName tp)
-             _ -> throwError e)) >>= toTextM tp
+             _ -> throwError e) >>= toTextM tp
 
 -- | Get default template for the specified writer.
 getDefaultTemplate :: PandocMonad m
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -29,7 +29,8 @@
 import Text.Pandoc.Class.PandocMonad (PandocMonad, report, toLang)
 import Text.Pandoc.Definition
 import Text.Pandoc.Highlighting
-  (formatConTeXtBlock, formatConTeXtInline, highlight, styleToConTeXt)
+  (formatConTeXtBlock, formatConTeXtInline, highlight, styleToConTeXt,
+   defaultStyle)
 import Text.Pandoc.ImageSize
 import Text.Pandoc.Logging
 import Text.Pandoc.Options
@@ -134,6 +135,9 @@
                 $ (case writerHighlightMethod options of
                       Skylighting sty | stHighlighting st ->
                         defField "highlighting-commands" (styleToConTeXt sty)
+                      DefaultHighlighting | stHighlighting st ->
+                        defField "highlighting-commands"
+                          (styleToConTeXt defaultStyle)
                       _ -> id)
                 $ (case T.toLower $ lookupMetaString "pdfa" meta of
                         "true" -> resetField "pdfa" (T.pack "1b:2005")
@@ -234,8 +238,9 @@
   -- blankline because \stoptyping can't have anything after it, inc. '}'
   ($$ blankline) . flush <$>
     case writerHighlightMethod opts of
-      Skylighting _ | not (null classes) -> pure unhighlighted
-      _ -> highlighted
+      Skylighting _ | not (null classes) -> highlighted
+      DefaultHighlighting | not (null classes) -> highlighted
+      _ -> pure unhighlighted
 blockToConTeXt b@(RawBlock f str)
   | f == Format "context" || f == Format "tex" = return $ literal str <> blankline
   | otherwise = empty <$ report (BlockNotRendered b)
@@ -627,6 +632,7 @@
             return (text (T.unpack h))
   case writerHighlightMethod opts of
     Skylighting _ | not (null classes) -> highlightCode
+    DefaultHighlighting | not (null classes) -> highlightCode
     _ -> rawCode
 inlineToConTeXt (Quoted SingleQuote lst) = do
   contents <- inlineListToConTeXt lst
diff --git a/src/Text/Pandoc/Writers/DocBook.hs b/src/Text/Pandoc/Writers/DocBook.hs
--- a/src/Text/Pandoc/Writers/DocBook.hs
+++ b/src/Text/Pandoc/Writers/DocBook.hs
@@ -113,7 +113,7 @@
                  meta'
   main <- fromBlocks blocks
   let context = defField "body" main
-              $ defField "mathml" (case writerHTMLMathMethod opts of
+              $ defField "mathml" (case writerMathMethod opts of
                                           MathML -> True
                                           _      -> False) metadata
   return $ render colwidth $
@@ -401,7 +401,7 @@
 inlineToDocBook _ (Code _ str) =
   return $ inTagsSimple "literal" $ literal (escapeStringForXML str)
 inlineToDocBook opts (Math t str)
-  | isMathML (writerHTMLMathMethod opts) = do
+  | isMathML (writerMathMethod opts) = do
     res <- convertMath writeMathML t str
     case res of
          Right r  -> return $ inTagsSimple tagtype
@@ -465,7 +465,7 @@
 inlineToDocBook opts (Note contents) =
   inTagsIndented "footnote" <$> blocksToDocBook opts contents
 
-isMathML :: HTMLMathMethod -> Bool
+isMathML :: MathMethod -> Bool
 isMathML MathML = True
 isMathML _      = False
 
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -98,6 +98,7 @@
 
   let env = defaultWriterEnv {
           envRTL = isRTLmeta
+        , envLang = getLang opts meta
         , envChangesAuthor = fromMaybe "unknown" username
         , envChangesDate   = T.pack $ formatTime defaultTimeLocale "%FT%XZ" utctime
         , envPrintWidth = maybe 420 (`quot` 20) pgContentWidth
diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -48,7 +48,7 @@
 import Text.Pandoc.Logging
 import Text.Pandoc.MIME (MimeType, extensionFromMimeType, getMimeType)
 import Text.Pandoc.URI (urlEncode)
-import Text.Pandoc.Options (EPUBVersion (..), HTMLMathMethod (..),
+import Text.Pandoc.Options (EPUBVersion (..), MathMethod (..),
                             ObfuscationMethod (NoObfuscation), WrapOption (..),
                             WriterOptions (..))
 import Text.Pandoc.Shared (normalizeDate, renderTags',
@@ -1233,7 +1233,7 @@
     newsrc <- modifyMediaRef $ T.unpack src
     return $ Image attr lab ("../" <> newsrc, tit)
 transformInline _ opts x@(Math t m)
-  | WebTeX url <- writerHTMLMathMethod opts = do
+  | WebTeX url <- writerMathMethod opts = do
     newsrc <- modifyMediaRef (T.unpack (url <> urlEncode m))
     let mathclass = if t == DisplayMath then "display" else "inline"
     return $ Span ("",["math",mathclass],[])
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -36,7 +36,7 @@
 import Text.Pandoc.Definition
 import Text.Pandoc.Error (PandocError(..))
 import Text.Pandoc.Logging
-import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
+import Text.Pandoc.Options (MathMethod (..), WriterOptions (..), def)
 import Text.Pandoc.Shared (blocksToInlines, capitalize, orderedListMarkers,
                            makeSections, tshow, stringify)
 import Text.Pandoc.Walk (walk)
@@ -454,7 +454,7 @@
 
 insertMath :: PandocMonad m => ImageMode -> Text -> FBM m [Content]
 insertMath immode formula = do
-  htmlMath <- fmap (writerHTMLMathMethod . writerOptions) get
+  htmlMath <- fmap (writerMathMethod . writerOptions) get
   case htmlMath of
     WebTeX url -> do
        let alt = [Code nullAttr formula]
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -314,7 +314,7 @@
   st <- get
   let html5 = stHtml5 st
   let thebody = blocks' >> notes
-  let math = layoutMarkup $ case writerHTMLMathMethod opts of
+  let math = layoutMarkup $ case writerMathMethod opts of
         MathJax url
           | slideVariant /= RevealJsSlides ->
           -- mathjax is handled via a special plugin in revealjs
@@ -379,12 +379,12 @@
                       then defField "math" math
                       else id) .
                   defField "abstract-title" abstractTitle .
-                  (case writerHTMLMathMethod opts of
+                  (case writerMathMethod opts of
                         MathJax u -> defField "mathjax" True .
                                      defField "mathjaxurl"
                                        (literal $ T.takeWhile (/='?') u)
                         _         -> defField "mathjax" False) .
-                  (case writerHTMLMathMethod opts of
+                  (case writerMathMethod opts of
                         PlainMath -> defField "displaymath-css" True
                         WebTeX _  -> defField "displaymath-css" True
                         _         -> id) .
@@ -938,7 +938,7 @@
   if ishtml
      then return $ preEscapedText str
      else if (f == Format "latex" || f == Format "tex") &&
-             allowsMathEnvironments (writerHTMLMathMethod opts) &&
+             allowsMathEnvironments (writerMathMethod opts) &&
              isMathEnvironment str
              then do
                modify (\st -> st {stMath = True})
@@ -1520,7 +1520,7 @@
       modify (\st -> st {stMath = True})
       let mathClass = toValue $ ("math " :: Text) <>
                       if t == InlineMath then "inline" else "display"
-      case writerHTMLMathMethod opts of
+      case writerMathMethod opts of
            WebTeX url -> do
               let imtag = if html5 then H5.img else H.img
               let str' = T.strip str
@@ -1565,7 +1565,7 @@
          then return $ preEscapedText str
          else do
            let istex = f == Format "latex" || f == Format "tex"
-           let mm = writerHTMLMathMethod opts
+           let mm = writerMathMethod opts
            case istex of
              True
                | allowsMathEnvironments mm && isMathEnvironment str
@@ -1773,14 +1773,14 @@
                      , "Vmatrix"
                      , "vmatrix" ]
 
-allowsMathEnvironments :: HTMLMathMethod -> Bool
+allowsMathEnvironments :: MathMethod -> Bool
 allowsMathEnvironments (MathJax _) = True
 allowsMathEnvironments (KaTeX _)   = True
 allowsMathEnvironments MathML      = True
 allowsMathEnvironments (WebTeX _)  = True
 allowsMathEnvironments _           = False
 
-allowsRef :: HTMLMathMethod -> Bool
+allowsRef :: MathMethod -> Bool
 allowsRef (MathJax _) = True
 allowsRef _           = False
 
diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs
--- a/src/Text/Pandoc/Writers/JATS.hs
+++ b/src/Text/Pandoc/Writers/JATS.hs
@@ -210,7 +210,7 @@
               $ addCreditNames
               $ resetField "title" title'
               $ resetField "date" date
-              $ defField "mathml" (case writerHTMLMathMethod opts of
+              $ defField "mathml" (case writerMathMethod opts of
                                         MathML -> True
                                         _      -> False) metadata
   return $ render colwidth $
@@ -366,12 +366,13 @@
                      [(k,v) | (k,v) <- kvs, k `elem` ["specific-use",
                                                       "content-type"]]
   let boxed_attr = [(k,v) | (k,v) <- kvs, k `elem` ["orientation", "position"]]
-  let attr = generic_attr <> boxed_attr
+  let isPlain Plain{} = True
+      isPlain _ = False
   return $
-    if null attr
+    if null generic_attr && null boxed_attr
     then contents
     else -- The contents must be wrapped in an appropriate element.
-      let element = if null boxed_attr
+      let element = if null boxed_attr && all isPlain bs
                     then "p"
                     else "boxed-text"
       in inTags True element (generic_attr <> boxed_attr) contents
diff --git a/src/Text/Pandoc/Writers/Markdown/Inline.hs b/src/Text/Pandoc/Writers/Markdown/Inline.hs
--- a/src/Text/Pandoc/Writers/Markdown/Inline.hs
+++ b/src/Text/Pandoc/Writers/Markdown/Inline.hs
@@ -510,7 +510,7 @@
   variant <- asks envVariant
   case () of
     _ | variant == Markua -> return $ "`" <> literal str <> "`" <> "$"
-      | otherwise -> case writerHTMLMathMethod opts of
+      | otherwise -> case writerMathMethod opts of
           WebTeX url ->
              inlineToMarkdown opts
                   (Image nullAttr [Str str'] (url <> urlEncode str', str'))
@@ -535,7 +535,7 @@
                                                         ("format", "latex"))
         return $ blankline <> attributes <> cr <> literal "```" <> cr
             <> literal str <> cr <> literal "```" <> blankline
-      | otherwise -> case writerHTMLMathMethod opts of
+      | otherwise -> case writerMathMethod opts of
           WebTeX url ->
             let str' = T.strip str
              in (\x -> blankline <> x <> blankline) `fmap`
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -458,7 +458,10 @@
     if inDefLabel
        then T.intercalate "<nowiki>:</nowiki>" $
               map escapeText $ T.splitOn ":" str
-       else escapeText str
+       else
+          (if "://" `T.isInfixOf` str -- see #11834
+              then inNowiki
+              else id) $ escapeText str
 
 inlineToMediaWiki (Math mt str) = return $ literal $
   "<math display=\"" <>
@@ -1169,3 +1172,6 @@
   case T.uncons t of
     Nothing -> False
     Just (c,_) -> c == '#' || c == ':' || c == ';' || c == '*'
+
+inNowiki :: Text -> Text
+inNowiki t = "<nowiki>" <> t <> "</nowiki>"
diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs
--- a/src/Text/Pandoc/Writers/Ms.hs
+++ b/src/Text/Pandoc/Writers/Ms.hs
@@ -78,6 +78,8 @@
   let highlightingMacros = if hasHighlighting
                               then case writerHighlightMethod opts of
                                      Skylighting sty -> styleToMs sty
+                                     DefaultHighlighting ->
+                                       styleToMs defaultStyle
                                      _ -> mempty
                               else mempty
 
@@ -647,10 +649,17 @@
 
 highlightCode :: PandocMonad m => WriterOptions -> Attr -> Text -> MS m (Doc Text)
 highlightCode opts attr str =
-  case highlight (writerSyntaxMap opts) (msFormatter opts) attr str of
+  case writerHighlightMethod opts of
+    Skylighting _ -> highlighted
+    DefaultHighlighting -> highlighted
+    _ -> unhighlighted
+ where
+  unhighlighted = return $ literal (escapeStr opts str)
+  highlighted =
+    case highlight (writerSyntaxMap opts) (msFormatter opts) attr str of
          Left msg -> do
            unless (T.null msg) $ report $ CouldNotHighlight msg
-           return $ literal (escapeStr opts str)
+           unhighlighted
          Right h -> do
            modify (\st -> st{ stHighlighting = True })
            return h
diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs
--- a/src/Text/Pandoc/Writers/ODT.hs
+++ b/src/Text/Pandoc/Writers/ODT.hs
@@ -35,7 +35,8 @@
 import Text.Pandoc.Logging
 import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
 import Text.Pandoc.Options (WrapOption (..), WriterOptions (..),
-                            HighlightMethod(Skylighting))
+                            HighlightMethod(Skylighting, DefaultHighlighting))
+import Text.Pandoc.Highlighting (defaultStyle)
 import Text.DocLayout
 import Text.Pandoc.Shared (stringify, tshow)
 import Text.Pandoc.Version (pandocVersionText)
@@ -216,6 +217,7 @@
                      (addListItemStyles .
                       (case writerHighlightMethod opts of
                         Skylighting style -> addHlStyles style
+                        DefaultHighlighting -> addHlStyles defaultStyle
                         _ -> id))
                 $ d )
         | otherwise = pure e
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -17,7 +17,7 @@
 import Control.Arrow ((***), (>>>))
 import Control.Monad (unless, liftM)
 import Control.Monad.State.Strict ( StateT(..), modify, gets, lift )
-import Data.Char (chr)
+import Data.Char (chr, isDigit)
 import Data.Foldable (find)
 import Data.List (sortOn, sortBy)
 import qualified Data.List as L
@@ -85,6 +85,9 @@
   | TableRef
   | FigureRef
 
+data Direction = LTR | RTL
+  deriving (Show, Eq, Ord)
+
 data WriterState =
     WriterState { stNotes          :: [Doc Text]
                 , stTableStyles    :: [Doc Text]
@@ -102,6 +105,11 @@
                 , stTableCaptionId :: Int
                 , stImageCaptionId :: Int
                 , stIdentTypes     :: [(Text,ReferenceType)]
+                , stDirection      :: Maybe Direction
+                  -- ^ active writing mode
+                , stDirStyles      :: Map.Map (Text, Direction) Text
+                  -- ^ cache of direction-adjusted paragraph styles,
+                  -- keyed on (parent style, writing mode)
                 }
 
 defaultWriterState :: WriterState
@@ -120,6 +128,8 @@
                 , stTableCaptionId = 1
                 , stImageCaptionId = 1
                 , stIdentTypes     = []
+                , stDirection      = Nothing
+                , stDirStyles      = Map.empty
                 }
 
 when :: Bool -> Doc Text -> Doc Text
@@ -154,11 +164,12 @@
 inParagraphTags :: PandocMonad m => Doc Text -> OD m (Doc Text)
 inParagraphTags d = do
   b <- gets stFirstPara
-  a <- if b
-       then do modify $ \st -> st { stFirstPara = False }
-               return [("text:style-name", "First_20_paragraph")]
-       else    return   [("text:style-name", "Text_20_body")]
-  return $ inTags False "text:p" a d
+  sty <- if b
+         then do modify $ \st -> st { stFirstPara = False }
+                 return "First_20_paragraph"
+         else    return "Text_20_body"
+  sty' <- dirStyleFor sty
+  return $ inTags False "text:p" [("text:style-name", sty')] d
 
 inParagraphTagsWithStyle :: Text -> Doc Text -> Doc Text
 inParagraphTagsWithStyle sty = inTags False "text:p" [("text:style-name", sty)]
@@ -178,6 +189,22 @@
 withTextStyle :: PandocMonad m => TextStyle -> OD m a -> OD m a
 withTextStyle s = withAlteredTextStyles (Set.insert s)
 
+withDirection :: PandocMonad m => Maybe Direction -> OD m a -> OD m a
+withDirection mbdir action = do
+  olddir <- gets stDirection
+  modify $ \st -> st{ stDirection = mbdir }
+  res <- action
+  modify $ \st -> st{ stDirection = olddir }
+  return res
+
+-- | Apply the writing direction from a @dir@ attribute, if present.
+withDirFromAttr :: PandocMonad m => Attr -> OD m a -> OD m a
+withDirFromAttr (_,_,kvs) action =
+  case lookup "dir" kvs of
+    Just "rtl" -> withDirection (Just RTL) action
+    Just "ltr" -> withDirection (Just LTR) action
+    _          -> action
+
 inTextStyle :: PandocMonad m => Doc Text -> OD m (Doc Text)
 inTextStyle d = do
   at <- gets stTextStyleAttr
@@ -232,8 +259,9 @@
   selfClosingTag "text:bookmark" [("text:name", ident)]
 
 inHeaderTags :: PandocMonad m => Int -> Text -> Doc Text -> OD m (Doc Text)
-inHeaderTags i ident d =
-  return $ inTags False "text:h" [ ("text:style-name", "Heading_20_" <> tshow i)
+inHeaderTags i ident d = do
+  sty <- dirStyleFor ("Heading_20_" <> tshow i)
+  return $ inTags False "text:h" [ ("text:style-name", sty)
                                  , ("text:outline-level", tshow i)]
          $ if T.null ident
               then d
@@ -270,8 +298,17 @@
                         (B.divWith ("",[],[("custom-style","Abstract")])
                           (B.fromList xs))
                         meta
+  -- Set the default writing direction from the "dir" metadata field;
+  -- in its absence, a right-to-left main language implies RTL.
+  let mbDir = case lookupMetaString "dir" meta of
+                "rtl" -> Just RTL
+                "ltr" -> Nothing
+                _     -> case getLang opts meta of
+                           Just l | Right lang <- parseLang l
+                                  , isRTLLang lang -> Just RTL
+                           _ -> Nothing
   ((body, metadata),s) <- flip runStateT
-        defaultWriterState $ do
+        defaultWriterState{ stDirection = mbDir } $ do
            let collectBlockIdent (Header _ (ident,_,_) _)      = [(ident,HeaderRef)]
                collectBlockIdent (Figure (ident,_,_) _ _ )     = [(ident,FigureRef)]
                collectBlockIdent (Table (ident,_,_) _ _ _ _ _) = [(ident,TableRef)]
@@ -300,15 +337,19 @@
 
 withParagraphStyle :: PandocMonad m
                    => WriterOptions -> Text -> [Block] -> OD m (Doc Text)
-withParagraphStyle  o s (b:bs)
-    | Para l <- b = go =<< inParagraphTagsWithStyle s <$> inlinesToOpenDocument o l
-    | otherwise   = go =<< blockToOpenDocument o b
-    where go i = (<>) i <$>  withParagraphStyle o s bs
-withParagraphStyle _ _ [] = return empty
+withParagraphStyle o s bs = do
+  s' <- dirStyleFor s
+  let go (b:bs')
+        | Para l <- b = cont bs' =<<
+            inParagraphTagsWithStyle s' <$> inlinesToOpenDocument o l
+        | otherwise   = cont bs' =<< blockToOpenDocument o b
+      go [] = return empty
+      cont bs' i = (<>) i <$> go bs'
+  go bs
 
-inPreformattedTags :: PandocMonad m => [Doc Text] -> OD m (Doc Text)
+inPreformattedTags :: [Doc Text] -> Doc Text
 inPreformattedTags s =
-  return $ inParagraphTagsWithStyle "Preformatted_20_Text" $ hcat s
+  inParagraphTagsWithStyle "Preformatted_20_Text" $ hcat s
 
 -- | Get the list-style name to use for an ordered list with the given
 -- numbering style and delimiter, registering an override automatic style
@@ -372,8 +413,9 @@
                           -> OD m (Doc Text)
 orderedItemToOpenDocument  o paraName bs = vcat <$> mapM go bs
  where go (OrderedList a l) = orderedList a l
-       go (Para          l) = inParagraphTagsWithStyle paraName <$>
-                                inlinesToOpenDocument o l
+       go (Para          l) = do
+         sty <- dirStyleFor paraName
+         inParagraphTagsWithStyle sty <$> inlinesToOpenDocument o l
        go b                 = blockToOpenDocument o b
        orderedList a@(_,ns,nd) l = do
          lstName <- orderedListStyleName ns nd
@@ -458,15 +500,17 @@
     OrderedList  a b -> setFirstPara >> orderedList a b
     CodeBlock attrs s -> do
       setFirstPara
-      case writerHighlightMethod o of
-        Skylighting {} ->
-          case highlight (writerSyntaxMap o) formatOpenDocument attrs s of
+      let highlighted =
+            case highlight (writerSyntaxMap o) formatOpenDocument attrs s of
                 Right h  -> return $ flush . vcat $ map (inTags True "text:p"
                                           [("text:style-name",
                                             "Preformatted_20_Text")] . hcat) h
                 Left msg -> do
                   unless (T.null msg) $ report $ CouldNotHighlight msg
                   unhighlighted s
+      case writerHighlightMethod o of
+        Skylighting {} -> highlighted
+        DefaultHighlighting -> highlighted
         _ -> unhighlighted s
     Table a bc s th tb tf -> setFirstPara >>
                               table o (Ann.toTable a bc s th tb tf)
@@ -481,11 +525,11 @@
                            r <- vcat  <$> mapM (deflistItemToOpenDocument o) b
                            setInDefinitionList False
                            return r
-      unhighlighted s = flush . vcat <$>
-            (mapM ((inPreformattedTags . (:[])) . preformatted) (T.lines s))
+      unhighlighted s = pure $ flush . vcat $
+            (map ((inPreformattedTags . (:[])) . preformatted) (T.lines s))
       mkDiv    attr s = do
         let (ident,_,kvs) = attr
-            i = withLangFromAttr attr $
+            i = withDirFromAttr attr $ withLangFromAttr attr $
                 case lookup "custom-style" kvs of
                   Just sty -> withParagraphStyle o sty s
                   _        -> blocksToOpenDocument o s
@@ -562,14 +606,16 @@
     id' <- gets stTableCaptionId
     modify (\st -> st{ stTableCaptionId = id' + 1 })
     capterm <- translateTerm Term.Table
-    return $ numberedCaption "TableCaption" capterm "Table" id' ident caption
+    sty <- dirStyleFor "TableCaption"
+    return $ numberedCaption sty capterm "Table" id' ident caption
 
 numberedFigureCaption :: PandocMonad m => Text -> Doc Text -> OD m (Doc Text)
 numberedFigureCaption ident caption = do
     id' <- gets stImageCaptionId
     modify (\st -> st{ stImageCaptionId = id' + 1 })
     capterm <- translateTerm Term.Figure
-    return $ numberedCaption "FigureCaption" capterm  "Illustration" id' ident caption
+    sty <- dirStyleFor "FigureCaption"
+    return $ numberedCaption sty capterm  "Illustration" id' ident caption
 
 numberedCaption :: Text -> Text -> Text -> Int -> Text -> Doc Text -> Doc Text
 numberedCaption style term name num ident caption =
@@ -585,8 +631,10 @@
         c = text ": "
     in inParagraphTagsWithStyle style $ hcat [ t, text " ", s, c, caption ]
 
-unNumberedCaption :: Monad m => Text -> Doc Text -> OD m (Doc Text)
-unNumberedCaption style caption = return $ inParagraphTagsWithStyle style caption
+unNumberedCaption :: PandocMonad m => Text -> Doc Text -> OD m (Doc Text)
+unNumberedCaption style caption = do
+  sty <- dirStyleFor style
+  return $ inParagraphTagsWithStyle sty caption
 
 colHeadsToOpenDocument :: PandocMonad m
                        => WriterOptions -> [Text] -> Ann.TableHead
@@ -713,14 +761,17 @@
     Subscript   l -> withTextStyle Sub    $ inlinesToOpenDocument o l
     SmallCaps   l -> withTextStyle SmallC $ inlinesToOpenDocument o l
     Quoted    t l -> inQuotes t <$> inlinesToOpenDocument o l
-    Code      attrs s -> case writerHighlightMethod o of
-      Skylighting {} ->
-        case highlight (writerSyntaxMap o) formatOpenDocument attrs s of
+    Code      attrs s ->
+      let highlighted =
+            case highlight (writerSyntaxMap o) formatOpenDocument attrs s of
                 Right h  -> inlinedCode $ mconcat $ mconcat h
                 Left msg -> do
                   unless (T.null msg) $ report $ CouldNotHighlight msg
                   unhighlighted s
-      _ -> unhighlighted s
+      in case writerHighlightMethod o of
+           Skylighting {} -> highlighted
+           DefaultHighlighting -> highlighted
+           _ -> unhighlighted s
     Math      t s -> lift (texMathToInlines t s) >>=
                          inlinesToOpenDocument o
     Cite      _ l -> inlinesToOpenDocument o l
@@ -880,6 +931,7 @@
   i  <- (*) (0.5 :: Double) . fromIntegral <$> gets stIndentPara
   b  <- gets stInDefinition
   t  <- gets stTight
+  dirAttrs <- getDirAttrs
   let indentVal = flip (<>) "in" . tshow $ if b then max 0.5 i else i
       tight     = if t then [ ("fo:margin-top"          , "0in"    )
                             , ("fo:margin-bottom"       , "0in"    )]
@@ -890,7 +942,7 @@
                            , ("fo:text-indent"         , "0in"    )
                            , ("style:auto-text-indent" , "false"  )]
                       else []
-      attributes = indent <> tight
+      attributes = indent <> tight <> dirAttrs
   case (attributes, attrs) of
     ([], [("style:parent-style-name", parent)]) -> return parent
     _ -> do
@@ -906,18 +958,59 @@
       return name
 
 paraStyleFromParent :: PandocMonad m => Text -> [(Text,Text)] -> OD m Text
-paraStyleFromParent parent attrs
-  | null attrs = return parent
-  | otherwise  = do
+paraStyleFromParent parent attrs = do
+  dirAttrs <- getDirAttrs
+  let attrs' = attrs <> dirAttrs
+  if null attrs'
+     then return parent
+     else do
       pn <- (+) 1 . length <$> gets stParaStyles
       let name      = "P" <> tshow pn
           styleAttr = [ ("style:name"             , name)
                       , ("style:family"           , "paragraph")
                       , ("style:parent-style-name", parent)]
-          paraProps = selfClosingTag "style:paragraph-properties" attrs
+          paraProps = selfClosingTag "style:paragraph-properties" attrs'
       addParaStyle $ inTags True "style:style" styleAttr paraProps
       return name
 
+getDirAttrs :: PandocMonad m => OD m [(Text, Text)]
+getDirAttrs = do
+  wm <- gets stDirection
+  pure $
+    case wm of
+      Nothing -> []
+      Just RTL -> [("style:writing-mode", "rl-tb"),
+                        ("fo:text-align", "right")]
+      Just LTR -> [("style:writing-mode", "lr-tb"),
+                        ("fo:text-align", "left")]
+
+-- | Adjust a named paragraph style for the current writing direction.
+-- When a direction is active, an automatic style derived from the
+-- given style with the appropriate @style:writing-mode@ is created
+-- (and cached).  Automatic style names (@P1@, @P2@, ...) pass through
+-- unchanged, since automatic styles are always created with the
+-- current direction included.
+dirStyleFor :: PandocMonad m => Text -> OD m Text
+dirStyleFor parent = do
+  mbDir <- gets stDirection
+  case mbDir of
+    Nothing -> return parent
+    Just d
+      | isAutoStyleName parent -> return parent
+      | otherwise -> do
+          cache <- gets stDirStyles
+          case Map.lookup (parent, d) cache of
+            Just name -> return name
+            Nothing -> do
+              name <- paraStyleFromParent parent []
+              modify $ \st -> st{ stDirStyles =
+                     Map.insert (parent, d) name (stDirStyles st) }
+              return name
+  where
+    isAutoStyleName t = case T.uncons t of
+      Just ('P', ds) -> not (T.null ds) && T.all isDigit ds
+      _              -> False
+
 paraTableStyles :: Text -> Int -> [Alignment] -> [(Text, Doc Text)]
 paraTableStyles _ _ [] = []
 paraTableStyles t s (a:xs)
@@ -964,9 +1057,21 @@
   Pre    -> Map.insert "style:font-name" "Courier New" .
             Map.insert "style:font-name-asian" "Courier New" .
             Map.insert "style:font-name-complex" "Courier New" $ m
-  Language lang ->
-            Map.insert "fo:language" (langLanguage lang) .
-            maybe id (Map.insert "fo:country") (langRegion lang) $ m
+  Language lang -> addLanguage lang m
+
+addLanguage :: Lang -> Map.Map Text Text -> Map.Map Text Text
+addLanguage lang
+  | isRTLLang lang =
+     Map.insert "style:language-complex" (langLanguage lang) .
+     maybe id (Map.insert "style:country-complex") (langRegion lang)
+  | otherwise =
+     Map.insert "fo:language" (langLanguage lang) .
+     maybe id (Map.insert "fo:country") (langRegion lang)
+
+-- | Returns True if the language is conventionally written right-to-left.
+isRTLLang :: Lang -> Bool
+isRTLLang Lang{ langLanguage = l } =
+  l `elem` ["ar", "he", "fa", "ur", "sd", "ckb", "yi", "dv"]
 
 withLangFromAttr :: PandocMonad m => Attr -> OD m a -> OD m a
 withLangFromAttr (_,_,kvs) action =
diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs
--- a/src/Text/Pandoc/Writers/TEI.hs
+++ b/src/Text/Pandoc/Writers/TEI.hs
@@ -46,7 +46,7 @@
                  meta
   main    <- fromBlocks blocks
   let context = defField "body" main
-              $ defField "mathml" (case writerHTMLMathMethod opts of
+              $ defField "mathml" (case writerMathMethod opts of
                                           MathML -> True
                                           _      -> False) metadata
   return $ render colwidth $
diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs
--- a/test/Tests/Old.hs
+++ b/test/Tests/Old.hs
@@ -73,7 +73,7 @@
     ]
   , testGroup "s5"
     [ s5WriterTest' "basic" ["-s"] "s5"
-    , s5WriterTest' "fancy" ["-s","--mathjax","-i"] "s5"
+    , s5WriterTest' "fancy" ["-s","--math-method=mathjax","-i"] "s5"
     , s5WriterTest' "fragment" [] "html4"
     , s5WriterTest' "inserts"  ["-s", "-H", "insert",
       "-B", "insert", "-A", "insert", "-c", "main.css"] "html4"
diff --git a/test/Tests/Readers/HTML.hs b/test/Tests/Readers/HTML.hs
--- a/test/Tests/Readers/HTML.hs
+++ b/test/Tests/Readers/HTML.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -Wno-deprecations #-}
 {- |
    Module      : Tests.Readers.HTML
    Copyright   : © 2006-2024 John MacFarlane
diff --git a/test/Tests/Readers/RTF.hs b/test/Tests/Readers/RTF.hs
--- a/test/Tests/Readers/RTF.hs
+++ b/test/Tests/Readers/RTF.hs
@@ -40,4 +40,6 @@
                     , "bookmark"
                     , "table_simple"
                     , "table_error_codes"
+                    , "table_nested"
+                    , "table_nested_malformed_itap"
                     ]
diff --git a/test/command/10915.md b/test/command/10915.md
--- a/test/command/10915.md
+++ b/test/command/10915.md
@@ -3,6 +3,7 @@
 \newcommand{\a}{\ifmmode x \else y \fi}
 $\a$ and \a
 ^D
-<p><span class="math inline"><em>x</em></span> and y</p>
+<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math>
+and y</p>
 ```
 
diff --git a/test/command/10940.md b/test/command/10940.md
new file mode 100644
--- /dev/null
+++ b/test/command/10940.md
@@ -0,0 +1,27 @@
+```
+% pandoc -t plain
+# Chapter one
+
+(@foo) an example list.
+(@) second item.
+
+# Chapter two
+
+(1@bar) reset the counter to one.
+(@) another.
+
+Foo is (@foo) and bar is (@bar).
+^D
+Chapter one
+
+(1) an example list.
+(2) second item.
+
+Chapter two
+
+(1) reset the counter to one.
+(2) another.
+
+Foo is (1) and bar is (1).
+
+```
diff --git a/test/command/11301-styles.opendocument b/test/command/11301-styles.opendocument
new file mode 100644
--- /dev/null
+++ b/test/command/11301-styles.opendocument
@@ -0,0 +1,2 @@
+$automatic-styles$
+$body$
diff --git a/test/command/11301.md b/test/command/11301.md
new file mode 100644
--- /dev/null
+++ b/test/command/11301.md
@@ -0,0 +1,87 @@
+RTL support in the opendocument/odt writer.
+
+`dir: rtl` in metadata should set `style:writing-mode` on paragraph styles:
+
+```
+% pandoc -f markdown -t opendocument --template command/11301-styles.opendocument
+---
+dir: rtl
+---
+
+# Heading
+
+Hello world.
+
+> quoted
+^D
+<style:style style:name="fr2" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" style:wrap="none" /></style:style>
+<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" /></style:style>
+<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_1">
+  <style:paragraph-properties style:writing-mode="rl-tb" fo:text-align="right" />
+</style:style>
+<style:style style:name="P2" style:family="paragraph" style:parent-style-name="First_20_paragraph">
+  <style:paragraph-properties style:writing-mode="rl-tb" fo:text-align="right" />
+</style:style>
+<style:style style:name="P3" style:family="paragraph" style:parent-style-name="Quotations">
+  <style:paragraph-properties style:writing-mode="rl-tb" fo:text-align="right" />
+</style:style>
+<text:h text:style-name="P1" text:outline-level="1"><text:bookmark-start text:name="heading" />Heading<text:bookmark-end text:name="heading" /></text:h>
+<text:p text:style-name="P2">Hello world.</text:p>
+<text:p text:style-name="P3">quoted</text:p>
+```
+
+An RTL `lang` in metadata implies RTL direction:
+
+```
+% pandoc -f markdown -t opendocument --template command/11301-styles.opendocument
+---
+lang: he
+---
+
+Hello world.
+^D
+<style:style style:name="fr2" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" style:wrap="none" /></style:style>
+<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" /></style:style>
+<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Text_20_body">
+  <style:paragraph-properties style:writing-mode="rl-tb" fo:text-align="right" />
+</style:style>
+<text:p text:style-name="P1">Hello world.</text:p>
+```
+
+`dir: ltr` in metadata overrides an RTL language:
+
+```
+% pandoc -f markdown -t opendocument --template command/11301-styles.opendocument
+---
+lang: he
+dir: ltr
+---
+
+Hello world.
+^D
+<style:style style:name="fr2" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" style:wrap="none" /></style:style>
+<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" /></style:style>
+<text:p text:style-name="Text_20_body">Hello world.</text:p>
+```
+
+A `dir` attribute on a div changes direction for its contents:
+
+```
+% pandoc -f markdown -t opendocument --template command/11301-styles.opendocument
+Plain paragraph.
+
+::: {dir=rtl}
+RTL paragraph.
+:::
+
+After div.
+^D
+<style:style style:name="fr2" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" style:wrap="none" /></style:style>
+<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" /></style:style>
+<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Text_20_body">
+  <style:paragraph-properties style:writing-mode="rl-tb" fo:text-align="right" />
+</style:style>
+<text:p text:style-name="Text_20_body">Plain paragraph.</text:p>
+<text:p text:style-name="P1">RTL paragraph.</text:p>
+<text:p text:style-name="Text_20_body">After div.</text:p>
+```
diff --git a/test/command/11809.md b/test/command/11809.md
new file mode 100644
--- /dev/null
+++ b/test/command/11809.md
@@ -0,0 +1,35 @@
+```
+% pandoc -f markdown -t jats
+::: {#d .warn}
+hi
+:::
+^D
+<boxed-text id="d">
+  <p>hi</p>
+</boxed-text>
+
+```
+
+```
+% pandoc -f html -t jats
+<div id="d">
+hi
+</div>
+^D
+<p id="d">
+  <p>hi</p>
+</p>
+
+```
+
+```
+% pandoc -f html -t jats
+<div class="foo">
+hi
+</div>
+^D
+<p>hi</p>
+
+```
+
+
diff --git a/test/command/11810.md b/test/command/11810.md
new file mode 100644
--- /dev/null
+++ b/test/command/11810.md
@@ -0,0 +1,15 @@
+```
+% pandoc -f html -t native
+<pre>alpha
+    beta
+        gamma</pre>
+^D
+[ Plain
+    [ Str "alpha"
+    , LineBreak
+    , Str "\160\160\160\160beta"
+    , LineBreak
+    , Str "\160\160\160\160\160\160\160\160gamma"
+    ]
+]
+```
diff --git a/test/command/11814.md b/test/command/11814.md
new file mode 100644
--- /dev/null
+++ b/test/command/11814.md
@@ -0,0 +1,16 @@
+```
+%  pandoc -f typst
+#block[
+para 1
+]
+#block[
+para 2
+]
+#block[
+para 3
+]
+^D
+<p>para 1</p>
+<p>para 2</p>
+<p>para 3</p>
+```
diff --git a/test/command/11833.docx b/test/command/11833.docx
new file mode 100644
Binary files /dev/null and b/test/command/11833.docx differ
diff --git a/test/command/11833.md b/test/command/11833.md
new file mode 100644
--- /dev/null
+++ b/test/command/11833.md
@@ -0,0 +1,40 @@
+```
+% pandoc command/11833.docx -t html
+^D
+<table>
+<colgroup>
+<col style="width: 39%" />
+<col style="width: 9%" />
+<col style="width: 35%" />
+<col style="width: 15%" />
+</colgroup>
+<thead>
+<tr>
+<th>VENDOR SERVICE MODEL</th>
+<th></th>
+<th></th>
+<th></th>
+</tr>
+<tr>
+<th>Question</th>
+<th>Response</th>
+<th>Comments</th>
+<th>Evidence Reference</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>question1</td>
+<td>response1</td>
+<td>comment1</td>
+<td>evidence1</td>
+</tr>
+<tr>
+<td>question 2</td>
+<td>response 2</td>
+<td>comment 2</td>
+<td>evidence 2</td>
+</tr>
+</tbody>
+</table>
+```
diff --git a/test/command/11834.md b/test/command/11834.md
new file mode 100644
--- /dev/null
+++ b/test/command/11834.md
@@ -0,0 +1,6 @@
+```
+% pandoc -t mediawiki
+http://foo.bar (https://foo.bar.baz)
+^D
+<nowiki>http://foo.bar</nowiki> <nowiki>(https://foo.bar.baz)</nowiki>
+```
diff --git a/test/command/3816.md b/test/command/3816.md
--- a/test/command/3816.md
+++ b/test/command/3816.md
@@ -1,5 +1,5 @@
 ```
-% pandoc --mathjax -t html5 --wrap=preserve
+% pandoc --math-method=mathjax -t html5 --wrap=preserve
 This is an equation:
 \begin{equation}
 y+2 = 3
diff --git a/test/command/4639.md b/test/command/4639.md
--- a/test/command/4639.md
+++ b/test/command/4639.md
@@ -1,5 +1,5 @@
 ```
-% pandoc -t html --mathjax
+% pandoc -t html --math-method=mathjax
 \begin{equation}
   E=mc^2
 \end{equation}
diff --git a/test/command/5655.md b/test/command/5655.md
--- a/test/command/5655.md
+++ b/test/command/5655.md
@@ -1,5 +1,5 @@
 ````
-% pandoc --webtex
+% pandoc --math-method=webtex
 $T_n={n+1 \choose 2}$
 ^D
 <p><img style="vertical-align:middle"
@@ -9,7 +9,7 @@
 ````
 
 ````
-% pandoc --webtex
+% pandoc --math-method=webtex
 $$T_n={n+1 \choose 2}$$
 ^D
 <p><img style="vertical-align:middle"
diff --git a/test/command/6739.md b/test/command/6739.md
--- a/test/command/6739.md
+++ b/test/command/6739.md
@@ -11,7 +11,7 @@
 ```
 
 ```
-% pandoc --mathjax -f gfm+tex_math_dollars
+% pandoc --math-method=mathjax -f gfm+tex_math_dollars
 * $|x|$
 * $|y|$
 ^D
diff --git a/test/command/8789.md b/test/command/8789.md
--- a/test/command/8789.md
+++ b/test/command/8789.md
@@ -33,8 +33,10 @@
 <tr>
 <td style="text-align: right;">160</td>
 <td style="text-align: right;">2</td>
-<td colspan="2" style="text-align: left;"><em>This is a test:</em> <span
-class="math display"><em>a</em><sup>2</sup> + <em>b</em><sup>2</sup> = <em>c</em><sup>2</sup></span></td>
+<td colspan="2" style="text-align: left;"><em>This is a test:</em>
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup><mo>=</mo><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\begin{equation*}
+                a^2+b^2 = c^2
+\end{equation*}</annotation></semantics></math></td>
 </tr>
 </tbody>
 </table>
diff --git a/test/command/completion.md b/test/command/completion.md
new file mode 100644
--- /dev/null
+++ b/test/command/completion.md
@@ -0,0 +1,380 @@
+```
+% pandoc --completion=bash
+^D
+# This script enables bash autocompletion for pandoc.  To enable
+# bash completion, add this to your .bashrc:
+# eval "$(pandoc --completion=bash)"
+
+_pandoc()
+{
+    local cur prev opts informats outformats highlight_styles math_methods datafiles
+    COMPREPLY=()
+    cur="${COMP_WORDS[COMP_CWORD]}"
+    prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+    # These should be filled in by pandoc:
+    opts="-f -r --from --read -t -w --to --write -o --output --data-dir -M --metadata --metadata-file -d --defaults --file-scope --sandbox -s --standalone --template -V --variable --variable-json --wrap --ascii --toc --table-of-contents --toc-depth --lof --list-of-figures --lot --list-of-tables -N --number-sections --number-offset --top-level-division --extract-media --resource-path -H --include-in-header -B --include-before-body -A --include-after-body --no-highlight --highlight-style --syntax-definition --syntax-highlighting --dpi --eol --columns -p --preserve-tabs --tab-stop --pdf-engine --pdf-engine-opt --reference-doc --self-contained --embed-resources --link-images --request-header --no-check-certificate --abbreviations --typst-input --indented-code-classes --default-image-extension -F --filter -L --lua-filter --shift-heading-level-by --base-header-level --track-changes --strip-comments --reference-links --reference-location --figure-caption-position --table-caption-position --markdown-headings --list-tables --listings -i --incremental --slide-level --section-divs --html-q-tags --email-obfuscation --id-prefix -T --title-prefix -c --css --epub-subdirectory --epub-cover-image --epub-title-page --epub-metadata --epub-embed-font --split-level --chunk-template --epub-chapter-level --ipynb-output -C --citeproc --bibliography --csl --citation-abbreviations --natbib --biblatex --math-method --mathml --webtex --mathjax --katex --gladtex --trace --dump-args --ignore-args --verbose --quiet --fail-if-warnings --log --completion --bash-completion --list-input-formats --list-output-formats --list-extensions --list-highlight-languages --list-highlight-styles -D --print-default-template --print-default-data-file --print-highlight-style -v --version -h --help"
+    informats="asciidoc biblatex bibtex bits commonmark commonmark_x creole csljson csv djot docbook docx dokuwiki endnotexml epub fb2 gfm haddock html ipynb jats jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict mdoc mediawiki muse native odt opml org pod pptx ris rst rtf t2t textile tikiwiki tsv twiki typst vimwiki xlsx xml"
+    outformats="ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki"
+    highlight_styles="pygments tango espresso zenburn kate monochrome breezedark haddock"
+    math_methods="plain mathml webtex mathjax katex gladtex"
+    datafiles="reference.docx reference.odt reference.pptx MANUAL.txt docx/_rels/.rels pptx/_rels/.rels abbreviations creole.lua default.csl docbook-entities.txt docx/[Content_Types].xml docx/docProps/app.xml docx/docProps/core.xml docx/docProps/custom.xml docx/word/_rels/document.xml.rels docx/word/_rels/footnotes.xml.rels docx/word/comments.xml docx/word/document.xml docx/word/fontTable.xml docx/word/footnotes.xml docx/word/numbering.xml docx/word/settings.xml docx/word/styles.xml docx/word/theme/theme1.xml docx/word/webSettings.xml dzslides/template.html epub.css init.lua odt/META-INF/manifest.xml odt/content.xml odt/manifest.rdf odt/meta.xml odt/mimetype odt/styles.xml pptx/[Content_Types].xml pptx/docProps/app.xml pptx/docProps/core.xml pptx/ppt/_rels/presentation.xml.rels pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels pptx/ppt/notesMasters/notesMaster1.xml pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels pptx/ppt/notesSlides/notesSlide1.xml pptx/ppt/notesSlides/notesSlide2.xml pptx/ppt/presProps.xml pptx/ppt/presentation.xml pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels pptx/ppt/slideLayouts/slideLayout1.xml pptx/ppt/slideLayouts/slideLayout10.xml pptx/ppt/slideLayouts/slideLayout11.xml pptx/ppt/slideLayouts/slideLayout2.xml pptx/ppt/slideLayouts/slideLayout3.xml pptx/ppt/slideLayouts/slideLayout4.xml pptx/ppt/slideLayouts/slideLayout5.xml pptx/ppt/slideLayouts/slideLayout6.xml pptx/ppt/slideLayouts/slideLayout7.xml pptx/ppt/slideLayouts/slideLayout8.xml pptx/ppt/slideLayouts/slideLayout9.xml pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels pptx/ppt/slideMasters/slideMaster1.xml pptx/ppt/slides/_rels/slide1.xml.rels pptx/ppt/slides/_rels/slide2.xml.rels pptx/ppt/slides/_rels/slide3.xml.rels pptx/ppt/slides/_rels/slide4.xml.rels pptx/ppt/slides/slide1.xml pptx/ppt/slides/slide2.xml pptx/ppt/slides/slide3.xml pptx/ppt/slides/slide4.xml pptx/ppt/tableStyles.xml pptx/ppt/theme/theme1.xml pptx/ppt/theme/theme2.xml pptx/ppt/viewProps.xml templates/affiliations.jats templates/after-header-includes.latex templates/article.jats_publishing templates/common.latex templates/default.ansi templates/default.asciidoc templates/default.bbcode templates/default.beamer templates/default.biblatex templates/default.bibtex templates/default.chunkedhtml templates/default.commonmark templates/default.context templates/default.djot templates/default.docbook4 templates/default.docbook5 templates/default.dokuwiki templates/default.dzslides templates/default.epub2 templates/default.epub3 templates/default.haddock templates/default.html4 templates/default.html5 templates/default.icml templates/default.jats_archiving templates/default.jats_articleauthoring templates/default.jats_publishing templates/default.jira templates/default.latex templates/default.man templates/default.markdown templates/default.markua templates/default.mediawiki templates/default.ms templates/default.muse templates/default.opendocument templates/default.openxml templates/default.opml templates/default.org templates/default.plain templates/default.revealjs templates/default.rst templates/default.rtf templates/default.s5 templates/default.slideous templates/default.slidy templates/default.t2t templates/default.tei templates/default.texinfo templates/default.textile templates/default.typst templates/default.vimdoc templates/default.xwiki templates/default.zimwiki templates/document-metadata.latex templates/font-settings.latex templates/fonts.latex templates/hypersetup.latex templates/passoptions.latex templates/styles.citations.html templates/styles.html templates/template.typst translations/af.yaml translations/alt.yaml translations/am.yaml translations/ar.yaml translations/as.yaml translations/ast.yaml translations/az.yaml translations/be.yaml translations/bg.yaml translations/bn.yaml translations/bo.yaml translations/br.yaml translations/bs.yaml translations/bua.yaml translations/ca.yaml translations/ckb-Arab.yaml translations/ckb-Latn.yaml translations/cs.yaml translations/cu.yaml translations/cy.yaml translations/cz.yaml translations/da.yaml translations/de.yaml translations/dsb.yaml translations/el.yaml translations/en.yaml translations/eo.yaml translations/es-ES.yaml translations/es-MX.yaml translations/es.yaml translations/et.yaml translations/eu.yaml translations/fa.yaml translations/fi.yaml translations/fil.yaml translations/fr.yaml translations/fur.yaml translations/ga.yaml translations/gd.yaml translations/gl.yaml translations/grc.yaml translations/gu.yaml translations/ha.yaml translations/he.yaml translations/hi.yaml translations/hr.yaml translations/hsb.yaml translations/hu.yaml translations/hy.yaml translations/ia.yaml translations/id.yaml translations/is.yaml translations/it.yaml translations/ja.yaml translations/ka.yaml translations/km.yaml translations/kmr-Arab.yaml translations/kmr-Latn.yaml translations/kn.yaml translations/ko.yaml translations/la.yaml translations/lb.yaml translations/lo.yaml translations/lt.yaml translations/lv.yaml translations/mk.yaml translations/ml.yaml translations/mn.yaml translations/mr.yaml translations/ms.yaml translations/nb.yaml translations/nko.yaml translations/nl.yaml translations/nn.yaml translations/no.yaml translations/oc.yaml translations/or.yaml translations/pa.yaml translations/pl.yaml translations/pms.yaml translations/pt-BR.yaml translations/pt-PT.yaml translations/pt.yaml translations/rm.yaml translations/ro.yaml translations/ru.yaml translations/se.yaml translations/si.yaml translations/sk.yaml translations/sl.yaml translations/sq.yaml translations/sr-Cyrl.yaml translations/sr-Latn.yaml translations/sr.yaml translations/sv.yaml translations/ta.yaml translations/te.yaml translations/th.yaml translations/tk.yaml translations/tr.yaml translations/ua.yaml translations/ug.yaml translations/uk.yaml translations/ur.yaml translations/vi.yaml translations/zh-Hans.yaml translations/zh-Hant.yaml"
+
+    case "${prev}" in
+         -f|-r|--from|--read)
+             COMPREPLY=( $(compgen -W "${informats}" -- ${cur}) )
+             return 0
+             ;;
+         -t|-w|--to|--write|-D|--print-default-template)
+             COMPREPLY=( $(compgen -W "${outformats}" -- ${cur}) )
+             return 0
+             ;;
+         --wrap)
+             COMPREPLY=( $(compgen -W "auto none preserve" -- ${cur}) )
+             return 0
+             ;;
+         --top-level-division)
+             COMPREPLY=( $(compgen -W "section chapter part" -- ${cur}) )
+             return 0
+             ;;
+         --highlight-style|--print-highlight-style)
+             COMPREPLY=( $(compgen -W "${highlight_styles}" -- ${cur}) )
+             return 0
+             ;;
+         --syntax-highlighting)
+             COMPREPLY=( $(compgen -W "none default idiomatic" -- ${cur}) )
+             return 0
+             ;;
+         --eol)
+             COMPREPLY=( $(compgen -W "crlf lf native" -- ${cur}) )
+             return 0
+             ;;
+         --pdf-engine)
+             COMPREPLY=( $(compgen -W "weasyprint wkhtmltopdf pagedjs-cli prince pdflatex lualatex xelatex latexmk tectonic pdflatex-dev lualatex-dev groff pdfroff typst context" -- ${cur}) )
+             return 0
+             ;;
+         --track-changes)
+             COMPREPLY=( $(compgen -W "accept reject all" -- ${cur}) )
+             return 0
+             ;;
+         --reference-location)
+             COMPREPLY=( $(compgen -W "block section document" -- ${cur}) )
+             return 0
+             ;;
+         --figure-caption-position|--table-caption-position)
+             COMPREPLY=( $(compgen -W "above below" -- ${cur}) )
+             return 0
+             ;;
+         --markdown-headings)
+             COMPREPLY=( $(compgen -W "setext atx" -- ${cur}) )
+             return 0
+             ;;
+         --email-obfuscation)
+             COMPREPLY=( $(compgen -W "references javascript none" -- ${cur}) )
+             return 0
+             ;;
+         --ipynb-output)
+             COMPREPLY=( $(compgen -W "all none best" -- ${cur}) )
+             return 0
+             ;;
+         --math-method)
+             COMPREPLY=( $(compgen -W "${math_methods}" -- ${cur}) )
+             return 0
+             ;;
+         --print-default-data-file)
+             COMPREPLY=( $(compgen -W "${datafiles}" -- ${cur}) )
+             return 0
+             ;;
+         *)
+             ;;
+    esac
+
+    case "${cur}" in
+         -*)
+             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+             return 0
+             ;;
+         *)
+             local IFS=$'\n'
+             COMPREPLY=( $(compgen -X '' -f "${cur}") )
+             return 0
+             ;;
+    esac
+
+}
+
+complete -o filenames -o bashdefault -F _pandoc pandoc
+
+.
+```
+
+```
+% pandoc --completion=zsh
+^D
+#compdef pandoc
+
+_pandoc() {
+  local -a args
+  args=(
+    '-f[Reader format]:FORMAT:(asciidoc biblatex bibtex bits commonmark commonmark_x creole csljson csv djot docbook docx dokuwiki endnotexml epub fb2 gfm haddock html ipynb jats jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict mdoc mediawiki muse native odt opml org pod pptx ris rst rtf t2t textile tikiwiki tsv twiki typst vimwiki xlsx xml)'
+    '-r[Reader format]:FORMAT:(asciidoc biblatex bibtex bits commonmark commonmark_x creole csljson csv djot docbook docx dokuwiki endnotexml epub fb2 gfm haddock html ipynb jats jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict mdoc mediawiki muse native odt opml org pod pptx ris rst rtf t2t textile tikiwiki tsv twiki typst vimwiki xlsx xml)'
+    '--from[Reader format]:FORMAT:(asciidoc biblatex bibtex bits commonmark commonmark_x creole csljson csv djot docbook docx dokuwiki endnotexml epub fb2 gfm haddock html ipynb jats jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict mdoc mediawiki muse native odt opml org pod pptx ris rst rtf t2t textile tikiwiki tsv twiki typst vimwiki xlsx xml)'
+    '--read[Reader format]:FORMAT:(asciidoc biblatex bibtex bits commonmark commonmark_x creole csljson csv djot docbook docx dokuwiki endnotexml epub fb2 gfm haddock html ipynb jats jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict mdoc mediawiki muse native odt opml org pod pptx ris rst rtf t2t textile tikiwiki tsv twiki typst vimwiki xlsx xml)'
+    '-t[Writer format]:FORMAT:(ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki)'
+    '-w[Writer format]:FORMAT:(ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki)'
+    '--to[Writer format]:FORMAT:(ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki)'
+    '--write[Writer format]:FORMAT:(ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki)'
+    '-o[Output file]:FILE:_files'
+    '--output[Output file]:FILE:_files'
+    '--data-dir[Directory for data files]:DIRECTORY:_files'
+    '-M[Metadata field KEY=VALUE]:KEY[=VALUE]:_files'
+    '--metadata[Metadata field KEY=VALUE]:KEY[=VALUE]:_files'
+    '--metadata-file[Metadata file]:FILE:_files'
+    '-d[Defaults file]:FILE:_files'
+    '--defaults[Defaults file]:FILE:_files'
+    '--file-scope[Parse files before combining]'
+    '--sandbox[Run pandoc in a sandbox]'
+    '-s[Include header and footer]'
+    '--standalone[Include header and footer]'
+    '--template[Custom template file]:FILE:_files'
+    '-V[Template variable KEY=VALUE]:KEY[=VALUE]:_files'
+    '--variable[Template variable KEY=VALUE]:KEY[=VALUE]:_files'
+    '--variable-json[Template variable KEY=JSON]:KEY[:JSON]:_files'
+    '--wrap[Text wrapping mode]:auto|none|preserve:(auto none preserve)'
+    '--ascii[Prefer ASCII output]'
+    '--toc[Include table of contents]'
+    '--table-of-contents[Include table of contents]'
+    '--toc-depth[Number of TOC levels]:NUMBER:_files'
+    '--lof[Include list of figures]'
+    '--list-of-figures[Include list of figures]'
+    '--lot[Include list of tables]'
+    '--list-of-tables[Include list of tables]'
+    '-N[Number section headings]'
+    '--number-sections[Number section headings]'
+    '--number-offset[Starting number for sections]:NUMBERS:_files'
+    '--top-level-division[Top-level document division]:section|chapter|part:(section chapter part)'
+    '--extract-media[Directory to extract media into]:PATH:_files'
+    '--resource-path[Search path for resources]:SEARCHPATH:_files'
+    '-H[File to include in the header]:FILE:_files'
+    '--include-in-header[File to include in the header]:FILE:_files'
+    '-B[File to include before the body]:FILE:_files'
+    '--include-before-body[File to include before the body]:FILE:_files'
+    '-A[File to include after the body]:FILE:_files'
+    '--include-after-body[File to include after the body]:FILE:_files'
+    '--no-highlight[Disable syntax highlighting]'
+    '--highlight-style[Highlighting style]:STYLE:(pygments tango espresso zenburn kate monochrome breezedark haddock)'
+    '--syntax-definition[Syntax definition XML file]:FILE:_files'
+    '--syntax-highlighting[Syntax highlighting method]:none|default|idiomatic|<stylename>|<themepath>:(none default idiomatic)'
+    '--dpi[DPI for imported images]:NUMBER:_files'
+    '--eol[End-of-line characters]:crlf|lf|native:(crlf lf native)'
+    '--columns[Line length in characters]:NUMBER:_files'
+    '-p[Preserve tabs]'
+    '--preserve-tabs[Preserve tabs]'
+    '--tab-stop[Tab stop width]:NUMBER:_files'
+    '--pdf-engine[Program used to produce PDF]:PROGRAM:(weasyprint wkhtmltopdf pagedjs-cli prince pdflatex lualatex xelatex latexmk tectonic pdflatex-dev lualatex-dev groff pdfroff typst context)'
+    '--pdf-engine-opt[Flag to pass to the PDF engine]:STRING:_files'
+    '--reference-doc[Custom reference doc]:FILE:_files'
+    '--self-contained[Embed resources (deprecated)]'
+    '--embed-resources[Embed referenced resources]'
+    '--link-images[Link images in ODT rather than embedding]'
+    '--request-header[HTTP header NAME=VALUE]:NAME=VALUE:_files'
+    '--no-check-certificate[Disable certificate validation]'
+    '--abbreviations[File with abbreviations]:FILE:_files'
+    '--typst-input[Typst variable KEY=VALUE]:KEY=VALUE:_files'
+    '--indented-code-classes[Classes for indented code blocks]:STRING:_files'
+    '--default-image-extension[Default extension for images]:extension:_files'
+    '-F[External JSON filter]:PROGRAM:_files'
+    '--filter[External JSON filter]:PROGRAM:_files'
+    '-L[Lua filter script]:SCRIPTPATH:_files'
+    '--lua-filter[Lua filter script]:SCRIPTPATH:_files'
+    '--shift-heading-level-by[Shift heading level by N]:NUMBER:_files'
+    '--base-header-level[Base header level (deprecated)]:NUMBER:_files'
+    '--track-changes[Handling of Word track-changes]:accept|reject|all:(accept reject all)'
+    '--strip-comments[Strip HTML comments]'
+    '--reference-links[Use reference links in HTML]'
+    '--reference-location[Location of references]:block|section|document:(block section document)'
+    '--figure-caption-position[Figure caption position]:above|below:(above below)'
+    '--table-caption-position[Table caption position]:above|below:(above below)'
+    '--markdown-headings[Markdown heading style]:setext|atx:(setext atx)'
+    '--list-tables[Use list tables for RST]'
+    '--listings[Use listings package (deprecated)]'
+    '-i[Make list items display incrementally]'
+    '--incremental[Make list items display incrementally]'
+    '--slide-level[Header level used for slides]:NUMBER:_files'
+    '--section-divs[Wrap sections in div tags]'
+    '--html-q-tags[Use q tags for quotes in HTML]'
+    '--email-obfuscation[Email obfuscation method]:none|javascript|references:(references javascript none)'
+    '--id-prefix[Prefix for auto identifiers]:STRING:_files'
+    '-T[Window title prefix]:STRING:_files'
+    '--title-prefix[Window title prefix]:STRING:_files'
+    '-c[CSS style sheet]:URL:_files'
+    '--css[CSS style sheet]:URL:_files'
+    '--epub-subdirectory[EPUB content subdirectory]:DIRNAME:_files'
+    '--epub-cover-image[EPUB cover image]:FILE:_files'
+    '--epub-title-page[URL or file for EPUB title page]:true|false:_files'
+    '--epub-metadata[EPUB metadata file]:FILE:_files'
+    '--epub-embed-font[Font file to embed in EPUB]:FILE:_files'
+    '--split-level[Split level for chunked HTML or EPUB]:NUMBER:_files'
+    '--chunk-template[Template for chunked HTML paths]:PATHTEMPLATE:_files'
+    '--epub-chapter-level[Split level (deprecated)]:NUMBER:_files'
+    '--ipynb-output[Handling of ipynb output cells]:all|none|best:(all none best)'
+    '-C[Process citations]'
+    '--citeproc[Process citations]'
+    '--bibliography[Bibliography file]:FILE:_files'
+    '--csl[CSL style file]:FILE:_files'
+    '--citation-abbreviations[Citation abbreviations file]:FILE:_files'
+    '--natbib[Use natbib citations in LaTeX]'
+    '--biblatex[Use biblatex citations in LaTeX]'
+    '--math-method[Specify method for rendering math in HTML]:METHOD:(plain mathml webtex mathjax katex gladtex)'
+    '--mathml[Use MathML for HTML math]'
+    '--webtex[Use WebTeX for HTML math]'
+    '--mathjax[Use MathJax for HTML math]'
+    '--katex[Use KaTeX for HTML math]'
+    '--gladtex[Use gladTeX for HTML math]'
+    '--trace[Turn on diagnostic tracing]'
+    '--dump-args[Print output filename and arguments]'
+    '--ignore-args[Ignore command-line arguments]'
+    '--verbose[Verbose diagnostic output]'
+    '--quiet[Suppress warning messages]'
+    '--fail-if-warnings[Exit with error status if there were warnings]'
+    '--log[Log messages in JSON format to this file]:FILE:_files'
+    '--completion[Shell for which to print the completion script]'
+    '--bash-completion[Print bash completion script (deprecated)]'
+    '--list-input-formats[List supported input formats]'
+    '--list-output-formats[List supported output formats]'
+    '--list-extensions[List supported extensions]'
+    '--list-highlight-languages[List highlighting languages]'
+    '--list-highlight-styles[List highlighting styles]'
+    '-D[Format to print template for]:FORMAT:(ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki)'
+    '--print-default-template[Format to print template for]:FORMAT:(ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki)'
+    '--print-default-data-file[Data file to print]:FILE:(reference.docx reference.odt reference.pptx MANUAL.txt docx/_rels/.rels pptx/_rels/.rels abbreviations creole.lua default.csl docbook-entities.txt docx/[Content_Types].xml docx/docProps/app.xml docx/docProps/core.xml docx/docProps/custom.xml docx/word/_rels/document.xml.rels docx/word/_rels/footnotes.xml.rels docx/word/comments.xml docx/word/document.xml docx/word/fontTable.xml docx/word/footnotes.xml docx/word/numbering.xml docx/word/settings.xml docx/word/styles.xml docx/word/theme/theme1.xml docx/word/webSettings.xml dzslides/template.html epub.css init.lua odt/META-INF/manifest.xml odt/content.xml odt/manifest.rdf odt/meta.xml odt/mimetype odt/styles.xml pptx/[Content_Types].xml pptx/docProps/app.xml pptx/docProps/core.xml pptx/ppt/_rels/presentation.xml.rels pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels pptx/ppt/notesMasters/notesMaster1.xml pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels pptx/ppt/notesSlides/notesSlide1.xml pptx/ppt/notesSlides/notesSlide2.xml pptx/ppt/presProps.xml pptx/ppt/presentation.xml pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels pptx/ppt/slideLayouts/slideLayout1.xml pptx/ppt/slideLayouts/slideLayout10.xml pptx/ppt/slideLayouts/slideLayout11.xml pptx/ppt/slideLayouts/slideLayout2.xml pptx/ppt/slideLayouts/slideLayout3.xml pptx/ppt/slideLayouts/slideLayout4.xml pptx/ppt/slideLayouts/slideLayout5.xml pptx/ppt/slideLayouts/slideLayout6.xml pptx/ppt/slideLayouts/slideLayout7.xml pptx/ppt/slideLayouts/slideLayout8.xml pptx/ppt/slideLayouts/slideLayout9.xml pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels pptx/ppt/slideMasters/slideMaster1.xml pptx/ppt/slides/_rels/slide1.xml.rels pptx/ppt/slides/_rels/slide2.xml.rels pptx/ppt/slides/_rels/slide3.xml.rels pptx/ppt/slides/_rels/slide4.xml.rels pptx/ppt/slides/slide1.xml pptx/ppt/slides/slide2.xml pptx/ppt/slides/slide3.xml pptx/ppt/slides/slide4.xml pptx/ppt/tableStyles.xml pptx/ppt/theme/theme1.xml pptx/ppt/theme/theme2.xml pptx/ppt/viewProps.xml templates/affiliations.jats templates/after-header-includes.latex templates/article.jats_publishing templates/common.latex templates/default.ansi templates/default.asciidoc templates/default.bbcode templates/default.beamer templates/default.biblatex templates/default.bibtex templates/default.chunkedhtml templates/default.commonmark templates/default.context templates/default.djot templates/default.docbook4 templates/default.docbook5 templates/default.dokuwiki templates/default.dzslides templates/default.epub2 templates/default.epub3 templates/default.haddock templates/default.html4 templates/default.html5 templates/default.icml templates/default.jats_archiving templates/default.jats_articleauthoring templates/default.jats_publishing templates/default.jira templates/default.latex templates/default.man templates/default.markdown templates/default.markua templates/default.mediawiki templates/default.ms templates/default.muse templates/default.opendocument templates/default.openxml templates/default.opml templates/default.org templates/default.plain templates/default.revealjs templates/default.rst templates/default.rtf templates/default.s5 templates/default.slideous templates/default.slidy templates/default.t2t templates/default.tei templates/default.texinfo templates/default.textile templates/default.typst templates/default.vimdoc templates/default.xwiki templates/default.zimwiki templates/document-metadata.latex templates/font-settings.latex templates/fonts.latex templates/hypersetup.latex templates/passoptions.latex templates/styles.citations.html templates/styles.html templates/template.typst translations/af.yaml translations/alt.yaml translations/am.yaml translations/ar.yaml translations/as.yaml translations/ast.yaml translations/az.yaml translations/be.yaml translations/bg.yaml translations/bn.yaml translations/bo.yaml translations/br.yaml translations/bs.yaml translations/bua.yaml translations/ca.yaml translations/ckb-Arab.yaml translations/ckb-Latn.yaml translations/cs.yaml translations/cu.yaml translations/cy.yaml translations/cz.yaml translations/da.yaml translations/de.yaml translations/dsb.yaml translations/el.yaml translations/en.yaml translations/eo.yaml translations/es-ES.yaml translations/es-MX.yaml translations/es.yaml translations/et.yaml translations/eu.yaml translations/fa.yaml translations/fi.yaml translations/fil.yaml translations/fr.yaml translations/fur.yaml translations/ga.yaml translations/gd.yaml translations/gl.yaml translations/grc.yaml translations/gu.yaml translations/ha.yaml translations/he.yaml translations/hi.yaml translations/hr.yaml translations/hsb.yaml translations/hu.yaml translations/hy.yaml translations/ia.yaml translations/id.yaml translations/is.yaml translations/it.yaml translations/ja.yaml translations/ka.yaml translations/km.yaml translations/kmr-Arab.yaml translations/kmr-Latn.yaml translations/kn.yaml translations/ko.yaml translations/la.yaml translations/lb.yaml translations/lo.yaml translations/lt.yaml translations/lv.yaml translations/mk.yaml translations/ml.yaml translations/mn.yaml translations/mr.yaml translations/ms.yaml translations/nb.yaml translations/nko.yaml translations/nl.yaml translations/nn.yaml translations/no.yaml translations/oc.yaml translations/or.yaml translations/pa.yaml translations/pl.yaml translations/pms.yaml translations/pt-BR.yaml translations/pt-PT.yaml translations/pt.yaml translations/rm.yaml translations/ro.yaml translations/ru.yaml translations/se.yaml translations/si.yaml translations/sk.yaml translations/sl.yaml translations/sq.yaml translations/sr-Cyrl.yaml translations/sr-Latn.yaml translations/sr.yaml translations/sv.yaml translations/ta.yaml translations/te.yaml translations/th.yaml translations/tk.yaml translations/tr.yaml translations/ua.yaml translations/ug.yaml translations/uk.yaml translations/ur.yaml translations/vi.yaml translations/zh-Hans.yaml translations/zh-Hant.yaml)'
+    '--print-highlight-style[Highlighting style]:STYLE:(pygments tango espresso zenburn kate monochrome breezedark haddock)'
+    '-v[Print version]'
+    '--version[Print version]'
+    '-h[Show help]'
+    '--help[Show help]'
+    '*:files:_files'
+  )
+  _arguments -s -S $args
+}
+
+_pandoc "$@"
+
+.
+```
+
+```
+% pandoc --completion=fish
+^D
+complete -c pandoc -l from -d "Reader format" -r -a "asciidoc biblatex bibtex bits commonmark commonmark_x creole csljson csv djot docbook docx dokuwiki endnotexml epub fb2 gfm haddock html ipynb jats jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict mdoc mediawiki muse native odt opml org pod pptx ris rst rtf t2t textile tikiwiki tsv twiki typst vimwiki xlsx xml"
+complete -c pandoc -l to -d "Writer format" -r -a "ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki"
+complete -c pandoc -s o -l output -d "Output file" -r
+complete -c pandoc -l data-dir -d "Directory for data files" -r
+complete -c pandoc -s M -l metadata -d "Metadata field KEY=VALUE" -r
+complete -c pandoc -l metadata-file -d "Metadata file" -r
+complete -c pandoc -s d -l defaults -d "Defaults file" -r
+complete -c pandoc -l file-scope -d "Parse files before combining"
+complete -c pandoc -l sandbox -d "Run pandoc in a sandbox"
+complete -c pandoc -s s -l standalone -d "Include header and footer"
+complete -c pandoc -l template -d "Custom template file" -r
+complete -c pandoc -s V -l variable -d "Template variable KEY=VALUE" -r
+complete -c pandoc -l variable-json -d "Template variable KEY=JSON" -r
+complete -c pandoc -l wrap -d "Text wrapping mode" -r -a "auto none preserve"
+complete -c pandoc -l ascii -d "Prefer ASCII output"
+complete -c pandoc -l toc -d "Include table of contents"
+complete -c pandoc -l toc-depth -d "Number of TOC levels" -r
+complete -c pandoc -l lof -d "Include list of figures"
+complete -c pandoc -l lot -d "Include list of tables"
+complete -c pandoc -s N -l number-sections -d "Number section headings"
+complete -c pandoc -l number-offset -d "Starting number for sections" -r
+complete -c pandoc -l top-level-division -d "Top-level document division" -r -a "section chapter part"
+complete -c pandoc -l extract-media -d "Directory to extract media into" -r
+complete -c pandoc -l resource-path -d "Search path for resources" -r
+complete -c pandoc -s H -l include-in-header -d "File to include in the header" -r
+complete -c pandoc -s B -l include-before-body -d "File to include before the body" -r
+complete -c pandoc -s A -l include-after-body -d "File to include after the body" -r
+complete -c pandoc -l no-highlight -d "Disable syntax highlighting"
+complete -c pandoc -l highlight-style -d "Highlighting style" -r -a "pygments tango espresso zenburn kate monochrome breezedark haddock"
+complete -c pandoc -l syntax-definition -d "Syntax definition XML file" -r
+complete -c pandoc -l syntax-highlighting -d "Syntax highlighting method" -r -a "none default idiomatic"
+complete -c pandoc -l dpi -d "DPI for imported images" -r
+complete -c pandoc -l eol -d "End-of-line characters" -r -a "crlf lf native"
+complete -c pandoc -l columns -d "Line length in characters" -r
+complete -c pandoc -s p -l preserve-tabs -d "Preserve tabs"
+complete -c pandoc -l tab-stop -d "Tab stop width" -r
+complete -c pandoc -l pdf-engine -d "Program used to produce PDF" -r -a "weasyprint wkhtmltopdf pagedjs-cli prince pdflatex lualatex xelatex latexmk tectonic pdflatex-dev lualatex-dev groff pdfroff typst context"
+complete -c pandoc -l pdf-engine-opt -d "Flag to pass to the PDF engine" -r
+complete -c pandoc -l reference-doc -d "Custom reference doc" -r
+complete -c pandoc -l self-contained -d "Embed resources (deprecated)"
+complete -c pandoc -l embed-resources -d "Embed referenced resources"
+complete -c pandoc -l link-images -d "Link images in ODT rather than embedding"
+complete -c pandoc -l request-header -d "HTTP header NAME=VALUE" -r
+complete -c pandoc -l no-check-certificate -d "Disable certificate validation"
+complete -c pandoc -l abbreviations -d "File with abbreviations" -r
+complete -c pandoc -l typst-input -d "Typst variable KEY=VALUE" -r
+complete -c pandoc -l indented-code-classes -d "Classes for indented code blocks" -r
+complete -c pandoc -l default-image-extension -d "Default extension for images" -r
+complete -c pandoc -s F -l filter -d "External JSON filter" -r
+complete -c pandoc -s L -l lua-filter -d "Lua filter script" -r
+complete -c pandoc -l shift-heading-level-by -d "Shift heading level by N" -r
+complete -c pandoc -l base-header-level -d "Base header level (deprecated)" -r
+complete -c pandoc -l track-changes -d "Handling of Word track-changes" -r -a "accept reject all"
+complete -c pandoc -l strip-comments -d "Strip HTML comments"
+complete -c pandoc -l reference-links -d "Use reference links in HTML"
+complete -c pandoc -l reference-location -d "Location of references" -r -a "block section document"
+complete -c pandoc -l figure-caption-position -d "Figure caption position" -r -a "above below"
+complete -c pandoc -l table-caption-position -d "Table caption position" -r -a "above below"
+complete -c pandoc -l markdown-headings -d "Markdown heading style" -r -a "setext atx"
+complete -c pandoc -l list-tables -d "Use list tables for RST"
+complete -c pandoc -l listings -d "Use listings package (deprecated)"
+complete -c pandoc -s i -l incremental -d "Make list items display incrementally"
+complete -c pandoc -l slide-level -d "Header level used for slides" -r
+complete -c pandoc -l section-divs -d "Wrap sections in div tags"
+complete -c pandoc -l html-q-tags -d "Use q tags for quotes in HTML"
+complete -c pandoc -l email-obfuscation -d "Email obfuscation method" -r -a "references javascript none"
+complete -c pandoc -l id-prefix -d "Prefix for auto identifiers" -r
+complete -c pandoc -s T -l title-prefix -d "Window title prefix" -r
+complete -c pandoc -s c -l css -d "CSS style sheet" -r
+complete -c pandoc -l epub-subdirectory -d "EPUB content subdirectory" -r
+complete -c pandoc -l epub-cover-image -d "EPUB cover image" -r
+complete -c pandoc -l epub-title-page -d "URL or file for EPUB title page" -r
+complete -c pandoc -l epub-metadata -d "EPUB metadata file" -r
+complete -c pandoc -l epub-embed-font -d "Font file to embed in EPUB" -r
+complete -c pandoc -l split-level -d "Split level for chunked HTML or EPUB" -r
+complete -c pandoc -l chunk-template -d "Template for chunked HTML paths" -r
+complete -c pandoc -l epub-chapter-level -d "Split level (deprecated)" -r
+complete -c pandoc -l ipynb-output -d "Handling of ipynb output cells" -r -a "all none best"
+complete -c pandoc -s C -l citeproc -d "Process citations"
+complete -c pandoc -l bibliography -d "Bibliography file" -r
+complete -c pandoc -l csl -d "CSL style file" -r
+complete -c pandoc -l citation-abbreviations -d "Citation abbreviations file" -r
+complete -c pandoc -l natbib -d "Use natbib citations in LaTeX"
+complete -c pandoc -l biblatex -d "Use biblatex citations in LaTeX"
+complete -c pandoc -l math-method -d "Specify method for rendering math in HTML" -r -a "plain mathml webtex mathjax katex gladtex"
+complete -c pandoc -l mathml -d "Use MathML for HTML math"
+complete -c pandoc -l webtex -d "Use WebTeX for HTML math"
+complete -c pandoc -l mathjax -d "Use MathJax for HTML math"
+complete -c pandoc -l katex -d "Use KaTeX for HTML math"
+complete -c pandoc -l gladtex -d "Use gladTeX for HTML math"
+complete -c pandoc -l trace -d "Turn on diagnostic tracing"
+complete -c pandoc -l dump-args -d "Print output filename and arguments"
+complete -c pandoc -l ignore-args -d "Ignore command-line arguments"
+complete -c pandoc -l verbose -d "Verbose diagnostic output"
+complete -c pandoc -l quiet -d "Suppress warning messages"
+complete -c pandoc -l fail-if-warnings -d "Exit with error status if there were warnings"
+complete -c pandoc -l log -d "Log messages in JSON format to this file" -r
+complete -c pandoc -l completion -d "Shell for which to print the completion script"
+complete -c pandoc -l bash-completion -d "Print bash completion script (deprecated)"
+complete -c pandoc -l list-input-formats -d "List supported input formats"
+complete -c pandoc -l list-output-formats -d "List supported output formats"
+complete -c pandoc -l list-extensions -d "List supported extensions"
+complete -c pandoc -l list-highlight-languages -d "List highlighting languages"
+complete -c pandoc -l list-highlight-styles -d "List highlighting styles"
+complete -c pandoc -s D -l print-default-template -d "Format to print template for" -r -a "ansi asciidoc asciidoc_legacy asciidoctor bbcode bbcode_fluxbb bbcode_hubzilla bbcode_phpbb bbcode_steam bbcode_xenforo beamer biblatex bibtex chunkedhtml commonmark commonmark_x context csljson djot docbook docbook4 docbook5 docx dokuwiki dzslides epub epub2 epub3 fb2 gfm haddock html html4 html5 icml ipynb jats jats_archiving jats_articleauthoring jats_publishing jira json latex man markdown markdown_github markdown_mmd markdown_phpextra markdown_strict markua mediawiki ms muse native odt opendocument opml org pdf plain pptx revealjs rst rtf s5 slideous slidy t2t tei texinfo textile typst vimdoc xml xwiki zimwiki"
+complete -c pandoc -l print-default-data-file -d "Data file to print" -r -a "reference.docx reference.odt reference.pptx MANUAL.txt docx/_rels/.rels pptx/_rels/.rels abbreviations creole.lua default.csl docbook-entities.txt docx/[Content_Types].xml docx/docProps/app.xml docx/docProps/core.xml docx/docProps/custom.xml docx/word/_rels/document.xml.rels docx/word/_rels/footnotes.xml.rels docx/word/comments.xml docx/word/document.xml docx/word/fontTable.xml docx/word/footnotes.xml docx/word/numbering.xml docx/word/settings.xml docx/word/styles.xml docx/word/theme/theme1.xml docx/word/webSettings.xml dzslides/template.html epub.css init.lua odt/META-INF/manifest.xml odt/content.xml odt/manifest.rdf odt/meta.xml odt/mimetype odt/styles.xml pptx/[Content_Types].xml pptx/docProps/app.xml pptx/docProps/core.xml pptx/ppt/_rels/presentation.xml.rels pptx/ppt/notesMasters/_rels/notesMaster1.xml.rels pptx/ppt/notesMasters/notesMaster1.xml pptx/ppt/notesSlides/_rels/notesSlide1.xml.rels pptx/ppt/notesSlides/_rels/notesSlide2.xml.rels pptx/ppt/notesSlides/notesSlide1.xml pptx/ppt/notesSlides/notesSlide2.xml pptx/ppt/presProps.xml pptx/ppt/presentation.xml pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels pptx/ppt/slideLayouts/slideLayout1.xml pptx/ppt/slideLayouts/slideLayout10.xml pptx/ppt/slideLayouts/slideLayout11.xml pptx/ppt/slideLayouts/slideLayout2.xml pptx/ppt/slideLayouts/slideLayout3.xml pptx/ppt/slideLayouts/slideLayout4.xml pptx/ppt/slideLayouts/slideLayout5.xml pptx/ppt/slideLayouts/slideLayout6.xml pptx/ppt/slideLayouts/slideLayout7.xml pptx/ppt/slideLayouts/slideLayout8.xml pptx/ppt/slideLayouts/slideLayout9.xml pptx/ppt/slideMasters/_rels/slideMaster1.xml.rels pptx/ppt/slideMasters/slideMaster1.xml pptx/ppt/slides/_rels/slide1.xml.rels pptx/ppt/slides/_rels/slide2.xml.rels pptx/ppt/slides/_rels/slide3.xml.rels pptx/ppt/slides/_rels/slide4.xml.rels pptx/ppt/slides/slide1.xml pptx/ppt/slides/slide2.xml pptx/ppt/slides/slide3.xml pptx/ppt/slides/slide4.xml pptx/ppt/tableStyles.xml pptx/ppt/theme/theme1.xml pptx/ppt/theme/theme2.xml pptx/ppt/viewProps.xml templates/affiliations.jats templates/after-header-includes.latex templates/article.jats_publishing templates/common.latex templates/default.ansi templates/default.asciidoc templates/default.bbcode templates/default.beamer templates/default.biblatex templates/default.bibtex templates/default.chunkedhtml templates/default.commonmark templates/default.context templates/default.djot templates/default.docbook4 templates/default.docbook5 templates/default.dokuwiki templates/default.dzslides templates/default.epub2 templates/default.epub3 templates/default.haddock templates/default.html4 templates/default.html5 templates/default.icml templates/default.jats_archiving templates/default.jats_articleauthoring templates/default.jats_publishing templates/default.jira templates/default.latex templates/default.man templates/default.markdown templates/default.markua templates/default.mediawiki templates/default.ms templates/default.muse templates/default.opendocument templates/default.openxml templates/default.opml templates/default.org templates/default.plain templates/default.revealjs templates/default.rst templates/default.rtf templates/default.s5 templates/default.slideous templates/default.slidy templates/default.t2t templates/default.tei templates/default.texinfo templates/default.textile templates/default.typst templates/default.vimdoc templates/default.xwiki templates/default.zimwiki templates/document-metadata.latex templates/font-settings.latex templates/fonts.latex templates/hypersetup.latex templates/passoptions.latex templates/styles.citations.html templates/styles.html templates/template.typst translations/af.yaml translations/alt.yaml translations/am.yaml translations/ar.yaml translations/as.yaml translations/ast.yaml translations/az.yaml translations/be.yaml translations/bg.yaml translations/bn.yaml translations/bo.yaml translations/br.yaml translations/bs.yaml translations/bua.yaml translations/ca.yaml translations/ckb-Arab.yaml translations/ckb-Latn.yaml translations/cs.yaml translations/cu.yaml translations/cy.yaml translations/cz.yaml translations/da.yaml translations/de.yaml translations/dsb.yaml translations/el.yaml translations/en.yaml translations/eo.yaml translations/es-ES.yaml translations/es-MX.yaml translations/es.yaml translations/et.yaml translations/eu.yaml translations/fa.yaml translations/fi.yaml translations/fil.yaml translations/fr.yaml translations/fur.yaml translations/ga.yaml translations/gd.yaml translations/gl.yaml translations/grc.yaml translations/gu.yaml translations/ha.yaml translations/he.yaml translations/hi.yaml translations/hr.yaml translations/hsb.yaml translations/hu.yaml translations/hy.yaml translations/ia.yaml translations/id.yaml translations/is.yaml translations/it.yaml translations/ja.yaml translations/ka.yaml translations/km.yaml translations/kmr-Arab.yaml translations/kmr-Latn.yaml translations/kn.yaml translations/ko.yaml translations/la.yaml translations/lb.yaml translations/lo.yaml translations/lt.yaml translations/lv.yaml translations/mk.yaml translations/ml.yaml translations/mn.yaml translations/mr.yaml translations/ms.yaml translations/nb.yaml translations/nko.yaml translations/nl.yaml translations/nn.yaml translations/no.yaml translations/oc.yaml translations/or.yaml translations/pa.yaml translations/pl.yaml translations/pms.yaml translations/pt-BR.yaml translations/pt-PT.yaml translations/pt.yaml translations/rm.yaml translations/ro.yaml translations/ru.yaml translations/se.yaml translations/si.yaml translations/sk.yaml translations/sl.yaml translations/sq.yaml translations/sr-Cyrl.yaml translations/sr-Latn.yaml translations/sr.yaml translations/sv.yaml translations/ta.yaml translations/te.yaml translations/th.yaml translations/tk.yaml translations/tr.yaml translations/ua.yaml translations/ug.yaml translations/uk.yaml translations/ur.yaml translations/vi.yaml translations/zh-Hans.yaml translations/zh-Hant.yaml"
+complete -c pandoc -l print-highlight-style -d "Highlighting style" -r -a "pygments tango espresso zenburn kate monochrome breezedark haddock"
+complete -c pandoc -s v -l version -d "Print version"
+complete -c pandoc -s h -l help -d "Show help"
+
+.
+```
diff --git a/test/docx/golden/document-properties.docx b/test/docx/golden/document-properties.docx
Binary files a/test/docx/golden/document-properties.docx and b/test/docx/golden/document-properties.docx differ
diff --git a/test/docx/sdt_elements.native b/test/docx/sdt_elements.native
--- a/test/docx/sdt_elements.native
+++ b/test/docx/sdt_elements.native
@@ -1,60 +1,62 @@
-[ Table
-    ( "" , [] , [] )
-    (Caption Nothing [])
-    [ ( AlignDefault , ColWidth 0.16167023554603854 )
-    , ( AlignDefault , ColWidth 0.16167023554603854 )
-    , ( AlignDefault , ColWidth 0.40920770877944324 )
-    ]
-    (TableHead
-       ( "" , [] , [] )
-       [ Row
-           ( "" , [] , [] )
-           [ Cell
-               ( "" , [] , [] )
-               AlignCenter
-               (RowSpan 1)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "col1Header" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignCenter
-               (RowSpan 1)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "col2Header" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignCenter
-               (RowSpan 1)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "col3Header" ] ] ]
-           ]
-       ])
-    [ TableBody
-        ( "" , [] , [] )
-        (RowHeadColumns 0)
-        []
-        [ Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "col1" , Space , Str "content" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "Body" , Space , Str "copy" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "col3" , Space , Str "content" ] ]
-            ]
-        ]
-    ]
-    (TableFoot ( "" , [] , [] ) [])
-]
+Pandoc
+  Meta { unMeta = fromList [] }
+  [ Table
+      ( "" , [] , [] )
+      (Caption Nothing [])
+      [ ( AlignCenter , ColWidth 0.16167023554603854 )
+      , ( AlignDefault , ColWidth 0.16167023554603854 )
+      , ( AlignDefault , ColWidth 0.40920770877944324 )
+      ]
+      (TableHead
+         ( "" , [] , [] )
+         [ Row
+             ( "" , [] , [] )
+             [ Cell
+                 ( "" , [] , [] )
+                 AlignCenter
+                 (RowSpan 1)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "col1Header" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignCenter
+                 (RowSpan 1)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "col2Header" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignCenter
+                 (RowSpan 1)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "col3Header" ] ] ]
+             ]
+         ])
+      [ TableBody
+          ( "" , [] , [] )
+          (RowHeadColumns 0)
+          []
+          [ Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "col1" , Space , Str "content" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "Body" , Space , Str "copy" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "col3" , Space , Str "content" ] ]
+              ]
+          ]
+      ]
+      (TableFoot ( "" , [] , [] ) [])
+  ]
diff --git a/test/docx/table_header_rowspan.native b/test/docx/table_header_rowspan.native
--- a/test/docx/table_header_rowspan.native
+++ b/test/docx/table_header_rowspan.native
@@ -1,542 +1,544 @@
-[ Table
-    ( "" , [] , [] )
-    (Caption Nothing [])
-    [ ( AlignLeft , ColWidth 0.30701754385964913 )
-    , ( AlignDefault , ColWidth 0.13645224171539963 )
-    , ( AlignDefault , ColWidth 0.10009746588693959 )
-    , ( AlignDefault , ColWidth 9.707602339181289e-2 )
-    , ( AlignDefault , ColWidth 7.719298245614035e-2 )
-    , ( AlignDefault , ColWidth 7.085769980506823e-2 )
-    , ( AlignDefault , ColWidth 7.09551656920078e-2 )
-    , ( AlignDefault , ColWidth 0.14035087719298248 )
-    ]
-    (TableHead
-       ( "" , [] , [] )
-       [ Row
-           ( "" , [] , [] )
-           [ Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 2)
-               (ColSpan 1)
-               [ Plain [ Str "A" ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 2)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "B" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 2)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "C" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 2)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "D" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 1)
-               (ColSpan 3)
-               [ Plain [ Str "E" ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 2)
-               (ColSpan 1)
-               [ Plain [ Str "F" ] ]
-           ]
-       , Row
-           ( "" , [] , [] )
-           [ Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 1)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "G" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 1)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "H" ] ] ]
-           , Cell
-               ( "" , [] , [] )
-               AlignDefault
-               (RowSpan 1)
-               (ColSpan 1)
-               [ Plain [ Strong [ Str "I" ] ] ]
-           ]
-       ])
-    [ TableBody
-        ( "" , [] , [] )
-        (RowHeadColumns 0)
-        []
-        [ Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        , Row
-            ( "" , [] , [] )
-            [ Cell
-                ( "" , [] , [] )
-                AlignLeft
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "1" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "2" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "3" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "4" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "5" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "6" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "7" ] ]
-            , Cell
-                ( "" , [] , [] )
-                AlignDefault
-                (RowSpan 1)
-                (ColSpan 1)
-                [ Plain [ Str "8" ] ]
-            ]
-        ]
-    ]
-    (TableFoot ( "" , [] , [] ) [])
-]
+Pandoc
+  Meta { unMeta = fromList [] }
+  [ Table
+      ( "" , [] , [] )
+      (Caption Nothing [])
+      [ ( AlignDefault , ColWidth 0.30701754385964913 )
+      , ( AlignDefault , ColWidth 0.13645224171539963 )
+      , ( AlignDefault , ColWidth 0.10009746588693959 )
+      , ( AlignDefault , ColWidth 9.707602339181289e-2 )
+      , ( AlignDefault , ColWidth 7.719298245614035e-2 )
+      , ( AlignDefault , ColWidth 7.085769980506823e-2 )
+      , ( AlignDefault , ColWidth 7.09551656920078e-2 )
+      , ( AlignDefault , ColWidth 0.14035087719298248 )
+      ]
+      (TableHead
+         ( "" , [] , [] )
+         [ Row
+             ( "" , [] , [] )
+             [ Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 2)
+                 (ColSpan 1)
+                 [ Plain [ Str "A" ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 2)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "B" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 2)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "C" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 2)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "D" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 1)
+                 (ColSpan 3)
+                 [ Plain [ Str "E" ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 2)
+                 (ColSpan 1)
+                 [ Plain [ Str "F" ] ]
+             ]
+         , Row
+             ( "" , [] , [] )
+             [ Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 1)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "G" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 1)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "H" ] ] ]
+             , Cell
+                 ( "" , [] , [] )
+                 AlignDefault
+                 (RowSpan 1)
+                 (ColSpan 1)
+                 [ Plain [ Strong [ Str "I" ] ] ]
+             ]
+         ])
+      [ TableBody
+          ( "" , [] , [] )
+          (RowHeadColumns 0)
+          []
+          [ Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          , Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignLeft
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "1" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "2" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "3" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "4" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "5" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "6" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "7" ] ]
+              , Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Plain [ Str "8" ] ]
+              ]
+          ]
+      ]
+      (TableFoot ( "" , [] , [] ) [])
+  ]
diff --git a/test/rtf/table_nested.native b/test/rtf/table_nested.native
new file mode 100644
--- /dev/null
+++ b/test/rtf/table_nested.native
@@ -0,0 +1,129 @@
+Pandoc
+  Meta { unMeta = fromList [] }
+  [ Table
+      ( "" , [] , [] )
+      (Caption Nothing [])
+      [ ( AlignDefault , ColWidthDefault ) ]
+      (TableHead ( "" , [] , [] ) [])
+      [ TableBody
+          ( "" , [] , [] )
+          (RowHeadColumns 0)
+          []
+          [ Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Table
+                      ( "" , [] , [] )
+                      (Caption Nothing [])
+                      [ ( AlignDefault , ColWidthDefault ) ]
+                      (TableHead ( "" , [] , [] ) [])
+                      [ TableBody
+                          ( "" , [] , [] )
+                          (RowHeadColumns 0)
+                          []
+                          [ Row
+                              ( "" , [] , [] )
+                              [ Cell
+                                  ( "" , [] , [] )
+                                  AlignDefault
+                                  (RowSpan 1)
+                                  (ColSpan 1)
+                                  [ Para
+                                      [ Str "Level"
+                                      , Space
+                                      , Str "two"
+                                      , Space
+                                      , Str "before"
+                                      ]
+                                  , Table
+                                      ( "" , [] , [] )
+                                      (Caption Nothing [])
+                                      [ ( AlignDefault
+                                        , ColWidthDefault
+                                        )
+                                      , ( AlignDefault
+                                        , ColWidthDefault
+                                        )
+                                      ]
+                                      (TableHead ( "" , [] , [] ) [])
+                                      [ TableBody
+                                          ( "" , [] , [] )
+                                          (RowHeadColumns 0)
+                                          []
+                                          [ Row
+                                              ( "" , [] , [] )
+                                              [ Cell
+                                                  ( "" , [] , [] )
+                                                  AlignDefault
+                                                  (RowSpan 1)
+                                                  (ColSpan 1)
+                                                  [ Para
+                                                      [ Str "Deep"
+                                                      , Space
+                                                      , Str "A"
+                                                      ]
+                                                  ]
+                                              , Cell
+                                                  ( "" , [] , [] )
+                                                  AlignDefault
+                                                  (RowSpan 1)
+                                                  (ColSpan 1)
+                                                  [ Para
+                                                      [ Str "Deep"
+                                                      , Space
+                                                      , Str "B"
+                                                      ]
+                                                  ]
+                                              ]
+                                          , Row
+                                              ( "" , [] , [] )
+                                              [ Cell
+                                                  ( "" , [] , [] )
+                                                  AlignDefault
+                                                  (RowSpan 1)
+                                                  (ColSpan 1)
+                                                  [ Para
+                                                      [ Str "Deep"
+                                                      , Space
+                                                      , Str "C"
+                                                      ]
+                                                  ]
+                                              , Cell
+                                                  ( "" , [] , [] )
+                                                  AlignDefault
+                                                  (RowSpan 1)
+                                                  (ColSpan 1)
+                                                  [ Para
+                                                      [ Str "Deep"
+                                                      , Space
+                                                      , Str "D"
+                                                      ]
+                                                  ]
+                                              ]
+                                          ]
+                                      ]
+                                      (TableFoot ( "" , [] , [] ) [])
+                                  , Para
+                                      [ Str "Level"
+                                      , Space
+                                      , Str "two"
+                                      , Space
+                                      , Str "after"
+                                      ]
+                                  ]
+                              ]
+                          ]
+                      ]
+                      (TableFoot ( "" , [] , [] ) [])
+                  , Para [ Str "Outer" , Space , Str "after" ]
+                  ]
+              ]
+          ]
+      ]
+      (TableFoot ( "" , [] , [] ) [])
+  , Para [ Str "Outside" , Space , Str "table" ]
+  ]
diff --git a/test/rtf/table_nested.rtf b/test/rtf/table_nested.rtf
new file mode 100644
--- /dev/null
+++ b/test/rtf/table_nested.rtf
@@ -0,0 +1,16 @@
+{\rtf1\ansi
+\trowd\cellx5000
+\pard\intbl\itap2 Level two before\par
+\pard\intbl\itap3 Deep A\nestcell Deep B\nestcell
+{\*\nesttableprops\trowd\cellx2000\cellx4000\nestrow}
+{\nonesttables NESTED FALLBACK ONE\par}
+\pard\intbl\itap3 Deep C\nestcell Deep D\nestcell
+{\*\nesttableprops\trowd\cellx2000\cellx4000\nestrow}
+{\nonesttables NESTED FALLBACK TWO\par}
+\pard\intbl\itap2 Level two after\nestcell
+{\*\nesttableprops\trowd\cellx4000\nestrow}
+{\nonesttables PARENT FALLBACK\par}
+\pard\intbl\itap1 Outer after\cell
+\row
+\pard\itap0 Outside table\par
+}
diff --git a/test/rtf/table_nested_malformed_itap.native b/test/rtf/table_nested_malformed_itap.native
new file mode 100644
--- /dev/null
+++ b/test/rtf/table_nested_malformed_itap.native
@@ -0,0 +1,89 @@
+Pandoc
+  Meta { unMeta = fromList [] }
+  [ Table
+      ( "" , [] , [] )
+      (Caption Nothing [])
+      [ ( AlignDefault , ColWidthDefault ) ]
+      (TableHead ( "" , [] , [] ) [])
+      [ TableBody
+          ( "" , [] , [] )
+          (RowHeadColumns 0)
+          []
+          [ Row
+              ( "" , [] , [] )
+              [ Cell
+                  ( "" , [] , [] )
+                  AlignDefault
+                  (RowSpan 1)
+                  (ColSpan 1)
+                  [ Table
+                      ( "" , [] , [] )
+                      (Caption Nothing [])
+                      [ ( AlignDefault , ColWidthDefault ) ]
+                      (TableHead ( "" , [] , [] ) [])
+                      [ TableBody
+                          ( "" , [] , [] )
+                          (RowHeadColumns 0)
+                          []
+                          [ Row
+                              ( "" , [] , [] )
+                              [ Cell
+                                  ( "" , [] , [] )
+                                  AlignDefault
+                                  (RowSpan 1)
+                                  (ColSpan 1)
+                                  [ Para
+                                      [ Str "Parent"
+                                      , Space
+                                      , Str "before"
+                                      ]
+                                  , Table
+                                      ( "" , [] , [] )
+                                      (Caption Nothing [])
+                                      [ ( AlignDefault
+                                        , ColWidthDefault
+                                        )
+                                      ]
+                                      (TableHead ( "" , [] , [] ) [])
+                                      [ TableBody
+                                          ( "" , [] , [] )
+                                          (RowHeadColumns 0)
+                                          []
+                                          [ Row
+                                              ( "" , [] , [] )
+                                              [ Cell
+                                                  ( "" , [] , [] )
+                                                  AlignDefault
+                                                  (RowSpan 1)
+                                                  (ColSpan 1)
+                                                  [ Para
+                                                      [ Str "Child"
+                                                      , Space
+                                                      , Str "at"
+                                                      , Space
+                                                      , Str "skipped"
+                                                      , Space
+                                                      , Str "level"
+                                                      ]
+                                                  ]
+                                              ]
+                                          ]
+                                      ]
+                                      (TableFoot ( "" , [] , [] ) [])
+                                  , Para
+                                      [ Str "Parent"
+                                      , Space
+                                      , Str "after"
+                                      ]
+                                  ]
+                              ]
+                          ]
+                      ]
+                      (TableFoot ( "" , [] , [] ) [])
+                  , Para [ Str "Outer" , Space , Str "cell" ]
+                  ]
+              ]
+          ]
+      ]
+      (TableFoot ( "" , [] , [] ) [])
+  ]
diff --git a/test/rtf/table_nested_malformed_itap.rtf b/test/rtf/table_nested_malformed_itap.rtf
new file mode 100644
--- /dev/null
+++ b/test/rtf/table_nested_malformed_itap.rtf
@@ -0,0 +1,10 @@
+{\rtf1\ansi
+\trowd\cellx5000
+\pard\intbl\itap2 Parent before\par
+\pard\intbl\itap5 Child at skipped level\nestcell
+{\*\nesttableprops\trowd\cellx4000\nestrow}
+\pard\intbl\itap2 Parent after\nestcell
+{\*\nesttableprops\trowd\cellx4000\nestrow}
+\pard\intbl\itap1 Outer cell\cell
+\row
+}
diff --git a/test/s5-basic.html b/test/s5-basic.html
--- a/test/s5-basic.html
+++ b/test/s5-basic.html
@@ -31,7 +31,6 @@
       margin: 0 0.8em 0.2em -1.6em;
       vertical-align: middle;
     }
-    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
   </style>
   <!-- configuration parameters -->
   <meta name="defaultView" content="slideshow" />
@@ -70,8 +69,7 @@
 <div id="math" class="slide section level1">
 <h1>Math</h1>
 <ul>
-<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to
-0}\frac{f(x+h)-f(x)}{h}$</span></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mrow><mi mathvariant="normal">lim</mi><mo>&#8289;</mo></mrow><mrow><mi>h</mi><mo>→</mo><mn>0</mn></mrow></msub><mfrac><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><mi>h</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</annotation></semantics></math></li>
 </ul>
 </div>
 </div>
diff --git a/test/s5-fragment.html b/test/s5-fragment.html
--- a/test/s5-fragment.html
+++ b/test/s5-fragment.html
@@ -5,6 +5,5 @@
 </ul>
 <h1 id="math">Math</h1>
 <ul>
-<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to
-0}\frac{f(x+h)-f(x)}{h}$</span></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mrow><mi mathvariant="normal">lim</mi><mo>&#8289;</mo></mrow><mrow><mi>h</mi><mo>→</mo><mn>0</mn></mrow></msub><mfrac><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><mi>h</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</annotation></semantics></math></li>
 </ul>
diff --git a/test/s5-inserts.html b/test/s5-inserts.html
--- a/test/s5-inserts.html
+++ b/test/s5-inserts.html
@@ -29,7 +29,6 @@
       margin: 0 0.8em 0.2em -1.6em;
       vertical-align: middle;
     }
-    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
   </style>
   <link rel="stylesheet" href="main.css" type="text/css" />
   STUFF INSERTED
@@ -49,8 +48,7 @@
 </ul>
 <h1 id="math">Math</h1>
 <ul>
-<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to
-0}\frac{f(x+h)-f(x)}{h}$</span></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mrow><mi mathvariant="normal">lim</mi><mo>&#8289;</mo></mrow><mrow><mi>h</mi><mo>→</mo><mn>0</mn></mrow></msub><mfrac><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><mi>h</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</annotation></semantics></math></li>
 </ul>
 STUFF INSERTED
 </body>
diff --git a/test/writer.djot b/test/writer.djot
--- a/test/writer.djot
+++ b/test/writer.djot
@@ -418,10 +418,46 @@
 
 Interpreted markdown in a table:
 
+```=html
+<table>
+```
+
+```=html
+<tr>
+```
+
+```=html
+<td>
+```
+
 This is _emphasized_
 
+```=html
+</td>
+```
+
+```=html
+<td>
+```
+
 And this is *strong*
 
+```=html
+</td>
+```
+
+```=html
+</tr>
+```
+
+```=html
+</table>
+```
+
+```=html
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+```
+
 Here's a simple block:
 
 :::
@@ -458,8 +494,25 @@
 
 This should just be an HTML comment:
 
+```=html
+<!-- Comment -->
+```
+
 Multiline:
 
+```=html
+<!--
+Blah
+Blah
+-->
+```
+
+```=html
+<!--
+    This is another comment.
+-->
+```
+
 Code block:
 
 ```
@@ -468,6 +521,10 @@
 
 Just plain comment, with trailing spaces on the line:
 
+```=html
+<!-- foo -->
+```
+
 Code:
 
 ```
@@ -476,6 +533,42 @@
 
 Hr's:
 
+```=html
+<hr>
+```
+
+```=html
+<hr />
+```
+
+```=html
+<hr />
+```
+
+```=html
+<hr>
+```
+
+```=html
+<hr />
+```
+
+```=html
+<hr />
+```
+
+```=html
+<hr class="foo" id="bar" />
+```
+
+```=html
+<hr class="foo" id="bar" />
+```
+
+```=html
+<hr class="foo" id="bar">
+```
+
 * * * *
 
 {#inline-markup}
@@ -533,7 +626,7 @@
 {#latex}
 # LaTeX
 
--
+- `\cite[22-23]{smith.1899}`{=tex}
 - $`2+2=4`
 - $`x \in y`
 - $`\alpha \wedge \omega`
@@ -552,6 +645,14 @@
 - Escaped `$`\: $73 _this should be emphasized_ 23$.
 
 Here's a LaTeX table:
+
+```=tex
+\begin{tabular}{|l|l|}\hline
+Animal & Number \\ \hline
+Dog    & 2      \\
+Cat    & 1      \\ \hline
+\end{tabular}
+```
 
 * * * *
 
diff --git a/test/writer.docbook4 b/test/writer.docbook4
--- a/test/writer.docbook4
+++ b/test/writer.docbook4
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-                  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook EBNF Module V1.1CR1//EN"
+                  "http://www.oasis-open.org/docbook/xml/mathml/1.1CR1/dbmathml.dtd">
 <article>
   <articleinfo>
     <title>Pandoc Test Suite</title>
@@ -1052,39 +1052,39 @@
       </listitem>
       <listitem>
         <para>
-          2 + 2 = 4
+          <inlineequation><mml:math><mml:mrow><mml:mn>2</mml:mn><mml:mo>+</mml:mo><mml:mn>2</mml:mn><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
+          <inlineequation><mml:math><mml:mrow><mml:mi>x</mml:mi><mml:mo>∈</mml:mo><mml:mi>y</mml:mi></mml:mrow></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          <emphasis>α</emphasis> ∧ <emphasis>ω</emphasis>
+          <inlineequation><mml:math><mml:mrow><mml:mi>α</mml:mi><mml:mo>∧</mml:mo><mml:mi>ω</mml:mi></mml:mrow></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          223
+          <inlineequation><mml:math><mml:mn>223</mml:mn></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          <emphasis>p</emphasis>-Tree
+          <inlineequation><mml:math><mml:mi>p</mml:mi></mml:math></inlineequation>-Tree
         </para>
       </listitem>
       <listitem>
         <para>
           Here’s some display math:
-          $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+          <informalequation><mml:math><mml:mrow><mml:mfrac><mml:mi>d</mml:mi><mml:mrow><mml:mi>d</mml:mi><mml:mi>x</mml:mi></mml:mrow></mml:mfrac><mml:mi>f</mml:mi><mml:mo mml:stretchy="false" mml:form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo mml:stretchy="false" mml:form="postfix">)</mml:mo><mml:mo>=</mml:mo><mml:munder><mml:mi mml:mathvariant="normal">lim</mml:mi><mml:mrow><mml:mi>h</mml:mi><mml:mo>→</mml:mo><mml:mn>0</mml:mn></mml:mrow></mml:munder><mml:mfrac><mml:mrow><mml:mi>f</mml:mi><mml:mo mml:stretchy="false" mml:form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo>+</mml:mo><mml:mi>h</mml:mi><mml:mo mml:stretchy="false" mml:form="postfix">)</mml:mo><mml:mo>−</mml:mo><mml:mi>f</mml:mi><mml:mo mml:stretchy="false" mml:form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo mml:stretchy="false" mml:form="postfix">)</mml:mo></mml:mrow><mml:mi>h</mml:mi></mml:mfrac></mml:mrow></mml:math></informalequation>
         </para>
       </listitem>
       <listitem>
         <para>
           Here’s one that has a line break in it:
-          <emphasis>α</emphasis> + <emphasis>ω</emphasis> × <emphasis>x</emphasis><superscript>2</superscript>.
+          <inlineequation><mml:math><mml:mrow><mml:mi>α</mml:mi><mml:mo>+</mml:mo><mml:mi>ω</mml:mi><mml:mo>×</mml:mo><mml:msup><mml:mi>x</mml:mi><mml:mn>2</mml:mn></mml:msup></mml:mrow></mml:math></inlineequation>.
         </para>
       </listitem>
     </itemizedlist>
diff --git a/test/writer.docbook5 b/test/writer.docbook5
--- a/test/writer.docbook5
+++ b/test/writer.docbook5
@@ -2,6 +2,7 @@
 <!DOCTYPE article>
 <article
   xmlns="http://docbook.org/ns/docbook" version="5.0"
+  xmlns:mml="http://www.w3.org/1998/Math/MathML"
   xmlns:xlink="http://www.w3.org/1999/xlink" >
   <info>
     <title>Pandoc Test Suite</title>
@@ -1027,39 +1028,39 @@
       </listitem>
       <listitem>
         <para>
-          2 + 2 = 4
+          <inlineequation><mml:math><mml:mrow><mml:mn>2</mml:mn><mml:mo>+</mml:mo><mml:mn>2</mml:mn><mml:mo>=</mml:mo><mml:mn>4</mml:mn></mml:mrow></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          <emphasis>x</emphasis> ∈ <emphasis>y</emphasis>
+          <inlineequation><mml:math><mml:mrow><mml:mi>x</mml:mi><mml:mo>∈</mml:mo><mml:mi>y</mml:mi></mml:mrow></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          <emphasis>α</emphasis> ∧ <emphasis>ω</emphasis>
+          <inlineequation><mml:math><mml:mrow><mml:mi>α</mml:mi><mml:mo>∧</mml:mo><mml:mi>ω</mml:mi></mml:mrow></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          223
+          <inlineequation><mml:math><mml:mn>223</mml:mn></mml:math></inlineequation>
         </para>
       </listitem>
       <listitem>
         <para>
-          <emphasis>p</emphasis>-Tree
+          <inlineequation><mml:math><mml:mi>p</mml:mi></mml:math></inlineequation>-Tree
         </para>
       </listitem>
       <listitem>
         <para>
           Here’s some display math:
-          $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
+          <informalequation><mml:math><mml:mrow><mml:mfrac><mml:mi>d</mml:mi><mml:mrow><mml:mi>d</mml:mi><mml:mi>x</mml:mi></mml:mrow></mml:mfrac><mml:mi>f</mml:mi><mml:mo mml:stretchy="false" mml:form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo mml:stretchy="false" mml:form="postfix">)</mml:mo><mml:mo>=</mml:mo><mml:munder><mml:mi mml:mathvariant="normal">lim</mml:mi><mml:mrow><mml:mi>h</mml:mi><mml:mo>→</mml:mo><mml:mn>0</mml:mn></mml:mrow></mml:munder><mml:mfrac><mml:mrow><mml:mi>f</mml:mi><mml:mo mml:stretchy="false" mml:form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo>+</mml:mo><mml:mi>h</mml:mi><mml:mo mml:stretchy="false" mml:form="postfix">)</mml:mo><mml:mo>−</mml:mo><mml:mi>f</mml:mi><mml:mo mml:stretchy="false" mml:form="prefix">(</mml:mo><mml:mi>x</mml:mi><mml:mo mml:stretchy="false" mml:form="postfix">)</mml:mo></mml:mrow><mml:mi>h</mml:mi></mml:mfrac></mml:mrow></mml:math></informalequation>
         </para>
       </listitem>
       <listitem>
         <para>
           Here’s one that has a line break in it:
-          <emphasis>α</emphasis> + <emphasis>ω</emphasis> × <emphasis>x</emphasis><superscript>2</superscript>.
+          <inlineequation><mml:math><mml:mrow><mml:mi>α</mml:mi><mml:mo>+</mml:mo><mml:mi>ω</mml:mi><mml:mo>×</mml:mo><mml:msup><mml:mi>x</mml:mi><mml:mn>2</mml:mn></mml:msup></mml:mrow></mml:math></inlineequation>.
         </para>
       </listitem>
     </itemizedlist>
diff --git a/test/writer.html4 b/test/writer.html4
--- a/test/writer.html4
+++ b/test/writer.html4
@@ -174,7 +174,6 @@
       margin: 0 0.8em 0.2em -1.6em;
       vertical-align: middle;
     }
-    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
   </style>
 </head>
 <body>
@@ -618,16 +617,15 @@
 <h1 id="latex">LaTeX</h1>
 <ul>
 <li></li>
-<li><span class="math inline">2 + 2 = 4</span></li>
-<li><span class="math inline"><em>x</em> ∈ <em>y</em></span></li>
-<li><span class="math inline"><em>α</em> ∧ <em>ω</em></span></li>
-<li><span class="math inline">223</span></li>
-<li><span class="math inline"><em>p</em></span>-Tree</li>
-<li>Here’s some display math: <span
-class="math display">$$\frac{d}{dx}f(x)=\lim_{h\to
-0}\frac{f(x+h)-f(x)}{h}$$</span></li>
-<li>Here’s one that has a line break in it: <span
-class="math inline"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>+</mo><mn>2</mn><mo>=</mo><mn>4</mn></mrow><annotation encoding="application/x-tex">2+2=4</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>∈</mo><mi>y</mi></mrow><annotation encoding="application/x-tex">x \in y</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi><mo>∧</mo><mi>ω</mi></mrow><annotation encoding="application/x-tex">\alpha \wedge \omega</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>223</mn><annotation encoding="application/x-tex">223</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>p</mi><annotation encoding="application/x-tex">p</annotation></semantics></math>-Tree</li>
+<li>Here’s some display math:
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><munder><mi mathvariant="normal">lim</mi><mrow><mi>h</mi><mo>→</mo><mn>0</mn></mrow></munder><mfrac><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><mi>h</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</annotation></semantics></math></li>
+<li>Here’s one that has a line break in it:
+<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi><mo>+</mo><mi>ω</mi><mo>×</mo><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\alpha + \omega \times x^2</annotation></semantics></math>.</li>
 </ul>
 <p>These shouldn’t be math:</p>
 <ul>
diff --git a/test/writer.html5 b/test/writer.html5
--- a/test/writer.html5
+++ b/test/writer.html5
@@ -174,7 +174,6 @@
       margin: 0 0.8em 0.2em -1.6em;
       vertical-align: middle;
     }
-    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
   </style>
 </head>
 <body>
@@ -618,16 +617,15 @@
 <h1 id="latex">LaTeX</h1>
 <ul>
 <li></li>
-<li><span class="math inline">2 + 2 = 4</span></li>
-<li><span class="math inline"><em>x</em> ∈ <em>y</em></span></li>
-<li><span class="math inline"><em>α</em> ∧ <em>ω</em></span></li>
-<li><span class="math inline">223</span></li>
-<li><span class="math inline"><em>p</em></span>-Tree</li>
-<li>Here’s some display math: <span
-class="math display">$$\frac{d}{dx}f(x)=\lim_{h\to
-0}\frac{f(x+h)-f(x)}{h}$$</span></li>
-<li>Here’s one that has a line break in it: <span
-class="math inline"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>+</mo><mn>2</mn><mo>=</mo><mn>4</mn></mrow><annotation encoding="application/x-tex">2+2=4</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>∈</mo><mi>y</mi></mrow><annotation encoding="application/x-tex">x \in y</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi><mo>∧</mo><mi>ω</mi></mrow><annotation encoding="application/x-tex">\alpha \wedge \omega</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>223</mn><annotation encoding="application/x-tex">223</annotation></semantics></math></li>
+<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>p</mi><annotation encoding="application/x-tex">p</annotation></semantics></math>-Tree</li>
+<li>Here’s some display math:
+<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><munder><mi mathvariant="normal">lim</mi><mrow><mi>h</mi><mo>→</mo><mn>0</mn></mrow></munder><mfrac><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><mi>h</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</annotation></semantics></math></li>
+<li>Here’s one that has a line break in it:
+<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi><mo>+</mo><mi>ω</mi><mo>×</mo><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\alpha + \omega \times x^2</annotation></semantics></math>.</li>
 </ul>
 <p>These shouldn’t be math:</p>
 <ul>
