diff --git a/AUTHORS.md b/AUTHORS.md
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -17,6 +17,7 @@
 - Antoine Latter
 - Antonio Terceiro
 - Arata Mizuki
+- Arfon Smith
 - Arlo O'Keeffe
 - Artyom Kazak
 - Agustín Martín Barbero
@@ -40,6 +41,7 @@
 - Clare Macrae
 - Clint Adams
 - Conal Elliott
+- Cormac Relf
 - Craig S. Bosma
 - Damien Clochard
 - Daniel Bergey
@@ -152,6 +154,8 @@
 - Or Neeman
 - OvidiusCicero
 - Pablo Rodríguez
+- Pascal Wagler
+- Paul Tilley
 - Paul Rivier
 - Paulo Tanimoto
 - Peter Wang
diff --git a/MANUAL.txt b/MANUAL.txt
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1,6 +1,6 @@
 % Pandoc User's Guide
 % John MacFarlane
-% March 2, 2019
+% March 12, 2019
 
 Synopsis
 ========
@@ -695,12 +695,17 @@
 
 :   Print the system default template for an output *FORMAT*. (See `-t`
     for a list of possible *FORMAT*s.)  Templates in the user data
-    directory are ignored.
+    directory are ignored.  This option may be used with
+    `-o`/`--output` to redirect output to a file, but
+    `-o`/`--output` must come before `--print-default-template`
+    on the command line.
 
 `--print-default-data-file=`*FILE*
 
 :   Print a system default data file.  Files in the user data directory
-    are ignored.
+    are ignored.  This option may be used with `-o`/`--output` to
+    redirect output to a file, but `-o`/`--output` must come before
+    `--print-default-data-file` on the command line.
 
 `--eol=crlf`|`lf`|`native`
 
@@ -784,7 +789,10 @@
 
 :   Prints a JSON version of a highlighting style, which can
     be modified, saved with a `.theme` extension, and used
-    with `--highlight-style`.
+    with `--highlight-style`.  This option may be used with
+    `-o`/`--output` to redirect output to a file, but
+    `-o`/`--output` must come before `--print-highlight-style`
+    on the command line.
 
 `--syntax-definition=`*FILE*
 
@@ -1016,11 +1024,11 @@
 
         To produce a custom `reference.docx`, first get a copy of
         the default `reference.docx`: `pandoc
-        --print-default-data-file reference.docx >
-        custom-reference.docx`.  Then open `custom-reference.docx`
-        in Word, modify the styles as you wish, and save the file.
-        For best results, do not make changes to this file other
-        than modifying the styles used by pandoc:
+        -o custom-reference.docx --print-default-data-file reference.docx`.
+        Then open `custom-reference.docx` in Word, modify the
+        styles as you wish, and save the file.  For best
+        results, do not make changes to this file other than
+        modifying the styles used by pandoc:
 
         Paragraph styles:
 
@@ -1078,10 +1086,9 @@
 
         To produce a custom `reference.odt`, first get a copy of
         the default `reference.odt`: `pandoc
-        --print-default-data-file reference.odt >
-        custom-reference.odt`.  Then open `custom-reference.odt` in
-        LibreOffice, modify the styles as you wish, and save the
-        file.
+        -o custom-reference.odt --print-default-data-file reference.odt`.
+        Then open `custom-reference.odt` in LibreOffice, modify
+        the styles as you wish, and save the file.
 
     PowerPoint
 
@@ -1102,10 +1109,10 @@
         `Home` menu to check.)
 
         You can also modify the default `reference.pptx`: first run
-        `pandoc --print-default-data-file reference.pptx >
-        custom-reference.pptx`, and then modify
-        `custom-reference.pptx` in MS PowerPoint (pandoc will use the
-        first four layout slides, as mentioned above).
+        `pandoc -o custom-reference.pptx --print-default-data-file
+        reference.pptx`, and then modify `custom-reference.pptx`
+        in MS PowerPoint (pandoc will use the first four layout
+        slides, as mentioned above).
 
 `--epub-cover-image=`*FILE*
 
@@ -1200,9 +1207,9 @@
 
 :   Use the specified engine when producing PDF output.
     Valid values are `pdflatex`, `lualatex`, `xelatex`, `latexmk`,
-    `wkhtmltopdf`, `weasyprint`, `prince`, `context`, and `pdfroff`.
-    The default is `pdflatex`.  If the engine is not in your PATH,
-    the full path of the engine may be specified here.
+    `tectonic`, `wkhtmltopdf`, `weasyprint`, `prince`, `context`,
+    and `pdfroff`. The default is `pdflatex`.  If the engine is
+    not in your PATH, the full path of the engine may be specified here.
 
 `--pdf-engine-opt=`*STRING*
 
@@ -5028,6 +5035,18 @@
 :::
 ::::::
 ````
+
+If you include raw HTML or TeX in an output cell, use the
+[raw attribute][Extension: `fenced_attribute`], as shown
+in the last cell of the example above.  Although pandoc can
+process "bare" raw HTML and TeX, the result is often
+interspersed raw elements and normal textual elements, and
+in an output cell pandoc expects a single, connected raw
+block.  To avoid using raw HTML or TeX except when
+marked explicitly using raw attributes, we recommend
+specifying the extensions `-raw_html-raw_tex+raw_attribute` when
+translating between Markdown and ipynb notebooks.
+
 
 Syntax highlighting
 ===================
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,3 +1,79 @@
+pandoc (2.7.1)
+
+  * Add tectonic as an option for --pdf-engine (#5345, Cormac Relf).
+    Runs tectonic on STDIN instead of a temporary .tex file, so that it
+    looks in the working directory for `\include` and `\input` like the rest
+    of the engines.  Allows overriding the output directory
+    args with `--pdf-engine-opt=--outdir --pdf-engine-opt="$DIR"`.
+
+  * Allow `-o/--output` to be used with `--print-default-data-file`,
+    `--print-highlighting-style`, `--print-default-template`.
+    Note that `-o` must occur BEFORE the `--print*` command on the command
+    line (this is documented, #5357).
+
+  * LaTeX reader:
+
+    + Support `\underline`, `\ul`, `\uline` (#5359, Paul
+      Tilley).  These are parsed as a Span with class `underline`, as
+      with other readers.
+    + Ensure that `\Footcite` and `\Footcites` get put in a note.
+
+  * ipynb reader:
+
+    + Remove sensitivity to `raw_html`, `raw_tex` extensions.
+      We now include every output format. Pruning is handled by
+      `--ipynb-output`.
+    + Better handling of cell metadata.  We now include even complex cell
+      metadata in the Div's attributes (as JSON, in complex cases, or
+      as plain strings in simple cases).
+
+  * ipynb writer:
+
+    + Recurse into native divs for output cell data (#5354).
+    + Render cell metadata fields from div attributes.
+
+  * Docx writer: avoid extra copy of abstractNum and num elements
+    in numbering.xml.  This caused pandoc-produced docx files to
+    be uneditable using Word Online (#5358).
+
+  * Markdown writer: improve handling of raw blocks/inline.
+    We now emit raw content using `raw_attribute` when no more
+    direct method is available.  Use of `raw_attribute` can be
+    forced by disabling `raw_html` and `raw_tex`.
+
+  * LaTeX writer: Add classes for frontmatter support (#5353, Andrew Dunning)
+    and remove frontmatter from `scrreprt`.
+
+  * LaTeX template:
+
+    + Improve readability (#5363, Andrew Dunning).
+    + Robust section numbering removal (#5351, Andrew Dunning).
+      Ensures that section numbering does not reappear with custom
+      section levels.  See <https://tex.stackexchange.com/questions/473653/>.
+    + Better handling of front/main/backmatter (#5348).
+      In pandoc 2.7 we assumed that every class with chapters would accept
+      `\frontmatter`, `\mainmatter`, and `\backmatter`.  This is not so (e.g.
+      report does not).  So pandoc 2.7 breaks on report class by including an
+      unsupported command.  Instead of the `book-class` variable, we use two
+      variables, `has-chapters` and `has-frontmatter`, and set these
+      intelligently in the writer.
+
+  * Text.Pandoc.Shared: Improve `filterIpynbOutput`.  Ensure that
+    images are prioritized over text. `best` should include everything
+    for ipynb.
+
+  * Tests.Old: specify `--data-dir=../data` to ensure tests can find
+    data files even if they haven't been installed.  Remove old
+    `pandoc_datadir` environment variable, which hasn't done anything for a
+    long time.
+
+  * MANUAL.txt: Add recommendation to use `raw_attribute` with ipynb (#5354).
+
+  * Use cmark-gfm-hs 0.1.8 (note that 0.1.7 is buggy).
+
+  * Use latest pandoc-citeproc, texmath.
+
+
 pandoc (2.7)
 
   * Use XDG data directory for user data directory (#3582). Instead of
@@ -171,13 +247,14 @@
   * LaTeX template:
 
     + Support the `subject` metadata variable (#5289, Pascal Wagler).
-    + Add \frontmatter, \mainmatter, \backmatter for book classes (#5306).
+    + Add `\frontmatter`, `\mainmatter`, `\backmatter`
+      for book classes (#5306).
 
   * epub3 template: Add titlepage class to section (#5269).
 
   * HTML5 template: Add ARIA role `doc-toc` for table of contents (#4213).
 
-  * Make --metadata-file use pandoc-markdown (#5279, #5272, Mauro Bieg).
+  * Make `--metadata-file` use selected extensions (#5279, #5272, Mauro Bieg).
 
   * Text.Pandoc.Shared:
 
diff --git a/data/bash_completion.tpl b/data/bash_completion.tpl
--- a/data/bash_completion.tpl
+++ b/data/bash_completion.tpl
@@ -34,7 +34,7 @@
              return 0
              ;;
          --pdf-engine)
-             COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
+             COMPREPLY=( $(compgen -W "pdflatex lualatex xelatex latexmk tectonic wkhtmltopdf weasyprint prince context pdfroff" -- ${cur}) )
              return 0
              ;;
          --print-default-data-file)
diff --git a/data/templates/default.latex b/data/templates/default.latex
--- a/data/templates/default.latex
+++ b/data/templates/default.latex
@@ -1,4 +1,5 @@
-\PassOptionsToPackage{unicode=true$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref} % options for packages loaded elsewhere
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode=true$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
 \PassOptionsToPackage{hyphens}{url}
 $if(colorlinks)$
 \PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
@@ -46,7 +47,7 @@
 $for(beameroption)$
 \setbeameroption{$beameroption$}
 $endfor$
-% Prevent slide breaks in the middle of a paragraph:
+% Prevent slide breaks in the middle of a paragraph
 \widowpenalties 1 10000
 \raggedbottom
 $if(section-titles)$
@@ -173,7 +174,7 @@
 \useoutertheme{$outertheme$}
 $endif$
 $endif$
-% use upquote if available, for straight quotes in verbatim environments
+% Use upquote if available, for straight quotes in verbatim environments
 \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
 \IfFileExists{microtype.sty}{% use microtype if available
   \usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
@@ -218,10 +219,10 @@
   citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
   urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
 $else$
-  pdfborder={0 0 0},
+  hidelinks,
 $endif$
-  breaklinks=true}
-\urlstyle{same}  % don't use monospace font for urls
+}
+\urlstyle{same} % disable monospaced font for URLs
 $if(verbatim-in-note)$
 \VerbatimFootnotes % allows verbatim text in footnotes
 $endif$
@@ -247,7 +248,7 @@
 \usepackage{longtable,booktabs}
 $if(beamer)$
 \usepackage{caption}
-% These lines are needed to make table captions work with longtable:
+% Make caption package work with longtable
 \makeatletter
 \def\fnum@table{\tablename~\thetable}
 \makeatother
@@ -274,16 +275,16 @@
 $endif$
 $if(strikeout)$
 \usepackage[normalem]{ulem}
-% avoid problems with \sout in headers with hyperref:
+% Avoid problems with \sout in headers with hyperref
 \pdfstringdefDisableCommands{\renewcommand{\sout}{}}
 $endif$
-\setlength{\emergencystretch}{3em}  % prevent overfull lines
+\setlength{\emergencystretch}{3em} % prevent overfull lines
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
 $if(numbersections)$
 \setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
 $else$
-\setcounter{secnumdepth}{-2}
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
 $endif$
 $if(beamer)$
 $else$
@@ -304,7 +305,7 @@
 \pagestyle{$pagestyle$}
 $endif$
 
-% set default figure placement to htbp
+% Set default figure placement to htbp
 \makeatletter
 \def\fps@figure{htbp}
 \makeatother
@@ -313,23 +314,23 @@
 $header-includes$
 $endfor$
 $if(lang)$
-\ifnum 0\ifxetex 1\fi=0 % if pdftex or luatex
-  \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
-$if(babel-newcommands)$
-  $babel-newcommands$
-$endif$
-\else % if xetex
-  % load polyglossia as late as possible as it *could* call bidi if RTL lang (e.g. Hebrew or Arabic)
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
   \usepackage{polyglossia}
   \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
 $for(polyglossia-otherlangs)$
   \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
 $endfor$
+\else
+  \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+$if(babel-newcommands)$
+  $babel-newcommands$
+$endif$
 \fi
 $endif$
 $if(dir)$
 \ifxetex
-  % load bidi as late as possible as it modifies e.g. graphicx
+  % Load bidi as late as possible as it modifies e.g. graphicx
   \usepackage{bidi}
 \fi
 \ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
@@ -383,10 +384,10 @@
 $endif$
 
 \begin{document}
-$if(title)$
-$if(book-class)$
+$if(has-frontmatter)$
 \frontmatter
 $endif$
+$if(title)$
 $if(beamer)$
 \frame{\titlepage}
 $else$
@@ -430,18 +431,18 @@
 $if(lof)$
 \listoffigures
 $endif$
-$if(book-class)$
+$if(has-frontmatter)$
 \mainmatter
 $endif$
 $body$
 
-$if(book-class)$
+$if(has-frontmatter)$
 \backmatter
 $endif$
 $if(natbib)$
 $if(bibliography)$
 $if(biblio-title)$
-$if(book-class)$
+$if(has-chapters)$
 \renewcommand\bibname{$biblio-title$}
 $else$
 \renewcommand\refname{$biblio-title$}
diff --git a/man/pandoc.1 b/man/pandoc.1
--- a/man/pandoc.1
+++ b/man/pandoc.1
@@ -1,5 +1,5 @@
 .\"t
-.TH PANDOC 1 "March 2, 2019" "pandoc 2.7"
+.TH PANDOC 1 "March 12, 2019" "pandoc 2.7.1"
 .SH NAME
 pandoc - general markup converter
 .SH SYNOPSIS
@@ -711,10 +711,16 @@
 Print the system default template for an output \f[I]FORMAT\f[R].
 (See \f[C]-t\f[R] for a list of possible \f[I]FORMAT\f[R]s.) Templates
 in the user data directory are ignored.
+This option may be used with \f[C]-o\f[R]/\f[C]--output\f[R] to redirect
+output to a file, but \f[C]-o\f[R]/\f[C]--output\f[R] must come before
+\f[C]--print-default-template\f[R] on the command line.
 .TP
 .B \f[C]--print-default-data-file=\f[R]\f[I]FILE\f[R]
 Print a system default data file.
 Files in the user data directory are ignored.
+This option may be used with \f[C]-o\f[R]/\f[C]--output\f[R] to redirect
+output to a file, but \f[C]-o\f[R]/\f[C]--output\f[R] must come before
+\f[C]--print-default-data-file\f[R] on the command line.
 .TP
 .B \f[C]--eol=crlf\f[R]|\f[C]lf\f[R]|\f[C]native\f[R]
 Manually specify line endings: \f[C]crlf\f[R] (Windows), \f[C]lf\f[R]
@@ -797,6 +803,9 @@
 Prints a JSON version of a highlighting style, which can be modified,
 saved with a \f[C].theme\f[R] extension, and used with
 \f[C]--highlight-style\f[R].
+This option may be used with \f[C]-o\f[R]/\f[C]--output\f[R] to redirect
+output to a file, but \f[C]-o\f[R]/\f[C]--output\f[R] must come before
+\f[C]--print-highlight-style\f[R] on the command line.
 .TP
 .B \f[C]--syntax-definition=\f[R]\f[I]FILE\f[R]
 Instructs pandoc to load a KDE XML syntax definition file, which will be
@@ -1034,7 +1043,7 @@
 .PP
 To produce a custom \f[C]reference.docx\f[R], first get a copy of the
 default \f[C]reference.docx\f[R]:
-\f[C]pandoc --print-default-data-file reference.docx > custom-reference.docx\f[R].
+\f[C]pandoc -o custom-reference.docx --print-default-data-file reference.docx\f[R].
 Then open \f[C]custom-reference.docx\f[R] in Word, modify the styles as
 you wish, and save the file.
 For best results, do not make changes to this file other than modifying
@@ -1130,7 +1139,7 @@
 .PP
 To produce a custom \f[C]reference.odt\f[R], first get a copy of the
 default \f[C]reference.odt\f[R]:
-\f[C]pandoc --print-default-data-file reference.odt > custom-reference.odt\f[R].
+\f[C]pandoc -o custom-reference.odt --print-default-data-file reference.odt\f[R].
 Then open \f[C]custom-reference.odt\f[R] in LibreOffice, modify the
 styles as you wish, and save the file.
 .RE
@@ -1158,7 +1167,7 @@
 check.)
 .PP
 You can also modify the default \f[C]reference.pptx\f[R]: first run
-\f[C]pandoc --print-default-data-file reference.pptx > custom-reference.pptx\f[R],
+\f[C]pandoc -o custom-reference.pptx --print-default-data-file reference.pptx\f[R],
 and then modify \f[C]custom-reference.pptx\f[R] in MS PowerPoint (pandoc
 will use the first four layout slides, as mentioned above).
 .RE
@@ -1269,9 +1278,9 @@
 .B \f[C]--pdf-engine=\f[R]\f[I]PROGRAM\f[R]
 Use the specified engine when producing PDF output.
 Valid values are \f[C]pdflatex\f[R], \f[C]lualatex\f[R],
-\f[C]xelatex\f[R], \f[C]latexmk\f[R], \f[C]wkhtmltopdf\f[R],
-\f[C]weasyprint\f[R], \f[C]prince\f[R], \f[C]context\f[R], and
-\f[C]pdfroff\f[R].
+\f[C]xelatex\f[R], \f[C]latexmk\f[R], \f[C]tectonic\f[R],
+\f[C]wkhtmltopdf\f[R], \f[C]weasyprint\f[R], \f[C]prince\f[R],
+\f[C]context\f[R], and \f[C]pdfroff\f[R].
 The default is \f[C]pdflatex\f[R].
 If the engine is not in your PATH, the full path of the engine may be
 specified here.
@@ -5934,6 +5943,17 @@
 ::::::
 \f[R]
 .fi
+.PP
+If you include raw HTML or TeX in an output cell, use the [raw
+attribute][Extension: \f[C]fenced_attribute\f[R]], as shown in the last
+cell of the example above.
+Although pandoc can process \[dq]bare\[dq] raw HTML and TeX, the result
+is often interspersed raw elements and normal textual elements, and in
+an output cell pandoc expects a single, connected raw block.
+To avoid using raw HTML or TeX except when marked explicitly using raw
+attributes, we recommend specifying the extensions
+\f[C]-raw_html-raw_tex+raw_attribute\f[R] when translating between
+Markdown and ipynb notebooks.
 .SH SYNTAX HIGHLIGHTING
 .PP
 Pandoc will automatically highlight syntax in fenced code blocks that
diff --git a/pandoc.cabal b/pandoc.cabal
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,5 +1,5 @@
 name:            pandoc
-version:         2.7
+version:         2.7.1
 cabal-version:   2.0
 build-type:      Simple
 license:         GPL-2
@@ -11,8 +11,8 @@
 stability:       alpha
 homepage:        https://pandoc.org
 category:        Text
-tested-with:     GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3,
-                 GHC == 8.6.1
+tested-with:     GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4,
+                 GHC == 8.6.3
 synopsis:        Conversion between markup formats
 description:     Pandoc is a Haskell library for converting from one markup
                  format to another, and a command-line tool that uses
@@ -394,7 +394,7 @@
                  deepseq >= 1.3 && < 1.5,
                  JuicyPixels >= 3.1.6.1 && < 3.4,
                  Glob >= 0.7 && < 0.11,
-                 cmark-gfm >= 0.1.1 && < 0.2,
+                 cmark-gfm >= 0.1.8 && < 0.2,
                  doctemplates >= 0.2.1 && < 0.3,
                  network-uri >= 2.6 && < 2.7,
                  network >= 2.6,
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs
--- a/src/Text/Pandoc/App/CommandLineOptions.hs
+++ b/src/Text/Pandoc/App/CommandLineOptions.hs
@@ -85,7 +85,7 @@
   return (opts{ optInputFiles = map normalizePath args })
 
 latexEngines :: [String]
-latexEngines  = ["pdflatex", "lualatex", "xelatex", "latexmk"]
+latexEngines  = ["pdflatex", "lualatex", "xelatex", "latexmk", "tectonic"]
 
 htmlEngines :: [String]
 htmlEngines  = ["wkhtmltopdf", "weasyprint", "prince"]
@@ -786,7 +786,10 @@
 
     , Option "D" ["print-default-template"]
                  (ReqArg
-                  (\arg _ -> do
+                  (\arg opt -> do
+                     let write = case optOutputFile opt of
+                                        Just f  -> UTF8.writeFile f
+                                        Nothing -> UTF8.hPutStr stdout
                      templ <- runIO $ do
                                 setUserDataDir Nothing
                                 getDefaultTemplate arg
@@ -794,7 +797,7 @@
                           Right "" -> -- e.g. for docx, odt, json:
                             E.throwIO $ PandocCouldNotFindDataFileError
                                ("templates/default." ++ arg)
-                          Right t -> UTF8.hPutStr stdout t
+                          Right t -> write t
                           Left e  -> E.throwIO e
                      exitSuccess)
                   "FORMAT")
@@ -802,18 +805,24 @@
 
     , Option "" ["print-default-data-file"]
                  (ReqArg
-                  (\arg _ -> do
+                  (\arg opt -> do
+                     let write = case optOutputFile opt of
+                                        Just f  -> BS.writeFile f
+                                        Nothing -> BS.hPutStr stdout
                      runIOorExplode $
-                       readDefaultDataFile arg >>= liftIO . BS.hPutStr stdout
+                       readDefaultDataFile arg >>= liftIO . write
                      exitSuccess)
                   "FILE")
                   "" -- "Print default data file"
 
     , Option "" ["print-highlight-style"]
                  (ReqArg
-                  (\arg _ -> do
+                  (\arg opt -> do
+                     let write = case optOutputFile opt of
+                                        Just f  -> B.writeFile f
+                                        Nothing -> B.putStr
                      sty <- fromMaybe pygments <$> lookupHighlightStyle arg
-                     B.putStr $ encodePretty'
+                     write $ encodePretty'
                        defConfig{confIndent = Spaces 4
                                 ,confCompare = keyOrder
                                   (map T.pack
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -70,7 +70,7 @@
         -> WriterOptions       -- ^ options
         -> Pandoc              -- ^ document
         -> PandocIO (Either ByteString ByteString)
-makePDF program pdfargs writer opts doc = do
+makePDF program pdfargs writer opts doc =
   case takeBaseName program of
     "wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc
     prog | prog `elem` ["weasyprint", "prince"] -> do
@@ -107,6 +107,7 @@
           source <- writer opts doc'
           res <- case baseProg of
             "context" -> context2pdf verbosity program pdfargs tmpdir source
+            "tectonic" -> tectonic2pdf verbosity program pdfargs tmpdir source
             prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"]
                 -> tex2pdf verbosity program pdfargs tmpdir source
             _ -> return $ Left $ UTF8.fromStringLazy
@@ -200,6 +201,21 @@
     mime = getMimeType fname
     doNothing = return (Right fname)
 
+tectonic2pdf :: Verbosity                       -- ^ Verbosity level
+             -> String                          -- ^ tex program
+             -> [String]                        -- ^ Arguments to the latex-engine
+             -> FilePath                        -- ^ temp directory for output
+             -> Text                            -- ^ tex source
+             -> PandocIO (Either ByteString ByteString)
+tectonic2pdf verbosity program args tmpDir source = do
+  (exit, log', mbPdf) <- runTectonic verbosity program args tmpDir source
+  case (exit, mbPdf) of
+       (ExitFailure _, _)      -> return $ Left $ extractMsg log'
+       (ExitSuccess, Nothing)  -> return $ Left ""
+       (ExitSuccess, Just pdf) -> do
+          missingCharacterWarnings verbosity log'
+          return $ Right pdf
+
 tex2pdf :: Verbosity                       -- ^ Verbosity level
         -> String                          -- ^ tex program
         -> [String]                        -- ^ Arguments to the latex-engine
@@ -207,12 +223,9 @@
         -> Text                            -- ^ tex source
         -> PandocIO (Either ByteString ByteString)
 tex2pdf verbosity program args tmpDir source = do
-  let numruns =
-        if takeBaseName program == "latexmk"
-           then 1
-           else if "\\tableofcontents" `T.isInfixOf` source
-                   then 3  -- to get page numbers
-                   else 2  -- 1 run won't give you PDF bookmarks
+  let numruns | takeBaseName program == "latexmk"        = 1
+              | "\\tableofcontents" `T.isInfixOf` source = 3  -- to get page numbers
+              | otherwise                                = 2  -- 1 run won't give you PDF bookmarks
   (exit, log', mbPdf) <- runTeXProgram verbosity program args 1 numruns
                           tmpDir source
   case (exit, mbPdf) of
@@ -262,6 +275,59 @@
 
 -- running tex programs
 
+runTectonic :: Verbosity -> String -> [String] -> FilePath
+              -> Text -> PandocIO (ExitCode, ByteString, Maybe ByteString)
+runTectonic verbosity program args' tmpDir' source = do
+    let getOutDir acc (a:b:xs) = if a `elem` ["-o", "--outdir"]
+                                    then (reverse acc ++ xs, Just b)
+                                    else getOutDir (b:a:acc) xs
+        getOutDir acc xs = (reverse acc ++ xs, Nothing)
+        (args, outDir) = getOutDir [] args'
+        tmpDir = fromMaybe tmpDir' outDir
+    liftIO $ createDirectoryIfMissing True tmpDir
+    -- run tectonic on stdin so it reads \include commands from $PWD instead of a temp directory
+    let sourceBL = BL.fromStrict $ UTF8.fromText source
+    let programArgs = ["--outdir", tmpDir] ++ args ++ ["-"]
+    env <- liftIO getEnvironment
+    when (verbosity >= INFO) $ liftIO $
+      showVerboseInfo (Just tmpDir) program programArgs env (UTF8.toStringLazy sourceBL)
+    (exit, out) <- liftIO $ E.catch
+      (pipeProcess (Just env) program programArgs sourceBL)
+      (\(e :: IOError) -> if isDoesNotExistError e
+                             then E.throwIO $ PandocPDFProgramNotFoundError
+                                   program
+                             else E.throwIO e)
+    when (verbosity >= INFO) $ liftIO $ do
+      putStrLn "[makePDF] Running"
+      BL.hPutStr stdout out
+      putStr "\n"
+    let pdfFile = tmpDir </> "texput.pdf"
+    (_, pdf) <- getResultingPDF Nothing pdfFile
+    return (exit, out, pdf)
+
+-- read a pdf that has been written to a temporary directory, and optionally read
+-- logs
+getResultingPDF :: Maybe String -> String -> PandocIO (Maybe ByteString, Maybe ByteString)
+getResultingPDF logFile pdfFile = do
+    pdfExists <- liftIO $ doesFileExist pdfFile
+    pdf <- if pdfExists
+              -- We read PDF as a strict bytestring to make sure that the
+              -- temp directory is removed on Windows.
+              -- See https://github.com/jgm/pandoc/issues/1192.
+              then (Just . BL.fromChunks . (:[])) `fmap`
+                   liftIO (BS.readFile pdfFile)
+              else return Nothing
+    -- Note that some things like Missing character warnings
+    -- appear in the log but not on stderr, so we prefer the log:
+    log' <- case logFile of
+              Just logFile' -> do
+                logExists <- liftIO $ doesFileExist logFile'
+                if logExists
+                  then liftIO $ Just <$> BL.readFile logFile'
+                  else return Nothing
+              Nothing -> return Nothing
+    return (log', pdf)
+
 -- Run a TeX program on an input bytestring and return (exit code,
 -- contents of stdout, contents of produced PDF if any).  Rerun
 -- a fixed number of times to resolve references.
@@ -276,12 +342,11 @@
     let file = tmpDir </> "input.tex"
     exists <- liftIO $ doesFileExist file
     unless exists $ liftIO $ BS.writeFile file $ UTF8.fromText source
-    let programArgs =
-          if takeBaseName program == "latexmk"
-             then ["-interaction=batchmode", "-halt-on-error", "-pdf",
-                   "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
-             else ["-halt-on-error", "-interaction", "nonstopmode",
-                   "-output-directory", tmpDir] ++ args ++ [file]
+    let isLatexMk = takeBaseName program == "latexmk"
+        programArgs | isLatexMk = ["-interaction=batchmode", "-halt-on-error", "-pdf",
+                                   "-quiet", "-outdir=" ++ tmpDir] ++ args ++ [file]
+                    | otherwise = ["-halt-on-error", "-interaction", "nonstopmode",
+                                   "-output-directory", tmpDir] ++ args ++ [file]
     env' <- liftIO getEnvironment
     let sep = [searchPathSeparator]
     let texinputs = maybe (tmpDir ++ sep) ((tmpDir ++ sep) ++)
@@ -306,23 +371,10 @@
     if runNumber < numRuns
        then runTeXProgram verbosity program args (runNumber + 1) numRuns tmpDir source
        else do
-         let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
-         pdfExists <- liftIO $ doesFileExist pdfFile
-         pdf <- if pdfExists
-                   -- We read PDF as a strict bytestring to make sure that the
-                   -- temp directory is removed on Windows.
-                   -- See https://github.com/jgm/pandoc/issues/1192.
-                   then (Just . BL.fromChunks . (:[])) `fmap`
-                        liftIO (BS.readFile pdfFile)
-                   else return Nothing
-         -- Note that some things like Missing character warnings
-         -- appear in the log but not on stderr, so we prefer the log:
          let logFile = replaceExtension file ".log"
-         logExists <- liftIO $ doesFileExist logFile
-         log' <- if logExists
-                    then liftIO $ BL.readFile logFile
-                    else return out
-         return (exit, log', pdf)
+         let pdfFile = replaceExtension file ".pdf"
+         (log', pdf) <- getResultingPDF (Just logFile) pdfFile
+         return (exit, fromMaybe out log', pdf)
 
 generic2pdf :: Verbosity
             -> String
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
@@ -18,6 +18,7 @@
 module Text.Pandoc.Readers.Ipynb ( readIpynb )
 where
 import Prelude
+import Data.Char (isDigit)
 import Data.List (isPrefixOf)
 import Data.Maybe (fromMaybe)
 import Data.Digest.Pure.SHA (sha1, showDigest)
@@ -39,6 +40,7 @@
 import Data.Aeson as Aeson
 import Control.Monad.Except (throwError)
 import Text.Pandoc.Readers.Markdown (readMarkdown)
+import qualified Text.Pandoc.UTF8 as UTF8
 
 readIpynb :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
 readIpynb opts t = do
@@ -99,7 +101,7 @@
       return $ B.divWith ("",["cell","raw"],kvs) $ B.rawBlock format'
              $ T.unpack source
     Ipynb.Code{ codeOutputs = outputs, codeExecutionCount = ec } -> do
-      outputBlocks <- mconcat <$> mapM (outputToBlock opts) outputs
+      outputBlocks <- mconcat <$> mapM outputToBlock outputs
       let kvs' = maybe kvs (\x -> ("execution_count", show x):kvs) ec
       return $ B.divWith ("",["cell","code"],kvs') $
         B.codeBlockWith ("",[lang],[]) (T.unpack source)
@@ -124,23 +126,23 @@
       insertMedia fp (Just $ T.unpack mimeType) (encode v)
     [] -> report $ CouldNotFetchResource fp "no attachment"
 
-outputToBlock :: PandocMonad m => ReaderOptions -> Output a -> m B.Blocks
-outputToBlock _ Stream{ streamName = sName,
-                        streamText = Source text } = do
+outputToBlock :: PandocMonad m => Output a -> m B.Blocks
+outputToBlock Stream{ streamName = sName,
+                      streamText = Source text } = do
   return $ B.divWith ("",["output","stream",T.unpack sName],[])
          $ B.codeBlock $ T.unpack . mconcat $ text
-outputToBlock opts DisplayData{ displayData = data',
-                                 displayMetadata = metadata' } =
+outputToBlock DisplayData{ displayData = data',
+                            displayMetadata = metadata' } =
   B.divWith ("",["output", "display_data"],[]) <$>
-    handleData opts metadata' data'
-outputToBlock opts ExecuteResult{ executeCount = ec,
-                                   executeData = data',
-                                   executeMetadata = metadata' } =
+    handleData metadata' data'
+outputToBlock ExecuteResult{ executeCount = ec,
+                              executeData = data',
+                              executeMetadata = metadata' } =
   B.divWith ("",["output", "execute_result"],[("execution_count",show ec)])
-    <$> handleData opts metadata' data'
-outputToBlock _ Err{ errName = ename,
-                     errValue = evalue,
-                     errTraceback = traceback } = do
+    <$> handleData metadata' data'
+outputToBlock Err{ errName = ename,
+                   errValue = evalue,
+                   errTraceback = traceback } = do
   return $ B.divWith ("",["output","error"],
                          [("ename",T.unpack ename),
                           ("evalue",T.unpack evalue)])
@@ -149,14 +151,12 @@
 -- We want to display the richest output possible given
 -- the output format.
 handleData :: PandocMonad m
-           => ReaderOptions -> JSONMeta -> MimeBundle -> m B.Blocks
-handleData opts metadata (MimeBundle mb) =
+           => JSONMeta -> MimeBundle -> m B.Blocks
+handleData metadata (MimeBundle mb) =
   mconcat <$> mapM dataBlock (M.toList mb)
 
   where
 
-    exts = readerExtensions opts
-
     dataBlock :: PandocMonad m => (MimeType, MimeData) -> m B.Blocks
     dataBlock (mt, BinaryData bs)
      | "image/" `T.isPrefixOf` mt
@@ -182,14 +182,10 @@
      | otherwise = return mempty
 
     dataBlock ("text/html", TextualData t)
-      | extensionEnabled Ext_raw_html exts
-        = return $ B.rawBlock "html" $ T.unpack t
-      | otherwise = return mempty
+      = return $ B.rawBlock "html" $ T.unpack t
 
     dataBlock ("text/latex", TextualData t)
-      | extensionEnabled Ext_raw_tex exts
-        = return $ B.rawBlock "latex" $ T.unpack t
-      | otherwise = return mempty
+      = return $ B.rawBlock "latex" $ T.unpack t
 
     dataBlock ("text/plain", TextualData t) =
       return $ B.codeBlock $ T.unpack t
@@ -217,10 +213,11 @@
     valueToMetaValue Aeson.Null = MetaString ""
 
 jsonMetaToPairs :: JSONMeta -> [(String, String)]
-jsonMetaToPairs = M.toList . M.mapMaybe
-     (\case
-        MetaString s -> Just s
-        MetaBool True -> Just "true"
-        MetaBool False -> Just "false"
-        -- for now we skip complex cell metadata:
-        _ -> Nothing) . jsonMetaToMeta
+jsonMetaToPairs = M.toList . M.mapKeys T.unpack . M.map
+  (\case
+      String t
+        | not (T.all isDigit t)
+        , t /= "true"
+        , t /= "false"
+                 -> T.unpack t
+      x          -> UTF8.toStringLazy $ Aeson.encode x)
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
@@ -866,6 +866,7 @@
   , ("slash", lit "/")
   , ("textbf", extractSpaces strong <$> tok)
   , ("textnormal", extractSpaces (spanWith ("",["nodecor"],[])) <$> tok)
+  , ("underline", underlineSpan <$> tok)
   , ("ldots", lit "…")
   , ("vdots", lit "\8942")
   , ("dots", lit "…")
@@ -1041,7 +1042,7 @@
   , ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
   , ("Autocite", citation "Autocite" NormalCitation False)
   , ("Smartcite", citation "Smartcite" NormalCitation False)
-  , ("Footcite", citation "Footcite" NormalCitation False)
+  , ("Footcite", inNote <$> citation "Footcite" NormalCitation False)
   , ("Parencite", citation "Parencite" NormalCitation False)
   , ("Supercite", citation "Supercite" NormalCitation False)
   , ("Footcitetext", inNote <$> citation "Footcitetext" NormalCitation False)
@@ -1054,7 +1055,7 @@
   , ("Textcites", citation "Textcites" AuthorInText True)
   , ("Cites", citation "Cites" NormalCitation True)
   , ("Autocites", citation "Autocites" NormalCitation True)
-  , ("Footcites", citation "Footcites" NormalCitation True)
+  , ("Footcites", inNote <$> citation "Footcites" NormalCitation True)
   , ("Parencites", citation "Parencites" NormalCitation True)
   , ("Supercites", citation "Supercites" NormalCitation True)
   , ("Footcitetexts", inNote <$> citation "Footcitetexts" NormalCitation True)
@@ -1122,6 +1123,10 @@
   , ("foreignlanguage", foreignlanguage)
   -- include
   , ("input", include "input")
+  -- soul package
+  , ("ul", underlineSpan <$> tok)
+  -- ulem package
+  , ("uline", underlineSpan <$> tok)
   -- plain tex stuff that should just be passed through as raw tex
   , ("ifdim", ifdim)
   ]
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -105,12 +105,12 @@
                   SpacingCombiningMark, EnclosingMark, ConnectorPunctuation))
 import Data.Data (Data, Typeable)
 import Data.List (find, intercalate, intersperse, stripPrefix, sortBy)
+import Data.Ord (comparing)
 import qualified Data.Map as M
 import Data.Maybe (mapMaybe)
 import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr)
 import qualified Data.Set as Set
 import qualified Data.Text as T
-import Data.Ord (comparing)
 import Data.Version (showVersion)
 import Network.URI (URI (uriScheme), escapeURIString, parseURI)
 import Paths_pandoc (version)
@@ -679,9 +679,13 @@
   where go (Div (ident, ("output":os), kvs) bs) =
           case mode of
             Nothing  -> Div (ident, ("output":os), kvs) []
-            Just fmt -> Div (ident, ("output":os), kvs) $
-              take 1 $ sortBy (comparing rank) bs
-                where
+            -- "best" for ipynb includes all formats:
+            Just fmt
+              | fmt == Format "ipynb"
+                          -> Div (ident, ("output":os), kvs) bs
+              | otherwise -> Div (ident, ("output":os), kvs) $
+                              take 1 $ sortBy (comparing rank) bs
+                 where
                   rank (RawBlock (Format "html") _)
                     | fmt == Format "html" = (1 :: Int)
                     | fmt == Format "markdown" = 2
@@ -693,6 +697,7 @@
                   rank (RawBlock f _)
                     | fmt == f = 1
                     | otherwise = 3
+                  rank (Para [Image{}]) = 1
                   rank _ = 2
         go x = x
 
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
@@ -465,7 +465,15 @@
   let numpath = "word/numbering.xml"
   numbering <- parseXml refArchive distArchive numpath
   newNumElts <- mkNumbering (stLists st)
-  let allElts = onlyElems (elContent numbering) ++ newNumElts
+  let pandocAdded e =
+       case findAttrBy ((== "abstractNumId") . qName) e >>= safeRead of
+         Just numid -> numid >= (990 :: Int)
+         Nothing    ->
+           case findAttrBy ((== "numId") . qName) e >>= safeRead of
+             Just numid -> numid >= (1000 :: Int)
+             Nothing    -> False
+  let oldElts = filter (not . pandocAdded) $ onlyElems (elContent numbering)
+  let allElts = oldElts ++ newNumElts
   let numEntry = toEntry numpath epochtime $ renderXml numbering{ elContent =
                        -- we want all the abstractNums first, then the nums,
                        -- otherwise things break:
diff --git a/src/Text/Pandoc/Writers/Ipynb.hs b/src/Text/Pandoc/Writers/Ipynb.hs
--- a/src/Text/Pandoc/Writers/Ipynb.hs
+++ b/src/Text/Pandoc/Writers/Ipynb.hs
@@ -208,14 +208,14 @@
        return (M.insert "text/html" (TextualData (T.pack raw)) mmap, meta)
     go (mmap, meta) (RawBlock (Format "latex") raw) =
        return (M.insert "text/latex" (TextualData (T.pack raw)) mmap, meta)
+    go (mmap, meta) (Div _ bs') = foldM go (mmap, meta) bs'
     go (mmap, meta) b = (mmap, meta) <$ report (BlockNotRendered b)
 
 pairsToJSONMeta :: [(String, String)] -> JSONMeta
 pairsToJSONMeta kvs =
-  M.fromList [(T.pack k, case v of
-                           "true"  -> Bool True
-                           "false" -> Bool False
-                           _       -> case safeRead v of
-                                        Just n -> Number n
-                                        _      -> String (T.pack v))
-             | (k,v) <- kvs , k /= "execution_count" ]
+  M.fromList [(T.pack k, case Aeson.decode (UTF8.fromStringLazy v) of
+                           Just val -> val
+                           Nothing  -> String (T.pack v))
+             | (k,v) <- kvs
+             , k /= "execution_count"
+             ]
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -63,7 +63,7 @@
               , stUrl           :: Bool          -- true if document has visible URL link
               , stGraphics      :: Bool          -- true if document contains images
               , stLHS           :: Bool          -- true if document has literate haskell code
-              , stBook          :: Bool          -- true if document uses book or memoir class
+              , stHasChapters   :: Bool          -- true if document has chapters
               , stCsquotes      :: Bool          -- true if document uses csquotes
               , stHighlighting  :: Bool          -- true if document has highlighted code
               , stIncremental   :: Bool          -- true if beamer lists should be displayed bit by bit
@@ -88,10 +88,10 @@
                 , stUrl = False
                 , stGraphics = False
                 , stLHS = False
-                , stBook = case writerTopLevelDivision options of
-                                TopLevelPart    -> True
-                                TopLevelChapter -> True
-                                _               -> False
+                , stHasChapters = case writerTopLevelDivision options of
+                                    TopLevelPart    -> True
+                                    TopLevelChapter -> True
+                                    _               -> False
                 , stCsquotes = False
                 , stHighlighting = False
                 , stIncremental = writerIncremental options
@@ -128,7 +128,6 @@
       isInternalLink _                     = []
   modify $ \s -> s{ stInternalLinks = query isInternalLink blocks' }
   let template = fromMaybe "" $ writerTemplate options
-  -- set stBook depending on documentclass
   let colwidth = if writerWrapText options == WrapAuto
                     then Just $ writerColumns options
                     else Nothing
@@ -138,17 +137,25 @@
               (fmap render' . blockListToLaTeX)
               (fmap render' . inlineListToLaTeX)
               meta
-  let bookClasses = ["memoir","book","report","scrreprt","scrbook"]
-  let documentClass = case P.parse pDocumentClass "template" template of
-                              Right r -> r
-                              Left _  -> ""
-  case lookup "documentclass" (writerVariables options) `mplus`
-        fmap stringify (lookupMeta "documentclass" meta) of
-         Just x  | x `elem` bookClasses -> modify $ \s -> s{stBook = True}
-                 | otherwise            -> return ()
-         Nothing | documentClass `elem` bookClasses
-                                        -> modify $ \s -> s{stBook = True}
-                 | otherwise               -> return ()
+  let chaptersClasses = ["memoir","book","report","scrreprt","scrbook","extreport","extbook","tufte-book"]
+  let frontmatterClasses = ["memoir","book","scrbook","extbook","tufte-book"]
+  -- these have \frontmatter etc.
+  beamer <- gets stBeamer
+  let documentClass =
+        case lookup "documentclass" (writerVariables options) `mplus`
+              fmap stringify (lookupMeta "documentclass" meta) of
+                 Just x -> x
+                 Nothing ->
+                  case P.parse pDocumentClass "template" template of
+                     Right r -> r
+                     Left _
+                      | beamer    -> "beamer"
+                      | otherwise -> case writerTopLevelDivision options of
+                                       TopLevelPart    -> "book"
+                                       TopLevelChapter -> "book"
+                                       _               -> "article"
+  when (documentClass `elem` chaptersClasses) $
+     modify $ \s -> s{ stHasChapters = True }
   -- check for \usepackage...{csquotes}; if present, we'll use
   -- \enquote{...} for smart quotes:
   let headerIncludesField :: FromJSON a => Maybe a
@@ -163,7 +170,6 @@
                                else case reverse blocks' of
                                  Header 1 _ il : _ -> (init blocks', il)
                                  _                 -> (blocks', [])
-  beamer <- gets stBeamer
   blocks''' <- if beamer
                   then toSlides blocks''
                   else return blocks''
@@ -197,17 +203,13 @@
 
   let context  =  defField "toc" (writerTableOfContents options) $
                   defField "toc-depth" (show (writerTOCDepth options -
-                                              if stBook st
+                                              if stHasChapters st
                                                  then 1
                                                  else 0)) $
                   defField "body" main $
                   defField "title-meta" titleMeta $
                   defField "author-meta" (intercalate "; " authorsMeta) $
-                  defField "documentclass" (if beamer
-                                               then ("beamer" :: String)
-                                               else if stBook st
-                                                    then "book"
-                                                    else "article") $
+                  defField "documentclass" documentClass $
                   defField "verbatim-in-note" (stVerbInNote st) $
                   defField "tables" (stTable st) $
                   defField "strikeout" (stStrikeout st) $
@@ -215,7 +217,8 @@
                   defField "numbersections" (writerNumberSections options) $
                   defField "lhs" (stLHS st) $
                   defField "graphics" (stGraphics st) $
-                  defField "book-class" (stBook st) $
+                  defField "has-chapters" (stHasChapters st) $
+                  defField "has-frontmatter" (documentClass `elem` frontmatterClasses) $
                   defField "listings" (writerListings options || stLHS st) $
                   defField "beamer" beamer $
                   (if stHighlighting st
@@ -991,7 +994,7 @@
                     else braces (text "\\texorpdfstring"
                          <> braces txt
                          <> braces (text plain))
-  book <- gets stBook
+  book <- gets stHasChapters
   opts <- gets stOptions
   let topLevelDivision = if book && writerTopLevelDivision opts == TopLevelDefault
                          then TopLevelChapter
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
@@ -444,30 +444,35 @@
     mdLines <- mapM (inlineListToMarkdown opts) lns
     return $ (vcat $ map (hang 2 (text "| ")) mdLines) <> blankline
   else blockToMarkdown opts $ linesToPara lns
-blockToMarkdown' opts b@(RawBlock f str)
-  | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
-              "markdown_mmd", "markdown_strict"]
-              = return $ text str <> text "\n"
-  | f `elem` ["html", "html5", "html4"] && isEnabled Ext_raw_html opts = do
-    plain <- asks envPlain
-    return $ if plain
-                then empty
-                else if isEnabled Ext_markdown_attribute opts
-                        then text (addMarkdownAttribute str) <> text "\n"
-                        else text str <> text "\n"
-  | f `elem` ["latex", "tex"] && isEnabled Ext_raw_tex opts = do
-    plain <- asks envPlain
-    return $ if plain
-                then empty
-                else text str <> text "\n"
-  | f == "plain" = do
-    plain <- asks envPlain
-    return $ if plain
-                then text str <> text "\n"
-                else empty
-  | otherwise = do
-      report $ BlockNotRendered b
-      return empty
+blockToMarkdown' opts b@(RawBlock f str) = do
+  plain <- asks envPlain
+  let Format fmt = f
+  let rawAttribBlock = return $
+         (text "```{=" <> text fmt <> "}") $$
+         text str $$
+         (text "```" <> text "\n")
+  let renderEmpty = mempty <$ report (BlockNotRendered b)
+  case () of
+    _ | plain -> renderEmpty
+      | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
+                  "markdown_mmd", "markdown_strict"] ->
+            return $ text str <> text "\n"
+      | f `elem` ["html", "html5", "html4"] ->
+            case () of
+              _ | isEnabled Ext_markdown_attribute opts -> return $
+                    text (addMarkdownAttribute str) <> text "\n"
+                | isEnabled Ext_raw_html opts -> return $
+                    text str <> text "\n"
+                | isEnabled Ext_raw_attribute opts -> rawAttribBlock
+                | otherwise -> renderEmpty
+      | f `elem` ["latex", "tex"] ->
+            case () of
+              _ | isEnabled Ext_raw_tex opts -> return $
+                    text str <> text "\n"
+                | isEnabled Ext_raw_attribute opts -> rawAttribBlock
+                | otherwise -> renderEmpty
+      | isEnabled Ext_raw_attribute opts -> rawAttribBlock
+      | otherwise -> renderEmpty
 blockToMarkdown' opts HorizontalRule = do
   return $ blankline <> text (replicate (writerColumns opts) '-') <> blankline
 blockToMarkdown' opts (Header level attr inlines) = do
@@ -1115,17 +1120,33 @@
         | otherwise -> (\x -> cr <> x <> cr) `fmap`
             (texMathToInlines DisplayMath str >>= inlineListToMarkdown opts)
 inlineToMarkdown opts il@(RawInline f str) = do
+  let tickGroups = filter (\s -> '`' `elem` s) $ group str
+  let numticks   = if null tickGroups
+                     then 1
+                     else 1 + maximum (map length tickGroups)
   plain <- asks envPlain
-  if (plain && f == "plain") || (not plain &&
-     ( f `elem` ["markdown", "markdown_github", "markdown_phpextra",
-                 "markdown_mmd", "markdown_strict"] ||
-       (isEnabled Ext_raw_tex opts && (f == "latex" || f == "tex")) ||
-       (isEnabled Ext_raw_html opts && f `elem` ["html", "html4", "html5"])
-     ))
-    then return $ text str
-    else do
-      report $ InlineNotRendered il
-      return empty
+  let Format fmt = f
+  let rawAttribInline = return $
+         text (replicate numticks '`') <> text str <>
+         text (replicate numticks '`') <> text "{=" <> text fmt <> text "}"
+  let renderEmpty = mempty <$ report (InlineNotRendered il)
+  case () of
+    _ | plain -> renderEmpty
+      | f `elem` ["markdown", "markdown_github", "markdown_phpextra",
+                  "markdown_mmd", "markdown_strict"] ->
+            return $ text str
+      | f `elem` ["html", "html5", "html4"] ->
+            case () of
+              _ | isEnabled Ext_raw_html opts -> return $ text str
+                | isEnabled Ext_raw_attribute opts -> rawAttribInline
+                | otherwise -> renderEmpty
+      | f `elem` ["latex", "tex"] ->
+            case () of
+              _ | isEnabled Ext_raw_tex opts -> return $ text str
+                | isEnabled Ext_raw_attribute opts -> rawAttribInline
+                | otherwise -> renderEmpty
+      | isEnabled Ext_raw_attribute opts -> rawAttribInline
+      | otherwise -> renderEmpty
 inlineToMarkdown opts (LineBreak) = do
   plain <- asks envPlain
   if plain || isEnabled Ext_hard_line_breaks opts
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -11,11 +11,12 @@
 packages:
 - '.'
 extra-deps:
-- pandoc-citeproc-0.16.1.1
+- pandoc-citeproc-0.16.1.3
 - skylighting-0.7.7
 - skylighting-core-0.7.7
 - ipynb-0.1
-- texmath-0.11.2.1
+- texmath-0.11.2.2
+- cmark-gfm-0.1.8
 ghc-options:
    "$locals": -fhide-source-paths -XNoImplicitPrelude
 resolver: lts-13.9
diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs
--- a/test/Tests/Old.hs
+++ b/test/Tests/Old.hs
@@ -192,9 +192,11 @@
       "org-select-tags.org" "org-select-tags.native"
     ]
   , testGroup "ipynb"
-    [ test' "reader" ["-f", "ipynb", "-t", "native", "-s"]
+    [ test' "reader" ["-f", "ipynb-raw_html-raw_tex+raw_attribute",
+                      "-t", "native", "-s"]
       "ipynb/simple.ipynb" "ipynb/simple.out.native"
-    , test' "writer" ["-f", "native", "-t", "ipynb", "-s"]
+    , test' "writer" ["-f", "native", "-t",
+                      "ipynb-raw_html-raw_tex+raw_attribute", "-s"]
       "ipynb/simple.in.native" "ipynb/simple.ipynb"
     ]
   ]
@@ -288,8 +290,7 @@
                                    Just d   -> [("DYLD_LIBRARY_PATH", d),
                                                 ("LD_LIBRARY_PATH", d)]
               let env = dynlibEnv ++
-                        [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"),
-                         ("pandoc_datadir","..")]
+                        [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./")]
               (ec, out) <- pipeProcess (Just env) pandocPath options mempty
               if ec == ExitSuccess
                  then return $ filter (/='\r') . normalizer
@@ -297,7 +298,7 @@
                    -- filter \r so the tests will work on Windows machines
                  else fail $ "Pandoc failed with error code " ++ show ec
         updateGolden = UTF8.writeFile norm
-        options = ["--quiet"] ++ [inp] ++ opts
+        options = ["--data-dir=../data","--quiet"] ++ [inp] ++ opts
 
 compareValues :: FilePath -> [String] -> String -> String -> IO (Maybe String)
 compareValues norm options expected actual = do
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/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/ipynb/simple.in.native b/test/ipynb/simple.in.native
--- a/test/ipynb/simple.in.native
+++ b/test/ipynb/simple.in.native
@@ -6,8 +6,10 @@
  [CodeBlock ("",["python"],[]) "print(\"hello\")"]
 ,Div ("",["cell","markdown"],[])
  [Header 2 ("pyout",[],[]) [Str "Pyout"]]
-,Div ("",["cell","code"],[])
- [CodeBlock ("",["python"],[]) "from IPython.display import HTML\nHTML(\"\"\"\n<script>\nconsole.log(\"hello\");\n</script>\n<b>HTML</b>\n\"\"\")"]
-,Div ("",["cell","markdown"],[])
+,Div ("",["cell","code"],[("execution_count","2")])
+ [CodeBlock ("",["python"],[]) "from IPython.display import HTML\nHTML(\"\"\"\n<script>\nconsole.log(\"hello\");\n</script>\n<b>HTML</b>\n\"\"\")"
+ ,Div ("",["output","execute_result"],[("execution_count","2")])
+  [RawBlock (Format "html") "<script>\nconsole.log(\"hello\");\n</script>\n<b>HTML</b>\nhello"]]
+,Div ("",["cell","markdown"],[("tags","[\"foo\",\"bar\"]")])
  [Header 2 ("image",[],[]) [Str "Image"]
  ,Para [Str "This",Space,Str "image",Space,Image ("",[],[]) [Str "the",Space,Str "moon"] ("lalune.jpg",""),Space,Str "will",Space,Str "be",Space,Str "included",Space,Str "as",Space,Str "a",Space,Str "cell",SoftBreak,Str "attachment."]]]
diff --git a/test/ipynb/simple.ipynb b/test/ipynb/simple.ipynb
--- a/test/ipynb/simple.ipynb
+++ b/test/ipynb/simple.ipynb
@@ -30,9 +30,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "execution_count": 2,
+     "metadata": {},
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "console.log(\"hello\");\n",
+       "</script>\n",
+       "<b>HTML</b>\n",
+       "hello"
+      ]
+     }
+    }
+   ],
    "source": [
     "from IPython.display import HTML\n",
     "HTML(\"\"\"\n",
@@ -45,7 +60,12 @@
   },
   {
    "cell_type": "markdown",
-   "metadata": {},
+   "metadata": {
+    "tags": [
+     "foo",
+     "bar"
+    ]
+   },
    "source": [
     "Image\n",
     "-----\n",
diff --git a/test/ipynb/simple.out.native b/test/ipynb/simple.out.native
--- a/test/ipynb/simple.out.native
+++ b/test/ipynb/simple.out.native
@@ -6,8 +6,10 @@
  [CodeBlock ("",["python"],[]) "print(\"hello\")"]
 ,Div ("",["cell","markdown"],[])
  [Header 2 ("pyout",[],[]) [Str "Pyout"]]
-,Div ("",["cell","code"],[])
- [CodeBlock ("",["python"],[]) "from IPython.display import HTML\nHTML(\"\"\"\n<script>\nconsole.log(\"hello\");\n</script>\n<b>HTML</b>\n\"\"\")"]
-,Div ("",["cell","markdown"],[])
+,Div ("",["cell","code"],[("execution_count","2")])
+ [CodeBlock ("",["python"],[]) "from IPython.display import HTML\nHTML(\"\"\"\n<script>\nconsole.log(\"hello\");\n</script>\n<b>HTML</b>\n\"\"\")"
+ ,Div ("",["output","execute_result"],[("execution_count","2")])
+  [RawBlock (Format "html") "<script>\nconsole.log(\"hello\");\n</script>\n<b>HTML</b>\nhello"]]
+,Div ("",["cell","markdown"],[("tags","[\"foo\",\"bar\"]")])
  [Header 2 ("image",[],[]) [Str "Image"]
  ,Para [Str "This",Space,Str "image",Space,Image ("",[],[]) [Str "the",Space,Str "moon"] ("lalune.jpg",""),Space,Str "will",Space,Str "be",Space,Str "included",Space,Str "as",Space,Str "a",Space,Str "cell",SoftBreak,Str "attachment."]]]
diff --git a/test/latex-reader.latex b/test/latex-reader.latex
--- a/test/latex-reader.latex
+++ b/test/latex-reader.latex
@@ -1,23 +1,18 @@
 \documentclass{article}
-\usepackage[mathletters]{ucs}
 \usepackage[utf8x]{inputenc}
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
 
-\usepackage[breaklinks=true,unicode=true]{hyperref}
+\usepackage{hyperref}
 \usepackage[normalem]{ulem}
-% avoid problems with \sout in headers with hyperref:
-\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
 \usepackage{enumerate}
+\usepackage{setspace}
 \usepackage{fancyvrb}
 \usepackage{graphicx}
-\usepackage{url}
-
-\setcounter{secnumdepth}{0}
 \VerbatimFootnotes % allows verbatim text in footnotes
+
 \title{Pandoc Test Suite}
 \author{John MacFarlane \and Anonymous}
 \date{July 17, 2006}
+
 \begin{document}
 \maketitle
 
diff --git a/test/lhs-test.latex b/test/lhs-test.latex
--- a/test/lhs-test.latex
+++ b/test/lhs-test.latex
@@ -1,4 +1,5 @@
-\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode=true}{hyperref}
 \PassOptionsToPackage{hyphens}{url}
 %
 \documentclass[
@@ -15,7 +16,7 @@
   \defaultfontfeatures{Scale=MatchLowercase}
   \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
 \fi
-% use upquote if available, for straight quotes in verbatim environments
+% Use upquote if available, for straight quotes in verbatim environments
 \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
 \IfFileExists{microtype.sty}{% use microtype if available
   \usepackage[]{microtype}
@@ -35,9 +36,9 @@
 \IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
 \IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
 \hypersetup{
-  pdfborder={0 0 0},
-  breaklinks=true}
-\urlstyle{same}  % don't use monospace font for urls
+  hidelinks,
+}
+\urlstyle{same} % disable monospaced font for URLs
 \usepackage{color}
 \usepackage{fancyvrb}
 \newcommand{\VerbBar}{|}
@@ -76,10 +77,10 @@
 \newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}}
 \newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}}
 \newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}}
-\setlength{\emergencystretch}{3em}  % prevent overfull lines
+\setlength{\emergencystretch}{3em} % prevent overfull lines
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{-2}
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
 % Redefines (sub)paragraphs to behave more like sections
 \ifx\paragraph\undefined\else
   \let\oldparagraph\paragraph
@@ -90,7 +91,7 @@
   \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
 \fi
 
-% set default figure placement to htbp
+% Set default figure placement to htbp
 \makeatletter
 \def\fps@figure{htbp}
 \makeatother
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
@@ -1,4 +1,5 @@
-\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode=true}{hyperref}
 \PassOptionsToPackage{hyphens}{url}
 %
 \documentclass[
@@ -15,7 +16,7 @@
   \defaultfontfeatures{Scale=MatchLowercase}
   \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
 \fi
-% use upquote if available, for straight quotes in verbatim environments
+% Use upquote if available, for straight quotes in verbatim environments
 \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
 \IfFileExists{microtype.sty}{% use microtype if available
   \usepackage[]{microtype}
@@ -35,18 +36,18 @@
 \IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
 \IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
 \hypersetup{
-  pdfborder={0 0 0},
-  breaklinks=true}
-\urlstyle{same}  % don't use monospace font for urls
+  hidelinks,
+}
+\urlstyle{same} % disable monospaced font for URLs
 \usepackage{listings}
 \newcommand{\passthrough}[1]{#1}
 \lstset{defaultdialect=[5.3]Lua}
 \lstset{defaultdialect=[x86masm]Assembler}
 \lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
-\setlength{\emergencystretch}{3em}  % prevent overfull lines
+\setlength{\emergencystretch}{3em} % prevent overfull lines
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{-2}
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
 % Redefines (sub)paragraphs to behave more like sections
 \ifx\paragraph\undefined\else
   \let\oldparagraph\paragraph
@@ -57,7 +58,7 @@
   \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
 \fi
 
-% set default figure placement to htbp
+% Set default figure placement to htbp
 \makeatletter
 \def\fps@figure{htbp}
 \makeatother
diff --git a/test/writer.latex b/test/writer.latex
--- a/test/writer.latex
+++ b/test/writer.latex
@@ -1,4 +1,5 @@
-\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode=true}{hyperref}
 \PassOptionsToPackage{hyphens}{url}
 %
 \documentclass[
@@ -15,7 +16,7 @@
   \defaultfontfeatures{Scale=MatchLowercase}
   \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
 \fi
-% use upquote if available, for straight quotes in verbatim environments
+% Use upquote if available, for straight quotes in verbatim environments
 \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
 \IfFileExists{microtype.sty}{% use microtype if available
   \usepackage[]{microtype}
@@ -38,9 +39,9 @@
 \hypersetup{
   pdftitle={Pandoc Test Suite},
   pdfauthor={John MacFarlane; Anonymous},
-  pdfborder={0 0 0},
-  breaklinks=true}
-\urlstyle{same}  % don't use monospace font for urls
+  hidelinks,
+}
+\urlstyle{same} % disable monospaced font for URLs
 \VerbatimFootnotes % allows verbatim text in footnotes
 \usepackage{graphicx,grffile}
 \makeatletter
@@ -52,12 +53,12 @@
 % using explicit options in \includegraphics[width, height, ...]{}
 \setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
 \usepackage[normalem]{ulem}
-% avoid problems with \sout in headers with hyperref:
+% Avoid problems with \sout in headers with hyperref
 \pdfstringdefDisableCommands{\renewcommand{\sout}{}}
-\setlength{\emergencystretch}{3em}  % prevent overfull lines
+\setlength{\emergencystretch}{3em} % prevent overfull lines
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{-2}
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
 % Redefines (sub)paragraphs to behave more like sections
 \ifx\paragraph\undefined\else
   \let\oldparagraph\paragraph
@@ -68,7 +69,7 @@
   \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
 \fi
 
-% set default figure placement to htbp
+% Set default figure placement to htbp
 \makeatletter
 \def\fps@figure{htbp}
 \makeatother
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
@@ -1,4 +1,5 @@
-\PassOptionsToPackage{unicode=true}{hyperref} % options for packages loaded elsewhere
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode=true}{hyperref}
 \PassOptionsToPackage{hyphens}{url}
 %
 \documentclass[
@@ -16,7 +17,7 @@
   \defaultfontfeatures{Scale=MatchLowercase}
   \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
 \fi
-% use upquote if available, for straight quotes in verbatim environments
+% Use upquote if available, for straight quotes in verbatim environments
 \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
 \IfFileExists{microtype.sty}{% use microtype if available
   \usepackage[]{microtype}
@@ -36,13 +37,13 @@
 \IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
 \IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
 \hypersetup{
-  pdfborder={0 0 0},
-  breaklinks=true}
-\urlstyle{same}  % don't use monospace font for urls
-\setlength{\emergencystretch}{3em}  % prevent overfull lines
+  hidelinks,
+}
+\urlstyle{same} % disable monospaced font for URLs
+\setlength{\emergencystretch}{3em} % prevent overfull lines
 \providecommand{\tightlist}{%
   \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
-\setcounter{secnumdepth}{-2}
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
 % Redefines (sub)paragraphs to behave more like sections
 \ifx\paragraph\undefined\else
   \let\oldparagraph\paragraph
@@ -53,12 +54,21 @@
   \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
 \fi
 
-% set default figure placement to htbp
+% Set default figure placement to htbp
 \makeatletter
 \def\fps@figure{htbp}
 \makeatother
 
-\ifnum 0\ifxetex 1\fi=0 % if pdftex or luatex
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
+  \usepackage{polyglossia}
+  \setmainlanguage[]{english}
+  \setotherlanguage[]{german}
+  \setotherlanguage[variant=british]{english}
+  \setotherlanguage[variant=swiss]{german}
+  \setotherlanguage[]{spanish}
+  \setotherlanguage[]{french}
+\else
   \usepackage[shorthands=off,ngerman,british,nswissgerman,spanish,french,main=english]{babel}
   \newcommand{\textgerman}[2][]{\foreignlanguage{ngerman}{#2}}
   \newenvironment{german}[2][]{\begin{otherlanguage}{ngerman}}{\end{otherlanguage}}
@@ -69,18 +79,9 @@
   \AddBabelHook{spanish}{afterextras}{\renewcommand{\textspanish}[2][]{\foreignlanguage{spanish}{##2}}}
   \newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
   \newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
-\else % if xetex
-  % load polyglossia as late as possible as it *could* call bidi if RTL lang (e.g. Hebrew or Arabic)
-  \usepackage{polyglossia}
-  \setmainlanguage[]{english}
-  \setotherlanguage[]{german}
-  \setotherlanguage[variant=british]{english}
-  \setotherlanguage[variant=swiss]{german}
-  \setotherlanguage[]{spanish}
-  \setotherlanguage[]{french}
 \fi
 \ifxetex
-  % load bidi as late as possible as it modifies e.g. graphicx
+  % Load bidi as late as possible as it modifies e.g. graphicx
   \usepackage{bidi}
 \fi
 \ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
