diff --git a/AUTHORS.md b/AUTHORS.md
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -66,6 +66,7 @@
 - Douglas Calvert
 - Eigil Rischel
 - Emanuel Evans
+- Emerson Harkin
 - Emily Eisenberg
 - Eric Kow
 - Eric Seidel
@@ -241,6 +242,7 @@
 - Urs Liska
 - Václav Zeman
 - Václav Haisman
+- Vaibhav Sagar
 - Vanessa McHale
 - Vasily Alferov
 - Viktor Kronvall
@@ -264,6 +266,7 @@
 - dbecher-ito
 - d-dorazio
 - ebiim
+- favonia
 - infinity0x
 - jeongminkim-islab
 - kaizshang91
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,8 +17,14 @@
 to make sure the issue hasn't come up before. Also, check the [User's Guide] and
 [FAQs] for anything relevant.
 
-Make sure you can reproduce the bug with the [latest released version] of pandoc
-(or, even better, the [development version]).
+Make sure you can reproduce the bug with the [latest released
+version] of pandoc---or, even better, the development version,
+since the bug may have been fixed since the last release.
+[Nightly builds] are available, so you don't need to compile
+from source to test againt the development version.
+(To fetch a nightly, visit the link, click the topmost "Nightly"
+in the table, then choose your platform under "Artifacts."  Note
+that you must be logged in with a GitHub account.)
 
 Your report should give detailed, *reproducible* instructions, including
 
@@ -346,7 +352,7 @@
 [open issues]: https://github.com/jgm/pandoc/issues
 [closed issues]: https://github.com/jgm/pandoc/issues?q=is%3Aissue+is%3Aclosed
 [latest released version]: https://github.com/jgm/pandoc/releases/latest
-[development version]: https://github.com/pandoc-extras/pandoc-nightly/releases/latest
+[Nightly builds]: https://github.com/jgm/pandoc/actions?query=workflow%3ANightly
 [pandoc-discuss]: http://groups.google.com/group/pandoc-discuss
 [issue tracker]: https://github.com/jgm/pandoc/issues
 [User's Guide]: http://pandoc.org/MANUAL.html
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: June 29, 2020
+date: July 23, 2020
 ---
 
 # Synopsis
@@ -226,6 +226,7 @@
 
     ::: {#input-formats}
     - `commonmark` ([CommonMark] Markdown)
+    - `commonmark_x` ([CommonMark] Markdown with extensions)
     - `creole` ([Creole 1.0])
     - `csv` ([CSV] table)
     - `docbook` ([DocBook])
@@ -277,6 +278,7 @@
     - `asciidoc` ([AsciiDoc]) or `asciidoctor` ([AsciiDoctor])
     - `beamer` ([LaTeX beamer][`beamer`] slide show)
     - `commonmark` ([CommonMark] Markdown)
+    - `commonmark_x` ([CommonMark] Markdown with extensions)
     - `context` ([ConTeXt])
     - `docbook` or `docbook4` ([DocBook] 4)
     - `docbook5` (DocBook 5)
@@ -902,7 +904,7 @@
     downloaded). If you're behind a proxy, you also need to set
     the environment variable `http_proxy` to `http://...`.
 
-`--no-check-certificate
+`--no-check-certificate`
 
 :   Disable the certificate verification to allow access to 
     unsecure HTTP resources (for example when the certificate
@@ -980,7 +982,7 @@
 
 `-N`, `--number-sections`
 
-:   Number section headings in LaTeX, ConTeXt, HTML, or EPUB output.
+:   Number section headings in LaTeX, ConTeXt, HTML, Docx, or EPUB output.
     By default, sections are not numbered.  Sections with class
     `unnumbered` will never be numbered, even if `--number-sections`
     is specified.
@@ -1123,6 +1125,7 @@
         - Verbatim Char
         - Footnote Reference
         - Hyperlink
+        - Section Number
 
         Table style:
 
@@ -2767,53 +2770,43 @@
 
 ## Raw HTML/TeX
 
-The following extensions (especially how they affect Markdown
-input/output) are also described in more detail in their respective
-sections of [Pandoc's Markdown].
-
-#### Extension: `raw_html` {#raw_html}
-
-When converting from HTML, parse elements to raw HTML which are not
-representable in pandoc's AST.
-By default, this is disabled for HTML input.
-
-#### Extension: `raw_tex` {#raw_tex}
-
-Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
-
-This extension can be enabled/disabled for the following formats
-(in addition to `markdown`):
-
-input formats
-:  `latex`, `org`, `textile`, `html` (environments, `\ref`, and
-   `\eqref` only), `ipynb`
-
-output formats
-:  `textile`, `commonmark`
-
-Note: as applied to `ipynb`, `raw_html` and `raw_tex` affect not
-only raw TeX in markdown cells, but data with mime type
-`text/html` in output cells.  Since the `ipynb` reader attempts
-to preserve the richest possible outputs when several options
-are given, you will get best results if you disable `raw_html`
-and `raw_tex` when converting to formats like `docx` which don't
-allow raw `html` or `tex`.
+The following extensions are described in more detail in
+their respective sections of [Pandoc's Markdown]:
 
-#### Extension: `native_divs` {#native_divs}
+- [`raw_html`](#extension-raw_html) allows HTML elements which
+  are not representable in pandoc's AST to be parsed as raw HTML.
+  By default, this is disabled for HTML input.
 
-This extension is enabled by default for HTML input. This means that
-`div`s are parsed to pandoc native elements. (Alternatively, you
-can parse them to raw HTML using `-f html-native_divs+raw_html`.)
+- [`raw_tex`](#extension-raw_tex) allows raw LaTeX, TeX, and ConTeXt
+  to be included in a document.  This extension can be enabled/disabled
+  for the following formats (in addition to `markdown`):
 
-When converting HTML to Markdown, for example, you may want to drop all
-`div`s and `span`s:
+  input formats
+  :  `latex`, `org`, `textile`, `html` (environments, `\ref`, and
+     `\eqref` only), `ipynb`
 
-    pandoc -f html-native_divs-native_spans -t markdown
+  output formats
+  :  `textile`, `commonmark`
 
-#### Extension: `native_spans` {#native_spans}
+  Note: as applied to `ipynb`, `raw_html` and `raw_tex` affect not
+  only raw TeX in markdown cells, but data with mime type
+  `text/html` in output cells.  Since the `ipynb` reader attempts
+  to preserve the richest possible outputs when several options
+  are given, you will get best results if you disable `raw_html`
+  and `raw_tex` when converting to formats like `docx` which don't
+  allow raw `html` or `tex`.
 
-Analogous to `native_divs` above.
+- [`native_divs`](#extension-native_divs) causes HTML `div`
+  elements to be parsed as native pandoc Div blocks.
+  If you want them to be parsed as raw HTML, use
+  `-f html-native_divs+raw_html`.
 
+- [`native_spans`](#extension-native_spans) causes HTML `span`
+  elements to be parsed as native pandoc Span inlines.
+  If you want them to be parsed as raw HTML, use
+  `-f html-native_spans+raw_html`.  If you want to drop all
+  `div`s and `span`s when converting HTML to Markdown, you
+  can use `pandoc -f html-native_divs-native_spans -t markdown`.
 
 ## Literate Haskell support
 
@@ -2917,6 +2910,14 @@
 In the `muse` input format, this enables Text::Amuse
 extensions to Emacs Muse markup.
 
+#### Extension: `raw_markdown` ####
+
+In the `ipynb` input format, this causes Markdown cells
+to be included as raw Markdown blocks (allowing lossless
+round-tripping) rather than being parsed.  Use this only
+when you are targetting `ipynb` or a markdown-based
+output format.
+
 #### Extension: `citations` {#org-citations}
 
 Some aspects of [Pandoc's Markdown citation syntax](#citations) are also accepted
@@ -4943,6 +4944,37 @@
 name, where `EXTENSION` is the name of the extension.  Thus, for
 example, `markdown+hard_line_breaks` is Markdown with hard line breaks.
 
+#### Extension: `attributes` ####
+
+Allows attributes to be attached to any inline or block-level
+element.  The syntax for the attributes is the same as that
+used in [`header_attributes`][Extension: `header_attributes`].
+
+- Attributes that occur immediately after an inline
+  element affect that element.  If they follow a space, then they
+  belong to the space.  (Hence, this option subsumes
+  `inline_code_attributes` and `link_attributes`.)
+- Attributes that occur immediately before a block
+  element, on a line by themselves, affect that
+  element.
+- Consecutive attribute specifiers may be used,
+  either for blocks or for inlines.  Their attributes
+  will be combined.
+- Attributes that occur at the end of the text of
+  a Setext or ATX heading (separated by whitespace
+  from the text) affect the heading element. (Hence, this
+  option subsumes `header_attributes`.)
+- Attributes that occur after the opening fence
+  in a fenced code block affect the code block element. (Hence,
+  this option subsumes `fenced_code_attributes`.)
+- Attributes that occur at the end of a reference
+  link definition affect links that refer to that
+  definition.
+
+Note that pandoc's AST does not currently allow attributes
+to be attached to arbitrary elements.  Hence a Span or Div
+container will be added if needed.
+
 #### Extension: `old_dashes` ####
 
 Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
@@ -5141,7 +5173,8 @@
 only affects `gfm` output, not input.
 
 `gfm` (GitHub-Flavored Markdown)
-:   `pipe_tables`, `raw_html`, `fenced_code_blocks`, `auto_identifiers`,
+:   `pipe_tables`, `raw_html`, `native_divs`,
+    `fenced_code_blocks`, `auto_identifiers`,
     `gfm_auto_identifiers`, `backtick_code_blocks`,
     `autolink_bare_uris`, `space_in_atx_header`,
     `intraword_underscores`, `strikeout`, `task_lists`, `emoji`,
@@ -5633,7 +5666,6 @@
 foreword                          frontmatter
 preface                           frontmatter
 seriespage                        frontmatter
-titlepage                         frontmatter
 appendix                          backmatter
 colophon                          backmatter
 bibliography                      backmatter
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,7 +3,8 @@
 pandoc --lua-filter tools/update-readme.lua README.template -o README.md
 -->
 
-# Pandoc
+Pandoc
+======
 
 [![github
 release](https://img.shields.io/github/release/jgm/pandoc.svg?label=current+release)](https://github.com/jgm/pandoc/releases)
@@ -19,7 +20,8 @@
 [![pandoc-discuss on google
 groups](https://img.shields.io/badge/pandoc-discuss-red.svg?style=social)](https://groups.google.com/forum/#!forum/pandoc-discuss)
 
-## The universal markup converter
+The universal markup converter
+------------------------------
 
 Pandoc is a [Haskell](http://haskell.org) library for converting from
 one markup format to another, and a command-line tool that uses this
@@ -27,58 +29,60 @@
 
 <div id="input-formats">
 
-  - `commonmark` ([CommonMark](https://commonmark.org) Markdown)
-  - `creole` ([Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0))
-  - `csv` ([CSV](https://tools.ietf.org/html/rfc4180) table)
-  - `docbook` ([DocBook](https://docbook.org))
-  - `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML))
-  - `dokuwiki` ([DokuWiki markup](https://www.dokuwiki.org/dokuwiki))
-  - `epub` ([EPUB](http://idpf.org/epub))
-  - `fb2`
+-   `commonmark` ([CommonMark](https://commonmark.org) Markdown)
+-   `commonmark_x` ([CommonMark](https://commonmark.org) Markdown with
+    extensions)
+-   `creole` ([Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0))
+-   `csv` ([CSV](https://tools.ietf.org/html/rfc4180) table)
+-   `docbook` ([DocBook](https://docbook.org))
+-   `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML))
+-   `dokuwiki` ([DokuWiki markup](https://www.dokuwiki.org/dokuwiki))
+-   `epub` ([EPUB](http://idpf.org/epub))
+-   `fb2`
     ([FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1)
     e-book)
-  - `gfm` ([GitHub-Flavored
+-   `gfm` ([GitHub-Flavored
     Markdown](https://help.github.com/articles/github-flavored-markdown/)),
     or the deprecated and less accurate `markdown_github`; use
     [`markdown_github`](https://pandoc.org/MANUAL.html#markdown-variants)
     only if you need extensions not supported in
     [`gfm`](https://pandoc.org/MANUAL.html#markdown-variants).
-  - `haddock` ([Haddock
+-   `haddock` ([Haddock
     markup](https://www.haskell.org/haddock/doc/html/ch03s08.html))
-  - `html` ([HTML](https://www.w3.org/html/))
-  - `ipynb` ([Jupyter
+-   `html` ([HTML](https://www.w3.org/html/))
+-   `ipynb` ([Jupyter
     notebook](https://nbformat.readthedocs.io/en/latest/))
-  - `jats` ([JATS](https://jats.nlm.nih.gov) XML)
-  - `jira`
+-   `jats` ([JATS](https://jats.nlm.nih.gov) XML)
+-   `jira`
     ([Jira](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)/Confluence
     wiki markup)
-  - `json` (JSON version of native AST)
-  - `latex` ([LaTeX](https://www.latex-project.org/))
-  - `markdown` ([Pandoc’s
+-   `json` (JSON version of native AST)
+-   `latex` ([LaTeX](https://www.latex-project.org/))
+-   `markdown` ([Pandoc’s
     Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown))
-  - `markdown_mmd`
+-   `markdown_mmd`
     ([MultiMarkdown](https://fletcherpenney.net/multimarkdown/))
-  - `markdown_phpextra` ([PHP Markdown
+-   `markdown_phpextra` ([PHP Markdown
     Extra](https://michelf.ca/projects/php-markdown/extra/))
-  - `markdown_strict` (original unextended
+-   `markdown_strict` (original unextended
     [Markdown](https://daringfireball.net/projects/markdown/))
-  - `mediawiki` ([MediaWiki
+-   `mediawiki` ([MediaWiki
     markup](https://www.mediawiki.org/wiki/Help:Formatting))
-  - `man` ([roff man](https://man.cx/groff_man\(7\)))
-  - `muse` ([Muse](https://amusewiki.org/library/manual))
-  - `native` (native Haskell)
-  - `odt` ([ODT](https://en.wikipedia.org/wiki/OpenDocument))
-  - `opml` ([OPML](http://dev.opml.org/spec2.html))
-  - `org` ([Emacs Org mode](https://orgmode.org))
-  - `rst`
+-   `man` ([roff man](https://man.cx/groff_man(7)))
+-   `muse` ([Muse](https://amusewiki.org/library/manual))
+-   `native` (native Haskell)
+-   `odt` ([ODT](https://en.wikipedia.org/wiki/OpenDocument))
+-   `opml` ([OPML](http://dev.opml.org/spec2.html))
+-   `org` ([Emacs Org mode](https://orgmode.org))
+-   `rst`
     ([reStructuredText](https://docutils.sourceforge.io/docs/ref/rst/introduction.html))
-  - `t2t` ([txt2tags](https://txt2tags.org))
-  - `textile` ([Textile](https://www.promptworks.com/textile))
-  - `tikiwiki` ([TikiWiki
+-   `t2t` ([txt2tags](https://txt2tags.org))
+-   `textile` ([Textile](https://www.promptworks.com/textile))
+-   `tikiwiki` ([TikiWiki
     markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax))
-  - `twiki` ([TWiki
+-   `twiki` ([TWiki
     markup](https://twiki.org/cgi-bin/view/TWiki/TextFormattingRules))
-  - `vimwiki` ([Vimwiki](https://vimwiki.github.io))
+-   `vimwiki` ([Vimwiki](https://vimwiki.github.io))
 
 </div>
 
@@ -86,94 +90,96 @@
 
 <div id="output-formats">
 
-  - `asciidoc` ([AsciiDoc](https://www.methods.co.nz/asciidoc/)) or
+-   `asciidoc` ([AsciiDoc](https://www.methods.co.nz/asciidoc/)) or
     `asciidoctor` ([AsciiDoctor](https://asciidoctor.org/))
-  - `beamer` ([LaTeX beamer](https://ctan.org/pkg/beamer) slide show)
-  - `commonmark` ([CommonMark](https://commonmark.org) Markdown)
-  - `context` ([ConTeXt](https://www.contextgarden.net/))
-  - `docbook` or `docbook4` ([DocBook](https://docbook.org) 4)
-  - `docbook5` (DocBook 5)
-  - `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML))
-  - `dokuwiki` ([DokuWiki markup](https://www.dokuwiki.org/dokuwiki))
-  - `epub` or `epub3` ([EPUB](http://idpf.org/epub) v3 book)
-  - `epub2` (EPUB v2)
-  - `fb2`
+-   `beamer` ([LaTeX beamer](https://ctan.org/pkg/beamer) slide show)
+-   `commonmark` ([CommonMark](https://commonmark.org) Markdown)
+-   `commonmark_x` ([CommonMark](https://commonmark.org) Markdown with
+    extensions)
+-   `context` ([ConTeXt](https://www.contextgarden.net/))
+-   `docbook` or `docbook4` ([DocBook](https://docbook.org) 4)
+-   `docbook5` (DocBook 5)
+-   `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML))
+-   `dokuwiki` ([DokuWiki markup](https://www.dokuwiki.org/dokuwiki))
+-   `epub` or `epub3` ([EPUB](http://idpf.org/epub) v3 book)
+-   `epub2` (EPUB v2)
+-   `fb2`
     ([FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1)
     e-book)
-  - `gfm` ([GitHub-Flavored
+-   `gfm` ([GitHub-Flavored
     Markdown](https://help.github.com/articles/github-flavored-markdown/)),
     or the deprecated and less accurate `markdown_github`; use
     [`markdown_github`](https://pandoc.org/MANUAL.html#markdown-variants)
     only if you need extensions not supported in
     [`gfm`](https://pandoc.org/MANUAL.html#markdown-variants).
-  - `haddock` ([Haddock
+-   `haddock` ([Haddock
     markup](https://www.haskell.org/haddock/doc/html/ch03s08.html))
-  - `html` or `html5` ([HTML](https://www.w3.org/html/),
+-   `html` or `html5` ([HTML](https://www.w3.org/html/),
     i.e. [HTML5](https://html.spec.whatwg.org/)/XHTML [polyglot
     markup](https://www.w3.org/TR/html-polyglot/))
-  - `html4` ([XHTML](https://www.w3.org/TR/xhtml1/) 1.0 Transitional)
-  - `icml` ([InDesign
+-   `html4` ([XHTML](https://www.w3.org/TR/xhtml1/) 1.0 Transitional)
+-   `icml` ([InDesign
     ICML](https://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf))
-  - `ipynb` ([Jupyter
+-   `ipynb` ([Jupyter
     notebook](https://nbformat.readthedocs.io/en/latest/))
-  - `jats_archiving` ([JATS](https://jats.nlm.nih.gov) XML, Archiving
+-   `jats_archiving` ([JATS](https://jats.nlm.nih.gov) XML, Archiving
     and Interchange Tag Set)
-  - `jats_articleauthoring` ([JATS](https://jats.nlm.nih.gov) XML,
+-   `jats_articleauthoring` ([JATS](https://jats.nlm.nih.gov) XML,
     Article Authoring Tag Set)
-  - `jats_publishing` ([JATS](https://jats.nlm.nih.gov) XML, Journal
+-   `jats_publishing` ([JATS](https://jats.nlm.nih.gov) XML, Journal
     Publishing Tag Set)
-  - `jats` (alias for `jats_archiving`)
-  - `jira`
+-   `jats` (alias for `jats_archiving`)
+-   `jira`
     ([Jira](https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all)/Confluence
     wiki markup)
-  - `json` (JSON version of native AST)
-  - `latex` ([LaTeX](https://www.latex-project.org/))
-  - `man` ([roff man](https://man.cx/groff_man\(7\)))
-  - `markdown` ([Pandoc’s
+-   `json` (JSON version of native AST)
+-   `latex` ([LaTeX](https://www.latex-project.org/))
+-   `man` ([roff man](https://man.cx/groff_man(7)))
+-   `markdown` ([Pandoc’s
     Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown))
-  - `markdown_mmd`
+-   `markdown_mmd`
     ([MultiMarkdown](https://fletcherpenney.net/multimarkdown/))
-  - `markdown_phpextra` ([PHP Markdown
+-   `markdown_phpextra` ([PHP Markdown
     Extra](https://michelf.ca/projects/php-markdown/extra/))
-  - `markdown_strict` (original unextended
+-   `markdown_strict` (original unextended
     [Markdown](https://daringfireball.net/projects/markdown/))
-  - `mediawiki` ([MediaWiki
+-   `mediawiki` ([MediaWiki
     markup](https://www.mediawiki.org/wiki/Help:Formatting))
-  - `ms` ([roff ms](https://man.cx/groff_ms\(7\)))
-  - `muse` ([Muse](https://amusewiki.org/library/manual)),
-  - `native` (native Haskell),
-  - `odt` ([OpenOffice text
+-   `ms` ([roff ms](https://man.cx/groff_ms(7)))
+-   `muse` ([Muse](https://amusewiki.org/library/manual)),
+-   `native` (native Haskell),
+-   `odt` ([OpenOffice text
     document](https://en.wikipedia.org/wiki/OpenDocument))
-  - `opml` ([OPML](http://dev.opml.org/spec2.html))
-  - `opendocument` ([OpenDocument](http://opendocument.xml.org))
-  - `org` ([Emacs Org mode](https://orgmode.org))
-  - `pdf` ([PDF](https://www.adobe.com/pdf/))
-  - `plain` (plain text),
-  - `pptx`
+-   `opml` ([OPML](http://dev.opml.org/spec2.html))
+-   `opendocument` ([OpenDocument](http://opendocument.xml.org))
+-   `org` ([Emacs Org mode](https://orgmode.org))
+-   `pdf` ([PDF](https://www.adobe.com/pdf/))
+-   `plain` (plain text),
+-   `pptx`
     ([PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint)
     slide show)
-  - `rst`
+-   `rst`
     ([reStructuredText](https://docutils.sourceforge.io/docs/ref/rst/introduction.html))
-  - `rtf` ([Rich Text
+-   `rtf` ([Rich Text
     Format](https://en.wikipedia.org/wiki/Rich_Text_Format))
-  - `texinfo` ([GNU Texinfo](https://www.gnu.org/software/texinfo/))
-  - `textile` ([Textile](https://www.promptworks.com/textile))
-  - `slideous` ([Slideous](https://goessner.net/articles/slideous/) HTML
+-   `texinfo` ([GNU Texinfo](https://www.gnu.org/software/texinfo/))
+-   `textile` ([Textile](https://www.promptworks.com/textile))
+-   `slideous` ([Slideous](https://goessner.net/articles/slideous/) HTML
     and JavaScript slide show)
-  - `slidy` ([Slidy](https://www.w3.org/Talks/Tools/Slidy2/) HTML and
+-   `slidy` ([Slidy](https://www.w3.org/Talks/Tools/Slidy2/) HTML and
     JavaScript slide show)
-  - `dzslides` ([DZSlides](http://paulrouget.com/dzslides/) HTML5 +
+-   `dzslides` ([DZSlides](http://paulrouget.com/dzslides/) HTML5 +
     JavaScript slide show),
-  - `revealjs` ([reveal.js](https://revealjs.com/) HTML5 + JavaScript
+-   `revealjs` ([reveal.js](https://revealjs.com/) HTML5 + JavaScript
     slide show)
-  - `s5` ([S5](https://meyerweb.com/eric/tools/s5/) HTML and JavaScript
+-   `s5` ([S5](https://meyerweb.com/eric/tools/s5/) HTML and JavaScript
     slide show)
-  - `tei` ([TEI Simple](https://github.com/TEIC/TEI-Simple))
-  - `xwiki` ([XWiki
+-   `tei` ([TEI Simple](https://github.com/TEIC/TEI-Simple))
+-   `xwiki` ([XWiki
     markup](https://www.xwiki.org/xwiki/bin/view/Documentation/UserGuide/Features/XWikiSyntax/))
-  - `zimwiki` ([ZimWiki
+-   `zimwiki` ([ZimWiki
     markup](https://zim-wiki.org/manual/Help/Wiki_Syntax.html))
-  - the path of a custom Lua writer, see [Custom
+-   the path of a custom Lua writer, see [Custom
     writers](https://pandoc.org/MANUAL.html#custom-writers) below
 
 </div>
@@ -204,11 +210,13 @@
 perfect, conversions from formats more expressive than pandoc’s Markdown
 can be expected to be lossy.
 
-## Installing
+Installing
+----------
 
 Here’s [how to install pandoc](INSTALL.md).
 
-## Documentation
+Documentation
+-------------
 
 Pandoc’s website contains a full [User’s
 Guide](https://pandoc.org/MANUAL.html). It is also available
@@ -217,13 +225,15 @@
 pandoc](https://pandoc.org/demos.html) and a limited [online
 demo](https://pandoc.org/try).
 
-## Contributing
+Contributing
+------------
 
 Pull requests, bug reports, and feature requests are welcome. Please
 make sure to read [the contributor guidelines](CONTRIBUTING.md) before
 opening a new issue.
 
-## License
+License
+-------
 
 © 2006-2020 John MacFarlane (jgm@berkeley.edu). Released under the
 [GPL](http://www.gnu.org/copyleft/gpl.html "GNU General Public License"),
diff --git a/benchmark/benchmark-pandoc.hs b/benchmark/benchmark-pandoc.hs
--- a/benchmark/benchmark-pandoc.hs
+++ b/benchmark/benchmark-pandoc.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TupleSections     #-}
 {-
 Copyright (C) 2012-2019 John MacFarlane <jgm@berkeley.edu>
 
@@ -21,39 +20,49 @@
 import Prelude
 import Text.Pandoc
 import Text.Pandoc.MIME
-import Text.Pandoc.Error (PandocError(..))
-import Control.Monad.Except (throwError)
+import Control.Monad.Except (throwError, liftIO)
 import qualified Text.Pandoc.UTF8 as UTF8
 import qualified Data.ByteString as B
 import qualified Data.Text as T
 import Criterion.Main
 import Criterion.Types (Config(..))
 import Data.List (intersect)
-import Data.Maybe (mapMaybe)
+import Data.Maybe (mapMaybe, catMaybes)
 import System.Environment (getArgs)
 import qualified Data.ByteString.Lazy as BL
 
+data Input = InputText {unInputText :: T.Text}
+           | InputBS {unInputBS :: BL.ByteString}
+
 readerBench :: Pandoc
             -> T.Text
-            -> Maybe Benchmark
-readerBench doc name =
-  case res of
-       Right (readerFun, inp) ->
-          Just $ bench (T.unpack $ name <> " reader")
-               $ nf (\i -> either (error . show) id $ runPure (readerFun i))
-                 inp
-       Left _ -> Nothing
-  where res = runPure $ do
-          (rdr, rexts) <- getReader name
+            -> IO (Maybe Benchmark)
+readerBench doc name = do
+  let (rdr, rexts) = either (error . show) id . runPure $ getReader name
+  res <- runIO $ do
           (wtr, wexts) <- getWriter name
           case (rdr, wtr) of
             (TextReader r, TextWriter w) -> do
-                     setResourcePath ["../test"]
+                     setResourcePath ["./test"]
                      inp <- w def{ writerWrapText = WrapAuto
                                  , writerExtensions = wexts } doc
-                     return $ (r def{ readerExtensions = rexts }, inp)
-            _ -> throwError $ PandocSomeError $ "not a text format: "
+                     return (r def{ readerExtensions = rexts } . unInputText, InputText inp)
+            (ByteStringReader r, ByteStringWriter w) -> do
+                     setResourcePath ["./test"]
+                     tmpl <- Just <$> compileDefaultTemplate name
+                     inp <- w def{ writerWrapText = WrapAuto
+                                 , writerExtensions = wexts
+                                 , writerTemplate = tmpl } doc
+                     liftIO $ BL.writeFile "/tmp/test.odt" inp
+                     return (r def{ readerExtensions = rexts } . unInputBS, InputBS inp)
+            _ -> throwError $ PandocSomeError $ "text/bytestring format mismatch: "
                                  <> name
+  return $ case res of
+       Right (readerFun, inp) ->
+          Just $ bench (T.unpack $ name <> " reader")
+               $ nf (\i -> either (error . show) id $ runPure (readerFun i))
+                 inp
+       Left _ -> Nothing
 
 getImages :: IO [(FilePath, MimeType, BL.ByteString)]
 getImages = do
@@ -89,22 +98,23 @@
 main = do
   args <- filter (\x -> T.take 1 x /= "-") . fmap T.pack <$> getArgs
   print args
-  let matchReader (n, TextReader _) =
+  let matchReader (n, _) =
          null args || ("reader" `elem` args && n `elem` args)
-      matchReader _                 = False
-  let matchWriter (n, TextWriter _) =
+      matchWriter (n, TextWriter _) =
          null args || ("writer" `elem` args && n `elem` args)
       matchWriter _                 = False
-  let matchedReaders = map fst $ (filter matchReader readers
+      allWriters = map fst (writers :: [(T.Text, Writer PandocPure)])
+      matchedReaders = map fst (filter matchReader readers
                                     :: [(T.Text, Reader PandocPure)])
-  let matchedWriters = map fst $ (filter matchWriter writers
+      matchedWriters = map fst (filter matchWriter writers
                                     :: [(T.Text, Writer PandocPure)])
   inp <- UTF8.toText <$> B.readFile "test/testsuite.txt"
   let opts = def
   let doc = either (error . show) id $ runPure $ readMarkdown opts inp
-  let readerBs = mapMaybe (readerBench doc)
-                 $ filter (/="haddock")
-                 (matchedReaders `intersect` matchedWriters)
+  readerBs <- fmap catMaybes
+              $ mapM (readerBench doc)
+              $ filter (/="haddock")
+              (matchedReaders `intersect` allWriters)
                  -- we need the corresponding writer to generate
                  -- input for the reader
   let writerBs = mapMaybe (writerBench doc) matchedWriters
diff --git a/cabal.project b/cabal.project
--- a/cabal.project
+++ b/cabal.project
@@ -12,3 +12,8 @@
     type: git
     location: https://github.com/jgm/pandoc-citeproc
     tag: 0.17.0.1
+
+ source-repository-package
+     type: git
+     location: https://github.com/jgm/commonmark-hs
+     tag: 8d4442abc443ce0100cc87af797e7df9a72b9b9a
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,7 +1,170 @@
 # Revision history for pandoc
 
-## pandoc 2.10 (YYYY-MM-DD)
+## pandoc 2.10.1 (2020-07-23)
 
+  * Add `commonmark_x` output format. This is `commonmark` with a number
+    of useful pandoc extensions enabled.
+
+  * Many more extensions now work with `commonmark` and `gfm`.
+
+  * Add generic `attributes` extension.  This allows attributes to
+    be added to any block or inline element in a uniform way.  Since
+    the Pandoc AST doesn't include attributes on each element type,
+    the attributes will sometimes be added by creating a surrounding
+    Div or Span container.  Currently this extension is only
+    compatible with the `commonmark` and `gfm` readers.
+
+    To add an attribute to a block-level element, e.g. a paragraph,
+    put it before the block:
+    ```
+    {#mypara}
+    This is a paragraph.
+    ```
+    Multiple attributes may be used and will be combined:
+    ```
+    {#mypara}
+    {.blue .warning key="val"}
+    This is a paragraph.
+    ```
+    To add an attribute to an inline-level element, put it
+    immediately after the element:
+    ```
+    *emphasized text*{.special}
+    ```
+
+  * Support `--number-sections` for docx output (#1413).
+
+  * LaTeX reader:
+
+    + Support `\SIRange` reader (#6418, Emerson Harkin).
+    + Support table col-span and row-span (#6311, Laurent P. René de Cotret).
+      Supports `\multirow` and `\multicolumn`.
+    + Support amsthm:  `\newtheorem`, `\theoremstyle`, and theorem and
+      proof environments, including labels and references.  The only thing
+      that is unsupported is the second optional argument, which causes
+      numbering to be reset after the specified series is incremented.
+    + Moved some code to T.P.LaTeX.Parsing.  We need to reduce the size
+      of the LaTeX reader to ease compilation on resource-limited systems.
+
+  * RST reader:
+
+    + Fix csv tables with multiline cells (#6549).
+    + Fix spurious newlines in some attributes from directives.
+    + Avoid extra newline in included code blocks.
+
+  * Commonmark reader:
+
+    + Switch from cmark-gfm to commonmark-hs for commonmark and gfm
+      parsing.  This avoids depending on a C library
+      and allows us to support more pandoc extensions for
+      `commonmark` and `gfm`.
+
+  * DocBook reader:
+
+    + Parse releaseinfo as metadata (#6542).
+
+  * Docx reader:
+
+    + Only use `bCs/iCs` on runs with `rtl` or `cs` property (#6514, Nikolay
+      Yakimov).
+    + Code cleanup/refactoring (Nikolay Yakimov).
+
+  * Org reader (Albert Krewinkel):
+
+    + Respect export setting which disables entities
+      MathML-like entities, e.g., `\alpha`, can be disabled with the
+      `#+OPTION: e:nil` export setting (Albert Krewinkel).
+    + Respect export setting disabling footnotes.  Footnotes can be removed
+      from the final document with the `#+OPTION: f:nil` export setting.
+    + Respect tables-excluding export setting.  Tables can be removed from
+      the final document with the `#+OPTION: |:nil` export setting.
+
+  * Markdown writer:
+
+    + Move `asciify` out of `escapeString`.  Otherwise `unsmartify`
+      doesn't catch quotes that have already been turned to entities.
+    + Add `writeCommonmark` (new exported function, API change).
+    + Use unicode super/subscript characters when possible if the
+      `superscript` or `subscript` extension or `raw_html` aren't available.
+    + Render caption as following paragraph when `table_caption` extension
+      is not enabled.
+    + Use numerical labels for reference links that are longer
+      than 999 characters or contain square brackets, for conformity
+      with commonmark (#6560).
+
+  * Commonmark writer:
+
+    + Instead of using cmark-gfm, use `writeCommonmark` from the
+      Markdown writer.  This function calls the markdown writer
+      with appropriate extensions and a few small modifications
+      (e.g. not requiring backslashes before spaces inside
+      super/subscripts).  With this change `comonmark` and
+      `gfm` output can be used with a wider selection of
+      extensions.
+
+  * Jira writer: keep image caption as alt attribute (#6529, Albert
+    Krewinkel).
+
+  * HTML writer:
+
+    + Improve alt-text/caption handling for HTML5 (#6491, Albert Krewinkel).
+      Screen readers read an image's `alt` attribute and the figure caption,
+      both of which come from the same source in pandoc. The figure caption is
+      hidden from screen readers with the `aria-hidden` attribute. This
+      improves accessibility.  For HTML4, where `aria-hidden` is not allowed,
+      pandoc still uses an empty `alt` attribute to avoid duplicate contents.
+
+  * Ms writer:
+
+    + Fix code highlighting with blank lines.  Previously blank lines
+      were simply omitted from highligted code.
+    + Escape starting periods in ms writer code blocks (#6505, Michael
+      Hoffmann).  If a line of ms code block output starts with a period (.),
+      it should be prepended by `\&` so that it is not interpreted as a roff
+      command.
+
+  * Text.Pandoc.Extensions:
+
+    + Add `raw_markdown` extension (which only affects `ipynb`
+      input).
+    + Trim down `githubMarkdownExtensions`.
+      Previously it included all of the following, which make
+      sense for the legacy `markdown_github` but not for `gfm`,
+      since they are part of base commonmark and thus
+      can't be turned off in `gfm`:
+
+      - `Ext_all_symbols_escapable`
+      - `Ext_backtick_code_blocks`
+      - `Ext_fenced_code_blocks`
+      - `Ext_space_in_atx_header`
+      - `Ext_intraword_underscores`
+      - `Ext_lists_without_preceding_blankline`
+      - `Ext_shortcut_reference_links`
+
+      These have been removed from `githubMarkdownExtensions`, though
+      they're still turned on for legacy `markdown_github`.
+    + Add `Ext_attributes` constructor for `Extension` [API change].
+
+  * LaTeX template: use selnolig to selectively suppress ligatures with
+    lualatex (#6534).
+
+  * Benchmark bytestring readers (Nikolay Yakimov).
+
+  * Documentation:
+
+    + Update using-the-pandoc-api.md (favonia).
+    + Fix Typos in lua-filters.md (tajmone).
+    + Rewrite Raw HTML/TeX section in MANUAL.txt to avoid duplicate
+      headings for the extensions.
+    + Fix typo in MANUAL.txt (Benjamin Wuethrich).
+    + Remove duplicate 'titlepage' in MANUAL.txt (Blake Eryx).
+    + CONTRIBUTING.md: Advertise the official nightlies in GitHub actions.
+      Replaces #6500, thanks to @ickc.
+
+
+
+## pandoc 2.10 (2020-06-29)
+
   * Use pandoc-types 1.21.  This adds two things:
 
     + A native Underline constructor for Inline (#6277, Vaibhav Sagar).
@@ -154,6 +317,14 @@
 
   * Ipynb reader:
 
+    + Implement `raw_markdown` extension (#5408).  Specifying
+      `-f ipynb+raw_markdown` will cause Markdown cells
+      to be represented as raw Markdown blocks, instead of being
+      parsed.  This is not what you want when going from `ipynb`
+      to other formats, but it may be useful when going from `ipynb`
+      to Markdown or to `ipynb`, to avoid semantically insignificant
+      changes in the contents of the Markdown cells that might
+      otherwise be introduced.
     + Handle application/pdf output as image (#6430).
     + Properly handle image/svg+xml as an image (#6430).
 
diff --git a/data/docx/word/styles.xml b/data/docx/word/styles.xml
--- a/data/docx/word/styles.xml
+++ b/data/docx/word/styles.xml
@@ -414,6 +414,10 @@
       <w:sz w:val="22" />
     </w:rPr>
   </w:style>
+  <w:style w:type="character" w:customStyle="1" w:styleId="SectionNumber">
+    <w:name w:val="Section Number" />
+    <w:basedOn w:val="BodyTextChar" />
+  </w:style>
   <w:style w:type="character" w:styleId="FootnoteReference">
     <w:name w:val="Footnote Reference" />
     <w:basedOn w:val="BodyTextChar" />
diff --git a/data/templates/default.latex b/data/templates/default.latex
--- a/data/templates/default.latex
+++ b/data/templates/default.latex
@@ -339,6 +339,9 @@
 $endif$
 \fi
 $endif$
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
 $if(dir)$
 \ifxetex
   % Load bidi as late as possible as it modifies e.g. graphicx
diff --git a/man/pandoc.1 b/man/pandoc.1
--- a/man/pandoc.1
+++ b/man/pandoc.1
@@ -1,7 +1,7 @@
 .\"t
-.\" Automatically generated by Pandoc 2.10
+.\" Automatically generated by Pandoc 2.10.1
 .\"
-.TH "Pandoc User\[aq]s Guide" "" "June 29, 2020" "pandoc 2.10" ""
+.TH "Pandoc User\[aq]s Guide" "" "July 23, 2020" "pandoc 2.10.1" ""
 .hy
 .SH NAME
 pandoc - general markup converter
@@ -229,6 +229,8 @@
 .IP \[bu] 2
 \f[C]commonmark\f[R] (CommonMark Markdown)
 .IP \[bu] 2
+\f[C]commonmark_x\f[R] (CommonMark Markdown with extensions)
+.IP \[bu] 2
 \f[C]creole\f[R] (Creole 1.0)
 .IP \[bu] 2
 \f[C]csv\f[R] (CSV table)
@@ -313,6 +315,8 @@
 .IP \[bu] 2
 \f[C]commonmark\f[R] (CommonMark Markdown)
 .IP \[bu] 2
+\f[C]commonmark_x\f[R] (CommonMark Markdown with extensions)
+.IP \[bu] 2
 \f[C]context\f[R] (ConTeXt)
 .IP \[bu] 2
 \f[C]docbook\f[R] or \f[C]docbook4\f[R] (DocBook 4)
@@ -936,7 +940,7 @@
 If you\[aq]re behind a proxy, you also need to set the environment
 variable \f[C]http_proxy\f[R] to \f[C]http://...\f[R].
 .TP
-\[ga]--no-check-certificate
+\f[B]\f[CB]--no-check-certificate\f[B]\f[R]
 Disable the certificate verification to allow access to unsecure HTTP
 resources (for example when the certificate is no longer valid or self
 signed).
@@ -1017,7 +1021,7 @@
 their default type.
 .TP
 \f[B]\f[CB]-N\f[B]\f[R], \f[B]\f[CB]--number-sections\f[B]\f[R]
-Number section headings in LaTeX, ConTeXt, HTML, or EPUB output.
+Number section headings in LaTeX, ConTeXt, HTML, Docx, or EPUB output.
 By default, sections are not numbered.
 Sections with class \f[C]unnumbered\f[R] will never be numbered, even if
 \f[C]--number-sections\f[R] is specified.
@@ -1196,6 +1200,8 @@
 Footnote Reference
 .IP \[bu] 2
 Hyperlink
+.IP \[bu] 2
+Section Number
 .PP
 Table style:
 .IP \[bu] 2
@@ -3131,20 +3137,18 @@
 example.
 .SS Raw HTML/TeX
 .PP
-The following extensions (especially how they affect Markdown
-input/output) are also described in more detail in their respective
-sections of Pandoc\[aq]s Markdown.
-.SS Extension: \f[C]raw_html\f[R]
-.PP
-When converting from HTML, parse elements to raw HTML which are not
-representable in pandoc\[aq]s AST.
+The following extensions are described in more detail in their
+respective sections of Pandoc\[aq]s Markdown:
+.IP \[bu] 2
+\f[C]raw_html\f[R] allows HTML elements which are not representable in
+pandoc\[aq]s AST to be parsed as raw HTML.
 By default, this is disabled for HTML input.
-.SS Extension: \f[C]raw_tex\f[R]
-.PP
-Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
-.PP
+.IP \[bu] 2
+\f[C]raw_tex\f[R] allows raw LaTeX, TeX, and ConTeXt to be included in a
+document.
 This extension can be enabled/disabled for the following formats (in
 addition to \f[C]markdown\f[R]):
+.RS 2
 .TP
 input formats
 \f[C]latex\f[R], \f[C]org\f[R], \f[C]textile\f[R], \f[C]html\f[R]
@@ -3162,24 +3166,20 @@
 results if you disable \f[C]raw_html\f[R] and \f[C]raw_tex\f[R] when
 converting to formats like \f[C]docx\f[R] which don\[aq]t allow raw
 \f[C]html\f[R] or \f[C]tex\f[R].
-.SS Extension: \f[C]native_divs\f[R]
-.PP
-This extension is enabled by default for HTML input.
-This means that \f[C]div\f[R]s are parsed to pandoc native elements.
-(Alternatively, you can parse them to raw HTML using
-\f[C]-f html-native_divs+raw_html\f[R].)
-.PP
-When converting HTML to Markdown, for example, you may want to drop all
-\f[C]div\f[R]s and \f[C]span\f[R]s:
-.IP
-.nf
-\f[C]
-pandoc -f html-native_divs-native_spans -t markdown
-\f[R]
-.fi
-.SS Extension: \f[C]native_spans\f[R]
-.PP
-Analogous to \f[C]native_divs\f[R] above.
+.RE
+.IP \[bu] 2
+\f[C]native_divs\f[R] causes HTML \f[C]div\f[R] elements to be parsed as
+native pandoc Div blocks.
+If you want them to be parsed as raw HTML, use
+\f[C]-f html-native_divs+raw_html\f[R].
+.IP \[bu] 2
+\f[C]native_spans\f[R] causes HTML \f[C]span\f[R] elements to be parsed
+as native pandoc Span inlines.
+If you want them to be parsed as raw HTML, use
+\f[C]-f html-native_spans+raw_html\f[R].
+If you want to drop all \f[C]div\f[R]s and \f[C]span\f[R]s when
+converting HTML to Markdown, you can use
+\f[C]pandoc -f html-native_divs-native_spans -t markdown\f[R].
 .SS Literate Haskell support
 .SS Extension: \f[C]literate_haskell\f[R]
 .PP
@@ -3289,6 +3289,13 @@
 .PP
 In the \f[C]muse\f[R] input format, this enables Text::Amuse extensions
 to Emacs Muse markup.
+.SS Extension: \f[C]raw_markdown\f[R]
+.PP
+In the \f[C]ipynb\f[R] input format, this causes Markdown cells to be
+included as raw Markdown blocks (allowing lossless round-tripping)
+rather than being parsed.
+Use this only when you are targetting \f[C]ipynb\f[R] or a
+markdown-based output format.
 .SS Extension: \f[C]citations\f[R]
 .PP
 Some aspects of Pandoc\[aq]s Markdown citation syntax are also accepted
@@ -5909,6 +5916,39 @@
 name, where \f[C]EXTENSION\f[R] is the name of the extension.
 Thus, for example, \f[C]markdown+hard_line_breaks\f[R] is Markdown with
 hard line breaks.
+.SS Extension: \f[C]attributes\f[R]
+.PP
+Allows attributes to be attached to any inline or block-level element.
+The syntax for the attributes is the same as that used in
+\f[C]header_attributes\f[R].
+.IP \[bu] 2
+Attributes that occur immediately after an inline element affect that
+element.
+If they follow a space, then they belong to the space.
+(Hence, this option subsumes \f[C]inline_code_attributes\f[R] and
+\f[C]link_attributes\f[R].)
+.IP \[bu] 2
+Attributes that occur immediately before a block element, on a line by
+themselves, affect that element.
+.IP \[bu] 2
+Consecutive attribute specifiers may be used, either for blocks or for
+inlines.
+Their attributes will be combined.
+.IP \[bu] 2
+Attributes that occur at the end of the text of a Setext or ATX heading
+(separated by whitespace from the text) affect the heading element.
+(Hence, this option subsumes \f[C]header_attributes\f[R].)
+.IP \[bu] 2
+Attributes that occur after the opening fence in a fenced code block
+affect the code block element.
+(Hence, this option subsumes \f[C]fenced_code_attributes\f[R].)
+.IP \[bu] 2
+Attributes that occur at the end of a reference link definition affect
+links that refer to that definition.
+.PP
+Note that pandoc\[aq]s AST does not currently allow attributes to be
+attached to arbitrary elements.
+Hence a Span or Div container will be added if needed.
 .SS Extension: \f[C]old_dashes\f[R]
 .PP
 Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
@@ -6105,11 +6145,12 @@
 Also, \f[C]raw_tex\f[R] only affects \f[C]gfm\f[R] output, not input.
 .TP
 \f[B]\f[CB]gfm\f[B]\f[R] (GitHub-Flavored Markdown)
-\f[C]pipe_tables\f[R], \f[C]raw_html\f[R], \f[C]fenced_code_blocks\f[R],
-\f[C]auto_identifiers\f[R], \f[C]gfm_auto_identifiers\f[R],
-\f[C]backtick_code_blocks\f[R], \f[C]autolink_bare_uris\f[R],
-\f[C]space_in_atx_header\f[R], \f[C]intraword_underscores\f[R],
-\f[C]strikeout\f[R], \f[C]task_lists\f[R], \f[C]emoji\f[R],
+\f[C]pipe_tables\f[R], \f[C]raw_html\f[R], \f[C]native_divs\f[R],
+\f[C]fenced_code_blocks\f[R], \f[C]auto_identifiers\f[R],
+\f[C]gfm_auto_identifiers\f[R], \f[C]backtick_code_blocks\f[R],
+\f[C]autolink_bare_uris\f[R], \f[C]space_in_atx_header\f[R],
+\f[C]intraword_underscores\f[R], \f[C]strikeout\f[R],
+\f[C]task_lists\f[R], \f[C]emoji\f[R],
 \f[C]shortcut_reference_links\f[R], \f[C]angle_brackets_escapable\f[R],
 \f[C]lists_without_preceding_blankline\f[R].
 .SH PRODUCING SLIDE SHOWS WITH PANDOC
@@ -6778,11 +6819,6 @@
 T}
 T{
 seriespage
-T}@T{
-frontmatter
-T}
-T{
-titlepage
 T}@T{
 frontmatter
 T}
diff --git a/pandoc.cabal b/pandoc.cabal
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,6 +1,6 @@
 cabal-version:   2.2
 name:            pandoc
-version:         2.10
+version:         2.10.1
 build-type:      Simple
 license:         GPL-2.0-or-later
 license-file:    COPYING.md
@@ -11,7 +11,7 @@
 stability:       alpha
 homepage:        https://pandoc.org
 category:        Text
-tested-with:     GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,
+tested-with:     GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5,
                  GHC == 8.8.3, GHC == 8.10.1
 synopsis:        Conversion between markup formats
 description:     Pandoc is a Haskell library for converting from one markup
@@ -205,6 +205,7 @@
                  test/command/B.txt
                  test/command/C.txt
                  test/command/D.txt
+                 test/command/01.csv
                  test/command/defaults1.yaml
                  test/command/defaults2.yaml
                  test/command/3533-rst-csv-tables.csv
@@ -421,8 +422,10 @@
                  deepseq >= 1.3 && < 1.5,
                  JuicyPixels >= 3.1.6.1 && < 3.4,
                  Glob >= 0.7 && < 0.11,
-                 cmark-gfm >= 0.2 && < 0.3,
                  doctemplates >= 0.8.2 && < 0.9,
+                 commonmark-pandoc >= 0.2 && < 0.3,
+                 commonmark >= 0.1.0.1 && < 0.2,
+                 commonmark-extensions >= 0.2 && < 0.3,
                  network-uri >= 2.6 && < 2.7,
                  network >= 2.6,
                  connection >= 0.3.1,
@@ -816,6 +819,7 @@
                   Tests.Writers.FB2
                   Tests.Writers.Powerpoint
                   Tests.Writers.OOXML
+                  Tests.Writers.Ms
   if os(windows)
     cpp-options:      -D_WINDOWS
   default-language: Haskell2010
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
--- a/src/Text/Pandoc/Extensions.hs
+++ b/src/Text/Pandoc/Extensions.hs
@@ -133,6 +133,7 @@
     | Ext_raw_attribute           -- ^ Allow explicit raw blocks/inlines
     | Ext_raw_html            -- ^ Allow raw HTML
     | Ext_raw_tex             -- ^ Allow raw TeX (other than math)
+    | Ext_raw_markdown        -- ^ Parse markdown in ipynb as raw markdown
     | Ext_shortcut_reference_links -- ^ Shortcut reference links
     | Ext_simple_tables       -- ^ Pandoc-style simple tables
     | Ext_smart               -- ^ "Smart" quotes, apostrophes, ellipses, dashes
@@ -150,6 +151,7 @@
     | Ext_tex_math_single_backslash  -- ^ TeX math btw \(..\) \[..\]
     | Ext_yaml_metadata_block -- ^ YAML metadata block
     | Ext_gutenberg           -- ^ Use Project Gutenberg conventions for plain
+    | Ext_attributes          -- ^ Generic attribute syntax
     deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
 
 -- | Extensions to be used with pandoc-flavored markdown.
@@ -242,21 +244,15 @@
 -- | Extensions to be used with github-flavored markdown.
 githubMarkdownExtensions :: Extensions
 githubMarkdownExtensions = extensionsFromList
-  [ Ext_all_symbols_escapable
-  , Ext_pipe_tables
+  [ Ext_pipe_tables
   , Ext_raw_html
-  , Ext_fenced_code_blocks
+  , Ext_native_divs
   , Ext_auto_identifiers
   , Ext_gfm_auto_identifiers
-  , Ext_backtick_code_blocks
   , Ext_autolink_bare_uris
-  , Ext_space_in_atx_header
-  , Ext_intraword_underscores
   , Ext_strikeout
   , Ext_task_lists
   , Ext_emoji
-  , Ext_lists_without_preceding_blankline
-  , Ext_shortcut_reference_links
   ]
 
 -- | Extensions to be used with multimarkdown.
@@ -308,7 +304,16 @@
 getDefaultExtensions "markdown_strict"   = strictExtensions
 getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
 getDefaultExtensions "markdown_mmd"      = multimarkdownExtensions
-getDefaultExtensions "markdown_github"   = githubMarkdownExtensions
+getDefaultExtensions "markdown_github"   = githubMarkdownExtensions <>
+  extensionsFromList
+    [ Ext_all_symbols_escapable
+    , Ext_backtick_code_blocks
+    , Ext_fenced_code_blocks
+    , Ext_space_in_atx_header
+    , Ext_intraword_underscores
+    , Ext_lists_without_preceding_blankline
+    , Ext_shortcut_reference_links
+    ]
 getDefaultExtensions "markdown"          = pandocExtensions
 getDefaultExtensions "ipynb"             =
   extensionsFromList
@@ -335,6 +340,29 @@
 getDefaultExtensions "gfm"             = githubMarkdownExtensions
 getDefaultExtensions "commonmark"      = extensionsFromList
                                           [Ext_raw_html]
+getDefaultExtensions "commonmark_x"    = extensionsFromList
+  [ Ext_pipe_tables
+  , Ext_raw_html
+  , Ext_auto_identifiers
+  , Ext_strikeout
+  , Ext_task_lists
+  , Ext_emoji
+  , Ext_pipe_tables
+  , Ext_raw_html
+  , Ext_raw_tex            -- only supported in writer (for math)
+  , Ext_smart
+  , Ext_tex_math_dollars
+  , Ext_superscript
+  , Ext_subscript
+  , Ext_definition_lists
+  , Ext_footnotes
+  , Ext_fancy_lists
+  , Ext_fenced_divs
+  , Ext_bracketed_spans
+  , Ext_raw_attribute
+  , Ext_implicit_header_references
+  , Ext_attributes
+  ]
 getDefaultExtensions "org"             = extensionsFromList
                                           [Ext_citations,
                                            Ext_auto_identifiers]
@@ -415,7 +443,8 @@
   getAll "markdown_mmd"      = allMarkdownExtensions
   getAll "markdown_github"   = allMarkdownExtensions
   getAll "markdown"          = allMarkdownExtensions
-  getAll "ipynb"             = allMarkdownExtensions
+  getAll "ipynb"             = allMarkdownExtensions <> extensionsFromList
+    [ Ext_raw_markdown ]
   getAll "docx"            = extensionsFromList
     [ Ext_empty_paragraphs
     , Ext_styles
@@ -430,16 +459,32 @@
     [ Ext_amuse ]
   getAll "asciidoc"        = autoIdExtensions
   getAll "plain"           = allMarkdownExtensions
-  getAll "gfm"             = githubMarkdownExtensions <>
+  getAll "gfm"             = getAll "commonmark"
+  getAll "commonmark"      =
     autoIdExtensions <>
     extensionsFromList
-    [ Ext_raw_html
+    [ Ext_pipe_tables
+    , Ext_autolink_bare_uris
+    , Ext_strikeout
+    , Ext_task_lists
+    , Ext_emoji
+    , Ext_raw_html
     , Ext_raw_tex            -- only supported in writer (for math)
     , Ext_implicit_figures
     , Ext_hard_line_breaks
     , Ext_smart
+    , Ext_tex_math_dollars
+    , Ext_superscript
+    , Ext_subscript
+    , Ext_definition_lists
+    , Ext_footnotes
+    , Ext_fancy_lists
+    , Ext_fenced_divs
+    , Ext_bracketed_spans
+    , Ext_raw_attribute
+    , Ext_implicit_header_references
+    , Ext_attributes
     ]
-  getAll "commonmark"      = getAll "gfm"
   getAll "org"             = autoIdExtensions <>
     extensionsFromList
     [ Ext_citations
diff --git a/src/Text/Pandoc/Readers.hs b/src/Text/Pandoc/Readers.hs
--- a/src/Text/Pandoc/Readers.hs
+++ b/src/Text/Pandoc/Readers.hs
@@ -111,6 +111,7 @@
            ,("markdown_github" , TextReader readMarkdown)
            ,("markdown_mmd",  TextReader readMarkdown)
            ,("commonmark"   , TextReader readCommonMark)
+           ,("commonmark_x" , TextReader readCommonMark)
            ,("creole"       , TextReader readCreole)
            ,("dokuwiki"     , TextReader readDokuWiki)
            ,("gfm"          , TextReader readCommonMark)
diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs
--- a/src/Text/Pandoc/Readers/CommonMark.hs
+++ b/src/Text/Pandoc/Readers/CommonMark.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ViewPatterns      #-}
 {- |
    Module      : Text.Pandoc.Readers.CommonMark
@@ -16,209 +17,50 @@
 module Text.Pandoc.Readers.CommonMark (readCommonMark)
 where
 
-import CMarkGFM
-import Control.Monad.State
-import qualified Data.Set as Set
+import Commonmark
+import Commonmark.Extensions
+import Commonmark.Pandoc
 import Data.Text (Text)
-import qualified Data.Text as T
 import Text.Pandoc.Class.PandocMonad (PandocMonad)
 import Text.Pandoc.Definition
-import Text.Pandoc.Emoji (emojiToInline)
+import Text.Pandoc.Builder as B
 import Text.Pandoc.Options
-import Text.Pandoc.Shared (uniqueIdent, taskListItemFromAscii)
-import Text.Pandoc.Walk (walkM)
+import Text.Pandoc.Error
+import Control.Monad.Except
+import Data.Functor.Identity (runIdentity)
 
 -- | Parse a CommonMark formatted string into a 'Pandoc' structure.
 readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
-readCommonMark opts s = return $
-  (if isEnabled Ext_auto_identifiers opts
-      then addHeaderIdentifiers opts
-      else id) $
-  nodeToPandoc opts $ commonmarkToNode opts' exts s
-  where opts' = [ optSmart | isEnabled Ext_smart opts ]
-        exts = [ extStrikethrough | isEnabled Ext_strikeout opts ] ++
-               [ extTable | isEnabled Ext_pipe_tables opts ] ++
-               [ extAutolink | isEnabled Ext_autolink_bare_uris opts ]
-
-convertEmojis :: Text -> [Inline]
-convertEmojis s@(T.uncons -> Just (':',xs)) =
-   case T.break (==':') xs of
-        (ys, T.uncons -> Just (':',zs)) ->
-           case emojiToInline ys of
-                Just em -> em : convertEmojis zs
-                Nothing -> Str (":" <> ys) : convertEmojis (":" <> zs)
-        _ -> [Str s]
-convertEmojis s =
-  case T.break (==':') s of
-    ("","") -> []
-    (_,"") -> [Str s]
-    (xs,ys) -> Str xs : convertEmojis ys
-
-addHeaderIdentifiers :: ReaderOptions -> Pandoc -> Pandoc
-addHeaderIdentifiers opts doc = evalState (walkM (addHeaderId opts) doc) mempty
-
-addHeaderId :: ReaderOptions -> Block -> State (Set.Set Text) Block
-addHeaderId opts (Header lev (_,classes,kvs) ils) = do
-  ids <- get
-  let ident = uniqueIdent (readerExtensions opts) ils ids
-  modify (Set.insert ident)
-  return $ Header lev (ident,classes,kvs) ils
-addHeaderId _ x = return x
-
-nodeToPandoc :: ReaderOptions -> Node -> Pandoc
-nodeToPandoc opts (Node _ DOCUMENT nodes) =
-  Pandoc nullMeta $ foldr (addBlock opts) [] nodes
-nodeToPandoc opts n =  -- shouldn't happen
-  Pandoc nullMeta $ foldr (addBlock opts) [] [n]
-
-addBlocks :: ReaderOptions -> [Node] -> [Block]
-addBlocks opts = foldr (addBlock opts) []
-
-addBlock :: ReaderOptions -> Node -> [Block] -> [Block]
-addBlock opts (Node _ PARAGRAPH nodes) =
-  case addInlines opts nodes of
-    [Image attr alt (src,tit)]
-      | isEnabled Ext_implicit_figures opts
-         -- the "fig:" prefix indicates an implicit figure
-      -> (Para [Image attr alt (src, "fig:" <> tit)] :)
-    ils -> (Para ils :)
-addBlock _ (Node _ THEMATIC_BREAK _) =
-  (HorizontalRule :)
-addBlock opts (Node _ BLOCK_QUOTE nodes) =
-  (BlockQuote (addBlocks opts nodes) :)
-addBlock opts (Node _ (HTML_BLOCK t) _)
-  | isEnabled Ext_raw_html opts = (RawBlock (Format "html") t :)
-  | otherwise                 = id
--- Note:  the cmark parser will never generate CUSTOM_BLOCK,
--- so we don't need to handle it:
-addBlock _ (Node _ (CUSTOM_BLOCK _onEnter _onExit) _nodes) =
-  id
-addBlock _ (Node _ (CODE_BLOCK info t) _) =
-  (CodeBlock ("", take 1 (T.words info), []) t :)
-addBlock opts (Node _ (HEADING lev) nodes) =
-  (Header lev ("",[],[]) (addInlines opts nodes) :)
-addBlock opts (Node _ (LIST listAttrs) nodes) =
-  (constructor (map listItem nodes) :)
-  where constructor = case listType listAttrs of
-                       BULLET_LIST  -> BulletList
-                       ORDERED_LIST -> OrderedList
-                                         (start, DefaultStyle, delim)
-        start = listStart listAttrs
-        listItem = taskListItemFromAscii exts . setTightness
-                     . addBlocks opts . children
-        setTightness = if listTight listAttrs
-                           then map paraToPlain
-                           else id
-        paraToPlain (Para xs) = Plain xs
-        paraToPlain x         = x
-        delim = case listDelim listAttrs of
-                     PERIOD_DELIM -> Period
-                     PAREN_DELIM  -> OneParen
-        exts = readerExtensions opts
-addBlock opts (Node _ (TABLE alignments) nodes) =
-  (Table
-    nullAttr
-    (Caption Nothing [])
-    (zip aligns widths)
-    (TableHead nullAttr headers)
-    [TableBody nullAttr 0 [] rows]
-    (TableFoot nullAttr []) :)
-  where aligns = map fromTableCellAlignment alignments
-        fromTableCellAlignment NoAlignment   = AlignDefault
-        fromTableCellAlignment LeftAligned   = AlignLeft
-        fromTableCellAlignment RightAligned  = AlignRight
-        fromTableCellAlignment CenterAligned = AlignCenter
-        widths = replicate numcols ColWidthDefault
-        numcols = if null rows'
-                     then 0
-                     else maximum $ map rowLength rows'
-        rows' = map toRow $ filter isRow nodes
-        (headers, rows) = case rows' of
-                               (h:rs) -> ([h], rs)
-                               []     -> ([], [])
-        isRow (Node _ TABLE_ROW _) = True
-        isRow _                    = False
-        isCell (Node _ TABLE_CELL _) = True
-        isCell _                     = False
-        toRow (Node _ TABLE_ROW ns) = Row nullAttr $ map toCell $ filter isCell ns
-        toRow (Node _ t _) = error $ "toRow encountered non-row " ++ show t
-        toCell (Node _ TABLE_CELL []) = fromSimpleCell []
-        toCell (Node _ TABLE_CELL (n:ns))
-          | isBlockNode n = fromSimpleCell $ addBlocks opts (n:ns)
-          | otherwise     = fromSimpleCell [Plain (addInlines opts (n:ns))]
-        toCell (Node _ t _) = error $ "toCell encountered non-cell " ++ show t
-        fromSimpleCell = Cell nullAttr AlignDefault 1 1
-        rowLength (Row _ body) = length body -- all cells are 1×1
-addBlock _ (Node _ TABLE_ROW _) = id -- handled in TABLE
-addBlock _ (Node _ TABLE_CELL _) = id -- handled in TABLE
-addBlock _ _ = id
-
-isBlockNode :: Node -> Bool
-isBlockNode (Node _ nodetype _) =
-  case nodetype of
-       DOCUMENT          -> True
-       THEMATIC_BREAK    -> True
-       PARAGRAPH         -> True
-       BLOCK_QUOTE       -> True
-       HTML_BLOCK _      -> True
-       CUSTOM_BLOCK _ _  -> True
-       CODE_BLOCK _ _    -> True
-       HEADING _         -> True
-       LIST _            -> True
-       ITEM              -> True
-       TEXT _            -> False
-       SOFTBREAK         -> False
-       LINEBREAK         -> False
-       HTML_INLINE _     -> False
-       CUSTOM_INLINE _ _ -> False
-       CODE _            -> False
-       EMPH              -> False
-       STRONG            -> False
-       LINK _ _          -> False
-       IMAGE _ _         -> False
-       STRIKETHROUGH     -> False
-       TABLE _           -> False
-       TABLE_ROW         -> False
-       TABLE_CELL        -> False
-
-children :: Node -> [Node]
-children (Node _ _ ns) = ns
-
-addInlines :: ReaderOptions -> [Node] -> [Inline]
-addInlines opts = foldr (addInline opts) []
+readCommonMark opts s = do
+  let res = runIdentity $
+              commonmarkWith (foldr (<>) defaultSyntaxSpec exts) "input" s
+  case res of
+    Left err -> throwError $ PandocParsecError s err
+    Right (Cm bls :: Cm () Blocks) -> return $ B.doc bls
+ where
+  exts = [ hardLineBreaksSpec | isEnabled Ext_hard_line_breaks opts ] ++
+         [ smartPunctuationSpec | isEnabled Ext_smart opts ] ++
+         [ strikethroughSpec | isEnabled Ext_strikeout opts ] ++
+         [ superscriptSpec | isEnabled Ext_superscript opts ] ++
+         [ subscriptSpec | isEnabled Ext_subscript opts ] ++
+         [ mathSpec | isEnabled Ext_tex_math_dollars opts ] ++
+         [ fancyListSpec | isEnabled Ext_fancy_lists opts ] ++
+         [ fencedDivSpec | isEnabled Ext_fenced_divs opts ] ++
+         [ bracketedSpanSpec | isEnabled Ext_bracketed_spans opts ] ++
+         [ rawAttributeSpec | isEnabled Ext_raw_attribute opts ] ++
+         [ attributesSpec | isEnabled Ext_attributes opts ] ++
+         [ pipeTableSpec | isEnabled Ext_pipe_tables opts ] ++
+         [ autolinkSpec | isEnabled Ext_autolink_bare_uris opts ] ++
+         [ emojiSpec | isEnabled Ext_emoji opts ] ++
+         [ autoIdentifiersSpec
+           | isEnabled Ext_gfm_auto_identifiers opts
+           , not (isEnabled Ext_ascii_identifiers opts) ] ++
+         [ autoIdentifiersAsciiSpec
+           | isEnabled Ext_gfm_auto_identifiers opts
+           , isEnabled Ext_ascii_identifiers opts ] ++
+         [ implicitHeadingReferencesSpec
+           | isEnabled Ext_implicit_header_references opts ] ++
+         [ footnoteSpec | isEnabled Ext_footnotes opts ] ++
+         [ definitionListSpec | isEnabled Ext_definition_lists opts ] ++
+         [ taskListSpec | isEnabled Ext_task_lists opts ]
 
-addInline :: ReaderOptions -> Node -> [Inline] -> [Inline]
-addInline opts (Node _ (TEXT t) _) = (concatMap toinl clumps ++)
-  where clumps = T.groupBy samekind t
-        samekind ' ' ' ' = True
-        samekind ' ' _   = False
-        samekind _   ' ' = False
-        samekind _  _    = True
-        toinl (T.uncons -> Just (' ', _)) = [Space]
-        toinl xs = if isEnabled Ext_emoji opts
-                   then convertEmojis xs
-                   else [Str xs]
-addInline _ (Node _ LINEBREAK _) = (LineBreak :)
-addInline opts (Node _ SOFTBREAK _)
-  | isEnabled Ext_hard_line_breaks opts = (LineBreak :)
-  | otherwise                           = (SoftBreak :)
-addInline opts (Node _ (HTML_INLINE t) _)
-  | isEnabled Ext_raw_html opts = (RawInline (Format "html") t :)
-  | otherwise                 = id
--- Note:  the cmark parser will never generate CUSTOM_BLOCK,
--- so we don't need to handle it:
-addInline _ (Node _ (CUSTOM_INLINE _onEnter _onExit) _nodes) =
-  id
-addInline _ (Node _ (CODE t) _) =
-  (Code ("",[],[]) t :)
-addInline opts (Node _ EMPH nodes) =
-  (Emph (addInlines opts nodes) :)
-addInline opts (Node _ STRONG nodes) =
-  (Strong (addInlines opts nodes) :)
-addInline opts (Node _ STRIKETHROUGH nodes) =
-  (Strikeout (addInlines opts nodes) :)
-addInline opts (Node _ (LINK url title) nodes) =
-  (Link nullAttr (addInlines opts nodes) (url, title) :)
-addInline opts (Node _ (IMAGE url title) nodes) =
-  (Image nullAttr (addInlines opts nodes) (url, title) :)
-addInline _ _ = id
diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs
--- a/src/Text/Pandoc/Readers/DocBook.hs
+++ b/src/Text/Pandoc/Readers/DocBook.hs
@@ -360,7 +360,7 @@
 [x] refsectioninfo - Meta-information for a refsection
 [ ] refsynopsisdiv - A syntactic synopsis of the subject of the reference page
 [ ] refsynopsisdivinfo - Meta-information for a RefSynopsisDiv
-[x] releaseinfo - Information about a particular release of a document
+[ ] releaseinfo - Information about a particular release of a document
 [ ] remark - A remark (or comment) intended for presentation in a draft
     manuscript
 [x] replaceable - Content that may or must be replaced by the user
@@ -608,6 +608,7 @@
     addMetaField "author" e
     addMetaField "date" e
     addMetaField "release" e
+    addMetaField "releaseinfo" e
     return mempty
   where addMetaField fieldname elt =
             case filterChildren (named fieldname) elt of
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
@@ -261,47 +261,44 @@
   | otherwise = return rPr
 
 runStyleToTransform :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
-runStyleToTransform rPr
-  | Just sn <- getStyleName <$> rParentStyle rPr
-  , sn `elem` spansToKeep = do
-      transform <- runStyleToTransform rPr{rParentStyle = Nothing}
-      return $ spanWith ("", [normalizeToClassName sn], []) . transform
-  | Just s <- rParentStyle rPr = do
-      ei <- extraInfo spanWith s
-      transform <- runStyleToTransform rPr{rParentStyle = Nothing}
-      return $ ei . transform
-  | Just True <- isItalic rPr = do
-      transform <- runStyleToTransform rPr{isItalic = Nothing}
-      return $ emph  . transform
-  | Just True <- isBold rPr = do
-      transform <- runStyleToTransform rPr{isBold = Nothing}
-      return $ strong . transform
-  | Just True <- isSmallCaps rPr = do
-      transform <- runStyleToTransform rPr{isSmallCaps = Nothing}
-      return $ smallcaps . transform
-  | Just True <- isStrike rPr = do
-      transform <- runStyleToTransform rPr{isStrike = Nothing}
-      return $ strikeout . transform
-  | Just True <- isRTL rPr = do
-      transform <- runStyleToTransform rPr{isRTL = Nothing}
-      return $ spanWith ("",[],[("dir","rtl")]) . transform
-  | Just False <- isRTL rPr = do
-      transform <- runStyleToTransform rPr{isRTL = Nothing}
-      inBidi <- asks docxInBidi
-      return $ if inBidi
-               then spanWith ("",[],[("dir","ltr")]) . transform
-               else transform
-  | Just SupScrpt <- rVertAlign rPr = do
-      transform <- runStyleToTransform rPr{rVertAlign = Nothing}
-      return $ superscript . transform
-  | Just SubScrpt <- rVertAlign rPr = do
-      transform <- runStyleToTransform rPr{rVertAlign = Nothing}
-      return $ subscript . transform
-  | Just "single" <- rUnderline rPr = do
-      transform <- runStyleToTransform rPr{rUnderline = Nothing}
-      return $ Pandoc.underline . transform
-  | otherwise = return id
+runStyleToTransform rPr' = do
+  opts <- asks docxOptions
+  inBidi <- asks docxInBidi
+  let styles = isEnabled Ext_styles opts
+      ctl = (Just True == isRTL rPr') || (Just True == isForceCTL rPr')
+      italic rPr | ctl = isItalicCTL rPr
+                 | otherwise = isItalic rPr
+      bold rPr | ctl = isBoldCTL rPr
+               | otherwise = isBold rPr
+      go rPr
+        | Just sn <- getStyleName <$> rParentStyle rPr
+        , sn `elem` spansToKeep =
+            spanWith ("", [normalizeToClassName sn], [])
+            . go rPr{rParentStyle = Nothing}
+        | styles, Just s <- rParentStyle rPr =
+             spanWith (extraAttr s) . go rPr{rParentStyle = Nothing}
+        | Just True <- italic rPr =
+            emph . go rPr{isItalic = Nothing, isItalicCTL = Nothing}
+        | Just True <- bold rPr =
+            strong . go rPr{isBold = Nothing, isBoldCTL = Nothing}
+        | Just True <- isSmallCaps rPr =
+            smallcaps . go rPr{isSmallCaps = Nothing}
+        | Just True <- isStrike rPr =
+            strikeout . go rPr{isStrike = Nothing}
+        | Just True <- isRTL rPr =
+            spanWith ("",[],[("dir","rtl")]) . go rPr{isRTL = Nothing}
+        | inBidi, Just False <- isRTL rPr =
+            spanWith ("",[],[("dir","ltr")]) . go rPr{isRTL = Nothing}
+        | Just SupScrpt <- rVertAlign rPr =
+            superscript . go rPr{rVertAlign = Nothing}
+        | Just SubScrpt <- rVertAlign rPr = do
+            subscript . go rPr{rVertAlign = Nothing}
+        | Just "single" <- rUnderline rPr = do
+            Pandoc.underline . go rPr{rUnderline = Nothing}
+        | otherwise = id
+  return $ go rPr'
 
+
 runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
 runToInlines (Run rs runElems)
   | maybe False isCodeCharStyle $ rParentStyle rs = do
@@ -512,13 +509,8 @@
         isSp LineBreak = True
         isSp _         = False
 
-extraInfo :: (Eq (StyleName a), PandocMonad m, HasStyleName a)
-          => (Attr -> i -> i) -> a -> DocxContext m (i -> i)
-extraInfo f s = do
-  opts <- asks docxOptions
-  return $ if isEnabled Ext_styles opts
-              then f ("", [], [("custom-style", fromStyleName $ getStyleName s)])
-              else id
+extraAttr :: (Eq (StyleName a), HasStyleName a) => a -> Attr
+extraAttr s = ("", [], [("custom-style", fromStyleName $ getStyleName s)])
 
 parStyleToTransform :: PandocMonad m => ParagraphStyle -> DocxContext m (Blocks -> Blocks)
 parStyleToTransform pPr = case pStyle pPr of
@@ -534,8 +526,11 @@
     | otherwise -> do
         let pPr' = pPr { pStyle = cs }
         transform <- parStyleToTransform pPr'
-        ei <- extraInfo divWith c
-        return $ ei . (if isBlockQuote c then blockQuote else id) . transform
+        styles <- asks (isEnabled Ext_styles . docxOptions)
+        return $
+          (if styles then divWith (extraAttr c) else id)
+          . (if isBlockQuote c then blockQuote else id)
+          . transform
   []
     | Just left <- indentation pPr >>= leftParIndent -> do
         let pPr' = pPr { indentation = Nothing }
diff --git a/src/Text/Pandoc/Readers/Docx/Combine.hs b/src/Text/Pandoc/Readers/Docx/Combine.hs
--- a/src/Text/Pandoc/Readers/Docx/Combine.hs
+++ b/src/Text/Pandoc/Readers/Docx/Combine.hs
@@ -1,10 +1,9 @@
-{-# LANGUAGE FlexibleInstances    #-}
-{-# LANGUAGE PatternGuards        #-}
 {-# LANGUAGE OverloadedStrings    #-}
 {- |
    Module      : Text.Pandoc.Readers.Docx.Combine
    Copyright   : © 2014-2020 Jesse Rosenthal <jrosenthal@jhu.edu>,
-                   2014-2020 John MacFarlane <jgm@berkeley.edu>
+                   2014-2020 John MacFarlane <jgm@berkeley.edu>,
+                   2020 Nikolay Yakimov <root@livid.pp.ru>
    License     : GNU GPL, version 2 or above
 
    Maintainer  : Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -59,79 +58,61 @@
        where
 
 import Data.List
-import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr, (><), (|>))
-import qualified Data.Sequence as Seq (null)
+import Data.Bifunctor
+import Data.Sequence ( ViewL (..), ViewR (..), viewl, viewr, spanr, spanl
+                     , (><), (|>) )
 import Text.Pandoc.Builder
 
 data Modifier a = Modifier (a -> a)
                 | AttrModifier (Attr -> a -> a) Attr
-                | NullModifier
 
 spaceOutInlinesL :: Inlines -> (Inlines, Inlines)
 spaceOutInlinesL ms = (l, stackInlines fs (m' <> r))
-  where (l, m, r) = spaceOutInlines ms
-        (fs, m')  = unstackInlines m
+  where (l, (fs, m'), r) = spaceOutInlines ms
 
 spaceOutInlinesR :: Inlines -> (Inlines, Inlines)
 spaceOutInlinesR ms = (stackInlines fs (l <> m'), r)
-  where (l, m, r) = spaceOutInlines ms
-        (fs, m')  = unstackInlines m
+  where (l, (fs, m'), r) = spaceOutInlines ms
 
-spaceOutInlines :: Inlines -> (Inlines, Inlines, Inlines)
+spaceOutInlines :: Inlines -> (Inlines, ([Modifier Inlines], Inlines), Inlines)
 spaceOutInlines ils =
   let (fs, ils') = unstackInlines ils
-      contents = unMany ils'
-      left  = case viewl contents of
-        (Space :< _) -> space
-        _            -> mempty
-      right = case viewr contents of
-        (_ :> Space) -> space
-        _            -> mempty in
-  (left, stackInlines fs $ trimInlines . Many $ contents, right)
+      (left, (right, contents')) = second (spanr isSpace) $ spanl isSpace $ unMany ils'
+      -- NOTE: spanr counterintuitively returns suffix as the FIRST tuple element
+  in (Many left, (fs, Many contents'), Many right)
 
+isSpace :: Inline -> Bool
+isSpace Space = True
+isSpace SoftBreak = True
+isSpace _ = False
+
 stackInlines :: [Modifier Inlines] -> Inlines -> Inlines
 stackInlines [] ms = ms
-stackInlines (NullModifier : fs) ms = stackInlines fs ms
 stackInlines (Modifier f : fs) ms =
-  if isEmpty ms
+  if null ms
   then stackInlines fs ms
   else f $ stackInlines fs ms
 stackInlines (AttrModifier f attr : fs) ms = f attr $ stackInlines fs ms
 
 unstackInlines :: Inlines -> ([Modifier Inlines], Inlines)
-unstackInlines ms = case ilModifier ms of
-  NullModifier -> ([], ms)
-  _            -> (f : fs, ms') where
-    f = ilModifier ms
-    (fs, ms') = unstackInlines $ ilInnards ms
-
-ilModifier :: Inlines -> Modifier Inlines
-ilModifier ils = case viewl (unMany ils) of
-  (x :< xs) | Seq.null xs -> case x of
-    (Emph _)          -> Modifier emph
-    (Strong _)        -> Modifier strong
-    (SmallCaps _)     -> Modifier smallcaps
-    (Strikeout _)     -> Modifier strikeout
-    (Superscript _)   -> Modifier superscript
-    (Subscript _)     -> Modifier subscript
-    (Link attr _ tgt) -> Modifier $ linkWith attr (fst tgt) (snd tgt)
-    (Span attr _)     -> AttrModifier spanWith attr
-    _                 -> NullModifier
-  _ -> NullModifier
+unstackInlines ms = case ilModifierAndInnards ms of
+  Nothing         -> ([], ms)
+  Just (f, inner) -> first (f :) $ unstackInlines inner
 
-ilInnards :: Inlines -> Inlines
-ilInnards ils = case viewl (unMany ils) of
-  (x :< xs) | Seq.null xs -> case x of
-    (Emph lst)        -> fromList lst
-    (Strong lst)      -> fromList lst
-    (SmallCaps lst)   -> fromList lst
-    (Strikeout lst)   -> fromList lst
-    (Superscript lst) -> fromList lst
-    (Subscript lst)   -> fromList lst
-    (Link _ lst _)    -> fromList lst
-    (Span _ lst)      -> fromList lst
-    _                 -> ils
-  _          -> ils
+ilModifierAndInnards :: Inlines -> Maybe (Modifier Inlines, Inlines)
+ilModifierAndInnards ils = case viewl $ unMany ils of
+  x :< xs | null xs -> second fromList <$> case x of
+    Emph lst          -> Just (Modifier emph, lst)
+    Strong lst        -> Just (Modifier strong, lst)
+    SmallCaps lst     -> Just (Modifier smallcaps, lst)
+    Strikeout lst     -> Just (Modifier strikeout, lst)
+    Underline lst     -> Just (Modifier underline, lst)
+    Superscript lst   -> Just (Modifier superscript, lst)
+    Subscript lst     -> Just (Modifier subscript, lst)
+    Link attr lst tgt -> Just (Modifier $ linkWith attr (fst tgt) (snd tgt), lst)
+    Span attr lst     -> Just (AttrModifier spanWith attr, lst)
+    _                 -> Nothing
+  _ -> Nothing
 
 inlinesL :: Inlines -> (Inlines, Inlines)
 inlinesL ils = case viewl $ unMany ils of
@@ -161,12 +142,12 @@
       y_rem_attr = filter isAttrModifier y_remaining
   in
    case null shared of
-     True | isEmpty xs && isEmpty ys ->
-            stackInlines (x_rem_attr ++ y_rem_attr) mempty
-          | isEmpty xs ->
+     True | null xs && null ys ->
+            stackInlines (x_rem_attr <> y_rem_attr) mempty
+          | null xs ->
             let (sp, y') = spaceOutInlinesL y in
             stackInlines x_rem_attr mempty <> sp <> y'
-          | isEmpty ys ->
+          | null ys ->
             let (x', sp) = spaceOutInlinesR x in
             x' <> sp <> stackInlines y_rem_attr mempty
           | otherwise ->
@@ -193,11 +174,7 @@
 instance (Monoid a, Eq a) => Eq (Modifier a) where
   (Modifier f) == (Modifier g) = f mempty == g mempty
   (AttrModifier f attr) == (AttrModifier g attr') = f attr mempty == g attr' mempty
-  NullModifier == NullModifier = True
   _ == _ = False
-
-isEmpty :: (Monoid a, Eq a) => a -> Bool
-isEmpty x = x == mempty
 
 isAttrModifier :: Modifier a -> Bool
 isAttrModifier (AttrModifier _ _) = True
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -259,10 +259,13 @@
 leftBiasedMergeRunStyle :: RunStyle -> RunStyle -> RunStyle
 leftBiasedMergeRunStyle a b = RunStyle
     { isBold = isBold a <|> isBold b
+    , isBoldCTL = isBoldCTL a <|> isBoldCTL b
     , isItalic = isItalic a <|> isItalic b
+    , isItalicCTL = isItalicCTL a <|> isItalicCTL b
     , isSmallCaps = isSmallCaps a <|> isSmallCaps b
     , isStrike = isStrike a <|> isStrike b
     , isRTL = isRTL a <|> isRTL b
+    , isForceCTL = isForceCTL a <|> isForceCTL b
     , rVertAlign = rVertAlign a <|> rVertAlign b
     , rUnderline = rUnderline a <|> rUnderline b
     , rParentStyle = rParentStyle a
diff --git a/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs b/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
--- a/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse/Styles.hs
@@ -44,7 +44,6 @@
   ) where
 import Codec.Archive.Zip
 import Control.Applicative ((<|>))
-import Control.Monad.Except
 import Data.Function (on)
 import Data.String (IsString(..))
 import qualified Data.Map as M
@@ -101,10 +100,13 @@
                            } deriving (Show)
 
 data RunStyle = RunStyle { isBold       :: Maybe Bool
+                         , isBoldCTL    :: Maybe Bool
                          , isItalic     :: Maybe Bool
+                         , isItalicCTL  :: Maybe Bool
                          , isSmallCaps  :: Maybe Bool
                          , isStrike     :: Maybe Bool
                          , isRTL        :: Maybe Bool
+                         , isForceCTL   :: Maybe Bool
                          , rVertAlign   :: Maybe VertAlign
                          , rUnderline   :: Maybe String
                          , rParentStyle :: Maybe CharStyle
@@ -121,10 +123,13 @@
 
 defaultRunStyle :: RunStyle
 defaultRunStyle = RunStyle { isBold = Nothing
+                           , isBoldCTL = Nothing
                            , isItalic = Nothing
+                           , isItalicCTL = Nothing
                            , isSmallCaps = Nothing
                            , isStrike = Nothing
                            , isRTL = Nothing
+                           , isForceCTL = Nothing
                            , rVertAlign = Nothing
                            , rUnderline = Nothing
                            , rParentStyle = Nothing
@@ -240,20 +245,21 @@
 elemToCharStyle ns element parentStyle
   = CharStyle <$> (CharStyleId <$> findAttrTextByName ns "w" "styleId" element)
               <*> getElementStyleName ns element
-              <*> (Just $ elemToRunStyle ns element parentStyle)
+              <*> Just (elemToRunStyle ns element parentStyle)
 
 elemToRunStyle :: NameSpaces -> Element -> Maybe CharStyle -> RunStyle
 elemToRunStyle ns element parentStyle
   | Just rPr <- findChildByName ns "w" "rPr" element =
     RunStyle
       {
-        isBold = checkOnOff ns rPr (elemName ns "w" "b") `mplus`
-                 checkOnOff ns rPr (elemName ns "w" "bCs")
-      , isItalic = checkOnOff ns rPr (elemName ns "w" "i") `mplus`
-                   checkOnOff ns rPr (elemName ns "w" "iCs")
+        isBold = checkOnOff ns rPr (elemName ns "w" "b")
+      , isBoldCTL = checkOnOff ns rPr (elemName ns "w" "bCs")
+      , isItalic = checkOnOff ns rPr (elemName ns "w" "i")
+      , isItalicCTL = checkOnOff ns rPr (elemName ns "w" "iCs")
       , isSmallCaps = checkOnOff ns rPr (elemName ns "w" "smallCaps")
       , isStrike = checkOnOff ns rPr (elemName ns "w" "strike")
       , isRTL = checkOnOff ns rPr (elemName ns "w" "rtl")
+      , isForceCTL = checkOnOff ns rPr (elemName ns "w" "cs")
       , rVertAlign =
            findChildByName ns "w" "vertAlign" rPr >>=
            findAttrByName ns "w" "val" >>=
diff --git a/src/Text/Pandoc/Readers/Ipynb.hs b/src/Text/Pandoc/Readers/Ipynb.hs
--- a/src/Text/Pandoc/Readers/Ipynb.hs
+++ b/src/Text/Pandoc/Readers/Ipynb.hs
@@ -78,7 +78,11 @@
   mapM_ addAttachment attachments
   case cellType c of
     Ipynb.Markdown -> do
-      Pandoc _ bs <- walk fixImage <$> readMarkdown opts source
+      bs <- if isEnabled Ext_raw_markdown opts
+               then return [RawBlock (Format "markdown") source]
+               else do
+                 Pandoc _ bs <- walk fixImage <$> readMarkdown opts source
+                 return bs
       return $ B.divWith ("",["cell","markdown"],kvs)
              $ B.fromList bs
     Ipynb.Heading lev -> do
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -35,6 +35,7 @@
 import qualified Data.Map as M
 import Data.Maybe (fromMaybe, maybeToList)
 import qualified Data.Set as Set
+import qualified Data.Sequence as Seq
 import Data.Text (Text)
 import qualified Data.Text as T
 import System.FilePath (addExtension, replaceExtension, takeExtension)
@@ -258,6 +259,29 @@
                       emptyOr160 unit,
                       unit]
 
+-- converts e.g. \SIRange{100}{200}{\ms} to "100 ms--200 ms"
+doSIRange :: PandocMonad m => LP m Inlines
+doSIRange = do
+  skipopts
+  startvalue <- tok
+  startvalueprefix <- option "" $ bracketed tok
+  stopvalue <- tok
+  stopvalueprefix <- option "" $ bracketed tok
+  unit <- grouped (mconcat <$> many1 siUnit) <|> siUnit <|> tok
+  let emptyOr160 "" = ""
+      emptyOr160 _  = "\160"
+  return . mconcat $ [startvalueprefix,
+                      emptyOr160 startvalueprefix,
+                      startvalue,
+                      emptyOr160 unit,
+                      unit,
+                      "\8211", -- An en-dash
+                      stopvalueprefix,
+                      emptyOr160 stopvalueprefix,
+                      stopvalue,
+                      emptyOr160 unit,
+                      unit]
+
 siUnit :: PandocMonad m => LP m Inlines
 siUnit = do
   Tok _ (CtrlSeq name) _ <- anyControlSeq
@@ -586,44 +610,6 @@
 nlToSpace '\n' = ' '
 nlToSpace x    = x
 
-keyval :: PandocMonad m => LP m (Text, Text)
-keyval = try $ do
-  Tok _ Word key <- satisfyTok isWordTok
-  sp
-  val <- option mempty $ do
-           symbol '='
-           sp
-           (untokenize <$> braced) <|>
-             (mconcat <$> many1 (
-                 (untokenize . snd <$> withRaw braced)
-                 <|>
-                 (untokenize <$> (many1
-                      (satisfyTok
-                         (\t -> case t of
-                                Tok _ Symbol "]" -> False
-                                Tok _ Symbol "," -> False
-                                Tok _ Symbol "{" -> False
-                                Tok _ Symbol "}" -> False
-                                _                -> True))))))
-  optional (symbol ',')
-  sp
-  return (key, T.strip val)
-
-keyvals :: PandocMonad m => LP m [(Text, Text)]
-keyvals = try $ symbol '[' >> manyTill keyval (symbol ']') <* sp
-
-accent :: PandocMonad m => Char -> Maybe Char -> LP m Inlines
-accent combiningAccent fallBack = try $ do
-  ils <- tok
-  case toList ils of
-       (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
-         -- try to normalize to the combined character:
-         Str (Normalize.normalize Normalize.NFC
-               (T.pack [x, combiningAccent]) <> xs) : ys
-       [Space]           -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
-       []                -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
-       _                 -> return ils
-
 mathDisplay :: Text -> Inlines
 mathDisplay = displayMath . trimMath
 
@@ -782,6 +768,7 @@
          <|> ignore rawcommand
   lookupListDefault raw names inlineCommands
 
+
 tok :: PandocMonad m => LP m Inlines
 tok = try $ spaces >> grouped inline <|> inlineCommand' <|> singleChar'
   where singleChar' = do
@@ -794,36 +781,6 @@
 paropt :: PandocMonad m => LP m Inlines
 paropt = parenWrapped inline
 
-rawopt :: PandocMonad m => LP m Text
-rawopt = try $ do
-  sp
-  inner <- untokenize <$> bracketedToks
-  sp
-  return $ "[" <> inner <> "]"
-
-skipopts :: PandocMonad m => LP m ()
-skipopts = skipMany (void overlaySpecification <|> void rawopt)
-
--- opts in angle brackets are used in beamer
-overlaySpecification :: PandocMonad m => LP m Text
-overlaySpecification = try $ do
-  symbol '<'
-  t <- untokenize <$> manyTill overlayTok (symbol '>')
-  -- see issue #3368
-  guard $ not (T.all isLetter t) ||
-          t `elem` ["beamer","presentation", "trans",
-                    "handout","article", "second"]
-  return $ "<" <> t <> ">"
-
-overlayTok :: PandocMonad m => LP m Tok
-overlayTok =
-  satisfyTok (\t ->
-                  case t of
-                    Tok _ Word _       -> True
-                    Tok _ Spaces _     -> True
-                    Tok _ Symbol c     -> c `elem` ["-","+","@","|",":",","]
-                    _                  -> False)
-
 inBrackets :: Inlines -> Inlines
 inBrackets x = str "[" <> x <> str "]"
 
@@ -937,6 +894,7 @@
   , ("_", lit "_")
   , ("{", lit "{")
   , ("}", lit "}")
+  , ("qed", lit "\a0\x25FB")
   -- old TeX commands
   , ("em", extractSpaces emph <$> inlines)
   , ("it", extractSpaces emph <$> inlines)
@@ -1140,6 +1098,7 @@
   , ("acsp", doAcronymPlural "abbrv")
   -- siuntix
   , ("SI", dosiunitx)
+  , ("SIRange", doSIRange)
   -- hyphenat
   , ("bshyp", lit "\\\173")
   , ("fshyp", lit "/\173")
@@ -1178,6 +1137,19 @@
   , ("ifdim", ifdim)
   ]
 
+accent :: PandocMonad m => Char -> Maybe Char -> LP m Inlines
+accent combiningAccent fallBack = try $ do
+  ils <- tok
+  case toList ils of
+       (Str (T.uncons -> Just (x, xs)) : ys) -> return $ fromList $
+         -- try to normalize to the combined character:
+         Str (Normalize.normalize Normalize.NFC
+               (T.pack [x, combiningAccent]) <> xs) : ys
+       [Space]           -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
+       []                -> return $ str $ T.singleton $ fromMaybe combiningAccent fallBack
+       _                 -> return ils
+
+
 lettrine :: PandocMonad m => LP m Inlines
 lettrine = do
   optional opt
@@ -1333,39 +1305,6 @@
     convert LineBreak = Str ""
     convert x         = x
 
-getRawCommand :: PandocMonad m => Text -> Text -> LP m Text
-getRawCommand name txt = do
-  (_, rawargs) <- withRaw $
-      case name of
-           "write" -> do
-             void $ satisfyTok isWordTok -- digits
-             void braced
-           "titleformat" -> do
-             void braced
-             skipopts
-             void $ count 4 braced
-           "def" ->
-             void $ manyTill anyTok braced
-           _ | isFontSizeCommand name -> return ()
-             | otherwise -> do
-               skipopts
-               option "" (try dimenarg)
-               void $ many braced
-  return $ txt <> untokenize rawargs
-
-isFontSizeCommand :: Text -> Bool
-isFontSizeCommand "tiny" = True
-isFontSizeCommand "scriptsize" = True
-isFontSizeCommand "footnotesize" = True
-isFontSizeCommand "small" = True
-isFontSizeCommand "normalsize" = True
-isFontSizeCommand "large" = True
-isFontSizeCommand "Large" = True
-isFontSizeCommand "LARGE" = True
-isFontSizeCommand "huge" = True
-isFontSizeCommand "Huge" = True
-isFontSizeCommand _ = False
-
 isBlockCommand :: Text -> Bool
 isBlockCommand s =
   s `M.member` (blockCommands :: M.Map Text (LP PandocPure Blocks))
@@ -1471,20 +1410,6 @@
 
 -- block elements:
 
-begin_ :: PandocMonad m => Text -> LP m ()
-begin_ t = try (do
-  controlSeq "begin"
-  spaces
-  txt <- untokenize <$> braced
-  guard (t == txt)) <?> ("\\begin{" ++ T.unpack t ++ "}")
-
-end_ :: PandocMonad m => Text -> LP m ()
-end_ t = try (do
-  controlSeq "end"
-  spaces
-  txt <- untokenize <$> braced
-  guard $ t == txt) <?> ("\\end{" ++ T.unpack t ++ "}")
-
 preamble :: PandocMonad m => LP m Blocks
 preamble = mconcat <$> many preambleBlock
   where preambleBlock =  (mempty <$ spaces1)
@@ -1824,6 +1749,8 @@
    , ("address", mempty <$ (skipopts *> tok >>= addMeta "address"))
    , ("signature", mempty <$ (skipopts *> authors))
    , ("date", mempty <$ (skipopts *> tok >>= addMeta "date"))
+   , ("newtheorem", newtheorem)
+   , ("theoremstyle", theoremstyle)
    -- KOMA-Script metadata commands
    , ("extratitle", mempty <$ (skipopts *> tok >>= addMeta "extratitle"))
    , ("frontispiece", mempty <$ (skipopts *> tok >>= addMeta "frontispiece"))
@@ -1946,6 +1873,8 @@
    , ("tikzcd", rawVerbEnv "tikzcd")
    , ("lilypond", rawVerbEnv "lilypond")
    , ("ly", rawVerbEnv "ly")
+   -- amsthm
+   , ("proof", proof)
    -- etoolbox
    , ("ifstrequal", ifstrequal)
    , ("newtoggle", braced >>= newToggle)
@@ -1954,16 +1883,127 @@
    , ("iftoggle", try $ ifToggle >> block)
    ]
 
+theoremstyle :: PandocMonad m => LP m Blocks
+theoremstyle = do
+  stylename <- untokenize <$> braced
+  let mbstyle = case stylename of
+                  "plain"      -> Just PlainStyle
+                  "definition" -> Just DefinitionStyle
+                  "remark"     -> Just RemarkStyle
+                  _            -> Nothing
+  case mbstyle of
+    Nothing  -> return ()
+    Just sty -> updateState $ \s -> s{ sLastTheoremStyle = sty }
+  return mempty
+
+newtheorem :: PandocMonad m => LP m Blocks
+newtheorem = do
+  number <- option True (False <$ symbol '*' <* sp)
+  name <- untokenize <$> braced
+  sp
+  series <- option Nothing $ Just . untokenize <$> bracketedToks
+  sp
+  showName <- untokenize <$> braced
+  sp
+  syncTo <- option Nothing $ Just . untokenize <$> bracketedToks
+  sty <- sLastTheoremStyle <$> getState
+  let spec = TheoremSpec { theoremName = showName
+                         , theoremStyle = sty
+                         , theoremSeries = series
+                         , theoremSyncTo = syncTo
+                         , theoremNumber = number
+                         , theoremLastNum = DottedNum [0] }
+  tmap <- sTheoremMap <$> getState
+  updateState $ \s -> s{ sTheoremMap =
+                            M.insert name spec tmap }
+  return mempty
+
+proof :: PandocMonad m => LP m Blocks
+proof = do
+  title <- option (B.text "Proof") opt
+  bs <- env "proof" blocks
+  return $
+    B.divWith ("", ["proof"], []) $
+      addQed $ addTitle (B.emph (title <> ".")) $ bs
+
+addTitle :: Inlines -> Blocks -> Blocks
+addTitle ils bs =
+  case B.toList bs of
+    (Para xs : rest)
+      -> B.fromList (Para (B.toList ils ++ (Space : xs)) : rest)
+    _ -> B.para ils <> bs
+
+addQed :: Blocks -> Blocks
+addQed bs =
+  case Seq.viewr (B.unMany bs) of
+    s Seq.:> Para ils
+      -> B.Many (s Seq.|> Para (ils ++ B.toList qedSign))
+    _ -> bs <> B.para qedSign
+ where
+  qedSign = B.str "\xa0\x25FB"
+
 environment :: PandocMonad m => LP m Blocks
 environment = try $ do
   controlSeq "begin"
   name <- untokenize <$> braced
   M.findWithDefault mzero name environments <|>
+    theoremEnvironment name <|>
     if M.member name (inlineEnvironments
                        :: M.Map Text (LP PandocPure Inlines))
        then mzero
        else try (rawEnv name) <|> rawVerbEnv name
 
+theoremEnvironment :: PandocMonad m => Text -> LP m Blocks
+theoremEnvironment name = do
+  tmap <- sTheoremMap <$> getState
+  case M.lookup name tmap of
+    Nothing -> mzero
+    Just tspec -> do
+       optTitle <- option mempty $ (\x -> space <> "(" <> x <> ")") <$> opt
+       mblabel <- option Nothing $ Just . untokenize <$>
+                   try (spaces >> controlSeq "label" >> spaces >> braced)
+       bs <- env name blocks
+       number <-
+         if theoremNumber tspec
+            then do
+               let name' = fromMaybe name $ theoremSeries tspec
+               num <- getNextNumber
+                   (fromMaybe (DottedNum [0]) .
+                    fmap theoremLastNum .
+                    M.lookup name' . sTheoremMap)
+               updateState $ \s ->
+                 s{ sTheoremMap =
+                       M.adjust
+                       (\spec -> spec{ theoremLastNum = num })
+                       name'
+                       (sTheoremMap s)
+                  }
+
+               case mblabel of
+                 Just ident ->
+                   updateState $ \s ->
+                     s{ sLabels = M.insert ident
+                         [Str (theoremName tspec), Str "\160",
+                          Str (renderDottedNum num)] (sLabels s) }
+                 Nothing -> return ()
+               return $ space <> B.text (renderDottedNum num)
+            else return mempty
+       let titleEmph = case theoremStyle tspec of
+                         PlainStyle      -> B.strong
+                         DefinitionStyle -> B.strong
+                         RemarkStyle     -> B.emph
+       let title = titleEmph (B.text (theoremName tspec) <> number)
+                                      <> optTitle <> "." <> space
+       return $ divWith (fromMaybe "" mblabel, [name], []) $ addTitle title
+              $ case theoremStyle tspec of
+                  PlainStyle -> walk italicize bs
+                  _          -> bs
+
+italicize :: Block -> Block
+italicize (Para ils) = Para [Emph ils]
+italicize (Plain ils) = Plain [Emph ils]
+italicize x = x
+
 env :: PandocMonad m => Text -> LP m a -> LP m a
 env name p = p <* end_ name
 
@@ -1997,24 +2037,6 @@
        report $ SkippedContent raw' pos
        return mempty
 
-verbEnv :: PandocMonad m => Text -> LP m Text
-verbEnv name = withVerbatimMode $ do
-  optional blankline
-  res <- manyTill anyTok (end_ name)
-  return $ stripTrailingNewline
-         $ untokenize
-         $ res
-
--- Strip single final newline and any spaces following it.
--- Input is unchanged if it doesn't end with newline +
--- optional spaces.
-stripTrailingNewline :: Text -> Text
-stripTrailingNewline t =
-  let (b, e) = T.breakOnEnd "\n" t
-  in  if T.all (== ' ') e
-         then T.dropEnd 1 b
-         else t
-
 fancyverbEnv :: PandocMonad m => Text -> LP m Blocks
 fancyverbEnv name = do
   options <- option [] keyvals
@@ -2340,10 +2362,9 @@
 parseTableRow :: PandocMonad m
               => Text   -- ^ table environment name
               -> [([Tok], [Tok])] -- ^ pref/suffixes
-              -> LP m [Blocks]
+              -> LP m Row
 parseTableRow envname prefsufs = do
   notFollowedBy (spaces *> end_ envname)
-  let cols = length prefsufs
   -- add prefixes and suffixes in token stream:
   let celltoks (pref, suff) = do
         prefpos <- getPosition
@@ -2362,22 +2383,63 @@
   cells <- mapM (\ts -> setInput ts >> parseTableCell) rawcells
   setInput oldInput
   spaces
-  let numcells = length cells
-  guard $ numcells <= cols && numcells >= 1
-  guard $ cells /= [mempty]
-  -- note:  a & b in a three-column table leaves an empty 3rd cell:
-  return $ cells ++ replicate (cols - numcells) mempty
+  return $ Row nullAttr cells 
 
-parseTableCell :: PandocMonad m => LP m Blocks
+parseTableCell :: PandocMonad m => LP m Cell
 parseTableCell = do
-  let plainify bs = case toList bs of
-                         [Para ils] -> plain (fromList ils)
-                         _          -> bs
   updateState $ \st -> st{ sInTableCell = True }
-  cells <- plainify <$> blocks
+  cell' <- parseMultiCell <|> parseSimpleCell
   updateState $ \st -> st{ sInTableCell = False }
-  return cells
+  return cell'
 
+cellAlignment :: PandocMonad m => LP m Alignment
+cellAlignment = skipMany (symbol '|') *> alignment <* skipMany (symbol '|')
+  where
+    alignment = do
+      c <- untoken <$> singleChar
+      return $ case c of
+        "l" -> AlignLeft
+        "r" -> AlignRight
+        "c" -> AlignCenter
+        "*" -> AlignDefault
+        _   -> AlignDefault
+
+plainify :: Blocks -> Blocks
+plainify bs = case toList bs of
+                [Para ils] -> plain (fromList ils)
+                _          -> bs
+
+parseMultiCell :: PandocMonad m => LP m Cell
+parseMultiCell =   (controlSeq "multirow"    >> parseMultirowCell) 
+               <|> (controlSeq "multicolumn" >> parseMulticolCell)
+  where
+    parseMultirowCell = parseMultiXCell RowSpan (const $ ColSpan 1)
+    parseMulticolCell = parseMultiXCell (const $ RowSpan 1) ColSpan
+
+    parseMultiXCell rowspanf colspanf = do
+      span' <- fmap (fromMaybe 1 . safeRead . untokenize) braced
+      alignment <- symbol '{' *> cellAlignment <* symbol '}'
+
+      -- Two possible contents: either a nested \multirow/\multicol, or content.
+      -- E.g. \multirow{1}{c}{\multicol{1}{c}{content}}
+      let singleCell = do
+            content <- plainify <$> blocks
+            return $ cell alignment (rowspanf span') (colspanf span') content
+
+      let nestedCell = do
+            (Cell _ _ (RowSpan rs) (ColSpan cs) bs) <- parseMultiCell
+            return $ cell
+                      alignment
+                      (RowSpan $ max span' rs)
+                      (ColSpan $ max span' cs)
+                      (fromList bs)
+
+      symbol '{' *> (nestedCell <|> singleCell) <* symbol '}'
+
+-- Parse a simple cell, i.e. not multirow/multicol
+parseSimpleCell :: PandocMonad m => LP m Cell
+parseSimpleCell = simpleCell <$> (plainify <$> blocks)
+
 simpTable :: PandocMonad m => Text -> Bool -> LP m Blocks
 simpTable envname hasWidthParameter = try $ do
   when hasWidthParameter $ () <$ (spaces >> tok)
@@ -2392,8 +2454,8 @@
   spaces
   skipMany hline
   spaces
-  header' <- option [] $ try (parseTableRow envname prefsufs <*
-                                   lbreak <* many1 hline)
+  header' <- option [] . try . fmap (:[]) $
+             parseTableRow envname prefsufs <* lbreak <* many1 hline
   spaces
   rows <- sepEndBy (parseTableRow envname prefsufs)
                     (lbreak <* optional (skipMany hline))
@@ -2405,12 +2467,10 @@
   optional lbreak
   spaces
   lookAhead $ controlSeq "end" -- make sure we're at end
-  let toRow = Row nullAttr . map simpleCell
-      toHeaderRow l = if null l then [] else [toRow l]
   return $ table emptyCaption
                  (zip aligns widths)
-                 (TableHead nullAttr $ toHeaderRow header')
-                 [TableBody nullAttr 0 [] $ map toRow rows]
+                 (TableHead nullAttr $ header')
+                 [TableBody nullAttr 0 [] rows]
                  (TableFoot nullAttr [])
 
 addTableCaption :: PandocMonad m => Blocks -> LP m Blocks
diff --git a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs
--- a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs
+++ b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings     #-}
 {-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE ViewPatterns          #-}
 {- |
    Module      : Text.Pandoc.Readers.LaTeX.Parsing
    Copyright   : Copyright (C) 2006-2020 John MacFarlane
@@ -17,6 +18,8 @@
   ( DottedNum(..)
   , renderDottedNum
   , incrementDottedNum
+  , TheoremSpec(..)
+  , TheoremStyle(..)
   , LaTeXState(..)
   , defaultLaTeXState
   , LP
@@ -66,6 +69,14 @@
   , dimenarg
   , ignore
   , withRaw
+  , keyvals
+  , verbEnv
+  , begin_
+  , end_
+  , getRawCommand
+  , skipopts
+  , rawopt
+  , overlaySpecification
   ) where
 
 import Control.Applicative (many, (<|>))
@@ -93,7 +104,7 @@
 -- import Debug.Trace
 
 newtype DottedNum = DottedNum [Int]
-  deriving (Show)
+  deriving (Show, Eq)
 
 renderDottedNum :: DottedNum -> T.Text
 renderDottedNum (DottedNum xs) = T.pack $
@@ -105,6 +116,20 @@
        (x:xs) -> reverse (x+1 : xs)
        []     -> []  -- shouldn't happen
 
+data TheoremStyle =
+  PlainStyle | DefinitionStyle | RemarkStyle
+  deriving (Show, Eq)
+
+data TheoremSpec =
+  TheoremSpec
+    { theoremName    :: Text
+    , theoremStyle   :: TheoremStyle
+    , theoremSeries  :: Maybe Text
+    , theoremSyncTo  :: Maybe Text
+    , theoremNumber  :: Bool
+    , theoremLastNum :: DottedNum }
+    deriving (Show, Eq)
+
 data LaTeXState = LaTeXState{ sOptions       :: ReaderOptions
                             , sMeta          :: Meta
                             , sQuoteContext  :: QuoteContext
@@ -119,6 +144,8 @@
                             , sLastHeaderNum :: DottedNum
                             , sLastFigureNum :: DottedNum
                             , sLastTableNum  :: DottedNum
+                            , sTheoremMap    :: M.Map Text TheoremSpec
+                            , sLastTheoremStyle :: TheoremStyle
                             , sLastLabel     :: Maybe Text
                             , sLabels        :: M.Map Text [Inline]
                             , sHasChapters   :: Bool
@@ -142,6 +169,8 @@
                               , sLastHeaderNum = DottedNum []
                               , sLastFigureNum = DottedNum []
                               , sLastTableNum  = DottedNum []
+                              , sTheoremMap    = M.empty
+                              , sLastTheoremStyle = PlainStyle
                               , sLastLabel     = Nothing
                               , sLabels        = M.empty
                               , sHasChapters   = False
@@ -695,3 +724,125 @@
   let raw = takeWhile (\(Tok pos _ _) -> maybe True
                   (\p -> sourceName p /= sourceName pos || pos < p) nxtpos) inp
   return (result, raw)
+
+keyval :: PandocMonad m => LP m (Text, Text)
+keyval = try $ do
+  Tok _ Word key <- satisfyTok isWordTok
+  sp
+  val <- option mempty $ do
+           symbol '='
+           sp
+           (untokenize <$> braced) <|>
+             (mconcat <$> many1 (
+                 (untokenize . snd <$> withRaw braced)
+                 <|>
+                 (untokenize <$> (many1
+                      (satisfyTok
+                         (\t -> case t of
+                                Tok _ Symbol "]" -> False
+                                Tok _ Symbol "," -> False
+                                Tok _ Symbol "{" -> False
+                                Tok _ Symbol "}" -> False
+                                _                -> True))))))
+  optional (symbol ',')
+  sp
+  return (key, T.strip val)
+
+keyvals :: PandocMonad m => LP m [(Text, Text)]
+keyvals = try $ symbol '[' >> manyTill keyval (symbol ']') <* sp
+
+verbEnv :: PandocMonad m => Text -> LP m Text
+verbEnv name = withVerbatimMode $ do
+  optional blankline
+  res <- manyTill anyTok (end_ name)
+  return $ stripTrailingNewline
+         $ untokenize
+         $ res
+
+-- Strip single final newline and any spaces following it.
+-- Input is unchanged if it doesn't end with newline +
+-- optional spaces.
+stripTrailingNewline :: Text -> Text
+stripTrailingNewline t =
+  let (b, e) = T.breakOnEnd "\n" t
+  in  if T.all (== ' ') e
+         then T.dropEnd 1 b
+         else t
+
+begin_ :: PandocMonad m => Text -> LP m ()
+begin_ t = try (do
+  controlSeq "begin"
+  spaces
+  txt <- untokenize <$> braced
+  guard (t == txt)) <?> ("\\begin{" ++ T.unpack t ++ "}")
+
+end_ :: PandocMonad m => Text -> LP m ()
+end_ t = try (do
+  controlSeq "end"
+  spaces
+  txt <- untokenize <$> braced
+  guard $ t == txt) <?> ("\\end{" ++ T.unpack t ++ "}")
+
+getRawCommand :: PandocMonad m => Text -> Text -> LP m Text
+getRawCommand name txt = do
+  (_, rawargs) <- withRaw $
+      case name of
+           "write" -> do
+             void $ satisfyTok isWordTok -- digits
+             void braced
+           "titleformat" -> do
+             void braced
+             skipopts
+             void $ count 4 braced
+           "def" ->
+             void $ manyTill anyTok braced
+           _ | isFontSizeCommand name -> return ()
+             | otherwise -> do
+               skipopts
+               option "" (try dimenarg)
+               void $ many braced
+  return $ txt <> untokenize rawargs
+
+skipopts :: PandocMonad m => LP m ()
+skipopts = skipMany (void overlaySpecification <|> void rawopt)
+
+-- opts in angle brackets are used in beamer
+overlaySpecification :: PandocMonad m => LP m Text
+overlaySpecification = try $ do
+  symbol '<'
+  t <- untokenize <$> manyTill overlayTok (symbol '>')
+  -- see issue #3368
+  guard $ not (T.all isLetter t) ||
+          t `elem` ["beamer","presentation", "trans",
+                    "handout","article", "second"]
+  return $ "<" <> t <> ">"
+
+overlayTok :: PandocMonad m => LP m Tok
+overlayTok =
+  satisfyTok (\t ->
+                  case t of
+                    Tok _ Word _       -> True
+                    Tok _ Spaces _     -> True
+                    Tok _ Symbol c     -> c `elem` ["-","+","@","|",":",","]
+                    _                  -> False)
+
+rawopt :: PandocMonad m => LP m Text
+rawopt = try $ do
+  sp
+  inner <- untokenize <$> bracketedToks
+  sp
+  return $ "[" <> inner <> "]"
+
+isFontSizeCommand :: Text -> Bool
+isFontSizeCommand "tiny" = True
+isFontSizeCommand "scriptsize" = True
+isFontSizeCommand "footnotesize" = True
+isFontSizeCommand "small" = True
+isFontSizeCommand "normalsize" = True
+isFontSizeCommand "large" = True
+isFontSizeCommand "Large" = True
+isFontSizeCommand "LARGE" = True
+isFontSizeCommand "huge" = True
+isFontSizeCommand "Huge" = True
+isFontSizeCommand _ = False
+
diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs
--- a/src/Text/Pandoc/Readers/Org/Blocks.hs
+++ b/src/Text/Pandoc/Readers/Org/Blocks.hs
@@ -608,7 +608,10 @@
   }
 
 table :: PandocMonad m => OrgParser m (F Blocks)
-table = gridTableWith blocks True <|> orgTable
+table = do
+  withTables <- getExportSetting exportWithTables
+  tbl <- gridTableWith blocks True <|> orgTable
+  return $ if withTables then tbl else mempty
 
 -- | A normal org table
 orgTable :: PandocMonad m => OrgParser m (F Blocks)
diff --git a/src/Text/Pandoc/Readers/Org/ExportSettings.hs b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
--- a/src/Text/Pandoc/Readers/Org/ExportSettings.hs
+++ b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
@@ -47,9 +47,9 @@
   , booleanSetting "creator" (\val es -> es { exportWithCreator = val })
   , complementableListSetting "d" (\val es -> es { exportDrawers = val })
   , ignoredSetting "date"
-  , ignoredSetting "e"
+  , booleanSetting "e" (\val es -> es { exportWithEntities = val })
   , booleanSetting "email" (\val es -> es { exportWithEmail = val })
-  , ignoredSetting "f"
+  , booleanSetting "f" (\val es -> es { exportWithFootnotes = val })
   , integerSetting "H" (\val es -> es { exportHeadlineLevels = val })
   , ignoredSetting "inline"
   , ignoredSetting "num"
@@ -64,7 +64,7 @@
   , ignoredSetting "title"
   , ignoredSetting "toc"
   , booleanSetting "todo" (\val es -> es { exportWithTodoKeywords = val })
-  , ignoredSetting "|"
+  , booleanSetting "|" (\val es -> es { exportWithTables = val })
   , ignoreAndWarn
   ] <?> "export setting"
 
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -378,7 +378,10 @@
               else rest
 
 footnote :: PandocMonad m => OrgParser m (F Inlines)
-footnote = try $ inlineNote <|> referencedNote
+footnote = try $ do
+  note <- inlineNote <|> referencedNote
+  withNote <- getExportSetting exportWithFootnotes
+  return $ if withNote then note else mempty
 
 inlineNote :: PandocMonad m => OrgParser m (F Inlines)
 inlineNote = try $ do
@@ -790,9 +793,12 @@
 inlineLaTeX = try $ do
   cmd <- inlineLaTeXCommand
   texOpt <- getExportSetting exportWithLatex
+  allowEntities <- getExportSetting exportWithEntities
   ils <- parseAsInlineLaTeX cmd texOpt
   maybe mzero returnF $
-     parseAsMathMLSym cmd `mplus` parseAsMath cmd texOpt `mplus` ils
+     parseAsMathMLSym allowEntities cmd `mplus`
+     parseAsMath cmd texOpt `mplus`
+     ils
  where
    parseAsInlineLaTeX :: PandocMonad m
                       => Text -> TeXExport -> OrgParser m (Maybe Inlines)
@@ -801,10 +807,15 @@
      TeXIgnore -> return (Just mempty)
      TeXVerbatim -> return (Just $ B.str cs)
 
-   parseAsMathMLSym :: Text -> Maybe Inlines
-   parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
-    -- drop initial backslash and any trailing "{}"
-    where clean = T.dropWhileEnd (`elem` ("{}" :: String)) . T.drop 1
+   parseAsMathMLSym :: Bool -> Text -> Maybe Inlines
+   parseAsMathMLSym allowEntities cs = do
+     -- drop initial backslash and any trailing "{}"
+     let clean = T.dropWhileEnd (`elem` ("{}" :: String)) . T.drop 1
+     -- If entities are disabled, then return the string as text, but
+     -- only if this *is* a MathML entity.
+     case B.str <$> MathMLEntityMap.getUnicode (clean cs) of
+       Just _ | not allowEntities -> Just $ B.str cs
+       x -> x
 
    state :: ParserState
    state = def{ stateOptions = def{ readerExtensions =
diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs
--- a/src/Text/Pandoc/Readers/Org/ParserState.hs
+++ b/src/Text/Pandoc/Readers/Org/ParserState.hs
@@ -257,9 +257,12 @@
   , exportWithAuthor       :: Bool -- ^ Include author in final meta-data
   , exportWithCreator      :: Bool -- ^ Include creator in final meta-data
   , exportWithEmail        :: Bool -- ^ Include email in final meta-data
+  , exportWithEntities     :: Bool -- ^ Include MathML-like entities
+  , exportWithFootnotes    :: Bool -- ^ Include footnotes
   , exportWithLatex        :: TeXExport -- ^ Handling of raw TeX commands
   , exportWithPlanning     :: Bool -- ^ Keep planning info after headlines
   , exportWithTags         :: Bool -- ^ Keep tags as part of headlines
+  , exportWithTables       :: Bool -- ^ Include tables
   , exportWithTodoKeywords :: Bool -- ^ Keep TODO keywords in headers
   }
 
@@ -279,8 +282,11 @@
   , exportWithAuthor = True
   , exportWithCreator = True
   , exportWithEmail = True
+  , exportWithEntities = True
+  , exportWithFootnotes = True
   , exportWithLatex = TeXExport
   , exportWithPlanning = False
   , exportWithTags = True
+  , exportWithTables = True
   , exportWithTodoKeywords = True
   }
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
@@ -223,7 +223,8 @@
   first <- anyLine
   rest <- option "" $ try $ do lookAhead (count indent (char ' ') >> spaceChar)
                                indentedBlock
-  let raw = (if T.null first then "" else first <> "\n") <> rest <> "\n"
+  let raw = (if T.null first then "" else first <> "\n") <> rest <>
+            (if T.null first && T.null rest then "" else "\n")
   return (name, raw)
 
 fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
@@ -484,7 +485,7 @@
                              Just patt -> drop 1 .
                                             dropWhile (not . (patt `T.isInfixOf`))
                              Nothing   -> id) $ contentLines'
-  let contents' = T.unlines contentLines'' <> "\n"
+  let contents' = T.unlines contentLines''
   case lookup "code" fields of
        Just lang -> do
          let classes =  maybe [] T.words (lookup "class" fields)
@@ -494,7 +495,7 @@
                          Just _  -> return $ B.rawBlock "rst" contents'
                          Nothing -> do
                            setPosition $ newPos (T.unpack f) 1 1
-                           setInput contents'
+                           setInput $ contents' <> "\n"
                            bs <- optional blanklines >>
                                   (mconcat <$> many block)
                            setInput oldInput
@@ -878,7 +879,12 @@
        Left e  ->
          throwError $ PandocParsecError "csv table" e
        Right rawrows -> do
-         let parseCell = parseFromString' (plain <|> return mempty)
+         let singleParaToPlain bs =
+               case B.toList bs of
+                 [Para ils] -> B.fromList [Plain ils]
+                 _          -> bs
+         let parseCell t = singleParaToPlain
+                <$> parseFromString' parseBlocks (t <> "\n\n")
          let parseRow = mapM parseCell
          rows <- mapM parseRow rawrows
          let (headerRow,bodyRows,numOfCols) =
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
@@ -97,6 +97,7 @@
        "markdown_mmd"      -> getDefaultTemplate "markdown"
        "markdown_phpextra" -> getDefaultTemplate "markdown"
        "gfm"               -> getDefaultTemplate "commonmark"
+       "commonmark_x"      -> getDefaultTemplate "commonmark"
        _        -> do
          let fname = "templates" </> "default" <.> T.unpack format
          UTF8.toText <$> readDataFile fname
diff --git a/src/Text/Pandoc/Writers.hs b/src/Text/Pandoc/Writers.hs
--- a/src/Text/Pandoc/Writers.hs
+++ b/src/Text/Pandoc/Writers.hs
@@ -178,6 +178,7 @@
   ,("asciidoctor"  , TextWriter writeAsciiDoctor)
   ,("haddock"      , TextWriter writeHaddock)
   ,("commonmark"   , TextWriter writeCommonMark)
+  ,("commonmark_x" , TextWriter writeCommonMark)
   ,("gfm"          , TextWriter writeCommonMark)
   ,("tei"          , TextWriter writeTEI)
   ,("muse"         , TextWriter writeMuse)
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
--- a/src/Text/Pandoc/Writers/CommonMark.hs
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -15,353 +15,5 @@
 -}
 module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
 
-import CMarkGFM
-import Control.Monad.State.Strict (State, get, modify, runState)
-import Data.Char (isAscii)
-import Data.Foldable (foldrM)
-import Data.List (transpose)
-import Data.Text (Text)
-import qualified Data.Text as T
-import Network.HTTP (urlEncode)
-import Text.Pandoc.Class.PandocMonad (PandocMonad)
-import Text.Pandoc.Definition
-import Text.Pandoc.Options
-import Text.Pandoc.Shared (capitalize, isTightList,
-    linesToPara, onlySimpleTableCells, taskListItemToAscii, tshow)
-import Text.Pandoc.Templates (renderTemplate)
-import Text.Pandoc.Walk (walk, walkM)
-import Text.Pandoc.Writers.HTML (writeHtml5String, tagWithAttributes)
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.XML (toHtml5Entities)
-import Text.DocLayout (literal, render)
-
--- | Convert Pandoc to CommonMark.
-writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
-writeCommonMark opts (Pandoc meta blocks) = do
-  toc <- if writerTableOfContents opts
-            then blocksToCommonMark opts [ toTableOfContents opts blocks ]
-            else return mempty
-
-  let (blocks', notes) = runState (walkM processNotes blocks) []
-      notes' = [OrderedList (1, Decimal, Period) $ reverse notes | not (null notes)]
-  main <-  blocksToCommonMark opts (blocks' ++ notes')
-  metadata <- metaToContext opts
-              (fmap (literal . T.stripEnd) . blocksToCommonMark opts)
-              (fmap (literal . T.stripEnd) . inlinesToCommonMark opts)
-              meta
-  let context =
-          -- for backwards compatibility we populate toc
-          -- with the contents of the toc, rather than a boolean:
-          defField "toc" toc
-        $ defField "table-of-contents" toc
-        $ defField "body" main metadata
-  return $
-    case writerTemplate opts of
-       Nothing  -> main
-       Just tpl -> render Nothing $ renderTemplate tpl context
-
-softBreakToSpace :: Inline -> Inline
-softBreakToSpace SoftBreak = Space
-softBreakToSpace x         = x
-
-processNotes :: Inline -> State [[Block]] Inline
-processNotes (Note bs) = do
-  modify (bs :)
-  notes <- get
-  return $ Str $ "[" <> tshow (length notes) <> "]"
-processNotes x = return x
-
-node :: NodeType -> [Node] -> Node
-node = Node Nothing
-
-blocksToCommonMark :: PandocMonad m => WriterOptions -> [Block] -> m Text
-blocksToCommonMark opts bs = do
-  let cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
-      colwidth = if writerWrapText opts == WrapAuto
-                 then Just $ writerColumns opts
-                 else Nothing
-  nodes <- blocksToNodes opts bs
-  return $ T.stripEnd $
-    nodeToCommonmark cmarkOpts colwidth $
-    node DOCUMENT nodes
-
-inlinesToCommonMark :: PandocMonad m => WriterOptions -> [Inline] -> m Text
-inlinesToCommonMark opts ils = return $
-  nodeToCommonmark cmarkOpts colwidth $
-    node PARAGRAPH (inlinesToNodes opts ils)
-   where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
-         colwidth = if writerWrapText opts == WrapAuto
-                       then Just $ writerColumns opts
-                       else Nothing
-
-blocksToNodes :: PandocMonad m => WriterOptions -> [Block] -> m [Node]
-blocksToNodes opts = foldrM (blockToNodes opts) []
-
-blockToNodes :: PandocMonad m => WriterOptions -> Block -> [Node] -> m [Node]
-blockToNodes opts (Plain xs) ns =
-  return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
-blockToNodes opts (Para xs) ns =
-  return (node PARAGRAPH (inlinesToNodes opts xs) : ns)
-blockToNodes opts (LineBlock lns) ns = blockToNodes opts (linesToPara lns) ns
-blockToNodes _ (CodeBlock (_,classes,_) xs) ns = return
-  (node (CODE_BLOCK (T.unwords classes) xs) [] : ns)
-blockToNodes opts (RawBlock (Format f) xs) ns
-  | f == "html" && isEnabled Ext_raw_html opts
-              = return (node (HTML_BLOCK xs) [] : ns)
-  | (f == "latex" || f == "tex") && isEnabled Ext_raw_tex opts
-              = return (node (CUSTOM_BLOCK xs T.empty) [] : ns)
-  | f == "markdown"
-              = return (node (CUSTOM_BLOCK xs T.empty) [] : ns)
-  | otherwise = return ns
-blockToNodes opts (BlockQuote bs) ns = do
-  nodes <- blocksToNodes opts bs
-  return (node BLOCK_QUOTE nodes : ns)
-blockToNodes opts (BulletList items) ns = do
-  let exts = writerExtensions opts
-  nodes <- mapM (blocksToNodes opts . taskListItemToAscii exts) items
-  return (node (LIST ListAttributes{
-                   listType = BULLET_LIST,
-                   listDelim = PERIOD_DELIM,
-                   listTight = isTightList items,
-                   listStart = 1 }) (map (node ITEM) nodes) : ns)
-blockToNodes opts (OrderedList (start, _sty, delim) items) ns = do
-  let exts = writerExtensions opts
-  nodes <- mapM (blocksToNodes opts . taskListItemToAscii exts) items
-  return (node (LIST ListAttributes{
-                   listType = ORDERED_LIST,
-                   listDelim = case delim of
-                                 OneParen  -> PAREN_DELIM
-                                 TwoParens -> PAREN_DELIM
-                                 _         -> PERIOD_DELIM,
-                   listTight = isTightList items,
-                   listStart = start }) (map (node ITEM) nodes) : ns)
-blockToNodes _ HorizontalRule ns = return (node THEMATIC_BREAK [] : ns)
-blockToNodes opts (Header lev _ ils) ns =
-  return (node (HEADING lev) (inlinesToNodes opts ils) : ns)
-blockToNodes opts (Div attr bs) ns = do
-  nodes <- blocksToNodes opts bs
-  let op = tagWithAttributes opts True False "div" attr
-  if isEnabled Ext_raw_html opts
-     then return (node (HTML_BLOCK op) [] : nodes ++
-                  [node (HTML_BLOCK (T.pack "</div>")) []] ++ ns)
-     else return (nodes ++ ns)
-blockToNodes opts (DefinitionList items) ns =
-  blockToNodes opts (BulletList items') ns
-  where items' = map dlToBullet items
-        dlToBullet (term, (Para xs : ys) : zs)  =
-          Para (term ++ [LineBreak] ++ xs) : ys ++ concat zs
-        dlToBullet (term, (Plain xs : ys) : zs) =
-          Plain (term ++ [LineBreak] ++ xs) : ys ++ concat zs
-        dlToBullet (term, xs) =
-          Para term : concat xs
-blockToNodes opts t@(Table _ blkCapt specs thead tbody tfoot) ns =
-  let (capt, aligns, _widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
-  in if isEnabled Ext_pipe_tables opts && onlySimpleTableCells (headers : rows)
-        then do
-          -- We construct a table manually as a CUSTOM_BLOCK, for
-          -- two reasons:  (1) cmark-gfm currently doesn't support
-          -- rendering TABLE nodes; (2) we can align the column sides;
-          -- (3) we can render the caption as a regular paragraph.
-          let capt' = node PARAGRAPH (inlinesToNodes opts capt)
-          -- backslash | in code and raw:
-          let fixPipe (Code attr xs) =
-                Code attr (T.replace "|" "\\|" xs)
-              fixPipe (RawInline format xs) =
-                RawInline format (T.replace "|" "\\|" xs)
-              fixPipe x = x
-          let toCell [Plain ils] = T.strip
-                                   $ nodeToCommonmark [] Nothing
-                                   $ node (CUSTOM_INLINE mempty mempty)
-                                   $ inlinesToNodes opts
-                                   $ walk (fixPipe . softBreakToSpace) ils
-              toCell [Para  ils] = T.strip
-                                   $ nodeToCommonmark [] Nothing
-                                   $ node (CUSTOM_INLINE mempty mempty)
-                                   $ inlinesToNodes opts
-                                   $ walk (fixPipe . softBreakToSpace) ils
-              toCell []          = ""
-              toCell xs          = error $ "toCell encountered " ++ show xs
-          let separator = " | "
-          let starter = "| "
-          let ender   = " |"
-          let rawheaders = map toCell headers
-          let rawrows = map (map toCell) rows
-          let maximum' [] = 0
-              maximum' xs = maximum xs
-          let colwidths = map (maximum' . map T.length) $
-                           transpose (rawheaders:rawrows)
-          let toHeaderLine len AlignDefault = T.replicate len "-"
-              toHeaderLine len AlignLeft    = ":" <>
-                     T.replicate (max (len - 1) 1) "-"
-              toHeaderLine len AlignRight   =
-                     T.replicate (max (len - 1) 1) "-" <> ":"
-              toHeaderLine len AlignCenter  = ":" <>
-                     T.replicate (max (len - 2) 1) (T.pack "-") <> ":"
-          let rawheaderlines = zipWith toHeaderLine colwidths aligns
-          let headerlines = starter <> T.intercalate separator rawheaderlines <>
-                             ender
-          let padContent (align, w) t' =
-                let padding = w - T.length t'
-                    halfpadding = padding `div` 2
-                in  case align of
-                         AlignRight -> T.replicate padding " " <> t'
-                         AlignCenter -> T.replicate halfpadding " " <> t' <>
-                                        T.replicate (padding - halfpadding) " "
-                         _ -> t' <> T.replicate padding " "
-          let toRow xs = starter <> T.intercalate separator
-                         (zipWith padContent (zip aligns colwidths) xs) <>
-                         ender
-          let table' = toRow rawheaders <> "\n" <> headerlines <> "\n" <>
-                        T.intercalate "\n" (map toRow rawrows)
-          return (node (CUSTOM_BLOCK table' mempty) [] :
-                  if null capt
-                     then ns
-                     else capt' : ns)
-        else do -- fall back to raw HTML
-          s <- writeHtml5String def $! Pandoc nullMeta [t]
-          return (node (HTML_BLOCK s) [] : ns)
-blockToNodes _ Null ns = return ns
-
-inlinesToNodes :: WriterOptions -> [Inline] -> [Node]
-inlinesToNodes opts  = foldr (inlineToNodes opts) []
-
-inlineToNodes :: WriterOptions -> Inline -> [Node] -> [Node]
-inlineToNodes opts (Str s) = stringToNodes opts s'
-  where s' = if isEnabled Ext_smart opts
-                then unsmartify opts s
-                else s
-inlineToNodes _ Space   = (node (TEXT (T.pack " ")) [] :)
-inlineToNodes _ LineBreak = (node LINEBREAK [] :)
-inlineToNodes opts SoftBreak
-  | isEnabled Ext_hard_line_breaks opts = (node (TEXT " ") [] :)
-  | writerWrapText opts == WrapNone     = (node (TEXT " ") [] :)
-  | otherwise                           = (node SOFTBREAK [] :)
-inlineToNodes opts (Emph xs) = (node EMPH (inlinesToNodes opts xs) :)
-inlineToNodes opts (Underline xs)
-  | isEnabled Ext_raw_html opts =
-    ((node (HTML_INLINE (T.pack "<u>")) [] : inlinesToNodes opts xs ++
-      [node (HTML_INLINE (T.pack "</u>")) []]) ++ )
-  | otherwise = (node EMPH (inlinesToNodes opts xs) :)
-inlineToNodes opts (Strong xs) = (node STRONG (inlinesToNodes opts xs) :)
-inlineToNodes opts (Strikeout xs)
-  | isEnabled Ext_strikeout opts = (node (CUSTOM_INLINE "~~" "~~") (inlinesToNodes opts xs) :)
-  | isEnabled Ext_raw_html opts = ((node (HTML_INLINE (T.pack "<s>")) [] : inlinesToNodes opts xs ++
-        [node (HTML_INLINE (T.pack "</s>")) []]) ++ )
-  | otherwise = (inlinesToNodes opts xs ++)
-inlineToNodes opts (Superscript xs) =
-  if isEnabled Ext_raw_html opts
-    then ((node (HTML_INLINE (T.pack "<sup>")) [] : inlinesToNodes opts xs ++
-          [node (HTML_INLINE (T.pack "</sup>")) []]) ++ )
-    else case traverse toSuperscriptInline xs of
-      Just xs' | not (writerPreferAscii opts)
-        -> (inlinesToNodes opts xs' ++)
-      _ ->
-        ((node (TEXT (T.pack "^(")) [] : inlinesToNodes opts xs ++
-          [node (TEXT (T.pack ")")) []]) ++ )
-inlineToNodes opts (Subscript xs) =
-  if isEnabled Ext_raw_html opts
-    then ((node (HTML_INLINE (T.pack "<sub>")) [] : inlinesToNodes opts xs ++
-          [node (HTML_INLINE (T.pack "</sub>")) []]) ++ )
-    else case traverse toSubscriptInline xs of
-      Just xs' | not (writerPreferAscii opts)
-              -> (inlinesToNodes opts xs' ++)
-      _ ->
-        ((node (TEXT (T.pack "_(")) [] : inlinesToNodes opts xs ++
-          [node (TEXT (T.pack ")")) []]) ++ )
-inlineToNodes opts (SmallCaps xs) =
-  if isEnabled Ext_raw_html opts
-    then ((node (HTML_INLINE (T.pack "<span class=\"smallcaps\">")) []
-           : inlinesToNodes opts xs ++
-           [node (HTML_INLINE (T.pack "</span>")) []]) ++ )
-    else (inlinesToNodes opts (capitalize xs) ++)
-inlineToNodes opts (Link _ ils (url,tit)) =
-  (node (LINK url tit) (inlinesToNodes opts ils) :)
--- title beginning with fig: indicates implicit figure
-inlineToNodes opts (Image alt ils (url,T.stripPrefix "fig:" -> Just tit)) =
-  inlineToNodes opts (Image alt ils (url,tit))
-inlineToNodes opts (Image _ ils (url,tit)) =
-  (node (IMAGE url tit) (inlinesToNodes opts ils) :)
-inlineToNodes opts (RawInline (Format f) xs)
-  | f == "html" && isEnabled Ext_raw_html opts
-              = (node (HTML_INLINE xs) [] :)
-  | (f == "latex" || f == "tex") && isEnabled Ext_raw_tex opts
-              = (node (CUSTOM_INLINE xs T.empty) [] :)
-  | f == "markdown"
-              = (node (CUSTOM_INLINE xs T.empty) [] :)
-  | otherwise = id
-inlineToNodes opts (Quoted qt ils) =
-  ((node (HTML_INLINE start) [] :
-   inlinesToNodes opts ils ++ [node (HTML_INLINE end) []]) ++)
-  where (start, end) = case qt of
-                          SingleQuote
-                            | isEnabled Ext_smart opts -> ("'","'")
-                            | writerPreferAscii opts ->
-                                     ("&lsquo;", "&rsquo;")
-                            | otherwise -> ("‘", "’")
-                          DoubleQuote
-                            | isEnabled Ext_smart opts -> ("\"", "\"")
-                            | writerPreferAscii opts ->
-                                     ("&ldquo;", "&rdquo;")
-                            | otherwise -> ("“", "”")
-inlineToNodes _ (Code _ str) = (node (CODE str) [] :)
-inlineToNodes opts (Math mt str) =
-  case writerHTMLMathMethod opts of
-       WebTeX url ->
-           let core = inlineToNodes opts
-                        (Image nullAttr [Str str] (url <> T.pack (urlEncode $ T.unpack str), str))
-               sep = if mt == DisplayMath
-                        then (node LINEBREAK [] :)
-                        else id
-           in  (sep . core . sep)
-       _  ->
-           case mt of
-            InlineMath  ->
-              (node (HTML_INLINE ("\\(" <> str <> "\\)")) [] :)
-            DisplayMath ->
-              (node (HTML_INLINE ("\\[" <> str <> "\\]")) [] :)
-inlineToNodes opts (Span ("",["emoji"],kvs) [Str s]) =
-  case lookup "data-emoji" kvs of
-       Just emojiname | isEnabled Ext_emoji opts ->
-            (node (TEXT (":" <> emojiname <> ":")) [] :)
-       _ -> (node (TEXT s) [] :)
-inlineToNodes opts (Span attr ils) =
-  let nodes = inlinesToNodes opts ils
-      op = tagWithAttributes opts True False "span" attr
-  in  if isEnabled Ext_raw_html opts
-         then ((node (HTML_INLINE op) [] : nodes ++
-                [node (HTML_INLINE (T.pack "</span>")) []]) ++)
-         else (nodes ++)
-inlineToNodes opts (Cite _ ils) = (inlinesToNodes opts ils ++)
-inlineToNodes _ (Note _) = id -- should not occur
--- we remove Note elements in preprocessing
-
-stringToNodes :: WriterOptions -> Text -> [Node] -> [Node]
-stringToNodes opts s
-  | not (writerPreferAscii opts) = (node (TEXT s) [] :)
-  | otherwise = step s
-  where
-    step input =
-      let (ascii, rest) = T.span isAscii input
-          this = node (TEXT ascii) []
-          nodes = case T.uncons rest of
-            Nothing -> id
-            Just (nonAscii, rest') ->
-              let escaped = toHtml5Entities (T.singleton nonAscii)
-              in (node (HTML_INLINE escaped) [] :) . step rest'
-      in (this :) . nodes
-
-toSubscriptInline :: Inline -> Maybe Inline
-toSubscriptInline Space = Just Space
-toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
-toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
-toSubscriptInline LineBreak = Just LineBreak
-toSubscriptInline SoftBreak = Just SoftBreak
-toSubscriptInline _ = Nothing
+import Text.Pandoc.Writers.Markdown (writeCommonMark)
 
-toSuperscriptInline :: Inline -> Maybe Inline
-toSuperscriptInline Space = Just Space
-toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
-toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
-toSuperscriptInline LineBreak = Just LineBreak
-toSuperscriptInline SoftBreak = Just SoftBreak
-toSuperscriptInline _ = Nothing
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
@@ -210,8 +210,11 @@
           => WriterOptions  -- ^ Writer options
           -> Pandoc         -- ^ Document to convert
           -> m BL.ByteString
-writeDocx opts doc@(Pandoc meta _) = do
-  let doc' = walk fixDisplayMath doc
+writeDocx opts doc = do
+  let Pandoc meta blocks = walk fixDisplayMath doc
+  let blocks' = makeSections True Nothing blocks
+  let doc' = Pandoc meta blocks'
+
   username <- P.lookupEnv "USERNAME"
   utctime <- P.getCurrentTime
   oldUserDataDir <- P.getUserDataDir
@@ -898,11 +901,21 @@
   header <- dirmod $ stylemod $ blocksToOpenXML opts hs
   contents <- dirmod $ bibmod $ stylemod $ blocksToOpenXML opts bs'
   wrapBookmark ident $ header <> contents
-blockToOpenXML' opts (Header lev (ident,_,_) lst) = do
+blockToOpenXML' opts (Header lev (ident,_,kvs) lst) = do
   setFirstPara
   paraProps <- withParaPropM (pStyleM (fromString $ "Heading "++show lev)) $
                     getParaProps False
-  contents <- inlinesToOpenXML opts lst
+  number <-
+        if writerNumberSections opts
+           then
+             case lookup "number" kvs of
+                Just n -> do
+                   num <- withTextPropM (rStyleM "SectionNumber")
+                            (inlineToOpenXML opts (Str n))
+                   return $ num ++ [mknode "w:r" [] [mknode "w:tab" [] ()]]
+                Nothing -> return []
+           else return []
+  contents <- (number ++) <$> inlinesToOpenXML opts lst
   if T.null ident
      then return [mknode "w:p" [] (paraProps ++ contents)]
      else do
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
@@ -1,6 +1,7 @@
 {-# LANGUAGE MultiWayIf          #-}
 {-# LANGUAGE OverloadedStrings   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
 {-# LANGUAGE ViewPatterns        #-}
 {- |
    Module      : Text.Pandoc.Writers.HTML
@@ -587,11 +588,18 @@
        => WriterOptions -> Attr -> [Inline] -> (Text, Text)
        -> StateT WriterState m Html
 figure opts attr txt (s,tit) = do
-  img <- inlineToHtml opts (Image attr [Str ""] (s,tit))
   html5 <- gets stHtml5
+  -- Screen-readers will normally read the @alt@ text and the figure; we
+  -- want to avoid them reading the same text twice. With HTML5 we can
+  -- use aria-hidden for the caption; with HTML4, we use an empty
+  -- alt-text instead.
+  let alt = if html5 then txt else [Str ""]
   let tocapt = if html5
-                  then H5.figcaption
+                  then H5.figcaption !
+                       H5.customAttribute (textTag "aria-hidden")
+                                          (toValue @Text "true")
                   else H.p ! A.class_ "caption"
+  img <- inlineToHtml opts (Image attr alt (s,tit))
   capt <- if null txt
              then return mempty
              else tocapt `fmap` inlineListToHtml opts txt
diff --git a/src/Text/Pandoc/Writers/Jira.hs b/src/Text/Pandoc/Writers/Jira.hs
--- a/src/Text/Pandoc/Writers/Jira.hs
+++ b/src/Text/Pandoc/Writers/Jira.hs
@@ -194,7 +194,7 @@
                               Jira.Monospaced (escapeSpecialChars cs)
         Emph xs            -> styled Jira.Emphasis xs
         Underline xs       -> styled Jira.Insert xs
-        Image attr _ tgt   -> imageToJira attr (fst tgt) (snd tgt)
+        Image attr cap tgt -> imageToJira attr cap (fst tgt) (snd tgt)
         LineBreak          -> pure . singleton $ Jira.Linebreak
         Link attr xs tgt   -> toJiraLink attr tgt xs
         Math mtype cs      -> mathToJira mtype cs
@@ -233,16 +233,18 @@
   Left _  -> singleton $ Jira.Str t
 
 imageToJira :: PandocMonad m
-            => Attr -> Text -> Text
+            => Attr -> [Inline] -> Text -> Text
             -> JiraConverter m [Jira.Inline]
-imageToJira (_, classes, kvs) src title =
-  let imgParams = if "thumbnail" `elem` classes
-                  then [Jira.Parameter "thumbnail" ""]
-                  else map (uncurry Jira.Parameter) kvs
-      imgParams' = if T.null title
-                   then imgParams
-                   else Jira.Parameter "title" title : imgParams
-  in pure . singleton $ Jira.Image imgParams' (Jira.URL src)
+imageToJira (_, classes, kvs) caption src title =
+  let imageWithParams ps = Jira.Image ps (Jira.URL src)
+      alt = stringify caption
+  in pure . singleton . imageWithParams $
+     if "thumbnail" `elem` classes
+     then [Jira.Parameter "thumbnail" ""]
+     else map (uncurry Jira.Parameter)
+          . (if T.null title then id else (("title", title):))
+          . (if T.null alt then id else (("alt", alt):))
+          $ kvs
 
 -- | Creates a Jira Link element.
 toJiraLink :: PandocMonad m
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -16,7 +16,10 @@
 
 Markdown:  <http://daringfireball.net/projects/markdown/>
 -}
-module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where
+module Text.Pandoc.Writers.Markdown (
+  writeMarkdown,
+  writeCommonMark,
+  writePlain) where
 import Control.Monad.Reader
 import Control.Monad.State.Strict
 import Data.Char (isAlphaNum)
@@ -44,6 +47,7 @@
 import Text.Pandoc.Writers.HTML (writeHtml5String)
 import Text.Pandoc.Writers.Math (texMathToInlines)
 import Text.Pandoc.XML (toHtml5Entities)
+import Data.Coerce (coerce)
 
 type Notes = [[Block]]
 type Ref   = (Text, Target, Attr)
@@ -55,15 +59,21 @@
 evalMD md env st = evalStateT (runReaderT md env) st
 
 data WriterEnv = WriterEnv { envInList          :: Bool
-                           , envPlain           :: Bool
+                           , envVariant         :: MarkdownVariant
                            , envRefShortcutable :: Bool
                            , envBlockLevel      :: Int
                            , envEscapeSpaces    :: Bool
                            }
 
+data MarkdownVariant =
+      PlainText
+    | Commonmark
+    | Markdown
+    deriving (Show, Eq)
+
 instance Default WriterEnv
-  where def = WriterEnv { envInList         = False
-                        , envPlain          = False
+  where def = WriterEnv { envInList          = False
+                        , envVariant         = Markdown
                         , envRefShortcutable = True
                         , envBlockLevel      = 0
                         , envEscapeSpaces    = False
@@ -102,8 +112,13 @@
 -- pictures, or inline formatting).
 writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m Text
 writePlain opts document =
-  evalMD (pandocToMarkdown opts document) def{ envPlain = True } def
+  evalMD (pandocToMarkdown opts document) def{ envVariant = PlainText } def
 
+-- | Convert Pandoc to Commonmark.
+writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
+writeCommonMark opts document =
+  evalMD (pandocToMarkdown opts document) def{ envVariant = Commonmark } def
+
 pandocTitleBlock :: Doc Text -> [Doc Text] -> Doc Text -> Doc Text
 pandocTitleBlock tit auths dat =
   hang 2 (text "% ") tit <> cr <>
@@ -187,7 +202,7 @@
   let colwidth = if writerWrapText opts == WrapAuto
                     then Just $ writerColumns opts
                     else Nothing
-  isPlain <- asks envPlain
+  variant <- asks envVariant
   metadata <- metaToContext'
                (blockListToMarkdown opts)
                (inlineListToMarkdown opts)
@@ -196,7 +211,7 @@
   let authors' = fromMaybe [] $ getField "author" metadata
   let date' = fromMaybe empty $ getField "date" metadata
   let titleblock = case writerTemplate opts of
-                        Just _ | isPlain ->
+                        Just _ | variant == PlainText ->
                                  plainTitleBlock title' authors' date'
                                | isEnabled Ext_yaml_metadata_block opts ->
                                    yamlMetadataBlock metadata
@@ -276,10 +291,7 @@
 
 -- | Escape special characters for Markdown.
 escapeText :: WriterOptions -> Text -> Text
-escapeText opts =
-  (if writerPreferAscii opts
-      then toHtml5Entities
-      else id) . T.pack . go . T.unpack
+escapeText opts = T.pack . go . T.unpack
   where
   go [] = []
   go (c:cs) =
@@ -422,7 +434,7 @@
              attrs' = (id',classes',("markdown","1"):kvs')
 blockToMarkdown' opts (Plain inlines) = do
   -- escape if para starts with ordered list marker
-  isPlain <- asks envPlain
+  variant <- asks envVariant
   let escapeMarker = T.concatMap $ \x -> if x `elemText` ".()"
                                          then T.pack ['\\', x]
                                          else T.singleton x
@@ -430,17 +442,15 @@
       startsWithSpace (SoftBreak:_) = True
       startsWithSpace _             = False
   let inlines' =
-        if isPlain
+        if variant == PlainText
            then inlines
            else case inlines of
                   (Str t:ys)
-                    | not isPlain
-                    , (null ys || startsWithSpace ys)
+                    | (null ys || startsWithSpace ys)
                     , beginsWithOrderedListMarker t
                     -> RawInline (Format "markdown") (escapeMarker t):ys
                   (Str t:_)
-                    | not isPlain
-                    , t == "+" || t == "-" ||
+                    | t == "+" || t == "-" ||
                       (t == "%" && isEnabled Ext_pandoc_title_block opts &&
                                    isEnabled Ext_all_symbols_escapable opts)
                     -> RawInline (Format "markdown") "\\" : inlines
@@ -465,19 +475,19 @@
     return $ (vcat $ map (hang 2 (literal "| ")) mdLines) <> blankline
   else blockToMarkdown opts $ linesToPara lns
 blockToMarkdown' opts b@(RawBlock f str) = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   let Format fmt = f
   let rawAttribBlock = return $
          (literal "```{=" <> literal fmt <> "}") $$
          literal str $$
          (literal "```" <> literal "\n")
   let renderEmpty = mempty <$ report (BlockNotRendered b)
-  case () of
-    _ | plain -> renderEmpty
-      | isEnabled Ext_raw_attribute opts -> rawAttribBlock
-      | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
+  case variant of
+    PlainText -> renderEmpty
+    _ | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
                   "markdown_mmd", "markdown_strict"] ->
             return $ literal str <> literal "\n"
+      | isEnabled Ext_raw_attribute opts -> rawAttribBlock
       | f `elem` ["html", "html5", "html4"] ->
             case () of
               _ | isEnabled Ext_markdown_attribute opts -> return $
@@ -503,7 +513,7 @@
           then notesAndRefs opts
           else return empty
 
-  plain <- asks envPlain
+  variant <- asks envVariant
   -- we calculate the id that would be used by auto_identifiers
   -- so we know whether to print an explicit identifier
   ids <- gets stIds
@@ -521,19 +531,20 @@
   contents <- inlineListToMarkdown opts $
                  -- ensure no newlines; see #3736
                  walk lineBreakToSpace $
-                 if level == 1 && plain && isEnabled Ext_gutenberg opts
-                    then capitalize inlines
-                    else inlines
+                   if level == 1 && variant == PlainText &&
+                      isEnabled Ext_gutenberg opts
+                      then capitalize inlines
+                      else inlines
   let setext = writerSetextHeaders opts
       hdr = nowrap $ case level of
-            1 | plain ->
+            1 | variant == PlainText ->
                 if isEnabled Ext_gutenberg opts
                    then blanklines 3 <> contents <> blanklines 2
                    else contents <> blankline
               | setext ->
                   contents <> attr' <> cr <> literal (T.replicate (offset contents) "=") <>
                   blankline
-            2 | plain ->
+            2 | variant == PlainText ->
                 if isEnabled Ext_gutenberg opts
                    then blanklines 2 <> contents <> blankline
                    else contents <> blankline
@@ -541,7 +552,7 @@
                   contents <> attr' <> cr <> literal (T.replicate (offset contents) "-") <>
                   blankline
             -- ghc interprets '#' characters in column 1 as linenum specifiers.
-            _ | plain || isEnabled Ext_literate_haskell opts ->
+            _ | variant == PlainText || isEnabled Ext_literate_haskell opts ->
                 contents <> blankline
             _ -> literal (T.replicate level "#") <> space <> contents <> attr' <> blankline
 
@@ -571,12 +582,12 @@
                                 (_,(cls:_),_) -> " " <> literal cls
                                 _             -> empty
 blockToMarkdown' opts (BlockQuote blocks) = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   -- if we're writing literate haskell, put a space before the bird tracks
   -- so they won't be interpreted as lhs...
   let leader = if isEnabled Ext_literate_haskell opts
                   then " > "
-                  else if plain then "  " else "> "
+                  else if variant == PlainText then "  " else "> "
   contents <- blockListToMarkdown opts blocks
   return $ (prefixed leader contents) <> blankline
 blockToMarkdown' opts t@(Table _ blkCapt specs thead tbody tfoot) = do
@@ -584,9 +595,12 @@
   let numcols = maximum (length aligns : length widths :
                            map length (headers:rows))
   caption' <- inlineListToMarkdown opts caption
-  let caption'' = if null caption || not (isEnabled Ext_table_captions opts)
+  let caption'' = if null caption
                      then blankline
-                     else blankline $$ (": " <> caption') $$ blankline
+                     else
+                       if isEnabled Ext_table_captions opts
+                          then blankline $$ (": " <> caption') $$ blankline
+                          else blankline $$ caption' $$ blankline
   let hasSimpleCells = onlySimpleTableCells $ headers : rows
   let isSimple = hasSimpleCells && all (==0) widths
   let isPlainBlock (Plain _) = True
@@ -806,8 +820,8 @@
   if isEnabled Ext_definition_lists opts
      then do
        let tabStop = writerTabStop opts
-       isPlain <- asks envPlain
-       let leader  = if isPlain then "   " else ":  "
+       variant <- asks envVariant
+       let leader  = if variant == PlainText then "   " else ":  "
        let sps = case writerTabStop opts - 3 of
                       n | n > 0   -> literal $ T.replicate n " "
                       _ -> literal " "
@@ -836,7 +850,7 @@
                     -> MD m (Doc Text)
 blockListToMarkdown opts blocks = do
   inlist <- asks envInList
-  isPlain <- asks envPlain
+  variant <- asks envVariant
   -- a) insert comment between list and indented code block, or the
   -- code block will be treated as a list continuation paragraph
   -- b) change Plain to Para unless it's followed by a RawBlock
@@ -870,7 +884,7 @@
       isListBlock (OrderedList _ _)  = True
       isListBlock (DefinitionList _) = True
       isListBlock _                  = False
-      commentSep  = if isPlain
+      commentSep  = if variant == PlainText
                        then Null
                        else if isEnabled Ext_raw_html opts
                             then RawBlock "html" "<!-- -->\n"
@@ -890,6 +904,7 @@
   prevRefs <- gets stPrevRefs
   refs <- gets stRefs
   i <- (+ 1) <$> gets stLastIdx
+  modify $ \s -> s{ stLastIdx = i }
   let refLbls = map (\(r,_,_) -> r) $ prevRefs ++ refs
   return $ findUsableIndex refLbls i
 
@@ -902,12 +917,15 @@
     Just (ref, _, _) -> return ref
     Nothing       -> do
       keys <- gets stKeys
-      case M.lookup (getKey label) keys of
+      let key = getKey label
+      let rawkey = coerce key
+      case M.lookup key keys of
            Nothing -> do -- no other refs with this label
-             (lab', idx) <- if isEmpty label
+             (lab', idx) <- if T.null rawkey ||
+                                 T.length rawkey > 999 ||
+                                 T.any (\c -> c == '[' || c == ']') rawkey
                                then do
                                  i <- getNextIndex
-                                 modify $ \s -> s{ stLastIdx = i }
                                  return (tshow i, i)
                                else
                                  return (render Nothing label, 0)
@@ -934,11 +952,10 @@
                     return lab'
                   Nothing -> do -- but this one is to a new target
                     i <- getNextIndex
-                    modify $ \s -> s{ stLastIdx = i }
                     let lab' = tshow i
                     modify (\s -> s{
                        stRefs = (lab', target, attr) : refs,
-                       stKeys = M.insert (getKey label)
+                       stKeys = M.insert key
                                    (M.insert (target, attr) i km)
                                          (stKeys s) })
                     return lab'
@@ -1022,11 +1039,11 @@
             return $ ":" <> literal emojiname <> ":"
        _ -> inlineToMarkdown opts (Str s)
 inlineToMarkdown opts (Span attrs ils) = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   contents <- inlineListToMarkdown opts ils
-  return $ case plain of
-                True -> contents
-                False | attrs == nullAttr -> contents
+  return $ case variant of
+                PlainText -> contents
+                _     | attrs == nullAttr -> contents
                       | isEnabled Ext_bracketed_spans opts ->
                         let attrs' = if attrs /= nullAttr
                                         then attrsToMarkdown attrs
@@ -1038,20 +1055,20 @@
                       | otherwise -> contents
 inlineToMarkdown _ (Emph []) = return empty
 inlineToMarkdown opts (Emph lst) = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   contents <- inlineListToMarkdown opts lst
-  return $ if plain
-              then if isEnabled Ext_gutenberg opts
-                      then "_" <> contents <> "_"
-                      else contents
-              else "*" <> contents <> "*"
+  return $ case variant of
+             PlainText
+               | isEnabled Ext_gutenberg opts -> "_" <> contents <> "_"
+               | otherwise ->  contents
+             _ -> "*" <> contents <> "*"
 inlineToMarkdown _ (Underline []) = return empty
 inlineToMarkdown opts (Underline lst) = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   contents <- inlineListToMarkdown opts lst
-  case plain of
-    True -> return contents
-    False | isEnabled Ext_bracketed_spans opts ->
+  case variant of
+    PlainText -> return contents
+    _     | isEnabled Ext_bracketed_spans opts ->
             return $ "[" <> contents <> "]" <> "{.ul}"
           | isEnabled Ext_native_spans opts ->
             return $ tagWithAttrs "span" ("", ["underline"], [])
@@ -1062,13 +1079,14 @@
           | otherwise -> inlineToMarkdown opts (Emph lst)
 inlineToMarkdown _ (Strong []) = return empty
 inlineToMarkdown opts (Strong lst) = do
-  plain <- asks envPlain
-  if plain
-     then inlineListToMarkdown opts $
-          if isEnabled Ext_gutenberg opts
-             then capitalize lst
-             else lst
-     else do
+  variant <- asks envVariant
+  case variant of
+    PlainText ->
+             inlineListToMarkdown opts $
+               if isEnabled Ext_gutenberg opts
+                  then capitalize lst
+                  else lst
+    _ -> do
        contents <- inlineListToMarkdown opts lst
        return $ "**" <> contents <> "**"
 inlineToMarkdown _ (Strikeout []) = return empty
@@ -1081,33 +1099,43 @@
                        else contents
 inlineToMarkdown _ (Superscript []) = return empty
 inlineToMarkdown opts (Superscript lst) =
-  local (\env -> env {envEscapeSpaces = True}) $ do
+  local (\env -> env {envEscapeSpaces = (envVariant env == Markdown)}) $ do
     contents <- inlineListToMarkdown opts lst
-    return $ if isEnabled Ext_superscript opts
-                then "^" <> contents <> "^"
-                else if isEnabled Ext_raw_html opts
-                         then "<sup>" <> contents <> "</sup>"
-                         else
-                           let rendered = render Nothing contents
-                           in  case mapM toSuperscript (T.unpack rendered) of
-                                    Just r  -> literal $ T.pack r
-                                    Nothing -> literal $ "^(" <> rendered <> ")"
+    if isEnabled Ext_superscript opts
+       then return $ "^" <> contents <> "^"
+       else if isEnabled Ext_raw_html opts
+                then return $ "<sup>" <> contents <> "</sup>"
+                else
+                  case traverse toSuperscriptInline lst of
+                    Just xs' | not (writerPreferAscii opts)
+                      -> inlineListToMarkdown opts xs'
+                    _ -> do
+                      let rendered = render Nothing contents
+                      return $
+                        case mapM toSuperscript (T.unpack rendered) of
+                           Just r  -> literal $ T.pack r
+                           Nothing -> literal $ "^(" <> rendered <> ")"
 inlineToMarkdown _ (Subscript []) = return empty
 inlineToMarkdown opts (Subscript lst) =
-  local (\env -> env {envEscapeSpaces = True}) $ do
+  local (\env -> env {envEscapeSpaces = (envVariant env == Markdown)}) $ do
     contents <- inlineListToMarkdown opts lst
-    return $ if isEnabled Ext_subscript opts
-                then "~" <> contents <> "~"
-                else if isEnabled Ext_raw_html opts
-                         then "<sub>" <> contents <> "</sub>"
-                         else
-                           let rendered = render Nothing contents
-                           in  case mapM toSubscript (T.unpack rendered) of
-                                    Just r  -> literal $ T.pack r
-                                    Nothing -> literal $ "_(" <> rendered <> ")"
+    if isEnabled Ext_subscript opts
+       then return $ "~" <> contents <> "~"
+       else if isEnabled Ext_raw_html opts
+                then return $ "<sub>" <> contents <> "</sub>"
+                else
+                  case traverse toSubscriptInline lst of
+                    Just xs' | not (writerPreferAscii opts)
+                      -> inlineListToMarkdown opts xs'
+                    _ -> do
+                      let rendered = render Nothing contents
+                      return $
+                        case mapM toSuperscript (T.unpack rendered) of
+                           Just r  -> literal $ T.pack r
+                           Nothing -> literal $ "_(" <> rendered <> ")"
 inlineToMarkdown opts (SmallCaps lst) = do
-  plain <- asks envPlain
-  if not plain &&
+  variant <- asks envVariant
+  if variant /= PlainText &&
      (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
      then inlineToMarkdown opts (Span ("",["smallcaps"],[]) lst)
      else inlineListToMarkdown opts $ capitalize lst
@@ -1137,18 +1165,22 @@
   let attrs      = if isEnabled Ext_inline_code_attributes opts && attr /= nullAttr
                       then attrsToMarkdown attr
                       else empty
-  plain <- asks envPlain
-  if plain
-     then return $ literal str
-     else return $ literal (marker <> spacer <> str <> spacer <> marker) <> attrs
+  variant <- asks envVariant
+  case variant of
+     PlainText -> return $ literal str
+     _     ->  return $ literal
+                  (marker <> spacer <> str <> spacer <> marker) <> attrs
 inlineToMarkdown opts (Str str) = do
-  isPlain <- asks envPlain
-  let str' = (if isEnabled Ext_smart opts
+  variant <- asks envVariant
+  let str' = (if writerPreferAscii opts
+                 then toHtml5Entities
+                 else id) .
+             (if isEnabled Ext_smart opts
                  then unsmartify opts
-                 else id) $
-              if isPlain
-                 then str
-                 else escapeText opts str
+                 else id) .
+             (if variant == PlainText
+                 then id
+                 else escapeText opts) $ str
   return $ literal str'
 inlineToMarkdown opts (Math InlineMath str) =
   case writerHTMLMathMethod opts of
@@ -1161,10 +1193,10 @@
          | isEnabled Ext_tex_math_double_backslash opts ->
              return $ "\\\\(" <> literal str <> "\\\\)"
          | otherwise -> do
-             plain <- asks envPlain
+             variant <- asks envVariant
              texMathToInlines InlineMath str >>=
                inlineListToMarkdown opts .
-                 (if plain then makeMathPlainer else id)
+                 (if variant == PlainText then makeMathPlainer else id)
 inlineToMarkdown opts (Math DisplayMath str) =
   case writerHTMLMathMethod opts of
       WebTeX url -> (\x -> blankline <> x <> blankline) `fmap`
@@ -1183,15 +1215,15 @@
   let numticks   = if null tickGroups
                      then 1
                      else 1 + maximum (map T.length tickGroups)
-  plain <- asks envPlain
+  variant <- asks envVariant
   let Format fmt = f
   let rawAttribInline = return $
          literal (T.replicate numticks "`") <> literal str <>
          literal (T.replicate numticks "`") <> literal "{=" <> literal fmt <> literal "}"
   let renderEmpty = mempty <$ report (InlineNotRendered il)
-  case () of
-    _ | plain -> renderEmpty
-      | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
+  case variant of
+    PlainText -> renderEmpty
+    _ | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
                   "markdown_mmd", "markdown_strict"] ->
             return $ literal str
       | isEnabled Ext_raw_attribute opts -> rawAttribInline
@@ -1207,8 +1239,8 @@
                 | otherwise -> renderEmpty
       | otherwise -> renderEmpty
 inlineToMarkdown opts LineBreak = do
-  plain <- asks envPlain
-  if plain || isEnabled Ext_hard_line_breaks opts
+  variant <- asks envVariant
+  if variant == PlainText || isEnabled Ext_hard_line_breaks opts
      then return cr
      else return $
           if isEnabled Ext_escaped_line_breaks opts
@@ -1261,7 +1293,7 @@
     (literal . T.strip) <$>
       writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [lnk]])
   | otherwise = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   linktext <- inlineListToMarkdown opts txt
   let linktitle = if T.null tit
                      then empty
@@ -1279,9 +1311,9 @@
                 then literal <$> getReference attr linktext (src, tit)
                 else return mempty
   return $ if useAuto
-              then if plain
-                      then literal srcSuffix
-                      else "<" <> literal srcSuffix <> ">"
+              then case variant of
+                     PlainText -> literal srcSuffix
+                     _ -> "<" <> literal srcSuffix <> ">"
               else if useRefLinks
                       then let first  = "[" <> linktext <> "]"
                                second = if getKey linktext == getKey reftext
@@ -1290,9 +1322,9 @@
                                                    else "[]"
                                            else "[" <> reftext <> "]"
                            in  first <> second
-                      else if plain
-                              then linktext
-                              else "[" <> linktext <> "](" <>
+                      else case variant of
+                             PlainText -> linktext
+                             _ -> "[" <> linktext <> "](" <>
                                    literal src <> linktitle <> ")" <>
                                    linkAttributes opts attr
 inlineToMarkdown opts img@(Image attr alternate (source, tit))
@@ -1302,15 +1334,15 @@
     (literal . T.strip) <$>
       writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]])
   | otherwise = do
-  plain <- asks envPlain
+  variant <- asks envVariant
   let txt = if null alternate || alternate == [Str source]
                                  -- to prevent autolinks
                then [Str ""]
                else alternate
   linkPart <- inlineToMarkdown opts (Link attr txt (source, tit))
-  return $ if plain
-              then "[" <> linkPart <> "]"
-              else "!" <> linkPart
+  return $ case variant of
+             PlainText -> "[" <> linkPart <> "]"
+             _     -> "!" <> linkPart
 inlineToMarkdown opts (Note contents) = do
   modify (\st -> st{ stNotes = contents : stNotes st })
   st <- get
@@ -1329,3 +1361,19 @@
 lineBreakToSpace LineBreak = Space
 lineBreakToSpace SoftBreak = Space
 lineBreakToSpace x         = x
+
+toSubscriptInline :: Inline -> Maybe Inline
+toSubscriptInline Space = Just Space
+toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils
+toSubscriptInline (Str s) = Str . T.pack <$> traverse toSubscript (T.unpack s)
+toSubscriptInline LineBreak = Just LineBreak
+toSubscriptInline SoftBreak = Just SoftBreak
+toSubscriptInline _ = Nothing
+
+toSuperscriptInline :: Inline -> Maybe Inline
+toSuperscriptInline Space = Just Space
+toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils
+toSuperscriptInline (Str s) = Str . T.pack <$> traverse toSuperscript (T.unpack s)
+toSuperscriptInline LineBreak = Just LineBreak
+toSuperscriptInline SoftBreak = Just SoftBreak
+toSuperscriptInline _ = Nothing
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
@@ -204,7 +204,9 @@
     literal ".IP" $$
     literal ".nf" $$
     literal "\\f[C]" $$
-    hlCode $$
+    ((case T.uncons str of
+      Just ('.',_) -> literal "\\&"
+      _            -> mempty) <> hlCode) $$
     literal "\\f[]" $$
     literal ".fi"
 blockToMs opts (LineBlock ls) = do
@@ -517,11 +519,11 @@
 
 msFormatter :: WriterOptions -> FormatOptions -> [SourceLine] -> Doc Text
 msFormatter opts _fmtopts =
-  vcat . map fmtLine
-  where fmtLine = hcat . map fmtToken
-        fmtToken (toktype, tok) = literal "\\*" <>
-           brackets (literal (tshow toktype) <> literal " \""
-             <> literal (escapeStr opts tok) <> literal "\"")
+  literal . T.intercalate "\n" . map fmtLine
+ where
+  fmtLine = mconcat . map fmtToken
+  fmtToken (toktype, tok) =
+    "\\*[" <> (tshow toktype) <> " \"" <> (escapeStr opts tok) <> "\"]"
 
 highlightCode :: PandocMonad m => WriterOptions -> Attr -> Text -> MS m (Doc Text)
 highlightCode opts attr str =
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -27,6 +27,10 @@
 - HsYAML-0.2.1.0
 - HsYAML-aeson-0.2.0.0
 - doctemplates-0.8.2
+- commonmark-0.1.0.1
+- commonmark-extensions-0.2.0.0
+- commonmark-pandoc-0.2.0.0
+
 ghc-options:
    "$locals": -fhide-source-paths -Wno-missing-home-modules
 resolver: lts-14.6
diff --git a/test/Tests/Readers/LaTeX.hs b/test/Tests/Readers/LaTeX.hs
--- a/test/Tests/Readers/LaTeX.hs
+++ b/test/Tests/Readers/LaTeX.hs
@@ -35,13 +35,17 @@
      => String -> (Text, c) -> TestTree
 (=:) = test latex
 
-simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
-simpleTable' aligns rows
+table' :: [Alignment] -> [Row] -> Blocks
+table' aligns rows
   = table emptyCaption
           (zip aligns (repeat ColWidthDefault))
           (TableHead nullAttr [])
-          [TableBody nullAttr 0 [] $ map toRow rows]
+          [TableBody nullAttr 0 [] rows]
           (TableFoot nullAttr [])
+
+simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
+simpleTable' aligns rows
+  = table' aligns (map toRow rows)
   where
     toRow = Row nullAttr . map simpleCell
 
@@ -137,6 +141,54 @@
           , "Table with vertical alignment argument" =:
             "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?>
             simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]]
+          , "Table with multicolumn item" =:
+            "\\begin{tabular}{l c r}\\multicolumn{2}{c}{One} & Two\\\\ \\end{tabular}" =?>
+            table' [AlignLeft, AlignCenter, AlignRight]
+                   [ Row nullAttr [ cell AlignCenter (RowSpan 1) (ColSpan 2) (plain "One")
+                                  , simpleCell (plain "Two")
+                                  ]
+                   ]
+          , "Table with multirow item" =:
+            T.unlines ["\\begin{tabular}{c}"
+                      ,"\\multirow{2}{c}{One}\\\\Two\\\\"
+                      ,"\\end{tabular}"
+                      ] =?>
+            table' [AlignCenter]
+                  [ Row nullAttr [ cell AlignCenter (RowSpan 2) (ColSpan 1) (plain "One") ]
+                  , Row nullAttr [ simpleCell (plain "Two") ]
+                  ]
+          , "Table with nested multirow/multicolumn item" =:
+            T.unlines [ "\\begin{tabular}{c c c}"
+                      , "\\multirow{2}{c}{\\multicolumn{2}{c}{One}}&Two\\\\"
+                      , "Three\\\\"
+                      , "Four&Five&Six\\\\"
+                      , "\\end{tabular}"
+                      ] =?>
+            table' [AlignCenter, AlignCenter, AlignCenter]
+                   [ Row nullAttr [ cell AlignCenter (RowSpan 2) (ColSpan 2) (plain "One")
+                                  , simpleCell (plain "Two")
+                                  ]
+                   , Row nullAttr [ simpleCell (plain "Three") ]
+                   , Row nullAttr [ simpleCell (plain "Four") 
+                                  , simpleCell (plain "Five")
+                                  , simpleCell (plain "Six")
+                                  ]
+                   ]
+          , "Table with multicolumn header" =:
+            T.unlines [ "\\begin{tabular}{ |l|l| }"
+                      , "\\hline\\multicolumn{2}{|c|}{Header}\\\\" 
+                      , "\\hline key & val\\\\" 
+                      , "\\hline\\end{tabular}"
+                      ] =?>
+            table emptyCaption
+                  (zip [AlignLeft, AlignLeft] (repeat ColWidthDefault))
+                  (TableHead nullAttr [ Row nullAttr [cell AlignCenter (RowSpan 1) (ColSpan 2) (plain "Header")]])
+                  [TableBody nullAttr 0 [] [Row nullAttr [ simpleCell (plain "key")
+                                                         , simpleCell (plain "val")
+                                                         ]
+                                           ]
+                  ]
+                  (TableFoot nullAttr [])
           ]
 
         , testGroup "citations"
diff --git a/test/Tests/Readers/Org/Directive.hs b/test/Tests/Readers/Org/Directive.hs
--- a/test/Tests/Readers/Org/Directive.hs
+++ b/test/Tests/Readers/Org/Directive.hs
@@ -150,6 +150,28 @@
                   ] =?>
         Pandoc nullMeta mempty
 
+    , "disable MathML-like entities" =:
+        T.unlines [ "#+OPTIONS: e:nil"
+                  , "Icelandic letter: \\thorn"
+                  ] =?>
+        para "Icelandic letter: \\thorn"
+
+    , testGroup "Option f"
+      [ "disable inline footnotes" =:
+        T.unlines [ "#+OPTIONS: f:nil"
+                  , "Funny![fn:funny:or not]"
+                  ] =?>
+        para "Funny!"
+
+      , "disable reference footnotes" =:
+        T.unlines [ "#+OPTIONS: f:nil"
+                  , "Burn everything[fn:1] down!"
+                  , ""
+                  , "[fn:2] Not quite everything."
+                  ] =?>
+        para "Burn everything down!"
+      ]
+
     , "disable inclusion of todo keywords" =:
         T.unlines [ "#+OPTIONS: todo:nil"
                   , "** DONE todo export"
@@ -256,6 +278,14 @@
                   , "* Wichtig"
                   ] =?>
         headerWith ("wichtig", mempty, mempty) 1 "Wichtig"
+      ]
+
+    , testGroup "Option |"
+      [ "disable export of tables" =:
+        T.unlines [ "#+OPTIONS: |:nil"
+                  , "| chair |"
+                  ] =?>
+        (mempty :: Blocks)
       ]
 
     , testGroup "unknown options"
diff --git a/test/Tests/Writers/Ms.hs b/test/Tests/Writers/Ms.hs
new file mode 100644
--- /dev/null
+++ b/test/Tests/Writers/Ms.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.Ms (tests) where
+
+import Prelude
+import Test.Tasty
+import Tests.Helpers
+import Text.Pandoc
+import Text.Pandoc.Builder
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+     => String -> (a, String) -> TestTree
+(=:) = test (purely (writeMs def . toPandoc))
+
+tests :: [TestTree]
+tests = [ testGroup "code blocks"
+          [ "basic"
+              =: codeBlock "hello"
+              =?> unlines
+              [ ".IP"
+              , ".nf"
+              , "\\f[C]"
+              , "hello"
+              , "\\f[]"
+              , ".fi"]
+          , "escape starting ."
+              =: codeBlock ". hello"
+              =?> unlines
+              [ ".IP"
+              , ".nf"
+              , "\\f[C]"
+              , "\\&. hello"
+              , "\\f[]"
+              , ".fi"]
+          ]
+        ]
diff --git a/test/command/01.csv b/test/command/01.csv
new file mode 100644
--- /dev/null
+++ b/test/command/01.csv
@@ -0,0 +1,4 @@
+"Column1";"Column2"
+"Data1";"- data1
+
+- data2"
diff --git a/test/command/1608.md b/test/command/1608.md
new file mode 100644
--- /dev/null
+++ b/test/command/1608.md
@@ -0,0 +1,41 @@
+```
+% pandoc -f latex -t native
+\newtheorem{theorem}{Theorem}
+\newtheorem{corollary}[theorem]{Corollary}
+\newtheorem{lemma}[theorem]{Lemma}
+\theoremstyle{definition}
+\newtheorem{definition}[theorem]{Definition}
+\theoremstyle{remark}
+\newtheorem{remark}{Remark}
+
+\begin{definition}[right-angled triangles] \label{def:tri}
+A \emph{right-angled triangle} is a triangle whose sides of length~\(a\), \(b\) and~\(c\), in some permutation of order, satisfies \(a^2+b^2=c^2\).
+\end{definition}
+
+\begin{lemma}
+The triangle with sides of length~\(3\), \(4\) and~\(5\) is right-angled.
+\end{lemma}
+
+\begin{proof}
+This lemma follows from \cref{def:tri} since \(3^2+4^2=9+16=25=5^2\).
+\end{proof}
+
+\begin{theorem}[Pythagorean triplets] \label{thm:py}
+Triangles with sides of length \(a=p^2-q^2\), \(b=2pq\) and \(c=p^2+q^2\) are right-angled triangles.
+\end{theorem}
+
+\begin{remark}
+These are all pretty interesting facts.
+\end{remark}
+^D
+[Div ("def:tri",["definition"],[])
+ [Para [Strong [Str "Definition",Space,Str "1"],Space,Str "(right-angled",Space,Str "triangles).",Space,Space,Str "A",Space,Emph [Str "right-angled",Space,Str "triangle"],Space,Str "is",Space,Str "a",Space,Str "triangle",Space,Str "whose",Space,Str "sides",Space,Str "of",Space,Str "length\160",Math InlineMath "a",Str ",",Space,Math InlineMath "b",Space,Str "and\160",Math InlineMath "c",Str ",",Space,Str "in",Space,Str "some",Space,Str "permutation",Space,Str "of",Space,Str "order,",Space,Str "satisfies",Space,Math InlineMath "a^2+b^2=c^2",Str "."]]
+,Div ("",["lemma"],[])
+ [Para [Strong [Str "Lemma",Space,Str "2"],Str ".",Space,Space,Emph [Str "The",Space,Str "triangle",Space,Str "with",Space,Str "sides",Space,Str "of",Space,Str "length\160",Math InlineMath "3",Str ",",Space,Math InlineMath "4",Space,Str "and\160",Math InlineMath "5",Space,Str "is",Space,Str "right-angled."]]]
+,Div ("",["proof"],[])
+ [Para [Emph [Str "Proof."],Space,Str "This",Space,Str "lemma",Space,Str "follows",Space,Str "from",Space,Link ("",[],[("reference-type","ref"),("reference","def:tri")]) [Str "Definition",Str "\160",Str "1"] ("#def:tri",""),Space,Str "since",Space,Math InlineMath "3^2+4^2=9+16=25=5^2",Str ".",Str "\160\9723"]]
+,Div ("thm:py",["theorem"],[])
+ [Para [Strong [Str "Theorem",Space,Str "3"],Space,Str "(Pythagorean",Space,Str "triplets).",Space,Space,Emph [Str "Triangles",Space,Str "with",Space,Str "sides",Space,Str "of",Space,Str "length",Space,Math InlineMath "a=p^2-q^2",Str ",",Space,Math InlineMath "b=2pq",Space,Str "and",Space,Math InlineMath "c=p^2+q^2",Space,Str "are",Space,Str "right-angled",Space,Str "triangles."]]]
+,Div ("",["remark"],[])
+ [Para [Emph [Str "Remark",Space,Str "1"],Str ".",Space,Space,Str "These",Space,Str "are",Space,Str "all",Space,Str "pretty",Space,Str "interesting",Space,Str "facts."]]]
+```
diff --git a/test/command/3577.md b/test/command/3577.md
--- a/test/command/3577.md
+++ b/test/command/3577.md
@@ -16,10 +16,10 @@
 \end{figure}
 ^D
 <figure>
-<img src="img1.jpg" alt="" /><figcaption>Caption 1</figcaption>
+<img src="img1.jpg" alt="Caption 1" /><figcaption aria-hidden="true">Caption 1</figcaption>
 </figure>
 <figure>
-<img src="img2.jpg" alt="" /><figcaption>Caption 2</figcaption>
+<img src="img2.jpg" alt="Caption 2" /><figcaption aria-hidden="true">Caption 2</figcaption>
 </figure>
 ```
 ```
@@ -30,6 +30,6 @@
 \end{figure}
 ^D
 <figure>
-<img src="img1.jpg" alt="" /><figcaption>Caption 3</figcaption>
+<img src="img1.jpg" alt="Caption 3" /><figcaption aria-hidden="true">Caption 3</figcaption>
 </figure>
 ```
diff --git a/test/command/3587.md b/test/command/3587.md
--- a/test/command/3587.md
+++ b/test/command/3587.md
@@ -55,3 +55,62 @@
 [Para [Str "18.2\160\176C"]]
 ```
 
+# SIRange tests
+
+## Integer range with simple common units
+
+```
+% pandoc -f latex -t native
+\SIRange{10}{20}{\gram}
+^D
+[Para [Str "10\160g\8211\&20\160g"]]
+```
+```
+% pandoc -f latex -t native
+\SIRange{35}{9}{\milli\meter}
+^D
+[Para [Str "35\160mm\8211\&9\160mm"]]
+```
+```
+% pandoc -f latex -t native
+\SIRange{4}{97367265}{\celsius}
+^D
+[Para [Str "4\160\176C\8211\&97367265\160\176C"]]
+```
+
+## Decimal range with simple units
+
+```
+% pandoc -f latex -t native
+\SIRange{4.5}{97367265.5}{\celsius}
+^D
+[Para [Str "4.5\160\176C\8211\&97367265.5\160\176C"]]
+```
+
+## Squared units
+
+```
+% pandoc -f latex -t native
+\SIRange{10}{20}{\square\meter}
+^D
+[Para [Str "10\160m\178\8211\&20\160m\178"]]
+```
+
+## Ignore round precision
+
+`round-precision` option appears to be ignored by `\SI` as of 7c6dbd37e, so
+`\SIRange` will ignore it as well.
+
+```
+% pandoc -f latex -t native
+\SIRange[round-precision=2]{10}{20}{\gram}
+^D
+[Para [Str "10\160g\8211\&20\160g"]]
+```
+```
+% pandoc -f latex -t native
+\SIRange[round-precision=2]{10.0}{20.25}{\gram}
+^D
+[Para [Str "10.0\160g\8211\&20.25\160g"]]
+```
+
diff --git a/test/command/3734.md b/test/command/3734.md
--- a/test/command/3734.md
+++ b/test/command/3734.md
@@ -27,6 +27,6 @@
 | aaaaaaaaaaaa |       | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
 ^D
 | aaaaaaaaaaaa | bbbbb | ccccccccccc                                                              |
-| ------------ | ----- | ------------------------------------------------------------------------ |
+|--------------|-------|--------------------------------------------------------------------------|
 | aaaaaaaaaaaa |       | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc |
 ```
diff --git a/test/command/4038.md b/test/command/4038.md
--- a/test/command/4038.md
+++ b/test/command/4038.md
@@ -1,5 +1,5 @@
 ```
-% pandoc -f gfm -t gfm
+% pandoc -f gfm -t gfm --atx-headers
 # ~~Header~~
 ^D
 # ~~Header~~
diff --git a/test/command/4528.md b/test/command/4528.md
--- a/test/command/4528.md
+++ b/test/command/4528.md
@@ -124,7 +124,7 @@
 % pandoc --wrap=none -f html -t commonmark-raw_html
 This has <sub>subscript</sub> in it and <sub>2 3</sub> again. With emphasis: <sub><em>2</em> 3</sub>. With letters: <sub>foo</sub>. With a span: <sub><span class=foo>2</span></sub>.
 ^D
-This has \_(subscript) in it and ₂ ₃ again. With emphasis: \_(*2* 3). With letters: \_(foo). With a span: ₂.
+This has _(subscript) in it and ₂ ₃ again. With emphasis: _(*2* 3). With letters: _(foo). With a span: ₂.
 ```
 
 ```
diff --git a/test/command/4677.md b/test/command/4677.md
--- a/test/command/4677.md
+++ b/test/command/4677.md
@@ -3,6 +3,6 @@
 ![Caption](img.png){#img:1}
 ^D
 <figure>
-<img src="img.png" id="img:1" alt="" /><figcaption>Caption</figcaption>
+<img src="img.png" id="img:1" alt="Caption" /><figcaption aria-hidden="true">Caption</figcaption>
 </figure>
 ```
diff --git a/test/command/5121.md b/test/command/5121.md
--- a/test/command/5121.md
+++ b/test/command/5121.md
@@ -5,7 +5,7 @@
 ## Header 2
 ^D
 <figure>
-<img src="./my-figure.jpg" width="500" alt="" /><figcaption>My caption</figcaption>
+<img src="./my-figure.jpg" width="500" alt="My caption" /><figcaption aria-hidden="true">My caption</figcaption>
 </figure>
 
 Header 2
diff --git a/test/command/5642.md b/test/command/5642.md
--- a/test/command/5642.md
+++ b/test/command/5642.md
@@ -3,6 +3,6 @@
 ![test](foo){aria-describedby="barbaz"}
 ^D
 <figure>
-<img src="foo" aria-describedby="barbaz" alt="" /><figcaption>test</figcaption>
+<img src="foo" aria-describedby="barbaz" alt="test" /><figcaption aria-hidden="true">test</figcaption>
 </figure>
 ```
diff --git a/test/command/6549.md b/test/command/6549.md
new file mode 100644
--- /dev/null
+++ b/test/command/6549.md
@@ -0,0 +1,26 @@
+```
+% pandoc -f rst
+.. csv-table:: Test table
+   :file: command/01.csv
+   :delim: ;
+   :header-rows: 1
+^D
+<table>
+<caption>Test table</caption>
+<thead>
+<tr class="header">
+<th>Column1</th>
+<th>Column2</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Data1</td>
+<td><ul>
+<li>data1</li>
+<li>data2</li>
+</ul></td>
+</tr>
+</tbody>
+</table>
+```
diff --git a/test/command/gfm.md b/test/command/gfm.md
--- a/test/command/gfm.md
+++ b/test/command/gfm.md
@@ -69,7 +69,7 @@
 % pandoc -f gfm+smart -t native
 "hi"
 ^D
-[Para [Str "\8220hi\8221"]]
+[Para [Quoted DoubleQuote [Str "hi"]]]
 ```
 
 ```
@@ -100,7 +100,7 @@
  [])]
 ^D
 | Fruit  | Price |
-| ------ | ----: |
+|--------|------:|
 | apple  |  0.13 |
 | orange |  1.12 |
 
@@ -161,6 +161,6 @@
 - [ ] foo
 - [x] bar
 ^D
-  - [ ] foo
-  - [x] bar
+-   [ ] foo
+-   [x] bar
 ```
diff --git a/test/docx/golden/block_quotes.docx b/test/docx/golden/block_quotes.docx
Binary files a/test/docx/golden/block_quotes.docx and b/test/docx/golden/block_quotes.docx differ
diff --git a/test/docx/golden/codeblock.docx b/test/docx/golden/codeblock.docx
Binary files a/test/docx/golden/codeblock.docx and b/test/docx/golden/codeblock.docx differ
diff --git a/test/docx/golden/comments.docx b/test/docx/golden/comments.docx
Binary files a/test/docx/golden/comments.docx and b/test/docx/golden/comments.docx differ
diff --git a/test/docx/golden/custom_style_no_reference.docx b/test/docx/golden/custom_style_no_reference.docx
Binary files a/test/docx/golden/custom_style_no_reference.docx and b/test/docx/golden/custom_style_no_reference.docx differ
diff --git a/test/docx/golden/custom_style_preserve.docx b/test/docx/golden/custom_style_preserve.docx
Binary files a/test/docx/golden/custom_style_preserve.docx and b/test/docx/golden/custom_style_preserve.docx differ
diff --git a/test/docx/golden/definition_list.docx b/test/docx/golden/definition_list.docx
Binary files a/test/docx/golden/definition_list.docx and b/test/docx/golden/definition_list.docx differ
diff --git a/test/docx/golden/document-properties-short-desc.docx b/test/docx/golden/document-properties-short-desc.docx
Binary files a/test/docx/golden/document-properties-short-desc.docx and b/test/docx/golden/document-properties-short-desc.docx differ
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/golden/headers.docx b/test/docx/golden/headers.docx
Binary files a/test/docx/golden/headers.docx and b/test/docx/golden/headers.docx differ
diff --git a/test/docx/golden/image.docx b/test/docx/golden/image.docx
Binary files a/test/docx/golden/image.docx and b/test/docx/golden/image.docx differ
diff --git a/test/docx/golden/inline_code.docx b/test/docx/golden/inline_code.docx
Binary files a/test/docx/golden/inline_code.docx and b/test/docx/golden/inline_code.docx differ
diff --git a/test/docx/golden/inline_formatting.docx b/test/docx/golden/inline_formatting.docx
Binary files a/test/docx/golden/inline_formatting.docx and b/test/docx/golden/inline_formatting.docx differ
diff --git a/test/docx/golden/inline_images.docx b/test/docx/golden/inline_images.docx
Binary files a/test/docx/golden/inline_images.docx and b/test/docx/golden/inline_images.docx differ
diff --git a/test/docx/golden/link_in_notes.docx b/test/docx/golden/link_in_notes.docx
Binary files a/test/docx/golden/link_in_notes.docx and b/test/docx/golden/link_in_notes.docx differ
diff --git a/test/docx/golden/links.docx b/test/docx/golden/links.docx
Binary files a/test/docx/golden/links.docx and b/test/docx/golden/links.docx differ
diff --git a/test/docx/golden/lists.docx b/test/docx/golden/lists.docx
Binary files a/test/docx/golden/lists.docx and b/test/docx/golden/lists.docx differ
diff --git a/test/docx/golden/lists_continuing.docx b/test/docx/golden/lists_continuing.docx
Binary files a/test/docx/golden/lists_continuing.docx and b/test/docx/golden/lists_continuing.docx differ
diff --git a/test/docx/golden/lists_restarting.docx b/test/docx/golden/lists_restarting.docx
Binary files a/test/docx/golden/lists_restarting.docx and b/test/docx/golden/lists_restarting.docx differ
diff --git a/test/docx/golden/nested_anchors_in_header.docx b/test/docx/golden/nested_anchors_in_header.docx
Binary files a/test/docx/golden/nested_anchors_in_header.docx and b/test/docx/golden/nested_anchors_in_header.docx differ
diff --git a/test/docx/golden/notes.docx b/test/docx/golden/notes.docx
Binary files a/test/docx/golden/notes.docx and b/test/docx/golden/notes.docx differ
diff --git a/test/docx/golden/table_one_row.docx b/test/docx/golden/table_one_row.docx
Binary files a/test/docx/golden/table_one_row.docx and b/test/docx/golden/table_one_row.docx differ
diff --git a/test/docx/golden/table_with_list_cell.docx b/test/docx/golden/table_with_list_cell.docx
Binary files a/test/docx/golden/table_with_list_cell.docx and b/test/docx/golden/table_with_list_cell.docx differ
diff --git a/test/docx/golden/tables.docx b/test/docx/golden/tables.docx
Binary files a/test/docx/golden/tables.docx and b/test/docx/golden/tables.docx differ
diff --git a/test/docx/golden/track_changes_deletion.docx b/test/docx/golden/track_changes_deletion.docx
Binary files a/test/docx/golden/track_changes_deletion.docx and b/test/docx/golden/track_changes_deletion.docx differ
diff --git a/test/docx/golden/track_changes_insertion.docx b/test/docx/golden/track_changes_insertion.docx
Binary files a/test/docx/golden/track_changes_insertion.docx and b/test/docx/golden/track_changes_insertion.docx differ
diff --git a/test/docx/golden/track_changes_move.docx b/test/docx/golden/track_changes_move.docx
Binary files a/test/docx/golden/track_changes_move.docx and b/test/docx/golden/track_changes_move.docx differ
diff --git a/test/docx/golden/unicode.docx b/test/docx/golden/unicode.docx
Binary files a/test/docx/golden/unicode.docx and b/test/docx/golden/unicode.docx differ
diff --git a/test/docx/golden/verbatim_subsuper.docx b/test/docx/golden/verbatim_subsuper.docx
Binary files a/test/docx/golden/verbatim_subsuper.docx and b/test/docx/golden/verbatim_subsuper.docx differ
diff --git a/test/docx/inline_formatting.native b/test/docx/inline_formatting.native
--- a/test/docx/inline_formatting.native
+++ b/test/docx/inline_formatting.native
@@ -1,6 +1,6 @@
 Pandoc (Meta {unMeta = fromList []})
 [Para [Str "Regular",Space,Str "text",Space,Emph [Str "italics"],Space,Strong [Str "bold",Space,Emph [Str "bold",Space,Str "italics"]],Str "."]
 ,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "Small",Space,Str "Caps"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "strikethrough"],Str "."]
-,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Underline [Str "single",Space,Str "underlines",Space,Str "for",Space],Emph [Underline [Str "emphasis"]],Str "."]
+,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Underline [Str "single",Space,Str "underlines",Space,Str "for",Space,Emph [Str "emphasis"]],Str "."]
 ,Para [Str "Above",Space,Str "the",Space,Str "line",Space,Str "is",Space,Superscript [Str "superscript"],Space,Str "and",Space,Str "below",Space,Str "the",Space,Str "line",Space,Str "is",Space,Subscript [Str "subscript"],Str "."]
 ,Para [Str "A",Space,Str "line",LineBreak,Str "break."]]
diff --git a/test/lhs-test.latex b/test/lhs-test.latex
--- a/test/lhs-test.latex
+++ b/test/lhs-test.latex
@@ -81,6 +81,9 @@
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
 \setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
 
 \author{}
 \date{}
diff --git a/test/lhs-test.latex+lhs b/test/lhs-test.latex+lhs
--- a/test/lhs-test.latex+lhs
+++ b/test/lhs-test.latex+lhs
@@ -48,6 +48,9 @@
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
 \setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
 
 \author{}
 \date{}
diff --git a/test/test-pandoc.hs b/test/test-pandoc.hs
--- a/test/test-pandoc.hs
+++ b/test/test-pandoc.hs
@@ -37,6 +37,7 @@
 import qualified Tests.Writers.Jira
 import qualified Tests.Writers.LaTeX
 import qualified Tests.Writers.Markdown
+import qualified Tests.Writers.Ms
 import qualified Tests.Writers.Muse
 import qualified Tests.Writers.Native
 import qualified Tests.Writers.Org
@@ -70,6 +71,7 @@
           , testGroup "Muse" Tests.Writers.Muse.tests
           , testGroup "FB2" Tests.Writers.FB2.tests
           , testGroup "PowerPoint" Tests.Writers.Powerpoint.tests
+          , testGroup "Ms" Tests.Writers.Ms.tests
           ]
         , testGroup "Readers"
           [ testGroup "LaTeX" Tests.Readers.LaTeX.tests
diff --git a/test/writer.html5 b/test/writer.html5
--- a/test/writer.html5
+++ b/test/writer.html5
@@ -523,7 +523,7 @@
 <h1 id="images">Images</h1>
 <p>From “Voyage dans la Lune” by Georges Melies (1902):</p>
 <figure>
-<img src="lalune.jpg" title="Voyage dans la Lune" alt="" /><figcaption>lalune</figcaption>
+<img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune" /><figcaption aria-hidden="true">lalune</figcaption>
 </figure>
 <p>Here is a movie <img src="movie.jpg" alt="movie" /> icon.</p>
 <hr />
diff --git a/test/writer.jira b/test/writer.jira
--- a/test/writer.jira
+++ b/test/writer.jira
@@ -513,9 +513,9 @@
 h1. {anchor:images}Images
 From "Voyage dans la Lune" by Georges Melies \(1902):
 
-!lalune.jpg|title=fig:Voyage dans la Lune!
+!lalune.jpg|title=fig:Voyage dans la Lune, alt=lalune!
 
-Here is a movie !movie.jpg! icon.
+Here is a movie !movie.jpg|alt=movie! icon.
 
 ----
 h1. {anchor:footnotes}Footnotes
diff --git a/test/writer.latex b/test/writer.latex
--- a/test/writer.latex
+++ b/test/writer.latex
@@ -63,6 +63,9 @@
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
 \setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
 
 \title{Pandoc Test Suite}
 \author{John MacFarlane \and Anonymous}
diff --git a/test/writers-lang-and-dir.latex b/test/writers-lang-and-dir.latex
--- a/test/writers-lang-and-dir.latex
+++ b/test/writers-lang-and-dir.latex
@@ -66,6 +66,9 @@
   \newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
   \newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
 \fi
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
 \ifxetex
   % Load bidi as late as possible as it modifies e.g. graphicx
   \usepackage{bidi}
