djot (empty) → 0.1.0.0
raw patch · 40 files changed
+14303/−0 lines, 40 filesdep +basedep +bytestringdep +containers
Dependencies added: base, bytestring, containers, directory, djot, doclayout, filepath, mtl, tasty, tasty-bench, tasty-hunit, tasty-quickcheck, text
Files
- CHANGELOG.md +6/−0
- LICENSE +20/−0
- app/Main.hs +97/−0
- benchmark/Main.hs +49/−0
- benchmark/m.dj +7523/−0
- djot.cabal +88/−0
- src/Djot.hs +17/−0
- src/Djot/AST.hs +445/−0
- src/Djot/Attributes.hs +187/−0
- src/Djot/Blocks.hs +1138/−0
- src/Djot/Djot.hs +477/−0
- src/Djot/Html.hs +350/−0
- src/Djot/Inlines.hs +525/−0
- src/Djot/Options.hs +25/−0
- src/Djot/Parse.hs +400/−0
- test/Main.hs +163/−0
- test/attributes.test +322/−0
- test/block_quote.test +154/−0
- test/code_blocks.test +65/−0
- test/definition_lists.test +95/−0
- test/emphasis.test +239/−0
- test/escapes.test +54/−0
- test/fenced_divs.test +134/−0
- test/footnotes.test +92/−0
- test/headings.test +182/−0
- test/insert_delete_mark.test +29/−0
- test/links_and_images.test +242/−0
- test/lists.test +510/−0
- test/math.test +44/−0
- test/para.test +7/−0
- test/raw.test +38/−0
- test/regression.test +93/−0
- test/smart.test +192/−0
- test/spans.test +19/−0
- test/super_subscript.test +23/−0
- test/symb.test +11/−0
- test/tables.test +125/−0
- test/task_lists.test +31/−0
- test/thematic_breaks.test +45/−0
- test/verbatim.test +47/−0
+ CHANGELOG.md view
@@ -0,0 +1,6 @@+# Revision history for djot++## 0.1.0.0 -- 2024-02-14++* Initial release.+
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2023 John MacFarlane++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ app/Main.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE Strict #-}+module Main where++import qualified Data.ByteString as B+import Data.ByteString.Builder (hPutBuilder)+import Djot ( ParseOptions(..), RenderOptions(..), SourcePosOption(..),+ parseDoc, renderHtml, renderDjot )+import System.Environment (getArgs)+import System.IO (stderr, stdout, hPutStrLn)+import System.Exit ( ExitCode(ExitFailure), exitWith, exitSuccess )+import Text.DocLayout (render)+import Text.Read (readMaybe)+import qualified Data.Text.IO as TIO++data OutputFormat = Html | Djot | Ast+ deriving (Eq, Show)++data WrapOption = Auto | Preserve | NoWrap+ deriving (Eq, Show)++data Opts =+ Opts{ format :: OutputFormat+ , files :: [FilePath]+ , wrap :: WrapOption+ , columns :: Int+ , sourcePos :: SourcePosOption }++parseOpts :: [String] -> IO Opts+parseOpts = go Opts{ format = Html, files = [], wrap = Preserve, columns = 72,+ sourcePos = NoSourcePos }+ where+ go opts [] = pure opts+ go opts ("--wrap" : as) =+ case as of+ "auto" : as' -> go opts{ wrap = Auto } as'+ "preserve" : as' -> go opts{ wrap = Preserve } as'+ "none" : as' -> go opts{ wrap = NoWrap } as'+ _ -> err "--wrap must be followed by auto, preserve, or none"+ go opts ("--columns" : as) =+ case as of+ (a:as') | Just n <- readMaybe a+ -> go opts{ columns = n } as'+ _ -> err "--columns must be followed by a number"+ go opts ("--to" : as) =+ case as of+ "djot" : as' -> go opts{ format = Djot } as'+ "html" : as' -> go opts{ format = Html } as'+ "ast" : as' -> go opts{ format = Ast } as'+ _ -> err "--to must be followed by djot, html, or ast"+ go opts ("--sourcepos" : as) =+ case as of+ ("none":as') -> go opts{ sourcePos = NoSourcePos } as'+ ("block":as') -> go opts{ sourcePos = BlockSourcePos } as'+ ("all":as') -> go opts{ sourcePos = AllSourcePos } as'+ _ -> err "--sourcepos takes an argument (none|block|all)"+ go _opts ("--help" : _) = do+ putStrLn "djoths [options] [files]"+ putStrLn " --to djot|html*|ast"+ putStrLn " --wrap auto|preserve*|none"+ putStrLn " --columns NUMBER"+ putStrLn " --sourcepos none*|block|all"+ putStrLn " --help"+ exitSuccess+ go opts (xs@('-':_) : as) =+ case break (== '=') xs of -- support e.g. '--columns=33'+ (ys, '=':zs) -> go opts (ys : zs : as)+ _ -> err $ "Unknown option " <> ('-':xs)+ go opts (f : as) = go opts{ files = files opts ++ [f] } as++err :: String -> IO a+err msg = do+ hPutStrLn stderr msg+ exitWith $ ExitFailure 1++main :: IO ()+main = do+ opts <- getArgs >>= parseOpts+ bs <- case files opts of+ [] -> B.getContents+ fs -> mconcat <$> mapM B.readFile fs+ let popts = ParseOptions { sourcePositions = sourcePos opts }+ let ropts = RenderOptions { preserveSoftBreaks = wrap opts == Preserve }+ case parseDoc popts bs of+ Right doc -> do+ case format opts of+ Html -> hPutBuilder stdout $ renderHtml ropts doc+ Djot -> TIO.putStr $ render (case wrap opts of+ NoWrap -> Nothing+ Preserve -> Nothing+ Auto -> Just (columns opts))+ $ renderDjot ropts doc+ Ast -> print doc+ exitSuccess+ Left e -> do+ hPutStrLn stderr e+ exitWith $ ExitFailure 1
+ benchmark/Main.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE Strict #-}+import Test.Tasty.Bench+import Data.Functor.Identity -- base >= 4.8+import qualified Data.ByteString as B+import Djot ( ParseOptions(..), RenderOptions(..), SourcePosOption(..),+ parseDoc, renderHtml, renderDjot )+import Data.ByteString.Builder ( toLazyByteString )+import Text.DocLayout (render)+import System.Directory+import System.FilePath (takeExtension, (</>))+import qualified Data.ByteString.Lazy as BL++main :: IO ()+main = do+ fns <- filter ((== ".dj") . takeExtension) <$> listDirectory "benchmark"+ files <- mapM (\fn -> (fn,) <$> B.readFile ("benchmark" </> fn)) fns+ defaultMain $+ map (\(fn, bs) ->+ bench ("parse " <> fn) $+ whnf (parseDoc ParseOptions{ sourcePositions = NoSourcePos }) bs)+ files+ +++ map (\(fn, bs) ->+ bench ("parse w/ block source positions only " <> fn) $+ whnf (parseDoc ParseOptions{ sourcePositions = BlockSourcePos }) bs)+ files+ +++ map (\(fn, bs) ->+ bench ("parse w/ source positions " <> fn) $+ whnf (parseDoc ParseOptions{ sourcePositions = AllSourcePos }) bs)+ files+ +++ map (\(fn, bs) ->+ let doc = either error id $ parseDoc ParseOptions{ sourcePositions = NoSourcePos } bs+ in bench ("renderHtml " <> fn) $+ nf (BL.toStrict . toLazyByteString .+ renderHtml RenderOptions{preserveSoftBreaks = True}) doc)+ files+ +++ map (\(fn, bs) ->+ let doc = either error id $ parseDoc ParseOptions{ sourcePositions = NoSourcePos } bs+ in bench ("renderDjot " <> fn) $+ nf (render (Just 72) .+ renderDjot RenderOptions{preserveSoftBreaks = True}) doc)+ files
+ benchmark/m.dj view
@@ -0,0 +1,7523 @@+{#synopsis}+# Synopsis++`pandoc` \[_options_\] \[_input-file_\]…++{#description}+# Description++Pandoc is a [Haskell](https://www.haskell.org) library for converting+from one markup format to another, and a command-line tool that uses+this library.++Pandoc can convert between numerous markup and word processing formats,+including, but not limited to, various flavors of+[Markdown](https://daringfireball.net/projects/markdown/),+[HTML](https://www.w3.org/html/),+[LaTeX](https://www.latex-project.org/) and [Word+docx](https://en.wikipedia.org/wiki/Office_Open_XML). For the full lists+of input and output formats, see the `--from` and `--to` [options+below](#general-options). Pandoc can also produce+[PDF](https://www.adobe.com/pdf/) output: see [creating a+PDF](#creating-a-pdf), below.++Pandoc’s enhanced version of Markdown includes syntax for+[tables](#tables), [definition lists](#definition-lists), [metadata+blocks](#metadata-blocks), [footnotes](#footnotes),+[citations](#citations), [math](#math), and much more. See below under+[Pandoc’s Markdown](#pandocs-markdown).++Pandoc has a modular design: it consists of a set of readers, which+parse text in a given format and produce a native representation of the+document (an _abstract syntax tree_ or AST), and a set of writers, which+convert this native representation into a target format. Thus, adding an+input or output format requires only adding a reader or writer. Users+can also run custom [pandoc filters](https://pandoc.org/filters.html) to+modify the intermediate AST.++Because pandoc’s intermediate representation of a document is less+expressive than many of the formats it converts between, one should not+expect perfect conversions between every format and every other. Pandoc+attempts to preserve the structural elements of a document, but not+formatting details such as margin size. And some document elements, such+as complex tables, may not fit into pandoc’s simple document model.+While conversions from pandoc’s Markdown to all formats aspire to be+perfect, conversions from formats more expressive than pandoc’s Markdown+can be expected to be lossy.++{#using-pandoc}+## Using pandoc++If no _input-files_ are specified, input is read from _stdin_. Output+goes to _stdout_ by default. For output to a file, use the `-o` option:++```+pandoc -o output.html input.txt+```++By default, pandoc produces a document fragment. To produce a standalone+document (e.g. a valid HTML file including `<head>` and `<body>`), use+the `-s` or `--standalone` flag:++```+pandoc -s -o output.html input.txt+```++For more information on how standalone documents are produced, see+[Templates](#templates) below.++If multiple input files are given, pandoc will concatenate them all+(with blank lines between them) before parsing. (Use `--file-scope` to+parse files individually.)++{#specifying-formats}+## Specifying formats++The format of the input and output can be specified explicitly using+command-line options. The input format can be specified using the+`-f/--from` option, the output format using the `-t/--to` option. Thus,+to convert `hello.txt` from Markdown to LaTeX, you could type:++```+pandoc -f markdown -t latex hello.txt+```++To convert `hello.html` from HTML to Markdown:++```+pandoc -f html -t markdown hello.html+```++Supported input and output formats are listed below under+[Options](#options) (see `-f` for input formats and `-t` for output+formats). You can also use `pandoc --list-input-formats` and+`pandoc --list-output-formats` to print lists of supported formats.++If the input or output format is not specified explicitly, pandoc will+attempt to guess it from the extensions of the filenames. Thus, for+example,++```+pandoc -o hello.tex hello.txt+```++will convert `hello.txt` from Markdown to LaTeX. If no output file is+specified (so that output goes to _stdout_), or if the output file’s+extension is unknown, the output format will default to HTML. If no+input file is specified (so that input comes from _stdin_), or if the+input files’ extensions are unknown, the input format will be assumed to+be Markdown.++{#character-encoding}+## Character encoding++Pandoc uses the UTF-8 character encoding for both input and output. If+your local character encoding is not UTF-8, you should pipe input and+output through [`iconv`](https://www.gnu.org/software/libiconv/):++```+iconv -t utf-8 input.txt | pandoc | iconv -f utf-8+```++Note that in some output formats (such as HTML, LaTeX, ConTeXt, RTF,+OPML, DocBook, and Texinfo), information about the character encoding is+included in the document header, which will only be included if you use+the `-s/--standalone` option.++{#creating-a-pdf}+## Creating a PDF++To produce a PDF, specify an output file with a `.pdf` extension:++```+pandoc test.txt -o test.pdf+```++By default, pandoc will use LaTeX to create the PDF, which requires that+a LaTeX engine be installed (see `--pdf-engine` below). Alternatively,+pandoc can use ConTeXt, roff ms, or HTML as an intermediate format. To+do this, specify an output file with a `.pdf` extension, as before, but+add the `--pdf-engine` option or `-t context`, `-t html`, or `-t ms` to+the command line. The tool used to generate the PDF from the+intermediate format may be specified using `--pdf-engine`.++You can control the PDF style using variables, depending on the+intermediate format used: see [variables for+LaTeX](#variables-for-latex), [variables for+ConTeXt](#variables-for-context), [variables for+`wkhtmltopdf`](#variables-for-wkhtmltopdf), [variables for+ms](#variables-for-ms). When HTML is used as an intermediate format, the+output can be styled using `--css`.++To debug the PDF creation, it can be useful to look at the intermediate+representation: instead of `-o test.pdf`, use for example+`-s -o test.tex` to output the generated LaTeX. You can then test it+with `pdflatex test.tex`.++When using LaTeX, the following packages need to be available (they are+included with all recent versions of [TeX+Live](https://www.tug.org/texlive/)):+[`amsfonts`](https://ctan.org/pkg/amsfonts),+[`amsmath`](https://ctan.org/pkg/amsmath),+[`lm`](https://ctan.org/pkg/lm),+[`unicode-math`](https://ctan.org/pkg/unicode-math),+[`iftex`](https://ctan.org/pkg/iftex),+[`listings`](https://ctan.org/pkg/listings) (if the `--listings` option+is used), [`fancyvrb`](https://ctan.org/pkg/fancyvrb),+[`longtable`](https://ctan.org/pkg/longtable),+[`booktabs`](https://ctan.org/pkg/booktabs),+[`graphicx`](https://ctan.org/pkg/graphicx) (if the document contains+images), [`hyperref`](https://ctan.org/pkg/hyperref),+[`xcolor`](https://ctan.org/pkg/xcolor),+[`soul`](https://ctan.org/pkg/soul),+[`geometry`](https://ctan.org/pkg/geometry) (with the `geometry`+variable set), [`setspace`](https://ctan.org/pkg/setspace) (with+`linestretch`), and [`babel`](https://ctan.org/pkg/babel) (with `lang`).+If `CJKmainfont` is set, [`xeCJK`](https://ctan.org/pkg/xecjk) is+needed. The use of `xelatex` or `lualatex` as the PDF engine requires+[`fontspec`](https://ctan.org/pkg/fontspec). `lualatex` uses+[`selnolig`](https://ctan.org/pkg/selnolig). `xelatex` uses+[`bidi`](https://ctan.org/pkg/bidi) (with the `dir` variable set). If+the `mathspec` variable is set, `xelatex` will use+[`mathspec`](https://ctan.org/pkg/mathspec) instead of+[`unicode-math`](https://ctan.org/pkg/unicode-math). The+[`upquote`](https://ctan.org/pkg/upquote) and+[`microtype`](https://ctan.org/pkg/microtype) packages are used if+available, and [`csquotes`](https://ctan.org/pkg/csquotes) will be used+for [typography](#typography) if the `csquotes` variable or metadata+field is set to a true value. The+[`natbib`](https://ctan.org/pkg/natbib),+[`biblatex`](https://ctan.org/pkg/biblatex),+[`bibtex`](https://ctan.org/pkg/bibtex), and+[`biber`](https://ctan.org/pkg/biber) packages can optionally be used+for [citation rendering](#citation-rendering). The following packages+will be used to improve output quality if present, but pandoc does not+require them to be present: [`upquote`](https://ctan.org/pkg/upquote)+(for straight quotes in verbatim environments),+[`microtype`](https://ctan.org/pkg/microtype) (for better spacing+adjustments), [`parskip`](https://ctan.org/pkg/parskip) (for better+inter-paragraph spaces), [`xurl`](https://ctan.org/pkg/xurl) (for better+line breaks in URLs), [`bookmark`](https://ctan.org/pkg/bookmark) (for+better PDF bookmarks), and+[`footnotehyper`](https://ctan.org/pkg/footnotehyper) or+[`footnote`](https://ctan.org/pkg/footnote) (to allow footnotes in+tables).++{#reading-from-the-web}+## Reading from the Web++Instead of an input file, an absolute URI may be given. In this case+pandoc will fetch the content using HTTP:++```+pandoc -f html -t markdown https://www.fsf.org+```++It is possible to supply a custom User-Agent string or other header when+requesting a document from a URL:++```+pandoc -f html -t markdown --request-header User-Agent:"Mozilla/5.0" \+ https://www.fsf.org+```++{#options}+# Options++{#general-options .options}+## General options++: `-f` _FORMAT_, `-r` _FORMAT_, `--from=`_FORMAT_, `--read=`_FORMAT_++ Specify input format. _FORMAT_ can be:++ {#input-formats}+ :::+ - `bibtex` ([BibTeX](https://ctan.org/pkg/bibtex) bibliography)+ - `biblatex` ([BibLaTeX](https://ctan.org/pkg/biblatex) bibliography)+ - `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))+ - `csljson` ([CSL+ JSON](https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html)+ bibliography)+ - `csv` ([CSV](https://tools.ietf.org/html/rfc4180) table)+ - `tsv`+ ([TSV](https://www.iana.org/assignments/media-types/text/tab-separated-values)+ 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))+ - `endnotexml` ([EndNote XML+ bibliography](https://support.clarivate.com/Endnote/s/article/EndNote-XML-Document-Type-Definition))+ - `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+ Markdown](https://help.github.com/articles/github-flavored-markdown/)),+ or the deprecated and less accurate `markdown_github`; use+ [`markdown_github`](#markdown-variants) only if you need extensions+ not supported in [`gfm`](#markdown-variants).+ - `haddock` ([Haddock+ markup](https://www.haskell.org/haddock/doc/html/ch03s08.html))+ - `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`+ ([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 Markdown](#pandocs-markdown))+ - `markdown_mmd`+ ([MultiMarkdown](https://fletcherpenney.net/multimarkdown/))+ - `markdown_phpextra` ([PHP Markdown+ Extra](https://michelf.ca/projects/php-markdown/extra/))+ - `markdown_strict` (original unextended+ [Markdown](https://daringfireball.net/projects/markdown/))+ - `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))+ - `ris` ([RIS](https://en.wikipedia.org/wiki/RIS_(file_format))+ bibliography)+ - `rtf` ([Rich Text+ Format](https://en.wikipedia.org/wiki/Rich_Text_Format))+ - `rst`+ ([reStructuredText](https://docutils.sourceforge.io/docs/ref/rst/introduction.html))+ - `t2t` ([txt2tags](https://txt2tags.org))+ - `textile` ([Textile](https://textile-lang.com))+ - `tikiwiki` ([TikiWiki+ markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax))+ - `twiki` ([TWiki+ markup](https://twiki.org/cgi-bin/view/TWiki/TextFormattingRules))+ - `typst` ([typst](https://typst.app))+ - `vimwiki` ([Vimwiki](https://vimwiki.github.io))+ - the path of a custom Lua reader, see [Custom readers and+ writers](#custom-readers-and-writers) below+ :::++ Extensions can be individually enabled or disabled by appending+ `+EXTENSION` or `-EXTENSION` to the format name. See+ [Extensions](#extensions) below, for a list of extensions and their+ names. See `--list-input-formats` and `--list-extensions`, below.+: `-t` _FORMAT_, `-w` _FORMAT_, `--to=`_FORMAT_, `--write=`_FORMAT_++ Specify output format. _FORMAT_ can be:++ {#output-formats}+ :::+ - `asciidoc` (modern [AsciiDoc](https://www.methods.co.nz/asciidoc/)+ as interpreted by [AsciiDoctor](https://asciidoctor.org/))+ - `asciidoc_legacy` ([AsciiDoc](https://www.methods.co.nz/asciidoc/)+ as interpreted by+ [`asciidoc-py`](https://github.com/asciidoc-py/asciidoc-py)).+ - `asciidoctor` (deprecated synonym for `asciidoc`)+ - `beamer` ([LaTeX beamer](https://ctan.org/pkg/beamer) slide show)+ - `bibtex` ([BibTeX](https://ctan.org/pkg/bibtex) bibliography)+ - `biblatex` ([BibLaTeX](https://ctan.org/pkg/biblatex) bibliography)+ - `chunkedhtml` (zip archive of multiple linked HTML files)+ - `commonmark` ([CommonMark](https://commonmark.org) Markdown)+ - `commonmark_x` ([CommonMark](https://commonmark.org) Markdown with+ extensions)+ - `context` ([ConTeXt](https://www.contextgarden.net/))+ - `csljson` ([CSL+ JSON](https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html)+ bibliography)+ - `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+ Markdown](https://help.github.com/articles/github-flavored-markdown/)),+ or the deprecated and less accurate `markdown_github`; use+ [`markdown_github`](#markdown-variants) only if you need extensions+ not supported in [`gfm`](#markdown-variants).+ - `haddock` ([Haddock+ markup](https://www.haskell.org/haddock/doc/html/ch03s08.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+ ICML](https://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf))+ - `ipynb` ([Jupyter+ notebook](https://nbformat.readthedocs.io/en/latest/))+ - `jats_archiving` ([JATS](https://jats.nlm.nih.gov) XML, Archiving+ and Interchange Tag Set)+ - `jats_articleauthoring` ([JATS](https://jats.nlm.nih.gov) XML,+ Article Authoring Tag Set)+ - `jats_publishing` ([JATS](https://jats.nlm.nih.gov) XML, Journal+ Publishing Tag Set)+ - `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 Markdown](#pandocs-markdown))+ - `markdown_mmd`+ ([MultiMarkdown](https://fletcherpenney.net/multimarkdown/))+ - `markdown_phpextra` ([PHP Markdown+ Extra](https://michelf.ca/projects/php-markdown/extra/))+ - `markdown_strict` (original unextended+ [Markdown](https://daringfireball.net/projects/markdown/))+ - `markua` ([Markua](https://leanpub.com/markua/read))+ - `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+ 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`+ ([PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint)+ slide show)+ - `rst`+ ([reStructuredText](https://docutils.sourceforge.io/docs/ref/rst/introduction.html))+ - `rtf` ([Rich Text+ Format](https://en.wikipedia.org/wiki/Rich_Text_Format))+ - `texinfo` ([GNU Texinfo](https://www.gnu.org/software/texinfo/))+ - `textile` ([Textile](https://textile-lang.com))+ - `slideous` ([Slideous](https://goessner.net/articles/slideous/) HTML+ and JavaScript slide show)+ - `slidy` ([Slidy](https://www.w3.org/Talks/Tools/Slidy2/) HTML and+ JavaScript slide show)+ - `dzslides` ([DZSlides](https://paulrouget.com/dzslides/) HTML5 ++ JavaScript slide show)+ - `revealjs` ([reveal.js](https://revealjs.com/) HTML5 + JavaScript+ slide show)+ - `s5` ([S5](https://meyerweb.com/eric/tools/s5/) HTML and JavaScript+ slide show)+ - `tei` ([TEI Simple](https://github.com/TEIC/TEI-Simple))+ - `typst` ([typst](https://typst.app))+ - `xwiki` ([XWiki+ markup](https://www.xwiki.org/xwiki/bin/view/Documentation/UserGuide/Features/XWikiSyntax/))+ - `zimwiki` ([ZimWiki+ markup](https://zim-wiki.org/manual/Help/Wiki_Syntax.html))+ - the path of a custom Lua writer, see [Custom readers and+ writers](#custom-readers-and-writers) below+ :::++ Note that `odt`, `docx`, `epub`, and `pdf` output will not be directed+ to _stdout_ unless forced with `-o -`.++ Extensions can be individually enabled or disabled by appending+ `+EXTENSION` or `-EXTENSION` to the format name. See+ [Extensions](#extensions) below, for a list of extensions and their+ names. See `--list-output-formats` and `--list-extensions`, below.+: `-o` _FILE_, `--output=`_FILE_++ Write output to _FILE_ instead of _stdout_. If _FILE_ is `-`, output+ will go to _stdout_, even if a non-textual format (`docx`, `odt`,+ `epub2`, `epub3`) is specified. If the output format is `chunkedhtml`+ and _FILE_ has no extension, then instead of producing a `.zip` file+ pandoc will create a directory _FILE_ and unpack the zip archive there+ (unless _FILE_ already exists, in which case an error will be raised).+: `--data-dir=`_DIRECTORY_++ Specify the user data directory to search for pandoc data files. If+ this option is not specified, the default user data directory will be+ used. On \*nix and macOS systems this will be the `pandoc`+ subdirectory of the XDG data directory (by default,+ `$HOME/.local/share`, overridable by setting the `XDG_DATA_HOME`+ environment variable). If that directory does not exist and+ `$HOME/.pandoc` exists, it will be used (for backwards compatibility).+ On Windows the default user data directory is `%APPDATA%\pandoc`. You+ can find the default user data directory on your system by looking at+ the output of `pandoc --version`. Data files placed in this directory+ (for example, `reference.odt`, `reference.docx`, `epub.css`,+ `templates`) will override pandoc’s normal defaults. (Note that the+ user data directory is not created by pandoc, so you will need to+ create it yourself if you want to make use of it.)+: `-d` _FILE_, `--defaults=`_FILE_++ Specify a set of default option settings. _FILE_ is a YAML file whose+ fields correspond to command-line option settings. All options for+ document conversion, including input and output files, can be set+ using a defaults file. The file will be searched for first in the+ working directory, and then in the `defaults` subdirectory of the user+ data directory (see `--data-dir`). The `.yaml` extension may be+ omitted. See the section [Defaults files](#defaults-files) for more+ information on the file format. Settings from the defaults file may be+ overridden or extended by subsequent options on the command line.+: `--bash-completion`++ Generate a bash completion script. To enable bash completion with+ pandoc, add this to your `.bashrc`:++ ```+ eval "$(pandoc --bash-completion)"+ ```+: `--verbose`++ Give verbose debugging output.+: `--quiet`++ Suppress warning messages.+: `--fail-if-warnings[=true|false]`++ Exit with error status if there are any warnings.+: `--log=`_FILE_++ Write log messages in machine-readable JSON format to _FILE_. All+ messages above DEBUG level will be written, regardless of verbosity+ settings (`--verbose`, `--quiet`).+: `--list-input-formats`++ List supported input formats, one per line.+: `--list-output-formats`++ List supported output formats, one per line.+: `--list-extensions`\[`=`_FORMAT_\]++ List supported extensions for _FORMAT_, one per line, preceded by a+ `+` or `-` indicating whether it is enabled by default in _FORMAT_. If+ _FORMAT_ is not specified, defaults for pandoc’s Markdown are given.+: `--list-highlight-languages`++ List supported languages for syntax highlighting, one per line.+: `--list-highlight-styles`++ List supported styles for syntax highlighting, one per line. See+ `--highlight-style`.+: `-v`, `--version`++ Print version.+: `-h`, `--help`++ Show usage message.++{#reader-options .options}+## Reader options++: `--shift-heading-level-by=`_NUMBER_++ Shift heading levels by a positive or negative integer. For example,+ with `--shift-heading-level-by=-1`, level 2 headings become level 1+ headings, and level 3 headings become level 2 headings. Headings+ cannot have a level less than 1, so a heading that would be shifted+ below level 1 becomes a regular paragraph. Exception: with a shift of+ -N, a level-N heading at the beginning of the document replaces the+ metadata title. `--shift-heading-level-by=-1` is a good choice when+ converting HTML or Markdown documents that use an initial level-1+ heading for the document title and level-2+ headings for sections.+ `--shift-heading-level-by=1` may be a good choice for converting+ Markdown documents that use level-1 headings for sections to HTML,+ since pandoc uses a level-1 heading to render the document title.+: `--base-header-level=`_NUMBER_++ _Deprecated. Use `--shift-heading-level-by`=X instead, where X =+ NUMBER - 1._ Specify the base level for headings (defaults to 1).+: `--indented-code-classes=`_CLASSES_++ Specify classes to use for indented code blocks–for example,+ `perl,numberLines` or `haskell`. Multiple classes may be separated by+ spaces or commas.+: `--default-image-extension=`_EXTENSION_++ Specify a default extension to use when image paths/URLs have no+ extension. This allows you to use the same source for formats that+ require different kinds of images. Currently this option only affects+ the Markdown and LaTeX readers.+: `--file-scope[=true|false]`++ Parse each file individually before combining for multifile documents.+ This will allow footnotes in different files with the same identifiers+ to work as expected. If this option is set, footnotes and links will+ not work across files. Reading binary files (docx, odt, epub) implies+ `--file-scope`.++ If two or more files are processed using `--file-scope`, prefixes+ based on the filenames will be added to identifiers in order to+ disambiguate them, and internal links will be adjusted accordingly.+ For example, a header with identifier `foo` in `subdir/file1.txt` will+ have its identifier changed to `subdir__file1.txt__foo`.++ In addition, a Div with an identifier based on the filename will be+ added around the file’s content, so that internal links to the+ filename will point to this Div’s identifier.+: `-F` _PROGRAM_, `--filter=`_PROGRAM_++ Specify an executable to be used as a filter transforming the pandoc+ AST after the input is parsed and before the output is written. The+ executable should read JSON from stdin and write JSON to stdout. The+ JSON must be formatted like pandoc’s own JSON input and output. The+ name of the output format will be passed to the filter as the first+ argument. Hence,++ ```+ pandoc --filter ./caps.py -t latex+ ```++ is equivalent to++ ```+ pandoc -t json | ./caps.py latex | pandoc -f json -t latex+ ```++ The latter form may be useful for debugging filters.++ Filters may be written in any language. `Text.Pandoc.JSON` exports+ `toJSONFilter` to facilitate writing filters in Haskell. Those who+ would prefer to write filters in python can use the module+ [`pandocfilters`](https://github.com/jgm/pandocfilters), installable+ from PyPI. There are also pandoc filter libraries in+ [PHP](https://github.com/vinai/pandocfilters-php),+ [perl](https://metacpan.org/pod/Pandoc::Filter), and+ [JavaScript/node.js](https://github.com/mvhenderson/pandoc-filter-node).++ In order of preference, pandoc will look for filters in++ 1. a specified full or relative path (executable or non-executable),++ 2. `$DATADIR/filters` (executable or non-executable) where `$DATADIR`+ is the user data directory (see `--data-dir`, above),++ 3. `$PATH` (executable only).++ Filters, Lua-filters, and citeproc processing are applied in the order+ specified on the command line.+: `-L` _SCRIPT_, `--lua-filter=`_SCRIPT_++ Transform the document in a similar fashion as JSON filters (see+ `--filter`), but use pandoc’s built-in Lua filtering system. The given+ Lua script is expected to return a list of Lua filters which will be+ applied in order. Each Lua filter must contain element-transforming+ functions indexed by the name of the AST element on which the filter+ function should be applied.++ The `pandoc` Lua module provides helper functions for element+ creation. It is always loaded into the script’s Lua environment.++ See the [Lua filters+ documentation](https://pandoc.org/lua-filters.html) for further+ details.++ In order of preference, pandoc will look for Lua filters in++ 1. a specified full or relative path,++ 2. `$DATADIR/filters` where `$DATADIR` is the user data directory (see+ `--data-dir`, above).++ Filters, Lua filters, and citeproc processing are applied in the order+ specified on the command line.+: `-M` _KEY_\[`=`_VAL_\], `--metadata=`_KEY_\[`:`_VAL_\]++ Set the metadata field _KEY_ to the value _VAL_. A value specified on+ the command line overrides a value specified in the document using+ [YAML metadata blocks](#extension-yaml_metadata_block). Values will be+ parsed as YAML boolean or string values. If no value is specified, the+ value will be treated as Boolean true. Like `--variable`, `--metadata`+ causes template variables to be set. But unlike `--variable`,+ `--metadata` affects the metadata of the underlying document (which is+ accessible from filters and may be printed in some output formats) and+ metadata values will be escaped when inserted into the template.+: `--metadata-file=`_FILE_++ Read metadata from the supplied YAML (or JSON) file. This option can+ be used with every input format, but string scalars in the metadata+ file will always be parsed as Markdown. (If the input format is+ Markdown or a Markdown variant, then the same variant will be used to+ parse the metadata file; if it is a non-Markdown format, pandoc’s+ default Markdown extensions will be used.) This option can be used+ repeatedly to include multiple metadata files; values in files+ specified later on the command line will be preferred over those+ specified in earlier files. Metadata values specified inside the+ document, or by using `-M`, overwrite values specified with this+ option. The file will be searched for first in the working directory,+ and then in the `metadata` subdirectory of the user data directory+ (see `--data-dir`).+: `-p`, `--preserve-tabs[=true|false]`++ Preserve tabs instead of converting them to spaces. (By default,+ pandoc converts tabs to spaces before parsing its input.) Note that+ this will only affect tabs in literal code spans and code blocks. Tabs+ in regular text are always treated as spaces.+: `--tab-stop=`_NUMBER_++ Specify the number of spaces per tab (default is 4).+: `--track-changes=accept`|`reject`|`all`++ Specifies what to do with insertions, deletions, and comments produced+ by the MS Word "Track Changes" feature. `accept` (the default)+ processes all the insertions and deletions. `reject` ignores them.+ Both `accept` and `reject` ignore comments. `all` includes all+ insertions, deletions, and comments, wrapped in spans with+ `insertion`, `deletion`, `comment-start`, and `comment-end` classes,+ respectively. The author and time of change is included. `all` is+ useful for scripting: only accepting changes from a certain reviewer,+ say, or before a certain date. If a paragraph is inserted or deleted,+ `track-changes=all` produces a span with the class+ `paragraph-insertion`/`paragraph-deletion` before the affected+ paragraph break. This option only affects the docx reader.+: `--extract-media=`_DIR_++ Extract images and other media contained in or linked from the source+ document to the path _DIR_, creating it if necessary, and adjust the+ images references in the document so they point to the extracted+ files. Media are downloaded, read from the file system, or extracted+ from a binary container (e.g. docx), as needed. The original file+ paths are used if they are relative paths not containing `..`.+ Otherwise filenames are constructed from the SHA1 hash of the+ contents.+: `--abbreviations=`_FILE_++ Specifies a custom abbreviations file, with abbreviations one to a+ line. If this option is not specified, pandoc will read the data file+ `abbreviations` from the user data directory or fall back on a system+ default. To see the system default, use+ `pandoc --print-default-data-file=abbreviations`. The only use pandoc+ makes of this list is in the Markdown reader. Strings found in this+ list will be followed by a nonbreaking space, and the period will not+ produce sentence-ending space in formats like LaTeX. The strings may+ not contain spaces.+: `--trace[=true|false]`++ Print diagnostic output tracing parser progress to stderr. This option+ is intended for use by developers in diagnosing performance issues.++{#general-writer-options .options}+## General writer options++: `-s`, `--standalone`++ Produce output with an appropriate header and footer (e.g. a+ standalone HTML, LaTeX, TEI, or RTF file, not a fragment). This option+ is set automatically for `pdf`, `epub`, `epub3`, `fb2`, `docx`, and+ `odt` output. For `native` output, this option causes metadata to be+ included; otherwise, metadata is suppressed.+: `--template=`_FILE_|_URL_++ Use the specified file as a custom template for the generated+ document. Implies `--standalone`. See [Templates](#templates), below,+ for a description of template syntax. If no extension is specified, an+ extension corresponding to the writer will be added, so that+ `--template=special` looks for `special.html` for HTML output. If the+ template is not found, pandoc will search for it in the `templates`+ subdirectory of the user data directory (see `--data-dir`). If this+ option is not used, a default template appropriate for the output+ format will be used (see `-D/--print-default-template`).+: `-V` _KEY_\[`=`_VAL_\], `--variable=`_KEY_\[`:`_VAL_\]++ Set the template variable _KEY_ to the value _VAL_ when rendering the+ document in standalone mode. If no _VAL_ is specified, the key will be+ given the value `true`.+: `--sandbox[=true|false]`++ Run pandoc in a sandbox, limiting IO operations in readers and writers+ to reading the files specified on the command line. Note that this+ option does not limit IO operations by filters or in the production of+ PDF documents. But it does offer security against, for example,+ disclosure of files through the use of `include` directives. Anyone+ using pandoc on untrusted user input should use this option.++ Note: some readers and writers (e.g., `docx`) need access to data+ files. If these are stored on the file system, then pandoc will not be+ able to find them when run in `--sandbox` mode and will raise an+ error. For these applications, we recommend using a pandoc binary+ compiled with the `embed_data_files` option, which causes the data+ files to be baked into the binary instead of being stored on the file+ system.+: `-D` _FORMAT_, `--print-default-template=`_FORMAT_++ 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. 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.++ Note that some of the default templates use partials, for example+ `styles.html`. To print the partials, use `--print-default-data-file`:+ for example, `--print-default-data-file=templates/styles.html`.+: `--print-default-data-file=`_FILE_++ Print a system default data file. Files in the user data 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-data-file` on the command line.+: `--eol=crlf`|`lf`|`native`++ Manually specify line endings: `crlf` (Windows), `lf`+ (macOS/Linux/UNIX), or `native` (line endings appropriate to the OS on+ which pandoc is being run). The default is `native`.+: `--dpi`=_NUMBER_++ Specify the default dpi (dots per inch) value for conversion from+ pixels to inch/centimeters and vice versa. (Technically, the correct+ term would be ppi: pixels per inch.) The default is 96dpi. When images+ contain information about dpi internally, the encoded value is used+ instead of the default specified by this option.+: `--wrap=auto`|`none`|`preserve`++ Determine how text is wrapped in the output (the source code, not the+ rendered version). With `auto` (the default), pandoc will attempt to+ wrap lines to the column width specified by `--columns` (default 72).+ With `none`, pandoc will not wrap lines at all. With `preserve`,+ pandoc will attempt to preserve the wrapping from the source document+ (that is, where there are nonsemantic newlines in the source, there+ will be nonsemantic newlines in the output as well). In `ipynb`+ output, this option affects wrapping of the contents of markdown+ cells.+: `--columns=`_NUMBER_++ Specify length of lines in characters. This affects text wrapping in+ the generated source code (see `--wrap`). It also affects calculation+ of column widths for plain text tables (see [Tables](#tables) below).+: `--toc[=true|false]`, `--table-of-contents[=true|false]`++ Include an automatically generated table of contents (or, in the case+ of `latex`, `context`, `docx`, `odt`, `opendocument`, `rst`, or `ms`,+ an instruction to create one) in the output document. This option has+ no effect unless `-s/--standalone` is used, and it has no effect on+ `man`, `docbook4`, `docbook5`, or `jats` output.++ Note that if you are producing a PDF via `ms`, the table of contents+ will appear at the beginning of the document, before the title. If you+ would prefer it to be at the end of the document, use the option+ `--pdf-engine-opt=--no-toc-relocation`.+: `--toc-depth=`_NUMBER_++ Specify the number of section levels to include in the table of+ contents. The default is 3 (which means that level-1, 2, and 3+ headings will be listed in the contents).+: `--strip-comments[=true|false]`++ Strip out HTML comments in the Markdown or Textile source, rather than+ passing them on to Markdown, Textile or HTML output as raw HTML. This+ does not apply to HTML comments inside raw HTML blocks when the+ `markdown_in_html_blocks` extension is not set.+: `--no-highlight`++ Disables syntax highlighting for code blocks and inlines, even when a+ language attribute is given.+: `--highlight-style=`_STYLE_|_FILE_++ Specifies the coloring style to be used in highlighted source code.+ Options are `pygments` (the default), `kate`, `monochrome`,+ `breezeDark`, `espresso`, `zenburn`, `haddock`, and `tango`. For more+ information on syntax highlighting in pandoc, see [Syntax+ highlighting](#syntax-highlighting), below. See also+ `--list-highlight-styles`.++ Instead of a _STYLE_ name, a JSON file with extension `.theme` may be+ supplied. This will be parsed as a KDE syntax highlighting theme and+ (if valid) used as the highlighting style.++ To generate the JSON version of an existing style, use+ `--print-highlight-style`.+: `--print-highlight-style=`_STYLE_|_FILE_++ Prints a JSON version of a highlighting style, which can be modified,+ saved with a `.theme` extension, and used 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_++ Instructs pandoc to load a KDE XML syntax definition file, which will+ be used for syntax highlighting of appropriately marked code blocks.+ This can be used to add support for new languages or to use altered+ syntax definitions for existing languages. This option may be repeated+ to add multiple syntax definitions.+: `-H` _FILE_, `--include-in-header=`_FILE_|_URL_++ Include contents of _FILE_, verbatim, at the end of the header. This+ can be used, for example, to include special CSS or JavaScript in HTML+ documents. This option can be used repeatedly to include multiple+ files in the header. They will be included in the order specified.+ Implies `--standalone`.+: `-B` _FILE_, `--include-before-body=`_FILE_|_URL_++ Include contents of _FILE_, verbatim, at the beginning of the document+ body (e.g. after the `<body>` tag in HTML, or the `\begin{document}`+ command in LaTeX). This can be used to include navigation bars or+ banners in HTML documents. This option can be used repeatedly to+ include multiple files. They will be included in the order specified.+ Implies `--standalone`.+: `-A` _FILE_, `--include-after-body=`_FILE_|_URL_++ Include contents of _FILE_, verbatim, at the end of the document body+ (before the `</body>` tag in HTML, or the `\end{document}` command in+ LaTeX). This option can be used repeatedly to include multiple files.+ They will be included in the order specified. Implies `--standalone`.+: `--resource-path=`_SEARCHPATH_++ List of paths to search for images and other resources. The paths+ should be separated by `:` on Linux, UNIX, and macOS systems, and by+ `;` on Windows. If `--resource-path` is not specified, the default+ resource path is the working directory. Note that, if+ `--resource-path` is specified, the working directory must be+ explicitly listed or it will not be searched. For example:+ `--resource-path=.:test` will search the working directory and the+ `test` subdirectory, in that order. This option can be used+ repeatedly. Search path components that come later on the command line+ will be searched before those that come earlier, so+ `--resource-path foo:bar --resource-path baz:bim` is equivalent to+ `--resource-path baz:bim:foo:bar`.+: `--request-header=`_NAME_`:`_VAL_++ Set the request header _NAME_ to the value _VAL_ when making HTTP+ requests (for example, when a URL is given on the command line, or+ when resources used in a document must be downloaded). If you’re+ behind a proxy, you also need to set the environment variable+ `http_proxy` to `http://...`.+: `--no-check-certificate[=true|false]`++ Disable the certificate verification to allow access to unsecure HTTP+ resources (for example when the certificate is no longer valid or self+ signed).++{#options-affecting-specific-writers .options}+## Options affecting specific writers++: `--self-contained[=true|false]`++ _Deprecated synonym for `--embed-resources --standalone`._+: `--embed-resources[=true|false]`++ Produce a standalone HTML file with no external dependencies, using+ `data:` URIs to incorporate the contents of linked scripts,+ stylesheets, images, and videos. The resulting file should be+ "self-contained," in the sense that it needs no external files and no+ net access to be displayed properly by a browser. This option works+ only with HTML output formats, including `html4`, `html5`, `html+lhs`,+ `html5+lhs`, `s5`, `slidy`, `slideous`, `dzslides`, and `revealjs`.+ Scripts, images, and stylesheets at absolute URLs will be downloaded;+ those at relative URLs will be sought relative to the working+ directory (if the first source file is local) or relative to the base+ URL (if the first source file is remote). Elements with the attribute+ `data-external="1"` will be left alone; the documents they link to+ will not be incorporated in the document. Limitation: resources that+ are loaded dynamically through JavaScript cannot be incorporated; as a+ result, fonts may be missing when `--mathjax` is used, and some+ advanced features (e.g. zoom or speaker notes) may not work in an+ offline "self-contained" `reveal.js` slide show.+: `--html-q-tags[=true|false]`++ Use `<q>` tags for quotes in HTML. (This option only has an effect if+ the `smart` extension is enabled for the input format used.)+: `--ascii[=true|false]`++ Use only ASCII characters in output. Currently supported for XML and+ HTML formats (which use entities instead of UTF-8 when this option is+ selected), CommonMark, gfm, and Markdown (which use entities), roff+ man and ms (which use hexadecimal escapes), and to a limited degree+ LaTeX (which uses standard commands for accented characters when+ possible).+: `--reference-links[=true|false]`++ Use reference-style links, rather than inline links, in writing+ Markdown or reStructuredText. By default inline links are used. The+ placement of link references is affected by the `--reference-location`+ option.+: `--reference-location=block`|`section`|`document`++ Specify whether footnotes (and references, if `reference-links` is+ set) are placed at the end of the current (top-level) block, the+ current section, or the document. The default is `document`. Currently+ this option only affects the `markdown`, `muse`, `html`, `epub`,+ `slidy`, `s5`, `slideous`, `dzslides`, and `revealjs` writers. In+ slide formats, specifying `--reference-location=section` will cause+ notes to be rendered at the bottom of a slide.+: `--markdown-headings=setext`|`atx`++ Specify whether to use ATX-style (`#`-prefixed) or Setext-style+ (underlined) headings for level 1 and 2 headings in Markdown output.+ (The default is `atx`.) ATX-style headings are always used for levels+ 3+. This option also affects Markdown cells in `ipynb` output.+: `--list-tables[=true|false]`++ Render tables as list tables in RST output.+: `--top-level-division=default`|`section`|`chapter`|`part`++ Treat top-level headings as the given division type in LaTeX, ConTeXt,+ DocBook, and TEI output. The hierarchy order is part, chapter, then+ section; all headings are shifted such that the top-level heading+ becomes the specified type. The default behavior is to determine the+ best division type via heuristics: unless other conditions apply,+ `section` is chosen. When the `documentclass` variable is set to+ `report`, `book`, or `memoir` (unless the `article` option is+ specified), `chapter` is implied as the setting for this option. If+ `beamer` is the output format, specifying either `chapter` or `part`+ will cause top-level headings to become `\part{..}`, while+ second-level headings remain as their default type.+: `-N`, `--number-sections`++ Number section headings in LaTeX, ConTeXt, HTML, Docx, ms, or EPUB+ output. By default, sections are not numbered. Sections with class+ `unnumbered` will never be numbered, even if `--number-sections` is+ specified.+: `--number-offset=`_NUMBER_\[`,`_NUMBER_`,`_…_\]++ Offset for section headings in HTML output (ignored in other output+ formats). The first number is added to the section number for+ top-level headings, the second for second-level headings, and so on.+ So, for example, if you want the first top-level heading in your+ document to be numbered "6", specify `--number-offset=5`. If your+ document starts with a level-2 heading which you want to be numbered+ "1.5", specify `--number-offset=1,4`. Offsets are 0 by default.+ Implies `--number-sections`.+: `--listings[=true|false]`++ Use the [`listings`](https://ctan.org/pkg/listings) package for LaTeX+ code blocks. The package does not support multi-byte encoding for+ source code. To handle UTF-8 you would need to use a custom template.+ This issue is fully documented here: [Encoding issue with the listings+ package](https://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings#Encoding_issue).+: `-i`, `--incremental[=true|false]`++ Make list items in slide shows display incrementally (one by one). The+ default is for lists to be displayed all at once.+: `--slide-level=`_NUMBER_++ Specifies that headings with the specified level create slides (for+ `beamer`, `s5`, `slidy`, `slideous`, `dzslides`). Headings above this+ level in the hierarchy are used to divide the slide show into+ sections; headings below this level create subheads within a slide.+ Valid values are 0-6. If a slide level of 0 is specified, slides will+ not be split automatically on headings, and horizontal rules must be+ used to indicate slide boundaries. If a slide level is not specified+ explicitly, the slide level will be set automatically based on the+ contents of the document; see [Structuring the slide+ show](#structuring-the-slide-show).+: `--section-divs[=true|false]`++ Wrap sections in `<section>` tags (or `<div>` tags for `html4`), and+ attach identifiers to the enclosing `<section>` (or `<div>`) rather+ than the heading itself (see [Heading+ identifiers](#heading-identifiers), below). This option only affects+ HTML output (and does not affect HTML slide formats).+: `--email-obfuscation=none`|`javascript`|`references`++ Specify a method for obfuscating `mailto:` links in HTML documents.+ `none` leaves `mailto:` links as they are. `javascript` obfuscates+ them using JavaScript. `references` obfuscates them by printing their+ letters as decimal or hexadecimal character references. The default is+ `none`.+: `--id-prefix=`_STRING_++ Specify a prefix to be added to all identifiers and internal links in+ HTML and DocBook output, and to footnote numbers in Markdown and+ Haddock output. This is useful for preventing duplicate identifiers+ when generating fragments to be included in other pages.+: `-T` _STRING_, `--title-prefix=`_STRING_++ Specify _STRING_ as a prefix at the beginning of the title that+ appears in the HTML header (but not in the title as it appears at the+ beginning of the HTML body). Implies `--standalone`.+: `-c` _URL_, `--css=`_URL_++ Link to a CSS style sheet. This option can be used repeatedly to+ include multiple files. They will be included in the order specified.+ This option only affects HTML (including HTML slide shows) and EPUB+ output. It should be used together with `-s/--standalone`, because the+ link to the stylesheet goes in the document header.++ A stylesheet is required for generating EPUB. If none is provided+ using this option (or the `css` or `stylesheet` metadata fields),+ pandoc will look for a file `epub.css` in the user data directory (see+ `--data-dir`). If it is not found there, sensible defaults will be+ used.+: `--reference-doc=`_FILE_|_URL_++ Use the specified file as a style reference in producing a docx or ODT+ file.++ : Docx++ For best results, the reference docx should be a modified version of+ a docx file produced using pandoc. The contents of the reference+ docx are ignored, but its stylesheets and document properties+ (including margins, page size, header, and footer) are used in the+ new docx. If no reference docx is specified on the command line,+ pandoc will look for a file `reference.docx` in the user data+ directory (see `--data-dir`). If this is not found either, sensible+ defaults will be used.++ To produce a custom `reference.docx`, first get a copy of the+ default `reference.docx`:+ `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:++ - Normal+ - Body Text+ - First Paragraph+ - Compact+ - Title+ - Subtitle+ - Author+ - Date+ - Abstract+ - AbstractTitle+ - Bibliography+ - Heading 1+ - Heading 2+ - Heading 3+ - Heading 4+ - Heading 5+ - Heading 6+ - Heading 7+ - Heading 8+ - Heading 9+ - Block Text+ - Source Code+ - Footnote Text+ - Definition Term+ - Definition+ - Caption+ - Table Caption+ - Image Caption+ - Figure+ - Captioned Figure+ - TOC Heading++ Character styles:++ - Default Paragraph Font+ - Body Text Char+ - Verbatim Char+ - Footnote Reference+ - Hyperlink+ - Section Number++ Table style:++ - Table+ : ODT++ For best results, the reference ODT should be a modified version of+ an ODT produced using pandoc. The contents of the reference ODT are+ ignored, but its stylesheets are used in the new ODT. If no+ reference ODT is specified on the command line, pandoc will look for+ a file `reference.odt` in the user data directory (see+ `--data-dir`). If this is not found either, sensible defaults will+ be used.++ To produce a custom `reference.odt`, first get a copy of the default+ `reference.odt`:+ `pandoc -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++ Templates included with Microsoft PowerPoint 2013 (either with+ `.pptx` or `.potx` extension) are known to work, as are most+ templates derived from these.++ The specific requirement is that the template should contain layouts+ with the following names (as seen within PowerPoint):++ - Title Slide+ - Title and Content+ - Section Header+ - Two Content+ - Comparison+ - Content with Caption+ - Blank++ For each name, the first layout found with that name will be used.+ If no layout is found with one of the names, pandoc will output a+ warning and use the layout with that name from the default reference+ doc instead. (How these layouts are used is described in [PowerPoint+ layout choice](#powerpoint-layout-choice).)++ All templates included with a recent version of MS PowerPoint will+ fit these criteria. (You can click on `Layout` under the `Home` menu+ to check.)++ You can also modify the default `reference.pptx`: first run+ `pandoc -o custom-reference.pptx --print-default-data-file reference.pptx`,+ and then modify `custom-reference.pptx` in MS PowerPoint (pandoc+ will use the layouts with the names listed above).+: `--split-level=`_NUMBER_++ Specify the heading level at which to split an EPUB or chunked HTML+ document into separate files. The default is to split into chapters at+ level-1 headings. In the case of EPUB, this option only affects the+ internal composition of the EPUB, not the way chapters and sections+ are displayed to users. Some readers may be slow if the chapter files+ are too large, so for large documents with few level-1 headings, one+ might want to use a chapter level of 2 or 3. For chunked HTML, this+ option determines how much content goes in each "chunk."+: `--chunk-template=`_PATHTEMPLATE_++ Specify a template for the filenames in a `chunkedhtml` document. In+ the template, `%n` will be replaced by the chunk number (padded with+ leading 0s to 3 digits), `%s` with the section number of the chunk,+ `%h` with the heading text (with formatting removed), `%i` with the+ section identifier. For example, `%section-%s-%i.html` might be+ resolved to `section-1.1-introduction.html`. The characters `/` and+ `\` are not allowed in chunk templates and will be ignored. The+ default is `%s-%i.html`.+: `--epub-chapter-level=`_NUMBER_++ _Deprecated synonym for `--split-level`._+: `--epub-cover-image=`_FILE_++ Use the specified image as the EPUB cover. It is recommended that the+ image be less than 1000px in width and height. Note that in a Markdown+ source document you can also specify `cover-image` in a YAML metadata+ block (see [EPUB Metadata](#epub-metadata), below).+: `--epub-title-page=true`|`false`++ Determines whether a the title page is included in the EPUB (default+ is `true`).+: `--epub-metadata=`_FILE_++ Look in the specified XML file for metadata for the EPUB. The file+ should contain a series of [Dublin Core+ elements](https://www.dublincore.org/specifications/dublin-core/dces/).+ For example:++ ```+ <dc:rights>Creative Commons</dc:rights>+ <dc:language>es-AR</dc:language>+ ```++ By default, pandoc will include the following metadata elements:+ `<dc:title>` (from the document title), `<dc:creator>` (from the+ document authors), `<dc:date>` (from the document date, which should+ be in [ISO 8601 format](https://www.w3.org/TR/NOTE-datetime)),+ `<dc:language>` (from the `lang` variable, or, if is not set, the+ locale), and `<dc:identifier id="BookId">` (a randomly generated+ UUID). Any of these may be overridden by elements in the metadata+ file.++ Note: if the source document is Markdown, a YAML metadata block in the+ document can be used instead. See below under [EPUB+ Metadata](#epub-metadata).+: `--epub-embed-font=`_FILE_++ Embed the specified font in the EPUB. This option can be repeated to+ embed multiple fonts. Wildcards can also be used: for example,+ `DejaVuSans-*.ttf`. However, if you use wildcards on the command line,+ be sure to escape them or put the whole filename in single quotes, to+ prevent them from being interpreted by the shell. To use the embedded+ fonts, you will need to add declarations like the following to your+ CSS (see `--css`):++ ```+ @font-face {+ font-family: DejaVuSans;+ font-style: normal;+ font-weight: normal;+ src:url("../fonts/DejaVuSans-Regular.ttf");+ }+ @font-face {+ font-family: DejaVuSans;+ font-style: normal;+ font-weight: bold;+ src:url("../fonts/DejaVuSans-Bold.ttf");+ }+ @font-face {+ font-family: DejaVuSans;+ font-style: italic;+ font-weight: normal;+ src:url("../fonts/DejaVuSans-Oblique.ttf");+ }+ @font-face {+ font-family: DejaVuSans;+ font-style: italic;+ font-weight: bold;+ src:url("../fonts/DejaVuSans-BoldOblique.ttf");+ }+ body { font-family: "DejaVuSans"; }+ ```+: `--epub-subdirectory=`_DIRNAME_++ Specify the subdirectory in the OCF container that is to hold the+ EPUB-specific contents. The default is `EPUB`. To put the EPUB+ contents in the top level, use an empty string.+: `--ipynb-output=all|none|best`++ Determines how ipynb output cells are treated. `all` means that all of+ the data formats included in the original are preserved. `none` means+ that the contents of data cells are omitted. `best` causes pandoc to+ try to pick the richest data block in each output cell that is+ compatible with the output format. The default is `best`.+: `--pdf-engine=`_PROGRAM_++ Use the specified engine when producing PDF output. Valid values are+ `pdflatex`, `lualatex`, `xelatex`, `latexmk`, `tectonic`,+ `wkhtmltopdf`, `weasyprint`, `pagedjs-cli`, `prince`, `context`,+ `pdfroff`, and `typst`. If the engine is not in your PATH, the full+ path of the engine may be specified here. If this option is not+ specified, pandoc uses the following defaults depending on the output+ format specified using `-t/--to`:++ - `-t latex` or none: `pdflatex` (other options: `xelatex`,+ `lualatex`, `tectonic`, `latexmk`)+ - `-t context`: `context`+ - `-t html`: `wkhtmltopdf` (other options: `prince`, `weasyprint`,+ `pagedjs-cli`; see [print-css.rocks](https://print-css.rocks) for a+ good introduction to PDF generation from HTML/CSS)+ - `-t ms`: `pdfroff`+ - `-t typst`: `typst`+: `--pdf-engine-opt=`_STRING_++ Use the given string as a command-line argument to the `pdf-engine`.+ For example, to use a persistent directory `foo` for `latexmk`’s+ auxiliary files, use `--pdf-engine-opt=-outdir=foo`. Note that no+ check for duplicate options is done.++{#citation-rendering .options}+## Citation rendering++: `-C`, `--citeproc`++ Process the citations in the file, replacing them with rendered+ citations and adding a bibliography. Citation processing will not take+ place unless bibliographic data is supplied, either through an+ external file specified using the `--bibliography` option or the+ `bibliography` field in metadata, or via a `references` section in+ metadata containing a list of citations in CSL YAML format with+ Markdown formatting. The style is controlled by a+ [CSL](https://docs.citationstyles.org/en/stable/specification.html)+ stylesheet specified using the `--csl` option or the `csl` field in+ metadata. (If no stylesheet is specified, the `chicago-author-date`+ style will be used by default.) The citation processing transformation+ may be applied before or after filters or Lua filters (see `--filter`,+ `--lua-filter`): these transformations are applied in the order they+ appear on the command line. For more information, see the section on+ [Citations](#citations).+: `--bibliography=`_FILE_++ Set the `bibliography` field in the document’s metadata to _FILE_,+ overriding any value set in the metadata. If you supply this argument+ multiple times, each _FILE_ will be added to bibliography. If _FILE_+ is a URL, it will be fetched via HTTP. If _FILE_ is not found relative+ to the working directory, it will be sought in the resource path (see+ `--resource-path`).+: `--csl=`_FILE_++ Set the `csl` field in the document’s metadata to _FILE_, overriding+ any value set in the metadata. (This is equivalent to+ `--metadata csl=FILE`.) If _FILE_ is a URL, it will be fetched via+ HTTP. If _FILE_ is not found relative to the working directory, it+ will be sought in the resource path (see `--resource-path`) and+ finally in the `csl` subdirectory of the pandoc user data directory.+: `--citation-abbreviations=`_FILE_++ Set the `citation-abbreviations` field in the document’s metadata to+ _FILE_, overriding any value set in the metadata. (This is equivalent+ to `--metadata citation-abbreviations=FILE`.) If _FILE_ is a URL, it+ will be fetched via HTTP. If _FILE_ is not found relative to the+ working directory, it will be sought in the resource path (see+ `--resource-path`) and finally in the `csl` subdirectory of the pandoc+ user data directory.+: `--natbib`++ Use [`natbib`](https://ctan.org/pkg/natbib) for citations in LaTeX+ output. This option is not for use with the `--citeproc` option or+ with PDF output. It is intended for use in producing a LaTeX file that+ can be processed with [`bibtex`](https://ctan.org/pkg/bibtex).+: `--biblatex`++ Use [`biblatex`](https://ctan.org/pkg/biblatex) for citations in LaTeX+ output. This option is not for use with the `--citeproc` option or+ with PDF output. It is intended for use in producing a LaTeX file that+ can be processed with [`bibtex`](https://ctan.org/pkg/bibtex) or+ [`biber`](https://ctan.org/pkg/biber).++{#math-rendering-in-html .options}+## Math rendering in HTML++The default is to render TeX math as far as possible using Unicode+characters. Formulas are put inside a `span` with `class="math"`, so+that they may be styled differently from the surrounding text if needed.+However, this gives acceptable results only for basic math, usually you+will want to use `--mathjax` or another of the following options.++: `--mathjax`\[`=`_URL_\]++ Use [MathJax](https://www.mathjax.org) to display embedded TeX math in+ HTML output. TeX math will be put between `\(...\)` (for inline math)+ or `\[...\]` (for display math) and wrapped in `<span>` tags with+ class `math`. Then the MathJax JavaScript will render it. The _URL_+ should point to the `MathJax.js` load script. If a _URL_ is not+ provided, a link to the Cloudflare CDN will be inserted.+: `--mathml`++ Convert TeX math to [MathML](https://www.w3.org/Math/) (in `epub3`,+ `docbook4`, `docbook5`, `jats`, `html4` and `html5`). This is the+ default in `odt` output. MathML is supported natively by the main web+ browsers and select e-book readers.+: `--webtex`\[`=`_URL_\]++ Convert TeX formulas to `<img>` tags that link to an external script+ that converts formulas to images. The formula will be URL-encoded and+ concatenated with the URL provided. For SVG images you can for example+ use `--webtex https://latex.codecogs.com/svg.latex?`. If no URL is+ specified, the CodeCogs URL generating PNGs will be used+ (`https://latex.codecogs.com/png.latex?`). Note: the `--webtex` option+ will affect Markdown output as well as HTML, which is useful if you’re+ targeting a version of Markdown without native math support.+: `--katex`\[`=`_URL_\]++ Use [KaTeX](https://github.com/Khan/KaTeX) to display embedded TeX+ math in HTML output. The _URL_ is the base URL for the KaTeX library.+ That directory should contain a `katex.min.js` and a `katex.min.css`+ file. If a _URL_ is not provided, a link to the KaTeX CDN will be+ inserted.+: `--gladtex`++ Enclose TeX math in `<eq>` tags in HTML output. The resulting HTML can+ then be processed by [GladTeX](https://humenda.github.io/GladTeX/) to+ produce SVG images of the typeset formulas and an HTML file with these+ images embedded.++ ```+ pandoc -s --gladtex input.md -o myfile.htex+ gladtex -d image_dir myfile.htex+ # produces myfile.html and images in image_dir+ ```++{#options-for-wrapper-scripts .options}+## Options for wrapper scripts++: `--dump-args[=true|false]`++ Print information about command-line arguments to _stdout_, then exit.+ This option is intended primarily for use in wrapper scripts. The+ first line of output contains the name of the output file specified+ with the `-o` option, or `-` (for _stdout_) if no output file was+ specified. The remaining lines contain the command-line arguments, one+ per line, in the order they appear. These do not include regular+ pandoc options and their arguments, but do include any options+ appearing after a `--` separator at the end of the line.+: `--ignore-args[=true|false]`++ Ignore command-line arguments (for use in wrapper scripts). Regular+ pandoc options are not ignored. Thus, for example,++ ```+ pandoc --ignore-args -o foo.html -s foo.txt -- -e latin1+ ```++ is equivalent to++ ```+ pandoc -o foo.html -s+ ```++{#exit-codes}+# Exit codes++If pandoc completes successfully, it will return exit code 0. Nonzero+exit codes have the following meanings:++|Code|Error|+|--:|:--|+|1|PandocIOError|+|3|PandocFailOnWarningError|+|4|PandocAppError|+|5|PandocTemplateError|+|6|PandocOptionError|+|21|PandocUnknownReaderError|+|22|PandocUnknownWriterError|+|23|PandocUnsupportedExtensionError|+|24|PandocCiteprocError|+|25|PandocBibliographyError|+|31|PandocEpubSubdirectoryError|+|43|PandocPDFError|+|44|PandocXMLError|+|47|PandocPDFProgramNotFoundError|+|61|PandocHttpError|+|62|PandocShouldNeverHappenError|+|63|PandocSomeError|+|64|PandocParseError|+|66|PandocMakePDFError|+|67|PandocSyntaxMapError|+|83|PandocFilterError|+|84|PandocLuaError|+|89|PandocNoScriptingEngine|+|91|PandocMacroLoop|+|92|PandocUTF8DecodingError|+|93|PandocIpynbDecodingError|+|94|PandocUnsupportedCharsetError|+|97|PandocCouldNotFindDataFileError|+|98|PandocCouldNotFindMetadataFileError|+|99|PandocResourceNotFound|++{#defaults-files}+# Defaults files++The `--defaults` option may be used to specify a package of options, in+the form of a YAML file.++Fields that are omitted will just have their regular default values. So+a defaults file can be as simple as one line:++``` yaml+verbosity: INFO+```++In fields that expect a file path (or list of file paths), the following+syntax may be used to interpolate environment variables:++``` yaml+csl: ${HOME}/mycsldir/special.csl+```++`${USERDATA}` may also be used; this will always resolve to the user+data directory that is current when the defaults file is parsed,+regardless of the setting of the environment variable `USERDATA`.++`${.}` will resolve to the directory containing the defaults file+itself. This allows you to refer to resources contained in that+directory:++``` yaml+epub-cover-image: ${.}/cover.jpg+epub-metadata: ${.}/meta.xml+resource-path:+- . # the working directory from which pandoc is run+- ${.}/images # the images subdirectory of the directory+ # containing this defaults file+```++This environment variable interpolation syntax _only_ works in fields+that expect file paths.++Defaults files can be placed in the `defaults` subdirectory of the user+data directory and used from any directory. For example, one could+create a file specifying defaults for writing letters, save it as+`letter.yaml` in the `defaults` subdirectory of the user data directory,+and then invoke these defaults from any directory using+`pandoc --defaults letter` or `pandoc -dletter`.++When multiple defaults are used, their contents will be combined.++Note that, where command-line arguments may be repeated+(`--metadata-file`, `--css`, `--include-in-header`,+`--include-before-body`, `--include-after-body`, `--variable`,+`--metadata`, `--syntax-definition`), the values specified on the+command line will combine with values specified in the defaults file,+rather than replacing them.++The following tables show the mapping between the command line and+defaults file entries.++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++The value of `input-files` may be left empty to indicate input from+stdin, and it can be an empty sequence `[]` for no input.++{#general-options-1}+## General options++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++Options specified in a defaults file itself always have priority over+those in another file included with a `defaults:` entry.++`verbosity` can have the values `ERROR`, `WARNING`, or `INFO`.++{#reader-options-1}+## Reader options++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++Metadata values specified in a defaults file are parsed as literal+string text, not Markdown.++Filters will be assumed to be Lua filters if they have the `.lua`+extension, and JSON filters otherwise. But the filter type can also be+specified explicitly, as shown. Filters are run in the order specified.+To include the built-in citeproc filter, use either `citeproc` or+`{type: citeproc}`.++{#general-writer-options-1}+## General writer options++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++{#options-affecting-specific-writers-1}+## Options affecting specific writers++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++{#citation-rendering-1}+## Citation rendering++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++`cite-method` can be `citeproc`, `natbib`, or `biblatex`. This only+affects LaTeX output. If you want to use citeproc to format citations,+you should also set 'citeproc: true'.++If you need control over when the citeproc processing is done relative+to other filters, you should instead use `citeproc` in the list of+`filters` (see above).++{#math-rendering-in-html-1}+## Math rendering in HTML++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++In addition to the values listed above, `method` can have the value+`plain`.++If the command line option accepts a URL argument, an `url:` field can+be added to `html-math-method:`.++{#options-for-wrapper-scripts-1}+## Options for wrapper scripts++|command line|defaults file|+|:--|:--|+|((content omitted))|((content omitted))|+|((content omitted))|((content omitted))|++{#templates}+# Templates++When the `-s/--standalone` option is used, pandoc uses a template to add+header and footer material that is needed for a self-standing document.+To see the default template that is used, just type++```+pandoc -D *FORMAT*+```++where _FORMAT_ is the name of the output format. A custom template can+be specified using the `--template` option. You can also override the+system default templates for a given output format _FORMAT_ by putting a+file `templates/default.*FORMAT*` in the user data directory (see+`--data-dir`, above). _Exceptions:_++- For `odt` output, customize the `default.opendocument` template.+- For `pdf` output, customize the `default.latex` template (or the+ `default.context` template, if you use `-t context`, or the+ `default.ms` template, if you use `-t ms`, or the `default.html`+ template, if you use `-t html`).+- `docx` and `pptx` have no template (however, you can use+ `--reference-doc` to customize the output).++Templates contain _variables_, which allow for the inclusion of+arbitrary information at any point in the file. They may be set at the+command line using the `-V/--variable` option. If a variable is not set,+pandoc will look for the key in the document’s metadata, which can be+set using either [YAML metadata blocks](#extension-yaml_metadata_block)+or with the `-M/--metadata` option. In addition, some variables are+given default values by pandoc. See [Variables](#variables) below for a+list of variables used in pandoc’s default templates.++If you use custom templates, you may need to revise them as pandoc+changes. We recommend tracking the changes in the default templates, and+modifying your custom templates accordingly. An easy way to do this is+to fork the [pandoc-templates](https://github.com/jgm/pandoc-templates)+repository and merge in changes after each pandoc release.++{#template-syntax}+## Template syntax++{#comments}+### Comments++Anything between the sequence `$--` and the end of the line will be+treated as a comment and omitted from the output.++{#delimiters}+### Delimiters++To mark variables and control structures in the template, either `$`…`$`+or `${`…`}` may be used as delimiters. The styles may also be mixed in+the same template, but the opening and closing delimiter must match in+each case. The opening delimiter may be followed by one or more spaces+or tabs, which will be ignored. The closing delimiter may be preceded by+one or more spaces or tabs, which will be ignored.++To include a literal `$` in the document, use `$$`.++{#interpolated-variables}+### Interpolated variables++A slot for an interpolated variable is a variable name surrounded by+matched delimiters. Variable names must begin with a letter and can+contain letters, numbers, `_`, `-`, and `.`. The keywords `it`, `if`,+`else`, `endif`, `for`, `sep`, and `endfor` may not be used as variable+names. Examples:++```+$foo$+$foo.bar.baz$+$foo_bar.baz-bim$+$ foo $+${foo}+${foo.bar.baz}+${foo_bar.baz-bim}+${ foo }+```++Variable names with periods are used to get at structured variable+values. So, for example, `employee.salary` will return the value of the+`salary` field of the object that is the value of the `employee` field.++- If the value of the variable is a simple value, it will be rendered+ verbatim. (Note that no escaping is done; the assumption is that the+ calling program will escape the strings appropriately for the output+ format.)+- If the value is a list, the values will be concatenated.+- If the value is a map, the string `true` will be rendered.+- Every other value will be rendered as the empty string.++{#conditionals}+### Conditionals++A conditional begins with `if(variable)` (enclosed in matched+delimiters) and ends with `endif` (enclosed in matched delimiters). It+may optionally contain an `else` (enclosed in matched delimiters). The+`if` section is used if `variable` has a non-empty value, otherwise the+`else` section is used (if present). Examples:++```+$if(foo)$bar$endif$++$if(foo)$+ $foo$+$endif$++$if(foo)$+part one+$else$+part two+$endif$++${if(foo)}bar${endif}++${if(foo)}+ ${foo}+${endif}++${if(foo)}+${ foo.bar }+${else}+no foo!+${endif}+```++The keyword `elseif` may be used to simplify complex nested+conditionals:++```+$if(foo)$+XXX+$elseif(bar)$+YYY+$else$+ZZZ+$endif$+```++{#for-loops}+### For loops++A for loop begins with `for(variable)` (enclosed in matched delimiters)+and ends with `endfor` (enclosed in matched delimiters).++- If `variable` is an array, the material inside the loop will be+ evaluated repeatedly, with `variable` being set to each value of the+ array in turn, and concatenated.+- If `variable` is a map, the material inside will be set to the map.+- If the value of the associated variable is not an array or a map, a+ single iteration will be performed on its value.++Examples:++```+$for(foo)$$foo$$sep$, $endfor$++$for(foo)$+ - $foo.last$, $foo.first$+$endfor$++${ for(foo.bar) }+ - ${ foo.bar.last }, ${ foo.bar.first }+${ endfor }++$for(mymap)$+$it.name$: $it.office$+$endfor$+```++You may optionally specify a separator between consecutive values using+`sep` (enclosed in matched delimiters). The material between `sep` and+the `endfor` is the separator.++```+${ for(foo) }${ foo }${ sep }, ${ endfor }+```++Instead of using `variable` inside the loop, the special anaphoric+keyword `it` may be used.++```+${ for(foo.bar) }+ - ${ it.last }, ${ it.first }+${ endfor }+```++{#partials}+### Partials++Partials (subtemplates stored in different files) may be included by+using the name of the partial, followed by `()`, for example:++```+${ styles() }+```++Partials will be sought in the directory containing the main template.+The file name will be assumed to have the same extension as the main+template if it lacks an extension. When calling the partial, the full+name including file extension can also be used:++```+${ styles.html() }+```++(If a partial is not found in the directory of the template and the+template path is given as a relative path, it will also be sought in the+`templates` subdirectory of the user data directory.)++Partials may optionally be applied to variables using a colon:++```+${ date:fancy() }++${ articles:bibentry() }+```++If `articles` is an array, this will iterate over its values, applying+the partial `bibentry()` to each one. So the second example above is+equivalent to++```+${ for(articles) }+${ it:bibentry() }+${ endfor }+```++Note that the anaphoric keyword `it` must be used when iterating over+partials. In the above examples, the `bibentry` partial should contain+`it.title` (and so on) instead of `articles.title`.++Final newlines are omitted from included partials.++Partials may include other partials.++A separator between values of an array may be specified in square+brackets, immediately after the variable name or partial:++```+${months[, ]}$++${articles:bibentry()[; ]$+```++The separator in this case is literal and (unlike with `sep` in an+explicit `for` loop) cannot contain interpolated variables or other+template directives.++{#nesting}+### Nesting++To ensure that content is "nested," that is, subsequent lines indented,+use the `^` directive:++```+$item.number$ $^$$item.description$ ($item.price$)+```++In this example, if `item.description` has multiple lines, they will all+be indented to line up with the first line:++```+00123 A fine bottle of 18-year old+ Oban whiskey. ($148)+```++To nest multiple lines to the same level, align them with the `^`+directive in the template. For example:++```+$item.number$ $^$$item.description$ ($item.price$)+ (Available til $item.sellby$.)+```++will produce++```+00123 A fine bottle of 18-year old+ Oban whiskey. ($148)+ (Available til March 30, 2020.)+```++If a variable occurs by itself on a line, preceded by whitespace and not+followed by further text or directives on the same line, and the+variable’s value contains multiple lines, it will be nested+automatically.++{#breakable-spaces}+### Breakable spaces++Normally, spaces in the template itself (as opposed to values of the+interpolated variables) are not breakable, but they can be made+breakable in part of the template by using the `~` keyword (ended with+another `~`).++```+$~$This long line may break if the document is rendered+with a short line length.$~$+```++{#pipes}+### Pipes++A pipe transforms the value of a variable or partial. Pipes are+specified using a slash (`/`) between the variable name (or partial) and+the pipe name. Example:++```+$for(name)$+$name/uppercase$+$endfor$++$for(metadata/pairs)$+- $it.key$: $it.value$+$endfor$++$employee:name()/uppercase$+```++Pipes may be chained:++```+$for(employees/pairs)$+$it.key/alpha/uppercase$. $it.name$+$endfor$+```++Some pipes take parameters:++```+|----------------------|------------|+$for(employee)$+$it.name.first/uppercase/left 20 "| "$$it.name.salary/right 10 " | " " |"$+$endfor$+|----------------------|------------|+```++Currently the following pipes are predefined:++- `pairs`: Converts a map or array to an array of maps, each with `key`+ and `value` fields. If the original value was an array, the `key` will+ be the array index, starting with 1.++- `uppercase`: Converts text to uppercase.++- `lowercase`: Converts text to lowercase.++- `length`: Returns the length of the value: number of characters for a+ textual value, number of elements for a map or array.++- `reverse`: Reverses a textual value or array, and has no effect on+ other values.++- `first`: Returns the first value of an array, if applied to a+ non-empty array; otherwise returns the original value.++- `last`: Returns the last value of an array, if applied to a non-empty+ array; otherwise returns the original value.++- `rest`: Returns all but the first value of an array, if applied to a+ non-empty array; otherwise returns the original value.++- `allbutlast`: Returns all but the last value of an array, if applied+ to a non-empty array; otherwise returns the original value.++- `chomp`: Removes trailing newlines (and breakable space).++- `nowrap`: Disables line wrapping on breakable spaces.++- `alpha`: Converts textual values that can be read as an integer into+ lowercase alphabetic characters `a..z` (mod 26). This can be used to+ get lettered enumeration from array indices. To get uppercase letters,+ chain with `uppercase`.++- `roman`: Converts textual values that can be read as an integer into+ lowercase roman numerals. This can be used to get lettered enumeration+ from array indices. To get uppercase roman, chain with `uppercase`.++- `left n "leftborder" "rightborder"`: Renders a textual value in a+ block of width `n`, aligned to the left, with an optional left and+ right border. Has no effect on other values. This can be used to align+ material in tables. Widths are positive integers indicating the number+ of characters. Borders are strings inside double quotes; literal `"`+ and `\` characters must be backslash-escaped.++- `right n "leftborder" "rightborder"`: Renders a textual value in a+ block of width `n`, aligned to the right, and has no effect on other+ values.++- `center n "leftborder" "rightborder"`: Renders a textual value in a+ block of width `n`, aligned to the center, and has no effect on other+ values.++{#variables}+## Variables++{#metadata-variables}+### Metadata variables++: `title`, `author`, `date`++ allow identification of basic aspects of the document. Included in PDF+ metadata through LaTeX and ConTeXt. These can be set through a [pandoc+ title block](#extension-pandoc_title_block), which allows for multiple+ authors, or through a [YAML metadata+ block](#extension-yaml_metadata_block):++ ```+ ---+ author:+ - Aristotle+ - Peter Abelard+ ...+ ```++ Note that if you just want to set PDF or HTML metadata, without+ including a title block in the document itself, you can set the+ `title-meta`, `author-meta`, and `date-meta` variables. (By default+ these are set automatically, based on `title`, `author`, and `date`.)+ The page title in HTML is set by `pagetitle`, which is equal to+ `title` by default.+: `subtitle`++ document subtitle, included in HTML, EPUB, LaTeX, ConTeXt, and docx+ documents+: `abstract`++ document summary, included in HTML, LaTeX, ConTeXt, AsciiDoc, and docx+ documents+: `abstract-title`++ title of abstract, currently used only in HTML, EPUB, and docx. This+ will be set automatically to a localized value, depending on `lang`,+ but can be manually overridden.+: `keywords`++ list of keywords to be included in HTML, PDF, ODT, pptx, docx and+ AsciiDoc metadata; repeat as for `author`, above+: `subject`++ document subject, included in ODT, PDF, docx, EPUB, and pptx metadata+: `description`++ document description, included in ODT, docx and pptx metadata. Some+ applications show this as `Comments` metadata.+: `category`++ document category, included in docx and pptx metadata++Additionally, any root-level string metadata, not included in ODT, docx+or pptx metadata is added as a _custom property_. The following+[YAML](https://yaml.org/spec/1.2/spec.html){title="YAML v1.2 Spec"}+metadata block for instance:++```+---+title: 'This is the title'+subtitle: "This is the subtitle"+author:+- Author One+- Author Two+description: |+ This is a long+ description.++ It consists of two paragraphs+...+```++will include `title`, `author` and `description` as standard document+properties and `subtitle` as a custom property when converting to docx,+ODT or pptx.++{#language-variables}+### Language variables++: `lang`++ identifies the main language of the document using IETF language tags+ (following the [BCP 47](https://tools.ietf.org/html/bcp47) standard),+ such as `en` or `en-GB`. The [Language subtag+ lookup](https://r12a.github.io/app-subtags/) tool can look up or+ verify these tags. This affects most formats, and controls hyphenation+ in PDF output when using LaTeX (through+ [`babel`](https://ctan.org/pkg/babel) and+ [`polyglossia`](https://ctan.org/pkg/polyglossia)) or ConTeXt.++ Use native pandoc [Divs and Spans](#divs-and-spans) with the `lang`+ attribute to switch the language:++ ```+ ---+ lang: en-GB+ ...++ Text in the main document language (British English).++ ::: {lang=fr-CA}+ > Cette citation est écrite en français canadien.+ :::++ More text in English. ['Zitat auf Deutsch.']{lang=de}+ ```+: `dir`++ the base script direction, either `rtl` (right-to-left) or `ltr`+ (left-to-right).++ For bidirectional documents, native pandoc `span`s and `div`s with the+ `dir` attribute (value `rtl` or `ltr`) can be used to override the+ base direction in some output formats. This may not always be+ necessary if the final renderer (e.g. the browser, when generating+ HTML) supports the [Unicode Bidirectional+ Algorithm](https://www.w3.org/International/articles/inline-bidi-markup/uba-basics).++ When using LaTeX for bidirectional documents, only the `xelatex`+ engine is fully supported (use `--pdf-engine=xelatex`).++{#variables-for-html}+### Variables for HTML++: `document-css`++ Enables inclusion of most of the+ [CSS](https://developer.mozilla.org/en-US/docs/Learn/CSS) in the+ `styles.html` [partial](#partials) (have a look with+ `pandoc --print-default-data-file=templates/styles.html`). Unless you+ use [`--css`](#option--css), this variable is set to `true` by+ default. You can disable it with e.g. `pandoc -M document-css=false`.+: `mainfont`++ sets the CSS `font-family` property on the `html` element.+: `fontsize`++ sets the base CSS `font-size`, which you’d usually set to e.g. `20px`,+ but it also accepts `pt` (12pt = 16px in most browsers).+: `fontcolor`++ sets the CSS `color` property on the `html` element.+: `linkcolor`++ sets the CSS `color` property on all links.+: `monofont`++ sets the CSS `font-family` property on `code` elements.+: `monobackgroundcolor`++ sets the CSS `background-color` property on `code` elements and adds+ extra padding.+: `linestretch`++ sets the CSS `line-height` property on the `html` element, which is+ preferred to be unitless.+: `maxwidth`++ sets the CSS `max-width` property (default is 32em).+: `backgroundcolor`++ sets the CSS `background-color` property on the `html` element.+: `margin-left`, `margin-right`, `margin-top`, `margin-bottom`++ sets the corresponding CSS `padding` properties on the `body` element.++To override or extend some+[CSS](https://developer.mozilla.org/en-US/docs/Learn/CSS) for just one+document, include for example:++```+---+header-includes: |+ <style>+ blockquote {+ font-style: italic;+ }+ tr.even {+ background-color: #f0f0f0;+ }+ td, th {+ padding: 0.5em 2em 0.5em 0.5em;+ }+ tbody {+ border-bottom: none;+ }+ </style>+---+```++{#variables-for-html-math}+### Variables for HTML math++: `classoption`++ when using [KaTeX](#option--katex), you can render display math+ equations flush left using [YAML metadata](#layout) or with+ `-M classoption=fleqn`.++{#variables-for-html-slides}+### Variables for HTML slides++These affect HTML output when [producing slide shows with+pandoc](#slide-shows).++: `institute`++ author affiliations: can be a list when there are multiple authors+: `revealjs-url`++ base URL for reveal.js documents (defaults to+ `https://unpkg.com/reveal.js@^4/`)+: `s5-url`++ base URL for S5 documents (defaults to `s5/default`)+: `slidy-url`++ base URL for Slidy documents (defaults to+ `https://www.w3.org/Talks/Tools/Slidy2`)+: `slideous-url`++ base URL for Slideous documents (defaults to `slideous`)+: `title-slide-attributes`++ additional attributes for the title slide of reveal.js slide shows.+ See [background in reveal.js, beamer, and+ pptx](#background-in-reveal.js-beamer-and-pptx) for an example.++All [reveal.js configuration options](https://revealjs.com/config/) are+available as variables. To turn off boolean flags that default to true+in reveal.js, use `0`.++{#variables-for-beamer-slides}+### Variables for Beamer slides++These variables change the appearance of PDF slides using+[`beamer`](https://ctan.org/pkg/beamer).++: `aspectratio`++ slide aspect ratio (`43` for 4:3 \[default\], `169` for 16:9, `1610`+ for 16:10, `149` for 14:9, `141` for 1.41:1, `54` for 5:4, `32` for+ 3:2)+: `beameroption`++ add extra beamer option with `\setbeameroption{}`+: `institute`++ author affiliations: can be a list when there are multiple authors+: `logo`++ logo image for slides+: `navigation`++ controls navigation symbols (default is `empty` for no navigation+ symbols; other valid values are `frame`, `vertical`, and `horizontal`)+: `section-titles`++ enables "title pages" for new sections (default is true)+: `theme`, `colortheme`, `fonttheme`, `innertheme`, `outertheme`++ beamer themes+: `themeoptions`++ options for LaTeX beamer themes (a list).+: `titlegraphic`++ image for title slide++{#variables-for-powerpoint}+### Variables for PowerPoint++These variables control the visual aspects of a slide show that are not+easily controlled via templates.++: `monofont`++ font to use for code.++{#variables-for-latex}+### Variables for LaTeX++Pandoc uses these variables when [creating a PDF](#creating-a-pdf) with+a LaTeX engine.++{#layout}+#### Layout++: `block-headings`++ make `\paragraph` and `\subparagraph` (fourth- and fifth-level+ headings, or fifth- and sixth-level with book classes) free-standing+ rather than run-in; requires further formatting to distinguish from+ `\subsubsection` (third- or fourth-level headings). Instead of using+ this option, [KOMA-Script](https://ctan.org/pkg/koma-script) can+ adjust headings more extensively:++ ```+ ---+ documentclass: scrartcl+ header-includes: |+ \RedeclareSectionCommand[+ beforeskip=-10pt plus -2pt minus -1pt,+ afterskip=1sp plus -1sp minus 1sp,+ font=\normalfont\itshape]{paragraph}+ \RedeclareSectionCommand[+ beforeskip=-10pt plus -2pt minus -1pt,+ afterskip=1sp plus -1sp minus 1sp,+ font=\normalfont\scshape,+ indent=0pt]{subparagraph}+ ...+ ```+: `classoption`++ option for document class, e.g. `oneside`; repeat for multiple+ options:++ ```+ ---+ classoption:+ - twocolumn+ - landscape+ ...+ ```+: `documentclass`++ document class: usually one of the standard classes,+ [`article`](https://ctan.org/pkg/article),+ [`book`](https://ctan.org/pkg/book), and+ [`report`](https://ctan.org/pkg/report); the+ [KOMA-Script](https://ctan.org/pkg/koma-script) equivalents,+ `scrartcl`, `scrbook`, and `scrreprt`, which default to smaller+ margins; or [`memoir`](https://ctan.org/pkg/memoir)+: `geometry`++ option for [`geometry`](https://ctan.org/pkg/geometry) package,+ e.g. `margin=1in`; repeat for multiple options:++ ```+ ---+ geometry:+ - top=30mm+ - left=20mm+ - heightrounded+ ...+ ```+: `hyperrefoptions`++ option for [`hyperref`](https://ctan.org/pkg/hyperref) package,+ e.g. `linktoc=all`; repeat for multiple options:++ ```+ ---+ hyperrefoptions:+ - linktoc=all+ - pdfwindowui+ - pdfpagemode=FullScreen+ ...+ ```+: `indent`++ if true, pandoc will use document class settings for indentation (the+ default LaTeX template otherwise removes indentation and adds space+ between paragraphs)+: `linestretch`++ adjusts line spacing using the+ [`setspace`](https://ctan.org/pkg/setspace) package, e.g. `1.25`,+ `1.5`+: `margin-left`, `margin-right`, `margin-top`, `margin-bottom`++ sets margins if `geometry` is not used (otherwise `geometry` overrides+ these)+: `pagestyle`++ control `\pagestyle{}`: the default article class supports `plain`+ (default), `empty` (no running heads or page numbers), and `headings`+ (section titles in running heads)+: `papersize`++ paper size, e.g. `letter`, `a4`+: `secnumdepth`++ numbering depth for sections (with `--number-sections` option or+ `numbersections` variable)+: `beamerarticle`++ produce an article from Beamer slides++{#fonts}+#### Fonts++: `fontenc`++ allows font encoding to be specified through `fontenc` package (with+ `pdflatex`); default is `T1` (see [LaTeX font encodings+ guide](https://ctan.org/pkg/encguide))+: `fontfamily`++ font package for use with `pdflatex`: [TeX+ Live](https://www.tug.org/texlive/) includes many options, documented+ in the [LaTeX Font Catalogue](https://tug.org/FontCatalogue/). The+ default is [Latin Modern](https://ctan.org/pkg/lm).+: `fontfamilyoptions`++ options for package used as `fontfamily`; repeat for multiple options.+ For example, to use the Libertine font with proportional lowercase+ (old-style) figures through the+ [`libertinus`](https://ctan.org/pkg/libertinus) package:++ ```+ ---+ fontfamily: libertinus+ fontfamilyoptions:+ - osf+ - p+ ...+ ```+: `fontsize`++ font size for body text. The standard classes allow 10pt, 11pt, and+ 12pt. To use another size, set `documentclass` to one of the+ [KOMA-Script](https://ctan.org/pkg/koma-script) classes, such as+ `scrartcl` or `scrbook`.+: `mainfont`, `sansfont`, `monofont`, `mathfont`, `CJKmainfont`,+ `CJKsansfont`, `CJKmonofont`++ font families for use with `xelatex` or `lualatex`: take the name of+ any system font, using the [`fontspec`](https://ctan.org/pkg/fontspec)+ package. `CJKmainfont` uses the [`xecjk`](https://ctan.org/pkg/xecjk)+ package.+: `mainfontoptions`, `sansfontoptions`, `monofontoptions`,+ `mathfontoptions`, `CJKoptions`++ options to use with `mainfont`, `sansfont`, `monofont`, `mathfont`,+ `CJKmainfont` in `xelatex` and `lualatex`. Allow for any choices+ available through [`fontspec`](https://ctan.org/pkg/fontspec); repeat+ for multiple options. For example, to use the [TeX+ Gyre](http://www.gust.org.pl/projects/e-foundry/tex-gyre) version of+ Palatino with lowercase figures:++ ```+ ---+ mainfont: TeX Gyre Pagella+ mainfontoptions:+ - Numbers=Lowercase+ - Numbers=Proportional+ ...+ ```+: `babelfonts`++ a map of Babel language names (e.g. `chinese`) to the font to be used+ with the language:++ * * * * *++ babelfonts: chinese-hant: "Noto Serif CJK TC" russian: "Noto Serif" …+: `microtypeoptions`++ options to pass to the microtype package++{#links}+#### Links++: `colorlinks`++ add color to link text; automatically enabled if any of `linkcolor`,+ `filecolor`, `citecolor`, `urlcolor`, or `toccolor` are set+: `boxlinks`++ add visible box around links (has no effect if `colorlinks` is set)+: `linkcolor`, `filecolor`, `citecolor`, `urlcolor`, `toccolor`++ color for internal links, external links, citation links, linked URLs,+ and links in table of contents, respectively: uses options allowed by+ [`xcolor`](https://ctan.org/pkg/xcolor), including the `dvipsnames`,+ `svgnames`, and `x11names` lists+: `links-as-notes`++ causes links to be printed as footnotes+: `urlstyle`++ style for URLs (e.g., `tt`, `rm`, `sf`, and, the default, `same`)++{#front-matter}+#### Front matter++: `lof`, `lot`++ include list of figures, list of tables+: `thanks`++ contents of acknowledgments footnote after document title+: `toc`++ include table of contents (can also be set using+ `--toc/--table-of-contents`)+: `toc-depth`++ level of section to include in table of contents++{#biblatex-bibliographies}+#### BibLaTeX Bibliographies++These variables function when using BibLaTeX for [citation+rendering](#citation-rendering).++: `biblatexoptions`++ list of options for biblatex+: `biblio-style`++ bibliography style, when used with `--natbib` and `--biblatex`+: `biblio-title`++ bibliography title, when used with `--natbib` and `--biblatex`+: `bibliography`++ bibliography to use for resolving references+: `natbiboptions`++ list of options for natbib++{#variables-for-context}+### Variables for ConTeXt++Pandoc uses these variables when [creating a PDF](#creating-a-pdf) with+ConTeXt.++: `fontsize`++ font size for body text (e.g. `10pt`, `12pt`)+: `headertext`, `footertext`++ text to be placed in running header or footer (see [ConTeXt Headers+ and Footers](https://wiki.contextgarden.net/Headers_and_Footers));+ repeat up to four times for different placement+: `indenting`++ controls indentation of paragraphs, e.g. `yes,small,next` (see+ [ConTeXt Indentation](https://wiki.contextgarden.net/Indentation));+ repeat for multiple options+: `interlinespace`++ adjusts line spacing, e.g. `4ex` (using+ [`setupinterlinespace`](https://wiki.contextgarden.net/Command/setupinterlinespace));+ repeat for multiple options+: `layout`++ options for page margins and text arrangement (see [ConTeXt+ Layout](https://wiki.contextgarden.net/Layout)); repeat for multiple+ options+: `linkcolor`, `contrastcolor`++ color for links outside and inside a page, e.g. `red`, `blue` (see+ [ConTeXt Color](https://wiki.contextgarden.net/Color))+: `linkstyle`++ typeface style for links, e.g. `normal`, `bold`, `slanted`,+ `boldslanted`, `type`, `cap`, `small`+: `lof`, `lot`++ include list of figures, list of tables+: `mainfont`, `sansfont`, `monofont`, `mathfont`++ font families: take the name of any system font (see [ConTeXt Font+ Switching](https://wiki.contextgarden.net/Font_Switching))+: `margin-left`, `margin-right`, `margin-top`, `margin-bottom`++ sets margins, if `layout` is not used (otherwise `layout` overrides+ these)+: `pagenumbering`++ page number style and location (using+ [`setuppagenumbering`](https://wiki.contextgarden.net/Command/setuppagenumbering));+ repeat for multiple options+: `papersize`++ paper size, e.g. `letter`, `A4`, `landscape` (see [ConTeXt Paper+ Setup](https://wiki.contextgarden.net/PaperSetup)); repeat for+ multiple options+: `pdfa`++ adds to the preamble the setup necessary to generate PDF/A of the type+ specified, e.g. `1a:2005`, `2a`. If no type is specified (i.e. the+ value is set to True, by e.g. `--metadata=pdfa` or `pdfa: true` in a+ YAML metadata block), `1b:2005` will be used as default, for reasons+ of backwards compatibility. Using `--variable=pdfa` without specified+ value is not supported. To successfully generate PDF/A the required+ ICC color profiles have to be available and the content and all+ included files (such as images) have to be standard-conforming. The+ ICC profiles and output intent may be specified using the variables+ `pdfaiccprofile` and `pdfaintent`. See also [ConTeXt+ PDFA](https://wiki.contextgarden.net/PDF/A) for more details.+: `pdfaiccprofile`++ when used in conjunction with `pdfa`, specifies the ICC profile to use+ in the PDF, e.g. `default.cmyk`. If left unspecified, `sRGB.icc` is+ used as default. May be repeated to include multiple profiles. Note+ that the profiles have to be available on the system. They can be+ obtained from [ConTeXt ICC+ Profiles](https://wiki.contextgarden.net/PDFX#ICC_profiles).+: `pdfaintent`++ when used in conjunction with `pdfa`, specifies the output intent for+ the colors, e.g. `ISO coated v2 300\letterpercent\space (ECI)` If left+ unspecified, `sRGB IEC61966-2.1` is used as default.+: `toc`++ include table of contents (can also be set using+ `--toc/--table-of-contents`)+: `urlstyle`++ typeface style for links without link text, e.g. `normal`, `bold`,+ `slanted`, `boldslanted`, `type`, `cap`, `small`+: `whitespace`++ spacing between paragraphs, e.g. `none`, `small` (using+ [`setupwhitespace`](https://wiki.contextgarden.net/Command/setupwhitespace))+: `includesource`++ include all source documents as file attachments in the PDF file++{#variables-for-wkhtmltopdf}+### Variables for `wkhtmltopdf`++Pandoc uses these variables when [creating a PDF](#creating-a-pdf) with+[`wkhtmltopdf`](https://wkhtmltopdf.org). The `--css` option also+affects the output.++: `footer-html`, `header-html`++ add information to the header and footer+: `margin-left`, `margin-right`, `margin-top`, `margin-bottom`++ set the page margins+: `papersize`++ sets the PDF paper size++{#variables-for-man-pages}+### Variables for man pages++: `adjusting`++ adjusts text to left (`l`), right (`r`), center (`c`), or both (`b`)+ margins+: `footer`++ footer in man pages+: `header`++ header in man pages+: `hyphenate`++ if `true` (the default), hyphenation will be used+: `section`++ section number in man pages++{#variables-for-typst}+### Variables for Typst++: `margin`++ A dictionary with the fields defined in the Typst documentation: `x`,+ `y`, `top`, `bottom`, `left`, `right`.+: `papersize`++ Paper size: `a4`, `us-letter`, etc.+: `mainfont`++ Name of system font to use for the main font.+: `fontsize`++ Font size (e.g., `12pt`).+: `section-numbering`++ Schema to use for numbering sections, e.g. `1.A.1`.+: `columns`++ Number of columns for body text.++{#variables-for-ms}+### Variables for ms++: `fontfamily`++ `A` (Avant Garde), `B` (Bookman), `C` (Helvetica), `HN` (Helvetica+ Narrow), `P` (Palatino), or `T` (Times New Roman). This setting does+ not affect source code, which is always displayed using monospace+ Courier. These built-in fonts are limited in their coverage of+ characters. Additional fonts may be installed using the script+ [`install-font.sh`](https://www.schaffter.ca/mom/bin/install-font.sh)+ provided by Peter Schaffter and documented in detail on [his web+ site](https://www.schaffter.ca/mom/momdoc/appendices.html#steps).+: `indent`++ paragraph indent (e.g. `2m`)+: `lineheight`++ line height (e.g. `12p`)+: `pointsize`++ point size (e.g. `10p`)++{#variables-set-automatically}+### Variables set automatically++Pandoc sets these variables automatically in response to+[options](#options) or document contents; users can also modify them.+These vary depending on the output format, and include the following:++: `body`++ body of document+: `date-meta`++ the `date` variable converted to ISO 8601 YYYY-MM-DD, included in all+ HTML based formats (dzslides, epub, html, html4, html5, revealjs, s5,+ slideous, slidy). The recognized formats for `date` are: `mm/dd/yyyy`,+ `mm/dd/yy`, `yyyy-mm-dd` (ISO 8601), `dd MM yyyy` (e.g. either+ `02 Apr 2018` or `02 April 2018`), `MM dd, yyyy` (e.g. `Apr. 02, 2018`+ or `April 02, 2018),`yyyy\[mm\[dd\]\]`(e.g.`20180402, `201804` or+ `2018`).+: `header-includes`++ contents specified by `-H/--include-in-header` (may have multiple+ values)+: `include-before`++ contents specified by `-B/--include-before-body` (may have multiple+ values)+: `include-after`++ contents specified by `-A/--include-after-body` (may have multiple+ values)+: `meta-json`++ JSON representation of all of the document’s metadata. Field values+ are transformed to the selected output format.+: `numbersections`++ non-null value if `-N/--number-sections` was specified+: `sourcefile`, `outputfile`++ source and destination filenames, as given on the command line.+ `sourcefile` can also be a list if input comes from multiple files, or+ empty if input is from stdin. You can use the following snippet in+ your template to distinguish them:++ ```+ $if(sourcefile)$+ $for(sourcefile)$+ $sourcefile$+ $endfor$+ $else$+ (stdin)+ $endif$+ ```++ Similarly, `outputfile` can be `-` if output goes to the terminal.++ If you need absolute paths, use e.g. `$curdir$/$sourcefile$`.+: `curdir`++ working directory from which pandoc is run.+: `pandoc-version`++ pandoc version.+: `toc`++ non-null value if `--toc/--table-of-contents` was specified+: `toc-title`++ title of table of contents (works only with EPUB, HTML, revealjs,+ opendocument, odt, docx, pptx, beamer, LaTeX)++{#extensions}+# Extensions++The behavior of some of the readers and writers can be adjusted by+enabling or disabling various extensions.++An extension can be enabled by adding `+EXTENSION` to the format name+and disabled by adding `-EXTENSION`. For example,+`--from markdown_strict+footnotes` is strict Markdown with footnotes+enabled, while `--from markdown-footnotes-pipe_tables` is pandoc’s+Markdown without footnotes or pipe tables.++The markdown reader and writer make by far the most use of extensions.+Extensions only used by them are therefore covered in the section+[Pandoc’s Markdown](#pandocs-markdown) below (see [Markdown+variants](#markdown-variants) for `commonmark` and `gfm`). In the+following, extensions that also work for other formats are covered.++Note that markdown extensions added to the `ipynb` format affect+Markdown cells in Jupyter notebooks (as do command-line options like+`--markdown-headings`).++{#typography}+## Typography++{#extension-smart}+#### Extension: `smart`++Interpret straight quotes as curly quotes, `---` as em-dashes, `--` as+en-dashes, and `...` as ellipses. Nonbreaking spaces are inserted after+certain abbreviations, such as "Mr."++This extension can be enabled/disabled for the following formats:++: input formats++ `markdown`, `commonmark`, `latex`, `mediawiki`, `org`, `rst`, `twiki`,+ `html`+: output formats++ `markdown`, `latex`, `context`, `rst`+: enabled by default in++ `markdown`, `latex`, `context` (both input and output)++Note: If you are _writing_ Markdown, then the `smart` extension has the+reverse effect: what would have been curly quotes comes out straight.++In LaTeX, `smart` means to use the standard TeX ligatures for quotation+marks (` `` ` and `''` for double quotes, `` ` `` and `'` for single+quotes) and dashes (`--` for en-dash and `---` for em-dash). If `smart`+is disabled, then in reading LaTeX pandoc will parse these characters+literally. In writing LaTeX, enabling `smart` tells pandoc to use the+ligatures when possible; if `smart` is disabled pandoc will use unicode+quotation mark and dash characters.++{#headings-and-sections}+## Headings and sections++{#extension-auto_identifiers}+#### Extension: `auto_identifiers`++A heading without an explicitly specified identifier will be+automatically assigned a unique identifier based on the heading text.++This extension can be enabled/disabled for the following formats:++: input formats++ `markdown`, `latex`, `rst`, `mediawiki`, `textile`+: output formats++ `markdown`, `muse`+: enabled by default in++ `markdown`, `muse`++The default algorithm used to derive the identifier from the heading+text is:++- Remove all formatting, links, etc.+- Remove all footnotes.+- Remove all non-alphanumeric characters, except underscores, hyphens,+ and periods.+- Replace all spaces and newlines with hyphens.+- Convert all alphabetic characters to lowercase.+- Remove everything up to the first letter (identifiers may not begin+ with a number or punctuation mark).+- If nothing is left after this, use the identifier `section`.++Thus, for example,++|Heading|Identifier|+|:--|:--|+|`Heading identifiers in HTML`|`heading-identifiers-in-html`|+|`Maître d'hôtel`|`maître-dhôtel`|+|`*Dogs*?--in *my* house?`|`dogs--in-my-house`|+|`[HTML], [S5], or [RTF]?`|`html-s5-or-rtf`|+|`3. Applications`|`applications`|+|`33`|`section`|++These rules should, in most cases, allow one to determine the identifier+from the heading text. The exception is when several headings have the+same text; in this case, the first will get an identifier as described+above; the second will get the same identifier with `-1` appended; the+third with `-2`; and so on.++(However, a different algorithm is used if `gfm_auto_identifiers` is+enabled; see below.)++These identifiers are used to provide link targets in the table of+contents generated by the `--toc|--table-of-contents` option. They also+make it easy to provide links from one section of a document to another.+A link to this section, for example, might look like this:++```+See the section on+[heading identifiers](#heading-identifiers-in-html-latex-and-context).+```++Note, however, that this method of providing links to sections works+only in HTML, LaTeX, and ConTeXt formats.++If the `--section-divs` option is specified, then each section will be+wrapped in a `section` (or a `div`, if `html4` was specified), and the+identifier will be attached to the enclosing `<section>` (or `<div>`)+tag rather than the heading itself. This allows entire sections to be+manipulated using JavaScript or treated differently in CSS.++{#extension-ascii_identifiers}+#### Extension: `ascii_identifiers`++Causes the identifiers produced by `auto_identifiers` to be pure ASCII.+Accents are stripped off of accented Latin letters, and non-Latin+letters are omitted.++{#extension-gfm_auto_identifiers}+#### Extension: `gfm_auto_identifiers`++Changes the algorithm used by `auto_identifiers` to conform to GitHub’s+method. Spaces are converted to dashes (`-`), uppercase characters to+lowercase characters, and punctuation characters other than `-` and `_`+are removed. Emojis are replaced by their names.++{#math-input}+## Math Input++The extensions [`tex_math_dollars`](#extension-tex_math_dollars),+[`tex_math_single_backslash`](#extension-tex_math_single_backslash), and+[`tex_math_double_backslash`](#extension-tex_math_double_backslash) are+described in the section about Pandoc’s Markdown.++However, they can also be used with HTML input. This is handy for+reading web pages formatted using MathJax, for example.++{#raw-htmltex}+## Raw HTML/TeX++The following extensions are described in more detail in their+respective sections of [Pandoc’s Markdown](#pandocs-markdown):++- [`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.++- [`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`):++ : input formats++ `latex`, `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`.++- [`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}+## Literate Haskell support++{#extension-literate_haskell}+#### Extension: `literate_haskell`++Treat the document as literate Haskell source.++This extension can be enabled/disabled for the following formats:++: input formats++ `markdown`, `rst`, `latex`+: output formats++ `markdown`, `rst`, `latex`, `html`++If you append `+lhs` (or `+literate_haskell`) to one of the formats+above, pandoc will treat the document as literate Haskell source. This+means that++- In Markdown input, "bird track" sections will be parsed as Haskell+ code rather than block quotations. Text between `\begin{code}` and+ `\end{code}` will also be treated as Haskell code. For ATX-style+ headings the character '=' will be used instead of '#'.++- In Markdown output, code blocks with classes `haskell` and `literate`+ will be rendered using bird tracks, and block quotations will be+ indented one space, so they will not be treated as Haskell code. In+ addition, headings will be rendered setext-style (with underlines)+ rather than ATX-style (with '#' characters). (This is because ghc+ treats '#' characters in column 1 as introducing line numbers.)++- In restructured text input, "bird track" sections will be parsed as+ Haskell code.++- In restructured text output, code blocks with class `haskell` will be+ rendered using bird tracks.++- In LaTeX input, text in `code` environments will be parsed as Haskell+ code.++- In LaTeX output, code blocks with class `haskell` will be rendered+ inside `code` environments.++- In HTML output, code blocks with class `haskell` will be rendered with+ class `literatehaskell` and bird tracks.++Examples:++```+pandoc -f markdown+lhs -t html+```++reads literate Haskell source formatted with Markdown conventions and+writes ordinary HTML (without bird tracks).++```+pandoc -f markdown+lhs -t html+lhs+```++writes HTML with the Haskell code in bird tracks, so it can be copied+and pasted as literate Haskell source.++Note that GHC expects the bird tracks in the first column, so indented+literate code blocks (e.g. inside an itemized environment) will not be+picked up by the Haskell compiler.++{#other-extensions}+## Other extensions++{#extension-empty_paragraphs}+#### Extension: `empty_paragraphs`++Allows empty paragraphs. By default empty paragraphs are omitted.++This extension can be enabled/disabled for the following formats:++: input formats++ `docx`, `html`+: output formats++ `docx`, `odt`, `opendocument`, `html`++{#extension-native_numbering}+#### Extension: `native_numbering`++Enables native numbering of figures and tables. Enumeration starts at 1.++This extension can be enabled/disabled for the following formats:++: output formats++ `odt`, `opendocument`, `docx`++{#extension-xrefs_name}+#### Extension: `xrefs_name`++Links to headings, figures and tables inside the document are+substituted with cross-references that will use the name or caption of+the referenced item. The original link text is replaced once the+generated document is refreshed. This extension can be combined with+`xrefs_number` in which case numbers will appear before the name.++Text in cross-references is only made consistent with the referenced+item once the document has been refreshed.++This extension can be enabled/disabled for the following formats:++: output formats++ `odt`, `opendocument`++{#extension-xrefs_number}+#### Extension: `xrefs_number`++Links to headings, figures and tables inside the document are+substituted with cross-references that will use the number of the+referenced item. The original link text is discarded. This extension can+be combined with `xrefs_name` in which case the name or caption numbers+will appear after the number.++For the `xrefs_number` to be useful heading numbers must be enabled in+the generated document, also table and figure captions must be enabled+using for example the `native_numbering` extension.++Numbers in cross-references are only visible in the final document once+it has been refreshed.++This extension can be enabled/disabled for the following formats:++: output formats++ `odt`, `opendocument`++{#ext-styles}+#### Extension: `styles`++When converting from docx, read all docx styles as divs (for paragraph+styles) and spans (for character styles) regardless of whether pandoc+understands the meaning of these styles. This can be used with [docx+custom styles](#custom-styles). Disabled by default.++: input formats++ `docx`++{#extension-amuse}+#### Extension: `amuse`++In the `muse` input format, this enables Text::Amuse extensions to Emacs+Muse markup.++{#extension-raw_markdown}+#### 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 targeting `ipynb` or a+markdown-based output format.++{#org-citations}+#### Extension: `citations`++When the `citations` extension is enabled in `org`, org-cite and org-ref+style citations will be parsed as native pandoc citations.++When `citations` is enabled in `docx`, citations inserted by Zotero or+Mendeley or EndNote plugins will be parsed as native pandoc citations.+(Otherwise, the formatted citations generated by the bibliographic+software will be parsed as regular text.)++{#org-fancy-lists}+#### Extension: `fancy_lists`++Some aspects of [Pandoc’s Markdown fancy lists](#extension-fancy_lists)+are also accepted in `org` input, mimicking the option+`org-list-allow-alphabetical` in Emacs. As in Org Mode, enabling this+extension allows lowercase and uppercase alphabetical markers for+ordered lists to be parsed in addition to arabic ones. Note that for+Org, this does not include roman numerals or the `#` placeholder that+are enabled by the extension in Pandoc’s Markdown.++{#extension-element_citations}+#### Extension: `element_citations`++In the `jats` output formats, this causes reference items to be replaced+with `<element-citation>` elements. These elements are not influenced by+CSL styles, but all information on the item is included in tags.++{#extension-ntb}+#### Extension: `ntb`++In the `context` output format this enables the use of [Natural Tables+(TABLE)](https://wiki.contextgarden.net/TABLE) instead of the default+[Extreme Tables (xtables)](https://wiki.contextgarden.net/xtables).+Natural tables allow more fine-grained global customization but come at+a performance penalty compared to extreme tables.++{#extension-tagging}+#### Extension: `tagging`++Enabling this extension with `context` output will produce markup+suitable for the production of tagged PDFs. This includes additional+markers for paragraphs and alternative markup for emphasized text. The+`emphasis-command` template variable is set if the extension is enabled.++{#pandocs-markdown}+# Pandoc’s Markdown++Pandoc understands an extended and slightly revised version of John+Gruber’s [Markdown](https://daringfireball.net/projects/markdown/)+syntax. This document explains the syntax, noting differences from+original Markdown. Except where noted, these differences can be+suppressed by using the `markdown_strict` format instead of `markdown`.+Extensions can be enabled or disabled to specify the behavior more+granularly. They are described in the following. See also+[Extensions](#extensions) above, for extensions that work also on other+formats.++{#philosophy}+## Philosophy++Markdown is designed to be easy to write, and, even more importantly,+easy to read:++> A Markdown-formatted document should be publishable as-is, as plain+> text, without looking like it’s been marked up with tags or formatting+> instructions. – [John+> Gruber](https://daringfireball.net/projects/markdown/syntax#philosophy)++This principle has guided pandoc’s decisions in finding syntax for+tables, footnotes, and other extensions.++There is, however, one respect in which pandoc’s aims are different from+the original aims of Markdown. Whereas Markdown was originally designed+with HTML generation in mind, pandoc is designed for multiple output+formats. Thus, while pandoc allows the embedding of raw HTML, it+discourages it, and provides other, non-HTMLish ways of representing+important document elements like definition lists, tables, mathematics,+and footnotes.++{#paragraphs}+## Paragraphs++A paragraph is one or more lines of text followed by one or more blank+lines. Newlines are treated as spaces, so you can reflow your paragraphs+as you like. If you need a hard line break, put two or more spaces at+the end of a line.++{#extension-escaped_line_breaks}+#### Extension: `escaped_line_breaks`++A backslash followed by a newline is also a hard line break. Note: in+multiline and grid table cells, this is the only way to create a hard+line break, since trailing spaces in the cells are ignored.++{#headings}+## Headings++There are two kinds of headings: Setext and ATX.++{#setext-style-headings}+### Setext-style headings++A setext-style heading is a line of text "underlined" with a row of `=`+signs (for a level-one heading) or `-` signs (for a level-two heading):++```+A level-one heading+===================++A level-two heading+-------------------+```++The heading text can contain inline formatting, such as emphasis (see+[Inline formatting](#inline-formatting), below).++{#atx-style-headings}+### ATX-style headings++An ATX-style heading consists of one to six `#` signs and a line of+text, optionally followed by any number of `#` signs. The number of `#`+signs at the beginning of the line is the heading level:++```+## A level-two heading++### A level-three heading ###+```++As with setext-style headings, the heading text can contain formatting:++```+# A level-one heading with a [link](/url) and *emphasis*+```++{#extension-blank_before_header}+#### Extension: `blank_before_header`++Original Markdown syntax does not require a blank line before a heading.+Pandoc does require this (except, of course, at the beginning of the+document). The reason for the requirement is that it is all too easy for+a `#` to end up at the beginning of a line by accident (perhaps through+line wrapping). Consider, for example:++```+I like several of their flavors of ice cream:+#22, for example, and #5.+```++{#extension-space_in_atx_header}+#### Extension: `space_in_atx_header`++Many Markdown implementations do not require a space between the opening+`#`s of an ATX heading and the heading text, so that `#5 bolt` and+`#hashtag` count as headings. With this extension, pandoc does require+the space.++{#heading-identifiers}+### Heading identifiers++See also the [`auto_identifiers` extension](#extension-auto_identifiers)+above.++{#extension-header_attributes}+#### Extension: `header_attributes`++Headings can be assigned attributes using this syntax at the end of the+line containing the heading text:++```+{#identifier .class .class key=value key=value}+```++Thus, for example, the following headings will all be assigned the+identifier `foo`:++```+# My heading {#foo}++## My heading ## {#foo}++My other heading {#foo}+---------------+```++(This syntax is compatible with [PHP Markdown+Extra](https://michelf.ca/projects/php-markdown/extra/).)++Note that although this syntax allows assignment of classes and+key/value attributes, writers generally don’t use all of this+information. Identifiers, classes, and key/value attributes are used in+HTML and HTML-based formats such as EPUB and slidy. Identifiers are used+for labels and link anchors in the LaTeX, ConTeXt, Textile, Jira markup,+and AsciiDoc writers.++Headings with the class `unnumbered` will not be numbered, even if+`--number-sections` is specified. A single hyphen (`-`) in an attribute+context is equivalent to `.unnumbered`, and preferable in non-English+documents. So,++```+# My heading {-}+```++is just the same as++```+# My heading {.unnumbered}+```++If the `unlisted` class is present in addition to `unnumbered`, the+heading will not be included in a table of contents. (Currently this+feature is only implemented for certain formats: those based on LaTeX+and HTML, PowerPoint, and RTF.)++{#extension-implicit_header_references}+#### Extension: `implicit_header_references`++Pandoc behaves as if reference links have been defined for each heading.+So, to link to a heading++```+# Heading identifiers in HTML+```++you can simply write++```+[Heading identifiers in HTML]+```++or++```+[Heading identifiers in HTML][]+```++or++```+[the section on heading identifiers][heading identifiers in+HTML]+```++instead of giving the identifier explicitly:++```+[Heading identifiers in HTML](#heading-identifiers-in-html)+```++If there are multiple headings with identical text, the corresponding+reference will link to the first one only, and you will need to use+explicit links to link to the others, as described above.++Like regular reference links, these references are case-insensitive.++Explicit link reference definitions always take priority over implicit+heading references. So, in the following example, the link will point to+`bar`, not to `#foo`:++```+# Foo++[foo]: bar++See [foo]+```++{#block-quotations}+## Block quotations++Markdown uses email conventions for quoting blocks of text. A block+quotation is one or more paragraphs or other block elements (such as+lists or headings), with each line preceded by a `>` character and an+optional space. (The `>` need not start at the left margin, but it+should not be indented more than three spaces.)++```+> This is a block quote. This+> paragraph has two lines.+>+> 1. This is a list inside a block quote.+> 2. Second item.+```++A "lazy" form, which requires the `>` character only on the first line+of each block, is also allowed:++```+> This is a block quote. This+paragraph has two lines.++> 1. This is a list inside a block quote.+2. Second item.+```++Among the block elements that can be contained in a block quote are+other block quotes. That is, block quotes can be nested:++```+> This is a block quote.+>+> > A block quote within a block quote.+```++If the `>` character is followed by an optional space, that space will+be considered part of the block quote marker and not part of the+indentation of the contents. Thus, to put an indented code block in a+block quote, you need five spaces after the `>`:++```+> code+```++{#extension-blank_before_blockquote}+#### Extension: `blank_before_blockquote`++Original Markdown syntax does not require a blank line before a block+quote. Pandoc does require this (except, of course, at the beginning of+the document). The reason for the requirement is that it is all too easy+for a `>` to end up at the beginning of a line by accident (perhaps+through line wrapping). So, unless the `markdown_strict` format is used,+the following does not produce a nested block quote in pandoc:++```+> This is a block quote.+>> Not nested, since `blank_before_blockquote` is enabled by default+```++{#verbatim-code-blocks}+## Verbatim (code) blocks++{#indented-code-blocks}+### Indented code blocks++A block of text indented four spaces (or one tab) is treated as verbatim+text: that is, special characters do not trigger special formatting, and+all spaces and line breaks are preserved. For example,++```+ if (a > 3) {+ moveShip(5 * gravity, DOWN);+ }+```++The initial (four space or one tab) indentation is not considered part+of the verbatim text, and is removed in the output.++Note: blank lines in the verbatim text need not begin with four spaces.++{#fenced-code-blocks}+### Fenced code blocks++{#extension-fenced_code_blocks}+#### Extension: `fenced_code_blocks`++In addition to standard indented code blocks, pandoc supports _fenced_+code blocks. These begin with a row of three or more tildes (`~`) and+end with a row of tildes that must be at least as long as the starting+row. Everything between these lines is treated as code. No indentation+is necessary:++```+~~~~~~~+if (a > 3) {+ moveShip(5 * gravity, DOWN);+}+~~~~~~~+```++Like regular code blocks, fenced code blocks must be separated from+surrounding text by blank lines.++If the code itself contains a row of tildes or backticks, just use a+longer row of tildes or backticks at the start and end:++```+~~~~~~~~~~~~~~~~+~~~~~~~~~~+code including tildes+~~~~~~~~~~+~~~~~~~~~~~~~~~~+```++{#extension-backtick_code_blocks}+#### Extension: `backtick_code_blocks`++Same as `fenced_code_blocks`, but uses backticks (`` ` ``) instead of+tildes (`~`).++{#extension-fenced_code_attributes}+#### Extension: `fenced_code_attributes`++Optionally, you may attach attributes to fenced or backtick code block+using this syntax:++```+~~~~ {#mycode .haskell .numberLines startFrom="100"}+qsort [] = []+qsort (x:xs) = qsort (filter (< x) xs) ++ [x] +++ qsort (filter (>= x) xs)+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+```++Here `mycode` is an identifier, `haskell` and `numberLines` are classes,+and `startFrom` is an attribute with value `100`. Some output formats+can use this information to do syntax highlighting. Currently, the only+output formats that use this information are HTML, LaTeX, Docx, Ms, and+PowerPoint. If highlighting is supported for your output format and+language, then the code block above will appear highlighted, with+numbered lines. (To see which languages are supported, type+`pandoc --list-highlight-languages`.) Otherwise, the code block above+will appear as follows:++```+<pre id="mycode" class="haskell numberLines" startFrom="100">+ <code>+ ...+ </code>+</pre>+```++The `numberLines` (or `number-lines`) class will cause the lines of the+code block to be numbered, starting with `1` or the value of the+`startFrom` attribute. The `lineAnchors` (or `line-anchors`) class will+cause the lines to be clickable anchors in HTML output.++A shortcut form can also be used for specifying the language of the code+block:++````+```haskell+qsort [] = []+```+````++This is equivalent to:++````+``` {.haskell}+qsort [] = []+```+````++This shortcut form may be combined with attributes:++````+```haskell {.numberLines}+qsort [] = []+```+````++Which is equivalent to:++````+``` {.haskell .numberLines}+qsort [] = []+```+````++If the `fenced_code_attributes` extension is disabled, but input+contains class attribute(s) for the code block, the first class+attribute will be printed after the opening fence as a bare word.++To prevent all highlighting, use the `--no-highlight` flag. To set the+highlighting style, use `--highlight-style`. For more information on+highlighting, see [Syntax highlighting](#syntax-highlighting), below.++{#line-blocks}+## Line blocks++{#extension-line_blocks}+#### Extension: `line_blocks`++A line block is a sequence of lines beginning with a vertical bar (`|`)+followed by a space. The division into lines will be preserved in the+output, as will any leading spaces; otherwise, the lines will be+formatted as Markdown. This is useful for verse and addresses:++```+| The limerick packs laughs anatomical+| In space that is quite economical.+| But the good ones I've seen+| So seldom are clean+| And the clean ones so seldom are comical++| 200 Main St.+| Berkeley, CA 94718+```++The lines can be hard-wrapped if needed, but the continuation line must+begin with a space.++```+| The Right Honorable Most Venerable and Righteous Samuel L.+ Constable, Jr.+| 200 Main St.+| Berkeley, CA 94718+```++Inline formatting (such as emphasis) is allowed in the content, but not+block-level formatting (such as block quotes or lists).++This syntax is borrowed from+[reStructuredText](https://docutils.sourceforge.io/docs/ref/rst/introduction.html).++{#lists}+## Lists++{#bullet-lists}+### Bullet lists++A bullet list is a list of bulleted list items. A bulleted list item+begins with a bullet (`*`, `+`, or `-`). Here is a simple example:++```+* one+* two+* three+```++This will produce a "compact" list. If you want a "loose" list, in which+each item is formatted as a paragraph, put spaces between the items:++```+* one++* two++* three+```++The bullets need not be flush with the left margin; they may be indented+one, two, or three spaces. The bullet must be followed by whitespace.++List items look best if subsequent lines are flush with the first line+(after the bullet):++```+* here is my first+ list item.+* and my second.+```++But Markdown also allows a "lazy" format:++```+* here is my first+list item.+* and my second.+```++{#block-content-in-list-items}+### Block content in list items++A list item may contain multiple paragraphs and other block-level+content. However, subsequent paragraphs must be preceded by a blank line+and indented to line up with the first non-space content after the list+marker.++```+ * First paragraph.++ Continued.++ * Second paragraph. With a code block, which must be indented+ eight spaces:++ { code }+```++Exception: if the list marker is followed by an indented code block,+which must begin 5 spaces after the list marker, then subsequent+paragraphs must begin two columns after the last character of the list+marker:++```+* code++ continuation paragraph+```++List items may include other lists. In this case the preceding blank+line is optional. The nested list must be indented to line up with the+first non-space character after the list marker of the containing list+item.++```+* fruits+ + apples+ - macintosh+ - red delicious+ + pears+ + peaches+* vegetables+ + broccoli+ + chard+```++As noted above, Markdown allows you to write list items "lazily,"+instead of indenting continuation lines. However, if there are multiple+paragraphs or other blocks in a list item, the first line of each must+be indented.++```++ A lazy, lazy, list+item.+++ Another one; this looks+bad but is legal.++ Second paragraph of second+list item.+```++{#ordered-lists}+### Ordered lists++Ordered lists work just like bulleted lists, except that the items begin+with enumerators rather than bullets.++In original Markdown, enumerators are decimal numbers followed by a+period and a space. The numbers themselves are ignored, so there is no+difference between this list:++```+1. one+2. two+3. three+```++and this one:++```+5. one+7. two+1. three+```++{#extension-fancy_lists}+#### Extension: `fancy_lists`++Unlike original Markdown, pandoc allows ordered list items to be marked+with uppercase and lowercase letters and roman numerals, in addition to+Arabic numerals. List markers may be enclosed in parentheses or followed+by a single right-parenthesis or period. They must be separated from the+text that follows by at least one space, and, if the list marker is a+capital letter with a period, by at least two spaces.[^1]++The `fancy_lists` extension also allows '`#`' to be used as an ordered+list marker in place of a numeral:++```+#. one+#. two+```++Note: the '`#`' ordered list marker doesn’t work with `commonmark`.++{#extension-startnum}+#### Extension: `startnum`++Pandoc also pays attention to the type of list marker used, and to the+starting number, and both of these are preserved where possible in the+output format. Thus, the following yields a list with numbers followed+by a single parenthesis, starting with 9, and a sublist with lowercase+roman numerals:++```+ 9) Ninth+10) Tenth+11) Eleventh+ i. subone+ ii. subtwo+ iii. subthree+```++Pandoc will start a new list each time a different type of list marker+is used. So, the following will create three lists:++```+(2) Two+(5) Three+1. Four+* Five+```++If default list markers are desired, use `#.`:++```+#. one+#. two+#. three+```++{#extension-task_lists}+#### Extension: `task_lists`++Pandoc supports task lists, using the syntax of GitHub-Flavored+Markdown.++```+- [ ] an unchecked task list item+- [x] checked item+```++{#definition-lists}+### Definition lists++{#extension-definition_lists}+#### Extension: `definition_lists`++Pandoc supports definition lists, using the syntax of [PHP Markdown+Extra](https://michelf.ca/projects/php-markdown/extra/) with some+extensions.[^2]++```+Term 1++: Definition 1++Term 2 with *inline markup*++: Definition 2++ { some code, part of Definition 2 }++ Third paragraph of definition 2.+```++Each term must fit on one line, which may optionally be followed by a+blank line, and must be followed by one or more definitions. A+definition begins with a colon or tilde, which may be indented one or+two spaces.++A term may have multiple definitions, and each definition may consist of+one or more block elements (paragraph, code block, list, etc.), each+indented four spaces or one tab stop. The body of the definition (not+including the first line) should be indented four spaces. However, as+with other Markdown lists, you can "lazily" omit indentation except at+the beginning of a paragraph or other block element:++```+Term 1++: Definition+with lazy continuation.++ Second paragraph of the definition.+```++If you leave space before the definition (as in the example above), the+text of the definition will be treated as a paragraph. In some output+formats, this will mean greater spacing between term/definition pairs.+For a more compact definition list, omit the space before the+definition:++```+Term 1+ ~ Definition 1++Term 2+ ~ Definition 2a+ ~ Definition 2b+```++Note that space between items in a definition list is required. (A+variant that loosens this requirement, but disallows "lazy" hard+wrapping, can be activated with the [`compact_definition_lists`+extension](#extension-compact_definition_lists).)++{#numbered-example-lists}+### Numbered example lists++{#extension-example_lists}+#### Extension: `example_lists`++The special list marker `@` can be used for sequentially numbered+examples. The first list item with a `@` marker will be numbered '1',+the next '2', and so on, throughout the document. The numbered examples+need not occur in a single list; each new list using `@` will take up+where the last stopped. So, for example:++```+(@) My first example will be numbered (1).+(@) My second example will be numbered (2).++Explanation of examples.++(@) My third example will be numbered (3).+```++Numbered examples can be labeled and referred to elsewhere in the+document:++```+(@good) This is a good example.++As (@good) illustrates, ...+```++The label can be any string of alphanumeric characters, underscores, or+hyphens.++Note: continuation paragraphs in example lists must always be indented+four spaces, regardless of the length of the list marker. That is,+example lists always behave as if the `four_space_rule` extension is+set. This is because example labels tend to be long, and indenting+content to the first non-space character after the label would be+awkward.++{#ending-a-list}+### Ending a list++What if you want to put an indented code block after a list?++```+- item one+- item two++ { my code block }+```++Trouble! Here pandoc (like other Markdown implementations) will treat+`{ my code block }` as the second paragraph of item two, and not as a+code block.++To "cut off" the list after item two, you can insert some non-indented+content, like an HTML comment, which won’t produce visible output in any+format:++```+- item one+- item two++<!-- end of list -->++ { my code block }+```++You can use the same trick if you want two consecutive lists instead of+one big list:++```+1. one+2. two+3. three++<!-- -->++1. uno+2. dos+3. tres+```++{#horizontal-rules}+## Horizontal rules++A line containing a row of three or more `*`, `-`, or `_` characters+(optionally separated by spaces) produces a horizontal rule:++```+* * * *++---------------+```++We strongly recommend that horizontal rules be separated from+surrounding text by blank lines. If a horizontal rule is not followed by+a blank line, pandoc may try to interpret the lines that follow as a+YAML metadata block or a table.++{#tables}+## Tables++Four kinds of tables may be used. The first three kinds presuppose the+use of a fixed-width font, such as Courier. The fourth kind can be used+with proportionally spaced fonts, as it does not require lining up+columns.++{#extension-table_captions}+#### Extension: `table_captions`++A caption may optionally be provided with all 4 kinds of tables (as+illustrated in the examples below). A caption is a paragraph beginning+with the string `Table:` (or `table:` or just `:`), which will be+stripped off. It may appear either before or after the table.++{#extension-simple_tables}+#### Extension: `simple_tables`++Simple tables look like this:++```+ Right Left Center Default+------- ------ ---------- -------+ 12 12 12 12+ 123 123 123 123+ 1 1 1 1++Table: Demonstration of simple table syntax.+```++The header and table rows must each fit on one line. Column alignments+are determined by the position of the header text relative to the dashed+line below it:[^3]++- If the dashed line is flush with the header text on the right side but+ extends beyond it on the left, the column is right-aligned.+- If the dashed line is flush with the header text on the left side but+ extends beyond it on the right, the column is left-aligned.+- If the dashed line extends beyond the header text on both sides, the+ column is centered.+- If the dashed line is flush with the header text on both sides, the+ default alignment is used (in most cases, this will be left).++The table must end with a blank line, or a line of dashes followed by a+blank line.++The column header row may be omitted, provided a dashed line is used to+end the table. For example:++```+------- ------ ---------- -------+ 12 12 12 12+ 123 123 123 123+ 1 1 1 1+------- ------ ---------- -------+```++When the header row is omitted, column alignments are determined on the+basis of the first line of the table body. So, in the tables above, the+columns would be right, left, center, and right aligned, respectively.++{#extension-multiline_tables}+#### Extension: `multiline_tables`++Multiline tables allow header and table rows to span multiple lines of+text (but cells that span multiple columns or rows of the table are not+supported). Here is an example:++```+-------------------------------------------------------------+ Centered Default Right Left+ Header Aligned Aligned Aligned+----------- ------- --------------- -------------------------+ First row 12.0 Example of a row that+ spans multiple lines.++ Second row 5.0 Here's another one. Note+ the blank line between+ rows.+-------------------------------------------------------------++Table: Here's the caption. It, too, may span+multiple lines.+```++These work like simple tables, but with the following differences:++- They must begin with a row of dashes, before the header text (unless+ the header row is omitted).+- They must end with a row of dashes, then a blank line.+- The rows must be separated by blank lines.++In multiline tables, the table parser pays attention to the widths of+the columns, and the writers try to reproduce these relative widths in+the output. So, if you find that one of the columns is too narrow in the+output, try widening it in the Markdown source.++The header may be omitted in multiline tables as well as simple tables:++```+----------- ------- --------------- -------------------------+ First row 12.0 Example of a row that+ spans multiple lines.++ Second row 5.0 Here's another one. Note+ the blank line between+ rows.+----------- ------- --------------- -------------------------++: Here's a multiline table without a header.+```++It is possible for a multiline table to have just one row, but the row+should be followed by a blank line (and then the row of dashes that ends+the table), or the table may be interpreted as a simple table.++{#extension-grid_tables}+#### Extension: `grid_tables`++Grid tables look like this:++```+: Sample grid table.+++---------------+---------------+--------------------++| Fruit | Price | Advantages |++===============+===============+====================++| Bananas | $1.34 | - built-in wrapper |+| | | - bright color |++---------------+---------------+--------------------++| Oranges | $2.10 | - cures scurvy |+| | | - tasty |++---------------+---------------+--------------------++```++The row of `=`s separates the header from the table body, and can be+omitted for a headerless table. The cells of grid tables may contain+arbitrary block elements (multiple paragraphs, code blocks, lists,+etc.).++Cells can span multiple columns or rows:++```++---------------------+----------++| Property | Earth |++=============+=======+==========++| | min | -89.2 °C |+| Temperature +-------+----------++| 1961-1990 | mean | 14 °C |+| +-------+----------++| | max | 56.7 °C |++-------------+-------+----------++```++A table header may contain more than one row:++```++---------------------+-----------------------++| Location | Temperature 1961-1990 |+| | in degree Celsius |+| +-------+-------+-------++| | min | mean | max |++=====================+=======+=======+=======++| Antarctica | -89.2 | N/A | 19.8 |++---------------------+-------+-------+-------++| Earth | -89.2 | 14 | 56.7 |++---------------------+-------+-------+-------++```++Alignments can be specified as with pipe tables, by putting colons at+the boundaries of the separator line after the header:++```++---------------+---------------+--------------------++| Right | Left | Centered |++==============:+:==============+:==================:++| Bananas | $1.34 | built-in wrapper |++---------------+---------------+--------------------++```++For headerless tables, the colons go on the top line instead:++```++--------------:+:--------------+:------------------:++| Right | Left | Centered |++---------------+---------------+--------------------++```++A table foot can be defined by enclosing it with separator lines that+use `=` instead of `-`:++```+ +---------------+---------------++ | Fruit | Price |+ +===============+===============++ | Bananas | $1.34 |+ +---------------+---------------++ | Oranges | $2.10 |+ +===============+===============++ | Sum | $3.44 |+ +===============+===============++```++The foot must always be placed at the very bottom of the table.++Grid tables can be created easily using Emacs’ table-mode+(`M-x table-insert`).++{#extension-pipe_tables}+#### Extension: `pipe_tables`++Pipe tables look like this:++```+| Right | Left | Default | Center |+|------:|:-----|---------|:------:|+| 12 | 12 | 12 | 12 |+| 123 | 123 | 123 | 123 |+| 1 | 1 | 1 | 1 |++ : Demonstration of pipe table syntax.+```++The syntax is identical to [PHP Markdown Extra+tables](https://michelf.ca/projects/php-markdown/extra/#table). The+beginning and ending pipe characters are optional, but pipes are+required between all columns. The colons indicate column alignment as+shown. The header cannot be omitted. To simulate a headerless table,+include a header with blank cells.++Since the pipes indicate column boundaries, columns need not be+vertically aligned, as they are in the above example. So, this is a+perfectly legal (though ugly) pipe table:++```+fruit| price+-----|-----:+apple|2.05+pear|1.37+orange|3.09+```++The cells of pipe tables cannot contain block elements like paragraphs+and lists, and cannot span multiple lines. If any line of the markdown+source is longer than the column width (see `--columns`), then the table+will take up the full text width and the cell contents will wrap, with+the relative cell widths determined by the number of dashes in the line+separating the table header from the table body. (For example `---|-`+would make the first column 3/4 and the second column 1/4 of the full+text width.) On the other hand, if no lines are wider than column width,+then cell contents will not be wrapped, and the cells will be sized to+their contents.++Note: pandoc also recognizes pipe tables of the following form, as can+be produced by Emacs’ orgtbl-mode:++```+| One | Two |+|-----+-------|+| my | table |+| is | nice |+```++The difference is that `+` is used instead of `|`. Other orgtbl features+are not supported. In particular, to get non-default column alignment,+you’ll need to add colons as above.++{#metadata-blocks}+## Metadata blocks++{#extension-pandoc_title_block}+#### Extension: `pandoc_title_block`++If the file begins with a title block++```+% title+% author(s) (separated by semicolons)+% date+```++it will be parsed as bibliographic information, not regular text. (It+will be used, for example, in the title of standalone LaTeX or HTML+output.) The block may contain just a title, a title and an author, or+all three elements. If you want to include an author but no title, or a+title and a date but no author, you need a blank line:++```+%+% Author+```++```+% My title+%+% June 15, 2006+```++The title may occupy multiple lines, but continuation lines must begin+with leading space, thus:++```+% My title+ on multiple lines+```++If a document has multiple authors, the authors may be put on separate+lines with leading space, or separated by semicolons, or both. So, all+of the following are equivalent:++```+% Author One+ Author Two+```++```+% Author One; Author Two+```++```+% Author One;+ Author Two+```++The date must fit on one line.++All three metadata fields may contain standard inline formatting+(italics, links, footnotes, etc.).++Title blocks will always be parsed, but they will affect the output only+when the `--standalone` (`-s`) option is chosen. In HTML output, titles+will appear twice: once in the document head – this is the title that+will appear at the top of the window in a browser – and once at the+beginning of the document body. The title in the document head can have+an optional prefix attached (`--title-prefix` or `-T` option). The title+in the body appears as an H1 element with class "title", so it can be+suppressed or reformatted with CSS. If a title prefix is specified with+`-T` and no title block appears in the document, the title prefix will+be used by itself as the HTML title.++The man page writer extracts a title, man page section number, and other+header and footer information from the title line. The title is assumed+to be the first word on the title line, which may optionally end with a+(single-digit) section number in parentheses. (There should be no space+between the title and the parentheses.) Anything after this is assumed+to be additional footer and header text. A single pipe character (`|`)+should be used to separate the footer text from the header text. Thus,++```+% PANDOC(1)+```++will yield a man page with the title `PANDOC` and section 1.++```+% PANDOC(1) Pandoc User Manuals+```++will also have "Pandoc User Manuals" in the footer.++```+% PANDOC(1) Pandoc User Manuals | Version 4.0+```++will also have "Version 4.0" in the header.++{#extension-yaml_metadata_block}+#### Extension: `yaml_metadata_block`++A [YAML](https://yaml.org/spec/1.2/spec.html){title="YAML v1.2 Spec"}+metadata block is a valid YAML object, delimited by a line of three+hyphens (`---`) at the top and a line of three hyphens (`---`) or three+dots (`...`) at the bottom. The initial line `---` must not be followed+by a blank line. A YAML metadata block may occur anywhere in the+document, but if it is not at the beginning, it must be preceded by a+blank line.++Note that, because of the way pandoc concatenates input files when+several are provided, you may also keep the metadata in a separate YAML+file and pass it to pandoc as an argument, along with your Markdown+files:++```+pandoc chap1.md chap2.md chap3.md metadata.yaml -s -o book.html+```++Just be sure that the YAML file begins with `---` and ends with `---` or+`...`. Alternatively, you can use the `--metadata-file` option. Using+that approach however, you cannot reference content (like footnotes)+from the main markdown input document.++Metadata will be taken from the fields of the YAML object and added to+any existing document metadata. Metadata can contain lists and objects+(nested arbitrarily), but all string scalars will be interpreted as+Markdown. Fields with names ending in an underscore will be ignored by+pandoc. (They may be given a role by external processors.) Field names+must not be interpretable as YAML numbers or boolean values (so, for+example, `yes`, `True`, and `15` cannot be used as field names).++A document may contain multiple metadata blocks. If two metadata blocks+attempt to set the same field, the value from the second block will be+taken.++Each metadata block is handled internally as an independent YAML+document. This means, for example, that any YAML anchors defined in a+block cannot be referenced in another block.++When pandoc is used with `-t markdown` to create a Markdown document, a+YAML metadata block will be produced only if the `-s/--standalone`+option is used. All of the metadata will appear in a single block at the+beginning of the document.++Note that+[YAML](https://yaml.org/spec/1.2/spec.html){title="YAML v1.2 Spec"}+escaping rules must be followed. Thus, for example, if a title contains+a colon, it must be quoted, and if it contains a backslash escape, then+it must be ensured that it is not treated as a [YAML escape+sequence](https://yaml.org/spec/1.2/spec.html#id2776092). The pipe+character (`|`) can be used to begin an indented block that will be+interpreted literally, without need for escaping. This form is necessary+when the field contains blank lines or block-level formatting:++```+---+title: 'This is the title: it contains a colon'+author:+- Author One+- Author Two+keywords: [nothing, nothingness]+abstract: |+ This is the abstract.++ It consists of two paragraphs.+...+```++The literal block after the `|` must be indented relative to the line+containing the `|`. If it is not, the YAML will be invalid and pandoc+will not interpret it as metadata. For an overview of the complex rules+governing YAML, see the [Wikipedia entry on YAML+syntax](https://en.wikipedia.org/wiki/YAML#Syntax).++Template variables will be set automatically from the metadata. Thus,+for example, in writing HTML, the variable `abstract` will be set to the+HTML equivalent of the Markdown in the `abstract` field:++```+<p>This is the abstract.</p>+<p>It consists of two paragraphs.</p>+```++Variables can contain arbitrary YAML structures, but the template must+match this structure. The `author` variable in the default templates+expects a simple list or string, but can be changed to support more+complicated structures. The following combination, for example, would+add an affiliation to the author if one is given:++```+---+title: The document title+author:+- name: Author One+ affiliation: University of Somewhere+- name: Author Two+ affiliation: University of Nowhere+...+```++To use the structured authors in the example above, you would need a+custom template:++```+$for(author)$+$if(author.name)$+$author.name$$if(author.affiliation)$ ($author.affiliation$)$endif$+$else$+$author$+$endif$+$endfor$+```++Raw content to include in the document’s header may be specified using+`header-includes`; however, it is important to mark up this content as+raw code for a particular output format, using the [`raw_attribute`+extension](#extension-raw_attribute), or it will be interpreted as+markdown. For example:++````+header-includes:+- |+ ```{=latex}+ \let\oldsection\section+ \renewcommand{\section}[1]{\clearpage\oldsection{#1}}+ ```+````++Note: the `yaml_metadata_block` extension works with `commonmark` as+well as `markdown` (and it is enabled by default in `gfm` and+`commonmark_x`). However, in these formats the following restrictions+apply:++- The YAML metadata block must occur at the beginning of the document+ (and there can be only one). If multiple files are given as arguments+ to pandoc, only the first can be a YAML metadata block.++- The leaf nodes of the YAML structure are parsed in isolation from each+ other and from the rest of the document. So, for example, you can’t+ use a reference link in these contexts if the link definition is+ somewhere else in the document.++{#backslash-escapes}+## Backslash escapes++{#extension-all_symbols_escapable}+#### Extension: `all_symbols_escapable`++Except inside a code block or inline code, any punctuation or space+character preceded by a backslash will be treated literally, even if it+would normally indicate formatting. Thus, for example, if one writes++```+*\*hello\**+```++one will get++```+<em>*hello*</em>+```++instead of++```+<strong>hello</strong>+```++This rule is easier to remember than original Markdown’s rule, which+allows only the following characters to be backslash-escaped:++```+\`*_{}[]()>#+-.!+```++(However, if the `markdown_strict` format is used, the original Markdown+rule will be used.)++A backslash-escaped space is parsed as a nonbreaking space. In TeX+output, it will appear as `~`. In HTML and XML output, it will appear as+a literal unicode nonbreaking space character (note that it will thus+actually look "invisible" in the generated HTML source; you can still+use the `--ascii` command-line option to make it appear as an explicit+entity).++A backslash-escaped newline (i.e. a backslash occurring at the end of a+line) is parsed as a hard line break. It will appear in TeX output as+`\\` and in HTML as `<br />`. This is a nice alternative to Markdown’s+"invisible" way of indicating hard line breaks using two trailing spaces+on a line.++Backslash escapes do not work in verbatim contexts.++{#inline-formatting}+## Inline formatting++{#emphasis}+### Emphasis++To _emphasize_ some text, surround it with `*`s or `_`, like this:++```+This text is _emphasized with underscores_, and this+is *emphasized with asterisks*.+```++Double `*` or `_` produces *strong emphasis*:++```+This is **strong emphasis** and __with underscores__.+```++A `*` or `_` character surrounded by spaces, or backslash-escaped, will+not trigger emphasis:++```+This is * not emphasized *, and \*neither is this\*.+```++{#extension-intraword_underscores}+#### Extension: `intraword_underscores`++Because `_` is sometimes used inside words and identifiers, pandoc does+not interpret a `_` surrounded by alphanumeric characters as an emphasis+marker. If you want to emphasize just part of a word, use `*`:++```+feas*ible*, not feas*able*.+```++{#strikeout}+### Strikeout++{#extension-strikeout}+#### Extension: `strikeout`++To strike out a section of text with a horizontal line, begin and end it+with `~~`. Thus, for example,++```+This ~~is deleted text.~~+```++{#superscripts-and-subscripts}+### Superscripts and subscripts++{#extension-superscript-subscript}+#### Extension: `superscript`, `subscript`++Superscripts may be written by surrounding the superscripted text by `^`+characters; subscripts may be written by surrounding the subscripted+text by `~` characters. Thus, for example,++```+H~2~O is a liquid. 2^10^ is 1024.+```++The text between `^...^` or `~...~` may not contain spaces or newlines.+If the superscripted or subscripted text contains spaces, these spaces+must be escaped with backslashes. (This is to prevent accidental+superscripting and subscripting through the ordinary use of `~` and `^`,+and also bad interactions with footnotes.) Thus, if you want the letter+P with 'a cat' in subscripts, use `P~a\ cat~`, not `P~a cat~`.++{#verbatim}+### Verbatim++To make a short span of text verbatim, put it inside backticks:++```+What is the difference between `>>=` and `>>`?+```++If the verbatim text includes a backtick, use double backticks:++```+Here is a literal backtick `` ` ``.+```++(The spaces after the opening backticks and before the closing backticks+will be ignored.)++The general rule is that a verbatim span starts with a string of+consecutive backticks (optionally followed by a space) and ends with a+string of the same number of backticks (optionally preceded by a space).++Note that backslash-escapes (and other Markdown constructs) do not work+in verbatim contexts:++```+This is a backslash followed by an asterisk: `\*`.+```++{#extension-inline_code_attributes}+#### Extension: `inline_code_attributes`++Attributes can be attached to verbatim text, just as with [fenced code+blocks](#fenced-code-blocks):++```+`<$>`{.haskell}+```++{#underline}+### Underline++To underline text, use the `underline` class:++```+[Underline]{.underline}+```++Or, without the `bracketed_spans` extension (but with `native_spans`):++```+<span class="underline">Underline</span>+```++This will work in all output formats that support underline.++{#small-caps}+### Small caps++To write small caps, use the `smallcaps` class:++```+[Small caps]{.smallcaps}+```++Or, without the `bracketed_spans` extension:++```+<span class="smallcaps">Small caps</span>+```++For compatibility with other Markdown flavors, CSS is also supported:++```+<span style="font-variant:small-caps;">Small caps</span>+```++This will work in all output formats that support small caps.++{#highlighting}+### Highlighting++To highlight text, use the `mark` class:++```+[Mark]{.mark}+```++Or, without the `bracketed_spans` extension (but with `native_spans`):++```+<span class="mark">Mark</span>+```++This will work in all output formats that support highlighting.++{#math}+## Math++{#extension-tex_math_dollars}+#### Extension: `tex_math_dollars`++Anything between two `$` characters will be treated as TeX math. The+opening `$` must have a non-space character immediately to its right,+while the closing `$` must have a non-space character immediately to its+left, and must not be followed immediately by a digit. Thus,+`$20,000 and $30,000` won’t parse as math. If for some reason you need+to enclose text in literal `$` characters, backslash-escape them and+they won’t be treated as math delimiters.++For display math, use `$$` delimiters. (In this case, the delimiters may+be separated from the formula by whitespace. However, there can be no+blank lines between the opening and closing `$$` delimiters.)++TeX math will be printed in all output formats. How it is rendered+depends on the output format:++: LaTeX++ It will appear verbatim surrounded by `\(...\)` (for inline math) or+ `\[...\]` (for display math).+: Markdown, Emacs Org mode, ConTeXt, ZimWiki++ It will appear verbatim surrounded by `$...$` (for inline math) or+ `$$...$$` (for display math).+: XWiki++ It will appear verbatim surrounded by `{{formula}}..{{/formula}}`.+: reStructuredText++ It will be rendered using an [interpreted text role+ `:math:`](https://docutils.sourceforge.io/docs/ref/rst/roles.html#math).+: AsciiDoc++ For AsciiDoc output math will appear verbatim surrounded by+ `latexmath:[...]`. For `asciidoc_legacy` the bracketed material will+ also include inline or display math delimiters.+: Texinfo++ It will be rendered inside a `@math` command.+: roff man, Jira markup++ It will be rendered verbatim without `$`’s.+: MediaWiki, DokuWiki++ It will be rendered inside `<math>` tags.+: Textile++ It will be rendered inside `<span class="math">` tags.+: RTF, OpenDocument++ It will be rendered, if possible, using Unicode characters, and will+ otherwise appear verbatim.+: ODT++ It will be rendered, if possible, using MathML.+: DocBook++ If the `--mathml` flag is used, it will be rendered using MathML in an+ `inlineequation` or `informalequation` tag. Otherwise it will be+ rendered, if possible, using Unicode characters.+: Docx and PowerPoint++ It will be rendered using OMML math markup.+: FictionBook2++ If the `--webtex` option is used, formulas are rendered as images+ using CodeCogs or other compatible web service, downloaded and+ embedded in the e-book. Otherwise, they will appear verbatim.+: HTML, Slidy, DZSlides, S5, EPUB++ The way math is rendered in HTML will depend on the command-line+ options selected. Therefore see [Math rendering in+ HTML](#math-rendering-in-html) above.++{#raw-html}+## Raw HTML++{#extension-raw_html}+#### Extension: `raw_html`++Markdown allows you to insert raw HTML (or DocBook) anywhere in a+document (except verbatim contexts, where `<`, `>`, and `&` are+interpreted literally). (Technically this is not an extension, since+standard Markdown allows it, but it has been made an extension so that+it can be disabled if desired.)++The raw HTML is passed through unchanged in HTML, S5, Slidy, Slideous,+DZSlides, EPUB, Markdown, CommonMark, Emacs Org mode, and Textile+output, and suppressed in other formats.++For a more explicit way of including raw HTML in a Markdown document,+see the [`raw_attribute` extension](#extension-raw_attribute).++In the CommonMark format, if `raw_html` is enabled, superscripts,+subscripts, strikeouts and small capitals will be represented as HTML.+Otherwise, plain-text fallbacks will be used. Note that even if+`raw_html` is disabled, tables will be rendered with HTML syntax if they+cannot use pipe syntax.++{#extension-markdown_in_html_blocks}+#### Extension: `markdown_in_html_blocks`++Original Markdown allows you to include HTML "blocks": blocks of HTML+between balanced tags that are separated from the surrounding text with+blank lines, and start and end at the left margin. Within these blocks,+everything is interpreted as HTML, not Markdown; so (for example), `*`+does not signify emphasis.++Pandoc behaves this way when the `markdown_strict` format is used; but+by default, pandoc interprets material between HTML block tags as+Markdown. Thus, for example, pandoc will turn++```+<table>+<tr>+<td>*one*</td>+<td>[a link](https://google.com)</td>+</tr>+</table>+```++into++```+<table>+<tr>+<td><em>one</em></td>+<td><a href="https://google.com">a link</a></td>+</tr>+</table>+```++whereas `Markdown.pl` will preserve it as is.++There is one exception to this rule: text between `<script>`, `<style>`,+and `<textarea>` tags is not interpreted as Markdown.++This departure from original Markdown should make it easier to mix+Markdown with HTML block elements. For example, one can surround a block+of Markdown text with `<div>` tags without preventing it from being+interpreted as Markdown.++{#extension-native_divs}+#### Extension: `native_divs`++Use native pandoc `Div` blocks for content inside `<div>` tags. For the+most part this should give the same output as `markdown_in_html_blocks`,+but it makes it easier to write pandoc filters to manipulate groups of+blocks.++{#extension-native_spans}+#### Extension: `native_spans`++Use native pandoc `Span` blocks for content inside `<span>` tags. For+the most part this should give the same output as `raw_html`, but it+makes it easier to write pandoc filters to manipulate groups of inlines.++{#extension-raw_tex}+#### Extension: `raw_tex`++In addition to raw HTML, pandoc allows raw LaTeX, TeX, and ConTeXt to be+included in a document. Inline TeX commands will be preserved and passed+unchanged to the LaTeX and ConTeXt writers. Thus, for example, you can+use LaTeX to include BibTeX citations:++```+This result was proved in \cite{jones.1967}.+```++Note that in LaTeX environments, like++```+\begin{tabular}{|l|l|}\hline+Age & Frequency \\ \hline+18--25 & 15 \\+26--35 & 33 \\+36--45 & 22 \\ \hline+\end{tabular}+```++the material between the begin and end tags will be interpreted as raw+LaTeX, not as Markdown.++For a more explicit and flexible way of including raw TeX in a Markdown+document, see the [`raw_attribute` extension](#extension-raw_attribute).++Inline LaTeX is ignored in output formats other than Markdown, LaTeX,+Emacs Org mode, and ConTeXt.++{#generic-raw-attribute}+### Generic raw attribute++{#extension-raw_attribute}+#### Extension: `raw_attribute`++Inline spans and fenced code blocks with a special kind of attribute+will be parsed as raw content with the designated format. For example,+the following produces a raw roff `ms` block:++````+```{=ms}+.MYMACRO+blah blah+```+````++And the following produces a raw `html` inline element:++```+This is `<a>html</a>`{=html}+```++This can be useful to insert raw xml into `docx` documents, e.g. a+pagebreak:++````+```{=openxml}+<w:p>+ <w:r>+ <w:br w:type="page"/>+ </w:r>+</w:p>+```+````++The format name should match the target format name (see `-t/--to`,+above, for a list, or use `pandoc --list-output-formats`). Use `openxml`+for `docx` output, `opendocument` for `odt` output, `html5` for `epub3`+output, `html4` for `epub2` output, and `latex`, `beamer`, `ms`, or+`html5` for `pdf` output (depending on what you use for `--pdf-engine`).++This extension presupposes that the relevant kind of inline code or+fenced code block is enabled. Thus, for example, to use a raw attribute+with a backtick code block, `backtick_code_blocks` must be enabled.++The raw attribute cannot be combined with regular attributes.++{#latex-macros}+## LaTeX macros++{#extension-latex_macros}+#### Extension: `latex_macros`++When this extension is enabled, pandoc will parse LaTeX macro+definitions and apply the resulting macros to all LaTeX math and raw+LaTeX. So, for example, the following will work in all output formats,+not just LaTeX:++```+\newcommand{\tuple}[1]{\langle #1 \rangle}++$\tuple{a, b, c}$+```++Note that LaTeX macros will not be applied if they occur inside a raw+span or block marked with the [`raw_attribute`+extension](#extension-raw_attribute).++When `latex_macros` is disabled, the raw LaTeX and math will not have+macros applied. This is usually a better approach when you are targeting+LaTeX or PDF.++Macro definitions in LaTeX will be passed through as raw LaTeX only if+`latex_macros` is not enabled. Macro definitions in Markdown source (or+other formats allowing `raw_tex`) will be passed through regardless of+whether `latex_macros` is enabled.++{#links-1}+## Links++Markdown allows links to be specified in several ways.++{#automatic-links}+### Automatic links++If you enclose a URL or email address in pointy brackets, it will become+a link:++```+<https://google.com>+<sam@green.eggs.ham>+```++{#inline-links}+### Inline links++An inline link consists of the link text in square brackets, followed by+the URL in parentheses. (Optionally, the URL can be followed by a link+title, in quotes.)++```+This is an [inline link](/url), and here's [one with+a title](https://fsf.org "click here for a good time!").+```++There can be no space between the bracketed part and the parenthesized+part. The link text can contain formatting (such as emphasis), but the+title cannot.++Email addresses in inline links are not autodetected, so they have to be+prefixed with `mailto`:++```+[Write me!](mailto:sam@green.eggs.ham)+```++{#reference-links}+### Reference links++An _explicit_ reference link has two parts, the link itself and the link+definition, which may occur elsewhere in the document (either before or+after the link).++The link consists of link text in square brackets, followed by a label+in square brackets. (There cannot be space between the two unless the+`spaced_reference_links` extension is enabled.) The link definition+consists of the bracketed label, followed by a colon and a space,+followed by the URL, and optionally (after a space) a link title either+in quotes or in parentheses. The label must not be parseable as a+citation (assuming the `citations` extension is enabled): citations take+precedence over link labels.++Here are some examples:++```+[my label 1]: /foo/bar.html "My title, optional"+[my label 2]: /foo+[my label 3]: https://fsf.org (The Free Software Foundation)+[my label 4]: /bar#special 'A title in single quotes'+```++The URL may optionally be surrounded by angle brackets:++```+[my label 5]: <http://foo.bar.baz>+```++The title may go on the next line:++```+[my label 3]: https://fsf.org+ "The Free Software Foundation"+```++Note that link labels are not case sensitive. So, this will work:++```+Here is [my link][FOO]++[Foo]: /bar/baz+```++In an _implicit_ reference link, the second pair of brackets is empty:++```+See [my website][].++[my website]: http://foo.bar.baz+```++Note: In `Markdown.pl` and most other Markdown implementations,+reference link definitions cannot occur in nested constructions such as+list items or block quotes. Pandoc lifts this arbitrary-seeming+restriction. So the following is fine in pandoc, though not in most+other implementations:++```+> My block [quote].+>+> [quote]: /foo+```++{#extension-shortcut_reference_links}+#### Extension: `shortcut_reference_links`++In a _shortcut_ reference link, the second pair of brackets may be+omitted entirely:++```+See [my website].++[my website]: http://foo.bar.baz+```++{#internal-links}+### Internal links++To link to another section of the same document, use the automatically+generated identifier (see [Heading identifiers](#heading-identifiers)).+For example:++```+See the [Introduction](#introduction).+```++or++```+See the [Introduction].++[Introduction]: #introduction+```++Internal links are currently supported for HTML formats (including HTML+slide shows and EPUB), LaTeX, and ConTeXt.++{#images}+## Images++A link immediately preceded by a `!` will be treated as an image. The+link text will be used as the image’s alt text:++```+++![movie reel]++[movie reel]: movie.gif+```++{#extension-implicit_figures}+#### Extension: `implicit_figures`++An image with nonempty alt text, occurring by itself in a paragraph,+will be rendered as a figure with a caption. The image’s alt text will+be used as the caption.++```++```++How this is rendered depends on the output format. Some output formats+(e.g. RTF) do not yet support figures. In those formats, you’ll just get+an image in a paragraph by itself, with no caption.++If you just want a regular inline image, just make sure it is not the+only thing in the paragraph. One way to do this is to insert a+nonbreaking space after the image:++```+\+```++Note that in reveal.js slide shows, an image in a paragraph by itself+that has the `r-stretch` class will fill the screen, and the caption and+figure tags will be omitted.++{#extension-link_attributes}+#### Extension: `link_attributes`++Attributes can be set on links and images:++```+An inline {#id .class width=30 height=20px}+and a reference ![image][ref] with attributes.++[ref]: foo.jpg "optional title" {#id .class key=val key2="val 2"}+```++(This syntax is compatible with [PHP Markdown+Extra](https://michelf.ca/projects/php-markdown/extra/) when only `#id`+and `.class` are used.)++For HTML and EPUB, all known HTML5 attributes except `width` and+`height` (but including `srcset` and `sizes`) are passed through as is.+Unknown attributes are passed through as custom attributes, with `data-`+prepended. The other writers ignore attributes that are not specifically+supported by their output format.++The `width` and `height` attributes on images are treated specially.+When used without a unit, the unit is assumed to be pixels. However, any+of the following unit identifiers can be used: `px`, `cm`, `mm`, `in`,+`inch` and `%`. There must not be any spaces between the number and the+unit. For example:++```+{ width=50% }+```++- Dimensions may be converted to a form that is compatible with the+ output format (for example, dimensions given in pixels will be+ converted to inches when converting HTML to LaTeX). Conversion between+ pixels and physical measurements is affected by the `--dpi` option (by+ default, 96 dpi is assumed, unless the image itself contains dpi+ information).+- The `%` unit is generally relative to some available space. For+ example the above example will render to the following.++ - HTML: `<img href="file.jpg" style="width: 50%;" />`+ - LaTeX:+ `\includegraphics[width=0.5\textwidth,height=\textheight]{file.jpg}`+ (If you’re using a custom template, you need to configure `graphicx`+ as in the default template.)+ - ConTeXt: `\externalfigure[file.jpg][width=0.5\textwidth]`+- Some output formats have a notion of a class+ ([ConTeXt](https://wiki.contextgarden.net/Using_Graphics#Multiple_Image_Settings))+ or a unique identifier (LaTeX `\caption`), or both (HTML).+- When no `width` or `height` attributes are specified, the fallback is+ to look at the image resolution and the dpi metadata embedded in the+ image file.++{#divs-and-spans}+## Divs and Spans++Using the `native_divs` and `native_spans` extensions (see+[above](#extension-native_divs)), HTML syntax can be used as part of+markdown to create native `Div` and `Span` elements in the pandoc AST+(as opposed to raw HTML). However, there is also nicer syntax available:++{#extension-fenced_divs}+#### Extension: `fenced_divs`++Allow special fenced syntax for native `Div` blocks. A Div starts with a+fence containing at least three consecutive colons plus some attributes.+The attributes may optionally be followed by another string of+consecutive colons.++Note: the `commonmark` parser doesn’t permit colons after the+attributes.++The attribute syntax is exactly as in fenced code blocks (see+[Extension:+`fenced_code_attributes`](#extension-fenced_code_attributes)). As with+fenced code blocks, one can use either attributes in curly braces or a+single unbraced word, which will be treated as a class name. The Div+ends with another line containing a string of at least three consecutive+colons. The fenced Div should be separated by blank lines from preceding+and following blocks.++Example:++```+::::: {#special .sidebar}+Here is a paragraph.++And another.+:::::+```++Fenced divs can be nested. Opening fences are distinguished because they+_must_ have attributes:++```+::: Warning ::::::+This is a warning.++::: Danger+This is a warning within a warning.+:::+::::::::::::::::::+```++Fences without attributes are always closing fences. Unlike with fenced+code blocks, the number of colons in the closing fence need not match+the number in the opening fence. However, it can be helpful for visual+clarity to use fences of different lengths to distinguish nested divs+from their parents.++{#extension-bracketed_spans}+#### Extension: `bracketed_spans`++A bracketed sequence of inlines, as one would use to begin a link, will+be treated as a `Span` with attributes if it is followed immediately by+attributes:++```+[This is *some text*]{.class key="val"}+```++{#footnotes}+## Footnotes++{#extension-footnotes}+#### Extension: `footnotes`++Pandoc’s Markdown allows footnotes, using the following syntax:++```+Here is a footnote reference,[^1] and another.[^longnote]++[^1]: Here is the footnote.++[^longnote]: Here's one with multiple blocks.++ Subsequent paragraphs are indented to show that they+belong to the previous footnote.++ { some.code }++ The whole paragraph can be indented, or just the first+ line. In this way, multi-paragraph footnotes work like+ multi-paragraph list items.++This paragraph won't be part of the note, because it+isn't indented.+```++The identifiers in footnote references may not contain spaces, tabs, or+newlines. These identifiers are used only to correlate the footnote+reference with the note itself; in the output, footnotes will be+numbered sequentially.++The footnotes themselves need not be placed at the end of the document.+They may appear anywhere except inside other block elements (lists,+block quotes, tables, etc.). Each footnote should be separated from+surrounding content (including other footnotes) by blank lines.++{#extension-inline_notes}+#### Extension: `inline_notes`++Inline footnotes are also allowed (though, unlike regular notes, they+cannot contain multiple paragraphs). The syntax is as follows:++```+Here is an inline note.^[Inline notes are easier to write, since+you don't have to pick an identifier and move down to type the+note.]+```++Inline and regular footnotes may be mixed freely.++{#citation-syntax}+## Citation syntax++{#extension-citations}+#### Extension: `citations`++To cite a bibliographic item with an identifier foo, use the syntax+`@foo`. Normal citations should be included in square brackets, with+semicolons separating distinct items:++```+Blah blah [@doe99; @smith2000; @smith2004].+```++How this is rendered depends on the citation style. In an author-date+style, it might render as++```+Blah blah (Doe 1999, Smith 2000, 2004).+```++In a footnote style, it might render as++```+Blah blah.[^1]++[^1]: John Doe, "Frogs," *Journal of Amphibians* 44 (1999);+Susan Smith, "Flies," *Journal of Insects* (2000);+Susan Smith, "Bees," *Journal of Insects* (2004).+```++See the [CSL user documentation](https://citationstyles.org/authors/)+for more information about CSL styles and how they affect rendering.++Unless a citation key starts with a letter, digit, or `_`, and contains+only alphanumerics and single internal punctuation characters+(`:.#$%&-+?<>~/`), it must be surrounded by curly braces, which are not+considered part of the key. In `@Foo_bar.baz.`, the key is `Foo_bar.baz`+because the final period is not _internal_ punctuation, so it is not+included in the key. In `@{Foo_bar.baz.}`, the key is `Foo_bar.baz.`,+including the final period. In `@Foo_bar--baz`, the key is `Foo_bar`+because the repeated internal punctuation characters terminate the key.+The curly braces are recommended if you use URLs as keys:+`[@{https://example.com/bib?name=foobar&date=2000}, p. 33]`.++Citation items may optionally include a prefix, a locator, and a suffix.+In++```+Blah blah [see @doe99, pp. 33-35 and *passim*; @smith04, chap. 1].+```++the first item (`doe99`) has prefix `see`, locator `pp. 33-35`, and+suffix `and *passim*`. The second item (`smith04`) has locator `chap. 1`+and no prefix or suffix.++Pandoc uses some heuristics to separate the locator from the rest of the+subject. It is sensitive to the locator terms defined in the [CSL locale+files](https://github.com/citation-style-language/locales). Either+abbreviated or unabbreviated forms are accepted. In the `en-US` locale,+locator terms can be written in either singular or plural forms, as+`book`, `bk.`/`bks.`; `chapter`, `chap.`/`chaps.`; `column`,+`col.`/`cols.`; `figure`, `fig.`/`figs.`; `folio`, `fol.`/`fols.`;+`number`, `no.`/`nos.`; `line`, `l.`/`ll.`; `note`, `n.`/`nn.`; `opus`,+`op.`/`opp.`; `page`, `p.`/`pp.`; `paragraph`, `para.`/`paras.`; `part`,+`pt.`/`pts.`; `section`, `sec.`/`secs.`; `sub verbo`, `s.v.`/`s.vv.`;+`verse`, `v.`/`vv.`; `volume`, `vol.`/`vols.`; `¶`/`¶¶`; `§`/`§§`. If no+locator term is used, "page" is assumed.++In complex cases, you can force something to be treated as a locator by+enclosing it in curly braces or prevent parsing the suffix as locator by+prepending curly braces:++```+[@smith{ii, A, D-Z}, with a suffix]+[@smith, {pp. iv, vi-xi, (xv)-(xvii)} with suffix here]+[@smith{}, 99 years later]+```++A minus sign (`-`) before the `@` will suppress mention of the author in+the citation. This can be useful when the author is already mentioned in+the text:++```+Smith says blah [-@smith04].+```++You can also write an author-in-text citation, by omitting the square+brackets:++```+@smith04 says blah.++@smith04 [p. 33] says blah.+```++This will cause the author’s name to be rendered, followed by the+bibliographical details. Use this form when you want to make the+citation the subject of a sentence.++When you are using a note style, it is usually better to let citeproc+create the footnotes from citations rather than writing an explicit+note. If you do write an explicit note that contains a citation, note+that normal citations will be put in parentheses, while author-in-text+citations will not. For this reason, it is sometimes preferable to use+the author-in-text style inside notes when using a note style.++{#non-default-extensions}+## Non-default extensions++The following Markdown syntax extensions are not enabled by default in+pandoc, but may be enabled by adding `+EXTENSION` to the format name,+where `EXTENSION` is the name of the extension. Thus, for example,+`markdown+hard_line_breaks` is Markdown with hard line breaks.++{#extension-rebase_relative_paths}+#### Extension: `rebase_relative_paths`++Rewrite relative paths for Markdown links and images, depending on the+path of the file containing the link or image link. For each link or+image, pandoc will compute the directory of the containing file,+relative to the working directory, and prepend the resulting path to the+link or image path.++The use of this extension is best understood by example. Suppose you+have a subdirectory for each chapter of a book, `chap1`, `chap2`,+`chap3`. Each contains a file `text.md` and a number of images used in+the chapter. You would like to have `` in+`chap1/text.md` refer to `chap1/spider.jpg` and ``+in `chap2/text.md` refer to `chap2/spider.jpg`. To do this, use++```+pandoc chap*/*.md -f markdown+rebase_relative_paths+```++Without this extension, you would have to use+`` in `chap1/text.md` and+`` in `chap2/text.md`. Links with relative+paths will be rewritten in the same way as images.++Absolute paths and URLs are not changed. Neither are empty paths or+paths consisting entirely of a fragment, e.g., `#foo`.++Note that relative paths in reference links and images will be rewritten+relative to the file containing the link reference definition, not the+file containing the reference link or image itself, if these differ.++{#extension-mark}+#### Extension: `mark`++To highlight out a section of text, begin and end it with with `==`.+Thus, for example,++```+This ==is deleted text.==+```++{#extension-attributes}+#### Extension: `attributes`++Allows attributes to be attached to any inline or block-level element+when parsing `commonmark`. 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}+#### Extension: `old_dashes`++Selects the pandoc \<= 1.8.2.1 behavior for parsing smart dashes: `-`+before a numeral is an en-dash, and `--` is an em-dash. This option only+has an effect if `smart` is enabled. It is selected automatically for+`textile` input.++{#extension-angle_brackets_escapable}+#### Extension: `angle_brackets_escapable`++Allow `<` and `>` to be backslash-escaped, as they can be in GitHub+flavored Markdown but not original Markdown. This is implied by pandoc’s+default `all_symbols_escapable`.++{#extension-lists_without_preceding_blankline}+#### Extension: `lists_without_preceding_blankline`++Allow a list to occur right after a paragraph, with no intervening blank+space.++{#extension-four_space_rule}+#### Extension: `four_space_rule`++Selects the pandoc \<= 2.0 behavior for parsing lists, so that four+spaces indent are needed for list item continuation paragraphs.++{#extension-spaced_reference_links}+#### Extension: `spaced_reference_links`++Allow whitespace between the two components of a reference link, for+example,++```+[foo] [bar].+```++{#extension-hard_line_breaks}+#### Extension: `hard_line_breaks`++Causes all newlines within a paragraph to be interpreted as hard line+breaks instead of spaces.++{#extension-ignore_line_breaks}+#### Extension: `ignore_line_breaks`++Causes newlines within a paragraph to be ignored, rather than being+treated as spaces or as hard line breaks. This option is intended for+use with East Asian languages where spaces are not used between words,+but text is divided into lines for readability.++{#extension-east_asian_line_breaks}+#### Extension: `east_asian_line_breaks`++Causes newlines within a paragraph to be ignored, rather than being+treated as spaces or as hard line breaks, when they occur between two+East Asian wide characters. This is a better choice than+`ignore_line_breaks` for texts that include a mix of East Asian wide+characters and other characters.++{#extension-emoji}+#### Extension: `emoji`++Parses textual emojis like `:smile:` as Unicode emoticons.++{#extension-tex_math_single_backslash}+#### Extension: `tex_math_single_backslash`++Causes anything between `\(` and `\)` to be interpreted as inline TeX+math, and anything between `\[` and `\]` to be interpreted as display+TeX math. Note: a drawback of this extension is that it precludes+escaping `(` and `[`.++{#extension-tex_math_double_backslash}+#### Extension: `tex_math_double_backslash`++Causes anything between `\\(` and `\\)` to be interpreted as inline TeX+math, and anything between `\\[` and `\\]` to be interpreted as display+TeX math.++{#extension-markdown_attribute}+#### Extension: `markdown_attribute`++By default, pandoc interprets material inside block-level tags as+Markdown. This extension changes the behavior so that Markdown is only+parsed inside block-level tags if the tags have the attribute+`markdown=1`.++{#extension-mmd_title_block}+#### Extension: `mmd_title_block`++Enables a [MultiMarkdown](https://fletcherpenney.net/multimarkdown/)+style title block at the top of the document, for example:++```+Title: My title+Author: John Doe+Date: September 1, 2008+Comment: This is a sample mmd title block, with+ a field spanning multiple lines.+```++See the MultiMarkdown documentation for details. If `pandoc_title_block`+or `yaml_metadata_block` is enabled, it will take precedence over+`mmd_title_block`.++{#extension-abbreviations}+#### Extension: `abbreviations`++Parses PHP Markdown Extra abbreviation keys, like++```+*[HTML]: Hypertext Markup Language+```++Note that the pandoc document model does not support abbreviations, so+if this extension is enabled, abbreviation keys are simply skipped (as+opposed to being parsed as paragraphs).++{#extension-autolink_bare_uris}+#### Extension: `autolink_bare_uris`++Makes all absolute URIs into links, even when not surrounded by pointy+braces `<...>`.++{#extension-mmd_link_attributes}+#### Extension: `mmd_link_attributes`++Parses multimarkdown style key-value attributes on link and image+references. This extension should not be confused with the+[`link_attributes`](#extension-link_attributes) extension.++```+This is a reference ![image][ref] with multimarkdown attributes.++[ref]: https://path.to/image "Image title" width=20px height=30px+ id=myId class="myClass1 myClass2"+```++{#extension-mmd_header_identifiers}+#### Extension: `mmd_header_identifiers`++Parses multimarkdown style heading identifiers (in square brackets,+after the heading but before any trailing `#`s in an ATX heading).++{#extension-compact_definition_lists}+#### Extension: `compact_definition_lists`++Activates the definition list syntax of pandoc 1.12.x and earlier. This+syntax differs from the one described above under [Definition+lists](#definition-lists) in several respects:++- No blank line is required between consecutive items of the definition+ list.+- To get a "tight" or "compact" list, omit space between consecutive+ items; the space between a term and its definition does not affect+ anything.+- Lazy wrapping of paragraphs is not allowed: the entire definition must+ be indented four spaces.[^4]++{#extension-gutenberg}+#### Extension: `gutenberg`++Use [Project Gutenberg](https://www.gutenberg.org) conventions for+`plain` output: all-caps for strong emphasis, surround by underscores+for regular emphasis, add extra blank space around headings.++{#extension-sourcepos}+#### Extension: `sourcepos`++Include source position attributes when parsing `commonmark`. For+elements that accept attributes, a `data-pos` attribute is added; other+elements are placed in a surrounding Div or Span element with a+`data-pos` attribute.++{#extension-short_subsuperscripts}+#### Extension: `short_subsuperscripts`++Parse multimarkdown style subscripts and superscripts, which start with+a '\~' or '\^' character, respectively, and include the alphanumeric+sequence that follows. For example:++```+x^2 = 4+```++or++```+Oxygen is O~2.+```++{#extension-wikilinks_title_after_pipe}+#### Extension: `wikilinks_title_after_pipe`++Pandoc supports multiple markdown wikilink syntaxes, regardless of+whether the title is before or after the pipe.++Using `--from=markdown+wikilinks_title_after_pipe` results in++``` [[wiki]]+[[URL|title]]+```++while using `--from=markdown+wikilinks_title_before_pipe` results in++``` [[wiki]]+[[title|URL]]+```++{#markdown-variants}+## Markdown variants++In addition to pandoc’s extended Markdown, the following Markdown+variants are supported:++- `markdown_phpextra` (PHP Markdown Extra)+- `markdown_github` (deprecated GitHub-Flavored Markdown)+- `markdown_mmd` (MultiMarkdown)+- `markdown_strict` (Markdown.pl)+- `commonmark` (CommonMark)+- `gfm` (Github-Flavored Markdown)+- `commonmark_x` (CommonMark with many pandoc extensions)++To see which extensions are supported for a given format, and which are+enabled by default, you can use the command++```+pandoc --list-extensions=FORMAT+```++where `FORMAT` is replaced with the name of the format.++Note that the list of extensions for `commonmark`, `gfm`, and+`commonmark_x` are defined relative to default commonmark. So, for+example, `backtick_code_blocks` does not appear as an extension, since+it is enabled by default and cannot be disabled.++{#citations}+# Citations++When the `--citeproc` option is used, pandoc can automatically generate+citations and a bibliography in a number of styles. Basic usage is++```+pandoc --citeproc myinput.txt+```++To use this feature, you will need to have++- a document containing citations (see [Citation+ syntax](#citation-syntax));+- a source of bibliographic data: either an external bibliography file+ or a list of `references` in the document’s YAML metadata;+- optionally, a+ [CSL](https://docs.citationstyles.org/en/stable/specification.html)+ citation style.++{#specifying-bibliographic-data}+## Specifying bibliographic data++You can specify an external bibliography using the `bibliography`+metadata field in a YAML metadata section or the `--bibliography`+command line argument. If you want to use multiple bibliography files,+you can supply multiple `--bibliography` arguments or set `bibliography`+metadata field to YAML array. A bibliography may have any of these+formats:++|Format|File extension|+|:--|---|+|BibLaTeX|.bib|+|BibTeX|.bibtex|+|CSL JSON|.json|+|CSL YAML|.yaml|+|RIS|.ris|++Note that `.bib` can be used with both BibTeX and BibLaTeX files; use+the extension `.bibtex` to force interpretation as BibTeX.++In BibTeX and BibLaTeX databases, pandoc parses LaTeX markup inside+fields such as `title`; in CSL YAML databases, pandoc Markdown; and in+CSL JSON databases, an [HTML-like+markup](https://docs.citationstyles.org/en/1.0/release-notes.html#rich-text-markup-within-fields):++: `<i>...</i>`++ italics+: `<b>...</b>`++ bold+: `<span style="font-variant:small-caps;">...</span>` or `<sc>...</sc>`++ small capitals+: `<sub>...</sub>`++ subscript+: `<sup>...</sup>`++ superscript+: `<span class="nocase">...</span>`++ prevent a phrase from being capitalized as title case++As an alternative to specifying a bibliography file using+`--bibliography` or the YAML metadata field `bibliography`, you can+include the citation data directly in the `references` field of the+document’s YAML metadata. The field should contain an array of+YAML-encoded references, for example:++```+---+references:+- type: article-journal+ id: WatsonCrick1953+ author:+ - family: Watson+ given: J. D.+ - family: Crick+ given: F. H. C.+ issued:+ date-parts:+ - - 1953+ - 4+ - 25+ title: 'Molecular structure of nucleic acids: a structure for+ deoxyribose nucleic acid'+ title-short: Molecular structure of nucleic acids+ container-title: Nature+ volume: 171+ issue: 4356+ page: 737-738+ DOI: 10.1038/171737a0+ URL: https://www.nature.com/articles/171737a0+ language: en-GB+...+```++If both an external bibliography and inline (YAML metadata) references+are provided, both will be used. In case of conflicting `id`s, the+inline references will take precedence.++Note that pandoc can be used to produce such a YAML metadata section+from a BibTeX, BibLaTeX, or CSL JSON bibliography:++```+pandoc chem.bib -s -f biblatex -t markdown+pandoc chem.json -s -f csljson -t markdown+```++Indeed, pandoc can convert between any of these citation formats:++```+pandoc chem.bib -s -f biblatex -t csljson+pandoc chem.yaml -s -f markdown -t biblatex+```++Running pandoc on a bibliography file with the `--citeproc` option will+create a formatted bibliography in the format of your choice:++```+pandoc chem.bib -s --citeproc -o chem.html+pandoc chem.bib -s --citeproc -o chem.pdf+```++{#capitalization-in-titles}+### Capitalization in titles++If you are using a bibtex or biblatex bibliography, then observe the+following rules:++- English titles should be in title case. Non-English titles should be+ in sentence case, and the `langid` field in biblatex should be set to+ the relevant language. (The following values are treated as English:+ `american`, `british`, `canadian`, `english`, `australian`,+ `newzealand`, `USenglish`, or `UKenglish`.)++- As is standard with bibtex/biblatex, proper names should be protected+ with curly braces so that they won’t be lowercased in styles that call+ for sentence case. For example:++ ```+ title = {My Dinner with {Andre}}+ ```++- In addition, words that should remain lowercase (or camelCase) should+ be protected:++ ```+ title = {Spin Wave Dispersion on the {nm} Scale}+ ```++ Though this is not necessary in bibtex/biblatex, it is necessary with+ citeproc, which stores titles internally in sentence case, and+ converts to title case in styles that require it. Here we protect "nm"+ so that it doesn’t get converted to "Nm" at this stage.++If you are using a CSL bibliography (either JSON or YAML), then observe+the following rules:++- All titles should be in sentence case.++- Use the `language` field for non-English titles to prevent their+ conversion to title case in styles that call for this. (Conversion+ happens only if `language` begins with `en` or is left empty.)++- Protect words that should not be converted to title case using this+ syntax:++ ```+ Spin wave dispersion on the <span class="nocase">nm</span> scale+ ```++{#conference-papers-published-vs.-unpublished}+### Conference Papers, Published vs. Unpublished++For a formally published conference paper, use the biblatex entry type+`inproceedings` (which will be mapped to CSL `paper-conference`).++For an unpublished manuscript, use the biblatex entry type `unpublished`+without an `eventtitle` field (this entry type will be mapped to CSL+`manuscript`).++For a talk, an unpublished conference paper, or a poster presentation,+use the biblatex entry type `unpublished` with an `eventtitle` field+(this entry type will be mapped to CSL `speech`). Use the biblatex+`type` field to indicate the type, e.g. "Paper", or "Poster". `venue`+and `eventdate` may be useful too, though `eventdate` will not be+rendered by most CSL styles. Note that `venue` is for the event’s venue,+unlike `location` which describes the publisher’s location; do not use+the latter for an unpublished conference paper.++{#specifying-a-citation-style}+## Specifying a citation style++Citations and references can be formatted using any style supported by+the [Citation Style Language](https://citationstyles.org), listed in the+[Zotero Style Repository](https://www.zotero.org/styles). These files+are specified using the `--csl` option or the `csl` (or+`citation-style`) metadata field. By default, pandoc will use the+[Chicago Manual of Style](https://chicagomanualofstyle.org) author-date+format. (You can override this default by copying a CSL style of your+choice to `default.csl` in your user data directory.) The CSL project+provides further information on [finding and editing+styles](https://citationstyles.org/authors/).++The `--citation-abbreviations` option (or the `citation-abbreviations`+metadata field) may be used to specify a JSON file containing+abbreviations of journals that should be used in formatted+bibliographies when `form="short"` is specified. The format of the file+can be illustrated with an example:++```+{ "default": {+ "container-title": {+ "Lloyd's Law Reports": "Lloyd's Rep",+ "Estates Gazette": "EG",+ "Scots Law Times": "SLT"+ }+ }+}+```++{#citations-in-note-styles}+## Citations in note styles++Pandoc’s citation processing is designed to allow you to move between+author-date, numerical, and note styles without modifying the markdown+source. When you’re using a note style, avoid inserting footnotes+manually. Instead, insert citations just as you would in an author-date+style—for example,++```+Blah blah [@foo, p. 33].+```++The footnote will be created automatically. Pandoc will take care of+removing the space and moving the note before or after the period,+depending on the setting of `notes-after-punctuation`, as described+below in [Other relevant metadata+fields](#other-relevant-metadata-fields).++In some cases you may need to put a citation inside a regular footnote.+Normal citations in footnotes (such as `[@foo, p. 33]`) will be rendered+in parentheses. In-text citations (such as `@foo [p. 33]`) will be+rendered without parentheses. (A comma will be added if appropriate.)+Thus:++```+[^1]: Some studies [@foo; @bar, p. 33] show that+frubulicious zoosnaps are quantical. For a survey+of the literature, see @baz [chap. 1].+```++{#placement-of-the-bibliography}+## Placement of the bibliography++If the style calls for a list of works cited, it will be placed in a div+with id `refs`, if one exists:++```+::: {#refs}+:::+```++Otherwise, it will be placed at the end of the document. Generation of+the bibliography can be suppressed by setting+`suppress-bibliography: true` in the YAML metadata.++If you wish the bibliography to have a section heading, you can set+`reference-section-title` in the metadata, or put the heading at the+beginning of the div with id `refs` (if you are using it) or at the end+of your document:++```+last paragraph...++# References+```++The bibliography will be inserted after this heading. Note that the+`unnumbered` class will be added to this heading, so that the section+will not be numbered.++If you want to put the bibliography into a variable in your template,+one way to do that is to put the div with id `refs` into a metadata+field, e.g.++```+---+refs: |+ ::: {#refs}+ :::+...+```++You can then put the variable `$refs$` into your template where you want+the bibliography to be placed.++{#including-uncited-items-in-the-bibliography}+## Including uncited items in the bibliography++If you want to include items in the bibliography without actually citing+them in the body text, you can define a dummy `nocite` metadata field+and put the citations there:++```+---+nocite: |+ @item1, @item2+...++@item3+```++In this example, the document will contain a citation for `item3` only,+but the bibliography will contain entries for `item1`, `item2`, and+`item3`.++It is possible to create a bibliography with all the citations, whether+or not they appear in the document, by using a wildcard:++```+---+nocite: |+ @*+...+```++For LaTeX output, you can also use+[`natbib`](https://ctan.org/pkg/natbib) or+[`biblatex`](https://ctan.org/pkg/biblatex) to render the bibliography.+In order to do so, specify bibliography files as outlined above, and add+`--natbib` or `--biblatex` argument to pandoc invocation. Bear in mind+that bibliography files have to be in either BibTeX (for `--natbib`) or+BibLaTeX (for `--biblatex`) format.++{#other-relevant-metadata-fields}+## Other relevant metadata fields++A few other metadata fields affect bibliography formatting:++: `link-citations`++ If true, citations will be hyperlinked to the corresponding+ bibliography entries (for author-date and numerical styles only).+ Defaults to false.+: `link-bibliography`++ If true, DOIs, PMCIDs, PMID, and URLs in bibliographies will be+ rendered as hyperlinks. (If an entry contains a DOI, PMCID, PMID, or+ URL, but none of these fields are rendered by the style, then the+ title, or in the absence of a title the whole entry, will be+ hyperlinked.) Defaults to true.+: `lang`++ The `lang` field will affect how the style is localized, for example+ in the translation of labels, the use of quotation marks, and the way+ items are sorted. (For backwards compatibility, `locale` may be used+ instead of `lang`, but this use is deprecated.)++ A BCP 47 language tag is expected: for example, `en`, `de`, `en-US`,+ `fr-CA`, `ug-Cyrl`. The unicode extension syntax (after `-u-`) may be+ used to specify options for collation (sorting) more precisely. Here+ are some examples:++ - `zh-u-co-pinyin` – Chinese with the Pinyin collation.+ - `es-u-co-trad` – Spanish with the traditional collation (with `Ch`+ sorting after `C`).+ - `fr-u-kb` – French with "backwards" accent sorting (with `coté`+ sorting after `côte`).+ - `en-US-u-kf-upper` – English with uppercase letters sorting before+ lower (default is lower before upper).+: `notes-after-punctuation`++ If true (the default for note styles), pandoc will put footnote+ references or superscripted numerical citations after following+ punctuation. For example, if the source contains+ `blah blah [@jones99].`, the result will look like `blah blah.[^1]`,+ with the note moved after the period and the space collapsed. If+ false, the space will still be collapsed, but the footnote will not be+ moved after the punctuation. The option may also be used in numerical+ styles that use superscripts for citation numbers (but for these+ styles the default is not to move the citation).++{#slide-shows}+# Slide shows++You can use pandoc to produce an HTML + JavaScript slide presentation+that can be viewed via a web browser. There are five ways to do this,+using [S5](https://meyerweb.com/eric/tools/s5/),+[DZSlides](https://paulrouget.com/dzslides/),+[Slidy](https://www.w3.org/Talks/Tools/Slidy2/),+[Slideous](https://goessner.net/articles/slideous/), or+[reveal.js](https://revealjs.com/). You can also produce a PDF slide+show using LaTeX [`beamer`](https://ctan.org/pkg/beamer), or slide shows+in Microsoft+[PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint) format.++Here’s the Markdown source for a simple slide show, `habits.txt`:++```+% Habits+% John Doe+% March 22, 2005++# In the morning++## Getting up++- Turn off alarm+- Get out of bed++## Breakfast++- Eat eggs+- Drink coffee++# In the evening++## Dinner++- Eat spaghetti+- Drink wine++------------------++++## Going to sleep++- Get in bed+- Count sheep+```++To produce an HTML/JavaScript slide show, simply type++```+pandoc -t FORMAT -s habits.txt -o habits.html+```++where `FORMAT` is either `s5`, `slidy`, `slideous`, `dzslides`, or+`revealjs`.++For Slidy, Slideous, reveal.js, and S5, the file produced by pandoc with+the `-s/--standalone` option embeds a link to JavaScript and CSS files,+which are assumed to be available at the relative path `s5/default` (for+S5), `slideous` (for Slideous), `reveal.js` (for reveal.js), or at the+Slidy website at `w3.org` (for Slidy). (These paths can be changed by+setting the `slidy-url`, `slideous-url`, `revealjs-url`, or `s5-url`+variables; see [Variables for HTML slides](#variables-for-html-slides),+above.) For DZSlides, the (relatively short) JavaScript and CSS are+included in the file by default.++With all HTML slide formats, the `--self-contained` option can be used+to produce a single file that contains all of the data necessary to+display the slide show, including linked scripts, stylesheets, images,+and videos.++To produce a PDF slide show using beamer, type++```+pandoc -t beamer habits.txt -o habits.pdf+```++Note that a reveal.js slide show can also be converted to a PDF by+printing it to a file from the browser.++To produce a PowerPoint slide show, type++```+pandoc habits.txt -o habits.pptx+```++{#structuring-the-slide-show}+## Structuring the slide show++By default, the _slide level_ is the highest heading level in the+hierarchy that is followed immediately by content, and not another+heading, somewhere in the document. In the example above, level-1+headings are always followed by level-2 headings, which are followed by+content, so the slide level is 2. This default can be overridden using+the `--slide-level` option.++The document is carved up into slides according to the following rules:++- A horizontal rule always starts a new slide.++- A heading at the slide level always starts a new slide.++- Headings _below_ the slide level in the hierarchy create headings+ _within_ a slide. (In beamer, a "block" will be created. If the+ heading has the class `example`, an `exampleblock` environment will be+ used; if it has the class `alert`, an `alertblock` will be used;+ otherwise a regular `block` will be used.)++- Headings _above_ the slide level in the hierarchy create "title+ slides," which just contain the section title and help to break the+ slide show into sections. Non-slide content under these headings will+ be included on the title slide (for HTML slide shows) or in a+ subsequent slide with the same title (for beamer).++- A title page is constructed automatically from the document’s title+ block, if present. (In the case of beamer, this can be disabled by+ commenting out some lines in the default template.)++These rules are designed to support many different styles of slide show.+If you don’t care about structuring your slides into sections and+subsections, you can either just use level-1 headings for all slides (in+that case, level 1 will be the slide level) or you can set+`--slide-level=0`.++Note: in reveal.js slide shows, if slide level is 2, a two-dimensional+layout will be produced, with level-1 headings building horizontally and+level-2 headings building vertically. It is not recommended that you use+deeper nesting of section levels with reveal.js unless you set+`--slide-level=0` (which lets reveal.js produce a one-dimensional layout+and only interprets horizontal rules as slide boundaries).++{#powerpoint-layout-choice}+### PowerPoint layout choice++When creating slides, the pptx writer chooses from a number of+pre-defined layouts, based on the content of the slide:++: Title Slide++ This layout is used for the initial slide, which is generated and+ filled from the metadata fields `date`, `author`, and `title`, if they+ are present.+: Section Header++ This layout is used for what pandoc calls "title slides", i.e. slides+ which start with a header which is above the slide level in the+ hierarchy.+: Two Content++ This layout is used for two-column slides, i.e. slides containing a+ div with class `columns` which contains at least two divs with class+ `column`.+: Comparison++ This layout is used instead of "Two Content" for any two-column slides+ in which at least one column contains text followed by non-text+ (e.g. an image or a table).+: Content with Caption++ This layout is used for any non-two-column slides which contain text+ followed by non-text (e.g. an image or a table).+: Blank++ This layout is used for any slides which only contain blank content,+ e.g. a slide containing only speaker notes, or a slide containing only+ a non-breaking space.+: Title and Content++ This layout is used for all slides which do not match the criteria for+ another layout.++These layouts are chosen from the default pptx reference doc included+with pandoc, unless an alternative reference doc is specified using+`--reference-doc`.++{#incremental-lists}+## Incremental lists++By default, these writers produce lists that display "all at once." If+you want your lists to display incrementally (one item at a time), use+the `-i` option. If you want a particular list to depart from the+default, put it in a `div` block with class `incremental` or+`nonincremental`. So, for example, using the `fenced div` syntax, the+following would be incremental regardless of the document default:++```+::: incremental++- Eat spaghetti+- Drink wine++:::+```++or++```+::: nonincremental++- Eat spaghetti+- Drink wine++:::+```++While using `incremental` and `nonincremental` divs is the recommended+method of setting incremental lists on a per-case basis, an older method+is also supported: putting lists inside a blockquote will depart from+the document default (that is, it will display incrementally without the+`-i` option and all at once with the `-i` option):++```+> - Eat spaghetti+> - Drink wine+```++Both methods allow incremental and nonincremental lists to be mixed in a+single document.++If you want to include a block-quoted list, you can work around this+behavior by putting the list inside a fenced div, so that it is not the+direct child of the block quote:++```+> ::: wrapper+> - a+> - list in a quote+> :::+```++{#inserting-pauses}+## Inserting pauses++You can add "pauses" within a slide by including a paragraph containing+three dots, separated by spaces:++```+# Slide with a pause++content before the pause++. . .++content after the pause+```++Note: this feature is not yet implemented for PowerPoint output.++{#styling-the-slides}+## Styling the slides++You can change the style of HTML slides by putting customized CSS files+in `$DATADIR/s5/default` (for S5), `$DATADIR/slidy` (for Slidy), or+`$DATADIR/slideous` (for Slideous), where `$DATADIR` is the user data+directory (see `--data-dir`, above). The originals may be found in+pandoc’s system data directory (generally+`$CABALDIR/pandoc-VERSION/s5/default`). Pandoc will look there for any+files it does not find in the user data directory.++For dzslides, the CSS is included in the HTML file itself, and may be+modified there.++All [reveal.js configuration options](https://revealjs.com/config/) can+be set through variables. For example, themes can be used by setting the+`theme` variable:++```+-V theme=moon+```++Or you can specify a custom stylesheet using the `--css` option.++To style beamer slides, you can specify a `theme`, `colortheme`,+`fonttheme`, `innertheme`, and `outertheme`, using the `-V` option:++```+pandoc -t beamer habits.txt -V theme:Warsaw -o habits.pdf+```++Note that heading attributes will turn into slide attributes (on a+`<div>` or `<section>`) in HTML slide formats, allowing you to style+individual slides. In beamer, a number of heading classes and attributes+are recognized as frame options and will be passed through as options to+the frame: see [Frame attributes in+beamer](#frame-attributes-in-beamer), below.++{#speaker-notes}+## Speaker notes++Speaker notes are supported in reveal.js, PowerPoint (pptx), and beamer+output. You can add notes to your Markdown document thus:++```+::: notes++This is my note.++- It can contain Markdown+- like this list++:::+```++To show the notes window in reveal.js, press `s` while viewing the+presentation. Speaker notes in PowerPoint will be available, as usual,+in handouts and presenter view.++Notes are not yet supported for other slide formats, but the notes will+not appear on the slides themselves.++{#columns}+## Columns++To put material in side by side columns, you can use a native div+container with class `columns`, containing two or more div containers+with class `column` and a `width` attribute:++```+:::::::::::::: {.columns}+::: {.column width="40%"}+contents...+:::+::: {.column width="60%"}+contents...+:::+::::::::::::::+```++{#additional-columns-attributes-in-beamer}+### Additional columns attributes in beamer++The div containers with classes `columns` and `column` can optionally+have an `align` attribute. The class `columns` can optionally have a+`totalwidth` attribute or an `onlytextwidth` class.++```+:::::::::::::: {.columns align=center totalwidth=8em}+::: {.column width="40%"}+contents...+:::+::: {.column width="60%" align=bottom}+contents...+:::+::::::::::::::+```++The `align` attributes on `columns` and `column` can be used with the+values `top`, `top-baseline`, `center` and `bottom` to vertically align+the columns. It defaults to `top` in `columns`.++The `totalwidth` attribute limits the width of the columns to the given+value.++```+:::::::::::::: {.columns align=top .onlytextwidth}+::: {.column width="40%" align=center}+contents...+:::+::: {.column width="60%"}+contents...+:::+::::::::::::::+```++The class `onlytextwidth` sets the `totalwidth` to `\textwidth`.++See Section 12.7 of the [Beamer User’s+Guide](http://mirrors.ctan.org/macros/latex/contrib/beamer/doc/beameruserguide.pdf)+for more details.++{#frame-attributes-in-beamer}+## Frame attributes in beamer++Sometimes it is necessary to add the LaTeX `[fragile]` option to a frame+in beamer (for example, when using the `minted` environment). This can+be forced by adding the `fragile` class to the heading introducing the+slide:++```+# Fragile slide {.fragile}+```++All of the other frame attributes described in Section 8.1 of the+[Beamer User’s+Guide](http://mirrors.ctan.org/macros/latex/contrib/beamer/doc/beameruserguide.pdf)+may also be used: `allowdisplaybreaks`, `allowframebreaks`, `b`, `c`,+`s`, `t`, `environment`, `label`, `plain`, `shrink`, `standout`,+`noframenumbering`, `squeeze`. `allowframebreaks` is recommended+especially for bibliographies, as it allows multiple slides to be+created if the content overfills the frame:++```+# References {.allowframebreaks}+```++In addition, the `frameoptions` attribute may be used to pass arbitrary+frame options to a beamer slide:++```+# Heading {frameoptions="squeeze,shrink,customoption=foobar"}+```++{#background-in-reveal.js-beamer-and-pptx}+## Background in reveal.js, beamer, and pptx++Background images can be added to self-contained reveal.js slide shows,+beamer slide shows, and pptx slide shows.++{#on-all-slides-beamer-reveal.js-pptx}+### On all slides (beamer, reveal.js, pptx)++With beamer and reveal.js, the configuration option `background-image`+can be used either in the YAML metadata block or as a command-line+variable to get the same image on every slide.++Note that for reveal.js, the `background-image` will be used as a+`parallaxBackgroundImage` (see below).++For pptx, you can use a [reference doc](#option--reference-doc) in which+background images have been set on the [relevant+layouts](#powerpoint-layout-choice).++{#parallaxbackgroundimage-reveal.js}+#### `parallaxBackgroundImage` (reveal.js)++For reveal.js, there is also the reveal.js-native option+`parallaxBackgroundImage`, which produces a parallax scrolling+background. You must also set `parallaxBackgroundSize`, and can+optionally set `parallaxBackgroundHorizontal` and+`parallaxBackgroundVertical` to configure the scrolling behaviour. See+the [reveal.js+documentation](https://revealjs.com/backgrounds/#parallax-background)+for more details about the meaning of these options.++In reveal.js’s overview mode, the parallaxBackgroundImage will show up+only on the first slide.++{#on-individual-slides-reveal.js-pptx}+### On individual slides (reveal.js, pptx)++To set an image for a particular reveal.js or pptx slide, add+`{background-image="/path/to/image"}` to the first slide-level heading+on the slide (which may even be empty).++As the [HTML writers pass unknown attributes+through](#extension-link_attributes), other reveal.js background+settings also work on individual slides, including `background-size`,+`background-repeat`, `background-color`, `transition`, and+`transition-speed`. (The `data-` prefix will automatically be added.)++Note: `data-background-image` is also supported in pptx for consistency+with reveal.js – if `background-image` isn’t found,+`data-background-image` will be checked.++{#on-the-title-slide-reveal.js-pptx}+### On the title slide (reveal.js, pptx)++To add a background image to the automatically generated title slide for+reveal.js, use the `title-slide-attributes` variable in the YAML+metadata block. It must contain a map of attribute names and values.+(Note that the `data-` prefix is required here, as it isn’t added+automatically.)++For pptx, pass a [reference doc](#option--reference-doc) with the+background image set on the "Title Slide" layout.++{#example-reveal.js}+### Example (reveal.js)++```+---+title: My Slide Show+parallaxBackgroundImage: /path/to/my/background_image.png+title-slide-attributes:+ data-background-image: /path/to/title_image.png+ data-background-size: contain+---++## Slide One++Slide 1 has background_image.png as its background.++## {background-image="/path/to/special_image.jpg"}++Slide 2 has a special image for its background, even though the heading has no content.+```++{#epubs}+# EPUBs++{#epub-metadata}+## EPUB Metadata++EPUB metadata may be specified using the `--epub-metadata` option, but+if the source document is Markdown, it is better to use a [YAML metadata+block](#extension-yaml_metadata_block). Here is an example:++```+---+title:+- type: main+ text: My Book+- type: subtitle+ text: An investigation of metadata+creator:+- role: author+ text: John Smith+- role: editor+ text: Sarah Jones+identifier:+- scheme: DOI+ text: doi:10.234234.234/33+publisher: My Press+rights: © 2007 John Smith, CC BY-NC+ibooks:+ version: 1.3.4+...+```++The following fields are recognized:++: `identifier`++ Either a string value or an object with fields `text` and `scheme`.+ Valid values for `scheme` are `ISBN-10`, `GTIN-13`, `UPC`, `ISMN-10`,+ `DOI`, `LCCN`, `GTIN-14`, `ISBN-13`, `Legal deposit number`, `URN`,+ `OCLC`, `ISMN-13`, `ISBN-A`, `JP`, `OLCC`.+: `title`++ Either a string value, or an object with fields `file-as` and `type`,+ or a list of such objects. Valid values for `type` are `main`,+ `subtitle`, `short`, `collection`, `edition`, `extended`.+: `creator`++ Either a string value, or an object with fields `role`, `file-as`, and+ `text`, or a list of such objects. Valid values for `role` are [MARC+ relators](https://loc.gov/marc/relators/relaterm.html), but pandoc+ will attempt to translate the human-readable versions (like "author"+ and "editor") to the appropriate marc relators.+: `contributor`++ Same format as `creator`.+: `date`++ A string value in `YYYY-MM-DD` format. (Only the year is necessary.)+ Pandoc will attempt to convert other common date formats.+: `lang` (or legacy: `language`)++ A string value in [BCP 47](https://tools.ietf.org/html/bcp47) format.+ Pandoc will default to the local language if nothing is specified.+: `subject`++ Either a string value, or an object with fields `text`, `authority`,+ and `term`, or a list of such objects. Valid values for `authority`+ are either a [reserved authority+ value](https://idpf.github.io/epub-registries/authorities/) (currently+ `AAT`, `BIC`, `BISAC`, `CLC`, `DDC`, `CLIL`, `EuroVoc`, `MEDTOP`,+ `LCSH`, `NDC`, `Thema`, `UDC`, and `WGS`) or an absolute IRI+ identifying a custom scheme. Valid values for `term` are defined by+ the scheme.+: `description`++ A string value.+: `type`++ A string value.+: `format`++ A string value.+: `relation`++ A string value.+: `coverage`++ A string value.+: `rights`++ A string value.+: `belongs-to-collection`++ A string value. Identifies the name of a collection to which the EPUB+ Publication belongs.+: `group-position`++ The `group-position` field indicates the numeric position in which the+ EPUB Publication belongs relative to other works belonging to the same+ `belongs-to-collection` field.+: `cover-image`++ A string value (path to cover image).+: `css` (or legacy: `stylesheet`)++ A string value (path to CSS stylesheet).+: `page-progression-direction`++ Either `ltr` or `rtl`. Specifies the `page-progression-direction`+ attribute for the [`spine`+ element](http://idpf.org/epub/301/spec/epub-publications.html#sec-spine-elem).+: `ibooks`++ iBooks-specific metadata, with the following fields:++ - `version`: (string)+ - `specified-fonts`: `true`|`false` (default `false`)+ - `ipad-orientation-lock`: `portrait-only`|`landscape-only`+ - `iphone-orientation-lock`: `portrait-only`|`landscape-only`+ - `binding`: `true`|`false` (default `true`)+ - `scroll-axis`: `vertical`|`horizontal`|`default`++{#the-epubtype-attribute}+## The `epub:type` attribute++For `epub3` output, you can mark up the heading that corresponds to an+EPUB chapter using the [`epub:type`+attribute](http://www.idpf.org/epub/31/spec/epub-contentdocs.html#sec-epub-type-attribute).+For example, to set the attribute to the value `prologue`, use this+markdown:++```+# My chapter {epub:type=prologue}+```++Which will result in:++```+<body epub:type="frontmatter">+ <section epub:type="prologue">+ <h1>My chapter</h1>+```++Pandoc will output `<body epub:type="bodymatter">`, unless you use one+of the following values, in which case either `frontmatter` or+`backmatter` will be output.++|`epub:type` of first section|`epub:type` of body|+|---|---|+|prologue|frontmatter|+|abstract|frontmatter|+|acknowledgments|frontmatter|+|copyright-page|frontmatter|+|dedication|frontmatter|+|credits|frontmatter|+|keywords|frontmatter|+|imprint|frontmatter|+|contributors|frontmatter|+|other-credits|frontmatter|+|errata|frontmatter|+|revision-history|frontmatter|+|titlepage|frontmatter|+|halftitlepage|frontmatter|+|seriespage|frontmatter|+|foreword|frontmatter|+|preface|frontmatter|+|frontispiece|frontmatter|+|appendix|backmatter|+|colophon|backmatter|+|bibliography|backmatter|+|index|backmatter|++{#linked-media}+## Linked media++By default, pandoc will download media referenced from any `<img>`,+`<audio>`, `<video>` or `<source>` element present in the generated+EPUB, and include it in the EPUB container, yielding a completely+self-contained EPUB. If you want to link to external media resources+instead, use raw HTML in your source and add `data-external="1"` to the+tag with the `src` attribute. For example:++```+<audio controls="1">+ <source src="https://example.com/music/toccata.mp3"+ data-external="1" type="audio/mpeg">+ </source>+</audio>+```++If the input format already is HTML then `data-external="1"` will work+as expected for `<img>` elements. Similarly, for Markdown, external+images can be declared with `{external=1}`. Note that this+only works for images; the other media elements have no native+representation in pandoc’s AST and require the use of raw HTML.++{#epub-styling}+## EPUB styling++By default, pandoc will include some basic styling contained in its+`epub.css` data file. (To see this, use+`pandoc --print-default-data-file epub.css`.) To use a different CSS+file, just use the `--css` command line option. A few inline styles are+defined in addition; these are essential for correct formatting of+pandoc’s HTML output.++The `document-css` variable may be set if the more opinionated styling+of pandoc’s default HTML templates is desired (and in that case the+variables defined in [Variables for HTML](#variables-for-html) may be+used to fine-tune the style).++{#chunked-html}+# Chunked HTML++`pandoc -t chunkedhtml` will produce a zip archive of linked HTML files,+one for each section of the original document. Internal links will+automatically be adjusted to point to the right place, images linked to+under the working directory will be incorporated, and navigation links+will be added. In addition, a JSON file `sitemap.json` will be included+describing the hierarchical structure of the files.++If an output file without an extension is specified, then it will be+interpreted as a directory and the zip archive will be automatically+unpacked into it (unless it already exists, in which case an error will+be raised). Otherwise a `.zip` file will be produced.++The navigation links can be customized by adjusting the template. By+default, a table of contents is included only on the top page. To+include it on every page, set the `toc` variable manually.++{#jupyter-notebooks}+# Jupyter notebooks++When creating a [Jupyter+notebook](https://nbformat.readthedocs.io/en/latest/), pandoc will try+to infer the notebook structure. Code blocks with the class `code` will+be taken as code cells, and intervening content will be taken as+Markdown cells. Attachments will automatically be created for images in+Markdown cells. Metadata will be taken from the `jupyter` metadata+field. For example:++````+---+title: My notebook+jupyter:+ nbformat: 4+ nbformat_minor: 5+ kernelspec:+ display_name: Python 2+ language: python+ name: python2+ language_info:+ codemirror_mode:+ name: ipython+ version: 2+ file_extension: ".py"+ mimetype: "text/x-python"+ name: "python"+ nbconvert_exporter: "python"+ pygments_lexer: "ipython2"+ version: "2.7.15"+---++# Lorem ipsum++**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus+bibendum felis dictum sodales.++``` code+print("hello")+```++## Pyout++``` code+from IPython.display import HTML+HTML("""+<script>+console.log("hello");+</script>+<b>HTML</b>+""")+```++## Image++This image  will be+included as a cell attachment.+````++If you want to add cell attributes, group cells differently, or add+output to code cells, then you need to include divs to indicate the+structure. You can use either [fenced divs](#extension-fenced_divs) or+[native divs](#extension-native_divs) for this. Here is an example:++````+:::::: {.cell .markdown}+# Lorem++**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus+bibendum felis dictum sodales.+::::::++:::::: {.cell .code execution_count=1}+``` {.python}+print("hello")+```++::: {.output .stream .stdout}+```+hello+```+:::+::::::++:::::: {.cell .code execution_count=2}+``` {.python}+from IPython.display import HTML+HTML("""+<script>+console.log("hello");+</script>+<b>HTML</b>+""")+```++::: {.output .execute_result execution_count=2}+```{=html}+<script>+console.log("hello");+</script>+<b>HTML</b>+hello+```+:::+::::::+````++If you include raw HTML or TeX in an output cell, use the [raw+attribute](#extension-raw_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.++Note that options and extensions that affect reading and writing of+Markdown will also affect Markdown cells in ipynb notebooks. For+example, `--wrap=preserve` will preserve soft line breaks in Markdown+cells; `--markdown-headings=setext` will cause Setext-style headings to+be used; and `--preserve-tabs` will prevent tabs from being turned to+spaces.++{#syntax-highlighting}+# Syntax highlighting++Pandoc will automatically highlight syntax in [fenced code+blocks](#fenced-code-blocks) that are marked with a language name. The+Haskell library [skylighting](https://github.com/jgm/skylighting) is+used for highlighting. Currently highlighting is supported only for+HTML, EPUB, Docx, Ms, and LaTeX/PDF output. To see a list of language+names that pandoc will recognize, type+`pandoc --list-highlight-languages`.++The color scheme can be selected using the `--highlight-style` option.+The default color scheme is `pygments`, which imitates the default color+scheme used by the Python library pygments (though pygments is not+actually used to do the highlighting). To see a list of highlight+styles, type `pandoc --list-highlight-styles`.++If you are not satisfied with the predefined styles, you can use+`--print-highlight-style` to generate a JSON `.theme` file which can be+modified and used as the argument to `--highlight-style`. To get a JSON+version of the `pygments` style, for example:++```+pandoc --print-highlight-style pygments > my.theme+```++Then edit `my.theme` and use it like this:++```+pandoc --highlight-style my.theme+```++If you are not satisfied with the built-in highlighting, or you want to+highlight a language that isn’t supported, you can use the+`--syntax-definition` option to load a [KDE-style XML syntax definition+file](https://docs.kde.org/stable5/en/kate/katepart/highlight.html).+Before writing your own, have a look at KDE’s [repository of syntax+definitions](https://github.com/KDE/syntax-highlighting/tree/master/data/syntax).++To disable highlighting, use the `--no-highlight` option.++{#custom-styles}+# Custom Styles++Custom styles can be used in the docx and ICML formats.++{#output}+## Output++By default, pandoc’s docx and ICML output applies a predefined set of+styles for blocks such as paragraphs and block quotes, and uses largely+default formatting (italics, bold) for inlines. This will work for most+purposes, especially alongside a `reference.docx` file. However, if you+need to apply your own styles to blocks, or match a preexisting set of+styles, pandoc allows you to define custom styles for blocks and text+using `div`s and `span`s, respectively.++If you define a `div` or `span` with the attribute `custom-style`,+pandoc will apply your specified style to the contained elements (with+the exception of elements whose function depends on a style, like+headings, code blocks, block quotes, or links). So, for example, using+the `bracketed_spans` syntax,++```+[Get out]{custom-style="Emphatically"}, he said.+```++would produce a docx file with "Get out" styled with character style+`Emphatically`. Similarly, using the `fenced_divs` syntax,++```+Dickinson starts the poem simply:++::: {custom-style="Poetry"}+| A Bird came down the Walk---+| He did not know I saw---+:::+```++would style the two contained lines with the `Poetry` paragraph style.++For docx output, styles will be defined in the output file as inheriting+from normal text, if the styles are not yet in your reference.docx. If+they are already defined, pandoc will not alter the definition.++This feature allows for greatest customization in conjunction with+[pandoc filters](https://pandoc.org/filters.html). If you want all+paragraphs after block quotes to be indented, you can write a filter to+apply the styles necessary. If you want all italics to be transformed to+the `Emphasis` character style (perhaps to change their color), you can+write a filter which will transform all italicized inlines to inlines+within an `Emphasis` custom-style `span`.++For docx output, you don’t need to enable any extensions for custom+styles to work.++{#input}+## Input++The docx reader, by default, only reads those styles that it can convert+into pandoc elements, either by direct conversion or interpreting the+derivation of the input document’s styles.++By enabling the [`styles` extension](#ext-styles) in the docx reader+(`-f docx+styles`), you can produce output that maintains the styles of+the input document, using the `custom-style` class. Paragraph styles are+interpreted as divs, while character styles are interpreted as spans.++For example, using the `custom-style-reference.docx` file in the test+directory, we have the following different outputs:++Without the `+styles` extension:++```+$ pandoc test/docx/custom-style-reference.docx -f docx -t markdown+This is some text.++This is text with an *emphasized* text style. And this is text with a+**strengthened** text style.++> Here is a styled paragraph that inherits from Block Text.+```++And with the extension:++```+$ pandoc test/docx/custom-style-reference.docx -f docx+styles -t markdown++::: {custom-style="First Paragraph"}+This is some text.+:::++::: {custom-style="Body Text"}+This is text with an [emphasized]{custom-style="Emphatic"} text style.+And this is text with a [strengthened]{custom-style="Strengthened"}+text style.+:::++::: {custom-style="My Block Style"}+> Here is a styled paragraph that inherits from Block Text.+:::+```++With these custom styles, you can use your input document as a+reference-doc while creating docx output (see below), and maintain the+same styles in your input and output files.++{#custom-readers-and-writers}+# Custom readers and writers++Pandoc can be extended with custom readers and writers written in+[Lua](https://www.lua.org). (Pandoc includes a Lua interpreter, so Lua+need not be installed separately.)++To use a custom reader or writer, simply specify the path to the Lua+script in place of the input or output format. For example:++```+pandoc -t data/sample.lua+pandoc -f my_custom_markup_language.lua -t latex -s+```++If the script is not found relative to the working directory, it will be+sought in the `custom` subdirectory of the user data directory (see+`--data-dir`).++A custom reader is a Lua script that defines one function, Reader, which+takes a string as input and returns a Pandoc AST. See the [Lua filters+documentation](https://pandoc.org/lua-filters.html) for documentation of+the functions that are available for creating pandoc AST elements. For+parsing, the [lpeg](http://www.inf.puc-rio.br/~roberto/lpeg/) parsing+library is available by default. To see a sample custom reader:++```+pandoc --print-default-data-file creole.lua+```++If you want your custom reader to have access to reader options+(e.g. the tab stop setting), you give your Reader function a second+`options` parameter.++A custom writer is a Lua script that defines a function that specifies+how to render each element in a Pandoc AST. See the+[djot-writer.lua](https://github.com/jgm/djot.lua/blob/main/djot-writer.lua)+for a full-featured example.++Note that custom writers have no default template. If you want to use+`--standalone` with a custom writer, you will need to specify a template+manually using `--template` or add a new default template with the name+`default.NAME_OF_CUSTOM_WRITER.lua` to the `templates` subdirectory of+your user data directory (see [Templates](#templates)).++{#reproducible-builds}+# Reproducible builds++Some of the document formats pandoc targets (such as EPUB, docx, and+ODT) include build timestamps in the generated document. That means that+the files generated on successive builds will differ, even if the source+does not. To avoid this, set the `SOURCE_DATE_EPOCH` environment+variable, and the timestamp will be taken from it instead of the current+time. `SOURCE_DATE_EPOCH` should contain an integer unix timestamp+(specifying the number of seconds since midnight UTC January 1, 1970).++Some document formats also include a unique identifier. For EPUB, this+can be set explicitly by setting the `identifier` metadata field (see+[EPUB Metadata](#epub-metadata), above).++{#accessible-pdfs-and-pdf-archiving-standards}+# Accessible PDFs and PDF archiving standards++PDF is a flexible format, and using PDF in certain contexts requires+additional conventions. For example, PDFs are not accessible by default;+they define how characters are placed on a page but do not contain+semantic information on the content. However, it is possible to generate+accessible PDFs, which use tagging to add semantic information to the+document.++Pandoc defaults to LaTeX to generate PDF. Tagging support in LaTeX is in+development and not readily available, so PDFs generated in this way+will always be untagged and not accessible. This means that alternative+engines must be used to generate accessible PDFs.++The PDF standards PDF/A and PDF/UA define further restrictions intended+to optimize PDFs for archiving and accessibility. Tagging is commonly+used in combination with these standards to ensure best results.++Note, however, that standard compliance depends on many things,+including the colorspace of embedded images. Pandoc cannot check this,+and external programs must be used to ensure that generated PDFs are in+compliance.++{#context}+## ConTeXt++ConTeXt always produces tagged PDFs, but the quality depends on the+input. The default ConTeXt markup generated by pandoc is optimized for+readability and reuse, not tagging. Enable the+[`tagging`](#extension--tagging) format extension to force markup that+is optimized for tagging. This can be combined with the `pdfa` variable+to generate standard-compliant PDFs. E.g.:++```+pandoc --to=context+tagging -V pdfa=3a+```++A recent `context` version should be used, as older versions contained a+bug that lead to invalid PDF metadata.++{#weasyprint}+## WeasyPrint++The HTML-based engine WeasyPrint includes experimental support for PDF/A+and PDF/UA since version 57. Tagged PDFs can created with++```+pandoc --pdf-engine=weasyprint \+ --pdf-engine-opt=--pdf-variant=pdf/ua-1 ...+```++The feature is experimental and standard compliance should not be+assumed.++{#prince-xml}+## Prince XML++The non-free HTML-to-PDf converter `prince` has extensive support for+various PDF standards as well as tagging. E.g.:++```+pandoc --pdf-engine=prince \+ --pdf-engine-opt=--tagged-pdf ...+```++See the prince documentation for more info.++{#word-processors}+## Word Processors++Word processors like LibreOffice and MS Word can also be used to+generate standardized and tagged PDF output. Pandoc does not support+direct conversions via these tools. However, pandoc can convert a+document to a `docx` or `odt` file, which can then be opened and+converted to PDF with the respective word processor. See the+documentation for+[Word](https://support.microsoft.com/en-us/office/create-accessible-pdfs-064625e0-56ea-4e16-ad71-3aa33bb4b7ed)+and+[LibreOffice](https://help.libreoffice.org/7.1/en-US/text/shared/01/ref_pdf_export_general.html).++{#running-pandoc-as-a-web-server}+# Running pandoc as a web server++If you rename (or symlink) the pandoc executable to `pandoc-server`, or+if you call pandoc with `server` as the first argument, it will start up+a web server with a JSON API. This server exposes most of the conversion+functionality of pandoc. For full documentation, see the+[pandoc-server](https://github.com/jgm/pandoc/blob/master/doc/pandoc-server.md)+man page.++If you rename (or symlink) the pandoc executable to `pandoc-server.cgi`,+it will function as a CGI program exposing the same API as+`pandoc-server`.++`pandoc-server` is designed to be maximally secure; it uses Haskell’s+type system to provide strong guarantees that no I/O will be performed+on the server during pandoc conversions.++{#running-pandoc-as-a-lua-interpreter}+# Running pandoc as a Lua interpreter++Calling the pandoc executable under the name `pandoc-lua` or with `lua`+as the first argument will make it function as a standalone Lua+interpreter. The behavior is mostly identical to that of the [standalone+`lua` executable](https://www.lua.org/manual/5.4/manual.html#7), version+5.4. However, there is no REPL yet, and the `-i` option has no effect.+For full documentation, see the+[pandoc-lua](https://github.com/jgm/pandoc/blob/master/doc/pandoc-lua.md)+man page.++{#a-note-on-security}+# A note on security++1. Although pandoc itself will not create or modify any files other than+ those you explicitly ask it create (with the exception of temporary+ files used in producing PDFs), a filter or custom writer could in+ principle do anything on your file system. Please audit filters and+ custom writers very carefully before using them.++2. Several input formats (including HTML, Org, and RST) support+ `include` directives that allow the contents of a file to be included+ in the output. An untrusted attacker could use these to view the+ contents of files on the file system. (Using the `--sandbox` option+ can protect against this threat.)++3. Several output formats (including RTF, FB2, HTML with+ `--self-contained`, EPUB, Docx, and ODT) will embed encoded or raw+ images into the output file. An untrusted attacker could exploit this+ to view the contents of non-image files on the file system. (Using+ the `--sandbox` option can protect against this threat, but will also+ prevent including images in these formats.)++4. If your application uses pandoc as a Haskell library (rather than+ shelling out to the executable), it is possible to use it in a mode+ that fully isolates pandoc from your file system, by running the+ pandoc operations in the `PandocPure` monad. See the document [Using+ the pandoc API](https://pandoc.org/using-the-pandoc-api.html) for+ more details. (This corresponds to the use of the `--sandbox` option+ on the command line.)++5. Pandoc’s parsers can exhibit pathological performance on some corner+ cases. It is wise to put any pandoc operations under a timeout, to+ avoid DOS attacks that exploit these issues. If you are using the+ pandoc executable, you can add the command line options+ `+RTS -M512M -RTS` (for example) to limit the heap size to 512MB.+ Note that the `commonmark` parser (including `commonmark_x` and+ `gfm`) is much less vulnerable to pathological performance than the+ `markdown` parser, so it is a better choice when processing untrusted+ input.++6. The HTML generated by pandoc is not guaranteed to be safe. If+ `raw_html` is enabled for the Markdown input, users can inject+ arbitrary HTML. Even if `raw_html` is disabled, users can include+ dangerous content in URLs and attributes. To be safe, you should run+ all HTML generated from untrusted user input through an HTML+ sanitizer.++{#authors}+# Authors++Copyright 2006–2022 John MacFarlane (jgm@berkeley.edu). Released under+the+[GPL](https://www.gnu.org/copyleft/gpl.html){title="GNU General Public License"},+version 2 or greater. This software carries no warranty of any kind.+(See COPYRIGHT for full copyright and warranty notices.) For a full list+of contributors, see the file AUTHORS.md in the pandoc source code.++[^1]: The point of this rule is to ensure that normal paragraphs+ starting with people’s initials, like++ ```+ B. Russell won a Nobel Prize (but not for "On Denoting").+ ```++ do not get treated as list items.++ This rule will not prevent++ ```+ (C) 2007 Joe Smith+ ```++ from being interpreted as a list item. In this case, a backslash+ escape can be used:++ ```+ (C\) 2007 Joe Smith+ ```++[^2]: I have been influenced by the suggestions of [David+ Wheeler](https://justatheory.com/2009/02/modest-markdown-proposal/).++[^3]: This scheme is due to Michel Fortin, who proposed it on the+ [Markdown discussion+ list](http://six.pairlist.net/pipermail/markdown-discuss/2005-March/001097.html).++[^4]: To see why laziness is incompatible with relaxing the requirement+ of a blank line between items, consider the following example:++ ```+ bar+ : definition+ foo+ : definition+ ```++ Is this a single list item with two definitions of "bar," the first of+ which is lazily wrapped, or two list items? To remove the ambiguity we+ must either disallow lazy wrapping or require a blank line between+ list items.
+ djot.cabal view
@@ -0,0 +1,88 @@+cabal-version: 3.0+name: djot+version: 0.1.0.0+synopsis: Parser and renderer for djot light markup syntax.+description: Djot (<https://djot.net>) is a light markup language.+ This package provides a data structure to represent+ djot documents, a very fast parser, and functions+ to render a parsed document as HTML and as djot.+license: MIT+license-file: LICENSE+author: John MacFarlane+maintainer: jgm@berkeley.edu+copyright: Copyright (C) 2024 John MacFarlane+category: Text+build-type: Simple+extra-doc-files: CHANGELOG.md+extra-source-files: test/*.test+ benchmark/m.dj++Library+ build-depends: base >= 4.12 && < 5,+ bytestring >= 0.11.3,+ containers,+ mtl,+ text,+ doclayout+ hs-source-dirs: src+ default-language: Haskell2010+ exposed-modules: Djot+ Djot.AST+ Djot.Parse+ Djot.Options+ Djot.Attributes+ Djot.Inlines+ Djot.Blocks+ Djot.Html+ Djot.Djot+ ghc-options: -Wall -O2++executable djoths+ main-is: Main.hs+ build-depends: base >= 4.12 && < 5,+ djot,+ bytestring,+ containers,+ text,+ doclayout+ hs-source-dirs: app+ default-language: Haskell2010+ ghc-options: -Wall -O2 -rtsopts -threaded++test-suite test-djot+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: test+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-K40K -with-rtsopts=-kc40K+ if impl(ghc >= 8.10)+ ghc-options: -Wunused-packages+ build-depends:+ base >= 4.12 && <5+ , djot+ , text+ , bytestring+ , directory+ , filepath+ , doclayout+ , tasty+ , tasty-hunit+ , tasty-quickcheck+ default-language: Haskell2010++benchmark benchmark-djot+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: benchmark+ build-depends:+ djot+ , base >= 4.9 && < 5+ , bytestring+ , directory+ , filepath+ , doclayout+ , tasty-bench+ ghc-options: -O2 -threaded -rtsopts -with-rtsopts=-K10K -with-rtsopts=-kc10K+ if impl(ghc >= 8.10)+ ghc-options: -Wunused-packages+ default-language: Haskell2010+
+ src/Djot.hs view
@@ -0,0 +1,17 @@+module Djot+ ( parseDoc+ , renderHtml+ , renderDjot+ , toIdentifier+ , ParseOptions(..)+ , SourcePosOption(..)+ , RenderOptions(..)+ , module Djot.AST+ )+where++import Djot.Options (ParseOptions(..), RenderOptions(..), SourcePosOption(..))+import Djot.Blocks (parseDoc, toIdentifier)+import Djot.Html (renderHtml)+import Djot.Djot (renderDjot)+import Djot.AST
+ src/Djot/AST.hs view
@@ -0,0 +1,445 @@+{-# LANGUAGE Strict #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+module Djot.AST+( Inline(..),+ Many(..),+ Inlines,+ MathStyle(..),+ Format(..),+ Node(Node),+ Pos(..),+ addAttr,+ addPos,+ Block(..),+ Blocks,+ Doc(..),+ NoteMap(..),+ insertNote,+ lookupNote,+ ReferenceMap(..),+ insertReference,+ lookupReference,+ normalizeLabel,+ Attr(..),+ Target(..),+ TaskStatus(..),+ Align(..),+ Cell(..),+ CellType(..),+ Caption(..),+ ListSpacing(..),+ OrderedListAttributes(..),+ OrderedListDelim(..),+ OrderedListStyle(..),+ QuoteType(..),+ delete,+ displayMath,+ insert,+ emailLink,+ emph,+ footnoteReference,+ hardBreak,+ highlight,+ image,+ inlineMath,+ link,+ nonBreakingSpace,+ rawInline,+ softBreak,+ span_,+ str,+ strong,+ subscript,+ superscript,+ singleQuoted,+ doubleQuoted,+ symbol,+ verbatim,+ urlLink,+ para,+ section,+ heading,+ blockQuote,+ codeBlock,+ div,+ bulletList,+ orderedList,+ definitionList,+ taskList,+ thematicBreak,+ table,+ rawBlock,+ inlinesToByteString+ )+where++import Prelude hiding (div)+import Data.ByteString (ByteString)+import Data.Sequence (Seq)+import qualified Data.Sequence as Seq+import qualified Data.Map.Strict as M+import Data.Set (Set)+import Data.Data (Data, Typeable)+import qualified Data.ByteString.Char8 as B8+import GHC.Generics (Generic)++-- import Debug.Trace++newtype Attr = Attr [(ByteString, ByteString)]+ deriving (Show, Eq, Ord, Typeable, Generic, Data)++instance Semigroup Attr where+ Attr as <> Attr bs =+ Attr $ foldr integrate bs as++instance Monoid Attr where+ mappend = (<>)+ mempty = Attr mempty++integrate :: (ByteString, ByteString)+ -> [(ByteString, ByteString)] -> [(ByteString, ByteString)]+integrate (k,v) kvs =+ case lookup k kvs of+ Nothing -> (k,v) : kvs+ Just v'+ | k == "class" ->+ (k, v <> " " <> v') : filter (\(k',_) -> k' /= "class") kvs+ | otherwise -> kvs++data Pos = NoPos | Pos Int Int Int Int -- start line, start col, end line, end col+ deriving (Show, Eq, Ord, Typeable, Generic)++instance Semigroup Pos where+ Pos sl1 sc1 _ _ <> Pos _ _ el2 ec2 =+ Pos sl1 sc1 el2 ec2+ NoPos <> _ = NoPos+ _ <> NoPos = NoPos++instance Monoid Pos where+ mappend = (<>)+ mempty = NoPos++data Node a = Node Pos Attr a+ deriving (Show, Eq, Ord, Functor, Traversable, Foldable, Typeable, Generic)++{-# INLINE addAttr #-}+addAttr :: Attr -> Node a -> Node a+addAttr attr (Node pos attr' bs) = Node pos (attr' <> attr) bs++{-# INLINE addPos #-}+addPos :: Pos -> Node a -> Node a+addPos pos (Node _ attr bs) = Node pos attr bs++newtype Format = Format { unFormat :: ByteString }+ deriving (Show, Eq, Ord, Typeable, Generic)++data MathStyle = DisplayMath | InlineMath+ deriving (Show, Ord, Eq, Typeable, Generic)++data Target =+ Direct ByteString+ | Reference ByteString+ deriving (Show, Ord, Eq, Typeable, Generic)++data QuoteType = SingleQuotes | DoubleQuotes+ deriving (Show, Ord, Eq, Typeable, Generic)++data Inline =+ Str ByteString+ | Emph Inlines+ | Strong Inlines+ | Highlight Inlines+ | Insert Inlines+ | Delete Inlines+ | Superscript Inlines+ | Subscript Inlines+ | Verbatim ByteString+ | Symbol ByteString+ | Math MathStyle ByteString+ | Link Inlines Target+ | Image Inlines Target+ | Span Inlines+ | FootnoteReference ByteString+ | UrlLink ByteString+ | EmailLink ByteString+ | RawInline Format ByteString+ | NonBreakingSpace+ | Quoted QuoteType Inlines+ | SoftBreak+ | HardBreak+ deriving (Show, Ord, Eq, Typeable, Generic)++newtype Many a = Many { unMany :: Seq a }+ deriving (Show, Ord, Eq, Functor, Traversable, Foldable, Typeable, Generic)++type Inlines = Many (Node Inline)++instance Semigroup Inlines where+ Many as <> Many bs =+ case (Seq.viewr as, Seq.viewl bs) of+ (as' Seq.:> Node pos1 attr (Str s), Node pos2 attr' (Str t) Seq.:< bs')+ | attr == mempty && attr' /= mempty+ , (sa, sb) <- B8.spanEnd (not . isSpaceOrTab) s+ , not (B8.null sb)+ -> if B8.null sa+ then+ Many (as' <> (Node (pos1 <> pos2) attr' (Str (s <> t)) Seq.<| bs'))+ else+ let sblen = B8.length (B8.filter (\c -> c < '\128' || c >= '\192') sb)+ (pos1', pos2') =+ case pos1 <> pos2 of+ NoPos -> (NoPos, NoPos)+ Pos sl sc el ec ->+ (Pos sl sc el (ec - sblen),+ Pos sl (sc + sblen + 1) el ec)+ in Many ((as' Seq.|> Node pos1' mempty (Str sa)+ Seq.|> Node pos2' attr (Str (sb <> t))) <> bs')+ | attr == attr'+ -> Many (as' <> (Node (pos1 <> pos2) attr (Str (s <> t)) Seq.<| bs'))+ (as' Seq.:> Node pos attr (Str s), Node _ _ HardBreak Seq.:< _)+ | B8.all isSpaceOrTab (B8.takeEnd 1 s)+ -> Many (as' <> (Node pos attr (Str (B8.dropWhileEnd isSpaceOrTab s))+ Seq.<| bs))+ _ -> Many (as <> bs)+ where+ isSpaceOrTab ' ' = True+ isSpaceOrTab '\t' = True+ isSpaceOrTab _ = False++instance Monoid Inlines where+ mappend = (<>)+ mempty = Many mempty++data ListSpacing = Tight | Loose+ deriving (Show, Ord, Eq, Typeable, Generic)++data OrderedListStyle =+ Decimal | LetterUpper | LetterLower | RomanUpper | RomanLower+ deriving (Show, Ord, Eq, Typeable, Generic)++data OrderedListDelim =+ RightPeriod | RightParen | LeftRightParen+ deriving (Show, Ord, Eq, Typeable, Generic)++data OrderedListAttributes =+ OrderedListAttributes+ { orderedListStyle :: OrderedListStyle+ , orderedListDelim :: OrderedListDelim+ , orderedListStart :: Int }+ deriving (Show, Ord, Eq, Typeable, Generic)++data TaskStatus = Complete | Incomplete+ deriving (Show, Ord, Eq, Typeable, Generic)++newtype Caption = Caption Blocks+ deriving (Show, Ord, Eq, Typeable, Generic)++data Align = AlignLeft | AlignRight | AlignCenter | AlignDefault+ deriving (Show, Ord, Eq, Typeable, Generic)++data CellType = HeadCell | BodyCell+ deriving (Show, Ord, Eq, Typeable, Generic)++data Cell = Cell CellType Align Inlines+ deriving (Show, Ord, Eq, Typeable, Generic)++data Block =+ Para Inlines+ | Section Blocks+ | Heading Int Inlines+ | BlockQuote Blocks+ | CodeBlock ByteString ByteString+ | Div Blocks+ | OrderedList OrderedListAttributes ListSpacing [Blocks]+ | BulletList ListSpacing [Blocks]+ | TaskList ListSpacing [(TaskStatus, Blocks)]+ | DefinitionList ListSpacing [(Inlines, Blocks)]+ | ThematicBreak+ | Table (Maybe Caption) [[Cell]]+ | RawBlock Format ByteString+ deriving (Show, Ord, Eq, Typeable, Generic)++type Blocks = Many (Node Block)++instance Semigroup Blocks where+ Many as <> Many bs = Many (as <> bs)++instance Monoid Blocks where+ mappend = (<>)+ mempty = Many mempty++data Doc =+ Doc{ docBlocks :: Blocks+ , docFootnotes :: NoteMap+ , docReferences :: ReferenceMap+ , docAutoReferences :: ReferenceMap+ , docAutoIdentifiers :: Set ByteString+ } deriving (Show, Ord, Eq, Typeable, Generic)++instance Semigroup Doc where+ Doc bs ns rs ar ai <> Doc bs' ns' rs' ar' ai' =+ Doc (bs <> bs') (ns <> ns') (rs <> rs') (ar <> ar') (ai <> ai')++instance Monoid Doc where+ mappend = (<>)+ mempty = Doc mempty mempty mempty mempty mempty++-- | A map from labels to contents.+newtype NoteMap = NoteMap { unNoteMap :: M.Map ByteString Blocks }+ deriving (Show, Ord, Eq, Semigroup, Monoid, Typeable, Generic)++insertNote :: ByteString -> Blocks -> NoteMap -> NoteMap+insertNote label ref (NoteMap m) =+ NoteMap (M.insert (normalizeLabel label) ref m)++lookupNote :: ByteString -> NoteMap -> Maybe Blocks+lookupNote label (NoteMap m) =+ M.lookup (normalizeLabel label) m++newtype ReferenceMap =+ ReferenceMap { unReferenceMap :: M.Map ByteString (ByteString, Attr) }+ deriving (Show, Ord, Eq, Semigroup, Monoid, Typeable, Generic)++normalizeLabel :: ByteString -> ByteString+normalizeLabel = B8.unwords . B8.words++insertReference :: ByteString -> (ByteString, Attr) -> ReferenceMap+ -> ReferenceMap+insertReference label ref (ReferenceMap rm) =+ ReferenceMap (M.insert (normalizeLabel label) ref rm)++lookupReference :: ByteString -> ReferenceMap -> Maybe (ByteString, Attr)+lookupReference label (ReferenceMap rm) =+ M.lookup (normalizeLabel label) rm++{-# INLINE inline #-}+inline :: Inline -> Inlines+inline = Many . Seq.singleton . Node NoPos mempty++str, verbatim, symbol :: ByteString -> Inlines+str = inline . Str+verbatim = inline . Verbatim+symbol = inline . Symbol++emph, strong, superscript, subscript :: Inlines -> Inlines+emph = inline . Emph+strong = inline . Strong+superscript = inline . Superscript+subscript = inline . Subscript++highlight, insert, delete :: Inlines -> Inlines+highlight = inline . Highlight+insert = inline . Insert+delete = inline . Delete++link, image :: Inlines -> Target -> Inlines+link ils url = inline $ Link ils url+image ils url = inline $ Image ils url++span_ :: Inlines -> Inlines+span_ = inline . Span++softBreak, hardBreak, nonBreakingSpace :: Inlines+softBreak = inline SoftBreak+hardBreak = inline HardBreak+nonBreakingSpace = inline NonBreakingSpace++inlineMath, displayMath :: ByteString -> Inlines+inlineMath = inline . Math InlineMath+displayMath = inline . Math DisplayMath++singleQuoted, doubleQuoted :: Inlines -> Inlines+singleQuoted = inline . Quoted SingleQuotes+doubleQuoted = inline . Quoted DoubleQuotes++footnoteReference :: ByteString -> Inlines+footnoteReference = inline . FootnoteReference++urlLink, emailLink :: ByteString -> Inlines+urlLink = inline . UrlLink+emailLink = inline . EmailLink++rawInline :: Format -> ByteString -> Inlines+rawInline f = inline . RawInline f+++--++block :: Block -> Blocks+block = Many . Seq.singleton . Node NoPos mempty++para :: Inlines -> Blocks+para = block . Para++section :: Blocks -> Blocks+section = block . Section++heading :: Int -> Inlines -> Blocks+heading lev = block . Heading lev++blockQuote :: Blocks -> Blocks+blockQuote = block . BlockQuote++codeBlock :: ByteString -> ByteString -> Blocks+codeBlock lang bs = block $ CodeBlock lang bs++bulletList :: ListSpacing -> [Blocks] -> Blocks+bulletList tightness = block . BulletList tightness++orderedList :: OrderedListAttributes -> ListSpacing -> [Blocks] -> Blocks+orderedList attr tightness = block . OrderedList attr tightness++definitionList :: ListSpacing -> [(Inlines, Blocks)] -> Blocks+definitionList tightness = block . DefinitionList tightness++taskList :: ListSpacing -> [(TaskStatus, Blocks)] -> Blocks+taskList tightness = block . TaskList tightness++div :: Blocks -> Blocks+div = block . Div++thematicBreak :: Blocks+thematicBreak = block ThematicBreak++table :: Maybe Caption -> [[Cell]] -> Blocks+table mbCaption = block . Table mbCaption++rawBlock :: Format -> ByteString -> Blocks+rawBlock f = block . RawBlock f++inlinesToByteString :: Inlines -> ByteString+inlinesToByteString = foldMap go . unMany+ where+ go (Node _pos _attr x) =+ case x of+ Str bs -> bs+ Emph ils -> inlinesToByteString ils+ Strong ils -> inlinesToByteString ils+ Highlight ils -> inlinesToByteString ils+ Insert ils -> inlinesToByteString ils+ Delete ils -> inlinesToByteString ils+ Superscript ils -> inlinesToByteString ils+ Subscript ils -> inlinesToByteString ils+ Quoted SingleQuotes ils ->+ "\x2018" <> inlinesToByteString ils <> "\x2019"+ Quoted DoubleQuotes ils ->+ "\x201C" <> inlinesToByteString ils <> "\x201D"+ Verbatim bs -> bs+ Math DisplayMath bs -> "$$" <> bs <> "$$"+ Math InlineMath bs -> "$" <> bs <> "$"+ Symbol bs -> ":" <> bs <> ":"+ Link ils _url -> inlinesToByteString ils+ Image ils _url -> inlinesToByteString ils+ Span ils -> inlinesToByteString ils+ UrlLink url -> url+ EmailLink email -> email+ RawInline _ _ -> mempty+ FootnoteReference bs -> "[" <> bs <> "]"+ SoftBreak -> "\n"+ HardBreak -> "\n"+ NonBreakingSpace -> "\160"
+ src/Djot/Attributes.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Strict #-}+{-# LANGUAGE DeriveDataTypeable #-}+module Djot.Attributes+ ( pAttributes+ , parseAttributes+ , AttrParserState -- opaque+ , AttrParseResult(..)+ )+where+import Data.Char (isAlphaNum, isSpace, isPunctuation)+import Djot.AST (Attr(..))+import Djot.Parse+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as B8+import Data.ByteString.Char8 ( (!?) )+import Data.Typeable (Typeable)+import Data.Maybe (fromMaybe)+-- import Debug.Trace+++-- attributes { id = "foo", class = "bar baz",+-- key1 = "val1", key2 = "val2" }+-- syntax:+--+-- attributes <- '{' (ignorable attribute)* ignorable* '}'+-- attribute <- identifier | class | keyval+-- identifier <- '#' name+-- class <- '.' name+-- name <- (nonspace, nonpunctuation other than ':', '_', '-')++-- keyval <- key '=' val+-- key <- (ASCII_ALPHANUM | ':' | '_' | '-')++-- val <- bareval | quotedval+-- bareval <- (ASCII_ALPHANUM | ':' | '_' | '-')++-- quotedval <- '"' ([^"] | '\"') '"'+-- ignorable <- whitespace | comment+-- comment <- '%' [^%}]* '%'++pAttributes :: Parser s Attr+pAttributes = lookahead (asciiChar '{') >> getSlice >>= go Nothing+ where+ getSlice = byteStringOf $+ branch+ (skipSome (skipSatisfyByte (/= '}')))+ (optional_ (asciiChar '}'))+ (asciiChar '}')+ go mbst bs = do+ case parseAttributes mbst bs of+ Done (attr, _off) -> pure attr+ Partial st -> getSlice >>= go (Just st)+ Failed _off -> failed++data AttrParseResult =+ Done (Attr, Int) -- result and byte offset+ | Failed Int -- byte offset of failure+ | Partial AttrParserState -- entire bytestring consumed+ deriving (Show, Typeable)++data AttrParserState =+ AttrParserState+ { aState :: AState+ , subject :: ByteString+ , offset :: Int+ , parts :: [AttrPart] }+ deriving (Show, Typeable)++data AState =+ SCANNING+ | AFTER_KEY+ | SCANNING_VALUE+ | SCANNING_QUOTED_VALUE+ | SCANNING_ESCAPE+ | SCANNING_COMMENT+ | FAIL+ | DONE+ | START+ deriving (Eq, Ord, Show, Typeable)++data AttrPart =+ AttrId ByteString+ | AttrClass ByteString+ | AttrKey ByteString+ | AttrValue ByteString+ deriving (Eq, Ord, Show, Typeable)++-- | Resumable parser, returning parts in reverse order.+parseAttributes :: Maybe AttrParserState -> ByteString -> AttrParseResult+parseAttributes mbState bs =+ case go (fromMaybe AttrParserState{ aState = START+ , subject = bs+ , offset = 0+ , parts = [] } mbState) of+ AttrParserState{ aState = DONE, parts = attparts, offset = off } ->+ Done (attrPartsToAttr attparts, off)+ AttrParserState{ aState = FAIL, offset = off } -> Failed off+ st -> Partial st+ where+ go :: AttrParserState -> AttrParserState+ go st@(AttrParserState _ subj off _) = -- trace (show st) $+ case subj !? off of+ Nothing -> st+ Just nextc ->+ case aState st of+ SCANNING ->+ case nextc of+ '}' -> go st{ aState = DONE, offset = off + 1 }+ '%' -> go st{ aState = SCANNING_COMMENT, offset = off + 1 }+ '#' -> go $ takePart isNameChar AttrId SCANNING st{ offset = off + 1 }+ '.' -> go $ takePart isNameChar AttrClass SCANNING st{ offset = off + 1 }+ c | isKeyChar c -> go $ takePart isKeyChar AttrKey AFTER_KEY st+ c | isWs c -> go $ skipWhile isWs st+ _ -> st{ aState = FAIL }+ AFTER_KEY ->+ case nextc of+ '=' -> go st{ aState = SCANNING_VALUE, offset = off + 1 }+ _ -> st{ aState = FAIL }+ SCANNING_VALUE ->+ case nextc of+ '"' -> go st{ aState = SCANNING_QUOTED_VALUE, offset = off + 1 }+ c | isBareValChar c -> go $ takePart isBareValChar AttrValue SCANNING st+ _ -> st{ aState = FAIL }+ SCANNING_QUOTED_VALUE ->+ case nextc of+ '"' -> go st{ aState = SCANNING, offset = off + 1 }+ '\\' -> go st{ aState = SCANNING_ESCAPE, offset = off + 1 }+ c | isWs c ->+ let st' = skipWhile isWs st+ in go st'{ parts = AttrValue " " : parts st' }+ _ -> go $ takePart (\c -> not (isWs c || c == '"' || c == '\\'))+ AttrValue SCANNING_QUOTED_VALUE st+ SCANNING_ESCAPE ->+ go st{ aState = SCANNING_QUOTED_VALUE, offset = off + 1,+ parts = AttrValue (B8.singleton nextc) : parts st }+ SCANNING_COMMENT ->+ case nextc of+ '%' -> go st{ aState = SCANNING, offset = off + 1 }+ '}' -> st{ aState = DONE, offset = off + 1 }+ _ -> go $ skipWhile (\c -> not (c == '%' || c == '}')) st+ FAIL -> st+ DONE -> st+ START ->+ case nextc of+ '{' -> go st{ aState = SCANNING, offset = off + 1 }+ _ -> st{ aState = FAIL }++takePart :: (Char -> Bool) -> (ByteString -> AttrPart) -> AState ->+ AttrParserState -> AttrParserState+takePart charP partConstructor nextstate st =+ case subject st !? offset st of+ Just c | charP c ->+ let val = B8.takeWhile charP (B8.drop (offset st) (subject st))+ in st{ aState = nextstate,+ offset = offset st + B8.length val,+ parts = partConstructor val : parts st }+ _ -> st{ aState = FAIL }++skipWhile :: (Char -> Bool) -> AttrParserState -> AttrParserState+skipWhile charP st =+ case B8.findIndex (not . charP) (B8.drop (offset st) (subject st)) of+ Nothing -> st{ offset = B8.length (subject st) }+ Just i -> st{ offset = offset st + i }++attrPartsToAttr :: [AttrPart] -> Attr+attrPartsToAttr = go+ where+ go [] = Attr []+ go (AttrId bs : xs) = (<> Attr [("id",bs)]) $ go xs+ go (AttrClass bs : xs) = (<> Attr [("class",bs)]) $ go xs+ go zs =+ case break isAttrKey zs of+ (vs, AttrKey bs : xs) ->+ (<> Attr [(bs, mconcat (reverse $ map getAttrVal vs))]) $ go xs+ _ -> Attr [] -- should not happen+ isAttrKey (AttrKey _) = True+ isAttrKey _ = False+ getAttrVal (AttrValue bs) = bs+ getAttrVal _ = mempty++isNameChar :: Char -> Bool+isNameChar c = not (isSpace c)+ && (not (isPunctuation c) || c == ':' || c == '_' || c == '-')++isKeyChar :: Char -> Bool+isKeyChar c = isAlphaNum c || c == ':' || c == '_' || c == '-'++isBareValChar :: Char -> Bool+isBareValChar c = isAlphaNum c || c == ':' || c == '_' || c == '-'
+ src/Djot/Blocks.hs view
@@ -0,0 +1,1138 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE Strict #-}+{-# LANGUAGE DeriveDataTypeable #-}+module Djot.Blocks+( parseDoc+, toIdentifier+)+where++import Prelude hiding (div)+import Text.Read (readMaybe)+import Data.Maybe (fromMaybe)+import Data.Char (ord, isAsciiLower, isAsciiUpper, isAscii, isAlphaNum, isDigit)+import Data.Foldable as F+import Djot.Parse+import Djot.AST+import Djot.Inlines (parseInlines, parseTableCells)+import Djot.Options (ParseOptions(..), SourcePosOption(..))+import Djot.Attributes (parseAttributes, AttrParserState, AttrParseResult(..))+import Data.Sequence (Seq)+import qualified Data.Sequence as Seq+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import Data.ByteString (ByteString)+import Control.Monad (replicateM_, void, mzero, unless, when, guard, foldM)+import Data.List.NonEmpty (NonEmpty(..))+import Data.List (intercalate)+import qualified Data.List.NonEmpty as NonEmpty+import Data.Set (Set)+import qualified Data.Set as Set+import Control.Applicative+import Data.Typeable (Typeable)+-- import Debug.Trace++parseDoc :: ParseOptions -> ByteString -> Either String Doc+parseDoc opts bs = do+ case parse pDoc PState{ psParseOptions = opts+ , psContainerStack =+ NonEmpty.fromList+ [emptyContainer{ containerSpec = docSpec }]+ , psReferenceMap = mempty+ , psAutoReferenceMap = mempty+ , psNoteMap = mempty+ , psAttributes = mempty+ , psAttrParserState = Nothing+ , psIds = mempty+ , psAutoIds = mempty+ , psLastColumnPrevLine = 0+ , psLastLine = 1+ } [Chunk{ chunkLine = 1, chunkColumn = 1, chunkBytes = bs }] of+ Just doc -> Right doc+ Nothing -> Left "Parse failure."++data BlockType =+ Normal | ListItem | CaptionBlock | Document+ deriving (Show, Eq)++data BlockSpec =+ BlockSpec+ { -- | Descriptive name+ blockName :: String+ , -- | Type of block+ blockType :: BlockType+ -- | Parser for start of this block type+ , blockStart :: P ()+ -- | Parser that must return True if this block is to continue+ , blockContinue :: Container -> P Bool+ -- | Just blockType if it can contain that type of block+ , blockContainsBlock :: Maybe BlockType+ -- | True if it can accept text lines+ , blockContainsLines :: Bool+ -- | Parser that runs when block is closed, possibly+ -- updating the container.+ , blockClose :: Container -> P Container+ -- | Parser that runs when the document is closed, creating the+ -- block AST element.+ , blockFinalize :: Container -> Blocks+ }++docSpec :: BlockSpec+docSpec =+ BlockSpec+ { blockName = "Doc"+ , blockType = Document+ , blockStart = mzero+ , blockContinue = \_ -> pure True+ , blockContainsBlock = Just Normal+ , blockContainsLines = False+ , blockClose = pure+ , blockFinalize = finalizeChildren+ }++listItemSpec :: BlockSpec+listItemSpec =+ BlockSpec+ { blockName = "ListItem"+ , blockType = ListItem+ , blockStart = do+ ind <- sourceColumn+ ltypes <- pListStart+ skipMany spaceOrTab+ tip :| _ <- psContainerStack <$> getState+ case blockContainsBlock (containerSpec tip) of+ Just ListItem -> pure ()+ _ -> addContainer listSpec ind NoData+ addContainer listItemSpec ind (ListItemData ind ltypes False)+ , blockContinue = \container -> do+ True <$ fails+ (do skipMany spaceOrTab+ curind <- sourceColumn+ let liIndent = case containerData container of+ ListItemData i _ _ -> i+ _ -> error "Missing ListItemData"+ tip :| _ <- psContainerStack <$> getState+ guard (curind <= liIndent)+ case blockName (containerSpec tip) of+ "Para" -> void pListStart+ _ -> pure ())+ <|> pure False+ , blockContainsBlock = Just Normal+ , blockContainsLines = False+ , blockClose = pure+ , blockFinalize = finalizeChildren+ }++pListStart :: P [ListType]+pListStart = pBulletListStart <|> pDefinitionListStart <|> pOrderedListStart++pBulletListStart :: P [ListType]+pBulletListStart = do+ bulletchar <- satisfyByte (\c -> c == '-' || c == '+' || c == '*')+ followedByWhitespace+ (do skipMany spaceOrTab+ asciiChar '['+ status <- (Complete <$ byteString "x]")+ <|> (Complete <$ byteString "X]")+ <|> (Incomplete <$ byteString " ]")+ followedByWhitespace+ pure [Task status])+ <|> pure [Bullet bulletchar]++pDefinitionListStart :: P [ListType]+pDefinitionListStart = do+ asciiChar ':'+ followedByWhitespace+ pure [Definition]++groupLists :: Seq Container -> Seq ([ListType], Seq Container)+groupLists = snd . foldl' go ([], mempty)+ where+ go :: ([ListType], Seq ([ListType], Seq Container))+ -> Container+ -> ([ListType], Seq ([ListType], Seq Container))+ go (curtypes, lists) cont =+ case Seq.viewr lists of+ Seq.EmptyR -> (getListTypes cont,+ Seq.singleton (getListTypes cont, Seq.singleton cont))+ rest Seq.:> (_, cur) ->+ let lt = getListTypes cont+ matchedTypes = [ty | ty <- curtypes, any (ty `matches`) lt]+ in if null matchedTypes+ then (getListTypes cont, lists Seq.|> (getListTypes cont, Seq.singleton cont)) -- new list+ else (matchedTypes, rest Seq.|> (matchedTypes, cur Seq.|> cont))++ matches :: ListType -> ListType -> Bool+ matches (Bullet b1) (Bullet b2) = b1 == b2+ matches (Ordered o1) (Ordered o2) =+ orderedListStyle o1 == orderedListStyle o2 &&+ orderedListDelim o1 == orderedListDelim o2+ matches Definition Definition = True+ matches Task{} Task{} = True+ matches _ _ = False+++getListTypes :: Container -> [ListType]+getListTypes cont = case containerData cont of+ ListItemData _ tys _ -> tys+ _ -> error "Missing ListItemData"++pOrderedListStart :: P [ListType]+pOrderedListStart = do+ openParen <- (True <$ asciiChar '(') <|> pure False+ lookahead $ do+ skipSome $ skipSatisfyByte (\c -> isAscii c && isAlphaNum c)+ skipSatisfyByte (\c -> c == '.' || c == ')')+ stylesAndStarts <- decimalStart <|> romanStart <|> letterStart+ delimType <-+ if openParen+ then LeftRightParen <$ asciiChar ')'+ else (RightParen <$ asciiChar ')') <|> (RightPeriod <$ asciiChar '.')+ followedByWhitespace+ pure $ map+ (\(style, start) -> Ordered+ OrderedListAttributes+ { orderedListStyle = style+ , orderedListDelim = delimType+ , orderedListStart = start }) stylesAndStarts+ where+ decimalStart = do+ digits <- some (satisfyByte isDigit)+ case readMaybe digits of+ Just n -> pure [(Decimal, n)]+ Nothing -> mzero+ letterStart = do+ c <- satisfyByte (\c -> isAsciiLower c || isAsciiUpper c)+ if isAsciiLower c+ then pure [(LetterLower, 1 + (ord c - ord 'a'))]+ else pure [(LetterUpper, 1 + (ord c - ord 'A'))]+ romanStart = do+ (n, lettercase) <- pRomanNumeral+ let sty = if lettercase == Uppercase then RomanUpper else RomanLower+ let altsty = if lettercase == Uppercase then LetterUpper else LetterLower+ pure $ (sty, n) :+ case n of+ 1 -> [(altsty, 9)]+ 5 -> [(altsty, 22)]+ 10 -> [(altsty, 24)]+ 50 -> [(altsty, 12)]+ 100 -> [(altsty, 3)]+ 500 -> [(altsty, 4)]+ 1000 -> [(altsty, 13)]+ _ -> []++data Case = Uppercase | Lowercase+ deriving (Eq)++pRomanNumeral :: P (Int, Case)+pRomanNumeral = do+ let isUpperRomanChar c = c == 'I' || c == 'V' || c == 'X' ||+ c == 'L' || c == 'C' || c == 'D' || c == 'M'+ let isLowerRomanChar c = c == 'i' || c == 'v' || c == 'x' ||+ c == 'l' || c == 'c' || c == 'd' || c == 'm'+ let isRomanChar c = isUpperRomanChar c || isLowerRomanChar c+ lettercase <- lookahead $ do+ c <- satisfyByte isRomanChar+ let lettercase = if isUpperRomanChar c then Uppercase else Lowercase+ skipMany $ skipSatisfyByte $+ case lettercase of+ Uppercase -> isUpperRomanChar+ Lowercase -> isLowerRomanChar+ skipSatisfyByte (\d -> d == ')' || d == '.')+ pure lettercase+ let rchar uc lc = satisfyByte $ if lettercase == Uppercase+ then (== uc)+ else (== lc)+ let one = rchar 'I' 'i'+ let five = rchar 'V' 'v'+ let ten = rchar 'X' 'x'+ let fifty = rchar 'L' 'l'+ let hundred = rchar 'C' 'c'+ let fivehundred = rchar 'D' 'd'+ let thousand = rchar 'M' 'm'+ thousands <- (1000 *) . length <$> many thousand+ ninehundreds <- option 0 $ hundred >> thousand >> return 900+ fivehundreds <- option 0 $ 500 <$ fivehundred+ fourhundreds <- option 0 $ hundred >> fivehundred >> return 400+ hundreds <- (100 *) . length <$> many hundred+ nineties <- option 0 $ ten >> hundred >> return 90+ fifties <- option 0 (50 <$ fifty)+ forties <- option 0 $ ten >> fifty >> return 40+ tens <- (10 *) . length <$> many ten+ nines <- option 0 $ one >> ten >> return 9+ fives <- option 0 (5 <$ five)+ fours <- option 0 $ one >> five >> return 4+ ones <- length <$> many one+ let total = thousands + ninehundreds + fivehundreds + fourhundreds ++ hundreds + nineties + fifties + forties + tens + nines ++ fives + fours + ones+ if total == 0+ then mzero+ else return (total, lettercase)+ where+ option defval p = p <|> pure defval++listSpec :: BlockSpec+listSpec =+ BlockSpec+ { blockName = "List"+ , blockType = Normal+ , blockStart = mzero -- added in listItemSpec+ , blockContinue = \_ -> pure True+ , blockContainsBlock = Just ListItem+ , blockContainsLines = False+ , blockClose = pure+ , blockFinalize = foldMap itemsToList . groupLists . containerChildren+ }++itemsToList :: ([ListType], Seq Container) -> Blocks+itemsToList (ltypes, containers) =+ case containers of+ Seq.Empty -> mempty+ _ ->+ let spacing =+ case Seq.viewr containers of+ Seq.EmptyR -> Tight+ as Seq.:> _ | any itemEndsWithBlank as ||+ any hasChildrenSeparatedWithBlank containers+ -> Loose+ _ -> Tight+ items' = toList items+ taskListStatus = map getTaskStatus (toList containers)+ pos = case (Seq.viewl containers, Seq.viewr containers) of+ (s Seq.:< _, _ Seq.:> e) | containerSourcePos s ->+ Pos (containerStartLine s) (containerStartColumn s)+ (containerEndLine e) (containerEndColumn e)+ _ -> NoPos+ in addPos pos <$>+ case ltypes of+ Bullet{} : _-> bulletList spacing items'+ Ordered _ : _->+ orderedList (chooseOrderedAttr ltypes) spacing items'+ Definition : _ -> definitionList spacing $ map toDefinition items'+ Task _ : _ -> taskList spacing $ zip taskListStatus items'+ [] -> mempty+ where+ items = map finalize $ toList containers+ getTaskStatus cont = case getListTypes cont of+ ([Task stat] :: [ListType]) -> stat+ _ -> error "getTaskStatus: wrong shape"+ -- when ambiguous between roman and lettered list, choose roman if start number is 1,+ -- otherwise lettered+ chooseOrderedAttr os =+ case [at | Ordered at <- os, isRomanStartOne at] of+ (a:_) -> a+ _ -> case [at | Ordered at <- os, isLettered at] of+ (a:_) -> a+ _ -> case [at | Ordered at <- os] of+ (a:_) -> a+ [] -> error "chooseOrderedAttr on empty list"+ isRomanStartOne at = (orderedListStyle at == RomanUpper ||+ orderedListStyle at == RomanLower) &&+ orderedListStart at == 1+ isLettered at = orderedListStyle at == LetterUpper ||+ orderedListStyle at == LetterLower++-- | We determine whether a list item ends with a blank line by+-- comparing its end line with the end line of its last child.+itemEndsWithBlank :: Container -> Bool+itemEndsWithBlank li =+ case Seq.viewr (containerChildren li) of+ Seq.EmptyR -> False+ _ Seq.:> lastChild -> containerEndLine li > containerEndLine lastChild++-- | We don't count blanks before lists, because+-- otherwise it would be impossible to have nested tight lists.+hasChildrenSeparatedWithBlank :: Container -> Bool+hasChildrenSeparatedWithBlank cont =+ or $ Seq.zipWith check children (Seq.drop 1 children)+ where+ children = (if Definition `elem` liTypes then Seq.drop 1 else id) $+ containerChildren cont+ check x y = (blockName (containerSpec y) /= "List") &&+ (containerStartLine y > containerEndLine x)+ liTypes = getListTypes cont++toDefinition :: Blocks -> (Inlines, Blocks)+toDefinition bs =+ case Seq.viewl bs' of+ Node _ _ (Para ils) Seq.:< _ -> (ils, Many (Seq.drop 1 bs'))+ _ -> (mempty, bs)+ where+ bs' = unMany bs++sectionSpec :: BlockSpec+sectionSpec =+ BlockSpec+ { blockName = "Section"+ , blockType = Normal+ , blockStart = mzero -- these containers are added by headingSpec+ , blockContinue = \_ -> pure True -- these are closed by headingSpec+ , blockContainsBlock = Just Normal+ , blockContainsLines = False+ , blockClose = \container -> do+ case containerChildren container of+ h Seq.:<| _+ | blockName (containerSpec h) == "Heading" -> do+ let lev = case containerData container of+ SectionData n _ -> n+ _ -> error "Missing SectionData"+ let ils = case containerData h of+ HeadingData _ xs -> xs+ _ -> error "Missing HeadingData"+ (secid, attr, label) <- do+ let bs = inlinesToByteString ils+ let Attr ats = containerAttr container+ case lookup "id" ats of+ Just id' -> pure (id', mempty, normalizeLabel bs)+ Nothing -> do -- generate id from title+ let generateId (n :: Int) base = do+ let candidate+ | n == 0 = base+ | otherwise = base <> "-" <> B8.pack (show n)+ ids <- psIds <$> getState+ if candidate `Set.member` ids+ then generateId (n+1) base+ else do+ updateState $ \st ->+ st{ psIds = Set.insert candidate (psIds st)+ , psAutoIds = Set.insert candidate+ (psAutoIds st) }+ pure candidate+ ident <- generateId 0 (toIdentifier bs)+ pure (ident, mempty, normalizeLabel bs)+ -- add implicit reference+ let dest = "#" <> secid+ updateState $ \st -> st{ psAutoReferenceMap = insertReference label+ (dest, Attr []) (psAutoReferenceMap st) }++ pure container{ containerData =+ SectionData lev (Just secid)+ , containerAttr = containerAttr container <> attr }+ _ -> pure container+ , blockFinalize = \container ->+ let blocks = finalizeChildren container+ secid = case containerData container of+ SectionData _ ident -> ident+ _ -> error "Missing SectionData"+ in addSourcePos container $+ maybe id (\ident -> addAttr (Attr [("id", ident)])) secid+ <$> section blocks+ }++blockQuoteSpec :: BlockSpec+blockQuoteSpec =+ BlockSpec+ { blockName = "BlockQuote"+ , blockType = Normal+ , blockStart = do+ ind <- sourceColumn+ asciiChar '>'+ followedByWhitespace+ skipMany spaceOrTab+ addContainer blockQuoteSpec ind NoData+ , blockContinue = \_ -> do+ skipMany spaceOrTab+ asciiChar '>'+ followedByWhitespace+ skipMany spaceOrTab+ pure True+ , blockContainsBlock = Just Normal+ , blockContainsLines = False+ , blockClose = pure+ , blockFinalize = \container ->+ addSourcePos container $ blockQuote $ finalizeChildren container+ }++tableSpec :: BlockSpec+tableSpec =+ BlockSpec+ { blockName = "Table"+ , blockType = Normal+ , blockStart = do+ lookahead pRawTableRow+ ind <- sourceColumn+ addContainer tableSpec ind (TableData mempty)+ , blockContinue = \container ->+ -- TODO: this is inefficient; we parse the inline contents+ -- twice. Find a better way.+ (True <$ lookahead pRawTableRow)+ <|> (True <$ followedByBlankLine)+ <|> (True <$ lookahead+ (skipMany spaceOrTab *> asciiChar '^' *> spaceOrTab))+ <|> (True <$ guard (not (null (containerChildren container))))+ , blockContainsBlock = Just CaptionBlock+ , blockContainsLines = True+ , blockClose = \container -> do+ let lns = containerText container+ rows <- reverse . snd <$> foldM parseTableRow ([], []) lns+ pure $ container{ containerData = TableData rows }+ , blockFinalize = \container ->+ let rows = case containerData container of+ TableData rs -> rs+ _ -> error "Missing TableData"+ mbCaption =+ case Seq.viewr (containerChildren container) of+ Seq.EmptyR -> Nothing+ _ Seq.:> x -> Just . Caption $ blockFinalize (containerSpec x) x+ in addSourcePos container $ table mbCaption rows+ }++parseTableRow :: ([Align], [[Cell]])+ -> Chunk+ -> P ([Align], [[Cell]])+parseTableRow (aligns, rows) chunk =+ case B8.uncons (B8.strip $ chunkBytes chunk) of+ Just ('|',_) -> do+ res <- pTableCells aligns chunk+ case res of+ Left aligns' -> pure (aligns',+ case rows of+ r:rs -> zipWith toHeadCell aligns' r : rs+ [] -> [] )+ Right cells -> pure (aligns, cells : rows)+ Nothing -> pure (aligns, rows)+ Just (_,_) -> mzero+ where+ toHeadCell align' (Cell _ _ ils) = Cell HeadCell align' ils++pTableCells :: [Align] -> Chunk -> P (Either [Align] [Cell])+pTableCells aligns chunk =+ case parse pTableSeps () [chunk] of+ Just aligns' -> pure $ Left aligns'+ Nothing -> do+ opts <- psParseOptions <$> getState+ case parseTableCells opts chunk of+ Right cs ->+ pure $ Right $+ zipWith (Cell BodyCell) (aligns ++ repeat AlignDefault) cs+ Left _ -> mzero++pTableSeps :: Parser () [Align]+pTableSeps = do+ skipMany spaceOrTab+ asciiChar '|'+ many pTableSep <* skipMany ws <* eof+ where+ pTableSep = do+ skipMany spaceOrTab+ start <- (True <$ asciiChar ':') <|> pure False+ skipSome (asciiChar '-')+ end <- (True <$ asciiChar ':') <|> pure False+ skipMany spaceOrTab+ asciiChar '|'+ pure $ case (start, end) of+ (True, True) -> AlignCenter+ (True, False) -> AlignLeft+ (False, True) -> AlignRight+ (False, False) -> AlignDefault++pRawTableRow :: P ()+pRawTableRow = do+ lookahead $ asciiChar '|'+ curline <- sourceLine+ curcolumn <- sourceColumn+ bs <- restOfLine+ void $ parseTableRow ([],[]) Chunk{ chunkLine = curline+ , chunkColumn = curcolumn+ , chunkBytes = bs }++captionSpec :: BlockSpec+captionSpec =+ BlockSpec+ { blockName = "Caption"+ , blockType = CaptionBlock+ , blockStart = do+ ind <- sourceColumn+ asciiChar '^'+ void spaceOrTab+ addContainer captionSpec ind $ CaptionData ind+ , blockContinue = \container -> (do+ skipMany spaceOrTab+ curind <- sourceColumn+ let ind = case containerData container of+ CaptionData i -> i+ _ -> error "Missing CaptionData"+ guard (curind > ind) <|> followedByBlankLine+ pure True) <|> pure False+ , blockContainsBlock = Just Normal+ , blockContainsLines = False+ , blockClose = pure+ , blockFinalize = finalizeChildren+ }+++thematicBreakSpec :: BlockSpec+thematicBreakSpec =+ BlockSpec+ { blockName = "ThematicBreak"+ , blockType = Normal+ , blockStart = do+ let breakChar = skipSatisfyByte (\c -> c == '-' || c == '*')+ *> skipMany spaceOrTab+ ind <- sourceColumn+ breakChar *> breakChar *> breakChar *> skipMany breakChar+ lookahead endline+ addContainer thematicBreakSpec ind NoData+ , blockContinue = \_ -> pure False+ , blockContainsBlock = Nothing+ , blockContainsLines = True+ , blockClose = pure+ , blockFinalize = \container -> addSourcePos container thematicBreak+ }++headingSpec :: BlockSpec+headingSpec =+ BlockSpec+ { blockName = "Heading"+ , blockType = Normal+ , blockStart = do+ ind <- sourceColumn+ lev <- length <$> some (asciiChar '#')+ followedByWhitespace+ skipMany spaceOrTab+ closeContainingSections lev+ addContainer sectionSpec ind $ SectionData lev Nothing+ addContainer headingSpec ind $ HeadingData lev mempty+ , blockContinue = \container -> do+ do skipMany spaceOrTab+ let lev = case containerData container of+ HeadingData n _ -> n+ _ -> error "Missing HeadingData"+ (True <$ (do lev' <- length <$> some (asciiChar '#')+ guard (lev' == lev)+ skipMany spaceOrTab))+ <|> (False <$ do+ lookahead (asciiChar '#' <|> endline <|> eof))+ <|> pure True+ , blockContainsBlock = Nothing+ , blockContainsLines = True+ , blockClose = \container -> do+ ils <- parseTextLines container+ let lev = case containerData container of+ HeadingData n _ -> n+ _ -> error "Missing HeadingData"+ pure $ container{ containerData = HeadingData lev ils }+ , blockFinalize = \container ->+ let (lev, title) =+ case containerData container of+ HeadingData l t -> (l, t)+ _ -> error "Missing HeadingData"+ in addSourcePos container $ heading lev title+ }++codeBlockSpec :: BlockSpec+codeBlockSpec =+ BlockSpec+ { blockName = "CodeBlock"+ , blockType = Normal+ , blockStart = do+ indent <- sourceColumn+ ticks <- byteStringOf $ asciiChar '`' *> asciiChar '`' *> skipSome (asciiChar '`')+ skipMany spaceOrTab+ lang <- (byteStringOf+ (skipSome $ skipSatisfyByte (\c -> c /= '`' && not (isWs c)))+ <* skipMany spaceOrTab)+ <|> pure ""+ lookahead endline+ addContainer codeBlockSpec indent (CodeBlockData ticks lang indent)+ , blockContinue = \container -> do+ let (ticks, indent) = case containerData container of+ CodeBlockData t _ i -> (t, i)+ _ -> error "Missing CodeBlockData"+ gobbleSpaceToIndent indent+ (do skipMany spaceOrTab+ byteString ticks+ skipMany (asciiChar '`')+ skipMany spaceOrTab+ lookahead endline+ pure False)+ <|> pure True+ , blockContainsBlock = Nothing+ , blockContainsLines = True+ , blockClose = pure+ , blockFinalize = \container ->+ let lang = case containerData container of+ CodeBlockData _ l _ -> l+ _ -> error "Missing CodeBlockData"+ -- drop first line which should be empty+ bs = foldMap chunkBytes (Seq.drop 1 $ containerText container)+ in addSourcePos container $+ case B8.uncons lang of+ Just ('=', fmt) -> rawBlock (Format fmt) bs+ _ -> codeBlock lang bs+ }++divSpec :: BlockSpec+divSpec =+ BlockSpec+ { blockName = "Div"+ , blockType = Normal+ , blockStart = do+ ind <- sourceColumn+ colons <- byteStringOf $+ asciiChar ':' *> asciiChar ':' *> skipSome (asciiChar ':')+ skipMany spaceOrTab+ label <- byteStringOf $ skipMany $ skipSatisfyByte (not . isWs)+ skipMany spaceOrTab+ lookahead endline+ addContainer divSpec ind (DivData colons label)+ , blockContinue = \container -> (do+ tip <- getTip+ -- see jgm/djot.js#109+ guard $ blockName (containerSpec tip) /= "CodeBlock"+ skipMany spaceOrTab+ let colons = case containerData container of+ DivData c _ -> c+ _ -> error "Missing DivData"+ byteString colons+ skipMany (asciiChar ':')+ skipMany spaceOrTab+ lookahead endline+ pure False) <|> pure True+ , blockContainsBlock = Just Normal+ , blockContainsLines = False+ , blockClose = pure+ , blockFinalize = \container ->+ let label = case containerData container of+ DivData _ l -> l+ _ -> error "Missing DivData"+ -- drop first line which should be empty+ bls = finalizeChildren container+ in (if B.null label+ then id+ else addAttr (Attr [("class", label)])) <$>+ addSourcePos container (div bls)+ }++attrSpec :: BlockSpec+attrSpec =+ BlockSpec+ { blockName = "Attributes"+ , blockType = Normal+ , blockStart = do+ ind <- sourceColumn+ lookahead $ asciiChar '{'+ addContainer attrSpec ind $ AttributeData ind+ , blockContinue = \container -> do+ let ind = case containerData container of+ AttributeData i -> i+ _ -> error "Missing AttributeData"+ skipMany spaceOrTab+ curind <- sourceColumn+ mbapstate <- psAttrParserState <$> getState+ if curind <= ind+ then pure False+ else do+ let lastLine = case Seq.viewr (containerText container) of+ _ Seq.:> ll -> chunkBytes ll+ _ -> mempty+ case parseAttributes mbapstate lastLine of+ Done _ -> pure False+ Partial apstate' -> do+ updateState $ \st -> st{ psAttrParserState = Just apstate' }+ pure True+ Failed _ -> pure True -- not yet: keep going!+ , blockContainsBlock = Nothing+ , blockContainsLines = True+ , blockClose = \container -> do+ let bs = foldMap chunkBytes $ containerText container+ case parseAttributes Nothing bs of+ Done (attr, off)+ | B8.all isWs (B8.drop off bs) -> do+ updateState $ \st -> st{ psAttributes = psAttributes st <> attr }+ pure container+ | otherwise -> do+ ils <- parseTextLines container+ pure $ container{ containerSpec = paraSpec+ , containerInlines = ils }+ _ -> do -- could not parse lines as attribute, treat as Para+ ils <- parseTextLines container+ pure $ container{ containerSpec = paraSpec+ , containerInlines = ils }+ , blockFinalize = const mempty+ }++referenceDefinitionSpec :: BlockSpec+referenceDefinitionSpec =+ BlockSpec+ { blockName = "ReferenceDefinition"+ , blockType = Normal+ , blockStart = do+ ind <- sourceColumn+ asciiChar '['+ fails (asciiChar '^') -- footnote+ label <- byteStringOf+ (some (skipSatisfyByte (\c -> c /= ']' && c /= '\n')))+ asciiChar ']'+ asciiChar ':'+ skipMany spaceOrTab+ addContainer referenceDefinitionSpec ind+ (ReferenceData (normalizeLabel label))+ , blockContinue = \_ ->+ True <$ skipSome spaceOrTab `notFollowedBy` endline+ , blockContainsBlock = Nothing+ , blockContainsLines = True+ , blockClose = \container -> do+ let label = case containerData container of+ ReferenceData l -> l+ _ -> error "Missing ReferenceData"+ let attr = containerAttr container+ let dest = B.filter (> 32) . foldMap chunkBytes $ containerText container+ updateState $ \st ->+ st{ psReferenceMap = insertReference label (dest, attr)+ (psReferenceMap st) }+ pure container+ , blockFinalize = const mempty+ }++footnoteSpec :: BlockSpec+footnoteSpec =+ BlockSpec+ { blockName = "Footnote"+ , blockType = Normal+ , blockStart = do+ ind <- sourceColumn+ asciiChar '['+ asciiChar '^'+ label <- byteStringOf+ (some (skipSatisfyByte (\c -> c /= ']' && c /= '\n')))+ asciiChar ']'+ asciiChar ':'+ skipMany spaceOrTab+ addContainer footnoteSpec ind $ FootnoteData ind (normalizeLabel label)+ , blockContinue = \container -> (do+ skipMany spaceOrTab+ curind <- sourceColumn+ let ind = case containerData container of+ FootnoteData i _ -> i+ _ -> error "Missing FootnoteData"+ guard (curind > ind) <|> followedByBlankLine+ pure True) <|> pure False+ , blockContainsBlock = Just Normal+ , blockContainsLines = True+ , blockClose = \container -> do+ let label = case containerData container of+ FootnoteData _ l -> l+ _ -> error "Missing FootnoteData"+ let bls = finalizeChildren container+ updateState $ \st -> st{ psNoteMap = insertNote label bls (psNoteMap st) }+ pure container+ , blockFinalize = const mempty+ }+++paraSpec :: BlockSpec+paraSpec =+ BlockSpec+ { blockName = "Para"+ , blockType = Normal+ , blockStart = do+ fails followedByBlankLine+ ind <- sourceColumn+ addContainer paraSpec ind NoData+ , blockContinue = \_ -> do+ skipMany spaceOrTab+ (False <$ lookahead (endline <|> eof)) <|> pure True+ , blockContainsBlock = Nothing+ , blockContainsLines = True+ , blockClose = \container -> do+ ils <- parseTextLines container+ pure $ container{ containerInlines = ils }+ , blockFinalize = \container ->+ addSourcePos container . para $ containerInlines container+ }++parseTextLines :: Container -> P Inlines+parseTextLines cont = do+ opts <- psParseOptions <$> getState+ either error pure . parseInlines opts $ containerText cont++emptyContainer :: Container+emptyContainer =+ Container { containerSpec = docSpec+ , containerChildren = mempty+ , containerText = mempty+ , containerInlines = mempty+ , containerStartLine = 1+ , containerStartColumn = 0+ , containerEndLine = 1+ , containerEndColumn = 0+ , containerData = NoData+ , containerAttr = mempty+ , containerSourcePos = False+ }++data Container =+ Container+ { containerSpec :: BlockSpec+ , containerChildren :: Seq Container+ , containerText :: Seq Chunk+ , containerInlines :: Inlines+ , containerStartLine :: Int+ , containerStartColumn :: Int+ , containerEndLine :: Int+ , containerEndColumn :: Int+ , containerData :: ContainerData+ , containerAttr :: Attr+ , containerSourcePos :: Bool+ }++data ContainerData =+ NoData+ | ListItemData Int [ListType] Bool+ | SectionData Int (Maybe ByteString)+ | HeadingData Int Inlines+ | CodeBlockData ByteString ByteString Int+ | DivData ByteString ByteString+ | FootnoteData Int ByteString+ | TableData [[Cell]]+ | CaptionData Int+ | AttributeData Int+ | ReferenceData ByteString+ deriving (Show, Eq, Ord, Typeable)++data ListType =+ Bullet Char+ | Ordered OrderedListAttributes+ | Definition+ | Task TaskStatus+ deriving (Show, Ord, Eq)++data PState =+ PState+ { psParseOptions :: ParseOptions+ , psContainerStack :: NonEmpty Container+ , psReferenceMap :: ReferenceMap+ , psAutoReferenceMap :: ReferenceMap+ , psNoteMap :: NoteMap+ , psAttributes :: Attr+ , psAttrParserState :: Maybe AttrParserState+ , psIds :: Set ByteString+ , psAutoIds :: Set ByteString+ , psLastColumnPrevLine :: Int+ , psLastLine :: Int+ }++type P = Parser PState++pDoc :: P Doc+pDoc = do+ bls <- pBlocks <* eof+ st <- getState+ pure $ Doc{ docBlocks = bls+ , docFootnotes = psNoteMap st+ , docReferences = psReferenceMap st+ , docAutoReferences = psAutoReferenceMap st+ , docAutoIdentifiers = psAutoIds st }++pBlocks :: P Blocks+pBlocks = processLines >> finalizeDocument++-- | Return value is True if all continuations match.+checkContinuations :: NonEmpty Container -> P Bool+checkContinuations = go . reverse . NonEmpty.toList+ where+ go [] = return True+ go (c:cs) = do continue <- (Just <$> blockContinue (containerSpec c) c)+ <|> pure Nothing+ when (continue == Just False) $ do -- early exit+ curline <- sourceLine+ curcol <- sourceColumn+ updateState $ \st ->+ st{ psLastLine = curline+ , psLastColumnPrevLine = curcol - 1 }+ if fromMaybe False continue+ then go cs+ else False <$ -- close len (c:cs) containers+ replicateM_ (length (c:cs)) closeCurrentContainer+++{-# INLINE processLines #-}+processLines :: P ()+processLines = do+ -- check continuations for open containers and close any that don't match+ containers <- psContainerStack <$> getState+ allContainersMatch <- checkContinuations containers++ -- check for new container starts and open if needed+ newContainersAdded <- tryContainerStarts++ followedByBlankLine <|> do+ -- determine if we have a lazy line+ let isLazy = not (allContainersMatch || newContainersAdded) &&+ blockName (containerSpec (NonEmpty.head containers)) == "Para"++ when isLazy $ -- restore original containers+ updateState (\st -> st{ psContainerStack = containers })++ tip <- getTip++ when (blockContainsBlock (containerSpec tip) == Just Normal) $ do+ -- add a paragraph container+ skipMany spaceOrTab+ blockStart paraSpec++ !curline <- sourceLine+ !curcolumn <- sourceColumn+ restline <- byteStringOf $ do+ skipMany (skipSatisfyByte (\c -> c /= '\n' && c /= '\r'))+ !lastcolumn <- sourceColumn+ optional_ endline+ updateState $ \st -> st{ psLastColumnPrevLine = lastcolumn - 1+ , psLastLine = curline }++ -- if current container is a line container, add remainder of line+ modifyContainers $+ \(c :| rest) ->+ if blockContainsLines (containerSpec c)+ then c{ containerText = containerText c Seq.|>+ Chunk{ chunkLine = curline+ , chunkColumn = curcolumn+ , chunkBytes = restline } } :| rest+ else c :| rest++ eof <|> processLines++-- True if new container was started+tryContainerStarts :: P Bool+tryContainerStarts = do+ (c :| _) <- psContainerStack <$> getState+ case blockContainsBlock (containerSpec c) of+ Just bt -> (do+ nextc <- lookahead (satisfyByte isAscii)+ next <- if nextc == ' ' || nextc == '\t'+ then skipMany spaceOrTab *> lookahead (satisfyByte isAscii)+ else pure nextc+ case next of+ '>' -> blockStart blockQuoteSpec+ '#' -> blockStart headingSpec+ ':' -> blockStart divSpec <|> blockStart listItemSpec+ '*' -> blockStart thematicBreakSpec <|> blockStart listItemSpec+ '-' -> blockStart thematicBreakSpec <|> blockStart listItemSpec+ '`' -> blockStart codeBlockSpec+ '{' -> blockStart attrSpec+ '[' -> blockStart referenceDefinitionSpec <|> blockStart footnoteSpec+ '|' | bt == Normal -> blockStart tableSpec+ '^' | bt == CaptionBlock -> blockStart captionSpec+ _ -> blockStart listItemSpec+ True <$ tryContainerStarts) <|> pure False+ _ -> pure False++-- | Close and finalize containers, returning Blocks.+finalizeDocument :: P Blocks+finalizeDocument = do+ cs <- psContainerStack <$> getState+ case cs of+ _ :| [] -> closeCurrentContainer >> finalize <$> getTip+ _ -> closeCurrentContainer >> finalizeDocument++{-# INLINE closeCurrentContainer #-}+-- | Close container and add to parent container.+closeCurrentContainer :: P ()+closeCurrentContainer = do+ cs <- psContainerStack <$> getState+ cs' <- case cs of+ _ :| [] -> pure cs+ c :| rest -> do+ case containerAttr c of+ Attr as | Just ident <- lookup "id" as+ -> updateState $ \st -> st{ psIds = Set.insert ident (psIds st) }+ _ -> pure ()+ c' <- blockClose (containerSpec c) c+ pure (c':|rest)+ case cs' of+ c :| (d:rest) -> updateState $+ \st -> st{ psContainerStack =+ d{ containerChildren = containerChildren d Seq.|>+ c{ containerEndLine = psLastLine st+ , containerEndColumn = psLastColumnPrevLine st } }+ :| rest }+ c :| [] -> updateState $+ \st -> st{ psContainerStack =+ c{ containerEndLine = psLastLine st+ , containerEndColumn = psLastColumnPrevLine st } :| [] }++{-# INLINE modifyContainers #-}+modifyContainers :: (NonEmpty Container -> NonEmpty Container) -> P ()+modifyContainers f =+ updateState $ \st -> st{ psContainerStack = f (psContainerStack st) }++{-# INLINE addContainer #-}+addContainer :: BlockSpec -> Int -> ContainerData -> P ()+addContainer bspec curcol bdata = do+ curline <- sourceLine+ attr <- psAttributes <$> getState+ opts <- psParseOptions <$> getState+ let newcontainer = emptyContainer { containerSpec = bspec+ , containerStartLine = curline+ , containerStartColumn = curcol+ , containerEndLine = curline+ , containerEndColumn = curcol+ , containerData = bdata+ , containerAttr = attr+ , containerSourcePos = sourcePositions opts /= NoSourcePos }+ unless (blockName bspec == "Attributes") $+ updateState $ \st -> st{ psAttributes = mempty }+ closeInappropriateContainers bspec+ modifyContainers (newcontainer NonEmpty.<|)++closeInappropriateContainers :: BlockSpec -> P ()+closeInappropriateContainers spec = do+ -- close containers until we get one that can accept this type of container+ cs <- psContainerStack <$> getState+ case cs of+ c :| _+ | blockContainsBlock (containerSpec c) == Just (blockType spec) ->+ pure ()+ | otherwise -> closeCurrentContainer *> closeInappropriateContainers spec+++finalize :: Container -> Blocks+finalize cont =+ addAttr (containerAttr cont)+ <$> blockFinalize (containerSpec cont) cont++addSourcePos :: Container -> Blocks -> Blocks+addSourcePos cont =+ if containerSourcePos cont+ then fmap+ (addPos (Pos (containerStartLine cont) (containerStartColumn cont)+ (containerEndLine cont) (containerEndColumn cont)))+ else id++finalizeChildren :: Container -> Blocks+finalizeChildren = foldMap finalize . containerChildren++-- Gobble as much space as possible up to indent.+gobbleSpaceToIndent :: Int -> P ()+gobbleSpaceToIndent indent = do+ curindent <- sourceColumn+ when (curindent < indent) $+ optional_ (spaceOrTab *> gobbleSpaceToIndent indent)++{-# INLINE getTip #-}+-- Get tip of container stack.+getTip :: P Container+getTip = NonEmpty.head . psContainerStack <$> getState++closeContainingSections :: Int -> P ()+closeContainingSections lev = do+ tip <- getTip+ case containerData tip of+ SectionData lev' _ | lev' >= lev ->+ closeCurrentContainer >>+ closeContainingSections lev+ _ -> pure ()++-- TODO avoid detour through String+toIdentifier :: ByteString -> ByteString+toIdentifier bs =+ if null parts+ then "sec"+ else strToUtf8 $ intercalate "-" parts+ where+ isSym = (`elem` ("][~!@#$%^&*(){}`,.<>\\|=+/" :: [Char]))+ parts = words $ map (\c -> if isSym c then ' ' else c) $ utf8ToStr bs
+ src/Djot/Djot.hs view
@@ -0,0 +1,477 @@+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE StrictData #-}+module Djot.Djot+ ( renderDjot+ , RenderOptions(..)+ )+where++import Djot.AST+import Djot.Options (RenderOptions(..))+import Data.Char (ord, chr)+import Djot.Parse (utf8ToStr)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as B8+import qualified Data.Set as Set+import Data.Set (Set)+import qualified Data.Sequence as Seq+import qualified Data.Map.Strict as M+import Data.Maybe (fromMaybe)+import Data.List (sortOn, intersperse, transpose)+import Control.Monad+import Control.Monad.State+import qualified Data.Foldable as F+import Text.DocLayout hiding (Doc)+import qualified Text.DocLayout as Layout+import Data.Text (Text)+import qualified Data.Text as T+import Data.Text.Encoding (decodeUtf8With)+import Data.Text.Encoding.Error (lenientDecode)+import qualified Data.IntMap.Strict as IntMap++renderDjot :: RenderOptions -> Doc -> Layout.Doc Text+renderDjot opts doc = evalState+ (do body <- toLayout (docBlocks doc)+ refs <- gets referenceMap >>= toReferences+ notes <- toNotes+ pure $ body $$ refs $$ notes <> cr)+ BState{ noteMap = docFootnotes doc+ , noteOrder = mempty+ , referenceMap = docReferences doc+ , autoIds = docAutoIdentifiers doc+ , afterSpace = True+ , nestings = IntMap.fromList+ -- anything not in this list+ -- will ALWAYS get {}:+ [(ord '_', 0)+ ,(ord '*', 0)+ ,(ord '~', 0)+ ,(ord '\'', 0)+ ,(ord '"', 0)+ ,(ord '^', 0)]+ , lastBullet = Nothing+ , options = opts+ }++data BState =+ BState { noteMap :: NoteMap+ , noteOrder :: M.Map ByteString Int+ , referenceMap :: ReferenceMap+ , autoIds :: Set ByteString+ , afterSpace :: Bool+ , nestings :: IntMap.IntMap Int+ , lastBullet :: Maybe Char+ , options :: RenderOptions+ }++toReferences :: ReferenceMap -> State BState (Layout.Doc Text)+toReferences (ReferenceMap refs) =+ (<> cr) . vcat <$> mapM toReference (M.toList refs)++toReference :: (ByteString, (ByteString, Attr)) -> State BState (Layout.Doc Text)+toReference (label, (url, attr)) = do+ attr' <- toLayout attr+ let ref = "[" <> literal (fromUtf8 label) <> "]:" <+> literal (fromUtf8 url)+ pure $ attr' $$ ref++toNotes :: State BState (Layout.Doc Text)+toNotes = do+ noterefs <- gets noteOrder+ allLabels <- gets (M.keys . unNoteMap . noteMap)+ let sortedLabels = sortOn (`M.lookup` noterefs) allLabels+ (<> cr) . vsep <$> mapM toNote sortedLabels++toNote :: ByteString -> State BState (Layout.Doc Text)+toNote label = do+ notes <- gets noteMap+ case lookupNote label notes of+ Nothing -> pure mempty+ Just bls ->+ hang 4 (toNoteRef label <> ":" <> space) <$> toLayout bls++fromUtf8 :: ByteString -> Text+fromUtf8 = decodeUtf8With lenientDecode++data EscapeContext = Normal++{-# INLINE escapeDjot #-}+escapeDjot :: EscapeContext -> ByteString -> Text+escapeDjot Normal bs+ | B8.any escapable bs = T.pack. go . utf8ToStr $ bs+ | otherwise = fromUtf8 bs+ where+ escapable c = c == '[' || c == ']' || c == '<' || c == '>' ||+ c == '$' || c == '!' || c == '{' || c == '}' || c == ':' ||+ c == '-' || c == '^' || c == '~' ||+ c == '*' || c == '_' || c == '\''|| c == '"' || c == '.' ||+ c == '|' || c == '`' || c == '\\'+ go [] = []+ go ('$':c:cs)+ | c == '`' = '\\' : '$' : c : go cs+ | otherwise = '$' : go (c : cs)+ go ('-':cs) =+ case cs of+ '-':_ -> '\\' : '-' : go cs+ _ -> '-' : go cs+ go ('.':cs) =+ case cs of+ '.':'.':_ -> '\\' : '.' : go cs+ _ -> '.' : go cs+ go (c:':':cs)+ | c /= ']'+ , case cs of+ [] -> True+ (' ':_) -> True+ _ -> False+ = (if escapable c then ('\\' :) else id) $ c : ':' : go cs+ go (c:cs)+ | escapable c = '\\' : c : go cs+ | otherwise = c : go cs++{-# SPECIALIZE toLayout :: Blocks -> State BState (Layout.Doc Text) #-}+{-# SPECIALIZE toLayout :: Inlines -> State BState (Layout.Doc Text) #-}+{-# SPECIALIZE toLayout :: Attr -> State BState (Layout.Doc Text) #-}+class ToLayout a where+ toLayout :: a -> State BState (Layout.Doc Text)++instance ToLayout Inlines where+ toLayout = fmap F.fold . mapM toLayout . unMany++instance ToLayout Blocks where+ toLayout = fmap F.fold . mapM toLayout . unMany++instance ToLayout Attr where+ toLayout (Attr kvs)+ = pure $ if isEmpty contents+ then mempty+ else "{" <> contents <> "}"+ where+ contents = hsep (map go kvs)+ go ("id",ident) = literal ("#" <> fromUtf8 ident)+ go ("class", classes') = hsep $ map (("." <>) . literal)+ $ T.words $ fromUtf8 classes'+ go (k,v) = literal (fromUtf8 k) <> "=" <>+ doubleQuotes (literal (escapeDjot Normal v))++instance ToLayout (Node Block) where+ toLayout (Node _pos attr bl) =+ ($$) <$> (case bl of+ -- don't print an id that was generated implicitly+ Heading{} -> do+ autoids <- gets autoIds+ let Attr as = attr+ toLayout $ Attr [(k,v) | (k,v) <- as+ , not (k == "id" && v `Set.member` autoids)]+ Section{} -> do+ autoids <- gets autoIds+ let Attr as = attr+ toLayout $ Attr [(k,v) | (k,v) <- as+ , not (k == "id" &&+ v `Set.member` autoids)]+ _ -> toLayout attr)+ <*> (($$ blankline) <$> case bl of+ Para ils -> toLayout ils+ Heading lev ils -> do+ contents <- toLayout ils+ pure $ literal (T.replicate lev "#") <+> contents+ Section bls -> ($$ blankline) <$> toLayout bls+ ThematicBreak -> pure $ literal "* * * *"+ BulletList listSpacing items -> do+ lastb <- gets lastBullet+ let bullet = case lastb of+ Just '+' -> "-"+ Just '-' -> "+"+ _ -> "-"+ (case listSpacing of+ Tight -> vcat . map chomp+ Loose -> vsep) <$>+ mapM (fmap (hang 2 (bullet <> space)) . toLayout) items+ OrderedList listAttr listSpacing items ->+ (case listSpacing of+ Tight -> vcat . map chomp+ Loose -> vsep) <$>+ zipWithM (toOrderedListItem listAttr)+ [(orderedListStart listAttr)..]+ items+ DefinitionList listSpacing items ->+ (case listSpacing of+ Tight -> vcat . map chomp+ Loose -> vsep) <$>+ mapM toDefinitionListItem items+ TaskList listSpacing items ->+ (case listSpacing of+ Tight -> vcat . map chomp+ Loose -> vsep) <$>+ mapM toTaskListItem items+ Div bls -> do+ let nestedDivs = computeDivNestingLevel bls+ contents <- toLayout bls+ let colons = literal (T.replicate (nestedDivs + 3) ":")+ pure $ colons $$ contents $$ colons+ BlockQuote bls ->+ if bls == mempty+ then pure ">"+ else prefixed "> " <$> toLayout bls+ CodeBlock lang bs -> do+ let longesttickline =+ case B8.lines bs of+ [] -> 0+ ls -> maximum $ map (B8.length . B8.takeWhile (=='`')) ls+ let numticks = max 3 longesttickline+ let ticks = literal $ T.replicate numticks "`"+ let lang' = if lang == mempty+ then mempty+ else literal (fromUtf8 lang)+ pure $ ticks <+> lang'+ $$ literal (fromUtf8 bs)+ $$ ticks+ Table mbCaption rows -> do+ caption <- case mbCaption of+ Nothing -> pure mempty+ Just (Caption bls)+ -> hang 2 ("^" <> space) <$> toLayout bls+ body <- toTable rows+ pure $ body $+$ caption+ RawBlock (Format "djot") bs ->+ pure $ literal (fromUtf8 bs)+ RawBlock _ _ -> pure mempty)+ <* modify' (\st -> st{ afterSpace = True+ -- Handle case of one bullet list right after+ -- another; we need to change the bullet to+ -- start a new list:+ , lastBullet = case bl of+ BulletList{} ->+ case lastBullet st of+ Just '-' -> Just '+'+ Just '+' -> Just '-'+ _ -> Just '-'+ _ -> Nothing })++toTable :: [[Cell]] -> State BState (Layout.Doc Text)+toTable [] = pure "|--|" -- minimal empty table+toTable rows = do+ let getCellContents (Cell hd al ils) = ((hd, al),) <$> toLayout ils+ rowContents <- mapM (mapM getCellContents) rows+ let colwidths = map (maximum . map (offset . snd))+ (transpose rowContents)+ let toCell width ((_,align), d) =+ (case align of+ AlignLeft -> lblock+ AlignRight -> rblock+ AlignCenter -> cblock+ AlignDefault -> lblock) width d+ let mkRow ds = hcat $ vfill "| " : intersperse (vfill " | ") ds +++ [vfill " |"]+ let mkLines ds = hcat $ vfill "|" : intersperse (vfill "|") ds +++ [vfill "|"]+ let toUnderline width ((_,al),_) = literal $+ case al of+ AlignLeft -> ":" <> T.replicate (width + 1) "-"+ AlignRight -> T.replicate (width + 1) "-" <> ":"+ AlignCenter -> ":" <> T.replicate width "-" <> ":"+ AlignDefault -> T.replicate width "-"+ let toRow cells =+ let isHeader = case cells of+ ((HeadCell,_),_) : _ -> True+ _ -> False+ in mkRow (zipWith toCell colwidths cells)+ $$+ if isHeader+ then mkLines (zipWith toUnderline colwidths cells)+ else mempty+ pure $ vcat $ map toRow rowContents++toDefinitionListItem :: (Inlines, Blocks) -> State BState (Layout.Doc Text)+toDefinitionListItem (term, def) = do+ term' <- toLayout term+ def' <- toLayout def+ pure $ hang 2 (":" <> space) $ term' $+$ def'++toTaskListItem :: (TaskStatus, Blocks) -> State BState (Layout.Doc Text)+toTaskListItem (status, bls) = do+ contents <- toLayout bls+ let marker = case status of+ Incomplete -> "- [ ]" <> space+ Complete -> "- [X]" <> space+ pure $ hang 2 marker contents++toOrderedListItem :: OrderedListAttributes -> Int -> Blocks+ -> State BState (Layout.Doc Text)+toOrderedListItem listAttr num bs = do+ contents <- toLayout bs+ let marker = formatOrderedListMarker listAttr num+ pure $ hang (offset marker + 1) (marker <> space) contents++formatOrderedListMarker :: OrderedListAttributes -> Int -> Layout.Doc Text+formatOrderedListMarker listAttr =+ addDelims (orderedListDelim listAttr) .+ formatNumber (orderedListStyle listAttr)++addDelims :: OrderedListDelim -> Layout.Doc Text -> Layout.Doc Text+addDelims RightPeriod d = d <> "."+addDelims RightParen d = d <> ")"+addDelims LeftRightParen d = "(" <> d <> ")"++formatNumber :: OrderedListStyle -> Int -> Layout.Doc Text+formatNumber Decimal n = literal (T.pack (show n))+formatNumber LetterUpper n = literal (T.singleton (chr (ord 'A' + n - 1)))+formatNumber LetterLower n = literal (T.singleton (chr (ord 'a' + n - 1)))+formatNumber RomanUpper n = literal $ toRomanNumeral n+formatNumber RomanLower n = literal $ T.toLower (toRomanNumeral n)++-- | Convert number < 4000 to uppercase roman numeral. (from pandoc)+toRomanNumeral :: Int -> T.Text+toRomanNumeral x+ | x >= 4000 || x < 0 = "?"+ | x >= 1000 = "M" <> toRomanNumeral (x - 1000)+ | x >= 900 = "CM" <> toRomanNumeral (x - 900)+ | x >= 500 = "D" <> toRomanNumeral (x - 500)+ | x >= 400 = "CD" <> toRomanNumeral (x - 400)+ | x >= 100 = "C" <> toRomanNumeral (x - 100)+ | x >= 90 = "XC" <> toRomanNumeral (x - 90)+ | x >= 50 = "L" <> toRomanNumeral (x - 50)+ | x >= 40 = "XL" <> toRomanNumeral (x - 40)+ | x >= 10 = "X" <> toRomanNumeral (x - 10)+ | x == 9 = "IX"+ | x >= 5 = "V" <> toRomanNumeral (x - 5)+ | x == 4 = "IV"+ | x >= 1 = "I" <> toRomanNumeral (x - 1)+ | otherwise = ""++++instance ToLayout (Node Inline) where+ toLayout (Node _pos attr il) = (<>)+ <$> case il of+ Str bs -> do+ let fixSmart = T.replace "\x2014" "---" .+ T.replace "\x2013" "--" .+ T.replace "\x2026" "..." .+ T.replace "\x2019" "'" .+ T.replace "\x201C" "\""+ let chunks =+ T.groupBy+ (\c d -> (c /= ' ' && d /= ' ') || (c == ' ' && d == ' '))+ (fixSmart $ escapeDjot Normal bs)+ let toChunk ch+ = case T.uncons ch of+ Just (' ', rest)+ -> afterBreak "{}" <> space <> literal rest+ _ -> literal ch+ pure $ hcat $ map toChunk chunks+ SoftBreak -> do+ opts <- gets options+ pure $ if preserveSoftBreaks opts then cr else space+ HardBreak -> pure (literal "\\" <> cr)+ NonBreakingSpace -> pure "\\ "+ Emph ils -> surround '_' ils+ Strong ils -> surround '*' ils+ Highlight ils -> surround '=' ils+ Insert ils -> surround '+' ils+ Delete ils -> surround '-' ils+ Superscript ils -> surround '^' ils+ Subscript ils -> surround '~' ils+ Quoted SingleQuotes ils -> surround '\'' ils+ Quoted DoubleQuotes ils -> surround '"' ils+ Verbatim bs -> pure $ toVerbatimSpan bs+ Math mt bs -> do+ let suffix = toVerbatimSpan bs+ let prefix = case mt of+ DisplayMath -> "$$"+ InlineMath -> "$"+ pure $ prefix <> suffix+ Symbol bs -> pure $ ":" <> literal (fromUtf8 bs) <> ":"+ Span ils -> do+ contents <- toLayout ils+ pure $ "[" <> contents <> "]" <>+ case attr of -- there must be attributes for it to be a span+ Attr [] -> "{}"+ _ -> mempty+ Link ils target -> do+ contents <- toLayout ils+ let suffix = toLinkSuffix target contents+ pure $ "[" <> contents <> "]" <> suffix+ Image ils target -> do+ contents <- toLayout ils+ let suffix = toLinkSuffix target contents+ pure $ "![" <> contents <> "]" <> suffix+ EmailLink email -> pure $ "<" <> literal (fromUtf8 email) <> ">"+ UrlLink url -> pure $ "<" <> literal (fromUtf8 url) <> ">"+ RawInline (Format "djot") bs -> pure $ literal (fromUtf8 bs)+ RawInline _ _ -> pure mempty+ FootnoteReference label -> do+ order <- gets noteOrder+ case M.lookup label order of+ Nothing -> modify' $ \st ->+ st{ noteOrder =+ M.insert label (M.size order + 1) order }+ Just _ -> pure ()+ pure $ toNoteRef label+ <*> toLayout attr+ <* modify' (\st ->+ st{ afterSpace =+ case il of+ Str bs | isWhite (B8.takeEnd 1 bs) -> True+ SoftBreak -> True+ HardBreak -> True+ NonBreakingSpace -> True+ _ -> False })++toLinkSuffix :: Target -> Layout.Doc Text -> Layout.Doc Text+toLinkSuffix (Direct url) _ = literal $ "(" <> fromUtf8 url <> ")"+toLinkSuffix (Reference label) d+ | render Nothing d == fromUtf8 label = literal "[]"+ | otherwise = literal $ "[" <> fromUtf8 label <> "]"++toVerbatimSpan :: ByteString -> Layout.Doc Text+toVerbatimSpan bs =+ ticks <> (if startsWithTick then " " else mempty) <>+ literal (fromUtf8 bs) <>+ (if endsWithTick then " " else mempty) <> ticks+ where+ startsWithTick = B8.take 1 bs == "`"+ endsWithTick = B8.takeEnd 1 bs == "`"+ ticks = literal $ T.replicate (maxticks + 1) "`"+ maxticks = fst $ B8.foldl' scanTicks (0,0) bs+ scanTicks (longest, theseticks) '`' =+ (max (theseticks + 1) longest, theseticks + 1)+ scanTicks (longest, _) _ = (longest, 0)++isWhite :: ByteString -> Bool+isWhite " " = True+isWhite "\t" = True+isWhite _ = False++surround :: Char -> Inlines -> State BState (Layout.Doc Text)+surround c ils = do+ let startBeforeSpace =+ case Seq.viewl (unMany ils) of+ Node _pos _ (Str bs) Seq.:< _ ->+ isWhite (B8.take 1 bs)+ _ -> False+ modify' $ \st -> st{ nestings = IntMap.adjust (+ 1) (ord c) (nestings st)}+ contents <- toLayout ils+ modify' $ \st -> st{ nestings = IntMap.adjust (\x -> x - 1)+ (ord c) (nestings st)}+ endAfterSpace <- gets afterSpace+ nestingLevel <- gets (fromMaybe 1 . IntMap.lookup (ord c) . nestings)+ let core = char c <> contents <> char c+ pure $+ if nestingLevel == 0 && not (startBeforeSpace || endAfterSpace) &&+ not (null ils)+ then core+ else char '{' <> core <> char '}'++toNoteRef :: ByteString -> Layout.Doc Text+toNoteRef bs = literal ("[^" <> fromUtf8 bs <> "]")++computeDivNestingLevel :: Blocks -> Int+computeDivNestingLevel =+ foldr go 0 . unMany+ where+ go (Node _pos _ (Div bls')) n =+ max (n + 1) (foldr go (n + 1) (unMany bls'))+ go _ n = n
+ src/Djot/Html.hs view
@@ -0,0 +1,350 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE Strict #-}+module Djot.Html+ ( inlinesToByteString+ , renderHtml+ , RenderOptions(..)+ )+where++import Djot.AST+import Data.Tuple (swap)+import Djot.Parse (strToUtf8)+import Djot.Options (RenderOptions(..))+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import Data.ByteString.Builder (Builder, byteString, word8, intDec)+import qualified Data.Sequence as Seq+import qualified Data.Map.Strict as M+import Data.Maybe (fromMaybe)+import Data.List (sort)+import Control.Monad.State+import qualified Data.Foldable as F++renderHtml :: RenderOptions -> Doc -> Builder+renderHtml opts doc = evalState+ ( (<>) <$> toBuilder (docBlocks doc)+ <*> toNotes )+ BState{ noteMap = docFootnotes doc+ , noteRefs = mempty+ , renderedNotes = mempty+ , referenceMap = docReferences doc+ <> docAutoReferences doc+ , options = opts+ }++toNotes :: State BState Builder+toNotes = do+ st <- get+ let noterefs = noteRefs st+ let numnotes = M.size noterefs+ let revnoterefs = sort $ map swap $ M.toList noterefs+ let toNote (num, lab) =+ let num' = B8.pack (show num)+ in inTags "li" NoPos (Attr [("id", "fn" <> num')])+ ("\n" <> fromMaybe mempty (M.lookup lab (renderedNotes st)))+ <> "\n"+ if numnotes < 1+ then pure mempty+ else pure $+ inTags "section" NoPos (Attr [("role", "doc-endnotes")])+ ("\n" <> singleTag "hr" NoPos mempty <> "\n" <>+ inTags "ol" NoPos mempty ("\n" <> foldMap toNote revnoterefs) <> "\n")+ <> "\n"++addBackref :: ByteString -> Blocks -> Blocks+addBackref num (Many bls) =+ Many $+ case Seq.viewr bls of+ rest Seq.:> Node pos attr (Para ils) ->+ rest Seq.|> Node pos attr (Para (ils <> backlink))+ _ -> bls Seq.|> Node NoPos mempty (Para backlink)+ where+ backlink = Many $ Seq.singleton $+ Node NoPos (Attr [("role", "doc-backlink")])+ (Link (str (strToUtf8 "\8617\65038"))+ (Direct ("#fnref" <> num)))++{-# INLINE escapeHtml #-}+escapeHtml :: ByteString -> Builder+escapeHtml bs =+ if hasEscapable bs+ then B.foldl' go mempty bs+ else byteString bs+ where+ hasEscapable = B.any (\w -> w == 38 || w == 60 || w == 62)+ go b 38 = b <> byteString "&"+ go b 60 = b <> byteString "<"+ go b 62 = b <> byteString ">"+ go b c = b <> word8 c++{-# INLINE escapeHtmlAttribute #-}+escapeHtmlAttribute :: ByteString -> Builder+escapeHtmlAttribute bs =+ if hasEscapable bs+ then B.foldl' go mempty bs+ else byteString bs+ where+ hasEscapable = B.any (\w -> w == 38 || w == 60 || w == 62 || w == 34)+ go b 38 = b <> byteString "&"+ go b 60 = b <> byteString "<"+ go b 62 = b <> byteString ">"+ go b 34 = b <> byteString """+ go b c = b <> word8 c++data BState =+ BState { noteMap :: NoteMap+ , noteRefs :: M.Map ByteString Int+ , renderedNotes :: M.Map ByteString Builder+ , referenceMap :: ReferenceMap+ , options :: RenderOptions+ }++{-# SPECIALIZE toBuilder :: Blocks -> State BState Builder #-}+{-# SPECIALIZE toBuilder :: Inlines -> State BState Builder #-}+class ToBuilder a where+ toBuilder :: a -> State BState Builder++instance ToBuilder Inlines where+ toBuilder = fmap F.fold . mapM toBuilder . unMany++instance ToBuilder Blocks where+ toBuilder = fmap F.fold . mapM toBuilder . unMany++instance ToBuilder (Node Block) where+ toBuilder (Node pos attr bl) =+ let addNl = (<> "\n") in+ case bl of+ Para ils -> addNl . inTags "p" pos attr <$> toBuilder ils+ Heading lev ils ->+ let tag = case lev of+ 1 -> "h1"+ 2 -> "h2"+ 3 -> "h3"+ 4 -> "h4"+ 5 -> "h5"+ 6 -> "h6"+ _ -> "p"+ in addNl . inTags tag pos attr <$> toBuilder ils+ Section bls -> do+ contents <- toBuilder bls+ pure $ addNl $ inTags "section" pos attr $ "\n" <> contents+ ThematicBreak -> pure $ addNl $ singleTag "hr" pos attr+ BulletList listSpacing items ->+ addNl . inTags "ul" pos attr . ("\n" <>) . mconcat <$> mapM toLi items+ where+ toLi bls = addNl . inTags "li" NoPos mempty . ("\n" <>) <$>+ toItemContents listSpacing bls+ OrderedList listAttr listSpacing items ->+ addNl . inTags "ol" pos (Attr [("start", strToUtf8 (show start))+ | start /= 1]+ <> Attr [("type", typ) | typ /= "1"] <> attr)+ . ("\n" <>) . mconcat <$> mapM toLi items+ where+ typ = case orderedListStyle listAttr of+ Decimal -> "1"+ LetterUpper -> "A"+ LetterLower -> "a"+ RomanUpper -> "I"+ RomanLower -> "i"+ start = orderedListStart listAttr+ toLi bls = addNl . inTags "li" NoPos mempty . ("\n" <>)+ <$> toItemContents listSpacing bls+ DefinitionList listSpacing defs ->+ addNl . inTags "dl" pos attr . ("\n" <>) . mconcat+ <$> mapM (toDefinition listSpacing) defs+ TaskList listSpacing items ->+ addNl . inTags "ul" pos (Attr [("class", "task-list")] <> attr)+ . ("\n" <>) . mconcat <$> mapM (toTaskListItem listSpacing) items+ Div bls -> addNl . inTags "div" pos attr . ("\n" <>) <$> toBuilder bls+ BlockQuote bls ->+ addNl . inTags "blockquote" pos attr . ("\n" <>) <$> toBuilder bls+ CodeBlock lang bs -> pure $+ inTags "pre" pos attr (inTags "code" NoPos codeattr (escapeHtml bs))+ <> "\n"+ where+ codeattr = if B.null lang+ then mempty+ else Attr [("class", "language-" <> lang)]+ Table mbCaption rows -> do+ rows' <- mapM toRow rows+ capt <- case mbCaption of+ Nothing -> pure mempty+ Just (Caption bs) ->+ addNl . inTags "caption" NoPos mempty+ <$> case F.toList (unMany bs) of+ [Node _pos at (Para ils)] | at == mempty+ -> toBuilder ils+ _ -> ("\n" <>) <$> toBuilder bs+ pure $ addNl . inTags "table" pos attr . ("\n" <>) $ capt <> mconcat rows'+ RawBlock (Format "html") bs -> pure $ byteString bs+ RawBlock _ _ -> pure mempty++toRow :: [Cell] -> State BState Builder+toRow cells = (<> "\n") . inTags "tr" NoPos mempty . ("\n" <>) . mconcat+ <$> mapM toCell cells++toCell :: Cell -> State BState Builder+toCell (Cell cellType align ils) =+ (<> "\n") . inTags (if cellType == HeadCell+ then "th"+ else "td") NoPos attr <$> toBuilder ils+ where+ attr = Attr $ case align of+ AlignDefault -> []+ AlignLeft -> [("style", "text-align: left;")]+ AlignRight -> [("style", "text-align: right;")]+ AlignCenter -> [("style", "text-align: center;")]+++toItemContents :: ListSpacing -> Blocks -> State BState Builder+toItemContents listSpacing = fmap F.fold . mapM go . unMany+ where+ go (Node pos attr bl) =+ case bl of+ Para ils+ | listSpacing == Tight ->+ if attr == mempty+ then (<> "\n") <$> toBuilder ils+ else (<> "\n") . inTags "span" pos attr <$> toBuilder ils+ | otherwise -> toBuilder (Node pos attr bl)+ _ -> toBuilder (Node pos attr bl)++toTaskListItem :: ListSpacing -> (TaskStatus, Blocks) -> State BState Builder+toTaskListItem listSpacing (status, bs) = do+ body <- case Seq.viewl $ unMany bs of+ Node pos attr (Para ils) Seq.:< rest ->+ toItemContents listSpacing (Many+ (Node pos attr+ (Para (rawInline (Format "html") ("<label>" <> input) <>+ ils <>+ rawInline (Format "html") "</label>")) Seq.<| rest))+ _ -> toBuilder $ rawBlock (Format "html") input <> bs+ pure $ inTags "li" NoPos (Attr [("class", if status == Complete+ then "checked"+ else "unchecked")]) ("\n" <> body) <> "\n"+ where+ inputattr = " type=\"checkbox\"" <>+ if status == Complete then " checked=\"\"" else ""+ input = "<input" <> inputattr <> " />"++toDefinition :: ListSpacing -> (Inlines, Blocks) -> State BState Builder+toDefinition listSpacing (term, defn) = (<>) <$>+ ((<> "\n") . inTags "dt" NoPos mempty <$> toBuilder term) <*>+ ((<> "\n") . inTags "dd" NoPos mempty . ("\n" <>) <$> toItemContents listSpacing defn)++instance ToBuilder (Node Inline) where+ toBuilder (Node pos attr il) =+ case il of+ Str bs -> case attr of+ Attr [] | pos == NoPos -> pure $ escapeHtml bs+ _ -> pure $ inTags "span" pos attr $ escapeHtml bs+ SoftBreak -> do+ opts <- gets options+ pure $ word8 $ if preserveSoftBreaks opts then 10 else 32+ HardBreak -> pure $ singleTag "br" NoPos attr <> "\n"+ NonBreakingSpace -> pure $ byteString " "+ Emph ils -> inTags "em" pos attr <$> toBuilder ils+ Strong ils -> inTags "strong" pos attr <$> toBuilder ils+ Highlight ils -> inTags "mark" pos attr <$> toBuilder ils+ Insert ils -> inTags "ins" pos attr <$> toBuilder ils+ Delete ils -> inTags "del" pos attr <$> toBuilder ils+ Superscript ils -> inTags "sup" pos attr <$> toBuilder ils+ Subscript ils -> inTags "sub" pos attr <$> toBuilder ils+ Quoted SingleQuotes ils -> inSingleQuotes <$> toBuilder ils+ Quoted DoubleQuotes ils -> inDoubleQuotes <$> toBuilder ils+ Verbatim bs -> pure $ inTags "code" pos attr (escapeHtml bs)+ Math DisplayMath bs -> pure $+ inTags "span" pos (Attr [("class", "math display")] <> attr)+ ("\\[" <> escapeHtml bs <> "\\]")+ Math InlineMath bs -> pure $+ inTags "span" pos (Attr [("class", "math inline")] <> attr)+ ("\\(" <> escapeHtml bs <> "\\)")+ Symbol bs -> pure $+ inTags "span" pos (Attr [("class", "symbol")] <> attr)+ (":" <> escapeHtml bs <> ":")+ Span ils -> inTags "span" pos attr <$> toBuilder ils+ Link ils target -> do+ attr' <- case target of+ Direct u -> pure $ Attr [("href", u)]+ Reference label -> do+ rm <- gets referenceMap+ case lookupReference label rm of+ Nothing -> pure $ Attr [("href", "")]+ Just (u, Attr as) -> pure $ Attr (("href",u):as)+ inTags "a" pos (attr' <> attr) <$> toBuilder ils+ Image ils target -> do+ attr' <- case target of+ Direct u -> pure $ Attr [("src", u)]+ Reference label -> do+ rm <- gets referenceMap+ case lookupReference label rm of+ Nothing -> pure $ Attr [("src", "")]+ Just (u, Attr as) -> pure $ Attr (("src",u):as)+ pure $ singleTag "img" pos+ (Attr [("alt", inlinesToByteString ils)] <> attr' <> attr)+ EmailLink email ->+ toBuilder (Node pos attr (Link (str email) (Direct ("mailto:" <> email))))+ UrlLink url -> toBuilder (Node pos attr (Link (str url) (Direct url)))+ RawInline (Format "html") bs -> pure $ byteString bs+ RawInline _ _ -> pure mempty+ FootnoteReference label -> do+ noterefs <- gets noteRefs+ notemap <- gets noteMap+ num <- case M.lookup label noterefs of+ Just num -> pure num+ Nothing -> do+ let num = M.size noterefs + 1+ modify $ \st -> st{ noteRefs = M.insert label num noterefs }+ renderedNotesMap <- gets renderedNotes+ case M.lookup label renderedNotesMap of+ Just _ -> pure ()+ Nothing -> do -- render the note and add to renderedNotes+ let num' = B8.pack (show num)+ rendered <- maybe (toBuilder $ addBackref num' (mempty :: Blocks))+ (toBuilder . addBackref num') (lookupNote label notemap)+ modify $ \st -> st{ renderedNotes =+ M.insert label rendered (renderedNotes st) }+ pure num+ let num' = B8.pack $ show num+ pure $ inTags "a" pos (Attr [("id", "fnref" <> num'),+ ("href", "#fn" <> num'),+ ("role", "doc-noteref")] <> attr) $+ inTags "sup" pos mempty (escapeHtml num')++{-# INLINE inTags #-}+inTags :: ByteString -> Pos -> Attr -> Builder -> Builder+inTags tag pos attr contents =+ "<" <> byteString tag <> posToBuilder pos+ <> attrToBuilder attr <> ">" <> contents+ <> "</" <> byteString tag <> ">"+++{-# INLINE singleTag #-}+singleTag :: ByteString -> Pos -> Attr -> Builder+singleTag tag pos attr =+ "<" <> byteString tag <> posToBuilder pos <> attrToBuilder attr <> ">"++{-# INLINE attrToBuilder #-}+attrToBuilder :: Attr -> Builder+attrToBuilder (Attr pairs) = foldMap go pairs+ where+ go (k,v) = " " <> byteString k <> "=\"" <> escapeHtmlAttribute v <> "\""++{-# INLINE posToBuilder #-}+posToBuilder :: Pos -> Builder+posToBuilder NoPos = mempty+posToBuilder (Pos sl sc el ec) =+ " data-pos=\"" <> intDec sl <> ":" <> intDec sc <> "-" <>+ intDec el <> ":" <> intDec ec <> "\""++inSingleQuotes :: Builder -> Builder+inSingleQuotes x =+ byteString (strToUtf8 "\x2018") <> x <> byteString (strToUtf8 "\x2019")++inDoubleQuotes :: Builder -> Builder+inDoubleQuotes x =+ byteString (strToUtf8 "\x201C") <> x <> byteString (strToUtf8 "\x201D")
+ src/Djot/Inlines.hs view
@@ -0,0 +1,525 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE Strict #-}+{-# LANGUAGE BinaryLiterals #-}+module Djot.Inlines+ ( parseInlines+ , parseTableCells+ )+where++import Data.Char (isAscii, isLetter, isAlphaNum, isSymbol, isPunctuation)+import Control.Monad (guard, when, mzero)+import Data.Sequence (Seq)+import qualified Data.Sequence as Seq+import Data.Set (Set)+import qualified Data.Set as Set+import Djot.Parse+import Djot.Options (ParseOptions(..), SourcePosOption(..))+import Djot.Attributes (pAttributes)+import Djot.AST+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import Data.ByteString (ByteString)+import Data.Foldable as F+import Control.Applicative+import Data.Maybe (fromMaybe)++-- import Debug.Trace++{-# INLINE isSpecial #-}+isSpecial :: Char -> Bool+isSpecial c = c == '[' || c == ']' || c == '<' || c == '>' ||+ c == '$' || c == '!' || c == '{' || c == '}' || c == ':' ||+ c == '=' || c == '+' || c == '-' || c == '^' || c == '~' ||+ c == '*' || c == '_' || c == '\''|| c == '"' || c == '.' ||+ c == '|' || c == '`' || c == '\\'|| c == '\n' || c == '\r'++parseInlines :: ParseOptions -> Seq Chunk -> Either String Inlines+parseInlines opts chunks = do+ case parse (pInlines <* eof) ParserState{ mode = NormalMode+ , activeDelims = mempty+ , options = opts }+ (toList (stripEndChunks chunks)) of+ Just ils -> Right ils+ Nothing -> Left $ "parseInlines failed on input: "+ <> show (foldMap chunkBytes chunks)++parseTableCells :: ParseOptions -> Chunk -> Either String [Inlines]+parseTableCells opts chunk = do+ case parse (asciiChar '|'+ *> some (removeFinalWs <$> pInlines <* asciiChar '|')+ <* skipMany ws+ <* eof)+ ParserState{ mode = TableCellMode+ , activeDelims = mempty+ , options = opts }+ [chunk] of+ Just cells -> Right cells+ Nothing -> Left $ "parseTableCells failed on input: " <> show chunk++removeFinalWs :: Inlines -> Inlines+removeFinalWs (Many ils) = Many $+ case Seq.viewr ils of+ rest Seq.:> Node pos attr (Str bs)+ | B8.takeEnd 1 bs == " "+ -> case B8.dropWhileEnd (== ' ') bs of+ "" -> rest+ bs' -> rest Seq.|> Node pos attr (Str bs')+ _ -> ils++data InlineParseMode =+ NormalMode | TableCellMode+ deriving (Show, Ord, Eq)++data ParserState =+ ParserState+ { mode :: InlineParseMode+ , activeDelims :: Set Delim+ , options :: ParseOptions }+ deriving (Show)++data Delim = Delim Bool Char+ deriving (Show, Ord, Eq)++type P = Parser ParserState++pInlines :: P Inlines+pInlines = skipMany ws *> (mconcat <$> many pInline)++pInline :: P Inlines+pInline = do+ sline <- sourceLine+ scol <- sourceColumn+ res <- pInline'+ opts <- options <$> getState+ (case sourcePositions opts of+ AllSourcePos -> do+ eline <- sourceLine+ ecol <- sourceColumn+ pure $ addPos (Pos sline scol eline (ecol - 1)) <$> res+ _ -> pure res) >>= pOptionalAttributes++pOptionalAttributes :: Inlines -> P Inlines+pOptionalAttributes (Many ils) = pAddAttributes (Many ils) <|> pure (Many ils)++pAddAttributes :: Inlines -> P Inlines+pAddAttributes (Many ils) = do+ attr <- mconcat <$> some pAttributes+ pure $+ case attr of+ Attr [] -> Many ils+ _ -> case Seq.viewr ils of+ Seq.EmptyR -> mempty+ ils' Seq.:> Node pos attr' (Str bs)+ | B8.any isWs bs ->+ -- attach attribute to last word+ let (front, lastword) = B8.breakEnd isWs bs+ in if B.null lastword+ then Many ils -- ignore attr after whitespace+ else+ let (pos1, pos2) =+ case pos of+ NoPos -> (NoPos, NoPos)+ Pos sl sc el ec ->+ let frontlen = B8.length+ (B8.filter (\c -> c < '\128' || c >= '\192') front)+ in (Pos sl sc sl (sc + frontlen),+ Pos sl (sc + frontlen + 1) el ec)+ in Many (ils' Seq.|>+ Node pos1 attr' (Str front) Seq.|>+ Node pos2 attr (Str lastword))+ ils' Seq.:> Node pos attr' il ->+ Many (ils' Seq.|> Node pos (attr' <> attr) il)++pInline' :: P Inlines+pInline' = do+ (do c <- lookahead (satisfyByte isSpecial)+ fails pCloser+ (case c of+ '\\' -> pEscaped+ '[' -> pFootnoteReference+ <|> pLinkOrSpan+ '<' -> pAutolink+ '!' -> pImage+ '_' -> pEmph+ '*' -> pStrong+ '^' -> pSuperscript+ '~' -> pSubscript+ '{' -> pEmph+ <|> pStrong+ <|> pHighlight+ <|> pInsert+ <|> pDelete+ <|> pSuperscript+ <|> pSubscript+ <|> pDoubleQuote+ <|> pSingleQuote+ <|> (mempty <$ pAttributes)+ '`' -> pVerbatim+ ':' -> pSymbol+ '$' -> pMath+ '"' -> pDoubleQuote+ '\'' -> pSingleQuote+ '-' -> pHyphens+ '.' -> pEllipses+ '\n' -> pSoftBreak+ _ -> mzero)+ <|> pSpecial+ ) <|> pWords++pSpecial :: P Inlines+pSpecial = do+ st <- getState+ c <- satisfyByte (case mode st of+ TableCellMode -> \d -> isSpecial d && d /= '|'+ _ -> isSpecial)+ if c == '\r'+ then pure mempty+ else pure $ str $ B8.singleton c++pWords :: P Inlines+pWords = str <$> byteStringOf (skipSome (skipSatisfyByte (not . isSpecial)))++pEscaped :: P Inlines+pEscaped = do+ asciiChar '\\'+ c <- satisfyByte (\d ->+ isAscii d &&+ (isSymbol d || isPunctuation d || d == ' ' || d == '\t'))+ <|> ('\n' <$ endline)+ <|> pure '\\'+ case c of+ '\n' -> hardBreak <$ skipMany spaceOrTab+ _ | c == ' ' || c == '\t' -> pHardBreak+ <|> if c == ' '+ then pure nonBreakingSpace+ else pure $ str "\\\t"+ _ -> pure $ str $ B8.singleton c++pHardBreak :: P Inlines+pHardBreak = do -- assumes we've parsed \ already+ skipMany spaceOrTab+ endline+ skipMany spaceOrTab+ pure hardBreak++pSoftBreak :: P Inlines+pSoftBreak = do+ endline+ skipMany spaceOrTab+ (mempty <$ eof) <|> pure softBreak++pSymbol :: P Inlines+pSymbol = do+ asciiChar ':'+ bs <- byteStringOf $ skipSome (skipSatisfyByte+ (\c -> c == '+' || c == '-' ||+ (isAscii c && isAlphaNum c)))+ asciiChar ':'+ pure $ symbol bs++pMath :: P Inlines+pMath = do+ asciiChar '$'+ mathStyle <- (DisplayMath <$ asciiChar '$') <|> pure InlineMath+ verb <- pVerbatim+ case unMany verb of+ [Node pos attr (Verbatim bs)] ->+ pure $ Many $ Seq.singleton $ Node pos attr (Math mathStyle bs)+ _ -> pure $ (case mathStyle of+ DisplayMath -> str "$$"+ _ -> str "$") <> verb++{-# INLINE bracesRequired #-}+bracesRequired :: Char -> Bool+bracesRequired '=' = True+bracesRequired '+' = True+bracesRequired '-' = True+bracesRequired _ = False++pCloser :: P ()+pCloser = do+ delims <- activeDelims <$> getState+ if Set.null delims+ then mzero+ else do+ openerHadBrace <- asum $+ map (\(Delim hadBrace c) -> hadBrace <$ asciiChar c) (F.toList delims)+ mblastc <- peekBack+ let afterws = maybe True isWs mblastc+ when ( afterws || openerHadBrace ) $ asciiChar '}'++pEmph, pStrong, pSuperscript, pSubscript :: P Inlines+pEmph = pBetween '_' emph+pStrong = pBetween '*' strong+pSuperscript = pBetween '^' superscript+pSubscript = pBetween '~' subscript++pHighlight, pInsert, pDelete :: P Inlines+pHighlight = pBetween '=' highlight+pInsert = pBetween '+' insert+pDelete = pBetween '-' delete++pBetween :: Char -> (Inlines -> Inlines) -> P Inlines+pBetween c constructor = do+ let starter leftBrace = do+ case leftBrace of+ False+ | bracesRequired c -> mzero+ | otherwise -> asciiChar c `notFollowedBy`+ (ws <|> asciiChar '}')+ True -> asciiChar c `notFollowedBy` asciiChar '}'+ let ender leftBrace = do+ mblastc <- peekBack+ let afterws = maybe True isWs mblastc+ asciiChar c+ if leftBrace+ then asciiChar '}'+ else guard (not afterws) `notFollowedBy` asciiChar '}'+ leftBrace <- (True <$ asciiChar '{') <|> pure False+ starterBs <- (if leftBrace then ("{" <>) else id) <$>+ byteStringOf (starter leftBrace) `notFollowedBy` pAttributes+ -- don't let *{.foo} start emphasis, for example+ oldActiveDelims <- activeDelims <$> getState+ updateState $ \st -> st{ activeDelims = Set.insert (Delim leftBrace c)+ (activeDelims st) }+ firstIl <- pInline <|> pBetween c constructor -- to allow stacked cases like '**hi**'+ restIls <- many pInline+ let ils = mconcat (firstIl:restIls)+ updateState $ \st -> st{ activeDelims = oldActiveDelims }+ (constructor ils <$ ender leftBrace) <|> pure (str starterBs <> ils)++pTicks :: P Int+pTicks = do+ sp <- getOffset+ skipSome (asciiChar '`')+ ep <- getOffset+ pure (ep - sp)++pVerbatim :: P Inlines+pVerbatim = do+ numticks <- pTicks+ let ender = pTicks >>= guard . (== numticks)+ let content = skipSome (skipSatisfyByte (\c -> c /= '`' && c /= '\\')) <|>+ (asciiChar '\\' <* anyChar) <|>+ (fails ender *> skipSome (asciiChar '`'))+ bs <- trimSpaces <$> byteStringOf (skipMany content) <* (ender <|> eof)+ (rawInline <$> pRawAttribute <*> pure bs) <|> pure (verbatim bs)++-- Trim a leading space if first non-space character is `,+-- and similarly for trailing space/last non-space.+trimSpaces :: ByteString -> ByteString+trimSpaces = trimSpaceFront . trimSpaceBack+ where+ trimSpaceFront bs =+ case B8.span (== ' ') bs of+ (a, b) | B8.take 1 b == "`"+ , not (B8.null a)+ -> B8.drop 1 bs+ _ -> bs+ trimSpaceBack bs =+ case B8.spanEnd (== ' ') bs of+ (a, b) | B8.takeEnd 1 a == "`"+ , not (B8.null b)+ -> B8.dropEnd 1 bs+ _ -> bs++pRawAttribute :: P Format+pRawAttribute = do+ byteString "{="+ fmt <- Format <$>+ byteStringOf (skipMany (skipSatisfyByte (\c -> c /= '}' &&+ not (isWs c))))+ asciiChar '}'+ pure fmt++pFootnoteReference :: P Inlines+pFootnoteReference = do+ asciiChar '['+ asciiChar '^'+ label <- byteStringOf $ skipMany $+ skipSatisfyByte (\c -> c /= ']' && not (isWs c))+ asciiChar ']'+ pure $ footnoteReference label++-- returns Left with parsed content if no ] has been reached, otherwise Right+-- with inner contents.+pBracketed :: P (Either Inlines Inlines)+pBracketed = do+ let starter = asciiChar '['+ let ender = asciiChar ']'+ starterBs <- byteStringOf starter+ oldActiveDelims <- activeDelims <$> getState+ updateState $ \st -> st{ activeDelims = Set.insert (Delim False ']') (activeDelims st) }+ ils <- mconcat <$> many pInline+ updateState $ \st -> st{ activeDelims = oldActiveDelims }+ (Right ils <$ ender) <|> pure (Left (str starterBs <> ils))++pImage :: P Inlines+pImage = do+ asciiChar '!'+ (res, raw) <- withByteString pBracketed+ case res of+ Left ils -> pure (str "!" <> ils)+ Right ils ->+ ((str "!" <>) <$> pAddAttributes (span_ ils))+ <|> (image ils <$> (pDestination <|> pReference raw))+ <|> pure (str "![" <> ils <> str "]")++pAutolink :: P Inlines+pAutolink = do+ asciiChar '<'+ res <- byteStringOf $ skipSome $ skipSatisfyByte (\c -> c /= '>' && c /= '<')+ asciiChar '>'+ let url = B8.filter (\c -> c /= '\n' && c /= '\r') res+ case B8.find (\c -> c == '@' || c == ':' || c == '.') url of+ Just '@' -> pure $ emailLink url+ Just _ -> pure $ urlLink url+ Nothing -> mzero++pLinkOrSpan :: P Inlines+pLinkOrSpan = do+ (res, raw) <- withByteString pBracketed+ case res of+ Left ils -> pure ils+ Right ils ->+ (span_ ils <$ lookahead (asciiChar '{'))+ <|> (link ils <$> (pDestination <|> pReference raw))+ <|> pure (str "[" <> ils <> str "]")++-- We allow balanced pairs of parens inside.+pDestination :: P Target+pDestination = do+ asciiChar '('+ res <- byteStringOf $ pInBalancedParens 0+ asciiChar ')'+ pure $ Direct (snd (handleEscapesAndNewlines res))+ where+ handleEscapesAndNewlines = B8.foldl' go (False, mempty)+ go (esc, bs) '\n' = (esc, bs)+ go (esc, bs) '\r' = (esc, bs)+ go (True, bs) c = (False, bs `B8.snoc` c)+ go (False, bs) '\\' = (True, bs)+ go (False, bs) c = (False, bs `B8.snoc` c)++pInBalancedParens :: Int -> P ()+pInBalancedParens nestlevel =+ (guard (nestlevel == 0) <* lookahead (asciiChar ')')) <|>+ do lev <- (nestlevel <$ (fails pCloser *>+ -- but see https://github.com/jgm/djot/discussions/247+ skipSatisfyByte+ (\c -> c /= '(' && c /= ')' && c /= '\\')))+ <|> (nestlevel <$ (asciiChar '\\' <* anyChar))+ <|> ((nestlevel + 1) <$ asciiChar '(')+ <|> ((nestlevel - 1) <$ asciiChar ')')+ pInBalancedParens lev++pReference :: ByteString -> P Target+pReference rawDescription = do+ asciiChar '['+ bs <- byteStringOf $ pAtMost 400 $ skipSatisfyByte+ (\c -> c /= '[' && c /= ']')+ asciiChar ']'+ let label = normalizeLabel $+ if B.null bs+ then B.drop 1 $ B.dropEnd 1+ $ B8.filter (/= '\n') rawDescription+ else bs+ pure $ Reference label++pAtMost :: Int -> P () -> P ()+pAtMost n pa = optional_ (pa *> when (n > 0) (pAtMost ( n - 1 ) pa))++pOpenDoubleQuote :: P ()+pOpenDoubleQuote = do+ lbrace <- (True <$ asciiChar '{') <|> pure False+ asciiChar '"'+ rbrace <- (True <$ asciiChar '}') <|> pure False+ guard $ lbrace || not rbrace++pCloseDoubleQuote :: P ()+pCloseDoubleQuote = do+ mblastc <- peekBack+ let whitespaceBefore = maybe True isWs mblastc+ lbrace <- (True <$ asciiChar '{') <|> pure False+ asciiChar '"'+ rbrace <- (True <$ asciiChar '}') <|> pure False+ whitespaceAfter <- (True <$ lookahead (skipSatisfyByte isWs)) <|> pure False+ guard $ not lbrace && (rbrace || not whitespaceBefore || whitespaceAfter)++pDoubleQuote :: P Inlines+pDoubleQuote = (do+ pOpenDoubleQuote+ contents <- mconcat <$> many (fails pCloseDoubleQuote *> pInline)+ (doubleQuoted contents <$ pCloseDoubleQuote)+ <|> pure (openDoubleQuote <> contents))+ <|> (closeDoubleQuote <$ asciiChar '"')++openDoubleQuote, closeDoubleQuote :: Inlines+openDoubleQuote = str "\226\128\156" -- utf8 0x201C+closeDoubleQuote = str "\226\128\157" -- utf8 0x201D++pOpenSingleQuote :: P ()+pOpenSingleQuote = do+ lastc <- fromMaybe '\n' <$> peekBack+ let openContext = lastc == '\t' || lastc == '\r' ||+ lastc == '\n' || lastc == ' ' ||+ lastc == '"' || lastc == '\'' ||+ lastc == '(' || lastc == '[' || lastc == '\0'+ lbrace <- (True <$ asciiChar '{') <|> pure False+ asciiChar '\''+ rbrace <- (True <$ asciiChar '}') <|> pure False+ guard $ lbrace || (openContext && not rbrace)++pCloseSingleQuote :: P ()+pCloseSingleQuote = do+ mblastc <- peekBack+ let whitespaceBefore = maybe True isWs mblastc+ lbrace <- (True <$ asciiChar '{') <|> pure False+ asciiChar '\''+ rbrace <- (True <$ asciiChar '}') <|> pure False+ letterAfter <- (True <$ lookahead (satisfy isLetter)) <|> pure False+ guard $ not lbrace && (rbrace || not (whitespaceBefore || letterAfter))++pSingleQuote :: P Inlines+pSingleQuote = (do+ pOpenSingleQuote+ contents <- mconcat <$> many (fails pCloseSingleQuote *> pInline)+ (singleQuoted contents <$ pCloseSingleQuote)+ <|> pure (closeSingleQuote <> contents))+ <|> (closeSingleQuote <$ asciiChar '\'')++closeSingleQuote :: Inlines+closeSingleQuote = str "\226\128\153" -- utf8 0x2019++pHyphens :: P Inlines+pHyphens = do+ numHyphens <- length <$> some hyphen+ pure $ str $ go numHyphens+ where+ emdash = "\226\128\148" -- utf8 0x2014+ endash = "\226\128\147" -- utf8 0x2013+ hyphen = asciiChar '-' `notFollowedBy` asciiChar '}'+ go 1 = "-"+ go n | n `mod` 3 == 0+ = mconcat (replicate (n `Prelude.div` 3) emdash)+ | n `mod` 2 == 0+ = mconcat (replicate (n `Prelude.div` 2) endash)+ | n `mod` 3 == 2+ = mconcat (replicate (n `Prelude.div` 3) emdash) <> endash+ | n `mod` 3 == 1+ = mconcat (replicate (n `Prelude.div` 3 - 1) emdash) <>+ endash <> endash+ | otherwise+ = emdash <> go (n - 3)++pEllipses :: P Inlines+pEllipses = str "\226\128\166" {- utf8 0x2026 -} <$ byteString "..."++stripEndChunks :: Seq Chunk -> Seq Chunk+stripEndChunks cs =+ case Seq.viewr cs of+ initial Seq.:> c ->+ initial Seq.|> c{ chunkBytes = B8.dropWhileEnd isWs (chunkBytes c) }+ _ -> cs
+ src/Djot/Options.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE StrictData #-}+module Djot.Options+( ParseOptions(..)+, RenderOptions(..)+, SourcePosOption(..) )+where++newtype ParseOptions =+ ParseOptions+ { sourcePositions :: SourcePosOption -- ^ Add attributes for source lines+ }+ deriving (Show)++newtype RenderOptions =+ RenderOptions+ { preserveSoftBreaks :: Bool -- ^ Preserve soft breaks as in the source+ }+ deriving (Show)++-- | Adding source positions for blocks adds almost no overhead to parsing.+-- Adding source positions for inlines has a small penalty. For many purposes+-- it is enough to have source lines for blocks, so we offer the option.+data SourcePosOption =+ NoSourcePos | BlockSourcePos | AllSourcePos+ deriving (Show, Eq, Ord)
+ src/Djot/Parse.hs view
@@ -0,0 +1,400 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BinaryLiterals #-}+module Djot.Parse+( Parser+ , Chunk(..)+ , parse+ , asciiChar+ , satisfyByte+ , skipSatisfyByte+ , satisfy+ , anyChar+ , skipMany+ , skipSome+ , eof+ , getState+ , updateState+ , lookahead+ , peek+ , peekBack+ , fails+ , failed+ , withByteString+ , byteStringOf+ , notFollowedBy+ , optional_+ , byteString+ , getOffset+ , sourceLine+ , sourceColumn+ , branch+ , endline+ , restOfLine+ , ws+ , followedByWhitespace+ , followedByBlankLine+ , spaceOrTab+ , isWs+ , strToUtf8+ , utf8ToStr+)+where++import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import Data.ByteString (ByteString)+import Control.Applicative+import Control.Monad (void, MonadPlus(..))+import Data.Char (chr)+import Data.Bits+import Data.Maybe (fromMaybe)+import Data.Text.Encoding (decodeUtf8With, encodeUtf8)+import Data.Text.Encoding.Error (lenientDecode)+import qualified Data.Text as T+-- import Text.Printf+-- import Debug.Trace++newtype Parser s a =+ Parser{ runParser :: ParserState s -> Maybe (ParserState s, a) }++instance Functor (Parser s) where+ fmap f g = Parser $ \s -> case runParser g s of+ Nothing -> Nothing+ Just (s', !x) -> Just (s', f x)++instance Applicative (Parser s) where+ pure x = Parser (\s -> Just (s, x))+ liftA2 f g h = Parser $ \s ->+ case runParser g s of+ Nothing -> Nothing+ Just (s', x) ->+ case runParser h s' of+ Nothing -> Nothing+ Just (s'', y) -> Just (s'', f x y)++instance Monad (Parser s) where+ return = pure+ f >>= g = Parser $ \s ->+ case runParser f s of+ Nothing -> Nothing+ Just (s', x) -> runParser (g x) s'++instance Alternative (Parser s) where+ empty = Parser (const Nothing)+ f <|> g = Parser $ \s ->+ case runParser f s of+ Just (s', x) -> Just (s', x)+ Nothing -> runParser g s++instance MonadPlus (Parser s) where+ mzero = empty+ mplus = (<|>)++data Chunk =+ Chunk{ chunkLine :: Int+ , chunkColumn :: Int+ , chunkBytes :: ByteString }+ deriving (Show, Eq, Ord)+++data ParserState a =+ ParserState+ { chunks :: [Chunk]+ , subject :: !ByteString+ , offset :: !Int+ , line :: !Int+ , column :: !Int+ , userState :: !a+ }+ deriving (Show)++-- | Apply a parser to a bytestring with a given user state.+-- Returns @Nothing@ on failure, @Just result@ on success.+parse :: Parser s a -> s -> [Chunk] -> Maybe a+parse parser ustate chunks'' =+ snd <$>+ runParser parser ParserState { chunks = chunks'+ , subject = bs+ , offset = 0+ , line = startline+ , column = startcol+ , userState = ustate }++ where+ (chunks', bs, startline, startcol) =+ case chunks'' of+ [] -> ([], mempty, 1, 0)+ (c:cs) -> (cs, chunkBytes c, chunkLine c, chunkColumn c)++-- | Given a number of bytes, advances the offset and updates line/column.+unsafeAdvance :: Int -> ParserState s -> ParserState s+unsafeAdvance 0 = id+unsafeAdvance !n = unsafeAdvance (n - 1) . unsafeAdvanceByte++-- | Advance the offset and line/column for consuming a given byte.+unsafeAdvanceByte :: ParserState s -> ParserState s+unsafeAdvanceByte st+ | offset st + 1 >= B.length (subject st)+ , c:cs <- chunks st+ = st{ chunks = cs+ , subject = chunkBytes c+ , offset = 0+ , line = chunkLine c+ , column = chunkColumn c }+ | otherwise+ = case B.index (subject st) (offset st) of+ 10 -> st{ offset = offset st + 1+ , line = line st + 1+ , column = 1 }+ 9 -> st{ offset = offset st + 1+ , column = column st + (4 - (column st `mod` 4)) }+ !w | w < 0x80 -> st{ offset = offset st + 1+ , column = column st + 1 }+ -- utf8 multibyte: only count byte 1:+ | w >= 0b11000000 -> st{ offset = offset st + 1+ , column = column st + 1 }+ | otherwise -> st{ offset = offset st + 1 }++-- | Returns current byte as Char.+current :: ParserState s -> Maybe Char+current st = subject st B8.!? offset st++-- | Returns current byte as Char.+peek :: Parser s (Maybe Char)+peek = Parser $ \st -> Just (st, current st)++-- | Returns previous byte as Char. Doesn't cross chunk boundaries.+peekBack :: Parser s (Maybe Char)+peekBack = Parser $ \st -> Just (st, subject st B8.!? (offset st - 1))++-- | Parse a byte satisfying a predicate.+satisfyByte :: (Char -> Bool) -> Parser s Char+satisfyByte f = Parser $ \st ->+ case current st of+ Just c | f c -> Just (unsafeAdvanceByte st, c)+ _ -> Nothing++-- | Skip byte satisfying a predicate.+skipSatisfyByte :: (Char -> Bool) -> Parser s ()+skipSatisfyByte f = Parser $ \st ->+ case current st of+ Just c | f c -> Just (unsafeAdvanceByte st, ())+ _ -> Nothing++-- | Parse a (possibly multibyte) Char satisfying a predicate.+-- Assumes UTF-8 encoding.+satisfy :: (Char -> Bool) -> Parser s Char+satisfy f = Parser $ \st ->+ let peekWord !n = subject st B.!? (offset st + n)+ b2 = fromMaybe 0 $ peekWord 1+ b3 = fromMaybe 0 $ peekWord 2+ b4 = fromMaybe 0 $ peekWord 3+ in case peekWord 0 of+ Nothing -> Nothing+ Just b1+ | b1 < 0b10000000+ , !c <- chr (fromIntegral b1)+ , f c -> Just (unsafeAdvanceByte st, c)+ | b1 .&. 0b11100000 == 0b11000000+ , b2 >= 0b10000000+ , !c <- chr (toCodePoint2 b1 b2)+ , f c -> Just (unsafeAdvance 2 st, c)+ | b1 .&. 0b11110000 == 0b11100000+ , b2 >= 0b10000000+ , b3 >= 0b10000000+ , !c <- chr (toCodePoint3 b1 b2 b3)+ , f c -> Just (unsafeAdvance 3 st, c)+ | b1 .&. 0b11111000 == 0b11110000+ , b2 >= 0b10000000+ , b3 >= 0b10000000+ , b4 >= 0b10000000+ , !c <- chr (toCodePoint4 b1 b2 b3 b4)+ , f c -> Just (unsafeAdvance 4 st, c)+ | otherwise -> Nothing+ where+ toCodePoint2 a b =+ (fromIntegral (a .&. 0b00011111) `shiftL` 6) ++ fromIntegral (b .&. 0b00111111)+ toCodePoint3 a b c =+ (fromIntegral (a .&. 0b00001111) `shiftL` 12) ++ (fromIntegral (b .&. 0b00111111) `shiftL` 6) ++ fromIntegral (c .&. 0b00111111)+ toCodePoint4 a b c d =+ (fromIntegral (a .&. 0b00000111) `shiftL` 18) ++ (fromIntegral (b .&. 0b00111111) `shiftL` 12) ++ (fromIntegral (c .&. 0b00111111) `shiftL` 6) ++ fromIntegral (d .&. 0b00111111)++-- | Parse any character. Assumes UTF-8 encoding.+anyChar :: Parser s Char+anyChar = satisfy (const True)++-- | Parse an ASCII character.+asciiChar :: Char -> Parser s ()+asciiChar !c = Parser $ \st ->+ case current st of+ Just d | d == c -> Just (unsafeAdvanceByte st, ())+ _ -> Nothing++-- | Apply parser 0 or more times, discarding result.+skipMany :: Parser s a -> Parser s ()+skipMany parser = Parser go+ where+ go st = case runParser parser st of+ Nothing -> Just (st, ())+ Just (st',_) -> go st'++-- | Apply parser 1 or more times, discarding result.+skipSome :: Parser s a -> Parser s ()+skipSome parser = parser *> skipMany parser++-- | Succeeds if no more input.+eof :: Parser s ()+eof = Parser $ \st ->+ case current st of+ Nothing -> Just (st, ())+ Just _ -> Nothing++-- | Returns current user state.+getState :: Parser s s+getState = Parser $ \st -> Just (st, userState st)++-- | Updates user state.+updateState :: (s -> s) -> Parser s ()+updateState f = Parser $ \st ->+ Just (st{ userState = f (userState st) }, ())++-- | Apply a parser, returning its result but not changing state+-- or advancing.+lookahead :: Parser s a -> Parser s a+lookahead pa = Parser $ \st ->+ case runParser pa st of+ Just (_, x) -> Just (st, x)+ Nothing -> Nothing++-- | Succeeds if parser fails.+fails :: Parser s a -> Parser s ()+fails pa = Parser $ \st ->+ case runParser pa st of+ Just _ -> Nothing+ Nothing -> Just (st, ())++-- | Always fails.+failed :: Parser s a+failed = Parser $ const Nothing++-- | Returns result of parse together with the bytestring+-- consumed.+withByteString :: Parser s a -> Parser s (a, ByteString)+withByteString pa = Parser $ \st ->+ case runParser pa st of+ Just (st', x) -> Just (st', (x, B8.take (offset st' - offset st)+ (B8.drop (offset st) (subject st))))+ Nothing -> Nothing++-- | Returns bytestring consumed by parse.+byteStringOf :: Parser s a -> Parser s ByteString+byteStringOf pa = Parser $ \st ->+ case runParser pa st of+ Just (st', _) -> Just (st',+ case length (chunks st) - length (chunks st') of+ 0 -> B8.take (offset st' - offset st) (B8.drop (offset st) (subject st))+ n ->+ B8.drop (offset st) (subject st) <>+ foldMap chunkBytes (take (n - 1) (chunks st)) <>+ B8.take (offset st') (subject st'))+ Nothing -> Nothing++-- | Succeeds if first parser succeeds and second fails, returning+-- first parser's value.+notFollowedBy :: Parser s a -> Parser s b -> Parser s a+notFollowedBy pa pb = pa <* fails pb++-- | Apply parser but still succeed if it doesn't succeed.+optional_ :: Parser s a -> Parser s ()+optional_ pa = void pa <|> pure ()++-- | Parse a bytestring.+byteString :: ByteString -> Parser s ()+byteString bs = Parser $ \st ->+ if bs `B8.isPrefixOf` B8.drop (offset st) (subject st)+ then Just (unsafeAdvance (B.length bs) st, ())+ else Nothing++-- | Returns byte offset in input.+getOffset :: Parser s Int+getOffset = Parser $ \st -> Just (st, offset st)++-- | Returns the line number.+sourceLine :: Parser s Int+sourceLine = Parser $ \st -> Just (st, line st)++-- | Returns the source column number. (Tab stop is computed at 4.)+sourceColumn :: Parser st Int+sourceColumn = Parser $ \st -> Just (st, column st)++-- | Try the first parser: if it succeeds, apply the second,+-- returning its result, otherwise the third.+branch :: Parser s b -> Parser s a -> Parser s a -> Parser s a+branch pa pb pc = Parser $ \st ->+ case runParser pa st of+ Just (st',_) -> runParser pb st'+ Nothing -> runParser pc st++-- | Parse an end of line sequence.+endline :: Parser s ()+endline = branch (asciiChar '\r') (optional_ (asciiChar '\n')) (asciiChar '\n')++-- | Return the rest of line (including the end of line).+restOfLine :: Parser s ByteString+restOfLine =+ byteStringOf $+ skipMany (skipSatisfyByte (\c -> c /= '\n' && c /= '\r'))+ <* optional_ endline++{-# INLINE isWs #-}+-- | Is space, tab, `\r`, or `\n`.+isWs :: Char -> Bool+isWs c = c == ' ' || c == '\t' || c == '\r' || c == '\n'++-- | Skip one space or tab.+spaceOrTab :: Parser s ()+spaceOrTab = Parser $ \st ->+ case current st of+ Just ' ' -> Just (unsafeAdvanceByte st, ())+ Just '\t' -> Just (unsafeAdvanceByte st, ())+ _ -> Nothing++-- | Skip 1 or more ASCII whitespace.+ws :: Parser s ()+ws = skipSome (satisfyByte isWs)++-- | Next character is ASCII whitespace.+followedByWhitespace :: Parser s ()+followedByWhitespace = Parser $ \st ->+ case current st of+ Just c | isWs c -> Just (st, ())+ _ -> Nothing++-- | Followed by 0 or more spaces/tabs and endline or eof.+followedByBlankLine :: Parser s ()+followedByBlankLine = Parser $ \st ->+ let subj = subject st+ !len = B8.length subj+ go !off+ | off >= len+ = Just (st, ())+ | otherwise+ = case B8.index subj off of+ ' ' -> go (off + 1)+ '\r' -> go (off + 1)+ '\t' -> go (off + 1)+ '\n' -> Just (st, ())+ _ -> Nothing+ in go (offset st)++strToUtf8 :: String -> ByteString+strToUtf8 = encodeUtf8 . T.pack++utf8ToStr :: ByteString -> String+utf8ToStr = T.unpack . decodeUtf8With lenientDecode
+ test/Main.hs view
@@ -0,0 +1,163 @@+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.HUnit+import qualified Data.Text.Lazy as TL+import Data.Text.Lazy.Encoding (decodeUtf8With, encodeUtf8)+import Data.Text.Encoding.Error (lenientDecode)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy.Char8 as BL+import Data.ByteString.Builder ( toLazyByteString )+import Djot ( ParseOptions(..), RenderOptions(..), SourcePosOption(..),+ parseDoc, renderHtml, renderDjot )+import Djot.Parse ( parse, satisfy, strToUtf8, utf8ToStr, Chunk(..) )+import Djot.AST+import System.FilePath ((</>), takeExtension, takeFileName)+import System.Directory (getDirectoryContents)+import Text.DocLayout (render)++main :: IO ()+main = do+ specTests <- filter ((== ".test") . takeExtension) <$>+ getDirectoryContents "test"+ tests <- mapM (\fp -> (fp,) <$> getSpecTests ("test" </> fp)) specTests+ let parser = parseDoc ParseOptions{ sourcePositions = NoSourcePos } . BL.toStrict+ defaultMain $ testGroup "Tests" $+ [ testGroup "djot -> html"+ (map (\(fp, ts) ->+ testGroup fp+ (map (toSpecTest parser) ts)) tests)+ , testGroup "native -> djot -> native"+ [testGroup fp (map (toRoundTripTest parser) ts)+ | (fp, ts) <- tests+ , takeFileName fp /= "raw.test"]+ , testGroup "Djot.Parse" parserTests+ , testGroup "sourcepos" sourcePosTests+ , testGroup "Fuzz"+ [testProperty "parses all inputs"+ (\s -> case parseDoc ParseOptions{ sourcePositions = NoSourcePos }+ (strToUtf8 s) of+ Left _ -> False+ Right _ -> True)+ ]+ ]++parserTests :: [TestTree]+parserTests =+ [ testCase "satisfy multibyte"+ (parse (satisfy (=='ǎ') *> satisfy (=='老')) ()+ (toChunks $ strToUtf8 "ǎ老bc") @?= Just '老')+ , testProperty "UTF8 conversion round-trips"+ (\s -> utf8ToStr (strToUtf8 s) == s)+ ]++sourcePosTests :: [TestTree]+sourcePosTests =+ let convert = either mempty (fromUtf8 . toLazyByteString .+ renderHtml RenderOptions{ preserveSoftBreaks = True })+ . parseDoc ParseOptions{ sourcePositions = AllSourcePos }+ in [ testCase "period at end" $+ convert "the `goo` option.\n" @?=+ "<p data-pos=\"1:1-1:17\"><span data-pos=\"1:1-1:4\">the </span><code data-pos=\"1:5-1:9\">goo</code><span data-pos=\"1:10-1:17\"> option.</span></p>\n"+ , testCase "attr after *" $+ convert "*{.foo}\n" @?=+ "<p data-pos=\"1:1-1:7\"><span data-pos=\"1:1-1:1\" class=\"foo\">*</span></p>\n"+ , testCase "no newline at end" $+ convert "foo" @?=+ "<p data-pos=\"1:1-1:3\"><span data-pos=\"1:1-1:3\">foo</span></p>\n"+ , testCase "list" $+ convert "1. > hello\nthere\n\n2. ok" @?=+ "<ol data-pos=\"1:1-4:6\">\n<li>\n<blockquote data-pos=\"1:4-2:5\">\n<p data-pos=\"1:6-2:5\"><span data-pos=\"1:6-1:10\">hello</span>\n<span data-pos=\"2:1-2:5\">there</span></p>\n</blockquote>\n</li>\n<li>\n<p data-pos=\"4:5-4:6\"><span data-pos=\"4:5-4:6\">ok</span></p>\n</li>\n</ol>\n"+ , testCase "code block" $+ convert "``` ruby\nhi\n```\n" @?=+ "<pre data-pos=\"1:1-3:3\"><code class=\"language-ruby\">hi\n</code></pre>\n"+ , testCase "nested " $+ convert "*_hi_*" @?=+ "<p data-pos=\"1:1-1:6\"><strong data-pos=\"1:1-1:6\"><em data-pos=\"1:2-1:5\"><span data-pos=\"1:3-1:4\">hi</span></em></strong></p>\n"+ , testCase "hr " $+ convert "----\n" @?=+ "<hr data-pos=\"1:1-1:4\">\n"+ ]++toChunks :: B.ByteString -> [Chunk]+toChunks bs = [Chunk{ chunkBytes = bs, chunkLine = 1, chunkColumn = 0 }]++toSpecTest :: (BL.ByteString -> Either String Doc)+ -> SpecTest -> TestTree+toSpecTest parser st =+ testCase name (actual @?= expected)+ where name = "lines " ++ show (start_line st) ++ "-" ++ show (end_line st)+ expected = fromUtf8 $ html st+ ropts = RenderOptions{ preserveSoftBreaks = True }+ actual = either mempty (fromUtf8 . toLazyByteString . renderHtml ropts)+ . parser $ djot st++toRoundTripTest :: (BL.ByteString -> Either String Doc)+ -> SpecTest -> TestTree+toRoundTripTest parser st =+ testCase name ((actual == expected) @? rtlog)+ where name = "lines " ++ show (start_line st) ++ "-" ++ show (end_line st)+ native = either (\_ -> mempty) id $ parser (djot st)+ expected = native+ ropts = RenderOptions{ preserveSoftBreaks = True }+ renderedDjot = encodeUtf8 . TL.fromStrict $ render (Just 62) $+ renderDjot ropts native+ actual = either (\_ -> mempty) id $ parser renderedDjot+ lbsToStr = TL.unpack . fromUtf8+ rtlog = lbsToStr (djot st) <>+ "↓\n" <>+ show native <> "\n" <>+ "↓\n" <>+ lbsToStr renderedDjot <>+ "↓\n" <>+ show actual <> "\n"++data SpecTest = SpecTest+ { djot :: BL.ByteString+ , source :: FilePath+ , end_line :: Int+ , start_line :: Int+ , html :: BL.ByteString }+ deriving (Show)++getSpecTests :: FilePath -> IO [SpecTest]+getSpecTests fp = do+ speclines <- zip [1..] . BL.lines <$> BL.readFile fp+ pure $ parseSpecTests fp speclines++--- state machine parser for spec test cases++data ParseState =+ Scanning+ | ParsingDjot (SpecTest, BL.ByteString)+ | ParsingHtml (SpecTest, BL.ByteString)+ deriving (Show)++parseSpecTests :: FilePath -> [(Int, BL.ByteString)] -> [SpecTest]+parseSpecTests fp = go Scanning+ where+ go _ [] = []+ go Scanning ((ln, bs) : xs)+ | BL.length bs > 0 && BL.all (== '`') bs =+ go (ParsingDjot (SpecTest { djot = mempty+ , source = fp+ , end_line = ln+ , start_line = ln+ , html = mempty }, bs)) xs+ | otherwise = go Scanning xs+ go (ParsingDjot (st,fence)) ((_,bs) : xs)+ | bs == "." =+ go (ParsingHtml (st, fence)) xs+ | otherwise =+ go (ParsingDjot (st{ djot = djot st <> bs <> "\n" }, fence)) xs+ go (ParsingHtml (st,fence)) ((ln,bs) : xs)+ | bs == fence =+ st{ end_line = ln } : go Scanning xs+ | otherwise =+ go (ParsingHtml (st{ html = html st <> bs <> "\n" }, fence)) xs++fromUtf8 :: BL.ByteString -> TL.Text+fromUtf8 = decodeUtf8With lenientDecode
+ test/attributes.test view
@@ -0,0 +1,322 @@+An inline attribute attaches to the preceding element, which might+be complex (span, emphasis, link) or a simple word (defined as a+sequence of non-ASCII-whitespace characters).+```+foo привет{.ru}+.+<p>foo <span class="ru">привет</span></p>+```++```+(some text){.attr}+.+<p>(some <span class="attr">text)</span></p>+```++```+[some text]{.attr}+.+<p><span class="attr">some text</span></p>+```++Ensure that emphasis that starts before the attribute can still close,+even if the attribute contains a potential closer.++```+a *b{#id key="*"}*+.+<p>a <strong><span id="id" key="*">b</span></strong></p>+```++```+a *b{#id key="*"}o+.+<p>a <span id="id" key="*">*b</span>o</p>+```++Don't mind braces in quotes:++```+hi{key="{#hi"}+.+<p><span key="{#hi">hi</span></p>+```++Process escapes correctly:++```+hi{key="\\\\\*"}++{key="\\\\\*"}+foo+.+<p><span key="\\*">hi</span></p>+<p key="\\*">foo</p>+```++Don't allow attributes to start when we're parsing a potential+attribute.++```+hi\{key="abc{#hi}"+.+<p>hi{key=“<span id="hi">abc</span>”</p>+```++```+hi{key="\"#hi"}+.+<p><span key=""#hi">hi</span></p>+```++```+hi{key="hi\"#hi"}+.+<p><span key="hi"#hi">hi</span></p>+```++Line break:++```+hi{#id .class+key="value"}+.+<p><span id="id" class="class" key="value">hi</span></p>+```++Here there is nothing for the attribute to attach to:++```+{#id} at beginning+.+<p> at beginning</p>+```++```+After {#id} space+{.class}+.+<p>After space+</p>+```++Block attributes come before the block, on a line by themselves.++```+{#id .class}+A paragraph+.+<p id="id" class="class">A paragraph</p>+```++Use indentation if you need to continue the attributes over a line break.++```+{#id .class+ style="color:red"}+A paragraph+.+<p id="id" class="class" style="color:red">A paragraph</p>+```++If the attribute block can't be parsed as attributes, it will be+parsed as a regular paragraph:++```+{#id .cla*ss*+.+<p>{#id .cla<strong>ss</strong></p>+```++You can use consecutive attribute blocks.+In case of conflict, later values take precedence over earlier ones,+but classes accumulate:++```+{#id}+{key=val}+{.foo .bar}+{key=val2}+{.baz}+{#id2}+Okay+.+<p class="foo bar baz" key="val2" id="id2">Okay</p>+```++Attributes on different kinds of blocks:++```+{#id}+> Block quote+.+<blockquote id="id">+<p>Block quote</p>+</blockquote>+```++```+{#id}+# Heading+.+<section id="id">+<h1>Heading</h1>+</section>+```++```+{.blue}+- - - - -+.+<hr class="blue">+```++````+{highlight=3}+``` ruby+x = 3+```+.+<pre highlight="3"><code class="language-ruby">x = 3+</code></pre>+````++```+{.special}+1. one+2. two+.+<ol class="special">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+> {.foo}+> > {.bar}+> > nested+.+<blockquote>+<blockquote class="foo">+<p class="bar">nested</p>+</blockquote>+</blockquote>+```++Comments start at a `%` character+(not in quotes) and end with another `%` or+the end of the attribute (`}`).+These can be used to comment up an attribute+list or without any real attributes.++```+foo{#ident % this is a comment % .class}+.+<p><span id="ident" class="class">foo</span></p>+```++```+foo{#ident % this is a comment}+.+<p><span id="ident">foo</span></p>+```++In block-level comment, subsequent lines must+be indented, as with attributes:++```+{% This is a comment before a+ block-level item. %}+Paragraph.+.+<p>Paragraph.</p>+```++Inline attributes can be empty:++```+hi{}+.+<p>hi</p>+```++Block attributes can be empty:++```+{}+hi+.+<p>hi</p>+```++Non-attributes:++```+text{a=x++hello+.+<p>text{a=x</p>+<p>hello</p>+```++skip ```+skip {a=x+skip hello+skip .+skip <p>{a=x+skip hello</p>+skip ```++```+text{a=x+# non-heading+.+<p>text{a=x+# non-heading</p>+```++skip ```+skip {a=x+skip # non-heading+skip .+skip <p>{a=x+skip # non-heading</p>+skip ```++```+{a=" inline text+.+<p>{a=“ inline text</p>+```+++```+{+ attr="long+ value+ spanning+ multiple+ lines"+ }+> a+.+<blockquote attr="long value spanning multiple lines">+<p>a</p>+</blockquote>+```++```+> {key="bar+> a\$bim"}+> ou+.+<blockquote>+<p key="bar a$bim">ou</p>+</blockquote>+```
+ test/block_quote.test view
@@ -0,0 +1,154 @@+```+> Basic+> block _quote_.+.+<blockquote>+<p>Basic+block <em>quote</em>.</p>+</blockquote>+```++```+> Lazy+block _quote_.+.+<blockquote>+<p>Lazy+block <em>quote</em>.</p>+</blockquote>+```++```+> block+>+> quote+.+<blockquote>+<p>block</p>+<p>quote</p>+</blockquote>+```++```+> block++> quote+.+<blockquote>+<p>block</p>+</blockquote>+<blockquote>+<p>quote</p>+</blockquote>+```++```+> > > nested+.+<blockquote>+<blockquote>+<blockquote>+<p>nested</p>+</blockquote>+</blockquote>+</blockquote>+```++```+> > > nested+lazy+.+<blockquote>+<blockquote>+<blockquote>+<p>nested+lazy</p>+</blockquote>+</blockquote>+</blockquote>+```++```+> > > nested+> lazy+.+<blockquote>+<blockquote>+<blockquote>+<p>nested+lazy</p>+</blockquote>+</blockquote>+</blockquote>+```++```+> nested+>+> > more+.+<blockquote>+<p>nested</p>+<blockquote>+<p>more</p>+</blockquote>+</blockquote>+```++```+>not blockquote+.+<p>>not blockquote</p>+```++```+>> not blockquote+.+<p>>> not blockquote</p>+```++```+>+.+<blockquote>+</blockquote>+```++```+> # Heading+.+<blockquote>+<section id="Heading">+<h1>Heading</h1>+</section>+</blockquote>+```++```+> hi+>there+.+<blockquote>+<p>hi+>there</p>+</blockquote>+```++```+aaa+> bbb+.+<p>aaa+> bbb</p>+```++```+aaa++> bbb+.+<p>aaa</p>+<blockquote>+<p>bbb</p>+</blockquote>+```
+ test/code_blocks.test view
@@ -0,0 +1,65 @@+```+```+code+ block+```+.+<pre><code>code+ block+</code></pre>+```++````+``` python+x = y + 3+```+.+<pre><code class="language-python">x = y + 3+</code></pre>+````++````+ ``` python+ if true:+ x = 3+ ```+.+<pre><code class="language-python">if true:+ x = 3+</code></pre>+````++````+``` not a code block ```+.+<p><code> not a code block </code></p>+````++````+``` not a code block+.+<p><code> not a code block</code></p>+````++````+```+hi+```+```+two+```+.+<pre><code>hi+</code></pre>+<pre><code>two+</code></pre>+````++Empty code block:++````+```+```+.+<pre><code></code></pre>+````
+ test/definition_lists.test view
@@ -0,0 +1,95 @@+Definition lists are just like ordinary bullet lists, but with+`:` as the marker instead of `-`, `+`, or `*`. The first+paragraph of the list item is interpreted as the term, and+the rest as the definition.++```+: apple++ red fruit+: banana++ yellow fruit+.+<dl>+<dt>apple</dt>+<dd>+red fruit+</dd>+<dt>banana</dt>+<dd>+yellow fruit+</dd>+</dl>+```++Loose:++```+: apple++ red fruit++: banana++ yellow fruit+.+<dl>+<dt>apple</dt>+<dd>+<p>red fruit</p>+</dd>+<dt>banana</dt>+<dd>+<p>yellow fruit</p>+</dd>+</dl>+```++```+: apple+ fruit++ Paragraph one++ Paragraph two++ - sub+ - list++: orange+.+<dl>+<dt>apple+fruit</dt>+<dd>+<p>Paragraph one</p>+<p>Paragraph two</p>+<ul>+<li>+sub+</li>+<li>+list+</li>+</ul>+</dd>+<dt>orange</dt>+<dd>+</dd>+</dl>+```++````+: ```+ ok+ ```+.+<dl>+<dt></dt>+<dd>+<pre><code>ok+</code></pre>+</dd>+</dl>+````
+ test/emphasis.test view
@@ -0,0 +1,239 @@+```+*foo bar*+.+<p><strong>foo bar</strong></p>+```++```+a* foo bar*+.+<p>a* foo bar*</p>+```++```+*foo bar *+.+<p>*foo bar *</p>+```++Unicode spaces don't block emphasis.++```+* a *+.+<p><strong> a </strong></p>+```++Intraword:++```+foo*bar*baz+.+<p>foo<strong>bar</strong>baz</p>+```++```+_foo bar_+.+<p><em>foo bar</em></p>+```++```+_ foo bar_+.+<p>_ foo bar_</p>+```++```+_foo bar _+.+<p>_foo bar _</p>+```++Unicode spaces don't block emphasis.++```+_ a _+.+<p><em> a </em></p>+```++Intraword:++```+foo_bar_baz+.+<p>foo<em>bar</em>baz</p>+```++```+aa_"bb"_cc+.+<p>aa<em>“bb”</em>cc</p>+```++```+*foo_+.+<p>*foo_</p>+```++```+_foo*+.+<p>_foo*</p>+```++A line ending counts as whitespace:++```+_foo bar+_+.+<p>_foo bar+_</p>+```++So does a tab:++```+_ a_+.+<p>_ a_</p>+```++This one is different from commonmark:++```+_(_foo_)_+.+<p><em>(</em>foo<em>)</em></p>+```++But you can force the second `_` to be an opener+using the marker `{`.++```+_({_foo_})_+.+<p><em>(<em>foo</em>)</em></p>+```++Note that an explicitly marked opener can only be closed+by an explicitly marked closer, and a non-marked opener+can only be closed by a non-marked closer:++```+{_ x_ _} _x_}+.+<p><em> x_ </em> _x_}</p>+```+++```+_(*foo*)_+.+<p><em>(<strong>foo</strong>)</em></p>+```++Overlapping scopes (first to close wins):++```+_foo *bar_ baz*+.+<p><em>foo *bar</em> baz*</p>+```++Over line break:++```+_foo+bar_+.+<p><em>foo+bar</em></p>+```++Inline content allowed:++```+*foo [link](url) `*`*+.+<p><strong>foo <a href="url">link</a> <code>*</code></strong></p>+```++Can't emph an underscore:++```+___+.+<p>___</p>+```++Unless you escape it:++```+_\__+.+<p><em>_</em></p>+```++No empty emph:++```+__+.+<p>__</p>+```++```+_}b_+.+<p>_}b_</p>+```++```+_\}b_+.+<p><em>}b</em></p>+```++```+_ab\_c_+.+<p><em>ab_c</em></p>+```++```+*****a*****+.+<p><strong><strong><strong><strong><strong>a</strong></strong></strong></strong></strong></p>+```++```+_[bar_](url)+.+<p><em>[bar</em>](url)</p>+```++```+\_[bar_](url)+.+<p>_<a href="url">bar_</a></p>+```++Code takes precedence:++```+_`a_`b+.+<p>_<code>a_</code>b</p>+```++Autolinks take precedence:++```+_<http://example.com/a_b>+.+<p>_<a href="http://example.com/a_b">http://example.com/a_b</a></p>+```
+ test/escapes.test view
@@ -0,0 +1,54 @@+ASCII punctuation characters can be escaped:++```+\`\*\_\[\#+.+<p>`*_[#</p>+```++Non-ASCII punctuation characters can't be escaped:++```+\a\«+.+<p>\a\«</p>+```++An escaped newline is a hard break:++```+ab\+c+.+<p>ab<br>+c</p>+```++There can be spaces and tabs between the backslash and the newline:++```+ab\ +c+.+<p>ab<br>+c</p>+```++There can also be spaces and tabs before the backslash, which are ignored:++```+ab \ +c+.+<p>ab<br>+c</p>+```++An escaped space is a non-breaking space:++```+a\ b+.+<p>a b</p>+```+
+ test/fenced_divs.test view
@@ -0,0 +1,134 @@+Fenced divs are containers for sequences of blocks, to+which an attribute can be attached.++A fenced div begins with an opening fence: a line with+three or more consecutive `:` characters, followed optionally by+a class name and optionally whitespace.++It ends with a closing fence: a line beginning with three+or more consecutive `:` characters, followed by optional+whitespace and the end of the line. The number of `:` characters+in the closing fence must be at least the number in the opening fence.++If the end of the input (or enclosing block) is encountered+before a closing fence, the fenced div is implicitly closed.++```+:::::::::: foo+Hi++> A block quote.+:::::::::::+.+<div class="foo">+<p>Hi</p>+<blockquote>+<p>A block quote.</p>+</blockquote>+</div>+```++```+{#bar .foo}+:::+Hi++> A block quote.+:::::::::::::+.+<div id="bar" class="foo">+<p>Hi</p>+<blockquote>+<p>A block quote.</p>+</blockquote>+</div>+```++Fenced divs may be nested.++```+{#bar .foo}+::::+Hi++::: baz+> A block quote.+:::+::::+.+<div id="bar" class="foo">+<p>Hi</p>+<div class="baz">+<blockquote>+<p>A block quote.</p>+</blockquote>+</div>+</div>+```++A fenced div cannot interrupt a paragraph, without+an intervening blank line.++```+Paragraph text+::::+Hi+::::+.+<p>Paragraph text+::::+Hi+::::</p>+```++A fenced div need not have attributes or a class name.++```+::::+Hi+::::+.+<div>+<p>Hi</p>+</div>+```++The closing fence must be at least as long as the opening fence.++```+::::::::: foo+Hi+::::+.+<div class="foo">+<p>Hi+::::</p>+</div>+```++If the end of the input (or enclosing block) is encountered+before a closing fence, the fenced div is implicitly closed.++```+> :::: foo+> Hi+.+<blockquote>+<div class="foo">+<p>Hi</p>+</div>+</blockquote>+```++````+::: outer+```+:::+```+:::+.+<div class="outer">+<pre><code>:::+</code></pre>+</div>+````
+ test/footnotes.test view
@@ -0,0 +1,92 @@+````+test[^a] and another[^foo_bar].++[^a]: This is a note.++ Second paragraph.++[^foo_bar]:+ ```+ code+ ```++another ref to the first note[^a].+.+<p>test<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a> and another<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a>.</p>+<p>another ref to the first note<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>.</p>+<section role="doc-endnotes">+<hr>+<ol>+<li id="fn1">+<p>This is a note.</p>+<p>Second paragraph.<a href="#fnref1" role="doc-backlink">↩︎</a></p>+</li>+<li id="fn2">+<pre><code>code+</code></pre>+<p><a href="#fnref2" role="doc-backlink">↩︎</a></p>+</li>+</ol>+</section>+````++```+test[^nonexistent]++[^unused]: note++ more+.+<p>test<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>+<section role="doc-endnotes">+<hr>+<ol>+<li id="fn1">+<p><a href="#fnref1" role="doc-backlink">↩︎</a></p>+</li>+</ol>+</section>+```++```+[^a]+[^b]++[^b]:+.+<p><a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>+<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a></p>+<section role="doc-endnotes">+<hr>+<ol>+<li id="fn1">+<p><a href="#fnref1" role="doc-backlink">↩︎</a></p>+</li>+<li id="fn2">+<p><a href="#fnref2" role="doc-backlink">↩︎</a></p>+</li>+</ol>+</section>+```++Issue #37:++```+text[^footnote].++[^footnote]: very long footnote[^another-footnote]+[^another-footnote]: bla bla[^another-footnote]+.+<p>text<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>.</p>+<section role="doc-endnotes">+<hr>+<ol>+<li id="fn1">+<p>very long footnote<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a><a href="#fnref1" role="doc-backlink">↩︎</a></p>+</li>+<li id="fn2">+<p>bla bla<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a><a href="#fnref2" role="doc-backlink">↩︎</a></p>+</li>+</ol>+</section>+```
+ test/headings.test view
@@ -0,0 +1,182 @@+```+## Heading+.+<section id="Heading">+<h2>Heading</h2>+</section>+```++```+# Heading++# another+.+<section id="Heading">+<h1>Heading</h1>+</section>+<section id="another">+<h1>another</h1>+</section>+```++```+# Heading+# continued+.+<section id="Heading-continued">+<h1>Heading+continued</h1>+</section>+```++```+##+heading++para+.+<section id="heading">+<h2>heading</h2>+<p>para</p>+</section>+```++```+##+.+<section id="sec">+<h2></h2>+</section>+```++```+## Heading+### Next level+.+<section id="Heading">+<h2>Heading</h2>+<section id="Next-level">+<h3>Next level</h3>+</section>+</section>+```++```+# Heading+lazy+.+<section id="Heading-lazy">+<h1>Heading+lazy</h1>+</section>+```++```+# Heading+lazy+# more+lazy++text+.+<section id="Heading-lazy-more-lazy">+<h1>Heading+lazy+more+lazy</h1>+<p>text</p>+</section>+```++```+##Notheading+.+<p>##Notheading</p>+```++```+ ## Heading+.+<section id="Heading">+<h2>Heading</h2>+</section>+```++```+## heading ##+.+<section id="heading">+<h2>heading ##</h2>+</section>+```++```+# # heading+.+<section id="heading">+<h1># heading</h1>+</section>+```++Auto-identifiers:++```+{#Foo-bar}+Paragraph++# Foo bar++## Foo bar++{#baz}+# Foo bar+.+<p id="Foo-bar">Paragraph</p>+<section id="Foo-bar-2">+<h1>Foo bar</h1>+<section id="Foo-bar-1">+<h2>Foo bar</h2>+</section>+</section>+<section id="baz">+<h1>Foo bar</h1>+</section>+```++Implicit header references:++```+See [Introduction][].++# Introduction+.+<p>See <a href="#Introduction">Introduction</a>.</p>+<section id="Introduction">+<h1>Introduction</h1>+</section>+```++```+See [Introduction][].++{#foo}+# Introduction+.+<p>See <a href="#foo">Introduction</a>.</p>+<section id="foo">+<h1>Introduction</h1>+</section>+```++```+See [Introduction][].++# Introduction++[Introduction]: #bar+.+<p>See <a href="#bar">Introduction</a>.</p>+<section id="Introduction">+<h1>Introduction</h1>+</section>+```
+ test/insert_delete_mark.test view
@@ -0,0 +1,29 @@+```+This is {-deleted+_text_-}. The braces are -required-.+And they must be in the -}right order{-.+.+<p>This is <del>deleted+<em>text</em></del>. The braces are -required-.+And they must be in the -}right order{-.</p>+```++```+{+ Inserted text +}+.+<p><ins> Inserted text </ins></p>+```++Interaction with smart:++```+{--hello--}+.+<p><del>-hello-</del></p>+```++```+This is {=marked *text*=}.+.+<p>This is <mark>marked <strong>text</strong></mark>.</p>+```
+ test/links_and_images.test view
@@ -0,0 +1,242 @@+```+[basic _link_][a_b_]++[a_b_]: url+.+<p><a href="url">basic <em>link</em></a></p>+```++```+![basic _image_][a_b_]++[a_b_]: url+.+<p><img alt="basic image" src="url"></p>+```++```+[link][]++[link]: url+.+<p><a href="url">link</a></p>+```++```+[link][]++[link]:+ url+.+<p><a href="url">link</a></p>+```++The URL can be split over multiple lines:++```+[link][]++[link]:+ url+ andurl+.+<p><a href="urlandurl">link</a></p>+```++```+[link](url+andurl)+.+<p><a href="urlandurl">link</a></p>+```++```+[link][]++[link]:+[link2]: url+.+<p><a href="">link</a></p>+```++```+[link][]+[link][link2]++[link2]:+ url2+[link]:+ url+.+<p><a href="url">link</a>+<a href="url2">link</a></p>+```++```+[link][a and+b]++[a and b]: url+.+<p><a href="url">link</a></p>+```++If the reference isn't found, we get an empty link.++```+[link][a and+b]+.+<p><a href="">link</a></p>+```++Reference definitions can't have line breaks in the key:++```+[link][a and+b]++[a and+b]: url+.+<p><a href="">link</a></p>+<p>[a and+b]: url</p>+```++No case normalization is done on reference definitions:++```+[Link][]++[link]: /url+.+<p><a href="">Link</a></p>+```++Attributes on reference definitions get transferred to+the link:++```+{title=foo}+[ref]: /url++[ref][]+.+<p><a href="/url" title="foo">ref</a></p>+```++Attributes on the link override those on references:++```+{title=foo}+[ref]: /url++[ref][]{title=bar}+.+<p><a href="/url" title="bar">ref</a></p>+```++```+[link _and_ link][]++[link _and_ link]: url+.+<p><a href="url">link <em>and</em> link</a></p>+```++```++.+<p><img alt="basic image" src="url"></p>+```++```+[](url)+.+<p><a href="url"><img alt="image" src="img.jpg"></a></p>+```++```+[unclosed](hello *a+b*+.+<p>[unclosed](hello <strong>a+b</strong></p>+```++Note that soft breaks are ignored, so long URLs+can be split over multiple lines:+```+[closed](hello *a+b*)+.+<p><a href="hello *ab*">closed</a></p>+```++Here the strong takes precedence over the link because it+starts first:+```+*[closed](hello*)+.+<p><strong>[closed](hello</strong>)</p>+```++Avoid this with a backslash escape:+```+*[closed](hello\*)+.+<p>*<a href="hello*">closed</a></p>+```++Link in link?+```+[[foo](bar)](baz)+.+<p><a href="baz"><a href="bar">foo</a></a></p>+```++Link in image?+```+](img)+.+<p><img alt="link" src="img"></p>+```++Image in link?+```+[](url)+.+<p><a href="url"><img alt="image" src="img"></a></p>+```++Autolinks:+```+<http://example.com/foo>+<me@example.com>+.+<p><a href="http://example.com/foo">http://example.com/foo</a>+<a href="mailto:me@example.com">me@example.com</a></p>+```++Openers inside `[..](` or `[..][` or `[..]{` can't match+outside them, even if the construction doesn't turn out to be+a link or span or image.++```+[x_y](x_y)+.+<p><a href="x_y">x_y</a></p>+```++```+[x_y](x_+.+<p>[x_y](x_</p>+```++```+[x_y]{.bar_}+.+<p><span class="bar_">x_y</span></p>+```
+ test/lists.test view
@@ -0,0 +1,510 @@+```+- one+- two+.+<ul>+<li>+one+</li>+<li>+two+</li>+</ul>+```++```+- one+ - two+ - three+.+<ul>+<li>+one+- two+- three+</li>+</ul>+```++```+- one++ - two++ - three+.+<ul>+<li>+one+<ul>+<li>+two+<ul>+<li>+three+</li>+</ul>+</li>+</ul>+</li>+</ul>+```++```+- one+ and++ another paragraph++ - a list++- two+.+<ul>+<li>+<p>one+and</p>+<p>another paragraph</p>+<ul>+<li>+a list+</li>+</ul>+</li>+<li>+<p>two</p>+</li>+</ul>+```++```+- one+lazy+- two+.+<ul>+<li>+one+lazy+</li>+<li>+two+</li>+</ul>+```++```+- a+- b++ c+.+<ul>+<li>+a+</li>+<li>+b+</li>+</ul>+<ul>+<li>+c+</li>+</ul>+```++```+- a++- b+.+<ul>+<li>+<p>a</p>+</li>+<li>+<p>b</p>+</li>+</ul>+```++```+- a+ - b++ - c+- d+.+<ul>+<li>+a+- b+<ul>+<li>+c+</li>+</ul>+</li>+<li>+d+</li>+</ul>+```++```+- a+ - b++ - c++- d+.+<ul>+<li>+a+- b+<ul>+<li>+c+</li>+</ul>+</li>+<li>+d+</li>+</ul>+```++```+- a++ b+- c+.+<ul>+<li>+<p>a</p>+<p>b</p>+</li>+<li>+<p>c</p>+</li>+</ul>+```++```+- a++ - b+ - c+- d+.+<ul>+<li>+a+<ul>+<li>+b+</li>+<li>+c+</li>+</ul>+</li>+<li>+d+</li>+</ul>+```++```+- a++ - b+ - c++- d+.+<ul>+<li>+a+<ul>+<li>+b+</li>+<li>+c+</li>+</ul>+</li>+<li>+d+</li>+</ul>+```++```+- a++ * b+cd+.+<ul>+<li>+a+<ul>+<li>+b+cd+</li>+</ul>+</li>+</ul>+```++```+- - - a+.+<ul>+<li>+<ul>+<li>+<ul>+<li>+a+</li>+</ul>+</li>+</ul>+</li>+</ul>+```++```+1. one+1. two+.+<ol>+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+1. one++ 1. two+.+<ol>+<li>+one+<ol>+<li>+two+</li>+</ol>+</li>+</ol>+```++```+4. one+5. two+.+<ol start="4">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+1) one+2) two+.+<ol>+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+(1) one+(2) two+.+<ol>+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+(a) one+(b) two+.+<ol type="a">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+(D) one+(E) two+.+<ol start="4" type="A">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+a. one+b. two+.+<ol type="a">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+i. one+ii. two+.+<ol type="i">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+xli) one+xlii) two+.+<ol start="41" type="i">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+(IV) one+(V) two+.+<ol start="4" type="I">+<li>+one+</li>+<li>+two+</li>+</ol>+```++```+i. a+ii. b+.+<ol type="i">+<li>+a+</li>+<li>+b+</li>+</ol>+```++```+i. a+j. b+.+<ol start="9" type="a">+<li>+a+</li>+<li>+b+</li>+</ol>+```++When ambiguous, prioritize roman numerals.++```+i. a+i. b+.+<ol type="i">+<li>+a+</li>+<li>+b+</li>+</ol>+```++```+I. a+II. b+E. d+.+<ol type="I">+<li>+a+</li>+<li>+b+</li>+</ol>+<ol start="5" type="A">+<li>+d+</li>+</ol>+```++```+The civil war ended in+1865. And this should not start a list.+.+<p>The civil war ended in+1865. And this should not start a list.</p>+```
+ test/math.test view
@@ -0,0 +1,44 @@+Math goes in verbatim spans prefixed with either `$` (for+inline math) or `$$` (for display math).++```+$`e=mc^2`+.+<p><span class="math inline">\(e=mc^2\)</span></p>+```++```+My equation: $`e=mc^2`+.+<p>My equation: <span class="math inline">\(e=mc^2\)</span></p>+```++```+$$`e=mc^2`+.+<p><span class="math display">\[e=mc^2\]</span></p>+```++```+My equation: $$`e=mc^2`+.+<p>My equation: <span class="math display">\[e=mc^2\]</span></p>+```++Newlines are allowed, just as in verbatim:++```+$`e=+mc^2`+.+<p><span class="math inline">\(e=+mc^2\)</span></p>+```++`$` characters are allowed inside:++```+$`e=\text{the number $\pi$}`+.+<p><span class="math inline">\(e=\text{the number $\pi$}\)</span></p>+```
+ test/para.test view
@@ -0,0 +1,7 @@+```+hi +there +.+<p>hi +there</p>+```
+ test/raw.test view
@@ -0,0 +1,38 @@+Raw inline content:++```+`<a>`{=html}+.+<p><a></p>+```++Raw block-level content:++````+``` =html+<table>+```+.+<table>+````++You can't mix regular attributes and raw syntax:++````+`<b>foo</b>`{=html #id}+```+.+<p><code><b>foo</b></code>{=html #id}+<code></code></p>+````++Attributes attached to raw content will just be ignored:++````+{.foo}+``` =html+<table>+```+.+<table>+````
+ test/regression.test view
@@ -0,0 +1,93 @@+Issue #104:++```+{1--}++{1-}+.+<p>{1--}</p>+<p>{1-}</p>+```++Issue #106:++```++|`|+.+<p>|<code>|</code></p>+```++```++|`|x+.+<p>|<code>|x</code></p>+```++Issue #127:++```+\$$`a`+.+<p>$<span class="math inline">\(a\)</span></p>+```++```+{+ .`+.+<p>{+.<code></code></p>+```++Issue #57:++```+| 1 | 2 |++ ^ cap1++ ^ cap2+.+<table>+<caption>cap2</caption>+<tr>+<td>1</td>+<td>2</td>+</tr>+</table>+```++Section start after list:++```+: term++ def++# New heading+.+<dl>+<dt>term</dt>+<dd>+def+</dd>+</dl>+<section id="New-heading">+<h1>New heading</h1>+</section>+```++Block quotes with markers unaligned:++```+> foo+ > bar+.+<blockquote>+<p>foo+bar</p>+</blockquote>+```+
+ test/smart.test view
@@ -0,0 +1,192 @@+Open quotes are matched with closed quotes.+The same method is used for matching openers and closers+as is used in emphasis parsing:++```+"Hello," said the spider.+"'Shelob' is my name."+.+<p>“Hello,” said the spider.+“‘Shelob’ is my name.”</p>+```++```+'A', 'B', and 'C' are letters.+.+<p>‘A’, ‘B’, and ‘C’ are letters.</p>+```++```+'Oak,' 'elm,' and 'beech' are names of trees.+So is 'pine.'+.+<p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees.+So is ‘pine.’</p>+```++```+'He said, "I want to go."'+.+<p>‘He said, “I want to go.”’</p>+```++A single quote that isn't an open quote matched+with a close quote will be treated as an+apostrophe:++```+Were you alive in the '70s?+.+<p>Were you alive in the ’70s?</p>+```++```+Here is some quoted '`code`' and a "[quoted link](url)".+.+<p>Here is some quoted ‘<code>code</code>’ and a “<a href="url">quoted link</a>”.</p>+```++Here the first `'` is treated as an apostrophe, not+an open quote, because the final single quote is matched+by the single quote before `jolly`:++```+'tis the season to be 'jolly'+.+<p>’tis the season to be ‘jolly’</p>+```++Multiple apostrophes should not be marked as open/closing quotes.++```+'We'll use Jane's boat and John's truck,' Jenna said.+.+<p>‘We’ll use Jane’s boat and John’s truck,’ Jenna said.</p>+```++An unmatched double quote will be interpreted as a+left double quote, to facilitate this style:++```+"A paragraph with no closing quote.++"Second paragraph by same speaker, in fiction."+.+<p>“A paragraph with no closing quote.</p>+<p>“Second paragraph by same speaker, in fiction.”</p>+```++A quote following a `]` or `)` character cannot+be an open quote:++```+[a]'s b'+.+<p>[a]’s b’</p>+```++Quotes that are escaped come out as literal straight+quotes:++```+\"This is not smart.\"+This isn\'t either.+5\'8\"+.+<p>"This is not smart."+This isn't either.+5'8"</p>+```++Doubled quotes are treated as nested:++```+''hi''+.+<p>‘‘hi’’</p>+```++Heuristics for determining openers and closers can+be overridden using `{` and `}`:++```+{''}hi{''}+.+<p>‘’hi‘’</p>+```++Two hyphens form an en-dash, three an em-dash.++```+Some dashes: em---em+en--en+em --- em+en -- en+2--3+.+<p>Some dashes: em—em+en–en+em — em+en – en+2–3</p>+```++A sequence of more than three hyphens is+parsed as a sequence of em and/or en dashes,+with no hyphens. If possible, a homogeneous+sequence of dashes is used (so, 10 hyphens+= 5 en dashes, and 9 hyphens = 3 em dashes).+When a heterogeneous sequence must be used,+the em dashes come first, followed by the en+dashes, and as few en dashes as possible are+used (so, 7 hyphens = 2 em dashes an 1 en+dash).++```+one-+two--+three---+four----+five-----+six------+seven-------+eight--------+nine---------+thirteen-------------.+.+<p>one-+two–+three—+four––+five—–+six——+seven—––+eight––––+nine———+thirteen———––.</p>+```++Hyphens can be escaped:++```+Escaped hyphens: \-- \-\-\-.+.+<p>Escaped hyphens: -- ---.</p>+```++Three periods form an ellipsis:++```+Ellipses...and...and....+.+<p>Ellipses…and…and….</p>+```++Periods can be escaped if ellipsis-formation+is not wanted:++```+No ellipses\.\.\.+.+<p>No ellipses...</p>+```
+ test/spans.test view
@@ -0,0 +1,19 @@+```+This is a [test of+*color*]{.blue}.+.+<p>This is a <span class="blue">test of+<strong>color</strong></span>.</p>+```++```+not a [span] {#id}.+.+<p>not a [span] .</p>+```++```+[nested [span]{.blue}]{#ident}+.+<p><span id="ident">nested <span class="blue">span</span></span></p>+```
+ test/super_subscript.test view
@@ -0,0 +1,23 @@+```+H~2~O+.+<p>H<sub>2</sub>O</p>+```++```+mc^2^+.+<p>mc<sup>2</sup></p>+```++```+test^of superscript ~with subscript~^+.+<p>test<sup>of superscript <sub>with subscript</sub></sup></p>+```++```+H{~2 ~}O+.+<p>H<sub>2 </sub>O</p>+```
+ test/symb.test view
@@ -0,0 +1,11 @@+```+:+1: :scream:+.+<p><span class="symbol">:+1:</span> <span class="symbol">:scream:</span></p>+```++```+:ice:scream:+.+<p><span class="symbol">:ice:</span>scream:</p>+```
+ test/tables.test view
@@ -0,0 +1,125 @@+Simplest table:++```+| a |+.+<table>+<tr>+<td>a</td>+</tr>+</table>+```++```+|a| *b*|+|*c| d* |+.+<table>+<tr>+<td>a</td>+<td><strong>b</strong></td>+</tr>+<tr>+<td>*c</td>+<td>d*</td>+</tr>+</table>+```++```+| `a |`+.+<p>| <code>a |</code></p>+```++```+| a | b |++^ With a _caption_+and another line.+.+<table>+<caption>With a <em>caption</em>+and another line.</caption>+<tr>+<td>a</td>+<td>b</td>+</tr>+</table>+```++Table headers: note that we can have multiple headers; each+determines the alignment for following cells, until the next header.++```+|a|b|+|:-|---:|+|c|d|+|cc|dd|+|-:|:-:|+|e|f|+|g|h|+.+<table>+<tr>+<th style="text-align: left;">a</th>+<th style="text-align: right;">b</th>+</tr>+<tr>+<td style="text-align: left;">c</td>+<td style="text-align: right;">d</td>+</tr>+<tr>+<th style="text-align: right;">cc</th>+<th style="text-align: center;">dd</th>+</tr>+<tr>+<td style="text-align: right;">e</td>+<td style="text-align: center;">f</td>+</tr>+<tr>+<td style="text-align: right;">g</td>+<td style="text-align: center;">h</td>+</tr>+</table>+```++```+|--|--|+.+<table>+</table>+```++```+|---|---|+| a | b |+.+<table>+<tr>+<td>a</td>+<td>b</td>+</tr>+</table>+```++```+| |+.+<table>+<tr>+<td></td>+</tr>+</table>+```++```+| just two \| `|` | cells in this table |+.+<table>+<tr>+<td>just two | <code>|</code></td>+<td>cells in this table</td>+</tr>+</table>+```
+ test/task_lists.test view
@@ -0,0 +1,31 @@+```+- [ ] an unchecked task list item+- [x] checked item+.+<ul class="task-list">+<li class="unchecked">+<label><input type="checkbox" />an unchecked task list item</label>+</li>+<li class="checked">+<label><input type="checkbox" checked="" />checked item</label>+</li>+</ul>+```++```+* [ ] an unchecked task list item++ with two paragraphs++* [x] checked item+.+<ul class="task-list">+<li class="unchecked">+<p><label><input type="checkbox" />an unchecked task list item</label></p>+<p>with two paragraphs</p>+</li>+<li class="checked">+<p><label><input type="checkbox" checked="" />checked item</label></p>+</li>+</ul>+```
+ test/thematic_breaks.test view
@@ -0,0 +1,45 @@+```+hello++- - -++there+.+<p>hello</p>+<hr>+<p>there</p>+```++```+hello++ ** **++there+.+<p>hello</p>+<hr>+<p>there</p>+```++```+hello++ *-*-*-*++there+.+<p>hello</p>+<hr>+<p>there</p>+```++```+hello+ *-*-*-*+there+.+<p>hello+<strong>-</strong>-<strong>-</strong>+there</p>+```
+ test/verbatim.test view
@@ -0,0 +1,47 @@+```+Some `code`+.+<p>Some <code>code</code></p>+```++```+Some `code+with a line break`+.+<p>Some <code>code+with a line break</code></p>+```++```+Special characters: `*hi*`+.+<p>Special characters: <code>*hi*</code></p>+```++```+*foo`*`+.+<p>*foo<code>*</code></p>+```++```````+`````a`a``a```a````a``````a`````+.+<p><code>a`a``a```a````a``````a</code></p>+```````++```+` ``a`` `+.+<p><code>``a``</code></p>+```++Implicitly closed by end of paragraph:++```+` a+c+.+<p><code> a+c</code></p>+```