aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml6
-rw-r--r--MANUAL.txt489
-rw-r--r--Makefile21
-rw-r--r--RELEASE-CHECKLIST14
-rw-r--r--appveyor.yml2
-rw-r--r--benchmark/benchmark-pandoc.hs9
-rw-r--r--changelog77
-rw-r--r--data/sample.lua10
-rw-r--r--doc/lua-filters.md9
-rw-r--r--linux/Dockerfile25
-rwxr-xr-xmacos/make_macos_package.sh2
-rw-r--r--man/pandoc.1675
-rw-r--r--pandoc.cabal47
-rw-r--r--src/Text/Pandoc/App.hs102
-rw-r--r--src/Text/Pandoc/Class.hs43
-rw-r--r--src/Text/Pandoc/Extensions.hs123
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse.hs32
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs24
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs2
-rw-r--r--src/Text/Pandoc/Readers/Org/Blocks.hs51
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs12
-rw-r--r--src/Text/Pandoc/Writers/FB2.hs11
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs7
-rw-r--r--src/Text/Pandoc/Writers/Powerpoint.hs3
-rw-r--r--stack.lts9.yaml29
-rw-r--r--stack.pkg.yaml16
-rw-r--r--stack.yaml12
-rw-r--r--test/Tests/Old.hs6
-rw-r--r--test/Tests/Readers/Docx.hs4
-rw-r--r--test/Tests/Readers/Org.hs1873
-rw-r--r--test/Tests/Readers/Org/Block.hs192
-rw-r--r--test/Tests/Readers/Org/Block/CodeBlock.hs194
-rw-r--r--test/Tests/Readers/Org/Block/Figure.hs57
-rw-r--r--test/Tests/Readers/Org/Block/Header.hs182
-rw-r--r--test/Tests/Readers/Org/Block/List.hs244
-rw-r--r--test/Tests/Readers/Org/Block/Table.hs150
-rw-r--r--test/Tests/Readers/Org/Directive.hs199
-rw-r--r--test/Tests/Readers/Org/Inline.hs516
-rw-r--r--test/Tests/Readers/Org/Inline/Note.hs87
-rw-r--r--test/Tests/Readers/Org/Inline/Smart.hs46
-rw-r--r--test/Tests/Readers/Org/Meta.hs173
-rw-r--r--test/Tests/Readers/Org/Shared.hs29
-rw-r--r--test/Tests/Writers/Powerpoint.hs101
-rw-r--r--test/command/4162.md10
-rw-r--r--test/command/4183.md32
-rw-r--r--test/command/4208.md18
-rw-r--r--test/docx/sdt_elements.docxbin0 -> 29409 bytes
-rw-r--r--test/docx/sdt_elements.native10
-rw-r--r--test/tables.custom201
-rw-r--r--test/tables.latex2
-rw-r--r--test/test-pandoc.hs2
-rw-r--r--test/writer.custom783
-rw-r--r--windows/make-windows-installer.bat2
53 files changed, 4418 insertions, 2548 deletions
diff --git a/.travis.yml b/.travis.yml
index 9c4177357..bb97802ac 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -61,6 +61,10 @@ matrix:
# The Stack builds. We can pass in arbitrary Stack arguments via the ARGS
# variable, such as using --stack-yaml to point to a different file.
+ # - env: BUILD=stack ARGS="--stack-yaml stack.lts9.yaml" OPTS="-Wall -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -fno-warn-unused-do-bind -Werror"
+ # compiler: ": #stack 8.0.2"
+ # addons: {apt: {packages: [ghc-8.0.2], sources: [hvr-ghc]}}
+
- env: BUILD=stack ARGS="--resolver lts-10" OPTS="-Wall -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -fno-warn-unused-do-bind -Werror"
compiler: ": #stack 8.2.2"
addons: {apt: {packages: [ghc-8.2.2], sources: [hvr-ghc]}}
@@ -107,6 +111,7 @@ install:
case "$BUILD" in
stack)
ulimit -n 4096
+ stack config set system-ghc --global true
stack --no-terminal --install-ghc $ARGS build --only-dependencies --fast --flag 'pandoc:embed_data_files' --flag 'aeson:fast' --jobs 2
;;
cabal)
@@ -121,6 +126,7 @@ script:
case "$BUILD" in
stack)
ulimit -n 4096
+ stack config set system-ghc --global true
stack --no-terminal $ARGS test --fast --flag 'aeson:fast' --flag pandoc:embed_data_files --haddock --no-haddock-deps --ghc-options="$OPTS"
;;
cabal)
diff --git a/MANUAL.txt b/MANUAL.txt
index 78bd057ed..5d60e2c19 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1,6 +1,6 @@
% Pandoc User's Guide
% John MacFarlane
-% December 8, 2017
+% December 27, 2017
Synopsis
========
@@ -284,16 +284,9 @@ General options
(`markdown_github` provides deprecated and less accurate support
for Github-Flavored Markdown; please use `gfm` instead, unless you
need to use extensions other than `smart`.)
- If `+lhs` is appended to `markdown`, `rst`, `latex`, or
- `html`, the input will be treated as literate Haskell source: see
- [Literate Haskell support], below. Markdown
- syntax extensions can be individually enabled or disabled by
- appending `+EXTENSION` or `-EXTENSION` to the format name. So, for
- example, `markdown_strict+footnotes+definition_lists` is strict
- Markdown with footnotes and definition lists enabled, and
- `markdown-pipe_tables+hard_line_breaks` is pandoc's Markdown
- without pipe tables and with hard line breaks. See [Pandoc's
- Markdown], below, for a list of extensions and
+ Extensions can be individually enabled or disabled by
+ appending `+EXTENSION` or `-EXTENSION` to the format name.
+ See [Extensions] below, for a list of extensions and
their names. See `--list-input-formats` and `--list-extensions`,
below.
@@ -327,13 +320,10 @@ General options
unless you use extensions that do not work with `gfm`.) Note that
`odt`, `epub`, and `epub3` output will not be directed to
*stdout*; an output filename must be specified using the
- `-o/--output` option. If `+lhs` is appended to `markdown`, `rst`,
- `latex`, `beamer`, `html4`, or `html5`, the output will be
- rendered as literate Haskell source: see [Literate Haskell
- support], below. Markdown syntax extensions can be individually
- enabled or disabled by appending `+EXTENSION` or `-EXTENSION` to
- the format name, as described above under `-f`. See
- `--list-output-formats` and `--list-extensions`, below.
+ `-o/--output` option. Extensions can be individually enabled or
+ disabled by appending `+EXTENSION` or `-EXTENSION` to the format
+ name. See [Extensions] below, for a list of extensions and their
+ names. See `--list-output-formats` and `--list-extensions`, below.
`-o` *FILE*, `--output=`*FILE*
@@ -397,11 +387,12 @@ General options
: List supported output formats, one per line.
-`--list-extensions`
+`--list-extensions`[`=`*FORMAT*]
-: List supported Markdown extensions, one per line, followed
+: List supported Markdown extensions, one per line, preceded
by a `+` or `-` indicating whether it is enabled by default
- in pandoc's Markdown.
+ in *FORMAT*. If *FORMAT* is not specified, defaults for
+ pandoc's Markdown are given.
`--list-highlight-languages`
@@ -491,6 +482,9 @@ Reader options
3. `$PATH` (executable only)
+ Filters and lua-filters are applied in the order specified
+ on the command line.
+
`--lua-filter=`*SCRIPT*
: Transform the document in a similar fashion as JSON filters (see
@@ -864,8 +858,8 @@ Options affecting specific writers
`--section-divs`
-: Wrap sections in `<div>` tags (or `<section>` tags in HTML5),
- and attach identifiers to the enclosing `<div>` (or `<section>`)
+: Wrap sections in `<section>` tags (or `<div>` tags for `html4`),
+ and attach identifiers to the enclosing `<section>` (or `<div>`)
rather than the header itself. See
[Header identifiers], below.
@@ -1106,7 +1100,7 @@ of the following options.
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] (in `epub3`, `docbook4`, `docbook5`, `jats`,
@@ -1698,6 +1692,269 @@ will be treated as a comment and ignored.
[pandoc-templates]: https://github.com/jgm/pandoc-templates
+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] below (See [Markdown variants] for
+`commonmark` and `gfm`.) In the following, extensions that also work
+for other formats are covered.
+
+Typography
+----------
+
+#### 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`
+
+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.
+
+Headers and sections
+--------------------
+
+#### Extension: `auto_identifiers` ####
+
+A header without an explicitly specified identifier will be
+automatically assigned a unique identifier based on the header 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 algorithm used to derive the identifier from the header text is:
+
+ - Remove all formatting, links, etc.
+ - Remove all footnotes.
+ - Remove all punctuation, 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,
+
+ Header Identifier
+ ------------------------------- ----------------------------
+ `Header identifiers in HTML` `header-identifiers-in-html`
+ `*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 header text. The exception is when several headers 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.
+
+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
+ [header identifiers](#header-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 header itself. This allows entire
+sections to be manipulated using JavaScript or treated differently in
+CSS.
+
+#### 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.
+
+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 HTML/TeX
+------------
+
+The following extensions (especially how they affect Markdown
+input/output) are also described in more detail in their respective
+sections of [Pandoc's Markdown].
+
+#### [Extension: `raw_html`] {#raw_html}
+
+When converting from HTML, parse elements to raw HTML which are not
+representable in pandoc's AST.
+By default, this is disabled for HTML input.
+
+#### [Extension: `raw_tex`] {#raw_tex}
+
+Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
+
+This extension can be enabled/disabled for the following formats
+(in addition to `markdown`):
+
+input formats
+: `latex`, `org`, `textile`
+
+output formats
+: `textile`
+
+#### [Extension: `native_divs`] {#native_divs}
+
+This extension is enabled by default for HTML input. This means that
+`div`s are parsed to pandoc native elements. (Alternatively, you
+can parse them to raw HTML using `-f html-native_divs+raw_html`.)
+
+When converting HTML to Markdown, for example, you may want to drop all
+`div`s and `span`s:
+
+ pandoc -f html-native_divs-native_spans -t markdown
+
+#### [Extension: `native_spans`] {#native_spans}
+
+Analogous to `native_divs` above.
+
+
+Literate Haskell support
+------------------------
+
+#### 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 headers 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, headers 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 indentend literate
+code blocks (e.g. inside an itemized environment) will not be picked up by the
+Haskell compiler.
+
+Other extensions
+----------------
+
+#### 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
+: `markdown`, `docx`, `odt`, `opendocument`, `html`
+
+#### Extension: `amuse` ####
+
+In the `muse` input format, this enables Text::Amuse
+extensions to Emacs Muse markup.
+
+#### Extension: `citations` {#org-citations}
+
+Some aspects of [Pandoc's Markdown citation syntax](#citations) are also accepted
+in `org` input.
+
+
Pandoc's Markdown
=================
@@ -1705,11 +1962,9 @@ Pandoc understands an extended and slightly revised version of
John Gruber's [Markdown] syntax. This document explains the syntax,
noting differences from standard Markdown. Except where noted, these
differences can be suppressed by using the `markdown_strict` format instead
-of `markdown`. An extensions can be enabled by adding `+EXTENSION`
-to the format name and disabled by adding `-EXTENSION`. For example,
-`markdown_strict+footnotes` is strict Markdown with footnotes
-enabled, while `markdown-footnotes-pipe_tables` is pandoc's
-Markdown without footnotes or pipe tables.
+of `markdown`. Extensions can be enabled or disabled to specify the
+behavior more granularly. They are described in the following. See also
+[Extensions] above, for extensions that work also on other formats.
Philosophy
----------
@@ -1801,6 +2056,8 @@ pandoc does require the space.
### Header identifiers ###
+See also the [`auto_identifiers` extension](#extension-auto_identifiers) above.
+
#### Extension: `header_attributes` ####
Headers can be assigned attributes using this syntax at the end
@@ -1837,55 +2094,6 @@ is just the same as
# My header {.unnumbered}
-#### Extension: `auto_identifiers` ####
-
-A header without an explicitly specified identifier will be
-automatically assigned a unique identifier based on the header text.
-To derive the identifier from the header text,
-
- - Remove all formatting, links, etc.
- - Remove all footnotes.
- - Remove all punctuation, 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,
-
- Header Identifier
- ------------------------------- ----------------------------
- `Header identifiers in HTML` `header-identifiers-in-html`
- `*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 header text. The exception is when several headers 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.
-
-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
- [header identifiers](#header-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 `div` (or a `section`, if `html5` was specified),
-and the identifier will be attached to the enclosing `<div>`
-(or `<section>`) tag rather than the header itself. This allows entire
-sections to be manipulated using JavaScript or treated differently in
-CSS.
-
#### Extension: `implicit_header_references` ####
Pandoc behaves as if reference links have been defined for each header.
@@ -3028,8 +3236,6 @@ HTML, Slidy, DZSlides, S5, EPUB
command-line options selected. Therefore see [Math rendering in HTML]
above.
-This extension can be used with both `markdown` and `html` input.
-
[interpreted text role `:math:`]: http://docutils.sourceforge.net/docs/ref/rst/roles.html#math
Raw HTML
@@ -3457,33 +3663,6 @@ they cannot contain multiple paragraphs). The syntax is as follows:
Inline and regular footnotes may be mixed freely.
-Typography
-----------
-
-#### 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
-option currently affects the input formats `markdown`,
-`commonmark`, `latex`, `mediawiki`, `org`, `rst`, and `twiki`,
-and the output formats `markdown`, `latex`, and `context`.
-It is enabled by default for `markdown`, `latex`, and `context`
-(in 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.
-
Citations
---------
@@ -3746,8 +3925,6 @@ 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 `[`.
-This extension can be used with both `markdown` and `html` input.
-
#### Extension: `tex_math_double_backslash` ####
Causes anything between `\\(` and `\\)` to be interpreted as inline
@@ -3790,12 +3967,6 @@ simply skipped (as opposed to being parsed as paragraphs).
Makes all absolute URIs into links, even when not surrounded by
pointy braces `<...>`.
-#### 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: `mmd_link_attributes` ####
Parses multimarkdown style key-value attributes on link
@@ -3839,12 +4010,6 @@ in several respects:
we must either disallow lazy wrapping or require a blank line between
list items.
-#### Extension: `empty_paragraphs` ####
-
-Allows empty paragraphs. By default empty paragraphs are
-omitted. This affects the `docx` reader and writer, the
-`opendocument` and `odt` writer, and all HTML-based readers and writers.
-
Markdown variants
-----------------
@@ -3878,34 +4043,21 @@ variants are supported:
: `raw_html`, `shortcut_reference_links`,
`spaced_reference_links`.
-We also support `gfm` (GitHub-Flavored Markdown) as a set of
-extensions on `commonmark`:
+We also support `commonmark` and `gfm` (GitHub-Flavored Markdown,
+which is implemented as a set of extensions on `commonmark`).
+Note, however, that `commonmark` and `gfm` have limited support
+for extensions. Only those listed below (and `smart` and
+`raw_tex`) will work. The extensions can, however, all be
+individually disabled.
+Also, `raw_tex` only affects `gfm` output, not input.
+
+`gfm` (GitHub-Flavored Markdown)
: `pipe_tables`, `raw_html`, `fenced_code_blocks`, `auto_identifiers`,
`ascii_identifiers`, `backtick_code_blocks`, `autolink_bare_uris`,
`intraword_underscores`, `strikeout`, `hard_line_breaks`, `emoji`,
`shortcut_reference_links`, `angle_brackets_escapable`.
- These can all be individually disabled. Note, however, that
- `commonmark` and `gfm` have limited support for extensions:
- extensions other than those listed above (and `smart` and
- `raw_tex`) will have no effect on `commonmark` or `gfm`.
- And `raw_tex` only affects `gfm` output, not input.
-
-Extensions with formats other than Markdown
--------------------------------------------
-
-Some of the extensions discussed above can be used with formats
-other than Markdown:
-
-* `auto_identifiers` can be used with `latex`, `rst`, `mediawiki`,
- and `textile` input (and is used by default).
-
-* `tex_math_dollars`, `tex_math_single_backslash`, and
- `tex_math_double_backslash` can be used with `html` input.
- (This is handy for reading web pages formatted using MathJax,
- for example.)
-
Producing slide shows with pandoc
=================================
@@ -4257,57 +4409,6 @@ with the `src` attribute. For example:
</source>
</audio>
-Literate Haskell support
-========================
-
-If you append `+lhs` (or `+literate_haskell`) to an appropriate input or output
-format (`markdown`, `markdown_strict`, `rst`, or `latex` for input or output;
-`beamer`, `html4` or `html5` for output only), 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 headers 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, headers 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 indentend literate
-code blocks (e.g. inside an itemized environment) will not be picked up by the
-Haskell compiler.
-
Syntax highlighting
===================
diff --git a/Makefile b/Makefile
index 46afc990d..f0e0d1b8a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ SOURCEFILES?=$(shell find pandoc.hs src test -name '*.hs')
BRANCH?=master
RESOLVER=lts-10
GHCOPTS=-fdiagnostics-color=always -Wall -fno-warn-unused-do-bind -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances
+WEBSITE=../../web/pandoc.org
quick:
stack install --resolver=$(RESOLVER) --ghc-options='$(GHCOPTS)' --install-ghc --flag 'pandoc:embed_data_files' --fast --test --test-arguments='-j4 --hide-successes $(TESTARGS)'
@@ -32,7 +33,7 @@ lint:
for f in $(SOURCEFILES); do echo $$f; hlint --verbose --refactor --refactor-options='-i -s' $$f; done
changes_github:
- pandoc --filter tools/extract-changes.hs changelog -t gfm+hard_line_breaks | sed -e 's/\\#/#/g' | pbcopy
+ pandoc --filter tools/extract-changes.hs changelog -t gfm --wrap=none | sed -e 's/\\#/#/g' | pbcopy
dist: man/pandoc.1
cabal sdist
@@ -85,7 +86,23 @@ download_stats:
curl https://api.github.com/repos/jgm/pandoc/releases | \
jq -r '.[] | .assets | .[] | "\(.download_count)\t\(.name)"'
+pandoc-templates:
+ rm ../pandoc-templates/default.* ; \
+ cp data/templates/default.* ../pandoc-templates/ ; \
+ pushd ../pandoc-templates/ && \
+ git add default.* && \
+ git commit -m "Updated templates for pandoc $(version)" && \
+ popd
+
+trypandoc:
+ ssh -t macfarlane 'cd src/pandoc && git pull && ~/.local/bin/stack install --flag pandoc:trypandoc --flag pandoc:embed_data_files && cd trypandoc && sudo make install'
+
+update-website:
+ make -C $(WEBSITE) update
+ make -C $(WEBSITE)
+ make -C $(WEBSITE) upload
+
clean:
stack clean
-.PHONY: deps quick full haddock install clean test bench changes_github macospkg dist prof download_stats reformat lint weigh doc/lua-filters.md packages
+.PHONY: deps quick full haddock install clean test bench changes_github macospkg dist prof download_stats reformat lint weigh doc/lua-filters.md packages pandoc-templates trypandoc update-website
diff --git a/RELEASE-CHECKLIST b/RELEASE-CHECKLIST
index f3e42a55e..dd8789b99 100644
--- a/RELEASE-CHECKLIST
+++ b/RELEASE-CHECKLIST
@@ -7,11 +7,10 @@ _ make man/pandoc.1 and commit if needed
_ Tag release in git
-_ Push templates:
- git subtree push --prefix=data/templates git@github.com:jgm/pandoc-templates.git master
+_ make pandoc-templates
cd ../pandoc-templates
- git pull
git tag REL
+ git push
git push --tags
_ Generate Windows package (make winpkg)
@@ -27,12 +26,9 @@ _ Upload to HackageDB: stack upload .
_ if docs don't build on Hackage:
'cabal install neil && neil docs --username=MYUSERNAME'
-_ Update website, including short description of changes ('make changes')
+_ make update-website
-_ Announce on pandoc-announce, pandoc-discuss
-
-_ on server, stack install --flag 'pandoc:trypandoc'
- and then 'cd trypandoc; sudo make install'
+_ make trypandoc
-_ recompile gitit
+_ Announce on pandoc-announce, pandoc-discuss
diff --git a/appveyor.yml b/appveyor.yml
index 534995891..9401d6666 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,7 +2,7 @@ clone_folder: "c:\\pandoc"
environment:
global:
WIXBIN: "c:\\Program Files (x86)\\WiX Toolset v3.11\\bin"
- STACK_YAML: "c:\\pandoc\\stack.pkg.yaml"
+ STACK_YAML: "c:\\pandoc\\stack.yaml"
STACK_BUILD_OPTS: "-j1 --no-terminal --test --local-bin-path=.\\windows"
matrix:
- STACK_VERSION: "windows-i386"
diff --git a/benchmark/benchmark-pandoc.hs b/benchmark/benchmark-pandoc.hs
index a667a6f81..645801c85 100644
--- a/benchmark/benchmark-pandoc.hs
+++ b/benchmark/benchmark-pandoc.hs
@@ -68,10 +68,11 @@ main = do
movie <- B.readFile "test/movie.jpg"
time <- Data.Time.getCurrentTime
let setupFakeFiles = modifyPureState $ \st -> st{ stFiles =
- FileTree $ Map.fromList [
- ("lalune.jpg", FileInfo time lalune),
- ("movie.jpg", FileInfo time movie)
- ]}
+ insertInFileTree "lalune.jpg"
+ (FileInfo time lalune) $
+ insertInFileTree "movie.jpg"
+ (FileInfo time movie) mempty
+ }
let opts = def
let doc = either (error . show) id $ runPure $ readMarkdown opts inp
let readers' = [(n, \o d ->
diff --git a/changelog b/changelog
index 43c781409..960fe381b 100644
--- a/changelog
+++ b/changelog
@@ -1,3 +1,15 @@
+pandoc (2.1)
+
+ * Filter changes (#4196). Previously we ran all lua filters before
+ JSON filters. Now we run filters in the order they are presented on
+ the command line, whether lua or JSON. There are two incompatible API
+ changes: The type of `applyFilters` has changed, and `applyLuaFilters`
+ has been removed.
+
+ * Text.Pandoc.Class: make `FileTree` opaque (don't export
+ `FileTree` cosntructor). This forces users to interact with it using
+ `insertInFileTree` and `getFileInfo`, which normalize file names.
+
pandoc (2.0.6)
* Added `jats` as an input format.
@@ -11,6 +23,12 @@ pandoc (2.0.6)
bibliographic information can be processed with pandoc and
pandoc-citeproc to produce a formatted bibliography.
+ * Allow `--list-extensions` to take an optional FORMAT argument.
+ This lists the extensions set by default for the selected FORMAT.
+ The extensions are now alphabetized, and the `+` or `-`
+ indicating the default setting comes before, rather than after,
+ the extension.
+
* Markdown reader:
+ Preserve original whitespace between blocks.
@@ -46,6 +64,8 @@ pandoc (2.0.6)
Markdown reader when parsing raw LaTeX with escaped spaces.
+ Add tests of LaTeX tokenizer.
+ Support `\foreignlanguage` from babel.
+ + Be more tolerant of `&` character (#4208). This allows us to parse
+ unknown tabular environments as raw LaTeX.
* Muse reader (Alexander Krotov):
@@ -56,6 +76,12 @@ pandoc (2.0.6)
* Org reader (Albert Krewinkel):
+ Fix asterisks-related parsing error (#4180).
+ + Support minlevel option for includes (#4154). The level of headers
+ in included files can be shifted to a higher level by specifying a
+ minimum header level via the `:minlevel` parameter. E.g.
+ `#+include: "tour.org" :minlevel 1` will shift the headers in
+ tour.org such that the topmost headers become level 1 headers.
+ + Break-up org reader test file into multiple modules.
* OPML reader:
@@ -78,6 +104,9 @@ pandoc (2.0.6)
interruption and introduces a new id if a list is starting again. So
we keep track of the state of lists and use them to define a "start"
attribute, if necessary.
+ + Add tests for structured document tags unwrapping (Jesse Rosenthal).
+ + Preprocess Document body to unwrap `w:sdt` elements (Jesse Rosenthal,
+ #4190).
* Plain writer:
@@ -102,6 +131,8 @@ pandoc (2.0.6)
+ Don't look for default template file for Powerpoint (#4181).
+ Add pptx to isTextFormat list. This is used to check standalone
and not writing to the terminal.
+ + Obey slide level option (Jesse Rosenthal).
+ + Introduce tests.
* Docx writer:
@@ -136,6 +167,12 @@ pandoc (2.0.6)
This avoids a clash with a deprecated `\textlatin` command defined
in Babel.
+ Allow fragile=singleslide attribute in beamer slides (#4169).
+ + Use `\endhead` after `\toprule` in headerless tables (#4207).
+
+ * FB2 writer:
+
+ + Add cover image specified by `cover-image` meta (Alexander Krotov,
+ #4195).
* JATS writer (Hamish Mackenzie):
@@ -150,16 +187,19 @@ pandoc (2.0.6)
+ Self closing tags for empty xref (#4187).
+ Improve support for code language.
- * Custom writer (Albert Krewinkel):
+ * Custom writer:
+ Use init file to setup Lua interpreter (Albert Krewinkel).
The same init file (`data/init`) that is used to setup the Lua
interpreter for Lua filters is also used to setup the interpreter of
custom writers.lua.
- + Define instances for newtype wrapper. The custom writer used its own
- `ToLuaStack` instance definitions, which made it difficult to share
- code with Lua filters, as this could result in conflicting instances.
- A `Stringify` wrapper is introduced to avoid this problem.
+ + Define instances for newtype wrapper (Albert Krewinkel). The custom
+ writer used its own `ToLuaStack` instance definitions, which made
+ it difficult to share code with Lua filters, as this could result
+ in conflicting instances. A `Stringify` wrapper is introduced to
+ avoid this problem.
+ + Added tests for custom writer.
+ + Fixed definition lists and tables in `data/sample.lua`.
* Fixed regression: when target is PDF, writer extensions were being
ignored. So, for example, `pandoc -t latex-smart -o file.pdf`
@@ -189,10 +229,20 @@ pandoc (2.0.6)
+ pandoc.lua: re-add missing MetaMap function. This was a bug
introduced in version 2.0.4.
+ * Text.Pandoc.Class: Add `insertInFileTree` [API change]. This gives
+ a pure way to insert an ersatz file into a `FileTree`. In addition, we
+ normalize paths both on insertion and on lookup.
+
* Text.Pandoc.Shared: export `blocksToInlines'` (API change, Maura Bieg).
* Text.Pandoc.MIME: Add opus to MIME type table as audio/ogg (#4198).
+ * Text.Pandoc.Extensions: Alphabetical order constructors for
+ `Extension`. This makes them appear in order in `--list-extensions`.
+
+ * Allow lenient decoding of latex error logs, which are not always
+ properly UTF8-encoded (#4200).
+
* Update latex template to work with recent versions of beamer.
The old template produced numbered sections with some recent
versions of beamer. Thanks to Thomas Hodgson.
@@ -205,10 +255,23 @@ pandoc (2.0.6)
* Removed `default.theme` data file (#4096). It is no longer needed now
that we have `--print-highlight-style`.
+ * Added `stack.lts9.yaml` for building with lts 9 and ghc 8.0.2.
+ We still need this for the alpine static linux build, since
+ we don't have ghc 8.2.2 for that yet.
+
+ * Removed `stack.pkg.yaml`. We only really need `stack.yaml`; we
+ can put flag settings for pandoc-citeproc there.
+
+ * Makefile: Add 'trypandoc' and 'pandoc-templates' targets to
+ make releases easier.
+
* MANUAL.txt:
+ Add note on what formats have `+smart` by default.
+ Use native syntax for custom-style (#4174, Mauro Bieg).
+ + Introduce dedicated Extensions section, since some extensions
+ affect formats other than markdown (Mauro Bieg, #4204).
+ + Clarify default html output for `--section-divs` (Richard Edwards).
* filters.md: say that Text.Pandoc.JSON comes form pandoc-types.
Closes jgm/pandoc-website#16.
@@ -255,7 +318,7 @@ pandoc (2.0.5)
+ Revert "Docx reader: don't strip out empty paragraphs."
This reverts commit d6c58eb836f033a48955796de4d9ffb3b30e297b.
+ Implement `empty_paragraphs` extension in docx reader and writer,
- opendocument writer, html reader and writer.
+ opendocument writer, HTML reader and writer.
+ Add tests for `empty_paragraphs` extension.
* Markdown reader:
@@ -535,6 +598,8 @@ pandoc (2.0.3)
+ Allow spaces after `\(` and before `\)` with `tex_math_single_backslash`.
Previously `\( \frac{1}{a} < \frac{1}{b} \)` was not parsed as math in
`markdown` or `html` `+tex_math_single_backslash`.
+ + Parse div with class `line-block` as LineBlock.
+ + Don't fail with block-level content in figcaption (Mauro Bieg, #4183).
* MANUAL: clarify that math extensions work with HTML.
Clarify that `tex_math_dollars` and `tex_math_single_backslash`
diff --git a/data/sample.lua b/data/sample.lua
index 1e3a08731..6c09442b5 100644
--- a/data/sample.lua
+++ b/data/sample.lua
@@ -242,14 +242,12 @@ function OrderedList(items)
return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>"
end
--- Revisit association list STackValue instance.
function DefinitionList(items)
local buffer = {}
for _,item in pairs(items) do
- for k, v in pairs(item) do
- table.insert(buffer,"<dt>" .. k .. "</dt>\n<dd>" ..
- table.concat(v,"</dd>\n<dd>") .. "</dd>")
- end
+ local k, v = next(item)
+ table.insert(buffer, "<dt>" .. k .. "</dt>\n<dd>" ..
+ table.concat(v, "</dd>\n<dd>") .. "</dd>")
end
return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>"
end
@@ -288,7 +286,7 @@ function Table(caption, aligns, widths, headers, rows)
end
if widths and widths[1] ~= 0 then
for _, w in pairs(widths) do
- add('<col width="' .. string.format("%d%%", w * 100) .. '" />')
+ add('<col width="' .. string.format("%.0f%%", w * 100) .. '" />')
end
end
local header_row = {}
diff --git a/doc/lua-filters.md b/doc/lua-filters.md
index e9ed704ad..07de33259 100644
--- a/doc/lua-filters.md
+++ b/doc/lua-filters.md
@@ -88,11 +88,10 @@ then it would be applied like this:
pandoc --lua-filter=current-date.lua -f markdown MANUAL.txt
-The `--lua-filter` can be supplied multiple times, causing the
-filters to be applied sequentially in the order they were given.
-If other, non-Lua filters are given as well (via `--filter`),
-then those are executed *after* all Lua filters have been
-applied.
+The `--lua-filter` option may be supplied multiple times. Pandoc
+applies all filters (including JSON filters specified via
+`--filter` and lua filters specified via `--lua-filter`)
+in the order they appear on the command line.
Pandoc expects each lua file to return a list of filters. The
filters in that list are called sequentially, each on the result
diff --git a/linux/Dockerfile b/linux/Dockerfile
index 3660aa4fc..40d37d13d 100644
--- a/linux/Dockerfile
+++ b/linux/Dockerfile
@@ -12,9 +12,28 @@ RUN stack config set system-ghc --global true
#RUN echo "build: { split-objs: true }" > /etc/stack/config.yaml
RUN mkdir -p /usr/src/
WORKDIR /usr/src/
-RUN git clone https://github.com/jgm/pandoc
+RUN git clone https://github.com/jgm/pandoc
WORKDIR /usr/src/pandoc
-RUN stack install --stack-yaml stack.pkg.yaml --only-dependencies \
+RUN stack install --stack-yaml stack.lts9.yaml \
+ --only-dependencies \
+ --flag 'pandoc:static' \
+ --flag 'pandoc:embed_data_files' \
+ --flag 'pandoc-citeproc:static' \
+ --flag 'pandoc-citeproc:embed_data_files' \
+ --flag 'hslua:-export-dynamic' \
+ --ghc-options '-O2 -optc-Os -optl=-pthread -optl=-static -fPIC' \
+ aeson
+RUN stack install --stack-yaml stack.lts9.yaml \
+ --only-dependencies \
+ --flag 'pandoc:static' \
+ --flag 'pandoc:embed_data_files' \
+ --flag 'pandoc-citeproc:static' \
+ --flag 'pandoc-citeproc:embed_data_files' \
+ --flag 'hslua:-export-dynamic' \
+ --ghc-options '-O2 -optc-Os -optl=-pthread -optl=-static -fPIC' \
+ http-client-tls
+RUN stack install --stack-yaml stack.lts9.yaml \
+ --only-dependencies \
--flag 'pandoc:static' \
--flag 'pandoc:embed_data_files' \
--flag 'pandoc-citeproc:static' \
@@ -24,7 +43,7 @@ RUN stack install --stack-yaml stack.pkg.yaml --only-dependencies \
pandoc pandoc-citeproc
CMD git pull && \
git checkout -b work $TREE && \
- stack install --stack-yaml stack.pkg.yaml \
+ stack install --stack-yaml stack.lts9.yaml \
--flag 'pandoc:static' \
--flag 'pandoc:embed_data_files' \
--flag 'pandoc-citeproc:static' \
diff --git a/macos/make_macos_package.sh b/macos/make_macos_package.sh
index 4b565b0de..85155c66c 100755
--- a/macos/make_macos_package.sh
+++ b/macos/make_macos_package.sh
@@ -27,7 +27,7 @@ stack setup
echo Building pandoc...
stack clean
-stack install --ghc-options="-O2" --stack-yaml=stack.pkg.yaml --local-bin-path $DEST/bin/ pandoc pandoc-citeproc
+stack install --ghc-options="-O2" --local-bin-path $DEST/bin/ pandoc pandoc-citeproc
strip $DEST/bin/pandoc
strip $DEST/bin/pandoc-citeproc
diff --git a/man/pandoc.1 b/man/pandoc.1
index 64db3ae51..ba809e78b 100644
--- a/man/pandoc.1
+++ b/man/pandoc.1
@@ -1,5 +1,5 @@
.\"t
-.TH PANDOC 1 "December 8, 2017" "pandoc 2.0.5"
+.TH PANDOC 1 "December 27, 2017" "pandoc 2.0.6"
.SH NAME
pandoc - general markup converter
.SH SYNOPSIS
@@ -12,16 +12,16 @@ another, and a command\-line tool that uses this library.
It can read Markdown, CommonMark, PHP Markdown Extra, GitHub\-Flavored
Markdown, MultiMarkdown, and (subsets of) Textile, reStructuredText,
HTML, LaTeX, MediaWiki markup, TWiki markup, TikiWiki markup, Creole
-1.0, Haddock markup, OPML, Emacs Org mode, DocBook, Muse, txt2tags,
-Vimwiki, EPUB, ODT, and Word docx; and it can write plain text,
-Markdown, CommonMark, PHP Markdown Extra, GitHub\-Flavored Markdown,
-MultiMarkdown, reStructuredText, XHTML, HTML5, LaTeX (including
-\f[C]beamer\f[] slide shows), ConTeXt, RTF, OPML, DocBook, OpenDocument,
-ODT, Word docx, GNU Texinfo, MediaWiki markup, DokuWiki markup, ZimWiki
-markup, Haddock markup, EPUB (v2 or v3), FictionBook2, Textile, groff
-man, groff ms, Emacs Org mode, AsciiDoc, InDesign ICML, TEI Simple,
-Muse, PowerPoint slide shows and Slidy, Slideous, DZSlides, reveal.js or
-S5 HTML slide shows.
+1.0, Haddock markup, OPML, Emacs Org mode, DocBook, JATS, Muse,
+txt2tags, Vimwiki, EPUB, ODT, and Word docx; and it can write plain
+text, Markdown, CommonMark, PHP Markdown Extra, GitHub\-Flavored
+Markdown, MultiMarkdown, reStructuredText, XHTML, HTML5, LaTeX
+(including \f[C]beamer\f[] slide shows), ConTeXt, RTF, OPML, DocBook,
+JATS, OpenDocument, ODT, Word docx, GNU Texinfo, MediaWiki markup,
+DokuWiki markup, ZimWiki markup, Haddock markup, EPUB (v2 or v3),
+FictionBook2, Textile, groff man, groff ms, Emacs Org mode, AsciiDoc,
+InDesign ICML, TEI Simple, Muse, PowerPoint slide shows and Slidy,
+Slideous, DZSlides, reveal.js or S5 HTML slide shows.
It can also produce PDF output on systems where LaTeX, ConTeXt,
\f[C]pdfroff\f[], \f[C]wkhtmltopdf\f[], \f[C]prince\f[], or
\f[C]weasyprint\f[] is installed.
@@ -242,19 +242,10 @@ markup), \f[C]tikiwiki\f[] (TikiWiki markup), \f[C]creole\f[] (Creole
1.0), \f[C]haddock\f[] (Haddock markup), or \f[C]latex\f[] (LaTeX).
(\f[C]markdown_github\f[] provides deprecated and less accurate support
for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless
-you need to use extensions other than \f[C]smart\f[].) If \f[C]+lhs\f[]
-is appended to \f[C]markdown\f[], \f[C]rst\f[], \f[C]latex\f[], or
-\f[C]html\f[], the input will be treated as literate Haskell source: see
-Literate Haskell support, below.
-Markdown syntax extensions can be individually enabled or disabled by
-appending \f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format
-name.
-So, for example, \f[C]markdown_strict+footnotes+definition_lists\f[] is
-strict Markdown with footnotes and definition lists enabled, and
-\f[C]markdown\-pipe_tables+hard_line_breaks\f[] is pandoc\[aq]s Markdown
-without pipe tables and with hard line breaks.
-See Pandoc\[aq]s Markdown, below, for a list of extensions and their
-names.
+you need to use extensions other than \f[C]smart\f[].) Extensions can be
+individually enabled or disabled by appending \f[C]+EXTENSION\f[] or
+\f[C]\-EXTENSION\f[] to the format name.
+See Extensions below, for a list of extensions and their names.
See \f[C]\-\-list\-input\-formats\f[] and \f[C]\-\-list\-extensions\f[],
below.
.RS
@@ -295,13 +286,9 @@ you use extensions that do not work with \f[C]gfm\f[].) Note that
\f[C]odt\f[], \f[C]epub\f[], and \f[C]epub3\f[] output will not be
directed to \f[I]stdout\f[]; an output filename must be specified using
the \f[C]\-o/\-\-output\f[] option.
-If \f[C]+lhs\f[] is appended to \f[C]markdown\f[], \f[C]rst\f[],
-\f[C]latex\f[], \f[C]beamer\f[], \f[C]html4\f[], or \f[C]html5\f[], the
-output will be rendered as literate Haskell source: see Literate Haskell
-support, below.
-Markdown syntax extensions can be individually enabled or disabled by
-appending \f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format
-name, as described above under \f[C]\-f\f[].
+Extensions can be individually enabled or disabled by appending
+\f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format name.
+See Extensions below, for a list of extensions and their names.
See \f[C]\-\-list\-output\-formats\f[] and
\f[C]\-\-list\-extensions\f[], below.
.RS
@@ -398,10 +385,12 @@ List supported output formats, one per line.
.RS
.RE
.TP
-.B \f[C]\-\-list\-extensions\f[]
-List supported Markdown extensions, one per line, followed by a
+.B \f[C]\-\-list\-extensions\f[][\f[C]=\f[]\f[I]FORMAT\f[]]
+List supported Markdown extensions, one per line, preceded by a
\f[C]+\f[] or \f[C]\-\f[] indicating whether it is enabled by default in
-pandoc\[aq]s Markdown.
+\f[I]FORMAT\f[].
+If \f[I]FORMAT\f[] is not specified, defaults for pandoc\[aq]s Markdown
+are given.
.RS
.RE
.TP
@@ -951,9 +940,9 @@ document; see Structuring the slide show.
.RE
.TP
.B \f[C]\-\-section\-divs\f[]
-Wrap sections in \f[C]<div>\f[] tags (or \f[C]<section>\f[] tags in
-HTML5), and attach identifiers to the enclosing \f[C]<div>\f[] (or
-\f[C]<section>\f[]) rather than the header itself.
+Wrap sections in \f[C]<section>\f[] tags (or \f[C]<div>\f[] tags for
+\f[C]html4\f[]), and attach identifiers to the enclosing
+\f[C]<section>\f[] (or \f[C]<div>\f[]) rather than the header itself.
See Header identifiers, below.
.RS
.RE
@@ -2035,6 +2024,336 @@ merge in changes after each pandoc release.
.PP
Templates may contain comments: anything on a line after \f[C]$\-\-\f[]
will be treated as a comment and ignored.
+.SH EXTENSIONS
+.PP
+The behavior of some of the readers and writers can be adjusted by
+enabling or disabling various extensions.
+.PP
+An extension can be enabled by adding \f[C]+EXTENSION\f[] to the format
+name and disabled by adding \f[C]\-EXTENSION\f[].
+For example, \f[C]\-\-from\ markdown_strict+footnotes\f[] is strict
+Markdown with footnotes enabled, while
+\f[C]\-\-from\ markdown\-footnotes\-pipe_tables\f[] is pandoc\[aq]s
+Markdown without footnotes or pipe tables.
+.PP
+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\[aq]s Markdown below (See Markdown variants for
+\f[C]commonmark\f[] and \f[C]gfm\f[].) In the following, extensions that
+also work for other formats are covered.
+.SS Typography
+.SS Extension: \f[C]smart\f[]
+.PP
+Interpret straight quotes as curly quotes, \f[C]\-\-\-\f[] as
+em\-dashes, \f[C]\-\-\f[] as en\-dashes, and \f[C]\&...\f[] as ellipses.
+Nonbreaking spaces are inserted after certain abbreviations, such as
+"Mr."
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]markdown\f[], \f[C]commonmark\f[], \f[C]latex\f[],
+\f[C]mediawiki\f[], \f[C]org\f[], \f[C]rst\f[], \f[C]twiki\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]latex\f[], \f[C]context\f[], \f[C]rst\f[]
+.RS
+.RE
+.TP
+.B enabled by default in
+\f[C]markdown\f[], \f[C]latex\f[], \f[C]context\f[] (both input and
+output)
+.RS
+.RE
+.PP
+Note: If you are \f[I]writing\f[] Markdown, then the \f[C]smart\f[]
+extension has the reverse effect: what would have been curly quotes
+comes out straight.
+.PP
+In LaTeX, \f[C]smart\f[] means to use the standard TeX ligatures for
+quotation marks (\f[C]``\f[] and \f[C]\[aq]\[aq]\f[] for double quotes,
+\f[C]`\f[] and \f[C]\[aq]\f[] for single quotes) and dashes
+(\f[C]\-\-\f[] for en\-dash and \f[C]\-\-\-\f[] for em\-dash).
+If \f[C]smart\f[] is disabled, then in reading LaTeX pandoc will parse
+these characters literally.
+In writing LaTeX, enabling \f[C]smart\f[] tells pandoc to use the
+ligatures when possible; if \f[C]smart\f[] is disabled pandoc will use
+unicode quotation mark and dash characters.
+.SS Headers and sections
+.SS Extension: \f[C]auto_identifiers\f[]
+.PP
+A header without an explicitly specified identifier will be
+automatically assigned a unique identifier based on the header text.
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]markdown\f[], \f[C]latex\f[], \f[C]rst\f[], \f[C]mediawiki\f[],
+\f[C]textile\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]muse\f[]
+.RS
+.RE
+.TP
+.B enabled by default in
+\f[C]markdown\f[], \f[C]muse\f[]
+.RS
+.RE
+.PP
+The algorithm used to derive the identifier from the header text is:
+.IP \[bu] 2
+Remove all formatting, links, etc.
+.IP \[bu] 2
+Remove all footnotes.
+.IP \[bu] 2
+Remove all punctuation, except underscores, hyphens, and periods.
+.IP \[bu] 2
+Replace all spaces and newlines with hyphens.
+.IP \[bu] 2
+Convert all alphabetic characters to lowercase.
+.IP \[bu] 2
+Remove everything up to the first letter (identifiers may not begin with
+a number or punctuation mark).
+.IP \[bu] 2
+If nothing is left after this, use the identifier \f[C]section\f[].
+.PP
+Thus, for example,
+.PP
+.TS
+tab(@);
+l l.
+T{
+Header
+T}@T{
+Identifier
+T}
+_
+T{
+\f[C]Header\ identifiers\ in\ HTML\f[]
+T}@T{
+\f[C]header\-identifiers\-in\-html\f[]
+T}
+T{
+\f[C]*Dogs*?\-\-in\ *my*\ house?\f[]
+T}@T{
+\f[C]dogs\-\-in\-my\-house\f[]
+T}
+T{
+\f[C][HTML],\ [S5],\ or\ [RTF]?\f[]
+T}@T{
+\f[C]html\-s5\-or\-rtf\f[]
+T}
+T{
+\f[C]3.\ Applications\f[]
+T}@T{
+\f[C]applications\f[]
+T}
+T{
+\f[C]33\f[]
+T}@T{
+\f[C]section\f[]
+T}
+.TE
+.PP
+These rules should, in most cases, allow one to determine the identifier
+from the header text.
+The exception is when several headers have the same text; in this case,
+the first will get an identifier as described above; the second will get
+the same identifier with \f[C]\-1\f[] appended; the third with
+\f[C]\-2\f[]; and so on.
+.PP
+These identifiers are used to provide link targets in the table of
+contents generated by the \f[C]\-\-toc|\-\-table\-of\-contents\f[]
+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:
+.IP
+.nf
+\f[C]
+See\ the\ section\ on
+[header\ identifiers](#header\-identifiers\-in\-html\-latex\-and\-context).
+\f[]
+.fi
+.PP
+Note, however, that this method of providing links to sections works
+only in HTML, LaTeX, and ConTeXt formats.
+.PP
+If the \f[C]\-\-section\-divs\f[] option is specified, then each section
+will be wrapped in a \f[C]section\f[] (or a \f[C]div\f[], if
+\f[C]html4\f[] was specified), and the identifier will be attached to
+the enclosing \f[C]<section>\f[] (or \f[C]<div>\f[]) tag rather than the
+header itself.
+This allows entire sections to be manipulated using JavaScript or
+treated differently in CSS.
+.SS Extension: \f[C]ascii_identifiers\f[]
+.PP
+Causes the identifiers produced by \f[C]auto_identifiers\f[] to be pure
+ASCII.
+Accents are stripped off of accented Latin letters, and non\-Latin
+letters are omitted.
+.SS Math Input
+.PP
+The extensions \f[C]tex_math_dollars\f[],
+\f[C]tex_math_single_backslash\f[], and
+\f[C]tex_math_double_backslash\f[] are described in the section about
+Pandoc\[aq]s Markdown.
+.PP
+However, they can also be used with HTML input.
+This is handy for reading web pages formatted using MathJax, for
+example.
+.SS Raw HTML/TeX
+.PP
+The following extensions (especially how they affect Markdown
+input/output) are also described in more detail in their respective
+sections of Pandoc\[aq]s Markdown.
+.SS Extension: \f[C]raw_html\f[]
+.PP
+When converting from HTML, parse elements to raw HTML which are not
+representable in pandoc\[aq]s AST.
+By default, this is disabled for HTML input.
+.SS Extension: \f[C]raw_tex\f[]
+.PP
+Allows raw LaTeX, TeX, and ConTeXt to be included in a document.
+.PP
+This extension can be enabled/disabled for the following formats (in
+addition to \f[C]markdown\f[]):
+.TP
+.B input formats
+\f[C]latex\f[], \f[C]org\f[], \f[C]textile\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]textile\f[]
+.RS
+.RE
+.SS Extension: \f[C]native_divs\f[]
+.PP
+This extension is enabled by default for HTML input.
+This means that \f[C]div\f[]s are parsed to pandoc native elements.
+(Alternatively, you can parse them to raw HTML using
+\f[C]\-f\ html\-native_divs+raw_html\f[].)
+.PP
+When converting HTML to Markdown, for example, you may want to drop all
+\f[C]div\f[]s and \f[C]span\f[]s:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ html\-native_divs\-native_spans\ \-t\ markdown
+\f[]
+.fi
+.SS Extension: \f[C]native_spans\f[]
+.PP
+Analogous to \f[C]native_divs\f[] above.
+.SS Literate Haskell support
+.SS Extension: \f[C]literate_haskell\f[]
+.PP
+Treat the document as literate Haskell source.
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]markdown\f[], \f[C]rst\f[], \f[C]latex\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]rst\f[], \f[C]latex\f[], \f[C]html\f[]
+.RS
+.RE
+.PP
+If you append \f[C]+lhs\f[] (or \f[C]+literate_haskell\f[]) to one of
+the formats above, pandoc will treat the document as literate Haskell
+source.
+This means that
+.IP \[bu] 2
+In Markdown input, "bird track" sections will be parsed as Haskell code
+rather than block quotations.
+Text between \f[C]\\begin{code}\f[] and \f[C]\\end{code}\f[] will also
+be treated as Haskell code.
+For ATX\-style headers the character \[aq]=\[aq] will be used instead of
+\[aq]#\[aq].
+.IP \[bu] 2
+In Markdown output, code blocks with classes \f[C]haskell\f[] and
+\f[C]literate\f[] 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, headers will be rendered setext\-style (with underlines)
+rather than ATX\-style (with \[aq]#\[aq] characters).
+(This is because ghc treats \[aq]#\[aq] characters in column 1 as
+introducing line numbers.)
+.IP \[bu] 2
+In restructured text input, "bird track" sections will be parsed as
+Haskell code.
+.IP \[bu] 2
+In restructured text output, code blocks with class \f[C]haskell\f[]
+will be rendered using bird tracks.
+.IP \[bu] 2
+In LaTeX input, text in \f[C]code\f[] environments will be parsed as
+Haskell code.
+.IP \[bu] 2
+In LaTeX output, code blocks with class \f[C]haskell\f[] will be
+rendered inside \f[C]code\f[] environments.
+.IP \[bu] 2
+In HTML output, code blocks with class \f[C]haskell\f[] will be rendered
+with class \f[C]literatehaskell\f[] and bird tracks.
+.PP
+Examples:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ markdown+lhs\ \-t\ html
+\f[]
+.fi
+.PP
+reads literate Haskell source formatted with Markdown conventions and
+writes ordinary HTML (without bird tracks).
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs
+\f[]
+.fi
+.PP
+writes HTML with the Haskell code in bird tracks, so it can be copied
+and pasted as literate Haskell source.
+.PP
+Note that GHC expects the bird tracks in the first column, so indentend
+literate code blocks (e.g.
+inside an itemized environment) will not be picked up by the Haskell
+compiler.
+.SS Other extensions
+.SS Extension: \f[C]empty_paragraphs\f[]
+.PP
+Allows empty paragraphs.
+By default empty paragraphs are omitted.
+.PP
+This extension can be enabled/disabled for the following formats:
+.TP
+.B input formats
+\f[C]docx\f[], \f[C]html\f[]
+.RS
+.RE
+.TP
+.B output formats
+\f[C]markdown\f[], \f[C]docx\f[], \f[C]odt\f[], \f[C]opendocument\f[],
+\f[C]html\f[]
+.RS
+.RE
+.SS Extension: \f[C]amuse\f[]
+.PP
+In the \f[C]muse\f[] input format, this enables Text::Amuse extensions
+to Emacs Muse markup.
+.SS Extension: \f[C]citations\f[]
+.PP
+Some aspects of Pandoc\[aq]s Markdown citation syntax are also accepted
+in \f[C]org\f[] input.
.SH PANDOC\[aq]S MARKDOWN
.PP
Pandoc understands an extended and slightly revised version of John
@@ -2043,11 +2362,11 @@ This document explains the syntax, noting differences from standard
Markdown.
Except where noted, these differences can be suppressed by using the
\f[C]markdown_strict\f[] format instead of \f[C]markdown\f[].
-An extensions can be enabled by adding \f[C]+EXTENSION\f[] to the format
-name and disabled by adding \f[C]\-EXTENSION\f[].
-For example, \f[C]markdown_strict+footnotes\f[] is strict Markdown with
-footnotes enabled, while \f[C]markdown\-footnotes\-pipe_tables\f[] is
-pandoc\[aq]s Markdown without footnotes or pipe tables.
+Extensions can be enabled or disabled to specify the behavior more
+granularly.
+They are described in the following.
+See also Extensions above, for extensions that work also on other
+formats.
.SS Philosophy
.PP
Markdown is designed to be easy to write, and, even more importantly,
@@ -2149,6 +2468,8 @@ Many Markdown implementations do not require a space between the opening
\f[C]#5\ bolt\f[] and \f[C]#hashtag\f[] count as headers.
With this extension, pandoc does require the space.
.SS Header identifiers
+.PP
+See also the \f[C]auto_identifiers\f[] extension above.
.SS Extension: \f[C]header_attributes\f[]
.PP
Headers can be assigned attributes using this syntax at the end of the
@@ -2203,96 +2524,6 @@ is just the same as
#\ My\ header\ {.unnumbered}
\f[]
.fi
-.SS Extension: \f[C]auto_identifiers\f[]
-.PP
-A header without an explicitly specified identifier will be
-automatically assigned a unique identifier based on the header text.
-To derive the identifier from the header text,
-.IP \[bu] 2
-Remove all formatting, links, etc.
-.IP \[bu] 2
-Remove all footnotes.
-.IP \[bu] 2
-Remove all punctuation, except underscores, hyphens, and periods.
-.IP \[bu] 2
-Replace all spaces and newlines with hyphens.
-.IP \[bu] 2
-Convert all alphabetic characters to lowercase.
-.IP \[bu] 2
-Remove everything up to the first letter (identifiers may not begin with
-a number or punctuation mark).
-.IP \[bu] 2
-If nothing is left after this, use the identifier \f[C]section\f[].
-.PP
-Thus, for example,
-.PP
-.TS
-tab(@);
-l l.
-T{
-Header
-T}@T{
-Identifier
-T}
-_
-T{
-\f[C]Header\ identifiers\ in\ HTML\f[]
-T}@T{
-\f[C]header\-identifiers\-in\-html\f[]
-T}
-T{
-\f[C]*Dogs*?\-\-in\ *my*\ house?\f[]
-T}@T{
-\f[C]dogs\-\-in\-my\-house\f[]
-T}
-T{
-\f[C][HTML],\ [S5],\ or\ [RTF]?\f[]
-T}@T{
-\f[C]html\-s5\-or\-rtf\f[]
-T}
-T{
-\f[C]3.\ Applications\f[]
-T}@T{
-\f[C]applications\f[]
-T}
-T{
-\f[C]33\f[]
-T}@T{
-\f[C]section\f[]
-T}
-.TE
-.PP
-These rules should, in most cases, allow one to determine the identifier
-from the header text.
-The exception is when several headers have the same text; in this case,
-the first will get an identifier as described above; the second will get
-the same identifier with \f[C]\-1\f[] appended; the third with
-\f[C]\-2\f[]; and so on.
-.PP
-These identifiers are used to provide link targets in the table of
-contents generated by the \f[C]\-\-toc|\-\-table\-of\-contents\f[]
-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:
-.IP
-.nf
-\f[C]
-See\ the\ section\ on
-[header\ identifiers](#header\-identifiers\-in\-html\-latex\-and\-context).
-\f[]
-.fi
-.PP
-Note, however, that this method of providing links to sections works
-only in HTML, LaTeX, and ConTeXt formats.
-.PP
-If the \f[C]\-\-section\-divs\f[] option is specified, then each section
-will be wrapped in a \f[C]div\f[] (or a \f[C]section\f[], if
-\f[C]html5\f[] was specified), and the identifier will be attached to
-the enclosing \f[C]<div>\f[] (or \f[C]<section>\f[]) tag rather than the
-header itself.
-This allows entire sections to be manipulated using JavaScript or
-treated differently in CSS.
.SS Extension: \f[C]implicit_header_references\f[]
.PP
Pandoc behaves as if reference links have been defined for each header.
@@ -2911,6 +3142,13 @@ As\ (\@good)\ illustrates,\ ...
.PP
The label can be any string of alphanumeric characters, underscores, or
hyphens.
+.PP
+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 \f[C]four_space_rule\f[]
+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.
.SS Compact and loose lists
.PP
Pandoc behaves differently from \f[C]Markdown.pl\f[] on some "edge
@@ -3756,9 +3994,6 @@ options selected.
Therefore see Math rendering in HTML above.
.RS
.RE
-.PP
-This extension can be used with both \f[C]markdown\f[] and \f[C]html\f[]
-input.
.SS Raw HTML
.SS Extension: \f[C]raw_html\f[]
.PP
@@ -3951,9 +4186,9 @@ The raw attribute cannot be combined with regular attributes.
.SS LaTeX macros
.SS Extension: \f[C]latex_macros\f[]
.PP
-For output formats other than LaTeX, pandoc will parse LaTeX
-\f[C]\\newcommand\f[] and \f[C]\\renewcommand\f[] definitions and apply
-the resulting macros to all LaTeX math.
+For output formats other than LaTeX, 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:
.IP
@@ -3965,8 +4200,13 @@ $\\tuple{a,\ b,\ c}$
\f[]
.fi
.PP
-In LaTeX output, the \f[C]\\newcommand\f[] definition will simply be
-passed unchanged to the output.
+In LaTeX output, the macro definitions will not be passed through as raw
+LaTeX.
+.PP
+When \f[C]latex_macros\f[] is disabled, the macro definitions will be
+passed through as raw LaTeX, and the raw LaTeX and math will not have
+macros applied.
+This is usually a better approach when you are targeting LaTeX or PDF.
.SS Links
.PP
Markdown allows links to be specified in several ways.
@@ -4288,30 +4528,6 @@ note.]
.fi
.PP
Inline and regular footnotes may be mixed freely.
-.SS Typography
-.SS Extension: \f[C]smart\f[]
-.PP
-Interpret straight quotes as curly quotes, \f[C]\-\-\-\f[] as
-em\-dashes, \f[C]\-\-\f[] as en\-dashes, and \f[C]\&...\f[] as ellipses.
-Nonbreaking spaces are inserted after certain abbreviations, such as
-"Mr." This option currently affects the input formats \f[C]markdown\f[],
-\f[C]commonmark\f[], \f[C]latex\f[], \f[C]mediawiki\f[], \f[C]org\f[],
-\f[C]rst\f[], and \f[C]twiki\f[], and the output formats
-\f[C]markdown\f[], \f[C]latex\f[], and \f[C]context\f[].
-.PP
-Note: If you are \f[I]writing\f[] Markdown, then the \f[C]smart\f[]
-extension has the reverse effect: what would have been curly quotes
-comes out straight.
-.PP
-In LaTeX, \f[C]smart\f[] means to use the standard TeX ligatures for
-quotation marks (\f[C]``\f[] and \f[C]\[aq]\[aq]\f[] for double quotes,
-\f[C]`\f[] and \f[C]\[aq]\f[] for single quotes) and dashes
-(\f[C]\-\-\f[] for en\-dash and \f[C]\-\-\-\f[] for em\-dash).
-If \f[C]smart\f[] is disabled, then in reading LaTeX pandoc will parse
-these characters literally.
-In writing LaTeX, enabling \f[C]smart\f[] tells pandoc to use the
-ligatures when possible; if \f[C]smart\f[] is disabled pandoc will use
-unicode quotation mark and dash characters.
.SS Citations
.SS Extension: \f[C]citations\f[]
.PP
@@ -4675,9 +4891,6 @@ as inline TeX math, and anything between \f[C]\\[\f[] and \f[C]\\]\f[]
to be interpreted as display TeX math.
Note: a drawback of this extension is that it precludes escaping
\f[C](\f[] and \f[C][\f[].
-.PP
-This extension can be used with both \f[C]markdown\f[] and \f[C]html\f[]
-input.
.SS Extension: \f[C]tex_math_double_backslash\f[]
.PP
Causes anything between \f[C]\\\\(\f[] and \f[C]\\\\)\f[] to be
@@ -4725,12 +4938,6 @@ opposed to being parsed as paragraphs).
.PP
Makes all absolute URIs into links, even when not surrounded by pointy
braces \f[C]<...>\f[].
-.SS Extension: \f[C]ascii_identifiers\f[]
-.PP
-Causes the identifiers produced by \f[C]auto_identifiers\f[] to be pure
-ASCII.
-Accents are stripped off of accented Latin letters, and non\-Latin
-letters are omitted.
.SS Extension: \f[C]mmd_link_attributes\f[]
.PP
Parses multimarkdown style key\-value attributes on link and image
@@ -4765,13 +4972,6 @@ anything.
.IP \[bu] 2
Lazy wrapping of paragraphs is not allowed: the entire definition must
be indented four spaces.
-.SS Extension: \f[C]empty_paragraphs\f[]
-.PP
-Allows empty paragraphs.
-By default empty paragraphs are omitted.
-This affects the \f[C]docx\f[] reader and writer, the
-\f[C]opendocument\f[] and \f[C]odt\f[] writer, and all HTML\-based
-readers and writers.
.SS Markdown variants
.PP
In addition to pandoc\[aq]s extended Markdown, the following Markdown
@@ -4817,37 +5017,26 @@ variants are supported:
.RS
.RE
.PP
-We also support \f[C]gfm\f[] (GitHub\-Flavored Markdown) as a set of
-extensions on \f[C]commonmark\f[]:
+We also support \f[C]commonmark\f[] and \f[C]gfm\f[] (GitHub\-Flavored
+Markdown, which is implemented as a set of extensions on
+\f[C]commonmark\f[]).
.PP
-: \f[C]pipe_tables\f[], \f[C]raw_html\f[], \f[C]fenced_code_blocks\f[],
+Note, however, that \f[C]commonmark\f[] and \f[C]gfm\f[] have limited
+support for extensions.
+Only those listed below (and \f[C]smart\f[] and \f[C]raw_tex\f[]) will
+work.
+The extensions can, however, all be individually disabled.
+Also, \f[C]raw_tex\f[] only affects \f[C]gfm\f[] output, not input.
+.TP
+.B \f[C]gfm\f[] (GitHub\-Flavored Markdown)
+\f[C]pipe_tables\f[], \f[C]raw_html\f[], \f[C]fenced_code_blocks\f[],
\f[C]auto_identifiers\f[], \f[C]ascii_identifiers\f[],
\f[C]backtick_code_blocks\f[], \f[C]autolink_bare_uris\f[],
\f[C]intraword_underscores\f[], \f[C]strikeout\f[],
\f[C]hard_line_breaks\f[], \f[C]emoji\f[],
\f[C]shortcut_reference_links\f[], \f[C]angle_brackets_escapable\f[].
-.IP
-.nf
-\f[C]
-These\ can\ all\ be\ individually\ disabled.\ Note,\ however,\ that
-`commonmark`\ and\ `gfm`\ have\ limited\ support\ for\ extensions:
-extensions\ other\ than\ those\ listed\ above\ (and\ `smart`\ and
-`raw_tex`)\ will\ have\ no\ effect\ on\ `commonmark`\ or\ `gfm`.
-And\ `raw_tex`\ only\ affects\ `gfm`\ output,\ not\ input.
-\f[]
-.fi
-.SS Extensions with formats other than Markdown
-.PP
-Some of the extensions discussed above can be used with formats other
-than Markdown:
-.IP \[bu] 2
-\f[C]auto_identifiers\f[] can be used with \f[C]latex\f[], \f[C]rst\f[],
-\f[C]mediawiki\f[], and \f[C]textile\f[] input (and is used by default).
-.IP \[bu] 2
-\f[C]tex_math_dollars\f[], \f[C]tex_math_single_backslash\f[], and
-\f[C]tex_math_double_backslash\f[] can be used with \f[C]html\f[] input.
-(This is handy for reading web pages formatted using MathJax, for
-example.)
+.RS
+.RE
.SH PRODUCING SLIDE SHOWS WITH PANDOC
.PP
You can use pandoc to produce an HTML + JavaScript slide presentation
@@ -5299,70 +5488,6 @@ For example:
</audio>
\f[]
.fi
-.SH LITERATE HASKELL SUPPORT
-.PP
-If you append \f[C]+lhs\f[] (or \f[C]+literate_haskell\f[]) to an
-appropriate input or output format (\f[C]markdown\f[],
-\f[C]markdown_strict\f[], \f[C]rst\f[], or \f[C]latex\f[] for input or
-output; \f[C]beamer\f[], \f[C]html4\f[] or \f[C]html5\f[] for output
-only), pandoc will treat the document as literate Haskell source.
-This means that
-.IP \[bu] 2
-In Markdown input, "bird track" sections will be parsed as Haskell code
-rather than block quotations.
-Text between \f[C]\\begin{code}\f[] and \f[C]\\end{code}\f[] will also
-be treated as Haskell code.
-For ATX\-style headers the character \[aq]=\[aq] will be used instead of
-\[aq]#\[aq].
-.IP \[bu] 2
-In Markdown output, code blocks with classes \f[C]haskell\f[] and
-\f[C]literate\f[] 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, headers will be rendered setext\-style (with underlines)
-rather than ATX\-style (with \[aq]#\[aq] characters).
-(This is because ghc treats \[aq]#\[aq] characters in column 1 as
-introducing line numbers.)
-.IP \[bu] 2
-In restructured text input, "bird track" sections will be parsed as
-Haskell code.
-.IP \[bu] 2
-In restructured text output, code blocks with class \f[C]haskell\f[]
-will be rendered using bird tracks.
-.IP \[bu] 2
-In LaTeX input, text in \f[C]code\f[] environments will be parsed as
-Haskell code.
-.IP \[bu] 2
-In LaTeX output, code blocks with class \f[C]haskell\f[] will be
-rendered inside \f[C]code\f[] environments.
-.IP \[bu] 2
-In HTML output, code blocks with class \f[C]haskell\f[] will be rendered
-with class \f[C]literatehaskell\f[] and bird tracks.
-.PP
-Examples:
-.IP
-.nf
-\f[C]
-pandoc\ \-f\ markdown+lhs\ \-t\ html
-\f[]
-.fi
-.PP
-reads literate Haskell source formatted with Markdown conventions and
-writes ordinary HTML (without bird tracks).
-.IP
-.nf
-\f[C]
-pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs
-\f[]
-.fi
-.PP
-writes HTML with the Haskell code in bird tracks, so it can be copied
-and pasted as literate Haskell source.
-.PP
-Note that GHC expects the bird tracks in the first column, so indentend
-literate code blocks (e.g.
-inside an itemized environment) will not be picked up by the Haskell
-compiler.
.SH SYNTAX HIGHLIGHTING
.PP
Pandoc will automatically highlight syntax in fenced code blocks that
@@ -5395,26 +5520,26 @@ blocks and text using \f[C]div\f[]s and \f[C]span\f[]s, respectively.
If you define a \f[C]div\f[] or \f[C]span\f[] with the attribute
\f[C]custom\-style\f[], pandoc will apply your specified style to the
contained elements.
-So, for example,
+So, for example using the \f[C]bracketed_spans\f[] syntax,
.IP
.nf
\f[C]
-<span\ custom\-style="Emphatically">Get\ out,</span>\ he\ said.
+[Get\ out]{custom\-style="Emphatically"},\ he\ said.
\f[]
.fi
.PP
-would produce a docx file with "Get out," styled with character style
+would produce a docx file with "Get out" styled with character style
\f[C]Emphatically\f[].
-Similarly,
+Similarly, using the \f[C]fenced_divs\f[] syntax,
.IP
.nf
\f[C]
Dickinson\ starts\ the\ poem\ simply:
-<div\ custom\-style="Poetry">
+:::\ {custom\-style="Poetry"}
|\ A\ Bird\ came\ down\ the\ Walk\-\-\-
|\ He\ did\ not\ know\ I\ saw\-\-\-
-</div>
+:::
\f[]
.fi
.PP
diff --git a/pandoc.cabal b/pandoc.cabal
index 73f51af0f..dea141a8f 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,5 +1,5 @@
name: pandoc
-version: 2.0.6
+version: 2.1
cabal-version: >= 1.10
build-type: Custom
license: GPL
@@ -81,6 +81,7 @@ data-files:
data/docx/docProps/core.xml
data/docx/word/document.xml
data/docx/word/fontTable.xml
+ data/docx/word/comments.xml
data/docx/word/footnotes.xml
data/docx/word/numbering.xml
data/docx/word/settings.xml
@@ -104,28 +105,28 @@ data-files:
data/pptx/docProps/thumbnail.jpeg
data/pptx/docProps/app.xml
data/pptx/docProps/core.xml
- data/pptx/ppt/slideLayouts/slideLayout4.xml
- data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels
- data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels
- data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels
data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout2.xml.rels
data/pptx/ppt/slideLayouts/_rels/slideLayout3.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels
data/pptx/ppt/slideLayouts/_rels/slideLayout5.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels
data/pptx/ppt/slideLayouts/_rels/slideLayout7.xml.rels
data/pptx/ppt/slideLayouts/_rels/slideLayout8.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout9.xml.rels
+ data/pptx/ppt/slideLayouts/_rels/slideLayout10.xml.rels
data/pptx/ppt/slideLayouts/_rels/slideLayout11.xml.rels
- data/pptx/ppt/slideLayouts/_rels/slideLayout4.xml.rels
- data/pptx/ppt/slideLayouts/_rels/slideLayout6.xml.rels
+ data/pptx/ppt/slideLayouts/slideLayout1.xml
data/pptx/ppt/slideLayouts/slideLayout2.xml
- data/pptx/ppt/slideLayouts/slideLayout8.xml
- data/pptx/ppt/slideLayouts/slideLayout11.xml
data/pptx/ppt/slideLayouts/slideLayout3.xml
- data/pptx/ppt/slideLayouts/slideLayout6.xml
- data/pptx/ppt/slideLayouts/slideLayout9.xml
+ data/pptx/ppt/slideLayouts/slideLayout4.xml
data/pptx/ppt/slideLayouts/slideLayout5.xml
+ data/pptx/ppt/slideLayouts/slideLayout6.xml
data/pptx/ppt/slideLayouts/slideLayout7.xml
- data/pptx/ppt/slideLayouts/slideLayout1.xml
+ data/pptx/ppt/slideLayouts/slideLayout8.xml
+ data/pptx/ppt/slideLayouts/slideLayout9.xml
data/pptx/ppt/slideLayouts/slideLayout10.xml
+ data/pptx/ppt/slideLayouts/slideLayout11.xml
data/pptx/ppt/_rels/presentation.xml.rels
data/pptx/ppt/theme/theme1.xml
data/pptx/ppt/presProps.xml
@@ -244,6 +245,7 @@ extra-source-files:
test/tables.txt
test/tables.fb2
test/tables.muse
+ test/tables.custom
test/testsuite.txt
test/writer.latex
test/writer.context
@@ -272,6 +274,7 @@ extra-source-files:
test/writer.dokuwiki
test/writer.zimwiki
test/writer.muse
+ test/writer.custom
test/writers-lang-and-dir.latex
test/writers-lang-and-dir.context
test/dokuwiki_inline_formatting.dokuwiki
@@ -603,7 +606,9 @@ test-suite test-pandoc
pandoc,
pandoc-types >= 1.17.3 && < 1.18,
bytestring >= 0.9 && < 0.11,
+ base64-bytestring >= 0.1 && < 1.1,
text >= 0.11 && < 1.3,
+ time >= 1.5 && < 1.9,
directory >= 1 && < 1.4,
filepath >= 1.1 && < 1.5,
hslua >= 0.9 && < 0.10,
@@ -618,6 +623,11 @@ test-suite test-pandoc
containers >= 0.4.2.1 && < 0.6,
executable-path >= 0.0 && < 0.1,
zip-archive >= 0.2.3.4 && < 0.4
+ if flag(old-locale)
+ build-depends: old-locale >= 1 && < 1.1,
+ time >= 1.2 && < 1.5
+ else
+ build-depends: time >= 1.5 && < 1.9
other-modules: Tests.Old
Tests.Command
Tests.Helpers
@@ -628,6 +638,18 @@ test-suite test-pandoc
Tests.Readers.JATS
Tests.Readers.Markdown
Tests.Readers.Org
+ Tests.Readers.Org.Block
+ Tests.Readers.Org.Block.CodeBlock
+ Tests.Readers.Org.Block.Figure
+ Tests.Readers.Org.Block.Header
+ Tests.Readers.Org.Block.List
+ Tests.Readers.Org.Block.Table
+ Tests.Readers.Org.Directive
+ Tests.Readers.Org.Inline
+ Tests.Readers.Org.Inline.Note
+ Tests.Readers.Org.Inline.Smart
+ Tests.Readers.Org.Meta
+ Tests.Readers.Org.Shared
Tests.Readers.RST
Tests.Readers.Docx
Tests.Readers.Odt
@@ -650,6 +672,7 @@ test-suite test-pandoc
Tests.Writers.TEI
Tests.Writers.Muse
Tests.Writers.FB2
+ Tests.Writers.Powerpoint
ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
default-language: Haskell98
diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs
index e597c56d6..7c463d743 100644
--- a/src/Text/Pandoc/App.hs
+++ b/src/Text/Pandoc/App.hs
@@ -35,11 +35,12 @@ Does a pandoc conversion based on command-line options.
module Text.Pandoc.App (
convertWithOpts
, Opt(..)
+ , LineEnding(..)
+ , Filter(..)
, defaultOpts
, parseOptions
, options
, applyFilters
- , applyLuaFilters
) where
import qualified Control.Exception as E
import Control.Monad
@@ -58,6 +59,9 @@ import Data.Monoid
import qualified Data.Set as Set
import Data.Text (Text)
import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Encoding as TE
+import qualified Data.Text.Encoding.Error as TE
import Data.Yaml (decode)
import qualified Data.Yaml as Yaml
import GHC.Generics
@@ -181,11 +185,13 @@ convertWithOpts opts = do
Nothing -> return Nothing
Just fp -> Just <$> UTF8.readFile fp
+ let isPandocCiteproc (JSONFilter f) = takeBaseName f == "pandoc-citeproc"
+ isPandocCiteproc _ = False
-- --bibliography implies -F pandoc-citeproc for backwards compatibility:
let needsCiteproc = isJust (lookup "bibliography" (optMetadata opts)) &&
optCiteMethod opts `notElem` [Natbib, Biblatex] &&
- "pandoc-citeproc" `notElem` map takeBaseName filters
- let filters' = if needsCiteproc then "pandoc-citeproc" : filters
+ all (not . isPandocCiteproc) filters
+ let filters' = if needsCiteproc then JSONFilter "pandoc-citeproc" : filters
else filters
let sources = case optInputFiles opts of
@@ -498,10 +504,9 @@ convertWithOpts opts = do
then fillMediaBag
else return)
>=> return . addMetadata metadata
- >=> applyLuaFilters datadir (optLuaFilters opts) format
- >=> maybe return extractMedia (optExtractMedia opts)
>=> applyTransforms transforms
- >=> applyFilters readerOpts datadir filters' [format]
+ >=> applyFilters readerOpts filters' [format]
+ >=> maybe return extractMedia (optExtractMedia opts)
)
case writer of
@@ -513,7 +518,9 @@ convertWithOpts opts = do
case res of
Right pdf -> writeFnBinary outputFile pdf
Left err' -> liftIO $
- E.throwIO $ PandocPDFError (UTF8.toStringLazy err')
+ E.throwIO $ PandocPDFError $
+ TL.unpack (TE.decodeUtf8With TE.lenientDecode err')
+
Nothing -> do
let htmlFormat = format `elem`
["html","html4","html5","s5","slidy",
@@ -578,6 +585,10 @@ externalFilter ropts f args' d = liftIO $ do
where filterException :: E.SomeException -> IO a
filterException e = E.throwIO $ PandocFilterError f (show e)
+data Filter = LuaFilter FilePath
+ | JSONFilter FilePath
+ deriving (Show)
+
-- | Data structure for command line options.
data Opt = Opt
{ optTabStop :: Int -- ^ Number of spaces per tab
@@ -621,8 +632,7 @@ data Opt = Opt
, optDpi :: Int -- ^ Dpi
, optWrapText :: WrapOption -- ^ Options for wrapping text
, optColumns :: Int -- ^ Line length in characters
- , optFilters :: [FilePath] -- ^ Filters to apply
- , optLuaFilters :: [FilePath] -- ^ Lua filters to apply
+ , optFilters :: [Filter] -- ^ Filters to apply
, optEmailObfuscation :: ObfuscationMethod
, optIdentifierPrefix :: String
, optStripEmptyParagraphs :: Bool -- ^ Strip empty paragraphs
@@ -695,7 +705,6 @@ defaultOpts = Opt
, optWrapText = WrapAuto
, optColumns = 72
, optFilters = []
- , optLuaFilters = []
, optEmailObfuscation = NoObfuscation
, optIdentifierPrefix = ""
, optStripEmptyParagraphs = False
@@ -827,41 +836,46 @@ applyTransforms transforms d = return $ foldr ($) d transforms
-- First we check to see if a filter is found. If not, and if it's
-- not an absolute path, we check to see whether it's in `userdir/filters`.
-- If not, we leave it unchanged.
-expandFilterPath :: MonadIO m => Maybe FilePath -> FilePath -> m FilePath
-expandFilterPath mbDatadir fp = liftIO $ do
- fpExists <- doesFileExist fp
+expandFilterPath :: PandocMonad m => FilePath -> m FilePath
+expandFilterPath fp = do
+ mbDatadir <- getUserDataDir
+ fpExists <- fileExists fp
if fpExists
then return fp
else case mbDatadir of
Just datadir | isRelative fp -> do
let filterPath = datadir </> "filters" </> fp
- filterPathExists <- doesFileExist filterPath
+ filterPathExists <- fileExists filterPath
if filterPathExists
then return filterPath
else return fp
_ -> return fp
-applyLuaFilters :: Maybe FilePath -> [FilePath] -> String -> Pandoc
- -> PandocIO Pandoc
-applyLuaFilters mbDatadir filters format d = do
- expandedFilters <- mapM (expandFilterPath mbDatadir) filters
- let go f d' = do
- res <- runLuaFilter f format d'
- case res of
- Right x -> return x
- Left (LuaException s) -> E.throw (PandocFilterError f s)
- foldrM ($) d $ map go expandedFilters
-
-applyFilters :: MonadIO m
- => ReaderOptions
- -> Maybe FilePath
- -> [FilePath]
+applyFilters :: ReaderOptions
+ -> [Filter]
-> [String]
-> Pandoc
- -> m Pandoc
-applyFilters ropts mbDatadir filters args d = do
- expandedFilters <- mapM (expandFilterPath mbDatadir) filters
- foldrM ($) d $ map (flip (externalFilter ropts) args) expandedFilters
+ -> PandocIO Pandoc
+applyFilters ropts filters args d = do
+ foldrM ($) d $ map (applyFilter ropts args) filters
+
+applyFilter :: ReaderOptions
+ -> [String]
+ -> Filter
+ -> Pandoc
+ -> PandocIO Pandoc
+applyFilter _ropts args (LuaFilter f) d = do
+ f' <- expandFilterPath f
+ let format = case args of
+ (x:_) -> x
+ _ -> error "Format not supplied for lua filter"
+ res <- runLuaFilter f' format d
+ case res of
+ Right x -> return x
+ Left (LuaException s) -> E.throw (PandocFilterError f s)
+applyFilter ropts args (JSONFilter f) d = do
+ f' <- expandFilterPath f
+ liftIO $ externalFilter ropts f' args d
readSource :: FilePath -> PandocIO Text
readSource "-" = liftIO (UTF8.toText <$> BS.getContents)
@@ -963,13 +977,15 @@ options =
, Option "F" ["filter"]
(ReqArg
- (\arg opt -> return opt { optFilters = arg : optFilters opt })
+ (\arg opt -> return opt { optFilters =
+ JSONFilter arg : optFilters opt })
"PROGRAM")
"" -- "External JSON filter"
, Option "" ["lua-filter"]
(ReqArg
- (\arg opt -> return opt { optLuaFilters = arg : optLuaFilters opt })
+ (\arg opt -> return opt { optFilters =
+ LuaFilter arg : optFilters opt })
"SCRIPTPATH")
"" -- "Lua filter"
@@ -1584,15 +1600,16 @@ options =
""
, Option "" ["list-extensions"]
- (NoArg
- (\_ -> do
- let showExt x = drop 4 (show x) ++
- if extensionEnabled x pandocExtensions
- then " +"
- else " -"
+ (OptArg
+ (\arg _ -> do
+ let exts = getDefaultExtensions (fromMaybe "markdown" arg)
+ let showExt x = (if extensionEnabled x exts
+ then '+'
+ else '-') : drop 4 (show x)
mapM_ (UTF8.hPutStrLn stdout . showExt)
([minBound..maxBound] :: [Extension])
- exitSuccess ))
+ exitSuccess )
+ "FORMAT")
""
, Option "" ["list-highlight-languages"]
@@ -1714,4 +1731,5 @@ deprecatedOption o msg =
-- see https://github.com/jgm/pandoc/pull/4083
-- using generic deriving caused long compilation times
$(deriveJSON defaultOptions ''LineEnding)
+$(deriveJSON defaultOptions ''Filter)
$(deriveJSON defaultOptions ''Opt)
diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs
index c63781adf..f8d6b6737 100644
--- a/src/Text/Pandoc/Class.hs
+++ b/src/Text/Pandoc/Class.hs
@@ -78,9 +78,10 @@ module Text.Pandoc.Class ( PandocMonad(..)
, getResourcePath
, PandocIO(..)
, PandocPure(..)
- , FileTree(..)
+ , FileTree
, FileInfo(..)
, addToFileTree
+ , insertInFileTree
, runIO
, runIOorExplode
, runPure
@@ -144,6 +145,8 @@ import System.Directory (createDirectoryIfMissing, getDirectoryContents,
import System.FilePath ((</>), (<.>), takeDirectory,
takeExtension, dropExtension, isRelative, normalise)
import qualified System.FilePath.Glob as IO (glob)
+import qualified System.FilePath.Posix as Posix
+import System.FilePath (splitDirectories)
import qualified System.Directory as IO (getModificationTime)
import Control.Monad as M (fail)
import Control.Monad.State.Strict
@@ -160,8 +163,6 @@ import Text.Pandoc.Translations (Term(..), Translations, lookupTerm,
import qualified Debug.Trace
#ifdef EMBED_DATA_FILES
import Text.Pandoc.Data (dataFiles)
-import qualified System.FilePath.Posix as Posix
-import System.FilePath (splitDirectories)
#else
import qualified Paths_pandoc as Paths
#endif
@@ -620,6 +621,7 @@ getDefaultReferenceDocx = do
"word/document.xml",
"word/fontTable.xml",
"word/footnotes.xml",
+ "word/comments.xml",
"word/numbering.xml",
"word/settings.xml",
"word/webSettings.xml",
@@ -686,8 +688,6 @@ getDefaultReferencePptx = do
, "ppt/presProps.xml"
, "ppt/presentation.xml"
, "ppt/slideLayouts/_rels/slideLayout1.xml.rels"
- , "ppt/slideLayouts/_rels/slideLayout10.xml.rels"
- , "ppt/slideLayouts/_rels/slideLayout11.xml.rels"
, "ppt/slideLayouts/_rels/slideLayout2.xml.rels"
, "ppt/slideLayouts/_rels/slideLayout3.xml.rels"
, "ppt/slideLayouts/_rels/slideLayout4.xml.rels"
@@ -696,6 +696,8 @@ getDefaultReferencePptx = do
, "ppt/slideLayouts/_rels/slideLayout7.xml.rels"
, "ppt/slideLayouts/_rels/slideLayout8.xml.rels"
, "ppt/slideLayouts/_rels/slideLayout9.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout10.xml.rels"
+ , "ppt/slideLayouts/_rels/slideLayout11.xml.rels"
, "ppt/slideLayouts/slideLayout1.xml"
, "ppt/slideLayouts/slideLayout10.xml"
, "ppt/slideLayouts/slideLayout11.xml"
@@ -711,6 +713,8 @@ getDefaultReferencePptx = do
, "ppt/slideMasters/slideMaster1.xml"
, "ppt/slides/_rels/slide1.xml.rels"
, "ppt/slides/slide1.xml"
+ , "ppt/slides/_rels/slide2.xml.rels"
+ , "ppt/slides/slide2.xml"
, "ppt/tableStyles.xml"
, "ppt/theme/theme1.xml"
, "ppt/viewProps.xml"
@@ -760,11 +764,6 @@ readDefaultDataFile fname =
case lookup (makeCanonical fname) dataFiles of
Nothing -> throwError $ PandocCouldNotFindDataFileError fname
Just contents -> return contents
- where makeCanonical = Posix.joinPath . transformPathParts . splitDirectories
- transformPathParts = reverse . foldl go []
- go as "." = as
- go (_:as) ".." = as
- go as x = x : as
#else
getDataFileName fname' >>= checkExistence >>= readFileStrict
where fname' = if fname == "MANUAL.txt" then fname else "data" </> fname
@@ -777,6 +776,13 @@ checkExistence fn = do
else throwError $ PandocCouldNotFindDataFileError fn
#endif
+makeCanonical :: FilePath -> FilePath
+makeCanonical = Posix.joinPath . transformPathParts . splitDirectories
+ where transformPathParts = reverse . foldl go []
+ go as "." = as
+ go (_:as) ".." = as
+ go as x = x : as
+
withPaths :: PandocMonad m => [FilePath] -> (FilePath -> m a) -> FilePath -> m a
withPaths [] _ fp = throwError $ PandocResourceNotFound fp
withPaths (p:ps) action fp =
@@ -912,12 +918,13 @@ newtype FileTree = FileTree {unFileTree :: M.Map FilePath FileInfo}
deriving (Monoid)
getFileInfo :: FilePath -> FileTree -> Maybe FileInfo
-getFileInfo fp tree = M.lookup fp $ unFileTree tree
+getFileInfo fp tree =
+ M.lookup (makeCanonical fp) (unFileTree tree)
-- | Add the specified file to the FileTree. If file
-- is a directory, add its contents recursively.
addToFileTree :: FileTree -> FilePath -> IO FileTree
-addToFileTree (FileTree treemap) fp = do
+addToFileTree tree fp = do
isdir <- doesDirectoryExist fp
if isdir
then do -- recursively add contents of directories
@@ -925,13 +932,17 @@ addToFileTree (FileTree treemap) fp = do
isSpecial "." = True
isSpecial _ = False
fs <- (map (fp </>) . filter (not . isSpecial)) <$> getDirectoryContents fp
- foldM addToFileTree (FileTree treemap) fs
+ foldM addToFileTree tree fs
else do
contents <- B.readFile fp
mtime <- IO.getModificationTime fp
- return $ FileTree $
- M.insert fp FileInfo{ infoFileMTime = mtime
- , infoFileContents = contents } treemap
+ return $ insertInFileTree fp FileInfo{ infoFileMTime = mtime
+ , infoFileContents = contents } tree
+
+-- | Insert an ersatz file into the 'FileTree'.
+insertInFileTree :: FilePath -> FileInfo -> FileTree -> FileTree
+insertInFileTree fp info (FileTree treemap) =
+ FileTree $ M.insert (makeCanonical fp) info treemap
newtype PandocPure a = PandocPure {
unPandocPure :: ExceptT PandocError
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
index bea293891..31fddb148 100644
--- a/src/Text/Pandoc/Extensions.hs
+++ b/src/Text/Pandoc/Extensions.hs
@@ -80,79 +80,79 @@ disableExtension x (Extensions exts) = Extensions (clearBit exts (fromEnum x))
-- | Individually selectable syntax extensions.
data Extension =
- Ext_footnotes -- ^ Pandoc/PHP/MMD style footnotes
- | Ext_inline_notes -- ^ Pandoc-style inline notes
- | Ext_pandoc_title_block -- ^ Pandoc title block
- | Ext_yaml_metadata_block -- ^ YAML metadata block
- | Ext_mmd_title_block -- ^ Multimarkdown metadata block
- | Ext_table_captions -- ^ Pandoc-style table captions
- | Ext_implicit_figures -- ^ A paragraph with just an image is a figure
- | Ext_simple_tables -- ^ Pandoc-style simple tables
- | Ext_multiline_tables -- ^ Pandoc-style multiline tables
- | Ext_grid_tables -- ^ Grid tables (pandoc, reST)
- | Ext_pipe_tables -- ^ Pipe tables (as in PHP markdown extra)
- | Ext_citations -- ^ Pandoc/citeproc citations
- | Ext_raw_tex -- ^ Allow raw TeX (other than math)
- | Ext_raw_html -- ^ Allow raw HTML
- | Ext_tex_math_dollars -- ^ TeX math between $..$ or $$..$$
- | Ext_tex_math_single_backslash -- ^ TeX math btw \(..\) \[..\]
- | Ext_tex_math_double_backslash -- ^ TeX math btw \\(..\\) \\[..\\]
- | Ext_latex_macros -- ^ Parse LaTeX macro definitions (for math only)
- | Ext_fenced_code_blocks -- ^ Parse fenced code blocks
- | Ext_fenced_code_attributes -- ^ Allow attributes on fenced code blocks
- | Ext_backtick_code_blocks -- ^ GitHub style ``` code blocks
- | Ext_inline_code_attributes -- ^ Allow attributes on inline code
- | Ext_raw_attribute -- ^ Allow explicit raw blocks/inlines
- | Ext_markdown_in_html_blocks -- ^ Interpret as markdown inside HTML blocks
- | Ext_native_divs -- ^ Use Div blocks for contents of <div> tags
- | Ext_fenced_divs -- ^ Allow fenced div syntax :::
- | Ext_native_spans -- ^ Use Span inlines for contents of <span>
- | Ext_bracketed_spans -- ^ Bracketed spans with attributes
- | Ext_markdown_attribute -- ^ Interpret text inside HTML as markdown
- -- iff container has attribute 'markdown'
- | Ext_escaped_line_breaks -- ^ Treat a backslash at EOL as linebreak
- | Ext_link_attributes -- ^ link and image attributes
- | Ext_mmd_link_attributes -- ^ MMD style reference link attributes
- | Ext_autolink_bare_uris -- ^ Make all absolute URIs into links
- | Ext_fancy_lists -- ^ Enable fancy list numbers and delimiters
- | Ext_lists_without_preceding_blankline -- ^ Allow lists without preceding blank
- | Ext_four_space_rule -- ^ Require 4-space indent for list contents
- | Ext_startnum -- ^ Make start number of ordered list significant
- | Ext_definition_lists -- ^ Definition lists as in pandoc, mmd, php
- | Ext_compact_definition_lists -- ^ Definition lists without
- -- space between items, and disallow laziness
- | Ext_example_lists -- ^ Markdown-style numbered examples
+ Ext_abbreviations -- ^ PHP markdown extra abbreviation definitions
| Ext_all_symbols_escapable -- ^ Make all non-alphanumerics escapable
+ | Ext_amuse -- ^ Enable Text::Amuse extensions to Emacs Muse markup
| Ext_angle_brackets_escapable -- ^ Make < and > escapable
- | Ext_intraword_underscores -- ^ Treat underscore inside word as literal
+ | Ext_ascii_identifiers -- ^ ascii-only identifiers for headers
+ | Ext_auto_identifiers -- ^ Automatic identifiers for headers
+ | Ext_autolink_bare_uris -- ^ Make all absolute URIs into links
+ | Ext_backtick_code_blocks -- ^ GitHub style ``` code blocks
| Ext_blank_before_blockquote -- ^ Require blank line before a blockquote
| Ext_blank_before_header -- ^ Require blank line before a header
- | Ext_space_in_atx_header -- ^ Require space between # and header text
- | Ext_strikeout -- ^ Strikeout using ~~this~~ syntax
- | Ext_superscript -- ^ Superscript using ^this^ syntax
- | Ext_subscript -- ^ Subscript using ~this~ syntax
- | Ext_hard_line_breaks -- ^ All newlines become hard line breaks
- | Ext_ignore_line_breaks -- ^ Newlines in paragraphs are ignored
+ | Ext_bracketed_spans -- ^ Bracketed spans with attributes
+ | Ext_citations -- ^ Pandoc/citeproc citations
+ | Ext_compact_definition_lists -- ^ Definition lists without space between items,
+ -- and disallow laziness
+ | Ext_definition_lists -- ^ Definition lists as in pandoc, mmd, php
| Ext_east_asian_line_breaks -- ^ Newlines in paragraphs are ignored between
- -- East Asian wide characters
- | Ext_literate_haskell -- ^ Enable literate Haskell conventions
- | Ext_abbreviations -- ^ PHP markdown extra abbreviation definitions
+ -- East Asian wide characters
| Ext_emoji -- ^ Support emoji like :smile:
- | Ext_auto_identifiers -- ^ Automatic identifiers for headers
- | Ext_gfm_auto_identifiers -- ^ Automatic identifiers for headers,
- -- using GitHub's method for generating identifiers
- | Ext_ascii_identifiers -- ^ ascii-only identifiers for headers
+ | Ext_empty_paragraphs -- ^ Allow empty paragraphs
+ | Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML
+ | Ext_escaped_line_breaks -- ^ Treat a backslash at EOL as linebreak
+ | Ext_example_lists -- ^ Markdown-style numbered examples
+ | Ext_fancy_lists -- ^ Enable fancy list numbers and delimiters
+ | Ext_fenced_code_attributes -- ^ Allow attributes on fenced code blocks
+ | Ext_fenced_code_blocks -- ^ Parse fenced code blocks
+ | Ext_fenced_divs -- ^ Allow fenced div syntax :::
+ | Ext_footnotes -- ^ Pandoc/PHP/MMD style footnotes
+ | Ext_four_space_rule -- ^ Require 4-space indent for list contents
+ | Ext_gfm_auto_identifiers -- ^ Automatic identifiers for headers, using
+ -- GitHub's method for generating identifiers
+ | Ext_grid_tables -- ^ Grid tables (pandoc, reST)
+ | Ext_hard_line_breaks -- ^ All newlines become hard line breaks
| Ext_header_attributes -- ^ Explicit header attributes {#id .class k=v}
- | Ext_mmd_header_identifiers -- ^ Multimarkdown style header identifiers [myid]
+ | Ext_ignore_line_breaks -- ^ Newlines in paragraphs are ignored
+ | Ext_implicit_figures -- ^ A paragraph with just an image is a figure
| Ext_implicit_header_references -- ^ Implicit reference links for headers
+ | Ext_inline_code_attributes -- ^ Allow attributes on inline code
+ | Ext_inline_notes -- ^ Pandoc-style inline notes
+ | Ext_intraword_underscores -- ^ Treat underscore inside word as literal
+ | Ext_latex_macros -- ^ Parse LaTeX macro definitions (for math only)
| Ext_line_blocks -- ^ RST style line blocks
- | Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML
+ | Ext_link_attributes -- ^ link and image attributes
+ | Ext_lists_without_preceding_blankline -- ^ Allow lists without preceding blank
+ | Ext_literate_haskell -- ^ Enable literate Haskell conventions
+ | Ext_markdown_attribute -- ^ Interpret text inside HTML as markdown iff
+ -- container has attribute 'markdown'
+ | Ext_markdown_in_html_blocks -- ^ Interpret as markdown inside HTML blocks
+ | Ext_mmd_header_identifiers -- ^ Multimarkdown style header identifiers [myid]
+ | Ext_mmd_link_attributes -- ^ MMD style reference link attributes
+ | Ext_mmd_title_block -- ^ Multimarkdown metadata block
+ | Ext_multiline_tables -- ^ Pandoc-style multiline tables
+ | Ext_native_divs -- ^ Use Div blocks for contents of <div> tags
+ | Ext_native_spans -- ^ Use Span inlines for contents of <span>
+ | Ext_old_dashes -- ^ -- = em, - before number = en
+ | Ext_pandoc_title_block -- ^ Pandoc title block
+ | Ext_pipe_tables -- ^ Pipe tables (as in PHP markdown extra)
+ | Ext_raw_attribute -- ^ Allow explicit raw blocks/inlines
+ | Ext_raw_html -- ^ Allow raw HTML
+ | Ext_raw_tex -- ^ Allow raw TeX (other than math)
| Ext_shortcut_reference_links -- ^ Shortcut reference links
+ | Ext_simple_tables -- ^ Pandoc-style simple tables
| Ext_smart -- ^ "Smart" quotes, apostrophes, ellipses, dashes
- | Ext_old_dashes -- ^ -- = em, - before number = en
+ | Ext_space_in_atx_header -- ^ Require space between # and header text
| Ext_spaced_reference_links -- ^ Allow space between two parts of ref link
- | Ext_amuse -- ^ Enable Text::Amuse extensions to Emacs Muse markup
- | Ext_empty_paragraphs -- ^ Allow empty paragraphs
+ | Ext_startnum -- ^ Make start number of ordered list significant
+ | Ext_strikeout -- ^ Strikeout using ~~this~~ syntax
+ | Ext_subscript -- ^ Subscript using ~this~ syntax
+ | Ext_superscript -- ^ Superscript using ^this^ syntax
+ | Ext_table_captions -- ^ Pandoc-style table captions
+ | Ext_tex_math_dollars -- ^ TeX math between $..$ or $$..$$
+ | Ext_tex_math_double_backslash -- ^ TeX math btw \\(..\\) \\[..\\]
+ | Ext_tex_math_single_backslash -- ^ TeX math btw \(..\) \[..\]
+ | Ext_yaml_metadata_block -- ^ YAML metadata block
deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
-- | Extensions to be used with pandoc-flavored markdown.
@@ -321,6 +321,7 @@ getDefaultExtensions "org" = extensionsFromList
getDefaultExtensions "html" = extensionsFromList
[Ext_auto_identifiers,
Ext_native_divs,
+ Ext_line_blocks,
Ext_native_spans]
getDefaultExtensions "html4" = getDefaultExtensions "html"
getDefaultExtensions "html5" = getDefaultExtensions "html"
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
index 99e6f99e6..48a512be2 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -73,6 +73,7 @@ import Text.TeXMath (Exp)
import Text.TeXMath.Readers.OMML (readOMML)
import Text.TeXMath.Unicode.Fonts (Font (..), getUnicode, stringToFont)
import Text.XML.Light
+import qualified Text.XML.Light.Cursor as XMLC
data ReaderEnv = ReaderEnv { envNotes :: Notes
, envComments :: Comments
@@ -117,6 +118,32 @@ mapD f xs =
in
concatMapM handler xs
+unwrapSDT :: NameSpaces -> Content -> Content
+unwrapSDT ns (Elem element)
+ | isElem ns "w" "sdt" element
+ , Just sdtContent <- findChildByName ns "w" "sdtContent" element
+ , child : _ <- elChildren sdtContent
+ = Elem child
+unwrapSDT _ content = content
+
+walkDocument' :: NameSpaces -> XMLC.Cursor -> XMLC.Cursor
+walkDocument' ns cur =
+ let modifiedCur = XMLC.modifyContent (unwrapSDT ns) cur
+ in
+ case XMLC.nextDF modifiedCur of
+ Just cur' -> walkDocument' ns cur'
+ Nothing -> XMLC.root modifiedCur
+
+walkDocument :: NameSpaces -> Element -> Maybe Element
+walkDocument ns element =
+ let cur = XMLC.fromContent (Elem element)
+ cur' = walkDocument' ns cur
+ in
+ case XMLC.toTree cur' of
+ Elem element' -> Just element'
+ _ -> Nothing
+
+
data Docx = Docx Document
deriving Show
@@ -298,7 +325,10 @@ archiveToDocument zf = do
docElem <- maybeToD $ (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
let namespaces = elemToNameSpaces docElem
bodyElem <- maybeToD $ findChildByName namespaces "w" "body" docElem
- body <- elemToBody namespaces bodyElem
+ let bodyElem' = case walkDocument namespaces bodyElem of
+ Just e -> e
+ Nothing -> bodyElem
+ body <- elemToBody namespaces bodyElem'
return $ Document namespaces body
elemToBody :: NameSpaces -> Element -> D Body
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
index f5f296712..65171d37a 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -51,7 +51,7 @@ import Data.Char (isAlphaNum, isDigit, isLetter)
import Data.Default (Default (..), def)
import Data.Foldable (for_)
import Data.List (intercalate, isPrefixOf)
-import Data.List.Split (wordsBy)
+import Data.List.Split (wordsBy, splitWhen)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Monoid (First (..), (<>))
@@ -70,12 +70,12 @@ import Text.Pandoc.Error
import Text.Pandoc.Logging
import Text.Pandoc.Options (
Extension (Ext_epub_html_exts, Ext_empty_paragraphs, Ext_native_divs,
- Ext_native_spans, Ext_raw_html),
+ Ext_native_spans, Ext_raw_html, Ext_line_blocks),
ReaderOptions (readerExtensions, readerStripComments),
extensionEnabled)
import Text.Pandoc.Parsing hiding ((<|>))
-import Text.Pandoc.Shared (addMetaField, crFilter, escapeURI, extractSpaces,
- safeRead, underlineSpan)
+import Text.Pandoc.Shared (addMetaField, blocksToInlines', crFilter, escapeURI,
+ extractSpaces, safeRead, underlineSpan)
import Text.Pandoc.Walk
import Text.Parsec.Error
import Text.TeXMath (readMathML, writeTeX)
@@ -191,6 +191,7 @@ block = do
, pHtml
, pHead
, pBody
+ , pLineBlock
, pDiv
, pPlain
, pFigure
@@ -377,6 +378,16 @@ pRawTag = do
then return mempty
else return $ renderTags' [tag]
+pLineBlock :: PandocMonad m => TagParser m Blocks
+pLineBlock = try $ do
+ guardEnabled Ext_line_blocks
+ _ <- pSatisfy $ tagOpen (=="div") (== [("class","line-block")])
+ ils <- trimInlines . mconcat <$> manyTill inline (pSatisfy (tagClose (=="div")))
+ let lns = map B.fromList $
+ splitWhen (== LineBreak) $ filter (/= SoftBreak) $
+ B.toList ils
+ return $ B.lineBlock lns
+
pDiv :: PandocMonad m => TagParser m Blocks
pDiv = try $ do
guardEnabled Ext_native_divs
@@ -588,8 +599,9 @@ pFigure = try $ do
skipMany pBlank
let pImg = (\x -> (Just x, Nothing)) <$>
(pOptInTag "p" pImage <* skipMany pBlank)
- pCapt = (\x -> (Nothing, Just x)) <$>
- (pInTags "figcaption" inline <* skipMany pBlank)
+ pCapt = (\x -> (Nothing, Just x)) <$> do
+ bs <- pInTags "figcaption" block
+ return $ blocksToInlines' $ B.toList bs
pSkip = (Nothing, Nothing) <$ pSatisfy (not . matchTagClose "figure")
res <- many (pImg <|> pCapt <|> pSkip)
let mbimg = msum $ map fst res
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index 6c5567ffd..e0972bb6c 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -1726,7 +1726,7 @@ inline = (mempty <$ comment)
<|> (guardEnabled Ext_literate_haskell *> symbol '|' *> doLHSverb)
<|> (str . (:[]) <$> primEscape)
<|> regularSymbol
- <|> (do res <- symbolIn "#^'`\"[]"
+ <|> (do res <- symbolIn "#^'`\"[]&"
pos <- getPosition
let s = T.unpack (untoken res)
report $ ParsingUnescaped s pos
diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs
index cc6abbfa5..a930652af 100644
--- a/src/Text/Pandoc/Readers/Org/Blocks.hs
+++ b/src/Text/Pandoc/Readers/Org/Blocks.hs
@@ -41,7 +41,6 @@ import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename,
originalLang, translateLang)
import Text.Pandoc.Builder (Blocks, Inlines)
-import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
import Text.Pandoc.Options
@@ -54,6 +53,9 @@ import Data.List (foldl', isPrefixOf)
import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Monoid ((<>))
+import qualified Text.Pandoc.Builder as B
+import qualified Text.Pandoc.Walk as Walk
+
--
-- parsing blocks
--
@@ -509,19 +511,18 @@ include :: PandocMonad m => OrgParser m (F Blocks)
include = try $ do
metaLineStart <* stringAnyCase "include:" <* skipSpaces
filename <- includeTarget
- blockType <- optionMaybe $ skipSpaces *> many1 alphaNum
- blocksParser <- case blockType of
- Just "example" ->
- return $ pure . B.codeBlock <$> parseRaw
- Just "export" -> do
- format <- skipSpaces *> many (noneOf "\n\r\t ")
- return $ pure . B.rawBlock format <$> parseRaw
- Just "src" -> do
- language <- skipSpaces *> many (noneOf "\n\r\t ")
- let attr = (mempty, [language], mempty)
- return $ pure . B.codeBlockWith attr <$> parseRaw
- _ -> return $ pure . B.fromList <$> blockList
- anyLine
+ includeArgs <- many (try $ skipSpaces *> many1 alphaNum)
+ params <- keyValues
+ blocksParser <- case includeArgs of
+ ("example" : _) -> return $ pure . B.codeBlock <$> parseRaw
+ ["export"] -> return . returnF $ B.fromList []
+ ("export" : format : []) -> return $ pure . B.rawBlock format <$> parseRaw
+ ("src" : rest) -> do
+ let attr = case rest of
+ [lang] -> (mempty, [lang], mempty)
+ _ -> nullAttr
+ return $ pure . B.codeBlockWith attr <$> parseRaw
+ _ -> return $ return . B.fromList . blockFilter params <$> blockList
insertIncludedFileF blocksParser ["."] filename
where
includeTarget :: PandocMonad m => OrgParser m FilePath
@@ -532,6 +533,28 @@ include = try $ do
parseRaw :: PandocMonad m => OrgParser m String
parseRaw = many anyChar
+ blockFilter :: [(String, String)] -> [Block] -> [Block]
+ blockFilter params blks =
+ let minlvl = lookup "minlevel" params
+ in case (minlvl >>= safeRead :: Maybe Int) of
+ Nothing -> blks
+ Just lvl -> let levels = Walk.query headerLevel blks
+ -- CAVE: partial function in else
+ curMin = if null levels then 0 else minimum levels
+ in Walk.walk (shiftHeader (curMin - lvl)) blks
+
+ headerLevel :: Block -> [Int]
+ headerLevel (Header lvl _attr _content) = [lvl]
+ headerLevel _ = []
+
+ shiftHeader :: Int -> Block -> Block
+ shiftHeader shift blk =
+ if shift <= 0
+ then blk
+ else case blk of
+ (Header lvl attr content) -> Header (lvl - shift) attr content
+ _ -> blk
+
rawExportLine :: PandocMonad m => OrgParser m Blocks
rawExportLine = try $ do
metaLineStart
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index 6a6fabf1d..a33196cbe 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -87,6 +87,15 @@ instance ToLuaStack (Stringify Citation) where
addValue "citationNoteNum" $ citationNoteNum cit
addValue "citationHash" $ citationHash cit
+-- | Key-value pair, pushed as a table with @a@ as the only key and @v@ as the
+-- associated value.
+newtype KeyValue a b = KeyValue (a, b)
+
+instance (ToLuaStack a, ToLuaStack b) => ToLuaStack (KeyValue a b) where
+ push (KeyValue (k, v)) = do
+ newtable
+ addValue k v
+
data PandocLuaException = PandocLuaException String
deriving (Show, Typeable)
@@ -165,7 +174,8 @@ blockToCustom (OrderedList (num,sty,delim) items) =
callFunc "OrderedList" (map Stringify items) num (show sty) (show delim)
blockToCustom (DefinitionList items) =
- callFunc "DefinitionList" (map (Stringify *** map Stringify) items)
+ callFunc "DefinitionList"
+ (map (KeyValue . (Stringify *** map Stringify)) items)
blockToCustom (Div attr items) =
callFunc "Div" (Stringify items) (attrToMap attr)
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index 633f42442..0a4130ca4 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -121,9 +121,18 @@ description meta' = do
Just (MetaString s) -> [el "lang" $ iso639 s]
_ -> []
where iso639 = takeWhile (/= '-') -- Convert BCP 47 to ISO 639
+ let coverimage url = do
+ let img = Image nullAttr mempty (url, "")
+ im <- insertImage InlineImage img
+ return [el "coverpage" im]
+ coverpage <- case lookupMeta "cover-image" meta' of
+ Just (MetaInlines [Str s]) -> coverimage s
+ Just (MetaString s) -> coverimage s
+ _ -> return []
return $ el "description"
[ el "title-info" (genre : (bt ++ as ++ dd ++ lang))
- , el "document-info" [ el "program-used" "pandoc" ] -- FIXME: +version
+ , el "document-info" ([ el "program-used" "pandoc" ] -- FIXME: +version
+ ++ coverpage)
]
booktitle :: PandocMonad m => Meta -> FBM m [Content]
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index d6ccc1512..87ce65586 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -699,10 +699,9 @@ blockToLaTeX (Table caption aligns widths heads rows) = do
then return empty
else ($$ text "\\endfirsthead") <$> toHeaders heads
head' <- if all null heads
- then return empty
+ then return "\\toprule"
-- avoid duplicate notes in head and firsthead:
- else ($$ text "\\endhead") <$>
- toHeaders (if isEmpty firsthead
+ else toHeaders (if isEmpty firsthead
then heads
else walk removeNote heads)
let capt = if isEmpty captionText
@@ -717,8 +716,8 @@ blockToLaTeX (Table caption aligns widths heads rows) = do
-- the @{} removes extra space at beginning and end
$$ capt
$$ firsthead
- $$ (if all null heads then "\\toprule" else empty)
$$ head'
+ $$ "\\endhead"
$$ vcat rows'
$$ "\\bottomrule"
$$ "\\end{longtable}"
diff --git a/src/Text/Pandoc/Writers/Powerpoint.hs b/src/Text/Pandoc/Writers/Powerpoint.hs
index d5627f51c..ab3b2eabf 100644
--- a/src/Text/Pandoc/Writers/Powerpoint.hs
+++ b/src/Text/Pandoc/Writers/Powerpoint.hs
@@ -86,6 +86,9 @@ writePowerpoint opts (Pandoc meta blks) = do
, envDistArchive = distArchive
, envUTCTime = utctime
, envOpts = opts
+ , envSlideLevel = case writerSlideLevel opts of
+ Just n -> n
+ Nothing -> 2
}
runP env def $ do pres <- blocksToPresentation blks'
archv <- presentationToArchive pres
diff --git a/stack.lts9.yaml b/stack.lts9.yaml
new file mode 100644
index 000000000..43cc9f511
--- /dev/null
+++ b/stack.lts9.yaml
@@ -0,0 +1,29 @@
+flags:
+ pandoc:
+ trypandoc: false
+ embed_data_files: true
+ old-locale: false
+ network-uri: true
+ pandoc-citeproc:
+ bibutils: true
+ embed_data_files: true
+ unicode_collation: false
+ test_citeproc: false
+ debug: false
+packages:
+- '.'
+extra-deps:
+- pandoc-types-1.17.3
+- hslua-0.9.3
+- hslua-module-text-0.1.2
+- skylighting-0.5
+- texmath-0.10.1
+- cmark-gfm-0.1.1
+- QuickCheck-2.10.0.1
+- tasty-quickcheck-0.9.1
+- doctemplates-0.2.1
+- haddock-library-1.4.3
+- tagsoup-0.14.2
+- hs-bibutils-6.2.0.1
+- pandoc-citeproc-0.12.2.1
+resolver: lts-9.14
diff --git a/stack.pkg.yaml b/stack.pkg.yaml
deleted file mode 100644
index 450c7c3ae..000000000
--- a/stack.pkg.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-flags:
- pandoc:
- trypandoc: false
- embed_data_files: true
- old-locale: false
- network-uri: true
- pandoc-citeproc:
- bibutils: true
- embed_data_files: true
- unicode_collation: false
- test_citeproc: false
- debug: false
-packages:
-- '.'
-extra-deps: []
-resolver: lts-10.1
diff --git a/stack.yaml b/stack.yaml
index e04468cfc..60ecb0627 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,9 +1,17 @@
flags:
pandoc:
trypandoc: false
- embed_data_files: false
+ embed_data_files: true
old-locale: false
network-uri: true
+ pandoc-citeproc:
+ bibutils: true
+ embed_data_files: true
+ unicode_collation: false
+ test_citeproc: false
+ debug: false
packages:
-extra-deps: []
+- '.'
+extra-deps:
+- pandoc-citeproc-0.12.2.1
resolver: lts-10.1
diff --git a/test/Tests/Old.hs b/test/Tests/Old.hs
index bbd51ee98..b82251a56 100644
--- a/test/Tests/Old.hs
+++ b/test/Tests/Old.hs
@@ -162,6 +162,12 @@ tests = [ testGroup "markdown"
[ test "reader" ["-r", "creole", "-w", "native", "-s"]
"creole-reader.txt" "creole-reader.native"
]
+ , testGroup "custom writer"
+ [ test "basic" ["-f", "native", "-t", "../data/sample.lua"]
+ "testsuite.native" "writer.custom"
+ , test "tables" ["-f", "native", "-t", "../data/sample.lua"]
+ "tables.native" "tables.custom"
+ ]
]
-- makes sure file is fully closed after reading
diff --git a/test/Tests/Readers/Docx.hs b/test/Tests/Readers/Docx.hs
index 6d91c36ae..5710a388f 100644
--- a/test/Tests/Readers/Docx.hs
+++ b/test/Tests/Readers/Docx.hs
@@ -171,6 +171,10 @@ tests = [ testGroup "inlines"
"inline code in subscript and superscript"
"docx/verbatim_subsuper.docx"
"docx/verbatim_subsuper.native"
+ , testCompare
+ "inlines inside of Structured Document Tags"
+ "docx/sdt_elements.docx"
+ "docx/sdt_elements.native"
]
, testGroup "blocks"
[ testCompare
diff --git a/test/Tests/Readers/Org.hs b/test/Tests/Readers/Org.hs
index dbd56c880..de7f14e32 100644
--- a/test/Tests/Readers/Org.hs
+++ b/test/Tests/Readers/Org.hs
@@ -1,1871 +1,16 @@
{-# LANGUAGE OverloadedStrings #-}
module Tests.Readers.Org (tests) where
-import Data.List (intersperse)
-import Data.Text (Text)
-import qualified Data.Text as T
-import Test.Tasty
-import Tests.Helpers
-import Text.Pandoc
-import Text.Pandoc.Builder
-import Text.Pandoc.Shared (underlineSpan)
-
-org :: Text -> Pandoc
-org = purely $ readOrg def{ readerExtensions = getDefaultExtensions "org" }
-
-orgSmart :: Text -> Pandoc
-orgSmart = purely $ readOrg def { readerExtensions =
- enableExtension Ext_smart $ getDefaultExtensions "org" }
-
-infix 4 =:
-(=:) :: ToString c
- => String -> (Text, c) -> TestTree
-(=:) = test org
-
-spcSep :: [Inlines] -> Inlines
-spcSep = mconcat . intersperse space
-
-simpleTable' :: Int
- -> [Blocks]
- -> [[Blocks]]
- -> Blocks
-simpleTable' n = table "" (replicate n (AlignDefault, 0.0))
-
--- | Create a span for the given tag.
-tagSpan :: String -> Inlines
-tagSpan t = spanWith ("", ["tag"], [("tag-name", t)]) . smallcaps $ str t
+import Test.Tasty (TestTree, testGroup)
+import qualified Tests.Readers.Org.Block as Block
+import qualified Tests.Readers.Org.Directive as Directive
+import qualified Tests.Readers.Org.Inline as Inline
+import qualified Tests.Readers.Org.Meta as Meta
tests :: [TestTree]
tests =
- [ testGroup "Inlines" $
- [ "Plain String" =:
- "Hello, World" =?>
- para (spcSep [ "Hello,", "World" ])
-
- , "Emphasis" =:
- "/Planet Punk/" =?>
- para (emph . spcSep $ ["Planet", "Punk"])
-
- , "Strong" =:
- "*Cider*" =?>
- para (strong "Cider")
-
- , "Strong Emphasis" =:
- "/*strength*/" =?>
- para (emph . strong $ "strength")
-
- , "Emphasized Strong preceded by space" =:
- " */super/*" =?>
- para (strong . emph $ "super")
-
- , "Underline" =:
- "_underline_" =?>
- para (underlineSpan $ "underline")
-
- , "Strikeout" =:
- "+Kill Bill+" =?>
- para (strikeout . spcSep $ [ "Kill", "Bill" ])
-
- , "Verbatim" =:
- "=Robot.rock()=" =?>
- para (code "Robot.rock()")
-
- , "Code" =:
- "~word for word~" =?>
- para (code "word for word")
-
- , "Math $..$" =:
- "$E=mc^2$" =?>
- para (math "E=mc^2")
-
- , "Math $$..$$" =:
- "$$E=mc^2$$" =?>
- para (displayMath "E=mc^2")
-
- , "Math \\[..\\]" =:
- "\\[E=ℎν\\]" =?>
- para (displayMath "E=ℎν")
-
- , "Math \\(..\\)" =:
- "\\(σ_x σ_p ≥ \\frac{ℏ}{2}\\)" =?>
- para (math "σ_x σ_p ≥ \\frac{ℏ}{2}")
-
- , "Symbol" =:
- "A * symbol" =?>
- para (str "A" <> space <> str "*" <> space <> "symbol")
-
- , "Superscript simple expression" =:
- "2^-λ" =?>
- para (str "2" <> superscript "-λ")
-
- , "Superscript multi char" =:
- "2^{n-1}" =?>
- para (str "2" <> superscript "n-1")
-
- , "Subscript simple expression" =:
- "a_n" =?>
- para (str "a" <> subscript "n")
-
- , "Subscript multi char" =:
- "a_{n+1}" =?>
- para (str "a" <> subscript "n+1")
-
- , "Linebreak" =:
- "line \\\\ \nbreak" =?>
- para ("line" <> linebreak <> "break")
-
- , "Inline note" =:
- "[fn::Schreib mir eine E-Mail]" =?>
- para (note $ para "Schreib mir eine E-Mail")
-
- , "Markup-chars not occuring on word break are symbols" =:
- T.unlines [ "this+that+ +so+on"
- , "seven*eight* nine*"
- , "+not+funny+"
- ] =?>
- para ("this+that+ +so+on" <> softbreak <>
- "seven*eight* nine*" <> softbreak <>
- strikeout "not+funny")
-
- , "No empty markup" =:
- "// ** __ <> == ~~ $$" =?>
- para (spcSep [ "//", "**", "__", "<>", "==", "~~", "$$" ])
-
- , "Adherence to Org's rules for markup borders" =:
- "/t/& a/ / ./r/ (*l*) /e/! /b/." =?>
- para (spcSep [ emph $ "t/&" <> space <> "a"
- , "/"
- , "./r/"
- , "(" <> strong "l" <> ")"
- , emph "e" <> "!"
- , emph "b" <> "."
- ])
-
- , "Quotes are allowed border chars" =:
- "/'yep/ *sure\"*" =?>
- para (emph "'yep" <> space <> strong "sure\"")
-
- , "Spaces are forbidden border chars" =:
- "/nada /" =?>
- para "/nada /"
-
- , "Markup should work properly after a blank line" =:
- T.unlines ["foo", "", "/bar/"] =?>
- (para $ text "foo") <> (para $ emph $ text "bar")
-
- , "Inline math must stay within three lines" =:
- T.unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
- para ((math "a\nb\nc") <> softbreak <>
- "$d" <> softbreak <> "e" <> softbreak <>
- "f" <> softbreak <> "g$")
-
- , "Single-character math" =:
- "$a$ $b$! $c$?" =?>
- para (spcSep [ math "a"
- , "$b$!"
- , (math "c") <> "?"
- ])
-
- , "Markup may not span more than two lines" =:
- "/this *is +totally\nnice+ not*\nemph/" =?>
- para ("/this" <> space <>
- strong ("is" <> space <>
- strikeout ("totally" <>
- softbreak <> "nice") <>
- space <> "not") <>
- softbreak <> "emph/")
-
- , "Sub- and superscript expressions" =:
- T.unlines [ "a_(a(b)(c)d)"
- , "e^(f(g)h)"
- , "i_(jk)l)"
- , "m^()n"
- , "o_{p{q{}r}}"
- , "s^{t{u}v}"
- , "w_{xy}z}"
- , "1^{}2"
- , "3_{{}}"
- , "4^(a(*b(c*)d))"
- ] =?>
- para (mconcat $ intersperse softbreak
- [ "a" <> subscript "(a(b)(c)d)"
- , "e" <> superscript "(f(g)h)"
- , "i" <> (subscript "(jk)") <> "l)"
- , "m" <> (superscript "()") <> "n"
- , "o" <> subscript "p{q{}r}"
- , "s" <> superscript "t{u}v"
- , "w" <> (subscript "xy") <> "z}"
- , "1" <> (superscript "") <> "2"
- , "3" <> subscript "{}"
- , "4" <> superscript ("(a(" <> strong "b(c" <> ")d))")
- ])
- , "Verbatim text can contain equal signes (=)" =:
- "=is_subst = True=" =?>
- para (code "is_subst = True")
-
- , testGroup "Images"
- [ "Image" =:
- "[[./sunset.jpg]]" =?>
- (para $ image "./sunset.jpg" "" "")
-
- , "Image with explicit file: prefix" =:
- "[[file:sunrise.jpg]]" =?>
- (para $ image "sunrise.jpg" "" "")
-
- , "Multiple images within a paragraph" =:
- T.unlines [ "[[file:sunrise.jpg]]"
- , "[[file:sunset.jpg]]"
- ] =?>
- (para $ (image "sunrise.jpg" "" "")
- <> softbreak
- <> (image "sunset.jpg" "" ""))
-
- , "Image with html attributes" =:
- T.unlines [ "#+ATTR_HTML: :width 50%"
- , "[[file:guinea-pig.gif]]"
- ] =?>
- (para $ imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "")
- ]
-
- , "Explicit link" =:
- "[[http://zeitlens.com/][pseudo-random /nonsense/]]" =?>
- (para $ link "http://zeitlens.com/" ""
- ("pseudo-random" <> space <> emph "nonsense"))
-
- , "Self-link" =:
- "[[http://zeitlens.com/]]" =?>
- (para $ link "http://zeitlens.com/" "" "http://zeitlens.com/")
-
- , "Absolute file link" =:
- "[[/url][hi]]" =?>
- (para $ link "file:///url" "" "hi")
-
- , "Link to file in parent directory" =:
- "[[../file.txt][moin]]" =?>
- (para $ link "../file.txt" "" "moin")
-
- , "Empty link (for gitit interop)" =:
- "[[][New Link]]" =?>
- (para $ link "" "" "New Link")
-
- , "Image link" =:
- "[[sunset.png][file:dusk.svg]]" =?>
- (para $ link "sunset.png" "" (image "dusk.svg" "" ""))
-
- , "Image link with non-image target" =:
- "[[http://example.com][./logo.png]]" =?>
- (para $ link "http://example.com" "" (image "./logo.png" "" ""))
-
- , "Plain link" =:
- "Posts on http://zeitlens.com/ can be funny at times." =?>
- (para $ spcSep [ "Posts", "on"
- , link "http://zeitlens.com/" "" "http://zeitlens.com/"
- , "can", "be", "funny", "at", "times."
- ])
-
- , "Angle link" =:
- "Look at <http://moltkeplatz.de> for fnords." =?>
- (para $ spcSep [ "Look", "at"
- , link "http://moltkeplatz.de" "" "http://moltkeplatz.de"
- , "for", "fnords."
- ])
-
- , "Absolute file link" =:
- "[[file:///etc/passwd][passwd]]" =?>
- (para $ link "file:///etc/passwd" "" "passwd")
-
- , "File link" =:
- "[[file:target][title]]" =?>
- (para $ link "target" "" "title")
-
- , "Anchor" =:
- "<<anchor>> Link here later." =?>
- (para $ spanWith ("anchor", [], []) mempty <>
- "Link" <> space <> "here" <> space <> "later.")
-
- , "Inline code block" =:
- "src_emacs-lisp{(message \"Hello\")}" =?>
- (para $ codeWith ( ""
- , [ "commonlisp" ]
- , [ ("org-language", "emacs-lisp") ])
- "(message \"Hello\")")
-
- , "Inline code block with arguments" =:
- "src_sh[:export both :results output]{echo 'Hello, World'}" =?>
- (para $ codeWith ( ""
- , [ "bash" ]
- , [ ("org-language", "sh")
- , ("export", "both")
- , ("results", "output")
- ]
- )
- "echo 'Hello, World'")
-
- , "Inline code block with toggle" =:
- "src_sh[:toggle]{echo $HOME}" =?>
- (para $ codeWith ( ""
- , [ "bash" ]
- , [ ("org-language", "sh")
- , ("toggle", "yes")
- ]
- )
- "echo $HOME")
-
- , "Citation" =:
- "[@nonexistent]" =?>
- let citation = Citation
- { citationId = "nonexistent"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0}
- in (para $ cite [citation] "[@nonexistent]")
-
- , "Citation containing text" =:
- "[see @item1 p. 34-35]" =?>
- let citation = Citation
- { citationId = "item1"
- , citationPrefix = [Str "see"]
- , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0}
- in (para $ cite [citation] "[see @item1 p. 34-35]")
-
- , "Org-ref simple citation" =:
- "cite:pandoc" =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc")
-
- , "Org-ref simple citation with underscores" =:
- "cite:pandoc_org_ref" =?>
- let citation = Citation
- { citationId = "pandoc_org_ref"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc_org_ref")
-
- , "Org-ref simple citation succeeded by comma" =:
- "cite:pandoc," =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc" <> str ",")
-
- , "Org-ref simple citation succeeded by dot" =:
- "cite:pandoc." =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc" <> str ".")
-
- , "Org-ref simple citation succeeded by colon" =:
- "cite:pandoc:" =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = AuthorInText
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "cite:pandoc" <> str ":")
-
- , "Org-ref simple citep citation" =:
- "citep:pandoc" =?>
- let citation = Citation
- { citationId = "pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "citep:pandoc")
-
- , "Org-ref extended citation" =:
- "[[citep:Dominik201408][See page 20::, for example]]" =?>
- let citation = Citation
- { citationId = "Dominik201408"
- , citationPrefix = toList "See page 20"
- , citationSuffix = toList ", for example"
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
-
- , testGroup "Berkeley-style citations" $
- let pandocCite = Citation
- { citationId = "Pandoc"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- pandocInText = pandocCite { citationMode = AuthorInText }
- dominikCite = Citation
- { citationId = "Dominik201408"
- , citationPrefix = mempty
- , citationSuffix = mempty
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
- dominikInText = dominikCite { citationMode = AuthorInText }
- in [
- "Berkeley-style in-text citation" =:
- "See @Dominik201408." =?>
- (para $ "See "
- <> cite [dominikInText] "@Dominik201408"
- <> ".")
-
- , "Berkeley-style parenthetical citation list" =:
- "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
- let pandocCite' = pandocCite {
- citationPrefix = toList "also"
- , citationSuffix = toList "and others"
- }
- dominikCite' = dominikCite {
- citationPrefix = toList "see"
- }
- in (para $ cite [dominikCite', pandocCite'] "")
-
- , "Berkeley-style plain citation list" =:
- "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
- let pandocCite' = pandocInText {
- citationPrefix = toList "and"
- }
- in (para $ "See "
- <> cite [dominikInText] ""
- <> "," <> space
- <> cite [pandocCite'] ""
- <> "," <> space <> "and others")
- ]
-
- , "Inline LaTeX symbol" =:
- "\\dots" =?>
- para "…"
-
- , "Inline LaTeX command" =:
- "\\textit{Emphasised}" =?>
- para (emph "Emphasised")
-
- , "Inline LaTeX command with spaces" =:
- "\\emph{Emphasis mine}" =?>
- para (emph "Emphasis mine")
-
- , "Inline LaTeX math symbol" =:
- "\\tau" =?>
- para (emph "τ")
-
- , "Unknown inline LaTeX command" =:
- "\\notacommand{foo}" =?>
- para (rawInline "latex" "\\notacommand{foo}")
-
- , "Export snippet" =:
- "@@html:<kbd>M-x org-agenda</kbd>@@" =?>
- para (rawInline "html" "<kbd>M-x org-agenda</kbd>")
-
- , "MathML symbol in LaTeX-style" =:
- "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: '\\nbsp')." =?>
- para ("There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: ' ').")
-
- , "MathML symbol in LaTeX-style, including braces" =:
- "\\Aacute{}stor" =?>
- para "Ástor"
-
- , "MathML copy sign" =:
- "\\copy" =?>
- para "©"
-
- , "MathML symbols, space separated" =:
- "\\ForAll \\Auml" =?>
- para "∀ Ä"
-
- , "LaTeX citation" =:
- "\\cite{Coffee}" =?>
- let citation = Citation
- { citationId = "Coffee"
- , citationPrefix = []
- , citationSuffix = []
- , citationMode = NormalCitation
- , citationNoteNum = 0
- , citationHash = 0}
- in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
-
- , "Macro" =:
- T.unlines [ "#+MACRO: HELLO /Hello, $1/"
- , "{{{HELLO(World)}}}"
- ] =?>
- para (emph "Hello, World")
-
- , "Macro repeting its argument" =:
- T.unlines [ "#+MACRO: HELLO $1$1"
- , "{{{HELLO(moin)}}}"
- ] =?>
- para "moinmoin"
-
- , "Macro called with too few arguments" =:
- T.unlines [ "#+MACRO: HELLO Foo $1 $2 Bar"
- , "{{{HELLO()}}}"
- ] =?>
- para "Foo Bar"
- ]
-
- , testGroup "Meta Information" $
- [ "Comment" =:
- "# Nothing to see here" =?>
- (mempty::Blocks)
-
- , "Not a comment" =:
- "#-tag" =?>
- para "#-tag"
-
- , "Comment surrounded by Text" =:
- T.unlines [ "Before"
- , "# Comment"
- , "After"
- ] =?>
- mconcat [ para "Before"
- , para "After"
- ]
-
- , "Title" =:
- "#+TITLE: Hello, World" =?>
- let titleInline = toList $ "Hello," <> space <> "World"
- meta = setMeta "title" (MetaInlines titleInline) $ nullMeta
- in Pandoc meta mempty
-
- , "Author" =:
- "#+author: Albert /Emacs-Fanboy/ Krewinkel" =?>
- let author = toList . spcSep $ [ "Albert", emph "Emacs-Fanboy", "Krewinkel" ]
- meta = setMeta "author" (MetaList [MetaInlines author]) $ nullMeta
- in Pandoc meta mempty
-
- , "Multiple authors" =:
- "#+author: James Dewey Watson, Francis Harry Compton Crick " =?>
- let watson = MetaInlines $ toList "James Dewey Watson"
- crick = MetaInlines $ toList "Francis Harry Compton Crick"
- meta = setMeta "author" (MetaList [watson, crick]) $ nullMeta
- in Pandoc meta mempty
-
- , "Date" =:
- "#+Date: Feb. *28*, 2014" =?>
- let date = toList . spcSep $ [ "Feb.", (strong "28") <> ",", "2014" ]
- meta = setMeta "date" (MetaInlines date) $ nullMeta
- in Pandoc meta mempty
-
- , "Description" =:
- "#+DESCRIPTION: Explanatory text" =?>
- let description = "Explanatory text"
- meta = setMeta "description" (MetaString description) $ nullMeta
- in Pandoc meta mempty
-
- , "Properties drawer" =:
- T.unlines [ " :PROPERTIES:"
- , " :setting: foo"
- , " :END:"
- ] =?>
- (mempty::Blocks)
-
- , "LaTeX_headers options are translated to header-includes" =:
- "#+LaTeX_header: \\usepackage{tikz}" =?>
- let latexInlines = rawInline "latex" "\\usepackage{tikz}"
- inclList = MetaList [MetaInlines (toList latexInlines)]
- meta = setMeta "header-includes" inclList nullMeta
- in Pandoc meta mempty
-
- , "LaTeX_class option is translated to documentclass" =:
- "#+LATEX_CLASS: article" =?>
- let meta = setMeta "documentclass" (MetaString "article") nullMeta
- in Pandoc meta mempty
-
- , "LaTeX_class_options is translated to classoption" =:
- "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
- let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
- in Pandoc meta mempty
-
- , "LaTeX_class_options is translated to classoption" =:
- "#+html_head: <meta/>" =?>
- let html = rawInline "html" "<meta/>"
- inclList = MetaList [MetaInlines (toList html)]
- meta = setMeta "header-includes" inclList nullMeta
- in Pandoc meta mempty
-
- , "later meta definitions take precedence" =:
- T.unlines [ "#+AUTHOR: this will not be used"
- , "#+author: Max"
- ] =?>
- let author = MetaInlines [Str "Max"]
- meta = setMeta "author" (MetaList [author]) $ nullMeta
- in Pandoc meta mempty
-
- , "Logbook drawer" =:
- T.unlines [ " :LogBook:"
- , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
- , " :END:"
- ] =?>
- (mempty::Blocks)
-
- , "Drawer surrounded by text" =:
- T.unlines [ "Before"
- , ":PROPERTIES:"
- , ":END:"
- , "After"
- ] =?>
- para "Before" <> para "After"
-
- , "Drawer markers must be the only text in the line" =:
- T.unlines [ " :LOGBOOK: foo"
- , " :END: bar"
- ] =?>
- para (":LOGBOOK: foo" <> softbreak <> ":END: bar")
-
- , "Drawers can be arbitrary" =:
- T.unlines [ ":FOO:"
- , "/bar/"
- , ":END:"
- ] =?>
- divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar")
-
- , "Anchor reference" =:
- T.unlines [ "<<link-here>> Target."
- , ""
- , "[[link-here][See here!]]"
- ] =?>
- (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
- para (link "#link-here" "" ("See" <> space <> "here!")))
-
- , "Search links are read as emph" =:
- "[[Wally][Where's Wally?]]" =?>
- (para (emph $ "Where's" <> space <> "Wally?"))
-
- , "Link to nonexistent anchor" =:
- T.unlines [ "<<link-here>> Target."
- , ""
- , "[[link$here][See here!]]"
- ] =?>
- (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
- para (emph ("See" <> space <> "here!")))
-
- , "Link abbreviation" =:
- T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
- , "[[wp:Org_mode][Wikipedia on Org-mode]]"
- ] =?>
- (para (link "https://en.wikipedia.org/wiki/Org_mode" ""
- ("Wikipedia" <> space <> "on" <> space <> "Org-mode")))
-
- , "Link abbreviation, defined after first use" =:
- T.unlines [ "[[zl:non-sense][Non-sense articles]]"
- , "#+LINK: zl http://zeitlens.com/tags/%s.html"
- ] =?>
- (para (link "http://zeitlens.com/tags/non-sense.html" ""
- ("Non-sense" <> space <> "articles")))
-
- , "Link abbreviation, URL encoded arguments" =:
- T.unlines [ "#+link: expl http://example.com/%h/foo"
- , "[[expl:Hello, World!][Moin!]]"
- ] =?>
- (para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!"))
-
- , "Link abbreviation, append arguments" =:
- T.unlines [ "#+link: expl http://example.com/"
- , "[[expl:foo][bar]]"
- ] =?>
- (para (link "http://example.com/foo" "" "bar"))
-
-
- , testGroup "export options"
-
- [ "disable simple sub/superscript syntax" =:
- T.unlines [ "#+OPTIONS: ^:nil"
- , "a^b"
- ] =?>
- para "a^b"
-
- , "directly select drawers to be exported" =:
- T.unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
- , ":IMPORTANT:"
- , "23"
- , ":END:"
- , ":BORING:"
- , "very boring"
- , ":END:"
- ] =?>
- divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23")
-
- , "exclude drawers from being exported" =:
- T.unlines [ "#+OPTIONS: d:(not \"BORING\")"
- , ":IMPORTANT:"
- , "5"
- , ":END:"
- , ":BORING:"
- , "very boring"
- , ":END:"
- ] =?>
- divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5")
-
- , "don't include archive trees" =:
- T.unlines [ "#+OPTIONS: arch:nil"
- , "* old :ARCHIVE:"
- ] =?>
- (mempty ::Blocks)
-
- , "include complete archive trees" =:
- T.unlines [ "#+OPTIONS: arch:t"
- , "* old :ARCHIVE:"
- , " boring"
- ] =?>
- mconcat [ headerWith ("old", [], mempty) 1
- ("old" <> space <> tagSpan "ARCHIVE")
- , para "boring"
- ]
-
- , "include archive tree header only" =:
- T.unlines [ "#+OPTIONS: arch:headline"
- , "* old :ARCHIVE:"
- , " boring"
- ] =?>
- headerWith ("old", [], mempty) 1 ("old" <> space <> tagSpan "ARCHIVE")
-
- , "limit headline depth" =:
- T.unlines [ "#+OPTIONS: H:2"
- , "* top-level section"
- , "** subsection"
- , "*** list item 1"
- , "*** list item 2"
- ] =?>
- mconcat [ headerWith ("top-level-section", [], []) 1 "top-level section"
- , headerWith ("subsection", [], []) 2 "subsection"
- , orderedList [ para "list item 1", para "list item 2" ]
- ]
-
- , "turn all headlines into lists" =:
- T.unlines [ "#+OPTIONS: H:0"
- , "first block"
- , "* top-level section 1"
- , "** subsection"
- , "* top-level section 2"
- ] =?>
- mconcat [ para "first block"
- , orderedList
- [ (para "top-level section 1" <>
- orderedList [ para "subsection" ])
- , para "top-level section 2" ]
- ]
-
- , "preserve linebreaks as hard breaks" =:
- T.unlines [ "#+OPTIONS: \\n:t"
- , "first"
- , "second"
- ] =?>
- para ("first" <> linebreak <> "second")
-
- , "disable author export" =:
- T.unlines [ "#+OPTIONS: author:nil"
- , "#+AUTHOR: ShyGuy"
- ] =?>
- Pandoc nullMeta mempty
-
- , "disable creator export" =:
- T.unlines [ "#+OPTIONS: creator:nil"
- , "#+creator: The Architect"
- ] =?>
- Pandoc nullMeta mempty
-
- , "disable email export" =:
- T.unlines [ "#+OPTIONS: email:nil"
- , "#+email: no-mail-please@example.com"
- ] =?>
- Pandoc nullMeta mempty
-
- , "disable inclusion of todo keywords" =:
- T.unlines [ "#+OPTIONS: todo:nil"
- , "** DONE todo export"
- ] =?>
- headerWith ("todo-export", [], []) 2 "todo export"
-
- , "remove tags from headlines" =:
- T.unlines [ "#+OPTIONS: tags:nil"
- , "* Headline :hello:world:"
- ] =?>
- headerWith ("headline", [], mempty) 1 "Headline"
- ]
- ]
-
- , testGroup "Basic Blocks" $
- [ "Paragraph" =:
- "Paragraph\n" =?>
- para "Paragraph"
-
- , testGroup "headers" $
- [ "First Level Header" =:
- "* Headline\n" =?>
- headerWith ("headline", [], []) 1 "Headline"
-
- , "Third Level Header" =:
- "*** Third Level Headline\n" =?>
- headerWith ("third-level-headline", [], [])
- 3
- ("Third" <> space <> "Level" <> space <> "Headline")
-
- , "Compact Headers with Paragraph" =:
- T.unlines [ "* First Level"
- , "** Second Level"
- , " Text"
- ] =?>
- mconcat [ headerWith ("first-level", [], [])
- 1
- ("First" <> space <> "Level")
- , headerWith ("second-level", [], [])
- 2
- ("Second" <> space <> "Level")
- , para "Text"
- ]
-
- , "Separated Headers with Paragraph" =:
- T.unlines [ "* First Level"
- , ""
- , "** Second Level"
- , ""
- , " Text"
- ] =?>
- mconcat [ headerWith ("first-level", [], [])
- 1
- ("First" <> space <> "Level")
- , headerWith ("second-level", [], [])
- 2
- ("Second" <> space <> "Level")
- , para "Text"
- ]
-
- , "Headers not preceded by a blank line" =:
- T.unlines [ "** eat dinner"
- , "Spaghetti and meatballs tonight."
- , "** walk dog"
- ] =?>
- mconcat [ headerWith ("eat-dinner", [], [])
- 2
- ("eat" <> space <> "dinner")
- , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
- , headerWith ("walk-dog", [], [])
- 2
- ("walk" <> space <> "dog")
- ]
-
- , testGroup "Todo keywords"
- [ "Header with known todo keyword" =:
- "* TODO header" =?>
- let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO"
- in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
-
- , "Header marked as done" =:
- "* DONE header" =?>
- let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE"
- in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
-
- , "Header with unknown todo keyword" =:
- "* WAITING header" =?>
- headerWith ("waiting-header", [], []) 1 "WAITING header"
-
- , "Custom todo keywords" =:
- T.unlines [ "#+TODO: WAITING CANCELLED"
- , "* WAITING compile"
- , "* CANCELLED lunch"
- ] =?>
- let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
- doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
- in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
- <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
-
- , "Custom todo keywords with multiple done-states" =:
- T.unlines [ "#+TODO: WAITING | DONE CANCELLED "
- , "* WAITING compile"
- , "* CANCELLED lunch"
- , "* DONE todo-feature"
- ] =?>
- let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
- cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
- done = spanWith ("", ["done", "DONE"], []) "DONE"
- in headerWith ("compile", [], []) 1 (waiting <> space <> "compile")
- <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch")
- <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature")
- ]
-
- , "Tagged headers" =:
- T.unlines [ "* Personal :PERSONAL:"
- , "** Call Mom :@PHONE:"
- , "** Call John :@PHONE:JOHN: "
- ] =?>
- mconcat [ headerWith ("personal", [], [])
- 1
- ("Personal " <> tagSpan "PERSONAL")
- , headerWith ("call-mom", [], [])
- 2
- ("Call Mom " <> tagSpan "@PHONE")
- , headerWith ("call-john", [], [])
- 2
- ("Call John " <> tagSpan "@PHONE" <> "\160" <> tagSpan "JOHN")
- ]
-
- , "Untagged header containing colons" =:
- "* This: is not: tagged" =?>
- headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
-
- , "Header starting with strokeout text" =:
- T.unlines [ "foo"
- , ""
- , "* +thing+ other thing"
- ] =?>
- mconcat [ para "foo"
- , headerWith ("thing-other-thing", [], [])
- 1
- ((strikeout "thing") <> " other thing")
- ]
-
- , "Comment Trees" =:
- T.unlines [ "* COMMENT A comment tree"
- , " Not much going on here"
- , "** This will be dropped"
- , "* Comment tree above"
- ] =?>
- headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
-
- , "Nothing but a COMMENT header" =:
- "* COMMENT Test" =?>
- (mempty::Blocks)
-
- , "Tree with :noexport:" =:
- T.unlines [ "* Should be ignored :archive:noexport:old:"
- , "** Old stuff"
- , " This is not going to be exported"
- ] =?>
- (mempty::Blocks)
-
- , "Subtree with :noexport:" =:
- T.unlines [ "* Exported"
- , "** This isn't exported :noexport:"
- , "*** This neither"
- , "** But this is"
- ] =?>
- mconcat [ headerWith ("exported", [], []) 1 "Exported"
- , headerWith ("but-this-is", [], []) 2 "But this is"
- ]
-
- , "Preferences are treated as header attributes" =:
- T.unlines [ "* foo"
- , " :PROPERTIES:"
- , " :custom_id: fubar"
- , " :bar: baz"
- , " :END:"
- ] =?>
- headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
-
-
- , "Headers marked with a unnumbered property get a class of the same name" =:
- T.unlines [ "* Not numbered"
- , " :PROPERTIES:"
- , " :UNNUMBERED: t"
- , " :END:"
- ] =?>
- headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
- ]
- , "Paragraph starting with an asterisk" =:
- "*five" =?>
- para "*five"
-
- , "Paragraph containing asterisk at beginning of line" =:
- T.unlines [ "lucky"
- , "*star"
- ] =?>
- para ("lucky" <> softbreak <> "*star")
-
- , "Example block" =:
- T.unlines [ ": echo hello"
- , ": echo dear tester"
- ] =?>
- codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n"
-
- , "Example block surrounded by text" =:
- T.unlines [ "Greetings"
- , ": echo hello"
- , ": echo dear tester"
- , "Bye"
- ] =?>
- mconcat [ para "Greetings"
- , codeBlockWith ("", ["example"], [])
- "echo hello\necho dear tester\n"
- , para "Bye"
- ]
-
- , "Horizontal Rule" =:
- T.unlines [ "before"
- , "-----"
- , "after"
- ] =?>
- mconcat [ para "before"
- , horizontalRule
- , para "after"
- ]
-
- , "Not a Horizontal Rule" =:
- "----- em and en dash" =?>
- para "\8212\8211 em and en dash"
-
- , "Comment Block" =:
- T.unlines [ "#+BEGIN_COMMENT"
- , "stuff"
- , "bla"
- , "#+END_COMMENT"] =?>
- (mempty::Blocks)
-
- , testGroup "Figures" $
- [ "Figure" =:
- T.unlines [ "#+caption: A very courageous man."
- , "#+name: goodguy"
- , "[[file:edward.jpg]]"
- ] =?>
- para (image "edward.jpg" "fig:goodguy" "A very courageous man.")
-
- , "Figure with no name" =:
- T.unlines [ "#+caption: I've been through the desert on this"
- , "[[file:horse.png]]"
- ] =?>
- para (image "horse.png" "fig:" "I've been through the desert on this")
-
- , "Figure with `fig:` prefix in name" =:
- T.unlines [ "#+caption: Used as a metapher in evolutionary biology."
- , "#+name: fig:redqueen"
- , "[[./the-red-queen.jpg]]"
- ] =?>
- para (image "./the-red-queen.jpg" "fig:redqueen"
- "Used as a metapher in evolutionary biology.")
-
- , "Figure with HTML attributes" =:
- T.unlines [ "#+CAPTION: mah brain just explodid"
- , "#+NAME: lambdacat"
- , "#+ATTR_HTML: :style color: blue :role button"
- , "[[file:lambdacat.jpg]]"
- ] =?>
- let kv = [("style", "color: blue"), ("role", "button")]
- name = "fig:lambdacat"
- caption = "mah brain just explodid"
- in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption)
-
- , "Labelled figure" =:
- T.unlines [ "#+CAPTION: My figure"
- , "#+LABEL: fig:myfig"
- , "[[file:blub.png]]"
- ] =?>
- let attr = ("fig:myfig", mempty, mempty)
- in para (imageWith attr "blub.png" "fig:" "My figure")
-
- , "Figure with empty caption" =:
- T.unlines [ "#+CAPTION:"
- , "[[file:guess.jpg]]"
- ] =?>
- para (image "guess.jpg" "fig:" "")
- ]
-
- , testGroup "Footnotes"
- [ "Footnote" =:
- T.unlines [ "A footnote[1]"
- , ""
- , "[1] First paragraph"
- , ""
- , "second paragraph"
- ] =?>
- para (mconcat
- [ "A", space, "footnote"
- , note $ mconcat [ para ("First" <> space <> "paragraph")
- , para ("second" <> space <> "paragraph")
- ]
- ])
-
- , "Two footnotes" =:
- T.unlines [ "Footnotes[fn:1][fn:2]"
- , ""
- , "[fn:1] First note."
- , ""
- , "[fn:2] Second note."
- ] =?>
- para (mconcat
- [ "Footnotes"
- , note $ para ("First" <> space <> "note.")
- , note $ para ("Second" <> space <> "note.")
- ])
-
- , "Emphasized text before footnote" =:
- T.unlines [ "/text/[fn:1]"
- , ""
- , "[fn:1] unicorn"
- ] =?>
- para (mconcat
- [ emph "text"
- , note . para $ "unicorn"
- ])
-
- , "Footnote that starts with emphasized text" =:
- T.unlines [ "text[fn:1]"
- , ""
- , "[fn:1] /emphasized/"
- ] =?>
- para (mconcat
- [ "text"
- , note . para $ emph "emphasized"
- ])
-
- , "Footnote followed by header" =:
- T.unlines [ "Another note[fn:yay]"
- , ""
- , "[fn:yay] This is great!"
- , ""
- , "** Headline"
- ] =?>
- mconcat
- [ para (mconcat
- [ "Another", space, "note"
- , note $ para ("This" <> space <> "is" <> space <> "great!")
- ])
- , headerWith ("headline", [], []) 2 "Headline"
- ]
-
- , "Footnote followed by two blank lines" =:
- T.unlines [ "footnote[fn:blanklines]"
- , ""
- , "[fn:blanklines] followed by blank lines"
- , ""
- , ""
- , "next"
- ] =?>
- mconcat
- [ para ("footnote" <> note (para "followed by blank lines"))
- , para "next"
- ]
- ]
- ]
-
- , testGroup "Lists" $
- [ "Simple Bullet Lists" =:
- ("- Item1\n" <>
- "- Item2\n") =?>
- bulletList [ plain "Item1"
- , plain "Item2"
- ]
-
- , "Indented Bullet Lists" =:
- (" - Item1\n" <>
- " - Item2\n") =?>
- bulletList [ plain "Item1"
- , plain "Item2"
- ]
-
- , "Unindented *" =:
- ("- Item1\n" <>
- "* Item2\n") =?>
- bulletList [ plain "Item1"
- ] <>
- headerWith ("item2", [], []) 1 "Item2"
-
- , "Multi-line Bullet Lists" =:
- ("- *Fat\n" <>
- " Tony*\n" <>
- "- /Sideshow\n" <>
- " Bob/") =?>
- bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony")
- , plain $ emph ("Sideshow" <> softbreak <> "Bob")
- ]
-
- , "Nested Bullet Lists" =:
- ("- Discovery\n" <>
- " + One More Time\n" <>
- " + Harder, Better, Faster, Stronger\n" <>
- "- Homework\n" <>
- " + Around the World\n"<>
- "- Human After All\n" <>
- " + Technologic\n" <>
- " + Robot Rock\n") =?>
- bulletList [ mconcat
- [ plain "Discovery"
- , bulletList [ plain ("One" <> space <>
- "More" <> space <>
- "Time")
- , plain ("Harder," <> space <>
- "Better," <> space <>
- "Faster," <> space <>
- "Stronger")
- ]
- ]
- , mconcat
- [ plain "Homework"
- , bulletList [ plain ("Around" <> space <>
- "the" <> space <>
- "World")
- ]
- ]
- , mconcat
- [ plain ("Human" <> space <> "After" <> space <> "All")
- , bulletList [ plain "Technologic"
- , plain ("Robot" <> space <> "Rock")
- ]
- ]
- ]
-
- , "Bullet List with Decreasing Indent" =:
- (" - Discovery\n\
- \ - Human After All\n") =?>
- mconcat [ bulletList [ plain "Discovery" ]
- , bulletList [ plain ("Human" <> space <> "After" <> space <> "All")]
- ]
-
- , "Header follows Bullet List" =:
- (" - Discovery\n\
- \ - Human After All\n\
- \* Homework") =?>
- mconcat [ bulletList [ plain "Discovery"
- , plain ("Human" <> space <> "After" <> space <> "All")
- ]
- , headerWith ("homework", [], []) 1 "Homework"
- ]
-
- , "Bullet List Unindented with trailing Header" =:
- ("- Discovery\n\
- \- Homework\n\
- \* NotValidListItem") =?>
- mconcat [ bulletList [ plain "Discovery"
- , plain "Homework"
- ]
- , headerWith ("notvalidlistitem", [], []) 1 "NotValidListItem"
- ]
-
- , "Empty bullet points" =:
- T.unlines [ "-"
- , "- "
- ] =?>
- bulletList [ plain "", plain "" ]
-
- , "Simple Ordered List" =:
- ("1. Item1\n" <>
- "2. Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Simple Ordered List with Parens" =:
- ("1) Item1\n" <>
- "2) Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Indented Ordered List" =:
- (" 1. Item1\n" <>
- " 2. Item2\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ plain "Item1"
- , plain "Item2"
- ]
- in orderedListWith listStyle listStructure
-
- , "Empty ordered list item" =:
- T.unlines [ "1."
- , "3. "
- ] =?>
- orderedList [ plain "", plain "" ]
-
- , "Nested Ordered Lists" =:
- ("1. One\n" <>
- " 1. One-One\n" <>
- " 2. One-Two\n" <>
- "2. Two\n" <>
- " 1. Two-One\n"<>
- " 2. Two-Two\n") =?>
- let listStyle = (1, DefaultStyle, DefaultDelim)
- listStructure = [ mconcat
- [ plain "One"
- , orderedList [ plain "One-One"
- , plain "One-Two"
- ]
- ]
- , mconcat
- [ plain "Two"
- , orderedList [ plain "Two-One"
- , plain "Two-Two"
- ]
- ]
- ]
- in orderedListWith listStyle listStructure
-
- , "Ordered List in Bullet List" =:
- ("- Emacs\n" <>
- " 1. Org\n") =?>
- bulletList [ (plain "Emacs") <>
- (orderedList [ plain "Org"])
- ]
-
- , "Bullet List in Ordered List" =:
- ("1. GNU\n" <>
- " - Freedom\n") =?>
- orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
-
- , "Definition List" =:
- T.unlines [ "- PLL :: phase-locked loop"
- , "- TTL ::"
- , " transistor-transistor logic"
- , "- PSK :: phase-shift keying"
- , ""
- , " a digital modulation scheme"
- ] =?>
- definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
- , ("TTL", [ plain $ "transistor-transistor" <> space <>
- "logic" ])
- , ("PSK", [ mconcat
- [ para $ "phase-shift" <> space <> "keying"
- , para $ spcSep [ "a", "digital"
- , "modulation", "scheme" ]
- ]
- ])
- ]
- , "Definition list with multi-word term" =:
- " - Elijah Wood :: He plays Frodo" =?>
- definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])]
- , "Compact definition list" =:
- T.unlines [ "- ATP :: adenosine 5' triphosphate"
- , "- DNA :: deoxyribonucleic acid"
- , "- PCR :: polymerase chain reaction"
- , ""
- ] =?>
- definitionList
- [ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ])
- , ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ])
- , ("PCR", [ plain $ spcSep [ "polymerase", "chain", "reaction" ] ])
- ]
-
- , "Definition List With Trailing Header" =:
- "- definition :: list\n\
- \- cool :: defs\n\
- \* header" =?>
- mconcat [ definitionList [ ("definition", [plain "list"])
- , ("cool", [plain "defs"])
- ]
- , headerWith ("header", [], []) 1 "header"
- ]
-
- , "Definition lists double-colon markers must be surrounded by whitespace" =:
- "- std::cout" =?>
- bulletList [ plain "std::cout" ]
-
- , "Loose bullet list" =:
- T.unlines [ "- apple"
- , ""
- , "- orange"
- , ""
- , "- peach"
- ] =?>
- bulletList [ para "apple"
- , para "orange"
- , para "peach"
- ]
-
- , "Recognize preceding paragraphs in non-list contexts" =:
- T.unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
- , "- Note taken on [2015-10-19 Mon 13:24]"
- ] =?>
- mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]"
- , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ]
- ]
- ]
-
- , testGroup "Tables"
- [ "Single cell table" =:
- "|Test|" =?>
- simpleTable' 1 mempty [[plain "Test"]]
-
- , "Multi cell table" =:
- "| One | Two |" =?>
- simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
-
- , "Multi line table" =:
- T.unlines [ "| One |"
- , "| Two |"
- , "| Three |"
- ] =?>
- simpleTable' 1 mempty
- [ [ plain "One" ]
- , [ plain "Two" ]
- , [ plain "Three" ]
- ]
-
- , "Empty table" =:
- "||" =?>
- simpleTable' 1 mempty [[mempty]]
-
- , "Glider Table" =:
- T.unlines [ "| 1 | 0 | 0 |"
- , "| 0 | 1 | 1 |"
- , "| 1 | 1 | 0 |"
- ] =?>
- simpleTable' 3 mempty
- [ [ plain "1", plain "0", plain "0" ]
- , [ plain "0", plain "1", plain "1" ]
- , [ plain "1", plain "1", plain "0" ]
- ]
-
- , "Table between Paragraphs" =:
- T.unlines [ "Before"
- , "| One | Two |"
- , "After"
- ] =?>
- mconcat [ para "Before"
- , simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
- , para "After"
- ]
-
- , "Table with Header" =:
- T.unlines [ "| Species | Status |"
- , "|--------------+--------------|"
- , "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- ] =?>
- simpleTable [ plain "Species", plain "Status" ]
- [ [ plain "cervisiae", plain "domesticated" ]
- , [ plain "paradoxus", plain "wild" ]
- ]
-
- , "Table with final hline" =:
- T.unlines [ "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- , "|--------------+--------------|"
- ] =?>
- simpleTable' 2 mempty
- [ [ plain "cervisiae", plain "domesticated" ]
- , [ plain "paradoxus", plain "wild" ]
- ]
-
- , "Table in a box" =:
- T.unlines [ "|---------|---------|"
- , "| static | Haskell |"
- , "| dynamic | Lisp |"
- , "|---------+---------|"
- ] =?>
- simpleTable' 2 mempty
- [ [ plain "static", plain "Haskell" ]
- , [ plain "dynamic", plain "Lisp" ]
- ]
-
- , "Table with empty cells" =:
- "|||c|" =?>
- simpleTable' 3 mempty [[mempty, mempty, plain "c"]]
-
- , "Table with empty rows" =:
- T.unlines [ "| first |"
- , "| |"
- , "| third |"
- ] =?>
- simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]]
-
- , "Table with alignment row" =:
- T.unlines [ "| Numbers | Text | More |"
- , "| <c> | <r> | |"
- , "| 1 | One | foo |"
- , "| 2 | Two | bar |"
- ] =?>
- table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
- []
- [ [ plain "Numbers", plain "Text", plain "More" ]
- , [ plain "1" , plain "One" , plain "foo" ]
- , [ plain "2" , plain "Two" , plain "bar" ]
- ]
-
- , "Pipe within text doesn't start a table" =:
- "Ceci n'est pas une | pipe " =?>
- para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
-
- , "Missing pipe at end of row" =:
- "|incomplete-but-valid" =?>
- simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ]
-
- , "Table with differing row lengths" =:
- T.unlines [ "| Numbers | Text "
- , "|-"
- , "| <c> | <r> |"
- , "| 1 | One | foo |"
- , "| 2"
- ] =?>
- table "" (zip [AlignCenter, AlignRight] [0, 0])
- [ plain "Numbers", plain "Text" ]
- [ [ plain "1" , plain "One" , plain "foo" ]
- , [ plain "2" ]
- ]
-
- , "Table with caption" =:
- T.unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
- , "| x | 6 |"
- , "| 9 | 42 |"
- ] =?>
- table "Hitchhiker's Multiplication Table"
- [(AlignDefault, 0), (AlignDefault, 0)]
- []
- [ [ plain "x", plain "6" ]
- , [ plain "9", plain "42" ]
- ]
- ]
-
- , testGroup "Blocks and fragments"
- [ "Source block" =:
- T.unlines [ " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"moin\""
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" <>
- " where greeting = \"moin\"\n"
- in codeBlockWith attr' code'
-
- , "Source block with indented code" =:
- T.unlines [ " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"moin\""
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" <>
- " where greeting = \"moin\"\n"
- in codeBlockWith attr' code'
-
- , "Source block with tab-indented code" =:
- T.unlines [ "\t#+BEGIN_SRC haskell"
- , "\tmain = putStrLn greeting"
- , "\t where greeting = \"moin\""
- , "\t#+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" <>
- " where greeting = \"moin\"\n"
- in codeBlockWith attr' code'
-
- , "Empty source block" =:
- T.unlines [ " #+BEGIN_SRC haskell"
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = ""
- in codeBlockWith attr' code'
-
- , "Source block between paragraphs" =:
- T.unlines [ "Low German greeting"
- , " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"Moin!\""
- , " #+END_SRC" ] =?>
- let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" <>
- " where greeting = \"Moin!\"\n"
- in mconcat [ para $ spcSep [ "Low", "German", "greeting" ]
- , codeBlockWith attr' code'
- ]
- , "Source block with babel arguments" =:
- T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC" ] =?>
- let classes = [ "commonlisp" ] -- as kate doesn't know emacs-lisp syntax
- params = [ ("org-language", "emacs-lisp")
- , ("exports", "both")
- ]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
- in codeBlockWith ("", classes, params) code'
-
- , "Source block with results and :exports both" =:
- T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65"] =?>
- let classes = [ "commonlisp" ]
- params = [ ("org-language", "emacs-lisp")
- , ("exports", "both")
- ]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
- results' = "65\n"
- in codeBlockWith ("", classes, params) code'
- <>
- codeBlockWith ("", ["example"], []) results'
-
- , "Source block with results and :exports code" =:
- T.unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
- let classes = [ "commonlisp" ]
- params = [ ("org-language", "emacs-lisp")
- , ("exports", "code")
- ]
- code' = unlines [ "(progn (message \"Hello, World!\")"
- , " (+ 23 42))" ]
- in codeBlockWith ("", classes, params) code'
-
- , "Source block with results and :exports results" =:
- T.unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
- let results' = "65\n"
- in codeBlockWith ("", ["example"], []) results'
-
- , "Source block with results and :exports none" =:
- T.unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
- (mempty :: Blocks)
-
- , "Source block with toggling header arguments" =:
- T.unlines [ "#+BEGIN_SRC sh :noeval"
- , "echo $HOME"
- , "#+END_SRC"
- ] =?>
- let classes = [ "bash" ]
- params = [ ("org-language", "sh"), ("noeval", "yes") ]
- in codeBlockWith ("", classes, params) "echo $HOME\n"
-
- , "Source block with line number switch" =:
- T.unlines [ "#+BEGIN_SRC sh -n 10"
- , ":() { :|:& };:"
- , "#+END_SRC"
- ] =?>
- let classes = [ "bash", "numberLines" ]
- params = [ ("org-language", "sh"), ("startFrom", "10") ]
- in codeBlockWith ("", classes, params) ":() { :|:& };:\n"
-
- , "Source block with multi-word parameter values" =:
- T.unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng "
- , "digraph { id [label=\"ID\"] }"
- , "#+END_SRC"
- ] =?>
- let classes = [ "dot" ]
- params = [ ("cmdline", "-Kdot -Tpng") ]
- in codeBlockWith ("", classes, params) "digraph { id [label=\"ID\"] }\n"
-
- , "Example block" =:
- T.unlines [ "#+begin_example"
- , "A chosen representation of"
- , "a rule."
- , "#+eND_exAMPle"
- ] =?>
- codeBlockWith ("", ["example"], [])
- "A chosen representation of\na rule.\n"
-
- , "HTML block" =:
- T.unlines [ "#+BEGIN_HTML"
- , "<aside>HTML5 is pretty nice.</aside>"
- , "#+END_HTML"
- ] =?>
- rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
-
- , "Quote block" =:
- T.unlines [ "#+BEGIN_QUOTE"
- , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
- , "#+END_QUOTE"
- ] =?>
- blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
- , "eine", "Mauer", "zu", "errichten!"
- ]))
-
- , "Verse block" =:
- T.unlines [ "The first lines of Goethe's /Faust/:"
- , "#+begin_verse"
- , "Habe nun, ach! Philosophie,"
- , "Juristerei und Medizin,"
- , "Und leider auch Theologie!"
- , "Durchaus studiert, mit heißem Bemühn."
- , "#+end_verse"
- ] =?>
- mconcat
- [ para $ spcSep [ "The", "first", "lines", "of"
- , "Goethe's", emph "Faust" <> ":"]
- , lineBlock
- [ "Habe nun, ach! Philosophie,"
- , "Juristerei und Medizin,"
- , "Und leider auch Theologie!"
- , "Durchaus studiert, mit heißem Bemühn."
- ]
- ]
-
- , "Verse block with blank lines" =:
- T.unlines [ "#+BEGIN_VERSE"
- , "foo"
- , ""
- , "bar"
- , "#+END_VERSE"
- ] =?>
- lineBlock [ "foo", mempty, "bar" ]
-
- , "Verse block with varying indentation" =:
- T.unlines [ "#+BEGIN_VERSE"
- , " hello darkness"
- , "my old friend"
- , "#+END_VERSE"
- ] =?>
- lineBlock [ "\160\160hello darkness", "my old friend" ]
-
- , "Raw block LaTeX" =:
- T.unlines [ "#+BEGIN_LaTeX"
- , "The category $\\cat{Set}$ is adhesive."
- , "#+END_LaTeX"
- ] =?>
- rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n"
-
- , "Raw LaTeX line" =:
- "#+LATEX: \\let\\foo\\bar" =?>
- rawBlock "latex" "\\let\\foo\\bar"
-
- , "Raw Beamer line" =:
- "#+beamer: \\pause" =?>
- rawBlock "beamer" "\\pause"
-
- , "Raw HTML line" =:
- "#+HTML: <aside>not important</aside>" =?>
- rawBlock "html" "<aside>not important</aside>"
-
- , "Export block HTML" =:
- T.unlines [ "#+BEGIN_export html"
- , "<samp>Hello, World!</samp>"
- , "#+END_export"
- ] =?>
- rawBlock "html" "<samp>Hello, World!</samp>\n"
-
- , "LaTeX fragment" =:
- T.unlines [ "\\begin{equation}"
- , "X_i = \\begin{cases}"
- , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
- , " C_{\\alpha(i)} & \\text{otherwise}"
- , " \\end{cases}"
- , "\\end{equation}"
- ] =?>
- rawBlock "latex"
- (unlines [ "\\begin{equation}"
- , "X_i = \\begin{cases}"
- , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <>
- " \\alpha(i)\\\\"
- , " C_{\\alpha(i)} & \\text{otherwise}"
- , " \\end{cases}"
- , "\\end{equation}"
- ])
-
- , "Code block with caption" =:
- T.unlines [ "#+CAPTION: Functor laws in Haskell"
- , "#+NAME: functor-laws"
- , "#+BEGIN_SRC haskell"
- , "fmap id = id"
- , "fmap (p . q) = (fmap p) . (fmap q)"
- , "#+END_SRC"
- ] =?>
- divWith
- nullAttr
- (mappend
- (plain $ spanWith ("", ["label"], [])
- (spcSep [ "Functor", "laws", "in", "Haskell" ]))
- (codeBlockWith ("functor-laws", ["haskell"], [])
- (unlines [ "fmap id = id"
- , "fmap (p . q) = (fmap p) . (fmap q)"
- ])))
-
- , "Convert blank lines in blocks to single newlines" =:
- T.unlines [ "#+begin_html"
- , ""
- , "<span>boring</span>"
- , ""
- , "#+end_html"
- ] =?>
- rawBlock "html" "\n<span>boring</span>\n\n"
-
- , "Accept `ATTR_HTML` attributes for generic block" =:
- T.unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
- , "#+BEGIN_TEST"
- , "nonsense"
- , "#+END_TEST"
- ] =?>
- let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")])
- in divWith attr (para "nonsense")
-
- , "Non-letter chars in source block parameters" =:
- T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
- , "code body"
- , "#+END_SRC"
- ] =?>
- let params = [ ("org-language", "C")
- , ("tangle", "xxxx.c")
- , ("city", "Zürich")
- ]
- in codeBlockWith ( "", ["c"], params) "code body\n"
- ]
-
- , testGroup "Smart punctuation"
- [ test orgSmart "quote before ellipses"
- ("'...hi'"
- =?> para (singleQuoted "…hi"))
-
- , test orgSmart "apostrophe before emph"
- ("D'oh! A l'/aide/!"
- =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
-
- , test orgSmart "apostrophe in French"
- ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
- =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
-
- , test orgSmart "Quotes cannot occur at the end of emphasized text"
- ("/say \"yes\"/" =?>
- para ("/say" <> space <> doubleQuoted "yes" <> "/"))
-
- , test orgSmart "Dashes are allowed at the borders of emphasis'"
- ("/foo---/" =?>
- para (emph "foo—"))
-
- , test orgSmart "Single quotes can be followed by emphasized text"
- ("Singles on the '/meat market/'" =?>
- para ("Singles on the " <> (singleQuoted $ emph "meat market")))
-
- , test orgSmart "Double quotes can be followed by emphasized text"
- ("Double income, no kids: \"/DINK/\"" =?>
- para ("Double income, no kids: " <> (doubleQuoted $ emph "DINK")))
- ]
+ [ testGroup "Inlines" Inline.tests
+ , testGroup "Basic Blocks" Block.tests
+ , testGroup "Meta Information" Meta.tests
+ , testGroup "Directives" Directive.tests
]
diff --git a/test/Tests/Readers/Org/Block.hs b/test/Tests/Readers/Org/Block.hs
new file mode 100644
index 000000000..15dc63554
--- /dev/null
+++ b/test/Tests/Readers/Org/Block.hs
@@ -0,0 +1,192 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+import qualified Tests.Readers.Org.Block.CodeBlock as CodeBlock
+import qualified Tests.Readers.Org.Block.Figure as Figure
+import qualified Tests.Readers.Org.Block.Header as Header
+import qualified Tests.Readers.Org.Block.List as List
+import qualified Tests.Readers.Org.Block.Table as Table
+
+tests :: [TestTree]
+tests =
+ [ "Paragraph" =:
+ "Paragraph\n" =?>
+ para "Paragraph"
+
+ , "Paragraph starting with an asterisk" =:
+ "*five" =?>
+ para "*five"
+
+ , "Paragraph containing asterisk at beginning of line" =:
+ T.unlines [ "lucky"
+ , "*star"
+ ] =?>
+ para ("lucky" <> softbreak <> "*star")
+
+ , "Example block" =:
+ T.unlines [ ": echo hello"
+ , ": echo dear tester"
+ ] =?>
+ codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n"
+
+ , "Example block surrounded by text" =:
+ T.unlines [ "Greetings"
+ , ": echo hello"
+ , ": echo dear tester"
+ , "Bye"
+ ] =?>
+ mconcat [ para "Greetings"
+ , codeBlockWith ("", ["example"], [])
+ "echo hello\necho dear tester\n"
+ , para "Bye"
+ ]
+
+ , "Horizontal Rule" =:
+ T.unlines [ "before"
+ , "-----"
+ , "after"
+ ] =?>
+ mconcat [ para "before"
+ , horizontalRule
+ , para "after"
+ ]
+
+ , "Not a Horizontal Rule" =:
+ "----- em and en dash" =?>
+ para "\8212\8211 em and en dash"
+
+ , "Comment Block" =:
+ T.unlines [ "#+BEGIN_COMMENT"
+ , "stuff"
+ , "bla"
+ , "#+END_COMMENT"] =?>
+ (mempty::Blocks)
+
+ , testGroup "Blocks and fragments"
+ [ "HTML block" =:
+ T.unlines [ "#+BEGIN_HTML"
+ , "<aside>HTML5 is pretty nice.</aside>"
+ , "#+END_HTML"
+ ] =?>
+ rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
+
+ , "Quote block" =:
+ T.unlines [ "#+BEGIN_QUOTE"
+ , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
+ , "#+END_QUOTE"
+ ] =?>
+ blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
+ , "eine", "Mauer", "zu", "errichten!"
+ ]))
+
+ , "Verse block" =:
+ T.unlines [ "The first lines of Goethe's /Faust/:"
+ , "#+begin_verse"
+ , "Habe nun, ach! Philosophie,"
+ , "Juristerei und Medizin,"
+ , "Und leider auch Theologie!"
+ , "Durchaus studiert, mit heißem Bemühn."
+ , "#+end_verse"
+ ] =?>
+ mconcat
+ [ para $ spcSep [ "The", "first", "lines", "of"
+ , "Goethe's", emph "Faust" <> ":"]
+ , lineBlock
+ [ "Habe nun, ach! Philosophie,"
+ , "Juristerei und Medizin,"
+ , "Und leider auch Theologie!"
+ , "Durchaus studiert, mit heißem Bemühn."
+ ]
+ ]
+
+ , "Verse block with blank lines" =:
+ T.unlines [ "#+BEGIN_VERSE"
+ , "foo"
+ , ""
+ , "bar"
+ , "#+END_VERSE"
+ ] =?>
+ lineBlock [ "foo", mempty, "bar" ]
+
+ , "Verse block with varying indentation" =:
+ T.unlines [ "#+BEGIN_VERSE"
+ , " hello darkness"
+ , "my old friend"
+ , "#+END_VERSE"
+ ] =?>
+ lineBlock [ "\160\160hello darkness", "my old friend" ]
+
+ , "Raw block LaTeX" =:
+ T.unlines [ "#+BEGIN_LaTeX"
+ , "The category $\\cat{Set}$ is adhesive."
+ , "#+END_LaTeX"
+ ] =?>
+ rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n"
+
+ , "Raw LaTeX line" =:
+ "#+LATEX: \\let\\foo\\bar" =?>
+ rawBlock "latex" "\\let\\foo\\bar"
+
+ , "Raw Beamer line" =:
+ "#+beamer: \\pause" =?>
+ rawBlock "beamer" "\\pause"
+
+ , "Raw HTML line" =:
+ "#+HTML: <aside>not important</aside>" =?>
+ rawBlock "html" "<aside>not important</aside>"
+
+ , "Export block HTML" =:
+ T.unlines [ "#+BEGIN_export html"
+ , "<samp>Hello, World!</samp>"
+ , "#+END_export"
+ ] =?>
+ rawBlock "html" "<samp>Hello, World!</samp>\n"
+
+ , "LaTeX fragment" =:
+ T.unlines [ "\\begin{equation}"
+ , "X_i = \\begin{cases}"
+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
+ , " C_{\\alpha(i)} & \\text{otherwise}"
+ , " \\end{cases}"
+ , "\\end{equation}"
+ ] =?>
+ rawBlock "latex"
+ (unlines [ "\\begin{equation}"
+ , "X_i = \\begin{cases}"
+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <>
+ " \\alpha(i)\\\\"
+ , " C_{\\alpha(i)} & \\text{otherwise}"
+ , " \\end{cases}"
+ , "\\end{equation}"
+ ])
+
+ , "Convert blank lines in blocks to single newlines" =:
+ T.unlines [ "#+begin_html"
+ , ""
+ , "<span>boring</span>"
+ , ""
+ , "#+end_html"
+ ] =?>
+ rawBlock "html" "\n<span>boring</span>\n\n"
+
+ , "Accept `ATTR_HTML` attributes for generic block" =:
+ T.unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
+ , "#+BEGIN_TEST"
+ , "nonsense"
+ , "#+END_TEST"
+ ] =?>
+ let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")])
+ in divWith attr (para "nonsense")
+ ]
+
+ , testGroup "Headers" Header.tests
+ , testGroup "Figures" Figure.tests
+ , testGroup "Lists" List.tests
+ , testGroup "CodeBlocks" CodeBlock.tests
+ , testGroup "Tables" Table.tests
+ ]
diff --git a/test/Tests/Readers/Org/Block/CodeBlock.hs b/test/Tests/Readers/Org/Block/CodeBlock.hs
new file mode 100644
index 000000000..8fa822089
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/CodeBlock.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.CodeBlock (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Source block" =:
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlockWith attr' code'
+
+ , "Source block with indented code" =:
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlockWith attr' code'
+
+ , "Source block with tab-indented code" =:
+ T.unlines [ "\t#+BEGIN_SRC haskell"
+ , "\tmain = putStrLn greeting"
+ , "\t where greeting = \"moin\""
+ , "\t#+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"moin\"\n"
+ in codeBlockWith attr' code'
+
+ , "Empty source block" =:
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = ""
+ in codeBlockWith attr' code'
+
+ , "Source block between paragraphs" =:
+ T.unlines [ "Low German greeting"
+ , " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"Moin!\""
+ , " #+END_SRC" ] =?>
+ let attr' = ("", ["haskell"], [])
+ code' = "main = putStrLn greeting\n" <>
+ " where greeting = \"Moin!\"\n"
+ in mconcat [ para $ spcSep [ "Low", "German", "greeting" ]
+ , codeBlockWith attr' code'
+ ]
+ , "Source block with babel arguments" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC" ] =?>
+ let classes = [ "commonlisp" ] -- as kate doesn't know emacs-lisp syntax
+ params = [ ("org-language", "emacs-lisp")
+ , ("exports", "both")
+ ]
+ code' = unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
+ in codeBlockWith ("", classes, params) code'
+
+ , "Source block with results and :exports both" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65"] =?>
+ let classes = [ "commonlisp" ]
+ params = [ ("org-language", "emacs-lisp")
+ , ("exports", "both")
+ ]
+ code' = unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
+ results' = "65\n"
+ in codeBlockWith ("", classes, params) code'
+ <>
+ codeBlockWith ("", ["example"], []) results'
+
+ , "Source block with results and :exports code" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
+ let classes = [ "commonlisp" ]
+ params = [ ("org-language", "emacs-lisp")
+ , ("exports", "code")
+ ]
+ code' = unlines [ "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))" ]
+ in codeBlockWith ("", classes, params) code'
+
+ , "Source block with results and :exports results" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
+ let results' = "65\n"
+ in codeBlockWith ("", ["example"], []) results'
+
+ , "Source block with results and :exports none" =:
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
+ (mempty :: Blocks)
+
+ , "Source block with toggling header arguments" =:
+ T.unlines [ "#+BEGIN_SRC sh :noeval"
+ , "echo $HOME"
+ , "#+END_SRC"
+ ] =?>
+ let classes = [ "bash" ]
+ params = [ ("org-language", "sh"), ("noeval", "yes") ]
+ in codeBlockWith ("", classes, params) "echo $HOME\n"
+
+ , "Source block with line number switch" =:
+ T.unlines [ "#+BEGIN_SRC sh -n 10"
+ , ":() { :|:& };:"
+ , "#+END_SRC"
+ ] =?>
+ let classes = [ "bash", "numberLines" ]
+ params = [ ("org-language", "sh"), ("startFrom", "10") ]
+ in codeBlockWith ("", classes, params) ":() { :|:& };:\n"
+
+ , "Source block with multi-word parameter values" =:
+ T.unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng "
+ , "digraph { id [label=\"ID\"] }"
+ , "#+END_SRC"
+ ] =?>
+ let classes = [ "dot" ]
+ params = [ ("cmdline", "-Kdot -Tpng") ]
+ in codeBlockWith ("", classes, params) "digraph { id [label=\"ID\"] }\n"
+
+ , "Example block" =:
+ T.unlines [ "#+begin_example"
+ , "A chosen representation of"
+ , "a rule."
+ , "#+eND_exAMPle"
+ ] =?>
+ codeBlockWith ("", ["example"], [])
+ "A chosen representation of\na rule.\n"
+
+ , "Code block with caption" =:
+ T.unlines [ "#+CAPTION: Functor laws in Haskell"
+ , "#+NAME: functor-laws"
+ , "#+BEGIN_SRC haskell"
+ , "fmap id = id"
+ , "fmap (p . q) = (fmap p) . (fmap q)"
+ , "#+END_SRC"
+ ] =?>
+ divWith
+ nullAttr
+ (mappend
+ (plain $ spanWith ("", ["label"], [])
+ (spcSep [ "Functor", "laws", "in", "Haskell" ]))
+ (codeBlockWith ("functor-laws", ["haskell"], [])
+ (unlines [ "fmap id = id"
+ , "fmap (p . q) = (fmap p) . (fmap q)"
+ ])))
+
+ , "Non-letter chars in source block parameters" =:
+ T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
+ , "code body"
+ , "#+END_SRC"
+ ] =?>
+ let params = [ ("org-language", "C")
+ , ("tangle", "xxxx.c")
+ , ("city", "Zürich")
+ ]
+ in codeBlockWith ( "", ["c"], params) "code body\n"
+ ]
diff --git a/test/Tests/Readers/Org/Block/Figure.hs b/test/Tests/Readers/Org/Block/Figure.hs
new file mode 100644
index 000000000..cae6ef179
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/Figure.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.Figure (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:))
+import Text.Pandoc.Builder (image, imageWith, para)
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Figure" =:
+ T.unlines [ "#+caption: A very courageous man."
+ , "#+name: goodguy"
+ , "[[file:edward.jpg]]"
+ ] =?>
+ para (image "edward.jpg" "fig:goodguy" "A very courageous man.")
+
+ , "Figure with no name" =:
+ T.unlines [ "#+caption: I've been through the desert on this"
+ , "[[file:horse.png]]"
+ ] =?>
+ para (image "horse.png" "fig:" "I've been through the desert on this")
+
+ , "Figure with `fig:` prefix in name" =:
+ T.unlines [ "#+caption: Used as a metapher in evolutionary biology."
+ , "#+name: fig:redqueen"
+ , "[[./the-red-queen.jpg]]"
+ ] =?>
+ para (image "./the-red-queen.jpg" "fig:redqueen"
+ "Used as a metapher in evolutionary biology.")
+
+ , "Figure with HTML attributes" =:
+ T.unlines [ "#+CAPTION: mah brain just explodid"
+ , "#+NAME: lambdacat"
+ , "#+ATTR_HTML: :style color: blue :role button"
+ , "[[file:lambdacat.jpg]]"
+ ] =?>
+ let kv = [("style", "color: blue"), ("role", "button")]
+ name = "fig:lambdacat"
+ caption = "mah brain just explodid"
+ in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption)
+
+ , "Labelled figure" =:
+ T.unlines [ "#+CAPTION: My figure"
+ , "#+LABEL: fig:myfig"
+ , "[[file:blub.png]]"
+ ] =?>
+ let attr = ("fig:myfig", mempty, mempty)
+ in para (imageWith attr "blub.png" "fig:" "My figure")
+
+ , "Figure with empty caption" =:
+ T.unlines [ "#+CAPTION:"
+ , "[[file:guess.jpg]]"
+ ] =?>
+ para (image "guess.jpg" "fig:" "")
+ ]
diff --git a/test/Tests/Readers/Org/Block/Header.hs b/test/Tests/Readers/Org/Block/Header.hs
new file mode 100644
index 000000000..d895c86e2
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/Header.hs
@@ -0,0 +1,182 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.Header (tests) where
+
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep, tagSpan)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "First Level Header" =:
+ "* Headline\n" =?>
+ headerWith ("headline", [], []) 1 "Headline"
+
+ , "Third Level Header" =:
+ "*** Third Level Headline\n" =?>
+ headerWith ("third-level-headline", [], [])
+ 3
+ ("Third" <> space <> "Level" <> space <> "Headline")
+
+ , "Compact Headers with Paragraph" =:
+ T.unlines [ "* First Level"
+ , "** Second Level"
+ , " Text"
+ ] =?>
+ mconcat [ headerWith ("first-level", [], [])
+ 1
+ ("First" <> space <> "Level")
+ , headerWith ("second-level", [], [])
+ 2
+ ("Second" <> space <> "Level")
+ , para "Text"
+ ]
+
+ , "Separated Headers with Paragraph" =:
+ T.unlines [ "* First Level"
+ , ""
+ , "** Second Level"
+ , ""
+ , " Text"
+ ] =?>
+ mconcat [ headerWith ("first-level", [], [])
+ 1
+ ("First" <> space <> "Level")
+ , headerWith ("second-level", [], [])
+ 2
+ ("Second" <> space <> "Level")
+ , para "Text"
+ ]
+
+ , "Headers not preceded by a blank line" =:
+ T.unlines [ "** eat dinner"
+ , "Spaghetti and meatballs tonight."
+ , "** walk dog"
+ ] =?>
+ mconcat [ headerWith ("eat-dinner", [], [])
+ 2
+ ("eat" <> space <> "dinner")
+ , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
+ , headerWith ("walk-dog", [], [])
+ 2
+ ("walk" <> space <> "dog")
+ ]
+
+ , testGroup "Todo keywords"
+ [ "Header with known todo keyword" =:
+ "* TODO header" =?>
+ let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO"
+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
+
+ , "Header marked as done" =:
+ "* DONE header" =?>
+ let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE"
+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
+
+ , "Header with unknown todo keyword" =:
+ "* WAITING header" =?>
+ headerWith ("waiting-header", [], []) 1 "WAITING header"
+
+ , "Custom todo keywords" =:
+ T.unlines [ "#+TODO: WAITING CANCELLED"
+ , "* WAITING compile"
+ , "* CANCELLED lunch"
+ ] =?>
+ let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
+ doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
+ in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
+ <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
+
+ , "Custom todo keywords with multiple done-states" =:
+ T.unlines [ "#+TODO: WAITING | DONE CANCELLED "
+ , "* WAITING compile"
+ , "* CANCELLED lunch"
+ , "* DONE todo-feature"
+ ] =?>
+ let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
+ cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
+ done = spanWith ("", ["done", "DONE"], []) "DONE"
+ in headerWith ("compile", [], []) 1 (waiting <> space <> "compile")
+ <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch")
+ <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature")
+ ]
+
+ , "Tagged headers" =:
+ T.unlines [ "* Personal :PERSONAL:"
+ , "** Call Mom :@PHONE:"
+ , "** Call John :@PHONE:JOHN: "
+ ] =?>
+ mconcat [ headerWith ("personal", [], [])
+ 1
+ ("Personal " <> tagSpan "PERSONAL")
+ , headerWith ("call-mom", [], [])
+ 2
+ ("Call Mom " <> tagSpan "@PHONE")
+ , headerWith ("call-john", [], [])
+ 2
+ ("Call John " <> tagSpan "@PHONE" <> "\160" <> tagSpan "JOHN")
+ ]
+
+ , "Untagged header containing colons" =:
+ "* This: is not: tagged" =?>
+ headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
+
+ , "Header starting with strokeout text" =:
+ T.unlines [ "foo"
+ , ""
+ , "* +thing+ other thing"
+ ] =?>
+ mconcat [ para "foo"
+ , headerWith ("thing-other-thing", [], [])
+ 1
+ ((strikeout "thing") <> " other thing")
+ ]
+
+ , "Comment Trees" =:
+ T.unlines [ "* COMMENT A comment tree"
+ , " Not much going on here"
+ , "** This will be dropped"
+ , "* Comment tree above"
+ ] =?>
+ headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
+
+ , "Nothing but a COMMENT header" =:
+ "* COMMENT Test" =?>
+ (mempty::Blocks)
+
+ , "Tree with :noexport:" =:
+ T.unlines [ "* Should be ignored :archive:noexport:old:"
+ , "** Old stuff"
+ , " This is not going to be exported"
+ ] =?>
+ (mempty::Blocks)
+
+ , "Subtree with :noexport:" =:
+ T.unlines [ "* Exported"
+ , "** This isn't exported :noexport:"
+ , "*** This neither"
+ , "** But this is"
+ ] =?>
+ mconcat [ headerWith ("exported", [], []) 1 "Exported"
+ , headerWith ("but-this-is", [], []) 2 "But this is"
+ ]
+
+ , "Preferences are treated as header attributes" =:
+ T.unlines [ "* foo"
+ , " :PROPERTIES:"
+ , " :custom_id: fubar"
+ , " :bar: baz"
+ , " :END:"
+ ] =?>
+ headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
+
+
+ , "Headers marked with a unnumbered property get a class of the same name" =:
+ T.unlines [ "* Not numbered"
+ , " :PROPERTIES:"
+ , " :UNNUMBERED: t"
+ , " :END:"
+ ] =?>
+ headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
+ ]
diff --git a/test/Tests/Readers/Org/Block/List.hs b/test/Tests/Readers/Org/Block/List.hs
new file mode 100644
index 000000000..32bb13294
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/List.hs
@@ -0,0 +1,244 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.List (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Simple Bullet Lists" =:
+ ("- Item1\n" <>
+ "- Item2\n") =?>
+ bulletList [ plain "Item1"
+ , plain "Item2"
+ ]
+
+ , "Indented Bullet Lists" =:
+ (" - Item1\n" <>
+ " - Item2\n") =?>
+ bulletList [ plain "Item1"
+ , plain "Item2"
+ ]
+
+ , "Unindented *" =:
+ ("- Item1\n" <>
+ "* Item2\n") =?>
+ bulletList [ plain "Item1"
+ ] <>
+ headerWith ("item2", [], []) 1 "Item2"
+
+ , "Multi-line Bullet Lists" =:
+ ("- *Fat\n" <>
+ " Tony*\n" <>
+ "- /Sideshow\n" <>
+ " Bob/") =?>
+ bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony")
+ , plain $ emph ("Sideshow" <> softbreak <> "Bob")
+ ]
+
+ , "Nested Bullet Lists" =:
+ ("- Discovery\n" <>
+ " + One More Time\n" <>
+ " + Harder, Better, Faster, Stronger\n" <>
+ "- Homework\n" <>
+ " + Around the World\n"<>
+ "- Human After All\n" <>
+ " + Technologic\n" <>
+ " + Robot Rock\n") =?>
+ bulletList [ mconcat
+ [ plain "Discovery"
+ , bulletList [ plain ("One" <> space <>
+ "More" <> space <>
+ "Time")
+ , plain ("Harder," <> space <>
+ "Better," <> space <>
+ "Faster," <> space <>
+ "Stronger")
+ ]
+ ]
+ , mconcat
+ [ plain "Homework"
+ , bulletList [ plain ("Around" <> space <>
+ "the" <> space <>
+ "World")
+ ]
+ ]
+ , mconcat
+ [ plain ("Human" <> space <> "After" <> space <> "All")
+ , bulletList [ plain "Technologic"
+ , plain ("Robot" <> space <> "Rock")
+ ]
+ ]
+ ]
+
+ , "Bullet List with Decreasing Indent" =:
+ (" - Discovery\n\
+ \ - Human After All\n") =?>
+ mconcat [ bulletList [ plain "Discovery" ]
+ , bulletList [ plain ("Human" <> space <> "After" <> space <> "All")]
+ ]
+
+ , "Header follows Bullet List" =:
+ (" - Discovery\n\
+ \ - Human After All\n\
+ \* Homework") =?>
+ mconcat [ bulletList [ plain "Discovery"
+ , plain ("Human" <> space <> "After" <> space <> "All")
+ ]
+ , headerWith ("homework", [], []) 1 "Homework"
+ ]
+
+ , "Bullet List Unindented with trailing Header" =:
+ ("- Discovery\n\
+ \- Homework\n\
+ \* NotValidListItem") =?>
+ mconcat [ bulletList [ plain "Discovery"
+ , plain "Homework"
+ ]
+ , headerWith ("notvalidlistitem", [], []) 1 "NotValidListItem"
+ ]
+
+ , "Empty bullet points" =:
+ T.unlines [ "-"
+ , "- "
+ ] =?>
+ bulletList [ plain "", plain "" ]
+
+ , "Simple Ordered List" =:
+ ("1. Item1\n" <>
+ "2. Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Simple Ordered List with Parens" =:
+ ("1) Item1\n" <>
+ "2) Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Indented Ordered List" =:
+ (" 1. Item1\n" <>
+ " 2. Item2\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ plain "Item1"
+ , plain "Item2"
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Empty ordered list item" =:
+ T.unlines [ "1."
+ , "3. "
+ ] =?>
+ orderedList [ plain "", plain "" ]
+
+ , "Nested Ordered Lists" =:
+ ("1. One\n" <>
+ " 1. One-One\n" <>
+ " 2. One-Two\n" <>
+ "2. Two\n" <>
+ " 1. Two-One\n"<>
+ " 2. Two-Two\n") =?>
+ let listStyle = (1, DefaultStyle, DefaultDelim)
+ listStructure = [ mconcat
+ [ plain "One"
+ , orderedList [ plain "One-One"
+ , plain "One-Two"
+ ]
+ ]
+ , mconcat
+ [ plain "Two"
+ , orderedList [ plain "Two-One"
+ , plain "Two-Two"
+ ]
+ ]
+ ]
+ in orderedListWith listStyle listStructure
+
+ , "Ordered List in Bullet List" =:
+ ("- Emacs\n" <>
+ " 1. Org\n") =?>
+ bulletList [ (plain "Emacs") <>
+ (orderedList [ plain "Org"])
+ ]
+
+ , "Bullet List in Ordered List" =:
+ ("1. GNU\n" <>
+ " - Freedom\n") =?>
+ orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
+
+ , "Definition List" =:
+ T.unlines [ "- PLL :: phase-locked loop"
+ , "- TTL ::"
+ , " transistor-transistor logic"
+ , "- PSK :: phase-shift keying"
+ , ""
+ , " a digital modulation scheme"
+ ] =?>
+ definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
+ , ("TTL", [ plain $ "transistor-transistor" <> space <>
+ "logic" ])
+ , ("PSK", [ mconcat
+ [ para $ "phase-shift" <> space <> "keying"
+ , para $ spcSep [ "a", "digital"
+ , "modulation", "scheme" ]
+ ]
+ ])
+ ]
+ , "Definition list with multi-word term" =:
+ " - Elijah Wood :: He plays Frodo" =?>
+ definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])]
+ , "Compact definition list" =:
+ T.unlines [ "- ATP :: adenosine 5' triphosphate"
+ , "- DNA :: deoxyribonucleic acid"
+ , "- PCR :: polymerase chain reaction"
+ , ""
+ ] =?>
+ definitionList
+ [ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ])
+ , ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ])
+ , ("PCR", [ plain $ spcSep [ "polymerase", "chain", "reaction" ] ])
+ ]
+
+ , "Definition List With Trailing Header" =:
+ "- definition :: list\n\
+ \- cool :: defs\n\
+ \* header" =?>
+ mconcat [ definitionList [ ("definition", [plain "list"])
+ , ("cool", [plain "defs"])
+ ]
+ , headerWith ("header", [], []) 1 "header"
+ ]
+
+ , "Definition lists double-colon markers must be surrounded by whitespace" =:
+ "- std::cout" =?>
+ bulletList [ plain "std::cout" ]
+
+ , "Loose bullet list" =:
+ T.unlines [ "- apple"
+ , ""
+ , "- orange"
+ , ""
+ , "- peach"
+ ] =?>
+ bulletList [ para "apple"
+ , para "orange"
+ , para "peach"
+ ]
+
+ , "Recognize preceding paragraphs in non-list contexts" =:
+ T.unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
+ , "- Note taken on [2015-10-19 Mon 13:24]"
+ ] =?>
+ mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]"
+ , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ]
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Block/Table.hs b/test/Tests/Readers/Org/Block/Table.hs
new file mode 100644
index 000000000..db6e756f8
--- /dev/null
+++ b/test/Tests/Readers/Org/Block/Table.hs
@@ -0,0 +1,150 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Block.Table (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+simpleTable' :: Int
+ -> [Blocks]
+ -> [[Blocks]]
+ -> Blocks
+simpleTable' n = table "" (replicate n (AlignDefault, 0.0))
+
+tests :: [TestTree]
+tests =
+ [ "Single cell table" =:
+ "|Test|" =?>
+ simpleTable' 1 mempty [[plain "Test"]]
+
+ , "Multi cell table" =:
+ "| One | Two |" =?>
+ simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
+
+ , "Multi line table" =:
+ T.unlines [ "| One |"
+ , "| Two |"
+ , "| Three |"
+ ] =?>
+ simpleTable' 1 mempty
+ [ [ plain "One" ]
+ , [ plain "Two" ]
+ , [ plain "Three" ]
+ ]
+
+ , "Empty table" =:
+ "||" =?>
+ simpleTable' 1 mempty [[mempty]]
+
+ , "Glider Table" =:
+ T.unlines [ "| 1 | 0 | 0 |"
+ , "| 0 | 1 | 1 |"
+ , "| 1 | 1 | 0 |"
+ ] =?>
+ simpleTable' 3 mempty
+ [ [ plain "1", plain "0", plain "0" ]
+ , [ plain "0", plain "1", plain "1" ]
+ , [ plain "1", plain "1", plain "0" ]
+ ]
+
+ , "Table between Paragraphs" =:
+ T.unlines [ "Before"
+ , "| One | Two |"
+ , "After"
+ ] =?>
+ mconcat [ para "Before"
+ , simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
+ , para "After"
+ ]
+
+ , "Table with Header" =:
+ T.unlines [ "| Species | Status |"
+ , "|--------------+--------------|"
+ , "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ ] =?>
+ simpleTable [ plain "Species", plain "Status" ]
+ [ [ plain "cervisiae", plain "domesticated" ]
+ , [ plain "paradoxus", plain "wild" ]
+ ]
+
+ , "Table with final hline" =:
+ T.unlines [ "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ , "|--------------+--------------|"
+ ] =?>
+ simpleTable' 2 mempty
+ [ [ plain "cervisiae", plain "domesticated" ]
+ , [ plain "paradoxus", plain "wild" ]
+ ]
+
+ , "Table in a box" =:
+ T.unlines [ "|---------|---------|"
+ , "| static | Haskell |"
+ , "| dynamic | Lisp |"
+ , "|---------+---------|"
+ ] =?>
+ simpleTable' 2 mempty
+ [ [ plain "static", plain "Haskell" ]
+ , [ plain "dynamic", plain "Lisp" ]
+ ]
+
+ , "Table with empty cells" =:
+ "|||c|" =?>
+ simpleTable' 3 mempty [[mempty, mempty, plain "c"]]
+
+ , "Table with empty rows" =:
+ T.unlines [ "| first |"
+ , "| |"
+ , "| third |"
+ ] =?>
+ simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]]
+
+ , "Table with alignment row" =:
+ T.unlines [ "| Numbers | Text | More |"
+ , "| <c> | <r> | |"
+ , "| 1 | One | foo |"
+ , "| 2 | Two | bar |"
+ ] =?>
+ table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
+ []
+ [ [ plain "Numbers", plain "Text", plain "More" ]
+ , [ plain "1" , plain "One" , plain "foo" ]
+ , [ plain "2" , plain "Two" , plain "bar" ]
+ ]
+
+ , "Pipe within text doesn't start a table" =:
+ "Ceci n'est pas une | pipe " =?>
+ para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
+
+ , "Missing pipe at end of row" =:
+ "|incomplete-but-valid" =?>
+ simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ]
+
+ , "Table with differing row lengths" =:
+ T.unlines [ "| Numbers | Text "
+ , "|-"
+ , "| <c> | <r> |"
+ , "| 1 | One | foo |"
+ , "| 2"
+ ] =?>
+ table "" (zip [AlignCenter, AlignRight] [0, 0])
+ [ plain "Numbers", plain "Text" ]
+ [ [ plain "1" , plain "One" , plain "foo" ]
+ , [ plain "2" ]
+ ]
+
+ , "Table with caption" =:
+ T.unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
+ , "| x | 6 |"
+ , "| 9 | 42 |"
+ ] =?>
+ table "Hitchhiker's Multiplication Table"
+ [(AlignDefault, 0), (AlignDefault, 0)]
+ []
+ [ [ plain "x", plain "6" ]
+ , [ plain "9", plain "42" ]
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Directive.hs b/test/Tests/Readers/Org/Directive.hs
new file mode 100644
index 000000000..862315ef3
--- /dev/null
+++ b/test/Tests/Readers/Org/Directive.hs
@@ -0,0 +1,199 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Directive (tests) where
+
+import Data.Time (UTCTime (UTCTime), secondsToDiffTime)
+import Data.Time.Calendar (Day (ModifiedJulianDay))
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>), ToString, purely, test)
+import Tests.Readers.Org.Shared ((=:), tagSpan)
+import Text.Pandoc
+import Text.Pandoc.Builder
+import qualified Data.ByteString as BS
+import qualified Data.Text as T
+
+testWithFiles :: (ToString c)
+ => [(FilePath, BS.ByteString)]
+ -> String -- ^ name of test case
+ -> (T.Text, c) -- ^ (input, expected value)
+ -> TestTree
+testWithFiles fileDefs = test (orgWithFiles fileDefs)
+ where
+orgWithFiles :: [(FilePath, BS.ByteString)] -> T.Text -> Pandoc
+orgWithFiles fileDefs input =
+ let readOrg' = readOrg def{ readerExtensions = getDefaultExtensions "org" }
+ in flip purely input $ \inp -> do
+ modifyPureState (\st -> st { stFiles = files fileDefs })
+ readOrg' inp
+
+
+files :: [(FilePath, BS.ByteString)] -> FileTree
+files fileDefs =
+ let dummyTime = UTCTime (ModifiedJulianDay 125) (secondsToDiffTime 0)
+ in foldr (\(fp, bs) -> insertInFileTree fp (FileInfo dummyTime bs))
+ mempty fileDefs
+
+tests :: [TestTree]
+tests =
+ [ testGroup "export options"
+ [ "disable simple sub/superscript syntax" =:
+ T.unlines [ "#+OPTIONS: ^:nil"
+ , "a^b"
+ ] =?>
+ para "a^b"
+
+ , "directly select drawers to be exported" =:
+ T.unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
+ , ":IMPORTANT:"
+ , "23"
+ , ":END:"
+ , ":BORING:"
+ , "very boring"
+ , ":END:"
+ ] =?>
+ divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23")
+
+ , "exclude drawers from being exported" =:
+ T.unlines [ "#+OPTIONS: d:(not \"BORING\")"
+ , ":IMPORTANT:"
+ , "5"
+ , ":END:"
+ , ":BORING:"
+ , "very boring"
+ , ":END:"
+ ] =?>
+ divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5")
+
+ , "don't include archive trees" =:
+ T.unlines [ "#+OPTIONS: arch:nil"
+ , "* old :ARCHIVE:"
+ ] =?>
+ (mempty ::Blocks)
+
+ , "include complete archive trees" =:
+ T.unlines [ "#+OPTIONS: arch:t"
+ , "* old :ARCHIVE:"
+ , " boring"
+ ] =?>
+ mconcat [ headerWith ("old", [], mempty) 1
+ ("old" <> space <> tagSpan "ARCHIVE")
+ , para "boring"
+ ]
+
+ , "include archive tree header only" =:
+ T.unlines [ "#+OPTIONS: arch:headline"
+ , "* old :ARCHIVE:"
+ , " boring"
+ ] =?>
+ headerWith ("old", [], mempty) 1 ("old" <> space <> tagSpan "ARCHIVE")
+
+ , "limit headline depth" =:
+ T.unlines [ "#+OPTIONS: H:2"
+ , "* top-level section"
+ , "** subsection"
+ , "*** list item 1"
+ , "*** list item 2"
+ ] =?>
+ mconcat [ headerWith ("top-level-section", [], []) 1 "top-level section"
+ , headerWith ("subsection", [], []) 2 "subsection"
+ , orderedList [ para "list item 1", para "list item 2" ]
+ ]
+
+ , "turn all headlines into lists" =:
+ T.unlines [ "#+OPTIONS: H:0"
+ , "first block"
+ , "* top-level section 1"
+ , "** subsection"
+ , "* top-level section 2"
+ ] =?>
+ mconcat [ para "first block"
+ , orderedList
+ [ (para "top-level section 1" <>
+ orderedList [ para "subsection" ])
+ , para "top-level section 2" ]
+ ]
+
+ , "preserve linebreaks as hard breaks" =:
+ T.unlines [ "#+OPTIONS: \\n:t"
+ , "first"
+ , "second"
+ ] =?>
+ para ("first" <> linebreak <> "second")
+
+ , "disable author export" =:
+ T.unlines [ "#+OPTIONS: author:nil"
+ , "#+AUTHOR: ShyGuy"
+ ] =?>
+ Pandoc nullMeta mempty
+
+ , "disable creator export" =:
+ T.unlines [ "#+OPTIONS: creator:nil"
+ , "#+creator: The Architect"
+ ] =?>
+ Pandoc nullMeta mempty
+
+ , "disable email export" =:
+ T.unlines [ "#+OPTIONS: email:nil"
+ , "#+email: no-mail-please@example.com"
+ ] =?>
+ Pandoc nullMeta mempty
+
+ , "disable inclusion of todo keywords" =:
+ T.unlines [ "#+OPTIONS: todo:nil"
+ , "** DONE todo export"
+ ] =?>
+ headerWith ("todo-export", [], []) 2 "todo export"
+
+ , "remove tags from headlines" =:
+ T.unlines [ "#+OPTIONS: tags:nil"
+ , "* Headline :hello:world:"
+ ] =?>
+ headerWith ("headline", [], mempty) 1 "Headline"
+ ]
+
+ , testGroup "Include"
+ [ testWithFiles [("./other.org", "content of other file\n")]
+ "file inclusion"
+ (T.unlines [ "#+include: \"other.org\"" ] =?>
+ plain "content of other file")
+
+ , testWithFiles [("./world.org", "World\n\n")]
+ "Included file belongs to item"
+ (T.unlines [ "- Hello,\n #+include: \"world.org\"" ] =?>
+ bulletList [para "Hello," <> para "World"])
+
+ , testWithFiles [("./level3.org", "*** Level3\n\n")]
+ "Default include preserves level"
+ (T.unlines [ "#+include: \"level3.org\"" ] =?>
+ headerWith ("level3", [], []) 3 "Level3")
+
+ , testWithFiles [("./level3.org", "*** Level3\n\n")]
+ "Minlevel shifts level"
+ (T.unlines [ "#+include: \"level3.org\" :minlevel 1" ] =?>
+ headerWith ("level3", [], []) 1 "Level3")
+
+ , testWithFiles [("./src.hs", "putStrLn outString\n")]
+ "Include file as source code snippet"
+ (T.unlines [ "#+include: \"src.hs\" src haskell" ] =?>
+ codeBlockWith ("", ["haskell"], []) "putStrLn outString\n")
+
+ , testWithFiles [("./export-latex.org", "\\emph{Hello}\n")]
+ "Include file as export snippet"
+ (T.unlines [ "#+include: \"export-latex.org\" export latex" ] =?>
+ rawBlock "latex" "\\emph{Hello}\n")
+
+ , testWithFiles [("./subdir/foo-bar.latex", "foo\n"),
+ ("./hello.lisp", "(print \"Hello!\")\n")
+ ]
+ "include directive is limited to one line"
+ (T.unlines [ "#+INCLUDE: \"hello.lisp\" src lisp"
+ , "#+include: \"subdir/foo-bar.latex\" export latex"
+ , "bar"
+ ] =?>
+ mconcat
+ [ codeBlockWith ("", ["lisp"], []) "(print \"Hello!\")\n"
+ , rawBlock "latex" "foo\n"
+ , para "bar"
+ ]
+ )
+ ]
+ ]
diff --git a/test/Tests/Readers/Org/Inline.hs b/test/Tests/Readers/Org/Inline.hs
new file mode 100644
index 000000000..cb50ba630
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline.hs
@@ -0,0 +1,516 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline (tests) where
+
+import Data.List (intersperse)
+import Test.Tasty (TestTree, testGroup)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc
+import Text.Pandoc.Builder
+import Text.Pandoc.Shared (underlineSpan)
+import qualified Data.Text as T
+import qualified Tests.Readers.Org.Inline.Note as Note
+import qualified Tests.Readers.Org.Inline.Smart as Smart
+
+tests :: [TestTree]
+tests =
+ [ "Plain String" =:
+ "Hello, World" =?>
+ para (spcSep [ "Hello,", "World" ])
+
+ , "Emphasis" =:
+ "/Planet Punk/" =?>
+ para (emph . spcSep $ ["Planet", "Punk"])
+
+ , "Strong" =:
+ "*Cider*" =?>
+ para (strong "Cider")
+
+ , "Strong Emphasis" =:
+ "/*strength*/" =?>
+ para (emph . strong $ "strength")
+
+ , "Emphasized Strong preceded by space" =:
+ " */super/*" =?>
+ para (strong . emph $ "super")
+
+ , "Underline" =:
+ "_underline_" =?>
+ para (underlineSpan $ "underline")
+
+ , "Strikeout" =:
+ "+Kill Bill+" =?>
+ para (strikeout . spcSep $ [ "Kill", "Bill" ])
+
+ , "Verbatim" =:
+ "=Robot.rock()=" =?>
+ para (code "Robot.rock()")
+
+ , "Code" =:
+ "~word for word~" =?>
+ para (code "word for word")
+
+ , "Math $..$" =:
+ "$E=mc^2$" =?>
+ para (math "E=mc^2")
+
+ , "Math $$..$$" =:
+ "$$E=mc^2$$" =?>
+ para (displayMath "E=mc^2")
+
+ , "Math \\[..\\]" =:
+ "\\[E=ℎν\\]" =?>
+ para (displayMath "E=ℎν")
+
+ , "Math \\(..\\)" =:
+ "\\(σ_x σ_p ≥ \\frac{ℏ}{2}\\)" =?>
+ para (math "σ_x σ_p ≥ \\frac{ℏ}{2}")
+
+ , "Symbol" =:
+ "A * symbol" =?>
+ para (str "A" <> space <> str "*" <> space <> "symbol")
+
+ , "Superscript simple expression" =:
+ "2^-λ" =?>
+ para (str "2" <> superscript "-λ")
+
+ , "Superscript multi char" =:
+ "2^{n-1}" =?>
+ para (str "2" <> superscript "n-1")
+
+ , "Subscript simple expression" =:
+ "a_n" =?>
+ para (str "a" <> subscript "n")
+
+ , "Subscript multi char" =:
+ "a_{n+1}" =?>
+ para (str "a" <> subscript "n+1")
+
+ , "Linebreak" =:
+ "line \\\\ \nbreak" =?>
+ para ("line" <> linebreak <> "break")
+
+ , "Inline note" =:
+ "[fn::Schreib mir eine E-Mail]" =?>
+ para (note $ para "Schreib mir eine E-Mail")
+
+ , "Markup-chars not occuring on word break are symbols" =:
+ T.unlines [ "this+that+ +so+on"
+ , "seven*eight* nine*"
+ , "+not+funny+"
+ ] =?>
+ para ("this+that+ +so+on" <> softbreak <>
+ "seven*eight* nine*" <> softbreak <>
+ strikeout "not+funny")
+
+ , "No empty markup" =:
+ "// ** __ <> == ~~ $$" =?>
+ para (spcSep [ "//", "**", "__", "<>", "==", "~~", "$$" ])
+
+ , "Adherence to Org's rules for markup borders" =:
+ "/t/& a/ / ./r/ (*l*) /e/! /b/." =?>
+ para (spcSep [ emph $ "t/&" <> space <> "a"
+ , "/"
+ , "./r/"
+ , "(" <> strong "l" <> ")"
+ , emph "e" <> "!"
+ , emph "b" <> "."
+ ])
+
+ , "Quotes are allowed border chars" =:
+ "/'yep/ *sure\"*" =?>
+ para (emph "'yep" <> space <> strong "sure\"")
+
+ , "Spaces are forbidden border chars" =:
+ "/nada /" =?>
+ para "/nada /"
+
+ , "Markup should work properly after a blank line" =:
+ T.unlines ["foo", "", "/bar/"] =?>
+ (para $ text "foo") <> (para $ emph $ text "bar")
+
+ , "Inline math must stay within three lines" =:
+ T.unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
+ para ((math "a\nb\nc") <> softbreak <>
+ "$d" <> softbreak <> "e" <> softbreak <>
+ "f" <> softbreak <> "g$")
+
+ , "Single-character math" =:
+ "$a$ $b$! $c$?" =?>
+ para (spcSep [ math "a"
+ , "$b$!"
+ , (math "c") <> "?"
+ ])
+
+ , "Markup may not span more than two lines" =:
+ "/this *is +totally\nnice+ not*\nemph/" =?>
+ para ("/this" <> space <>
+ strong ("is" <> space <>
+ strikeout ("totally" <>
+ softbreak <> "nice") <>
+ space <> "not") <>
+ softbreak <> "emph/")
+
+ , "Sub- and superscript expressions" =:
+ T.unlines [ "a_(a(b)(c)d)"
+ , "e^(f(g)h)"
+ , "i_(jk)l)"
+ , "m^()n"
+ , "o_{p{q{}r}}"
+ , "s^{t{u}v}"
+ , "w_{xy}z}"
+ , "1^{}2"
+ , "3_{{}}"
+ , "4^(a(*b(c*)d))"
+ ] =?>
+ para (mconcat $ intersperse softbreak
+ [ "a" <> subscript "(a(b)(c)d)"
+ , "e" <> superscript "(f(g)h)"
+ , "i" <> (subscript "(jk)") <> "l)"
+ , "m" <> (superscript "()") <> "n"
+ , "o" <> subscript "p{q{}r}"
+ , "s" <> superscript "t{u}v"
+ , "w" <> (subscript "xy") <> "z}"
+ , "1" <> (superscript "") <> "2"
+ , "3" <> subscript "{}"
+ , "4" <> superscript ("(a(" <> strong "b(c" <> ")d))")
+ ])
+ , "Verbatim text can contain equal signes (=)" =:
+ "=is_subst = True=" =?>
+ para (code "is_subst = True")
+
+ , testGroup "Images"
+ [ "Image" =:
+ "[[./sunset.jpg]]" =?>
+ (para $ image "./sunset.jpg" "" "")
+
+ , "Image with explicit file: prefix" =:
+ "[[file:sunrise.jpg]]" =?>
+ (para $ image "sunrise.jpg" "" "")
+
+ , "Multiple images within a paragraph" =:
+ T.unlines [ "[[file:sunrise.jpg]]"
+ , "[[file:sunset.jpg]]"
+ ] =?>
+ (para $ (image "sunrise.jpg" "" "")
+ <> softbreak
+ <> (image "sunset.jpg" "" ""))
+
+ , "Image with html attributes" =:
+ T.unlines [ "#+ATTR_HTML: :width 50%"
+ , "[[file:guinea-pig.gif]]"
+ ] =?>
+ (para $ imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "")
+ ]
+
+ , "Explicit link" =:
+ "[[http://zeitlens.com/][pseudo-random /nonsense/]]" =?>
+ (para $ link "http://zeitlens.com/" ""
+ ("pseudo-random" <> space <> emph "nonsense"))
+
+ , "Self-link" =:
+ "[[http://zeitlens.com/]]" =?>
+ (para $ link "http://zeitlens.com/" "" "http://zeitlens.com/")
+
+ , "Absolute file link" =:
+ "[[/url][hi]]" =?>
+ (para $ link "file:///url" "" "hi")
+
+ , "Link to file in parent directory" =:
+ "[[../file.txt][moin]]" =?>
+ (para $ link "../file.txt" "" "moin")
+
+ , "Empty link (for gitit interop)" =:
+ "[[][New Link]]" =?>
+ (para $ link "" "" "New Link")
+
+ , "Image link" =:
+ "[[sunset.png][file:dusk.svg]]" =?>
+ (para $ link "sunset.png" "" (image "dusk.svg" "" ""))
+
+ , "Image link with non-image target" =:
+ "[[http://example.com][./logo.png]]" =?>
+ (para $ link "http://example.com" "" (image "./logo.png" "" ""))
+
+ , "Plain link" =:
+ "Posts on http://zeitlens.com/ can be funny at times." =?>
+ (para $ spcSep [ "Posts", "on"
+ , link "http://zeitlens.com/" "" "http://zeitlens.com/"
+ , "can", "be", "funny", "at", "times."
+ ])
+
+ , "Angle link" =:
+ "Look at <http://moltkeplatz.de> for fnords." =?>
+ (para $ spcSep [ "Look", "at"
+ , link "http://moltkeplatz.de" "" "http://moltkeplatz.de"
+ , "for", "fnords."
+ ])
+
+ , "Absolute file link" =:
+ "[[file:///etc/passwd][passwd]]" =?>
+ (para $ link "file:///etc/passwd" "" "passwd")
+
+ , "File link" =:
+ "[[file:target][title]]" =?>
+ (para $ link "target" "" "title")
+
+ , "Anchor" =:
+ "<<anchor>> Link here later." =?>
+ (para $ spanWith ("anchor", [], []) mempty <>
+ "Link" <> space <> "here" <> space <> "later.")
+
+ , "Inline code block" =:
+ "src_emacs-lisp{(message \"Hello\")}" =?>
+ (para $ codeWith ( ""
+ , [ "commonlisp" ]
+ , [ ("org-language", "emacs-lisp") ])
+ "(message \"Hello\")")
+
+ , "Inline code block with arguments" =:
+ "src_sh[:export both :results output]{echo 'Hello, World'}" =?>
+ (para $ codeWith ( ""
+ , [ "bash" ]
+ , [ ("org-language", "sh")
+ , ("export", "both")
+ , ("results", "output")
+ ]
+ )
+ "echo 'Hello, World'")
+
+ , "Inline code block with toggle" =:
+ "src_sh[:toggle]{echo $HOME}" =?>
+ (para $ codeWith ( ""
+ , [ "bash" ]
+ , [ ("org-language", "sh")
+ , ("toggle", "yes")
+ ]
+ )
+ "echo $HOME")
+
+ , "Citation" =:
+ "[@nonexistent]" =?>
+ let citation = Citation
+ { citationId = "nonexistent"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}
+ in (para $ cite [citation] "[@nonexistent]")
+
+ , "Citation containing text" =:
+ "[see @item1 p. 34-35]" =?>
+ let citation = Citation
+ { citationId = "item1"
+ , citationPrefix = [Str "see"]
+ , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}
+ in (para $ cite [citation] "[see @item1 p. 34-35]")
+
+ , "Org-ref simple citation" =:
+ "cite:pandoc" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc")
+
+ , "Org-ref simple citation with underscores" =:
+ "cite:pandoc_org_ref" =?>
+ let citation = Citation
+ { citationId = "pandoc_org_ref"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc_org_ref")
+
+ , "Org-ref simple citation succeeded by comma" =:
+ "cite:pandoc," =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ",")
+
+ , "Org-ref simple citation succeeded by dot" =:
+ "cite:pandoc." =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ".")
+
+ , "Org-ref simple citation succeeded by colon" =:
+ "cite:pandoc:" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ":")
+
+ , "Org-ref simple citep citation" =:
+ "citep:pandoc" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "citep:pandoc")
+
+ , "Org-ref extended citation" =:
+ "[[citep:Dominik201408][See page 20::, for example]]" =?>
+ let citation = Citation
+ { citationId = "Dominik201408"
+ , citationPrefix = toList "See page 20"
+ , citationSuffix = toList ", for example"
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
+
+ , testGroup "Berkeley-style citations" $
+ let pandocCite = Citation
+ { citationId = "Pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ pandocInText = pandocCite { citationMode = AuthorInText }
+ dominikCite = Citation
+ { citationId = "Dominik201408"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ dominikInText = dominikCite { citationMode = AuthorInText }
+ in [
+ "Berkeley-style in-text citation" =:
+ "See @Dominik201408." =?>
+ (para $ "See "
+ <> cite [dominikInText] "@Dominik201408"
+ <> ".")
+
+ , "Berkeley-style parenthetical citation list" =:
+ "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
+ let pandocCite' = pandocCite {
+ citationPrefix = toList "also"
+ , citationSuffix = toList "and others"
+ }
+ dominikCite' = dominikCite {
+ citationPrefix = toList "see"
+ }
+ in (para $ cite [dominikCite', pandocCite'] "")
+
+ , "Berkeley-style plain citation list" =:
+ "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
+ let pandocCite' = pandocInText {
+ citationPrefix = toList "and"
+ }
+ in (para $ "See "
+ <> cite [dominikInText] ""
+ <> "," <> space
+ <> cite [pandocCite'] ""
+ <> "," <> space <> "and others")
+ ]
+
+ , "Inline LaTeX symbol" =:
+ "\\dots" =?>
+ para "…"
+
+ , "Inline LaTeX command" =:
+ "\\textit{Emphasised}" =?>
+ para (emph "Emphasised")
+
+ , "Inline LaTeX command with spaces" =:
+ "\\emph{Emphasis mine}" =?>
+ para (emph "Emphasis mine")
+
+ , "Inline LaTeX math symbol" =:
+ "\\tau" =?>
+ para (emph "τ")
+
+ , "Unknown inline LaTeX command" =:
+ "\\notacommand{foo}" =?>
+ para (rawInline "latex" "\\notacommand{foo}")
+
+ , "Export snippet" =:
+ "@@html:<kbd>M-x org-agenda</kbd>@@" =?>
+ para (rawInline "html" "<kbd>M-x org-agenda</kbd>")
+
+ , "MathML symbol in LaTeX-style" =:
+ "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: '\\nbsp')." =?>
+ para ("There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: ' ').")
+
+ , "MathML symbol in LaTeX-style, including braces" =:
+ "\\Aacute{}stor" =?>
+ para "Ástor"
+
+ , "MathML copy sign" =:
+ "\\copy" =?>
+ para "©"
+
+ , "MathML symbols, space separated" =:
+ "\\ForAll \\Auml" =?>
+ para "∀ Ä"
+
+ , "LaTeX citation" =:
+ "\\cite{Coffee}" =?>
+ let citation = Citation
+ { citationId = "Coffee"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0}
+ in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
+
+ , "Macro" =:
+ T.unlines [ "#+MACRO: HELLO /Hello, $1/"
+ , "{{{HELLO(World)}}}"
+ ] =?>
+ para (emph "Hello, World")
+
+ , "Macro repeting its argument" =:
+ T.unlines [ "#+MACRO: HELLO $1$1"
+ , "{{{HELLO(moin)}}}"
+ ] =?>
+ para "moinmoin"
+
+ , "Macro called with too few arguments" =:
+ T.unlines [ "#+MACRO: HELLO Foo $1 $2 Bar"
+ , "{{{HELLO()}}}"
+ ] =?>
+ para "Foo Bar"
+
+ , testGroup "Footnotes" Note.tests
+ , testGroup "Smart punctuation" Smart.tests
+ ]
diff --git a/test/Tests/Readers/Org/Inline/Note.hs b/test/Tests/Readers/Org/Inline/Note.hs
new file mode 100644
index 000000000..46416d7d8
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline/Note.hs
@@ -0,0 +1,87 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline.Note (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:))
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Footnote" =:
+ T.unlines [ "A footnote[1]"
+ , ""
+ , "[1] First paragraph"
+ , ""
+ , "second paragraph"
+ ] =?>
+ para (mconcat
+ [ "A", space, "footnote"
+ , note $ mconcat [ para ("First" <> space <> "paragraph")
+ , para ("second" <> space <> "paragraph")
+ ]
+ ])
+
+ , "Two footnotes" =:
+ T.unlines [ "Footnotes[fn:1][fn:2]"
+ , ""
+ , "[fn:1] First note."
+ , ""
+ , "[fn:2] Second note."
+ ] =?>
+ para (mconcat
+ [ "Footnotes"
+ , note $ para ("First" <> space <> "note.")
+ , note $ para ("Second" <> space <> "note.")
+ ])
+
+ , "Emphasized text before footnote" =:
+ T.unlines [ "/text/[fn:1]"
+ , ""
+ , "[fn:1] unicorn"
+ ] =?>
+ para (mconcat
+ [ emph "text"
+ , note . para $ "unicorn"
+ ])
+
+ , "Footnote that starts with emphasized text" =:
+ T.unlines [ "text[fn:1]"
+ , ""
+ , "[fn:1] /emphasized/"
+ ] =?>
+ para (mconcat
+ [ "text"
+ , note . para $ emph "emphasized"
+ ])
+
+ , "Footnote followed by header" =:
+ T.unlines [ "Another note[fn:yay]"
+ , ""
+ , "[fn:yay] This is great!"
+ , ""
+ , "** Headline"
+ ] =?>
+ mconcat
+ [ para (mconcat
+ [ "Another", space, "note"
+ , note $ para ("This" <> space <> "is" <> space <> "great!")
+ ])
+ , headerWith ("headline", [], []) 2 "Headline"
+ ]
+
+ , "Footnote followed by two blank lines" =:
+ T.unlines [ "footnote[fn:blanklines]"
+ , ""
+ , "[fn:blanklines] followed by blank lines"
+ , ""
+ , ""
+ , "next"
+ ] =?>
+ mconcat
+ [ para ("footnote" <> note (para "followed by blank lines"))
+ , para "next"
+ ]
+ ]
+
diff --git a/test/Tests/Readers/Org/Inline/Smart.hs b/test/Tests/Readers/Org/Inline/Smart.hs
new file mode 100644
index 000000000..7a5e653cf
--- /dev/null
+++ b/test/Tests/Readers/Org/Inline/Smart.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Inline.Smart (tests) where
+
+import Data.Text (Text)
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>), purely, test)
+import Text.Pandoc (ReaderOptions (readerExtensions),
+ Extension (Ext_smart), def, enableExtension,
+ getDefaultExtensions, readOrg)
+import Text.Pandoc.Builder
+
+orgSmart :: Text -> Pandoc
+orgSmart = purely $
+ let extensionsSmart = enableExtension Ext_smart (getDefaultExtensions "org")
+ in readOrg def{ readerExtensions = extensionsSmart }
+
+tests :: [TestTree]
+tests =
+ [ test orgSmart "quote before ellipses"
+ ("'...hi'"
+ =?> para (singleQuoted "…hi"))
+
+ , test orgSmart "apostrophe before emph"
+ ("D'oh! A l'/aide/!"
+ =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
+
+ , test orgSmart "apostrophe in French"
+ ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
+ =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
+
+ , test orgSmart "Quotes cannot occur at the end of emphasized text"
+ ("/say \"yes\"/" =?>
+ para ("/say" <> space <> doubleQuoted "yes" <> "/"))
+
+ , test orgSmart "Dashes are allowed at the borders of emphasis'"
+ ("/foo---/" =?>
+ para (emph "foo—"))
+
+ , test orgSmart "Single quotes can be followed by emphasized text"
+ ("Singles on the '/meat market/'" =?>
+ para ("Singles on the " <> (singleQuoted $ emph "meat market")))
+
+ , test orgSmart "Double quotes can be followed by emphasized text"
+ ("Double income, no kids: \"/DINK/\"" =?>
+ para ("Double income, no kids: " <> (doubleQuoted $ emph "DINK")))
+ ]
diff --git a/test/Tests/Readers/Org/Meta.hs b/test/Tests/Readers/Org/Meta.hs
new file mode 100644
index 000000000..3ad6f5d8b
--- /dev/null
+++ b/test/Tests/Readers/Org/Meta.hs
@@ -0,0 +1,173 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.Org.Meta (tests) where
+
+import Test.Tasty (TestTree)
+import Tests.Helpers ((=?>))
+import Tests.Readers.Org.Shared ((=:), spcSep)
+import Text.Pandoc
+import Text.Pandoc.Builder
+import qualified Data.Text as T
+
+tests :: [TestTree]
+tests =
+ [ "Comment" =:
+ "# Nothing to see here" =?>
+ (mempty::Blocks)
+
+ , "Not a comment" =:
+ "#-tag" =?>
+ para "#-tag"
+
+ , "Comment surrounded by Text" =:
+ T.unlines [ "Before"
+ , "# Comment"
+ , "After"
+ ] =?>
+ mconcat [ para "Before"
+ , para "After"
+ ]
+
+ , "Title" =:
+ "#+TITLE: Hello, World" =?>
+ let titleInline = toList $ "Hello," <> space <> "World"
+ meta = setMeta "title" (MetaInlines titleInline) $ nullMeta
+ in Pandoc meta mempty
+
+ , "Author" =:
+ "#+author: John /Emacs-Fanboy/ Doe" =?>
+ let author = toList . spcSep $ [ "John", emph "Emacs-Fanboy", "Doe" ]
+ meta = setMeta "author" (MetaList [MetaInlines author]) $ nullMeta
+ in Pandoc meta mempty
+
+ , "Multiple authors" =:
+ "#+author: James Dewey Watson, Francis Harry Compton Crick " =?>
+ let watson = MetaInlines $ toList "James Dewey Watson"
+ crick = MetaInlines $ toList "Francis Harry Compton Crick"
+ meta = setMeta "author" (MetaList [watson, crick]) $ nullMeta
+ in Pandoc meta mempty
+
+ , "Date" =:
+ "#+Date: Feb. *28*, 2014" =?>
+ let date = toList . spcSep $ [ "Feb.", (strong "28") <> ",", "2014" ]
+ meta = setMeta "date" (MetaInlines date) $ nullMeta
+ in Pandoc meta mempty
+
+ , "Description" =:
+ "#+DESCRIPTION: Explanatory text" =?>
+ let description = "Explanatory text"
+ meta = setMeta "description" (MetaString description) $ nullMeta
+ in Pandoc meta mempty
+
+ , "Properties drawer" =:
+ T.unlines [ " :PROPERTIES:"
+ , " :setting: foo"
+ , " :END:"
+ ] =?>
+ (mempty::Blocks)
+
+ , "LaTeX_headers options are translated to header-includes" =:
+ "#+LaTeX_header: \\usepackage{tikz}" =?>
+ let latexInlines = rawInline "latex" "\\usepackage{tikz}"
+ inclList = MetaList [MetaInlines (toList latexInlines)]
+ meta = setMeta "header-includes" inclList nullMeta
+ in Pandoc meta mempty
+
+ , "LaTeX_class option is translated to documentclass" =:
+ "#+LATEX_CLASS: article" =?>
+ let meta = setMeta "documentclass" (MetaString "article") nullMeta
+ in Pandoc meta mempty
+
+ , "LaTeX_class_options is translated to classoption" =:
+ "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
+ let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
+ in Pandoc meta mempty
+
+ , "LaTeX_class_options is translated to classoption" =:
+ "#+html_head: <meta/>" =?>
+ let html = rawInline "html" "<meta/>"
+ inclList = MetaList [MetaInlines (toList html)]
+ meta = setMeta "header-includes" inclList nullMeta
+ in Pandoc meta mempty
+
+ , "later meta definitions take precedence" =:
+ T.unlines [ "#+AUTHOR: this will not be used"
+ , "#+author: Max"
+ ] =?>
+ let author = MetaInlines [Str "Max"]
+ meta = setMeta "author" (MetaList [author]) $ nullMeta
+ in Pandoc meta mempty
+
+ , "Logbook drawer" =:
+ T.unlines [ " :LogBook:"
+ , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
+ , " :END:"
+ ] =?>
+ (mempty::Blocks)
+
+ , "Drawer surrounded by text" =:
+ T.unlines [ "Before"
+ , ":PROPERTIES:"
+ , ":END:"
+ , "After"
+ ] =?>
+ para "Before" <> para "After"
+
+ , "Drawer markers must be the only text in the line" =:
+ T.unlines [ " :LOGBOOK: foo"
+ , " :END: bar"
+ ] =?>
+ para (":LOGBOOK: foo" <> softbreak <> ":END: bar")
+
+ , "Drawers can be arbitrary" =:
+ T.unlines [ ":FOO:"
+ , "/bar/"
+ , ":END:"
+ ] =?>
+ divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar")
+
+ , "Anchor reference" =:
+ T.unlines [ "<<link-here>> Target."
+ , ""
+ , "[[link-here][See here!]]"
+ ] =?>
+ (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
+ para (link "#link-here" "" ("See" <> space <> "here!")))
+
+ , "Search links are read as emph" =:
+ "[[Wally][Where's Wally?]]" =?>
+ (para (emph $ "Where's" <> space <> "Wally?"))
+
+ , "Link to nonexistent anchor" =:
+ T.unlines [ "<<link-here>> Target."
+ , ""
+ , "[[link$here][See here!]]"
+ ] =?>
+ (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
+ para (emph ("See" <> space <> "here!")))
+
+ , "Link abbreviation" =:
+ T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
+ , "[[wp:Org_mode][Wikipedia on Org-mode]]"
+ ] =?>
+ (para (link "https://en.wikipedia.org/wiki/Org_mode" ""
+ ("Wikipedia" <> space <> "on" <> space <> "Org-mode")))
+
+ , "Link abbreviation, defined after first use" =:
+ T.unlines [ "[[zl:non-sense][Non-sense articles]]"
+ , "#+LINK: zl http://zeitlens.com/tags/%s.html"
+ ] =?>
+ (para (link "http://zeitlens.com/tags/non-sense.html" ""
+ ("Non-sense" <> space <> "articles")))
+
+ , "Link abbreviation, URL encoded arguments" =:
+ T.unlines [ "#+link: expl http://example.com/%h/foo"
+ , "[[expl:Hello, World!][Moin!]]"
+ ] =?>
+ (para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!"))
+
+ , "Link abbreviation, append arguments" =:
+ T.unlines [ "#+link: expl http://example.com/"
+ , "[[expl:foo][bar]]"
+ ] =?>
+ (para (link "http://example.com/foo" "" "bar"))
+ ]
diff --git a/test/Tests/Readers/Org/Shared.hs b/test/Tests/Readers/Org/Shared.hs
new file mode 100644
index 000000000..5e8f6dd54
--- /dev/null
+++ b/test/Tests/Readers/Org/Shared.hs
@@ -0,0 +1,29 @@
+module Tests.Readers.Org.Shared
+ ( (=:)
+ , org
+ , spcSep
+ , tagSpan
+ ) where
+
+import Data.List (intersperse)
+import Data.Text (Text)
+import Tests.Helpers (ToString, purely, test)
+import Test.Tasty (TestTree)
+import Text.Pandoc (Pandoc, ReaderOptions (readerExtensions),
+ def, getDefaultExtensions, readOrg)
+import Text.Pandoc.Builder (Inlines, smallcaps, space, spanWith, str)
+
+org :: Text -> Pandoc
+org = purely $ readOrg def{ readerExtensions = getDefaultExtensions "org" }
+
+infix 4 =:
+(=:) :: ToString c
+ => String -> (Text, c) -> TestTree
+(=:) = test org
+
+spcSep :: [Inlines] -> Inlines
+spcSep = mconcat . intersperse space
+
+-- | Create a span for the given tag.
+tagSpan :: String -> Inlines
+tagSpan t = spanWith ("", ["tag"], [("tag-name", t)]) . smallcaps $ str t
diff --git a/test/Tests/Writers/Powerpoint.hs b/test/Tests/Writers/Powerpoint.hs
new file mode 100644
index 000000000..46ebd77bd
--- /dev/null
+++ b/test/Tests/Writers/Powerpoint.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Tests.Writers.Powerpoint (tests) where
+
+import Control.Exception (throwIO)
+import Text.Pandoc
+import Text.Pandoc.Builder
+import Test.Tasty
+import Test.Tasty.HUnit
+import Codec.Archive.Zip
+import Data.List (isPrefixOf, isSuffixOf)
+
+----- Number of Slides -----------
+
+numberOfSlides :: WriterOptions -> Pandoc -> IO Int
+numberOfSlides opts pd = do
+ mbs <- runIO $
+ do setUserDataDir $ Just "../data"
+ writePowerpoint opts pd
+ case mbs of
+ Left e -> throwIO e
+ Right bs -> do
+ let archive = toArchive bs
+ return $
+ length $
+ filter (isSuffixOf ".xml") $
+ filter (isPrefixOf "ppt/slides/slide") $
+ filesInArchive archive
+
+testNumberOfSlides :: TestName -> Int -> WriterOptions -> Pandoc -> TestTree
+testNumberOfSlides name n opts pd =
+ testCase name $ do
+ n' <- numberOfSlides opts pd
+ n' @=? n
+
+numSlideTests :: TestTree
+numSlideTests = testGroup "Number of slides in output"
+ [ testNumberOfSlides
+ "simple one-slide deck" 1
+ def
+ (doc $ para "foo")
+ , testNumberOfSlides
+ "with metadata (header slide)" 2
+ def
+ (setTitle "My Title" $ doc $ para "foo")
+ , testNumberOfSlides
+ "With h1 slide (using default slide-level)" 2
+ def
+ (doc $ header 1 "Header" <> para "foo")
+ , testNumberOfSlides
+ "With h2 slide (using default slide-level)" 2
+ def
+ (doc $ header 1 "Header" <> header 2 "subeader" <> para "foo")
+ , testNumberOfSlides
+ "With h1 slide (using default slide-level)" 2
+ def
+ (doc $ header 1 "Header" <> para "foo")
+ , testNumberOfSlides
+ "With h2 slide (using default slide-level)" 2
+ def
+ (doc $ header 1 "Header" <> header 2 "subeader" <> para "foo")
+ , testNumberOfSlides
+ "With image slide, no header" 3
+ def
+ (doc $
+ para "first slide" <>
+ (para $ image "lalune.jpg" "" "") <>
+ para "foo")
+ , testNumberOfSlides
+ "With image slide, header" 3
+ def
+ (doc $
+ para "first slide" <>
+ header 2 "image header" <>
+ (para $ image "lalune.jpg" "" "") <>
+ para "foo")
+ , testNumberOfSlides
+ "With table, no header" 3
+ def
+ (doc $
+ para "first slide" <>
+ (simpleTable [para "foo" <> para "bar"] [[para "this" <> para "that"]]) <>
+ para "foo")
+ , testNumberOfSlides
+ "With table, header" 3
+ def
+ (doc $
+ para "first slide" <>
+ header 2 "table header" <>
+ (simpleTable [para "foo" <> para "bar"] [[para "this" <> para "that"]]) <>
+ para "foo")
+ , testNumberOfSlides
+ "hrule" 2
+ def
+ (doc $
+ para "first slide" <> horizontalRule <> para "last slide")
+ ]
+
+
+tests :: [TestTree]
+tests = [numSlideTests]
diff --git a/test/command/4162.md b/test/command/4162.md
new file mode 100644
index 000000000..d88e1ec4e
--- /dev/null
+++ b/test/command/4162.md
@@ -0,0 +1,10 @@
+```
+% pandoc -f html -t native
+<div class="line-block">hi<br /><br>
+ there</div>
+^D
+[LineBlock
+ [[Str "hi"]
+ ,[]
+ ,[Str "\160there"]]]
+```
diff --git a/test/command/4183.md b/test/command/4183.md
new file mode 100644
index 000000000..c18320882
--- /dev/null
+++ b/test/command/4183.md
@@ -0,0 +1,32 @@
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo" alt="bar">
+</figure>
+^D
+[Para [Image ("",[],[]) [] ("foo","fig:")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo" alt="bar">
+ <figcaption>
+ <div>
+ baz
+ </div>
+ </figcaption>
+</figure>
+^D
+[Para [Image ("",[],[]) [Str "baz"] ("foo","fig:")]]
+```
+
+```
+% pandoc -f html -t native
+<figure>
+ <img src="foo">
+ <figcaption><p><em>baz</em></p></figcaption>
+</figure>
+^D
+[Para [Image ("",[],[]) [Emph [Str "baz"]] ("foo","fig:")]]
+```
diff --git a/test/command/4208.md b/test/command/4208.md
new file mode 100644
index 000000000..9bc519d90
--- /dev/null
+++ b/test/command/4208.md
@@ -0,0 +1,18 @@
+```
+% pandoc -t latex
+What is a _piffle_? Mark the correct answer(s):
+
+\begin{TAB}(@)[6pt]{|l|c|}{|c|c|c|}
+(a) a subnormal woffle & $\Box$ \\
+(b) an infinite-dimensional baffle & $\Box$ \\
+(c) an inverted first-order triffle & $\Box$ \\
+\end{TAB}
+^D
+What is a \emph{piffle}? Mark the correct answer(s):
+
+\begin{TAB}(@)[6pt]{|l|c|}{|c|c|c|}
+(a) a subnormal woffle & $\Box$ \\
+(b) an infinite-dimensional baffle & $\Box$ \\
+(c) an inverted first-order triffle & $\Box$ \\
+\end{TAB}
+```
diff --git a/test/docx/sdt_elements.docx b/test/docx/sdt_elements.docx
new file mode 100644
index 000000000..9356a6b40
--- /dev/null
+++ b/test/docx/sdt_elements.docx
Binary files differ
diff --git a/test/docx/sdt_elements.native b/test/docx/sdt_elements.native
new file mode 100644
index 000000000..7f7768728
--- /dev/null
+++ b/test/docx/sdt_elements.native
@@ -0,0 +1,10 @@
+[Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Strong [Str "col1Header"]]]
+ ,[Plain [Strong [Str "col2Header"]]]
+ ,[Plain [Strong [Str "col3Header"]]]]
+ ,[[Plain [Str "col1",Space,Str "content"]]
+ ,[Plain [Str "Body",Space,Str "copy"]]
+ ,[Plain [Str "col3",Space,Str "content"]]]]]
diff --git a/test/tables.custom b/test/tables.custom
new file mode 100644
index 000000000..410b68d3f
--- /dev/null
+++ b/test/tables.custom
@@ -0,0 +1,201 @@
+<p>Simple table with caption:</p>
+
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th align="left">Default</th>
+</tr>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table
+
+<p>Simple table without caption:</p>
+
+<table>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th align="left">Default</th>
+</tr>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table
+
+<p>Simple table indented two spaces:</p>
+
+<table>
+<caption>Demonstration of simple table syntax.</caption>
+<tr class="header">
+<th align="right">Right</th>
+<th align="left">Left</th>
+<th align="center">Center</th>
+<th align="left">Default</th>
+</tr>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="left">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="left">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="left">1</td>
+</tr>
+</table
+
+<p>Multiline table with caption:</p>
+
+<table>
+<caption>Here’s the caption.
+It may span multiple lines.</caption>
+<col width="15%" />
+<col width="14%" />
+<col width="16%" />
+<col width="34%" />
+<tr class="header">
+<th align="center">Centered
+Header</th>
+<th align="left">Left
+Aligned</th>
+<th align="right">Right
+Aligned</th>
+<th align="left">Default aligned</th>
+</tr>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans
+multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note
+the blank line between rows.</td>
+</tr>
+</table
+
+<p>Multiline table without caption:</p>
+
+<table>
+<col width="15%" />
+<col width="14%" />
+<col width="16%" />
+<col width="34%" />
+<tr class="header">
+<th align="center">Centered
+Header</th>
+<th align="left">Left
+Aligned</th>
+<th align="right">Right
+Aligned</th>
+<th align="left">Default aligned</th>
+</tr>
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans
+multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note
+the blank line between rows.</td>
+</tr>
+</table
+
+<p>Table without column headers:</p>
+
+<table>
+<tr class="odd">
+<td align="right">12</td>
+<td align="left">12</td>
+<td align="center">12</td>
+<td align="right">12</td>
+</tr>
+<tr class="even">
+<td align="right">123</td>
+<td align="left">123</td>
+<td align="center">123</td>
+<td align="right">123</td>
+</tr>
+<tr class="odd">
+<td align="right">1</td>
+<td align="left">1</td>
+<td align="center">1</td>
+<td align="right">1</td>
+</tr>
+</table
+
+<p>Multiline table without column headers:</p>
+
+<table>
+<col width="15%" />
+<col width="14%" />
+<col width="16%" />
+<col width="34%" />
+<tr class="odd">
+<td align="center">First</td>
+<td align="left">row</td>
+<td align="right">12.0</td>
+<td align="left">Example of a row that spans
+multiple lines.</td>
+</tr>
+<tr class="even">
+<td align="center">Second</td>
+<td align="left">row</td>
+<td align="right">5.0</td>
+<td align="left">Here’s another one. Note
+the blank line between rows.</td>
+</tr>
+</table
+
diff --git a/test/tables.latex b/test/tables.latex
index 7e3d9613d..759b35dfa 100644
--- a/test/tables.latex
+++ b/test/tables.latex
@@ -136,6 +136,7 @@ Table without column headers:
\begin{longtable}[]{@{}rlcr@{}}
\toprule
+\endhead
12 & 12 & 12 & 12\tabularnewline
123 & 123 & 123 & 123\tabularnewline
1 & 1 & 1 & 1\tabularnewline
@@ -146,6 +147,7 @@ Multiline table without column headers:
\begin{longtable}[]{@{}clrl@{}}
\toprule
+\endhead
\begin{minipage}[t]{0.13\columnwidth}\centering
First\strut
\end{minipage} & \begin{minipage}[t]{0.12\columnwidth}\raggedright
diff --git a/test/test-pandoc.hs b/test/test-pandoc.hs
index ff852ee0e..4cf1a952d 100644
--- a/test/test-pandoc.hs
+++ b/test/test-pandoc.hs
@@ -33,6 +33,7 @@ import qualified Tests.Writers.Muse
import qualified Tests.Writers.Native
import qualified Tests.Writers.Org
import qualified Tests.Writers.Plain
+import qualified Tests.Writers.Powerpoint
import qualified Tests.Writers.RST
import qualified Tests.Writers.TEI
import Text.Pandoc.Shared (inDirectory)
@@ -57,6 +58,7 @@ tests = testGroup "pandoc tests" [ Tests.Command.tests
, testGroup "TEI" Tests.Writers.TEI.tests
, testGroup "Muse" Tests.Writers.Muse.tests
, testGroup "FB2" Tests.Writers.FB2.tests
+ , testGroup "PowerPoint" Tests.Writers.Powerpoint.tests
]
, testGroup "Readers"
[ testGroup "LaTeX" Tests.Readers.LaTeX.tests
diff --git a/test/writer.custom b/test/writer.custom
new file mode 100644
index 000000000..b32d777de
--- /dev/null
+++ b/test/writer.custom
@@ -0,0 +1,783 @@
+<p>This is a set of tests for pandoc. Most of them are adapted from
+John Gruber’s markdown test suite.</p>
+
+<hr/>
+
+<h1 id="headers">Headers</h1>
+
+<h2 id="level-2-with-an-embedded-link">Level 2 with an <a href='/url' title=''>embedded link</a></h2>
+
+<h3 id="level-3-with-emphasis">Level 3 with <em>emphasis</em></h3>
+
+<h4 id="level-4">Level 4</h4>
+
+<h5 id="level-5">Level 5</h5>
+
+<h1 id="level-1">Level 1</h1>
+
+<h2 id="level-2-with-emphasis">Level 2 with <em>emphasis</em></h2>
+
+<h3 id="level-3">Level 3</h3>
+
+<p>with no blank line</p>
+
+<h2 id="level-2">Level 2</h2>
+
+<p>with no blank line</p>
+
+<hr/>
+
+<h1 id="paragraphs">Paragraphs</h1>
+
+<p>Here’s a regular paragraph.</p>
+
+<p>In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.</p>
+
+<p>Here’s one with a bullet.
+* criminey.</p>
+
+<p>There should be a hard line break<br/>here.</p>
+
+<hr/>
+
+<h1 id="block-quotes">Block Quotes</h1>
+
+<p>E-mail style:</p>
+
+<blockquote>
+<p>This is a block quote.
+It is pretty short.</p>
+</blockquote>
+
+<blockquote>
+<p>Code in a block quote:</p>
+
+<pre><code>sub status {
+ print &quot;working&quot;;
+}</code></pre>
+
+<p>A list:</p>
+
+<ol>
+<li>item one</li>
+<li>item two</li>
+</ol>
+
+<p>Nested block quotes:</p>
+
+<blockquote>
+<p>nested</p>
+</blockquote>
+
+<blockquote>
+<p>nested</p>
+</blockquote>
+</blockquote>
+
+<p>This should not be a block quote: 2
+&gt; 1.</p>
+
+<p>And a following paragraph.</p>
+
+<hr/>
+
+<h1 id="code-blocks">Code Blocks</h1>
+
+<p>Code:</p>
+
+<pre><code>---- (should be four hyphens)
+
+sub status {
+ print &quot;working&quot;;
+}
+
+this code block is indented by one tab</code></pre>
+
+<p>And:</p>
+
+<pre><code> this code block is indented by two tabs
+
+These should not be escaped: \$ \\ \&gt; \[ \{</code></pre>
+
+<hr/>
+
+<h1 id="lists">Lists</h1>
+
+<h2 id="unordered">Unordered</h2>
+
+<p>Asterisks tight:</p>
+
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+
+<p>Asterisks loose:</p>
+
+<ul>
+<li><p>asterisk 1</p></li>
+<li><p>asterisk 2</p></li>
+<li><p>asterisk 3</p></li>
+</ul>
+
+<p>Pluses tight:</p>
+
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+
+<p>Pluses loose:</p>
+
+<ul>
+<li><p>Plus 1</p></li>
+<li><p>Plus 2</p></li>
+<li><p>Plus 3</p></li>
+</ul>
+
+<p>Minuses tight:</p>
+
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+
+<p>Minuses loose:</p>
+
+<ul>
+<li><p>Minus 1</p></li>
+<li><p>Minus 2</p></li>
+<li><p>Minus 3</p></li>
+</ul>
+
+<h2 id="ordered">Ordered</h2>
+
+<p>Tight:</p>
+
+<ol>
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+
+<p>and:</p>
+
+<ol>
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+
+<p>Loose using tabs:</p>
+
+<ol>
+<li><p>First</p></li>
+<li><p>Second</p></li>
+<li><p>Third</p></li>
+</ol>
+
+<p>and using spaces:</p>
+
+<ol>
+<li><p>One</p></li>
+<li><p>Two</p></li>
+<li><p>Three</p></li>
+</ol>
+
+<p>Multiple paragraphs:</p>
+
+<ol>
+<li><p>Item 1, graf one.</p>
+
+<p>Item 1. graf two. The quick brown fox jumped over the lazy dog’s
+back.</p></li>
+<li><p>Item 2.</p></li>
+<li><p>Item 3.</p></li>
+</ol>
+
+<h2 id="nested">Nested</h2>
+
+<ul>
+<li>Tab
+
+<ul>
+<li>Tab
+
+<ul>
+<li>Tab</li>
+</ul></li>
+</ul></li>
+</ul>
+
+<p>Here’s another:</p>
+
+<ol>
+<li>First</li>
+<li>Second:
+
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li>Third</li>
+</ol>
+
+<p>Same thing but with paragraphs:</p>
+
+<ol>
+<li><p>First</p></li>
+<li><p>Second:</p>
+
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li><p>Third</p></li>
+</ol>
+
+<h2 id="tabs-and-spaces">Tabs and spaces</h2>
+
+<ul>
+<li><p>this is a list item
+indented with tabs</p></li>
+<li><p>this is a list item
+indented with spaces</p>
+
+<ul>
+<li><p>this is an example list item
+indented with tabs</p></li>
+<li><p>this is an example list item
+indented with spaces</p></li>
+</ul></li>
+</ul>
+
+<h2 id="fancy-list-markers">Fancy list markers</h2>
+
+<ol>
+<li>begins with 2</li>
+<li><p>and now 3</p>
+
+<p>with a continuation</p>
+
+<ol>
+<li>sublist with roman numerals,
+starting with 4</li>
+<li>more items
+
+<ol>
+<li>a subsublist</li>
+<li>a subsublist</li>
+</ol></li>
+</ol></li>
+</ol>
+
+<p>Nesting:</p>
+
+<ol>
+<li>Upper Alpha
+
+<ol>
+<li>Upper Roman.
+
+<ol>
+<li>Decimal start with 6
+
+<ol>
+<li>Lower alpha with paren</li>
+</ol></li>
+</ol></li>
+</ol></li>
+</ol>
+
+<p>Autonumbering:</p>
+
+<ol>
+<li>Autonumber.</li>
+<li>More.
+
+<ol>
+<li>Nested.</li>
+</ol></li>
+</ol>
+
+<p>Should not be a list item:</p>
+
+<p>M.A. 2007</p>
+
+<p>B. Williams</p>
+
+<hr/>
+
+<h1 id="definition-lists">Definition Lists</h1>
+
+<p>Tight using spaces:</p>
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dt>banana</dt>
+<dd>yellow fruit</dd>
+</dl>
+
+<p>Tight using tabs:</p>
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dt>banana</dt>
+<dd>yellow fruit</dd>
+</dl>
+
+<p>Loose:</p>
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p></dd>
+<dt>banana</dt>
+<dd><p>yellow fruit</p></dd>
+</dl>
+
+<p>Multiple blocks with italics:</p>
+
+<dl>
+<dt><em>apple</em></dt>
+<dd><p>red fruit</p>
+
+<p>contains seeds,
+crisp, pleasant to taste</p></dd>
+<dt><em>orange</em></dt>
+<dd><p>orange fruit</p>
+
+<pre><code>{ orange code block }</code></pre>
+
+<blockquote>
+<p>orange block quote</p>
+</blockquote></dd>
+</dl>
+
+<p>Multiple definitions, tight:</p>
+
+<dl>
+<dt>apple</dt>
+<dd>red fruit</dd>
+<dd>computer</dd>
+<dt>orange</dt>
+<dd>orange fruit</dd>
+<dd>bank</dd>
+</dl>
+
+<p>Multiple definitions, loose:</p>
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dd><p>computer</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p></dd>
+<dd><p>bank</p></dd>
+</dl>
+
+<p>Blank line after term, indented marker, alternate markers:</p>
+
+<dl>
+<dt>apple</dt>
+<dd><p>red fruit</p></dd>
+<dd><p>computer</p></dd>
+<dt>orange</dt>
+<dd><p>orange fruit</p>
+
+<ol>
+<li>sublist</li>
+<li>sublist</li>
+</ol></dd>
+</dl>
+
+<h1 id="html-blocks">HTML Blocks</h1>
+
+<p>Simple block on one line:</p>
+
+<div>
+foo</div>
+
+<p>And nested without indentation:</p>
+
+<div>
+<div>
+<div>
+<p>foo</p></div></div>
+
+<div>
+bar</div></div>
+
+<p>Interpreted markdown in a table:</p>
+
+<table>
+
+<tr>
+
+<td>
+
+This is <em>emphasized</em>
+
+</td>
+
+<td>
+
+And this is <strong>strong</strong>
+
+</td>
+
+</tr>
+
+</table>
+
+<script type="text/javascript">document.write('This *should not* be interpreted as markdown');</script>
+
+<p>Here’s a simple block:</p>
+
+<div>
+<p>foo</p></div>
+
+<p>This should be a code block, though:</p>
+
+<pre><code>&lt;div&gt;
+ foo
+&lt;/div&gt;</code></pre>
+
+<p>As should this:</p>
+
+<pre><code>&lt;div&gt;foo&lt;/div&gt;</code></pre>
+
+<p>Now, nested:</p>
+
+<div>
+<div>
+<div>
+foo</div></div></div>
+
+<p>This should just be an HTML comment:</p>
+
+<!-- Comment -->
+
+<p>Multiline:</p>
+
+<!--
+Blah
+Blah
+-->
+
+<!--
+ This is another comment.
+-->
+
+<p>Code block:</p>
+
+<pre><code>&lt;!-- Comment --&gt;</code></pre>
+
+<p>Just plain comment, with trailing spaces on the line:</p>
+
+<!-- foo -->
+
+<p>Code:</p>
+
+<pre><code>&lt;hr /&gt;</code></pre>
+
+<p>Hr’s:</p>
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr>
+
+<hr />
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar">
+
+<hr/>
+
+<h1 id="inline-markup">Inline Markup</h1>
+
+<p>This is <em>emphasized</em>, and so <em>is this</em>.</p>
+
+<p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p>
+
+<p>An <em><a href='/url' title=''>emphasized link</a></em>.</p>
+
+<p><strong><em>This is strong and em.</em></strong></p>
+
+<p>So is <strong><em>this</em></strong> word.</p>
+
+<p><strong><em>This is strong and em.</em></strong></p>
+
+<p>So is <strong><em>this</em></strong> word.</p>
+
+<p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p>
+
+<p><del>This is <em>strikeout</em>.</del></p>
+
+<p>Superscripts: a<sup>bc</sup>d a<sup><em>hello</em></sup> a<sup>hello there</sup>.</p>
+
+<p>Subscripts: H<sub>2</sub>O, H<sub>23</sub>O, H<sub>many of them</sub>O.</p>
+
+<p>These should not be superscripts or subscripts,
+because of the unescaped spaces: a^b c^d, a~b c~d.</p>
+
+<hr/>
+
+<h1 id="smart-quotes-ellipses-dashes">Smart quotes, ellipses, dashes</h1>
+
+<p> said the spider. </p>
+
+<p>, , and are letters.</p>
+
+<p> and are names of trees.
+So is </p>
+
+<p> Were you alive in the
+70’s?</p>
+
+<p>Here is some quoted and a .</p>
+
+<p>Some dashes: one—two — three—four — five.</p>
+
+<p>Dashes between numbers: 5–7, 255–66, 1987–1999.</p>
+
+<p>Ellipses…and…and….</p>
+
+<hr/>
+
+<h1 id="latex">LaTeX</h1>
+
+<ul>
+<li></li>
+<li>\(2+2=4\)</li>
+<li>\(x \in y\)</li>
+<li>\(\alpha \wedge \omega\)</li>
+<li>\(223\)</li>
+<li>\(p\)-Tree</li>
+<li>Here’s some display math:
+\[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\]</li>
+<li>Here’s one that has a line break in it: \(\alpha + \omega \times x^2\).</li>
+</ul>
+
+<p>These shouldn’t be math:</p>
+
+<ul>
+<li>To get the famous equation, write <code>$e = mc^2$</code>.</li>
+<li>$22,000 is a <em>lot</em> of money. So is $34,000.
+(It worked if is emphasized.)</li>
+<li>Shoes ($20) and socks ($5).</li>
+<li>Escaped <code>$</code>: $73 <em>this should be emphasized</em> 23$.</li>
+</ul>
+
+<p>Here’s a LaTeX table:</p>
+
+
+
+<hr/>
+
+<h1 id="special-characters">Special Characters</h1>
+
+<p>Here is some unicode:</p>
+
+<ul>
+<li>I hat: Î</li>
+<li>o umlaut: ö</li>
+<li>section: §</li>
+<li>set membership: ∈</li>
+<li>copyright: ©</li>
+</ul>
+
+<p>AT&amp;T has an ampersand in their name.</p>
+
+<p>AT&amp;T is another way to write it.</p>
+
+<p>This &amp; that.</p>
+
+<p>4 &lt; 5.</p>
+
+<p>6 &gt; 5.</p>
+
+<p>Backslash: \</p>
+
+<p>Backtick: `</p>
+
+<p>Asterisk: *</p>
+
+<p>Underscore: _</p>
+
+<p>Left brace: {</p>
+
+<p>Right brace: }</p>
+
+<p>Left bracket: [</p>
+
+<p>Right bracket: ]</p>
+
+<p>Left paren: (</p>
+
+<p>Right paren: )</p>
+
+<p>Greater-than: &gt;</p>
+
+<p>Hash: #</p>
+
+<p>Period: .</p>
+
+<p>Bang: !</p>
+
+<p>Plus: +</p>
+
+<p>Minus: -</p>
+
+<hr/>
+
+<h1 id="links">Links</h1>
+
+<h2 id="explicit">Explicit</h2>
+
+<p>Just a <a href='/url/' title=''>URL</a>.</p>
+
+<p><a href='/url/' title='title'>URL and title</a>.</p>
+
+<p><a href='/url/' title='title preceded by two spaces'>URL and title</a>.</p>
+
+<p><a href='/url/' title='title preceded by a tab'>URL and title</a>.</p>
+
+<p><a href='/url/' title='title with &quot;quotes&quot; in it'>URL and title</a></p>
+
+<p><a href='/url/' title='title with single quotes'>URL and title</a></p>
+
+<p><a href='/url/with_underscore' title=''>with_underscore</a></p>
+
+<p><a href='mailto:nobody@nowhere.net' title=''>Email link</a></p>
+
+<p><a href='' title=''>Empty</a>.</p>
+
+<h2 id="reference">Reference</h2>
+
+<p>Foo <a href='/url/' title=''>bar</a>.</p>
+
+<p>With <a href='/url/' title=''>embedded [brackets]</a>.</p>
+
+<p><a href='/url/' title=''>b</a> by itself should be a link.</p>
+
+<p>Indented <a href='/url' title=''>once</a>.</p>
+
+<p>Indented <a href='/url' title=''>twice</a>.</p>
+
+<p>Indented <a href='/url' title=''>thrice</a>.</p>
+
+<p>This should [not][] be a link.</p>
+
+<pre><code>[not]: /url</code></pre>
+
+<p>Foo <a href='/url/' title='Title with &quot;quotes&quot; inside'>bar</a>.</p>
+
+<p>Foo <a href='/url/' title='Title with &quot;quote&quot; inside'>biz</a>.</p>
+
+<h2 id="with-ampersands">With ampersands</h2>
+
+<p>Here’s a <a href='http://example.com/?foo=1&amp;bar=2' title=''>link with an ampersand in the URL</a>.</p>
+
+<p>Here’s a link with an amersand in the link text: <a href='http://att.com/' title='AT&amp;T'>AT&amp;T</a>.</p>
+
+<p>Here’s an <a href='/script?foo=1&amp;bar=2' title=''>inline link</a>.</p>
+
+<p>Here’s an <a href='/script?foo=1&amp;bar=2' title=''>inline link in pointy braces</a>.</p>
+
+<h2 id="autolinks">Autolinks</h2>
+
+<p>With an ampersand: <a href='http://example.com/?foo=1&amp;bar=2' title=''>http://example.com/?foo=1&amp;bar=2</a></p>
+
+<ul>
+<li>In a list?</li>
+<li><a href='http://example.com/' title=''>http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+
+<p>An e-mail address: <a href='mailto:nobody@nowhere.net' title=''>nobody@nowhere.net</a></p>
+
+<blockquote>
+<p>Blockquoted: <a href='http://example.com/' title=''>http://example.com/</a></p>
+</blockquote>
+
+<p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p>
+
+<pre><code>or here: &lt;http://example.com/&gt;</code></pre>
+
+<hr/>
+
+<h1 id="images">Images</h1>
+
+<p>From by Georges Melies (1902):</p>
+
+<div class="figure">
+<img src="lalune.jpg" title="fig:Voyage dans la Lune"/>
+<p class="caption">lalune</p>
+</div>
+
+<p>Here is a movie <img src='movie.jpg' title=''/> icon.</p>
+
+<hr/>
+
+<h1 id="footnotes">Footnotes</h1>
+
+<p>Here is a footnote reference,<a id="fnref1" href="#fn1"><sup>1</sup></a> and another.<a id="fnref2" href="#fn2"><sup>2</sup></a>
+This should <em>not</em> be a footnote reference, because it
+contains a space.[^my note] Here is an inline note.<a id="fnref3" href="#fn3"><sup>3</sup></a></p>
+
+<blockquote>
+<p>Notes can go in quotes.<a id="fnref4" href="#fn4"><sup>4</sup></a></p>
+</blockquote>
+
+<ol>
+<li>And in list items.<a id="fnref5" href="#fn5"><sup>5</sup></a></li>
+</ol>
+
+<p>This paragraph should not be part of the note, as it is not indented.</p>
+<ol class="footnotes">
+<li id="fn1"><p>Here is the footnote. It can go anywhere after the footnote
+reference. It need not be placed at the end of the document. <a href="#fnref1">&#8617;</a></p></li>
+<li id="fn2"><p>Here’s the long note. This one contains multiple
+blocks.</p>
+
+<p>Subsequent blocks are indented to show that they belong to the
+footnote (as with list items).</p>
+
+<pre><code> { &lt;code&gt; }</code></pre>
+
+<p>If you want, you can indent every line, but you can also be
+lazy and just indent the first line of each block. <a href="#fnref2">&#8617;</a></p></li>
+<li id="fn3"><p>This
+is <em>easier</em> to type. Inline notes may contain
+<a href='http://google.com' title=''>links</a> and <code>]</code> verbatim characters,
+as well as [bracketed text]. <a href="#fnref3">&#8617;</a></p></li>
+<li id="fn4"><p>In quote. <a href="#fnref4">&#8617;</a></p></li>
+<li id="fn5"><p>In list. <a href="#fnref5">&#8617;</a></p></li>
+</ol>
+
diff --git a/windows/make-windows-installer.bat b/windows/make-windows-installer.bat
index 15d97d9d2..a64af6621 100644
--- a/windows/make-windows-installer.bat
+++ b/windows/make-windows-installer.bat
@@ -1,5 +1,5 @@
@echo off
-stack install --test --ghc-options="-O2" --stack-yaml=..\stack.pkg.yml
+stack install --test --ghc-options="-O2" --stack-yaml=..\stack.yaml
if %errorlevel% neq 0 exit /b %errorlevel%
for /f "delims=" %%a in ('stack path --local-bin-path') do @set BINPATH=%%a
%BINPATH%\pandoc.exe -s --toc ..\MANUAL.txt -o MANUAL.html